فهرست منبع

Merge branch 'upstream-curl' into update-curl

* upstream-curl:
  curl 2024-07-24 (5040f7e9)
Brad King 1 سال پیش
والد
کامیت
54c5367320
100فایلهای تغییر یافته به همراه2893 افزوده شده و 1385 حذف شده
  1. 4 3
      Utilities/cmcurl/CMake/CurlSymbolHiding.cmake
  2. 1 1
      Utilities/cmcurl/CMake/CurlTests.c
  3. 1 1
      Utilities/cmcurl/CMake/FindBearSSL.cmake
  4. 9 9
      Utilities/cmcurl/CMake/FindBrotli.cmake
  5. 1 1
      Utilities/cmcurl/CMake/FindCARES.cmake
  6. 56 56
      Utilities/cmcurl/CMake/FindGSS.cmake
  7. 2 2
      Utilities/cmcurl/CMake/FindLibPSL.cmake
  8. 2 2
      Utilities/cmcurl/CMake/FindLibSSH2.cmake
  9. 1 1
      Utilities/cmcurl/CMake/FindMbedTLS.cmake
  10. 5 5
      Utilities/cmcurl/CMake/FindNGHTTP2.cmake
  11. 30 6
      Utilities/cmcurl/CMake/FindWolfSSL.cmake
  12. 2 2
      Utilities/cmcurl/CMake/OtherTests.cmake
  13. 10 0
      Utilities/cmcurl/CMake/PickyWarnings.cmake
  14. 2 1
      Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
  15. 4 0
      Utilities/cmcurl/CMake/curl-config.cmake.in
  16. 261 175
      Utilities/cmcurl/CMakeLists.txt
  17. 68 57
      Utilities/cmcurl/include/curl/curl.h
  18. 4 4
      Utilities/cmcurl/include/curl/curlver.h
  19. 1 1
      Utilities/cmcurl/include/curl/easy.h
  20. 2 1
      Utilities/cmcurl/include/curl/mprintf.h
  21. 8 8
      Utilities/cmcurl/include/curl/multi.h
  22. 2 2
      Utilities/cmcurl/include/curl/system.h
  23. 5 5
      Utilities/cmcurl/include/curl/typecheck-gcc.h
  24. 3 2
      Utilities/cmcurl/include/curl/urlapi.h
  25. 32 33
      Utilities/cmcurl/lib/CMakeLists.txt
  26. 12 12
      Utilities/cmcurl/lib/altsvc.c
  27. 1 1
      Utilities/cmcurl/lib/altsvc.h
  28. 1 1
      Utilities/cmcurl/lib/amigaos.c
  29. 1 1
      Utilities/cmcurl/lib/arpa_telnet.h
  30. 46 46
      Utilities/cmcurl/lib/asyn-ares.c
  31. 48 15
      Utilities/cmcurl/lib/asyn-thread.c
  32. 8 8
      Utilities/cmcurl/lib/asyn.h
  33. 1 1
      Utilities/cmcurl/lib/bufref.c
  34. 11 10
      Utilities/cmcurl/lib/c-hyper.c
  35. 15 15
      Utilities/cmcurl/lib/cf-h1-proxy.c
  36. 72 12
      Utilities/cmcurl/lib/cf-h2-proxy.c
  37. 1 0
      Utilities/cmcurl/lib/cf-haproxy.c
  38. 47 2
      Utilities/cmcurl/lib/cf-https-connect.c
  39. 383 203
      Utilities/cmcurl/lib/cf-socket.c
  40. 7 2
      Utilities/cmcurl/lib/cf-socket.h
  41. 108 3
      Utilities/cmcurl/lib/cfilters.c
  42. 35 4
      Utilities/cmcurl/lib/cfilters.h
  43. 632 41
      Utilities/cmcurl/lib/conncache.c
  44. 45 3
      Utilities/cmcurl/lib/conncache.h
  45. 94 8
      Utilities/cmcurl/lib/connect.c
  46. 17 2
      Utilities/cmcurl/lib/connect.h
  47. 28 21
      Utilities/cmcurl/lib/content_encoding.c
  48. 39 38
      Utilities/cmcurl/lib/cookie.c
  49. 1 1
      Utilities/cmcurl/lib/cookie.h
  50. 13 5
      Utilities/cmcurl/lib/curl_addrinfo.c
  51. 3 3
      Utilities/cmcurl/lib/curl_addrinfo.h
  52. 21 12
      Utilities/cmcurl/lib/curl_config.h.cmake
  53. 1 1
      Utilities/cmcurl/lib/curl_des.c
  54. 3 3
      Utilities/cmcurl/lib/curl_endian.c
  55. 1 1
      Utilities/cmcurl/lib/curl_fnmatch.c
  56. 5 5
      Utilities/cmcurl/lib/curl_gethostname.c
  57. 4 3
      Utilities/cmcurl/lib/curl_multibyte.h
  58. 18 18
      Utilities/cmcurl/lib/curl_ntlm_core.c
  59. 0 7
      Utilities/cmcurl/lib/curl_ntlm_core.h
  60. 3 3
      Utilities/cmcurl/lib/curl_rtmp.c
  61. 1 1
      Utilities/cmcurl/lib/curl_sasl.c
  62. 60 11
      Utilities/cmcurl/lib/curl_setup.h
  63. 7 7
      Utilities/cmcurl/lib/curl_setup_once.h
  64. 9 9
      Utilities/cmcurl/lib/curl_sha512_256.c
  65. 1 1
      Utilities/cmcurl/lib/curl_sspi.c
  66. 9 4
      Utilities/cmcurl/lib/curl_threads.c
  67. 7 2
      Utilities/cmcurl/lib/curl_threads.h
  68. 2 2
      Utilities/cmcurl/lib/cw-out.c
  69. 3 3
      Utilities/cmcurl/lib/dict.c
  70. 81 48
      Utilities/cmcurl/lib/doh.c
  71. 16 13
      Utilities/cmcurl/lib/doh.h
  72. 2 2
      Utilities/cmcurl/lib/dynbuf.c
  73. 1 1
      Utilities/cmcurl/lib/dynhds.c
  74. 20 16
      Utilities/cmcurl/lib/dynhds.h
  75. 17 11
      Utilities/cmcurl/lib/easy.c
  76. 1 1
      Utilities/cmcurl/lib/easygetopt.c
  77. 1 1
      Utilities/cmcurl/lib/easyif.h
  78. 2 1
      Utilities/cmcurl/lib/easyoptions.c
  79. 6 5
      Utilities/cmcurl/lib/escape.c
  80. 33 29
      Utilities/cmcurl/lib/file.c
  81. 4 4
      Utilities/cmcurl/lib/fopen.c
  82. 10 10
      Utilities/cmcurl/lib/formdata.c
  83. 2 2
      Utilities/cmcurl/lib/formdata.h
  84. 96 90
      Utilities/cmcurl/lib/ftp.c
  85. 3 3
      Utilities/cmcurl/lib/ftp.h
  86. 3 3
      Utilities/cmcurl/lib/getenv.c
  87. 7 7
      Utilities/cmcurl/lib/getinfo.c
  88. 3 3
      Utilities/cmcurl/lib/gopher.c
  89. 26 14
      Utilities/cmcurl/lib/hash.c
  90. 5 0
      Utilities/cmcurl/lib/hash.h
  91. 3 3
      Utilities/cmcurl/lib/headers.c
  92. 1 1
      Utilities/cmcurl/lib/hmac.c
  93. 25 25
      Utilities/cmcurl/lib/hostip.c
  94. 4 4
      Utilities/cmcurl/lib/hostip.h
  95. 11 11
      Utilities/cmcurl/lib/hostip4.c
  96. 6 6
      Utilities/cmcurl/lib/hsts.c
  97. 2 2
      Utilities/cmcurl/lib/hsts.h
  98. 158 131
      Utilities/cmcurl/lib/http.c
  99. 3 8
      Utilities/cmcurl/lib/http.h
  100. 1 1
      Utilities/cmcurl/lib/http1.c

+ 4 - 3
Utilities/cmcurl/CMake/CurlSymbolHiding.cmake

@@ -26,9 +26,10 @@ include(CheckCSourceCompiles)
 option(CURL_HIDDEN_SYMBOLS "Set to ON to hide libcurl internal symbols (=hide all symbols that aren't officially external)." ON)
 mark_as_advanced(CURL_HIDDEN_SYMBOLS)
 
-if(WIN32 AND ENABLE_CURLDEBUG)
-  # We need to export internal debug functions (e.g. curl_dbg_*), so disable
-  # symbol hiding for debug builds.
+if(WIN32 AND (ENABLE_DEBUG OR ENABLE_CURLDEBUG))
+  # We need to export internal debug functions,
+  # e.g. curl_easy_perform_ev() or curl_dbg_*(),
+  # so disable symbol hiding for debug builds and for memory tracking.
   set(CURL_HIDDEN_SYMBOLS OFF)
 endif()
 

+ 1 - 1
Utilities/cmcurl/CMake/CurlTests.c

@@ -380,7 +380,7 @@ int main(void)
 #ifdef HAVE_BUILTIN_AVAILABLE
 int main(void)
 {
-  if(__builtin_available(macOS 10.12, *)) {}
+  if(__builtin_available(macOS 10.12, iOS 5.0, *)) {}
   return 0;
 }
 #endif

+ 1 - 1
Utilities/cmcurl/CMake/FindBearSSL.cmake

@@ -27,6 +27,6 @@ find_library(BEARSSL_LIBRARY bearssl)
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(BEARSSL DEFAULT_MSG
-    BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)
+  BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)
 
 mark_as_advanced(BEARSSL_INCLUDE_DIRS BEARSSL_LIBRARY)

+ 9 - 9
Utilities/cmcurl/CMake/FindBrotli.cmake

@@ -29,15 +29,15 @@ find_library(BROTLICOMMON_LIBRARY NAMES brotlicommon)
 find_library(BROTLIDEC_LIBRARY NAMES brotlidec)
 
 find_package_handle_standard_args(Brotli
-    FOUND_VAR
-      BROTLI_FOUND
-    REQUIRED_VARS
-      BROTLIDEC_LIBRARY
-      BROTLICOMMON_LIBRARY
-      BROTLI_INCLUDE_DIR
-    FAIL_MESSAGE
-      "Could NOT find Brotli"
+  FOUND_VAR
+    BROTLI_FOUND
+  REQUIRED_VARS
+    BROTLIDEC_LIBRARY
+    BROTLICOMMON_LIBRARY
+    BROTLI_INCLUDE_DIR
+  FAIL_MESSAGE
+    "Could NOT find Brotli"
 )
 
 set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
-set(BROTLI_LIBRARIES ${BROTLICOMMON_LIBRARY} ${BROTLIDEC_LIBRARY})
+set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARY} ${BROTLICOMMON_LIBRARY})

+ 1 - 1
Utilities/cmcurl/CMake/FindCARES.cmake

@@ -39,7 +39,7 @@ find_library(CARES_LIBRARY
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(CARES
-    REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR)
+  REQUIRED_VARS CARES_LIBRARY CARES_INCLUDE_DIR)
 
 mark_as_advanced(
   CARES_LIBRARY

+ 56 - 56
Utilities/cmcurl/CMake/FindGSS.cmake

@@ -45,8 +45,8 @@ include(CheckIncludeFiles)
 include(CheckTypeSize)
 
 set(_GSS_ROOT_HINTS
-    "${GSS_ROOT_DIR}"
-    "$ENV{GSS_ROOT_DIR}"
+  "${GSS_ROOT_DIR}"
+  "$ENV{GSS_ROOT_DIR}"
 )
 
 # try to find library using system pkg-config if user didn't specify root dir
@@ -62,30 +62,30 @@ endif()
 
 if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approach.
   find_file(_GSS_CONFIGURE_SCRIPT
-      NAMES
-          "krb5-config"
-      HINTS
-          ${_GSS_ROOT_HINTS}
-      PATH_SUFFIXES
-          bin
-      NO_CMAKE_PATH
-      NO_CMAKE_ENVIRONMENT_PATH
+    NAMES
+      "krb5-config"
+    HINTS
+      ${_GSS_ROOT_HINTS}
+    PATH_SUFFIXES
+      bin
+    NO_CMAKE_PATH
+    NO_CMAKE_ENVIRONMENT_PATH
   )
 
   # if not found in user-supplied directories, maybe system knows better
   find_file(_GSS_CONFIGURE_SCRIPT
-      NAMES
-          "krb5-config"
-      PATH_SUFFIXES
-          bin
+    NAMES
+      "krb5-config"
+    PATH_SUFFIXES
+      bin
   )
 
   if(_GSS_CONFIGURE_SCRIPT)
     execute_process(
-          COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi"
-          OUTPUT_VARIABLE _GSS_CFLAGS
-          RESULT_VARIABLE _GSS_CONFIGURE_FAILED
-          OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--cflags" "gssapi"
+      OUTPUT_VARIABLE _GSS_CFLAGS
+      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+      OUTPUT_STRIP_TRAILING_WHITESPACE
       )
     message(STATUS "CFLAGS: ${_GSS_CFLAGS}")
     if(NOT _GSS_CONFIGURE_FAILED) # 0 means success
@@ -105,10 +105,10 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
     endif()
 
     execute_process(
-        COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi"
-        OUTPUT_VARIABLE _GSS_LIB_FLAGS
-        RESULT_VARIABLE _GSS_CONFIGURE_FAILED
-        OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--libs" "gssapi"
+      OUTPUT_VARIABLE _GSS_LIB_FLAGS
+      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+      OUTPUT_STRIP_TRAILING_WHITESPACE
     )
     message(STATUS "LDFLAGS: ${_GSS_LIB_FLAGS}")
 
@@ -132,10 +132,10 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
     endif()
 
     execute_process(
-        COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version"
-        OUTPUT_VARIABLE _GSS_VERSION
-        RESULT_VARIABLE _GSS_CONFIGURE_FAILED
-        OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--version"
+      OUTPUT_VARIABLE _GSS_VERSION
+      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+      OUTPUT_STRIP_TRAILING_WHITESPACE
     )
 
     # older versions may not have the "--version" parameter. In this case we just don't care.
@@ -144,10 +144,10 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
     endif()
 
     execute_process(
-        COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor"
-        OUTPUT_VARIABLE _GSS_VENDOR
-        RESULT_VARIABLE _GSS_CONFIGURE_FAILED
-        OUTPUT_STRIP_TRAILING_WHITESPACE
+      COMMAND ${_GSS_CONFIGURE_SCRIPT} "--vendor"
+      OUTPUT_VARIABLE _GSS_VENDOR
+      RESULT_VARIABLE _GSS_CONFIGURE_FAILED
+      OUTPUT_STRIP_TRAILING_WHITESPACE
     )
 
     # older versions may not have the "--vendor" parameter. In this case we just don't care.
@@ -164,13 +164,13 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
   else() # either there is no config script or we are on a platform that doesn't provide one (Windows?)
 
     find_path(_GSS_INCLUDE_DIR
-        NAMES
-            "gssapi/gssapi.h"
-        HINTS
-            ${_GSS_ROOT_HINTS}
-        PATH_SUFFIXES
-            include
-            inc
+      NAMES
+        "gssapi/gssapi.h"
+      HINTS
+        ${_GSS_ROOT_HINTS}
+      PATH_SUFFIXES
+        include
+        inc
     )
 
     if(_GSS_INCLUDE_DIR) #jay, we've found something
@@ -193,13 +193,13 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
     else()
       # I'm not convinced if this is the right way but this is what autotools do at the moment
       find_path(_GSS_INCLUDE_DIR
-          NAMES
-              "gssapi.h"
-          HINTS
-              ${_GSS_ROOT_HINTS}
-          PATH_SUFFIXES
-              include
-              inc
+        NAMES
+          "gssapi.h"
+        HINTS
+          ${_GSS_ROOT_HINTS}
+        PATH_SUFFIXES
+          include
+          inc
       )
 
       if(_GSS_INCLUDE_DIR)
@@ -240,12 +240,12 @@ if(NOT _GSS_FOUND) #not found by pkg-config. Let's take more traditional approac
       endif()
 
       find_library(_GSS_LIBRARIES
-          NAMES
-              ${_GSS_LIBNAME}
-          HINTS
-              ${_GSS_LIBDIR_HINTS}
-          PATH_SUFFIXES
-              ${_GSS_LIBDIR_SUFFIXES}
+        NAMES
+          ${_GSS_LIBNAME}
+        HINTS
+          ${_GSS_LIBDIR_HINTS}
+        PATH_SUFFIXES
+          ${_GSS_LIBDIR_SUFFIXES}
       )
 
     endif()
@@ -301,12 +301,12 @@ include(FindPackageHandleStandardArgs)
 set(_GSS_REQUIRED_VARS GSS_LIBRARIES GSS_FLAVOUR)
 
 find_package_handle_standard_args(GSS
-    REQUIRED_VARS
-        ${_GSS_REQUIRED_VARS}
-    VERSION_VAR
-        GSS_VERSION
-    FAIL_MESSAGE
-        "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
+  REQUIRED_VARS
+    ${_GSS_REQUIRED_VARS}
+  VERSION_VAR
+    GSS_VERSION
+  FAIL_MESSAGE
+    "Could NOT find GSS, try to set the path to GSS root folder in the system variable GSS_ROOT_DIR"
 )
 
 mark_as_advanced(GSS_INCLUDE_DIR GSS_LIBRARIES)

+ 2 - 2
Utilities/cmcurl/CMake/FindLibPSL.cmake

@@ -39,7 +39,7 @@ endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(LibPSL
-    REQUIRED_VARS LIBPSL_LIBRARY LIBPSL_INCLUDE_DIR
-    VERSION_VAR LIBPSL_VERSION)
+  REQUIRED_VARS LIBPSL_LIBRARY LIBPSL_INCLUDE_DIR
+  VERSION_VAR LIBPSL_VERSION)
 
 mark_as_advanced(LIBPSL_INCLUDE_DIR LIBPSL_LIBRARY)

+ 2 - 2
Utilities/cmcurl/CMake/FindLibSSH2.cmake

@@ -39,7 +39,7 @@ endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(LibSSH2
-    REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR
-    VERSION_VAR LIBSSH2_VERSION)
+  REQUIRED_VARS LIBSSH2_LIBRARY LIBSSH2_INCLUDE_DIR
+  VERSION_VAR LIBSSH2_VERSION)
 
 mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)

+ 1 - 1
Utilities/cmcurl/CMake/FindMbedTLS.cmake

@@ -31,6 +31,6 @@ set(MBEDTLS_LIBRARIES "${MBEDTLS_LIBRARY}" "${MBEDX509_LIBRARY}" "${MBEDCRYPTO_L
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(MbedTLS DEFAULT_MSG
-    MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
+  MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)
 
 mark_as_advanced(MBEDTLS_INCLUDE_DIRS MBEDTLS_LIBRARY MBEDX509_LIBRARY MBEDCRYPTO_LIBRARY)

+ 5 - 5
Utilities/cmcurl/CMake/FindNGHTTP2.cmake

@@ -28,11 +28,11 @@ find_path(NGHTTP2_INCLUDE_DIR "nghttp2/nghttp2.h")
 find_library(NGHTTP2_LIBRARY NAMES nghttp2 nghttp2_static)
 
 find_package_handle_standard_args(NGHTTP2
-    FOUND_VAR
-      NGHTTP2_FOUND
-    REQUIRED_VARS
-      NGHTTP2_LIBRARY
-      NGHTTP2_INCLUDE_DIR
+  FOUND_VAR
+    NGHTTP2_FOUND
+  REQUIRED_VARS
+    NGHTTP2_LIBRARY
+    NGHTTP2_INCLUDE_DIR
 )
 
 set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR})

+ 30 - 6
Utilities/cmcurl/CMake/FindWolfSSL.cmake

@@ -21,16 +21,40 @@
 # SPDX-License-Identifier: curl
 #
 ###########################################################################
-find_path(WolfSSL_INCLUDE_DIR NAMES wolfssl/ssl.h)
-find_library(WolfSSL_LIBRARY NAMES wolfssl)
-mark_as_advanced(WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY)
+
+find_package(PkgConfig QUIET)
+pkg_check_modules(PC_WOLFSSL QUIET "wolfssl")
+
+find_path(WolfSSL_INCLUDE_DIR
+  NAMES "wolfssl/ssl.h"
+  HINTS ${PC_WOLFSSL_INCLUDE_DIRS}
+)
+
+find_library(WolfSSL_LIBRARY
+  NAMES "wolfssl"
+  HINTS ${PC_WOLFSSL_LIBRARY_DIRS}
+)
+
+if(WolfSSL_INCLUDE_DIR)
+  set(_version_regex "^#define[ \t]+LIBWOLFSSL_VERSION_STRING[ \t]+\"([^\"]+)\".*")
+  file(STRINGS "${WolfSSL_INCLUDE_DIR}/wolfssl/version.h"
+    WolfSSL_VERSION REGEX "${_version_regex}")
+  string(REGEX REPLACE "${_version_regex}" "\\1"
+    WolfSSL_VERSION "${WolfSSL_VERSION}")
+  unset(_version_regex)
+endif()
 
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(WolfSSL
-  REQUIRED_VARS WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY
-  )
+  REQUIRED_VARS
+    WolfSSL_INCLUDE_DIR
+    WolfSSL_LIBRARY
+  VERSION_VAR WolfSSL_VERSION
+)
 
 if(WolfSSL_FOUND)
   set(WolfSSL_INCLUDE_DIRS ${WolfSSL_INCLUDE_DIR})
-  set(WolfSSL_LIBRARIES ${WolfSSL_LIBRARY})
+  set(WolfSSL_LIBRARIES    ${WolfSSL_LIBRARY})
 endif()
+
+mark_as_advanced(WolfSSL_INCLUDE_DIR WolfSSL_LIBRARY)

+ 2 - 2
Utilities/cmcurl/CMake/OtherTests.cmake

@@ -137,7 +137,7 @@ if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
     #ifdef h_errno
       return 0;
     #else
-      force compilation error
+      #error force compilation error
     #endif
     }" HAVE_H_ERRNO)
 
@@ -158,7 +158,7 @@ if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
         #elif defined(_XOPEN_SOURCE) && (_XOPEN_SOURCE >= 700)
           return 0;
         #else
-          force compilation error
+          #error force compilation error
         #endif
         }" HAVE_H_ERRNO_SBS_ISSUE_7)
     endif()

+ 10 - 0
Utilities/cmcurl/CMake/PickyWarnings.cmake

@@ -33,6 +33,16 @@ if(CURL_WERROR AND
   set(WPICKY "${WPICKY} -pedantic-errors")
 endif()
 
+if(APPLE AND
+   (CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
+   (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
+  set(WPICKY "${WPICKY} -Werror=partial-availability")  # clang 3.6  appleclang 6.3
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
+  set(WPICKY "${WPICKY} -Werror-implicit-function-declaration")  # clang 1.0  gcc 2.95
+endif()
+
 if(PICKY_COMPILER)
   if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_C_COMPILER_ID MATCHES "Clang")
 

+ 2 - 1
Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake

@@ -88,6 +88,7 @@ set(HAVE_GETPWUID_R 0)
 set(HAVE_STRERROR_R 0)
 set(HAVE_SIGINTERRUPT 0)
 set(HAVE_PIPE 0)
+set(HAVE_EVENTFD 0)
 set(HAVE_IF_NAMETOINDEX 0)
 set(HAVE_GETRLIMIT 0)
 set(HAVE_SETRLIMIT 0)
@@ -121,6 +122,7 @@ set(HAVE_POLL_H 0)
 set(HAVE_POLL_FINE 0)
 set(HAVE_PWD_H 0)
 set(HAVE_STRINGS_H 0)  # mingw-w64 has it (wrapper to string.h)
+set(HAVE_SYS_EVENTFD_H 0)
 set(HAVE_SYS_FILIO_H 0)
 set(HAVE_SYS_WAIT_H 0)
 set(HAVE_SYS_IOCTL_H 0)
@@ -171,7 +173,6 @@ set(HAVE_IOCTLSOCKET_FIONBIO 1)
 set(HAVE_IOCTL_FIONBIO 0)
 set(HAVE_SETSOCKOPT_SO_NONBLOCK 0)
 set(HAVE_POSIX_STRERROR_R 0)
-set(HAVE_BUILTIN_AVAILABLE 0)
 set(HAVE_MSG_NOSIGNAL 0)
 set(HAVE_STRUCT_TIMEVAL 1)
 set(HAVE_STRUCT_SOCKADDR_STORAGE 1)

+ 4 - 0
Utilities/cmcurl/CMake/curl-config.cmake.in

@@ -38,3 +38,7 @@ check_required_components("@PROJECT_NAME@")
 if(NOT TARGET @PROJECT_NAME@::libcurl)
   add_library(@PROJECT_NAME@::libcurl ALIAS @PROJECT_NAME@::@LIB_SELECTED@)
 endif()
+
+# For compatibility with CMake's FindCURL.cmake
+set(CURL_LIBRARIES @PROJECT_NAME@::libcurl)
+set_and_check(CURL_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")

+ 261 - 175
Utilities/cmcurl/CMakeLists.txt

@@ -223,15 +223,15 @@ string(REGEX REPLACE "[^0]+0x" "" CURL_VERSION_NUM ${CURL_VERSION_NUM})
 
 
 # Setup package meta-data
-# SET(PACKAGE "curl")
+# set(PACKAGE "curl")
 if(0) # This code not needed for building within CMake.
 message(STATUS "curl version=[${CURL_VERSION}]")
 endif()
-# SET(PACKAGE_TARNAME "curl")
-# SET(PACKAGE_NAME "curl")
-# SET(PACKAGE_VERSION "-")
-# SET(PACKAGE_STRING "curl-")
-# SET(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.se/mail/")
+# set(PACKAGE_TARNAME "curl")
+# set(PACKAGE_NAME "curl")
+# set(PACKAGE_VERSION "-")
+# set(PACKAGE_STRING "curl-")
+# set(PACKAGE_BUGREPORT "a suitable curl mailing list => https://curl.se/mail/")
 set(OPERATING_SYSTEM "${CMAKE_SYSTEM_NAME}")
 if(CMAKE_C_COMPILER_TARGET)
   set(OS "\"${CMAKE_C_COMPILER_TARGET}\"")
@@ -274,19 +274,17 @@ option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF)
 
 if(0) # This code not needed for building within CMake.
 cmake_dependent_option(ENABLE_THREADED_RESOLVER "Set to ON to enable threaded DNS lookup"
-        ON "NOT ENABLE_ARES"
-        OFF)
+  ON "NOT ENABLE_ARES"
+  OFF)
 endif()
 
-option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF)
-option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OFF)
-
 include(PickyWarnings)
 
+option(ENABLE_DEBUG "Set to ON to enable curl debug features" OFF)
+option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" ${ENABLE_DEBUG})
+
 if(ENABLE_DEBUG)
-  # DEBUGBUILD will be defined only for Debug builds
-  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS $<$<CONFIG:Debug>:DEBUGBUILD>)
-  set(ENABLE_CURLDEBUG ON)
+  set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS DEBUGBUILD)
 endif()
 
 if(ENABLE_CURLDEBUG)
@@ -328,11 +326,13 @@ endif()
 
 # initialize CURL_LIBS
 set(CURL_LIBS "")
+set(LIBCURL_PC_REQUIRES_PRIVATE "")
 
 if(ENABLE_ARES)
   set(USE_ARES 1)
   find_package(CARES REQUIRED)
   list(APPEND CURL_LIBS ${CARES_LIBRARY})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libcares")
 endif()
 
 if(0) # This code not needed for building within CMake.
@@ -449,6 +449,10 @@ if(HTTP_ONLY)
   set(CURL_DISABLE_TFTP ON)
 endif()
 
+if(WINDOWS_STORE)
+  set(CURL_DISABLE_TELNET ON)  # telnet code needs fixing to compile for UWP.
+endif()
+
 option(ENABLE_IPV6 "Define if you want to enable IPv6 support" ON)
 mark_as_advanced(ENABLE_IPV6)
 if(ENABLE_IPV6 AND NOT WIN32)
@@ -464,7 +468,7 @@ if(ENABLE_IPV6 AND NOT WIN32)
         CACHE BOOL "Define if you want to enable IPv6 support" FORCE)
   endif()
 
-  if(CMAKE_SYSTEM_NAME STREQUAL "Darwin" AND NOT ENABLE_ARES)
+  if(APPLE AND NOT ENABLE_ARES)
     set(use_core_foundation_and_core_services ON)
 
     find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
@@ -597,8 +601,8 @@ endif()
 
 if(CURL_USE_SCHANNEL)
   set(SSL_ENABLED ON)
-  set(USE_SCHANNEL ON) # Windows native SSL/TLS support
-  set(USE_WINDOWS_SSPI ON) # CURL_USE_SCHANNEL implies CURL_WINDOWS_SSPI
+  set(USE_SCHANNEL ON)  # Windows native SSL/TLS support
+  set(USE_WINDOWS_SSPI ON)  # CURL_USE_SCHANNEL implies CURL_WINDOWS_SSPI
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "schannel")
     set(valid_default_ssl_backend TRUE)
@@ -636,7 +640,7 @@ if(use_core_foundation_and_core_services)
     message(FATAL_ERROR "CoreServices framework not found")
   endif()
 
-  list(APPEND CURL_LIBS "-framework CoreFoundation -framework CoreServices")
+  list(APPEND CURL_LIBS "-framework CoreFoundation" "-framework CoreServices")
 endif()
 
 if(CURL_USE_OPENSSL)
@@ -650,10 +654,12 @@ if(CURL_USE_OPENSSL)
   set(USE_OPENSSL ON)
   list(APPEND CURL_LIBS ${OPENSSL_LIBRARIES})
   include_directories(${OPENSSL_INCLUDE_DIR})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "openssl")
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "openssl")
     set(valid_default_ssl_backend TRUE)
   endif()
+  set(curl_ca_bundle_supported TRUE)
 
   set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
   if(NOT DEFINED HAVE_BORINGSSL)
@@ -678,11 +684,13 @@ if(CURL_USE_MBEDTLS)
   set(SSL_ENABLED ON)
   set(USE_MBEDTLS ON)
   list(APPEND CURL_LIBS ${MBEDTLS_LIBRARIES})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "mbedtls")
   include_directories(${MBEDTLS_INCLUDE_DIRS})
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "mbedtls")
     set(valid_default_ssl_backend TRUE)
   endif()
+  set(curl_ca_bundle_supported TRUE)
 endif()
 
 if(CURL_USE_BEARSSL)
@@ -695,6 +703,7 @@ if(CURL_USE_BEARSSL)
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "bearssl")
     set(valid_default_ssl_backend TRUE)
   endif()
+  set(curl_ca_bundle_supported TRUE)
 endif()
 
 if(CURL_USE_WOLFSSL)
@@ -702,11 +711,13 @@ if(CURL_USE_WOLFSSL)
   set(SSL_ENABLED ON)
   set(USE_WOLFSSL ON)
   list(APPEND CURL_LIBS ${WolfSSL_LIBRARIES})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "wolfssl")
   include_directories(${WolfSSL_INCLUDE_DIRS})
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "wolfssl")
     set(valid_default_ssl_backend TRUE)
   endif()
+  set(curl_ca_bundle_supported TRUE)
 endif()
 
 if(CURL_USE_GNUTLS)
@@ -714,11 +725,13 @@ if(CURL_USE_GNUTLS)
   set(SSL_ENABLED ON)
   set(USE_GNUTLS ON)
   list(APPEND CURL_LIBS ${GNUTLS_LIBRARIES} "nettle")
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "gnutls")
   include_directories(${GNUTLS_INCLUDE_DIRS})
 
   if(CURL_DEFAULT_SSL_BACKEND AND CURL_DEFAULT_SSL_BACKEND STREQUAL "gnutls")
     set(valid_default_ssl_backend TRUE)
   endif()
+  set(curl_ca_bundle_supported TRUE)
 
   if(NOT DEFINED HAVE_GNUTLS_SRP AND NOT CURL_DISABLE_SRP)
     cmake_push_check_state()
@@ -757,6 +770,7 @@ if(ZLIB_FOUND)
     include_directories(${ZLIB_INCLUDE_DIRS})
     list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
   endif()
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "zlib")
 endif()
 
 option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
@@ -765,8 +779,8 @@ if(CURL_BROTLI)
   find_package(Brotli REQUIRED)
   if(BROTLI_FOUND)
     set(HAVE_BROTLI ON)
-    set(CURL_LIBS "${BROTLI_LIBRARIES};${CURL_LIBS}")  # For 'ld' linker. Emulate `list(PREPEND ...)` to stay compatible with <v3.15 CMake.
     list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
+    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libbrotlidec")
     include_directories(${BROTLI_INCLUDE_DIRS})
     list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
   endif()
@@ -779,6 +793,7 @@ if(CURL_ZSTD)
   if(Zstd_FOUND AND NOT Zstd_VERSION VERSION_LESS "1.0.0")
     set(HAVE_ZSTD ON)
     list(APPEND CURL_LIBS ${Zstd_LIBRARIES})
+    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libzstd")
     include_directories(${Zstd_INCLUDE_DIRS})
   else()
     message(WARNING "zstd v1.0.0 or newer is required, disabling zstd support.")
@@ -831,6 +846,11 @@ macro(openssl_check_quic)
   endif()
 endmacro()
 
+if(USE_WOLFSSL)
+  openssl_check_symbol_exists(wolfSSL_DES_ecb_encrypt "wolfssl/openssl/des.h" HAVE_WOLFSSL_DES_ECB_ENCRYPT "")
+  openssl_check_symbol_exists(wolfSSL_BIO_set_shutdown "wolfssl/ssl.h" HAVE_WOLFSSL_FULL_BIO "")
+endif()
+
 if(USE_OPENSSL OR USE_WOLFSSL)
   if(NOT DEFINED HAVE_SSL_SET0_WBIO)
     openssl_check_symbol_exists(SSL_set0_wbio "openssl/ssl.h" HAVE_SSL_SET0_WBIO "")
@@ -869,6 +889,7 @@ if(USE_NGHTTP2)
   find_package(NGHTTP2 REQUIRED)
   include_directories(${NGHTTP2_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp2")
 endif()
 
 option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF)
@@ -876,25 +897,31 @@ if(USE_NGTCP2)
   if(USE_OPENSSL OR USE_WOLFSSL)
     if(USE_WOLFSSL)
       find_package(NGTCP2 REQUIRED wolfSSL)
+      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2_crypto_wolfssl")
     elseif(HAVE_BORINGSSL OR HAVE_AWSLC)
       find_package(NGTCP2 REQUIRED BoringSSL)
+      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2_crypto_boringssl")
     else()
       find_package(NGTCP2 REQUIRED quictls)
+      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2_crypto_quictls")
     endif()
     openssl_check_quic()
   elseif(USE_GNUTLS)
     find_package(NGTCP2 REQUIRED GnuTLS)
+    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2_crypto_gnutls")
   else()
     message(FATAL_ERROR "ngtcp2 requires OpenSSL, wolfSSL or GnuTLS")
   endif()
   set(USE_NGTCP2 ON)
   include_directories(${NGTCP2_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NGTCP2_LIBRARIES})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libngtcp2")
 
   find_package(NGHTTP3 REQUIRED)
   set(USE_NGHTTP3 ON)
   include_directories(${NGHTTP3_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp3")
 endif()
 
 option(USE_QUICHE "Use quiche library for HTTP/3 support" OFF)
@@ -910,6 +937,7 @@ if(USE_QUICHE)
   set(USE_QUICHE ON)
   include_directories(${QUICHE_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${QUICHE_LIBRARIES})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "quiche")
   if(NOT DEFINED HAVE_QUICHE_CONN_SET_QLOG_FD)
     cmake_push_check_state()
     set(CMAKE_REQUIRED_INCLUDES   "${QUICHE_INCLUDE_DIRS}")
@@ -927,6 +955,7 @@ if(USE_MSH3)
   set(USE_MSH3 ON)
   include_directories(${MSH3_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${MSH3_LIBRARIES})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libmsh3")
 endif()
 
 option(USE_OPENSSL_QUIC "Use openssl and nghttp3 libraries for HTTP/3 support" OFF)
@@ -934,12 +963,13 @@ if(USE_OPENSSL_QUIC)
   if(USE_NGTCP2 OR USE_QUICHE OR USE_MSH3)
     message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
   endif()
-  find_package(OpenSSL 3.2.0 REQUIRED)
+  find_package(OpenSSL 3.3.0 REQUIRED)
 
   find_package(NGHTTP3 REQUIRED)
   set(USE_NGHTTP3 ON)
   include_directories(${NGHTTP3_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NGHTTP3_LIBRARIES})
+  list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libnghttp3")
 endif()
 
 if(0) # This code not needed for building within CMake.
@@ -959,7 +989,7 @@ if(NOT CURL_DISABLE_SRP AND (HAVE_GNUTLS_SRP OR HAVE_OPENSSL_SRP))
 endif()
 
 if(NOT CURL_DISABLE_LDAP)
-  if(WIN32)
+  if(WIN32 AND NOT WINDOWS_STORE)
     option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
     if(USE_WIN32_LDAP)
       list(APPEND CURL_LIBS "wldap32")
@@ -1072,9 +1102,22 @@ option(USE_LIBIDN2 "Use libidn2 for IDN support" ON)
 if(USE_LIBIDN2)
   check_library_exists("idn2" "idn2_lookup_ul" "" HAVE_LIBIDN2)
   if(HAVE_LIBIDN2)
-    set(CURL_LIBS "idn2;${CURL_LIBS}")
+    set(LIBIDN2_LINK_LIBRARIES "idn2")
     check_include_file_concat("idn2.h" HAVE_IDN2_H)
   endif()
+  if(NOT HAVE_LIBIDN2 OR NOT HAVE_IDN2_H)
+    find_package(PkgConfig QUIET)
+    pkg_check_modules(LIBIDN2 "libidn2")
+    if(LIBIDN2_FOUND)
+      include_directories(${LIBIDN2_INCLUDE_DIRS})
+      set(HAVE_LIBIDN2 ON)
+      set(HAVE_IDN2_H ON)
+    endif()
+  endif()
+  if(HAVE_LIBIDN2 AND HAVE_IDN2_H)
+    set(CURL_LIBS "${LIBIDN2_LINK_LIBRARIES};${CURL_LIBS}")
+    set(LIBCURL_PC_REQUIRES_PRIVATE "libidn2;${LIBCURL_PC_REQUIRES_PRIVATE}")
+  endif()
 else()
   set(HAVE_LIBIDN2 OFF)
 endif()
@@ -1101,8 +1144,8 @@ if(APPLE)
   endif()
 endif()
 
-#libpsl
-option(CURL_USE_LIBPSL "Use libPSL" ON)
+# libpsl
+option(CURL_USE_LIBPSL "Use libpsl" ON)
 mark_as_advanced(CURL_USE_LIBPSL)
 set(USE_LIBPSL OFF)
 
@@ -1110,14 +1153,15 @@ if(CURL_USE_LIBPSL)
   find_package(LibPSL)
   if(LIBPSL_FOUND)
     list(APPEND CURL_LIBS ${LIBPSL_LIBRARY})
+    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libpsl")
     list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBPSL_INCLUDE_DIR}")
     include_directories("${LIBPSL_INCLUDE_DIR}")
     set(USE_LIBPSL ON)
   endif()
 endif()
 
-#libSSH2
-option(CURL_USE_LIBSSH2 "Use libSSH2" ON)
+# libssh2
+option(CURL_USE_LIBSSH2 "Use libssh2" ON)
 mark_as_advanced(CURL_USE_LIBSSH2)
 set(USE_LIBSSH2 OFF)
 
@@ -1125,6 +1169,7 @@ if(CURL_USE_LIBSSH2)
   find_package(LibSSH2)
   if(LIBSSH2_FOUND)
     list(APPEND CURL_LIBS ${LIBSSH2_LIBRARY})
+    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libssh2")
     list(APPEND CMAKE_REQUIRED_INCLUDES "${LIBSSH2_INCLUDE_DIR}")
     include_directories("${LIBSSH2_INCLUDE_DIR}")
     set(USE_LIBSSH2 ON)
@@ -1132,7 +1177,7 @@ if(CURL_USE_LIBSSH2)
 endif()
 
 # libssh
-option(CURL_USE_LIBSSH "Use libSSH" OFF)
+option(CURL_USE_LIBSSH "Use libssh" OFF)
 mark_as_advanced(CURL_USE_LIBSSH)
 if(NOT USE_LIBSSH2 AND CURL_USE_LIBSSH)
   find_package(libssh CONFIG)
@@ -1140,10 +1185,20 @@ if(NOT USE_LIBSSH2 AND CURL_USE_LIBSSH)
     message(STATUS "Found libssh ${libssh_VERSION}")
     # Use imported target for include and library paths.
     list(APPEND CURL_LIBS ssh)
+    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "libssh")
     set(USE_LIBSSH ON)
   endif()
 endif()
 
+option(CURL_USE_GSASL "Use GSASL implementation" OFF)
+mark_as_advanced(CURL_USE_GSASL)
+if(CURL_USE_GSASL)
+  find_package(PkgConfig REQUIRED)
+  pkg_check_modules(GSASL REQUIRED libgsasl)
+  list(APPEND CURL_LIBS ${GSASL_LINK_LIBRARIES})
+  set(USE_GSASL ON)
+endif()
+
 option(CURL_USE_GSSAPI "Use GSSAPI implementation (right now only Heimdal is supported with CMake build)" OFF)
 mark_as_advanced(CURL_USE_GSSAPI)
 
@@ -1198,7 +1253,9 @@ if(CURL_USE_GSSAPI)
     set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
     set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${GSS_LINKER_FLAGS}")
     list(APPEND CURL_LIBS ${GSS_LIBRARIES})
-
+    if(GSS_FLAVOUR STREQUAL "MIT")
+      list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "mit-krb5-gssapi")
+    endif()
   else()
     message(WARNING "GSSAPI support has been requested but no supporting libraries found. Skipping.")
   endif()
@@ -1215,6 +1272,7 @@ if(USE_LIBRTMP)
   cmake_pop_check_state()
   if(HAVE_LIBRTMP)
     list(APPEND CURL_LIBS "rtmp")
+    list(APPEND LIBCURL_PC_REQUIRES_PRIVATE "librtmp")
     if(WIN32)
       list(APPEND CURL_LIBS "winmm")
     endif()
@@ -1236,88 +1294,81 @@ else()
   unset(USE_UNIX_SOCKETS CACHE)
 endif()
 
-
 if(0) # This code not needed for building within CMake.
 #
 # CA handling
 #
-set(CURL_CA_BUNDLE "auto" CACHE STRING
-    "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
-set(CURL_CA_FALLBACK OFF CACHE BOOL
-    "Set ON to use built-in CA store of TLS backend. Defaults to OFF")
-set(CURL_CA_PATH "auto" CACHE STRING
-    "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
-
-if("${CURL_CA_BUNDLE}" STREQUAL "")
-  message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
-elseif("${CURL_CA_BUNDLE}" STREQUAL "none")
-  unset(CURL_CA_BUNDLE CACHE)
-elseif("${CURL_CA_BUNDLE}" STREQUAL "auto")
-  unset(CURL_CA_BUNDLE CACHE)
-  if(NOT CMAKE_CROSSCOMPILING)
-    set(CURL_CA_BUNDLE_AUTODETECT TRUE)
+if(curl_ca_bundle_supported)
+  set(CURL_CA_BUNDLE "auto" CACHE STRING
+      "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
+  set(CURL_CA_FALLBACK OFF CACHE BOOL
+      "Set ON to use built-in CA store of TLS backend. Defaults to OFF")
+  set(CURL_CA_PATH "auto" CACHE STRING
+      "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
+
+  if(CURL_CA_BUNDLE STREQUAL "")
+    message(FATAL_ERROR "Invalid value of CURL_CA_BUNDLE. Use 'none', 'auto' or file path.")
+  elseif(CURL_CA_BUNDLE STREQUAL "none")
+    unset(CURL_CA_BUNDLE CACHE)
+  elseif(CURL_CA_BUNDLE STREQUAL "auto")
+    unset(CURL_CA_BUNDLE CACHE)
+    if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32)
+      set(CURL_CA_BUNDLE_AUTODETECT TRUE)
+    endif()
+  else()
+    set(CURL_CA_BUNDLE_SET TRUE)
   endif()
-else()
-  set(CURL_CA_BUNDLE_SET TRUE)
-endif()
 
-if("${CURL_CA_PATH}" STREQUAL "")
-  message(FATAL_ERROR "Invalid value of CURL_CA_PATH. Use 'none', 'auto' or directory path.")
-elseif("${CURL_CA_PATH}" STREQUAL "none")
-  unset(CURL_CA_PATH CACHE)
-elseif("${CURL_CA_PATH}" STREQUAL "auto")
-  unset(CURL_CA_PATH CACHE)
-  if(NOT CMAKE_CROSSCOMPILING)
-    set(CURL_CA_PATH_AUTODETECT TRUE)
-  endif()
-else()
-  set(CURL_CA_PATH_SET TRUE)
-endif()
-
-if(CURL_CA_BUNDLE_SET AND CURL_CA_PATH_AUTODETECT)
-  # Skip autodetection of unset CA path because CA bundle is set explicitly
-elseif(CURL_CA_PATH_SET AND CURL_CA_BUNDLE_AUTODETECT)
-  # Skip autodetection of unset CA bundle because CA path is set explicitly
-elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT)
-  # first try autodetecting a CA bundle, then a CA path
-
-  if(CURL_CA_BUNDLE_AUTODETECT)
-    set(SEARCH_CA_BUNDLE_PATHS
-        /etc/ssl/certs/ca-certificates.crt
-        /etc/pki/tls/certs/ca-bundle.crt
-        /usr/share/ssl/certs/ca-bundle.crt
-        /usr/local/share/certs/ca-root-nss.crt
-        /etc/ssl/cert.pem)
-
-    foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS})
-      if(EXISTS "${SEARCH_CA_BUNDLE_PATH}")
-        message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}")
-        set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}" CACHE STRING
-            "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
-        set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
-        break()
-      endif()
-    endforeach()
-  endif()
+  if(CURL_CA_PATH STREQUAL "")
+    message(FATAL_ERROR "Invalid value of CURL_CA_PATH. Use 'none', 'auto' or directory path.")
+  elseif(CURL_CA_PATH STREQUAL "none")
+    unset(CURL_CA_PATH CACHE)
+  elseif(CURL_CA_PATH STREQUAL "auto")
+    unset(CURL_CA_PATH CACHE)
+    if(NOT CMAKE_CROSSCOMPILING AND NOT WIN32)
+      set(CURL_CA_PATH_AUTODETECT TRUE)
+    endif()
+  else()
+    set(CURL_CA_PATH_SET TRUE)
+  endif()
+
+  if(CURL_CA_BUNDLE_SET AND CURL_CA_PATH_AUTODETECT)
+    # Skip auto-detection of unset CA path because CA bundle is set explicitly
+  elseif(CURL_CA_PATH_SET AND CURL_CA_BUNDLE_AUTODETECT)
+    # Skip auto-detection of unset CA bundle because CA path is set explicitly
+  elseif(CURL_CA_BUNDLE_AUTODETECT OR CURL_CA_PATH_AUTODETECT)
+    # First try auto-detecting a CA bundle, then a CA path
+
+    if(CURL_CA_BUNDLE_AUTODETECT)
+      foreach(SEARCH_CA_BUNDLE_PATH IN ITEMS
+          "/etc/ssl/certs/ca-certificates.crt"
+          "/etc/pki/tls/certs/ca-bundle.crt"
+          "/usr/share/ssl/certs/ca-bundle.crt"
+          "/usr/local/share/certs/ca-root-nss.crt"
+          "/etc/ssl/cert.pem")
+        if(EXISTS "${SEARCH_CA_BUNDLE_PATH}")
+          message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}")
+          set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}" CACHE STRING
+              "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
+          set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
+          break()
+        endif()
+      endforeach()
+    endif()
 
-  if(CURL_CA_PATH_AUTODETECT AND (NOT CURL_CA_PATH_SET))
-    if(EXISTS "/etc/ssl/certs")
-      set(CURL_CA_PATH "/etc/ssl/certs" CACHE STRING
-          "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
-      set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
+    if(CURL_CA_PATH_AUTODETECT AND NOT CURL_CA_PATH_SET)
+      set(SEARCH_CA_PATH "/etc/ssl/certs")
+      file(GLOB curl_ca_files_found "${SEARCH_CA_PATH}/[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].0")
+      if(curl_ca_files_found)
+        unset(curl_ca_files_found)
+        message(STATUS "Found CA path: ${SEARCH_CA_PATH}")
+        set(CURL_CA_PATH "${SEARCH_CA_PATH}" CACHE STRING
+            "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
+        set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
+      endif()
     endif()
   endif()
 endif()
-
-if(CURL_CA_PATH_SET AND
-   NOT USE_OPENSSL AND
-   NOT USE_WOLFSSL AND
-   NOT USE_GNUTLS AND
-   NOT USE_MBEDTLS)
-  message(STATUS
-          "CA path only supported by OpenSSL, wolfSSL, GnuTLS or mbedTLS. "
-          "Set CURL_CA_PATH=none or enable one of those TLS backends.")
-endif()
 endif()
 
 # Check for header files
@@ -1361,6 +1412,7 @@ if(WIN32)
   endif()
 endif()
 
+check_include_file_concat("sys/eventfd.h"    HAVE_SYS_EVENTFD_H)
 check_include_file_concat("sys/filio.h"      HAVE_SYS_FILIO_H)
 check_include_file_concat("sys/wait.h"       HAVE_SYS_WAIT_H)
 check_include_file_concat("sys/ioctl.h"      HAVE_SYS_IOCTL_H)
@@ -1467,6 +1519,7 @@ check_symbol_exists(getaddrinfo    "${CURL_INCLUDES};stdlib.h;string.h" HAVE_GET
 check_symbol_exists(getifaddrs     "${CURL_INCLUDES};stdlib.h" HAVE_GETIFADDRS)
 check_symbol_exists(freeaddrinfo   "${CURL_INCLUDES}" HAVE_FREEADDRINFO)
 check_symbol_exists(pipe           "${CURL_INCLUDES}" HAVE_PIPE)
+check_symbol_exists(eventfd        "${CURL_INCLUDES};sys/eventfd.h" HAVE_EVENTFD)
 check_symbol_exists(ftruncate      "${CURL_INCLUDES}" HAVE_FTRUNCATE)
 check_symbol_exists(_fseeki64      "${CURL_INCLUDES};stdio.h" HAVE__FSEEKI64)
 check_symbol_exists(getpeername    "${CURL_INCLUDES}" HAVE_GETPEERNAME)
@@ -1618,8 +1671,10 @@ if(NOT WIN32)
   curl_internal_test(HAVE_CLOCK_GETTIME_MONOTONIC)
 endif()
 
-# Check compiler support of __builtin_available()
-curl_internal_test(HAVE_BUILTIN_AVAILABLE)
+if(APPLE)
+  # Check compiler support of __builtin_available()
+  curl_internal_test(HAVE_BUILTIN_AVAILABLE)
+endif()
 
 # Some other minor tests
 
@@ -1630,9 +1685,9 @@ endif()
 # Check for nonblocking
 set(HAVE_DISABLED_NONBLOCKING 1)
 if(HAVE_FIONBIO OR
-    HAVE_IOCTLSOCKET OR
-    HAVE_IOCTLSOCKET_CASE OR
-    HAVE_O_NONBLOCK)
+   HAVE_IOCTLSOCKET OR
+   HAVE_IOCTLSOCKET_CASE OR
+   HAVE_O_NONBLOCK)
   set(HAVE_DISABLED_NONBLOCKING)
 endif()
 
@@ -1640,7 +1695,7 @@ if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
   include(CheckCCompilerFlag)
   check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double)
   if(HAVE_C_FLAG_Wno_long_double)
-    # The Mac version of GCC warns about use of long double.  Disable it.
+    # The Mac version of GCC warns about use of long double. Disable it.
     get_source_file_property(MPRINTF_COMPILE_FLAGS mprintf.c COMPILE_FLAGS)
     if(MPRINTF_COMPILE_FLAGS)
       set(MPRINTF_COMPILE_FLAGS "${MPRINTF_COMPILE_FLAGS} -Wno-long-double")
@@ -1719,7 +1774,8 @@ if(CURL_LTO)
 endif()
 
 
-# Ugly (but functional) way to include "Makefile.inc" by transforming it (= regenerate it).
+# Ugly (but functional) way to include "Makefile.inc" by transforming it
+# (= regenerate it).
 function(transform_makefile_inc INPUT_FILE OUTPUT_FILE)
   file(READ ${INPUT_FILE} MAKEFILE_INC_TEXT)
   string(REPLACE "$(top_srcdir)"   "\${CURL_SOURCE_DIR}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
@@ -1729,8 +1785,8 @@ function(transform_makefile_inc INPUT_FILE OUTPUT_FILE)
   string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
   string(REPLACE "!π!α!" "\n" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})
 
-  string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})    # Replace $() with ${}
-  string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})    # Replace @@ with ${}, even if that may not be read by CMake scripts.
+  string(REGEX REPLACE "\\$\\(([a-zA-Z_][a-zA-Z0-9_]*)\\)" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})  # Replace $() with ${}
+  string(REGEX REPLACE "@([a-zA-Z_][a-zA-Z0-9_]*)@" "\${\\1}" MAKEFILE_INC_TEXT ${MAKEFILE_INC_TEXT})  # Replace @@ with ${}, even if that may not be read by CMake scripts.
   file(WRITE ${OUTPUT_FILE} ${MAKEFILE_INC_TEXT})
   set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS "${INPUT_FILE}")
 endfunction()
@@ -1791,8 +1847,8 @@ if(NOT CURL_DISABLE_INSTALL)
             GROUP_READ GROUP_EXECUTE
             WORLD_READ WORLD_EXECUTE)
 
-  # Helper to populate a list (_items) with a label when conditions (the remaining
-  # args) are satisfied
+  # Helper to populate a list (_items) with a label when conditions
+  # (the remaining args) are satisfied
   macro(_add_if label)
     # needs to be a macro to allow this indirection
     if(${ARGN})
@@ -1800,58 +1856,24 @@ if(NOT CURL_DISABLE_INSTALL)
     endif()
   endmacro()
 
-  # NTLM support requires crypto function adaptions from various SSL libs
-  if(NOT (CURL_DISABLE_NTLM) AND
-      (USE_OPENSSL OR USE_MBEDTLS OR USE_DARWINSSL OR USE_WIN32_CRYPTO OR USE_GNUTLS))
+  # NTLM support requires crypto functions from various SSL libs.
+  # These conditions must match those in lib/curl_setup.h.
+  if(NOT CURL_DISABLE_NTLM AND
+     (USE_OPENSSL OR
+      USE_MBEDTLS OR
+      USE_GNUTLS OR
+      USE_SECTRANSP OR
+      USE_WIN32_CRYPTO OR
+      (USE_WOLFSSL AND HAVE_WOLFSSL_DES_ECB_ENCRYPT)))
     set(use_curl_ntlm_core ON)
   endif()
 
-  # Clear list and try to detect available features
-  set(_items)
-  _add_if("SSL"           SSL_ENABLED)
-  _add_if("IPv6"          ENABLE_IPV6)
-  _add_if("UnixSockets"   USE_UNIX_SOCKETS)
-  _add_if("libz"          HAVE_LIBZ)
-  _add_if("brotli"        HAVE_BROTLI)
-  _add_if("zstd"          HAVE_ZSTD)
-  _add_if("AsynchDNS"     USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
-  _add_if("IDN"           HAVE_LIBIDN2 OR USE_WIN32_IDN OR USE_APPLE_IDN)
-  _add_if("Largefile"     (SIZEOF_CURL_OFF_T GREATER 4) AND
-                          ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
-  _add_if("SSPI"          USE_WINDOWS_SSPI)
-  _add_if("GSS-API"       HAVE_GSSAPI)
-  _add_if("alt-svc"       NOT CURL_DISABLE_ALTSVC)
-  _add_if("HSTS"          NOT CURL_DISABLE_HSTS)
-  _add_if("SPNEGO"        NOT CURL_DISABLE_NEGOTIATE_AUTH AND
-                          (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
-  _add_if("Kerberos"      NOT CURL_DISABLE_KERBEROS_AUTH AND
-                          (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
-  _add_if("NTLM"          NOT (CURL_DISABLE_NTLM) AND
-                          (use_curl_ntlm_core OR USE_WINDOWS_SSPI))
-  _add_if("TLS-SRP"       USE_TLS_SRP)
-  _add_if("HTTP2"         USE_NGHTTP2)
-  _add_if("HTTP3"         USE_NGTCP2 OR USE_QUICHE OR USE_OPENSSL_QUIC)
-  _add_if("MultiSSL"      CURL_WITH_MULTI_SSL)
-  # TODO wolfSSL only support this from v5.0.0 onwards
-  _add_if("HTTPS-proxy"   SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS
-                          OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
-                          USE_MBEDTLS OR USE_SECTRANSP))
-  _add_if("unicode"       ENABLE_UNICODE)
-  _add_if("threadsafe"    HAVE_ATOMIC OR
-                          (USE_THREADS_POSIX AND HAVE_PTHREAD_H) OR
-                          (WIN32 AND HAVE_WIN32_WINNT GREATER_EQUAL 0x600))
-  _add_if("PSL"           USE_LIBPSL)
-  string(REPLACE ";" " " SUPPORT_FEATURES "${_items}")
-  message(STATUS "Enabled features: ${SUPPORT_FEATURES}")
-
   # Clear list and try to detect available protocols
   set(_items)
   _add_if("HTTP"          NOT CURL_DISABLE_HTTP)
   _add_if("IPFS"          NOT CURL_DISABLE_HTTP)
   _add_if("IPNS"          NOT CURL_DISABLE_HTTP)
   _add_if("HTTPS"         NOT CURL_DISABLE_HTTP AND SSL_ENABLED)
-  _add_if("ECH"           HAVE_ECH)
-  _add_if("HTTPSRR"       HAVE_ECH)
   _add_if("FTP"           NOT CURL_DISABLE_FTP)
   _add_if("FTPS"          NOT CURL_DISABLE_FTP AND SSL_ENABLED)
   _add_if("FILE"          NOT CURL_DISABLE_FILE)
@@ -1881,12 +1903,64 @@ if(NOT CURL_DISABLE_INSTALL)
   _add_if("RTMP"          USE_LIBRTMP)
   _add_if("MQTT"          NOT CURL_DISABLE_MQTT)
   _add_if("WS"            USE_WEBSOCKETS)
-  _add_if("WSS"           USE_WEBSOCKETS)
+  _add_if("WSS"           USE_WEBSOCKETS AND SSL_ENABLED)
   if(_items)
     list(SORT _items)
   endif()
   string(REPLACE ";" " " SUPPORT_PROTOCOLS "${_items}")
-  message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}")
+  string(TOLOWER "${SUPPORT_PROTOCOLS}" SUPPORT_PROTOCOLS_LOWER)
+  message(STATUS "Protocols: ${SUPPORT_PROTOCOLS_LOWER}")
+
+  # Clear list and try to detect available features
+  set(_items)
+  _add_if("SSL"           SSL_ENABLED)
+  _add_if("IPv6"          ENABLE_IPV6)
+  _add_if("UnixSockets"   USE_UNIX_SOCKETS)
+  _add_if("libz"          HAVE_LIBZ)
+  _add_if("brotli"        HAVE_BROTLI)
+  _add_if("gsasl"         USE_GSASL)
+  _add_if("zstd"          HAVE_ZSTD)
+  _add_if("AsynchDNS"     USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
+  _add_if("IDN"           (HAVE_LIBIDN2 AND HAVE_IDN2_H) OR
+                          USE_WIN32_IDN OR
+                          USE_APPLE_IDN)
+  _add_if("Largefile"     (SIZEOF_CURL_OFF_T GREATER 4) AND
+                          ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
+  _add_if("SSPI"          USE_WINDOWS_SSPI)
+  _add_if("GSS-API"       HAVE_GSSAPI)
+  _add_if("alt-svc"       NOT CURL_DISABLE_ALTSVC)
+  _add_if("HSTS"          NOT CURL_DISABLE_HSTS)
+  _add_if("SPNEGO"        NOT CURL_DISABLE_NEGOTIATE_AUTH AND
+                          (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
+  _add_if("Kerberos"      NOT CURL_DISABLE_KERBEROS_AUTH AND
+                          (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
+  _add_if("NTLM"          NOT (CURL_DISABLE_NTLM) AND
+                          (use_curl_ntlm_core OR USE_WINDOWS_SSPI))
+  _add_if("TLS-SRP"       USE_TLS_SRP)
+  _add_if("HTTP2"         USE_NGHTTP2)
+  _add_if("HTTP3"         USE_NGTCP2 OR USE_QUICHE OR USE_OPENSSL_QUIC)
+  _add_if("MultiSSL"      CURL_WITH_MULTI_SSL)
+  _add_if("HTTPS-proxy"   SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS
+                          OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
+                          USE_MBEDTLS OR USE_SECTRANSP OR
+                          (USE_WOLFSSL AND HAVE_WOLFSSL_FULL_BIO)))
+  _add_if("Unicode"       ENABLE_UNICODE)
+  _add_if("threadsafe"    HAVE_ATOMIC OR
+                          (USE_THREADS_POSIX AND HAVE_PTHREAD_H) OR
+                          (WIN32 AND HAVE_WIN32_WINNT GREATER_EQUAL 0x600))
+  _add_if("Debug"         ENABLE_DEBUG)
+  _add_if("TrackMemory"   ENABLE_CURLDEBUG)
+  _add_if("ECH"           SSL_ENABLED AND HAVE_ECH)
+  _add_if("PSL"           USE_LIBPSL)
+  if(_items)
+    if(NOT CMAKE_VERSION VERSION_LESS 3.13)
+      list(SORT _items CASE INSENSITIVE)
+    else()
+      list(SORT _items)
+    endif()
+  endif()
+  string(REPLACE ";" " " SUPPORT_FEATURES "${_items}")
+  message(STATUS "Features: ${SUPPORT_FEATURES}")
 
   # Clear list and collect SSL backends
   set(_items)
@@ -1899,7 +1973,11 @@ if(NOT CURL_DISABLE_INSTALL)
   _add_if("GnuTLS"           SSL_ENABLED AND USE_GNUTLS)
 
   if(_items)
-    list(SORT _items)
+    if(NOT CMAKE_VERSION VERSION_LESS 3.13)
+      list(SORT _items CASE INSENSITIVE)
+    else()
+      list(SORT _items)
+    endif()
   endif()
   string(REPLACE ";" " " SSL_BACKENDS "${_items}")
   message(STATUS "Enabled SSL backends: ${SSL_BACKENDS}")
@@ -1978,12 +2056,21 @@ if(NOT CURL_DISABLE_INSTALL)
       set(LIBCURL_LIBS          "${LIBCURL_LIBS} -l${_lib}")
     endif()
   endforeach()
+
+  # Export a .pc file for client projects not using CMake
+  if(LIBCURL_PC_REQUIRES_PRIVATE)
+    string(REPLACE ";" "," LIBCURL_PC_REQUIRES_PRIVATE "${LIBCURL_PC_REQUIRES_PRIVATE}")
+  endif()
+
+  # Merge pkg-config private fields into public ones when static-only
   if(BUILD_SHARED_LIBS)
     set(ENABLE_SHARED         "yes")
+    set(LIBCURL_PC_REQUIRES   "")
     set(LIBCURL_NO_SHARED     "")
     set(CPPFLAG_CURL_STATICLIB "")
   else()
     set(ENABLE_SHARED         "no")
+    set(LIBCURL_PC_REQUIRES   "${LIBCURL_PC_REQUIRES_PRIVATE}")
     set(LIBCURL_NO_SHARED     "${LIBCURL_LIBS}")
     set(CPPFLAG_CURL_STATICLIB "-DCURL_STATICLIB")
   endif()
@@ -2006,7 +2093,7 @@ if(NOT CURL_DISABLE_INSTALL)
   # * ENABLE_SHARED
   # * ENABLE_STATIC
   configure_file("${CURL_SOURCE_DIR}/curl-config.in"
-                "${CURL_BINARY_DIR}/curl-config" @ONLY)
+                 "${CURL_BINARY_DIR}/curl-config" @ONLY)
   install(FILES "${CURL_BINARY_DIR}/curl-config"
           DESTINATION ${CMAKE_INSTALL_BINDIR}
           PERMISSIONS
@@ -2016,7 +2103,7 @@ if(NOT CURL_DISABLE_INSTALL)
 
   # Finally generate a pkg-config file matching this config
   configure_file("${CURL_SOURCE_DIR}/libcurl.pc.in"
-                "${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
+                 "${CURL_BINARY_DIR}/libcurl.pc" @ONLY)
   install(FILES "${CURL_BINARY_DIR}/libcurl.pc"
           DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig)
 
@@ -2032,11 +2119,11 @@ if(NOT CURL_DISABLE_INSTALL)
       COMPATIBILITY SameMajorVersion
   )
   file(READ "${version_config}" generated_version_config)
-  file(WRITE "${version_config}"
-  "if(NOT PACKAGE_FIND_VERSION_RANGE AND PACKAGE_FIND_VERSION_MAJOR STREQUAL \"7\")
-      # Version 8 satisfies version 7... requirements
-      set(PACKAGE_FIND_VERSION_MAJOR 8)
-      set(PACKAGE_FIND_VERSION_COUNT 1)
+  file(WRITE "${version_config}" "
+  if(NOT PACKAGE_FIND_VERSION_RANGE AND PACKAGE_FIND_VERSION_MAJOR STREQUAL \"7\")
+    # Version 8 satisfies version 7... requirements
+    set(PACKAGE_FIND_VERSION_MAJOR 8)
+    set(PACKAGE_FIND_VERSION_COUNT 1)
   endif()
   ${generated_version_config}"
   )
@@ -2045,20 +2132,19 @@ if(NOT CURL_DISABLE_INSTALL)
   # * TARGETS_EXPORT_NAME
   # * PROJECT_NAME
   configure_package_config_file(CMake/curl-config.cmake.in
-          "${project_config}"
-          INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR}
+    "${project_config}"
+    INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR}
+    PATH_VARS CMAKE_INSTALL_INCLUDEDIR
   )
 
   if(CURL_ENABLE_EXPORT_TARGET)
-    install(
-            EXPORT "${TARGETS_EXPORT_NAME}"
+    install(EXPORT "${TARGETS_EXPORT_NAME}"
             NAMESPACE "${PROJECT_NAME}::"
             DESTINATION ${CURL_INSTALL_CMAKE_DIR}
     )
   endif()
 
-  install(
-          FILES ${version_config} ${project_config}
+  install(FILES ${version_config} ${project_config}
           DESTINATION ${CURL_INSTALL_CMAKE_DIR}
   )
 
@@ -2073,12 +2159,12 @@ if(NOT CURL_DISABLE_INSTALL)
 
   if(NOT TARGET curl_uninstall)
     configure_file(
-        ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in
-        ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake
-        IMMEDIATE @ONLY)
+      ${CMAKE_CURRENT_SOURCE_DIR}/CMake/cmake_uninstall.cmake.in
+      ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake
+      IMMEDIATE @ONLY)
 
     add_custom_target(curl_uninstall
-        COMMAND ${CMAKE_COMMAND} -P
-        ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake)
+      COMMAND ${CMAKE_COMMAND} -P
+      ${CMAKE_CURRENT_BINARY_DIR}/CMake/cmake_uninstall.cmake)
   endif()
 endif()

+ 68 - 57
Utilities/cmcurl/include/curl/curl.h

@@ -34,24 +34,32 @@
 #endif
 
 /* Compile-time deprecation macros. */
-#if defined(__GNUC__) &&                                                \
-  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) &&  \
+#if (defined(__GNUC__) &&                                               \
+  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) ||  \
+  defined(__IAR_SYSTEMS_ICC__)) &&                                      \
   !defined(__INTEL_COMPILER) &&                                         \
   !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
 #define CURL_DEPRECATED(version, message)                       \
   __attribute__((deprecated("since " # version ". " message)))
+#if defined(__IAR_SYSTEMS_ICC__)
+#define CURL_IGNORE_DEPRECATION(statements) \
+      _Pragma("diag_suppress=Pe1444") \
+      statements \
+      _Pragma("diag_default=Pe1444")
+#else
 #define CURL_IGNORE_DEPRECATION(statements) \
       _Pragma("GCC diagnostic push") \
       _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
       statements \
       _Pragma("GCC diagnostic pop")
+#endif
 #else
 #define CURL_DEPRECATED(version, message)
 #define CURL_IGNORE_DEPRECATION(statements)     statements
 #endif
 
 #include "curlver.h"         /* libcurl version defines   */
-#include "system.h"          /* determine things run-time */
+#include "system.h"          /* determine things runtime */
 
 #include <stdio.h>
 #include <limits.h>
@@ -69,7 +77,7 @@
 #if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || \
       defined(__LWIP_OPT_H__) || defined(LWIP_HDR_OPT_H))
 /* The check above prevents the winsock2 inclusion if winsock.h already was
-   included, since they can't co-exist without problems */
+   included, since they cannot co-exist without problems */
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #endif
@@ -189,9 +197,9 @@ struct curl_httppost {
                                        files */
   long flags;                       /* as defined below */
 
-/* specified content is a file name */
+/* specified content is a filename */
 #define CURL_HTTPPOST_FILENAME (1<<0)
-/* specified content is a file name */
+/* specified content is a filename */
 #define CURL_HTTPPOST_READFILE (1<<1)
 /* name is only stored pointer do not free in formfree */
 #define CURL_HTTPPOST_PTRNAME (1<<2)
@@ -207,8 +215,8 @@ struct curl_httppost {
 /* use size in 'contentlen', added in 7.46.0 */
 #define CURL_HTTPPOST_LARGE (1<<7)
 
-  char *showfilename;               /* The file name to show. If not set, the
-                                       actual file name will be used (if this
+  char *showfilename;               /* The filename to show. If not set, the
+                                       actual filename will be used (if this
                                        is a file part) */
   void *userp;                      /* custom pointer used for
                                        HTTPPOST_CALLBACK posts */
@@ -350,13 +358,13 @@ typedef long (*curl_chunk_bgn_callback)(const void *transfer_info,
    download of an individual chunk finished.
    Note! After this callback was set then it have to be called FOR ALL chunks.
    Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
-   This is the reason why we don't need "transfer_info" parameter in this
+   This is the reason why we do not need "transfer_info" parameter in this
    callback and we are not interested in "remains" parameter too. */
 typedef long (*curl_chunk_end_callback)(void *ptr);
 
 /* return codes for FNMATCHFUNCTION */
 #define CURL_FNMATCHFUNC_MATCH    0 /* string corresponds to the pattern */
-#define CURL_FNMATCHFUNC_NOMATCH  1 /* pattern doesn't match the string */
+#define CURL_FNMATCHFUNC_NOMATCH  1 /* pattern does not match the string */
 #define CURL_FNMATCHFUNC_FAIL     2 /* an error occurred */
 
 /* callback type for wildcard downloading pattern matching. If the
@@ -368,7 +376,7 @@ typedef int (*curl_fnmatch_callback)(void *ptr,
 /* These are the return codes for the seek callbacks */
 #define CURL_SEEKFUNC_OK       0
 #define CURL_SEEKFUNC_FAIL     1 /* fail the entire transfer */
-#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
+#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking cannot be done, so
                                     libcurl might try other means instead */
 typedef int (*curl_seek_callback)(void *instream,
                                   curl_off_t offset,
@@ -451,7 +459,7 @@ typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
 #ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS
 /*
  * The following typedef's are signatures of malloc, free, realloc, strdup and
- * calloc respectively.  Function pointers of these types can be passed to the
+ * calloc respectively. Function pointers of these types can be passed to the
  * curl_global_init_mem() function to set user defined memory management
  * callback routines.
  */
@@ -539,17 +547,17 @@ typedef enum {
   CURLE_WRITE_ERROR,             /* 23 */
   CURLE_OBSOLETE24,              /* 24 - NOT USED */
   CURLE_UPLOAD_FAILED,           /* 25 - failed upload "command" */
-  CURLE_READ_ERROR,              /* 26 - couldn't open/read from file */
+  CURLE_READ_ERROR,              /* 26 - could not open/read from file */
   CURLE_OUT_OF_MEMORY,           /* 27 */
   CURLE_OPERATION_TIMEDOUT,      /* 28 - the timeout time was reached */
   CURLE_OBSOLETE29,              /* 29 - NOT USED */
   CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
   CURLE_FTP_COULDNT_USE_REST,    /* 31 - the REST command failed */
   CURLE_OBSOLETE32,              /* 32 - NOT USED */
-  CURLE_RANGE_ERROR,             /* 33 - RANGE "command" didn't work */
+  CURLE_RANGE_ERROR,             /* 33 - RANGE "command" did not work */
   CURLE_HTTP_POST_ERROR,         /* 34 */
   CURLE_SSL_CONNECT_ERROR,       /* 35 - wrong when connecting with SSL */
-  CURLE_BAD_DOWNLOAD_RESUME,     /* 36 - couldn't resume download */
+  CURLE_BAD_DOWNLOAD_RESUME,     /* 36 - could not resume download */
   CURLE_FILE_COULDNT_READ_FILE,  /* 37 */
   CURLE_LDAP_CANNOT_BIND,        /* 38 */
   CURLE_LDAP_SEARCH_FAILED,      /* 39 */
@@ -573,9 +581,9 @@ typedef enum {
   CURLE_RECV_ERROR,              /* 56 - failure in receiving network data */
   CURLE_OBSOLETE57,              /* 57 - NOT IN USE */
   CURLE_SSL_CERTPROBLEM,         /* 58 - problem with the local certificate */
-  CURLE_SSL_CIPHER,              /* 59 - couldn't use specified cipher */
+  CURLE_SSL_CIPHER,              /* 59 - could not use specified cipher */
   CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
-                                     wasn't verified fine */
+                                     was not verified fine */
   CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized/bad encoding */
   CURLE_OBSOLETE62,              /* 62 - NOT IN USE since 7.82.0 */
   CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
@@ -604,7 +612,7 @@ typedef enum {
   CURLE_SSL_SHUTDOWN_FAILED,     /* 80 - Failed to shut down the SSL
                                     connection */
   CURLE_AGAIN,                   /* 81 - socket is not ready for send/recv,
-                                    wait till it's ready and try again (Added
+                                    wait till it is ready and try again (Added
                                     in 7.18.2) */
   CURLE_SSL_CRL_BADFILE,         /* 82 - could not load CRL file, missing or
                                     wrong format (Added in 7.19.0) */
@@ -763,7 +771,7 @@ typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
 
 typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl,    /* easy handle */
                                           void *ssl_ctx, /* actually an OpenSSL
-                                                            or WolfSSL SSL_CTX,
+                                                            or wolfSSL SSL_CTX,
                                                             or an mbedTLS
                                                           mbedtls_ssl_config */
                                           void *userptr);
@@ -780,7 +788,7 @@ typedef enum {
   CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
   CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
   CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
-                                   host name rather than the IP address. added
+                                   hostname rather than the IP address. added
                                    in 7.18.0 */
 } curl_proxytype;  /* this enum was added in 7.10 */
 
@@ -860,7 +868,7 @@ enum curl_khstat {
   CURLKHSTAT_FINE_ADD_TO_FILE,
   CURLKHSTAT_FINE,
   CURLKHSTAT_REJECT, /* reject the connection, return an error */
-  CURLKHSTAT_DEFER,  /* do not accept it, but we can't answer right now.
+  CURLKHSTAT_DEFER,  /* do not accept it, but we cannot answer right now.
                         Causes a CURLE_PEER_FAILED_VERIFICATION error but the
                         connection will be left intact etc */
   CURLKHSTAT_FINE_REPLACE, /* accept and replace the wrong key */
@@ -1080,7 +1088,7 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
 #define CURLOPT(na,t,nu) na = t + nu
 #define CURLOPTDEPRECATED(na,t,nu,v,m) na CURL_DEPRECATED(v,m) = t + nu
 
-/* CURLOPT aliases that make no run-time difference */
+/* CURLOPT aliases that make no runtime difference */
 
 /* 'char *' argument to a string with a trailing zero */
 #define CURLOPTTYPE_STRINGPOINT CURLOPTTYPE_OBJECTPOINT
@@ -1147,7 +1155,7 @@ typedef enum {
    *
    * For large file support, there is also a _LARGE version of the key
    * which takes an off_t type, allowing platforms with larger off_t
-   * sizes to handle larger files.  See below for INFILESIZE_LARGE.
+   * sizes to handle larger files. See below for INFILESIZE_LARGE.
    */
   CURLOPT(CURLOPT_INFILESIZE, CURLOPTTYPE_LONG, 14),
 
@@ -1180,7 +1188,7 @@ typedef enum {
    *
    * Note there is also a _LARGE version of this key which uses
    * off_t types, allowing for large file offsets on platforms which
-   * use larger-than-32-bit off_t's.  Look below for RESUME_FROM_LARGE.
+   * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
    */
   CURLOPT(CURLOPT_RESUME_FROM, CURLOPTTYPE_LONG, 21),
 
@@ -1316,9 +1324,9 @@ typedef enum {
   /* Set the interface string to use as outgoing network interface */
   CURLOPT(CURLOPT_INTERFACE, CURLOPTTYPE_STRINGPOINT, 62),
 
-  /* Set the krb4/5 security level, this also enables krb4/5 awareness.  This
-   * is a string, 'clear', 'safe', 'confidential' or 'private'.  If the string
-   * is set but doesn't match one of these, 'private' will be used.  */
+  /* Set the krb4/5 security level, this also enables krb4/5 awareness. This
+   * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string
+   * is set but does not match one of these, 'private' will be used.  */
   CURLOPT(CURLOPT_KRBLEVEL, CURLOPTTYPE_STRINGPOINT, 63),
 
   /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
@@ -1350,16 +1358,16 @@ typedef enum {
   /* 73 = OBSOLETE */
 
   /* Set to explicitly use a new connection for the upcoming transfer.
-     Do not use this unless you're absolutely sure of this, as it makes the
+     Do not use this unless you are absolutely sure of this, as it makes the
      operation slower and is less friendly for the network. */
   CURLOPT(CURLOPT_FRESH_CONNECT, CURLOPTTYPE_LONG, 74),
 
   /* Set to explicitly forbid the upcoming transfer's connection to be reused
-     when done. Do not use this unless you're absolutely sure of this, as it
+     when done. Do not use this unless you are absolutely sure of this, as it
      makes the operation slower and is less friendly for the network. */
   CURLOPT(CURLOPT_FORBID_REUSE, CURLOPTTYPE_LONG, 75),
 
-  /* Set to a file name that contains random data for libcurl to use to
+  /* Set to a filename that contains random data for libcurl to use to
      seed the random engine when doing SSL connects. */
   CURLOPTDEPRECATED(CURLOPT_RANDOM_FILE, CURLOPTTYPE_STRINGPOINT, 76,
                     7.84.0, "Serves no purpose anymore"),
@@ -1386,8 +1394,8 @@ typedef enum {
    * provided hostname. */
   CURLOPT(CURLOPT_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 81),
 
-  /* Specify which file name to write all known cookies in after completed
-     operation. Set file name to "-" (dash) to make it go to stdout. */
+  /* Specify which filename to write all known cookies in after completed
+     operation. Set filename to "-" (dash) to make it go to stdout. */
   CURLOPT(CURLOPT_COOKIEJAR, CURLOPTTYPE_STRINGPOINT, 82),
 
   /* Specify which SSL ciphers to use */
@@ -1486,7 +1494,7 @@ typedef enum {
   CURLOPT(CURLOPT_HTTPAUTH, CURLOPTTYPE_VALUES, 107),
 
   /* Set the ssl context callback function, currently only for OpenSSL or
-     WolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
+     wolfSSL ssl_ctx, or mbedTLS mbedtls_ssl_config in the second argument.
      The function must match the curl_ssl_ctx_callback prototype. */
   CURLOPT(CURLOPT_SSL_CTX_FUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 108),
 
@@ -1506,7 +1514,7 @@ typedef enum {
   CURLOPT(CURLOPT_PROXYAUTH, CURLOPTTYPE_VALUES, 111),
 
   /* Option that changes the timeout, in seconds, associated with getting a
-     response.  This is different from transfer timeout time and essentially
+     response. This is different from transfer timeout time and essentially
      places a demand on the server to acknowledge commands in a timely
      manner. For FTP, SMTP, IMAP and POP3. */
   CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT, CURLOPTTYPE_LONG, 112),
@@ -1520,7 +1528,7 @@ typedef enum {
      an HTTP or FTP server.
 
      Note there is also _LARGE version which adds large file support for
-     platforms which have larger off_t sizes.  See MAXFILESIZE_LARGE below. */
+     platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
   CURLOPT(CURLOPT_MAXFILESIZE, CURLOPTTYPE_LONG, 114),
 
   /* See the comment for INFILESIZE above, but in short, specifies
@@ -1528,17 +1536,17 @@ typedef enum {
    */
   CURLOPT(CURLOPT_INFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 115),
 
-  /* Sets the continuation offset.  There is also a CURLOPTTYPE_LONG version
+  /* Sets the continuation offset. There is also a CURLOPTTYPE_LONG version
    * of this; look above for RESUME_FROM.
    */
   CURLOPT(CURLOPT_RESUME_FROM_LARGE, CURLOPTTYPE_OFF_T, 116),
 
   /* Sets the maximum size of data that will be downloaded from
-   * an HTTP or FTP server.  See MAXFILESIZE above for the LONG version.
+   * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
    */
   CURLOPT(CURLOPT_MAXFILESIZE_LARGE, CURLOPTTYPE_OFF_T, 117),
 
-  /* Set this option to the file name of your .netrc file you want libcurl
+  /* Set this option to the filename of your .netrc file you want libcurl
      to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
      a poor attempt to find the user's home directory and check for a .netrc
      file in there. */
@@ -1685,7 +1693,7 @@ typedef enum {
 
   /* Callback function for opening socket (instead of socket(2)). Optionally,
      callback is able change the address or refuse to connect returning
-     CURL_SOCKET_BAD.  The callback should have type
+     CURL_SOCKET_BAD. The callback should have type
      curl_opensocket_callback */
   CURLOPT(CURLOPT_OPENSOCKETFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 163),
   CURLOPT(CURLOPT_OPENSOCKETDATA, CURLOPTTYPE_CBPOINT, 164),
@@ -1755,7 +1763,7 @@ typedef enum {
   CURLOPTDEPRECATED(CURLOPT_REDIR_PROTOCOLS, CURLOPTTYPE_LONG, 182,
                     7.85.0, "Use CURLOPT_REDIR_PROTOCOLS_STR"),
 
-  /* set the SSH knownhost file name to use */
+  /* set the SSH knownhost filename to use */
   CURLOPT(CURLOPT_SSH_KNOWNHOSTS, CURLOPTTYPE_STRINGPOINT, 183),
 
   /* set the SSH host key callback, must point to a curl_sshkeycallback
@@ -1836,7 +1844,7 @@ typedef enum {
      future libcurl release.
 
      libcurl will ask for the compressed methods it knows of, and if that
-     isn't any, it will not ask for transfer-encoding at all even if this
+     is not any, it will not ask for transfer-encoding at all even if this
      option is set to 1.
 
   */
@@ -1938,7 +1946,7 @@ typedef enum {
   /* Service Name */
   CURLOPT(CURLOPT_SERVICE_NAME, CURLOPTTYPE_STRINGPOINT, 236),
 
-  /* Wait/don't wait for pipe/mutex to clarify */
+  /* Wait/do not wait for pipe/mutex to clarify */
   CURLOPT(CURLOPT_PIPEWAIT, CURLOPTTYPE_LONG, 237),
 
   /* Set the protocol used when curl is given a URL without a protocol */
@@ -2099,7 +2107,7 @@ typedef enum {
   /* alt-svc control bitmask */
   CURLOPT(CURLOPT_ALTSVC_CTRL, CURLOPTTYPE_LONG, 286),
 
-  /* alt-svc cache file name to possibly read from/write to */
+  /* alt-svc cache filename to possibly read from/write to */
   CURLOPT(CURLOPT_ALTSVC, CURLOPTTYPE_STRINGPOINT, 287),
 
   /* maximum age (idle time) of a connection to consider it for reuse
@@ -2131,7 +2139,7 @@ typedef enum {
 
   /* HSTS bitmask */
   CURLOPT(CURLOPT_HSTS_CTRL, CURLOPTTYPE_LONG, 299),
-  /* HSTS file name */
+  /* HSTS filename */
   CURLOPT(CURLOPT_HSTS, CURLOPTTYPE_STRINGPOINT, 300),
 
   /* HSTS read callback */
@@ -2210,9 +2218,12 @@ typedef enum {
   /* millisecond version */
   CURLOPT(CURLOPT_SERVER_RESPONSE_TIMEOUT_MS, CURLOPTTYPE_LONG, 324),
 
-  /* set ECH configuration  */
+  /* set ECH configuration */
   CURLOPT(CURLOPT_ECH, CURLOPTTYPE_STRINGPOINT, 325),
 
+  /* maximum number of keepalive probes (Linux, *BSD, macOS, etc.) */
+  CURLOPT(CURLOPT_TCP_KEEPCNT, CURLOPTTYPE_LONG, 326),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -2263,9 +2274,9 @@ typedef enum {
 
   /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
 enum {
-  CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
-                             like the library to choose the best possible
-                             for us! */
+  CURL_HTTP_VERSION_NONE, /* setting this means we do not care, and that we
+                             would like the library to choose the best
+                             possible for us! */
   CURL_HTTP_VERSION_1_0,  /* please use HTTP 1.0 in the request */
   CURL_HTTP_VERSION_1_1,  /* please use HTTP 1.1 in the request */
   CURL_HTTP_VERSION_2_0,  /* please use HTTP 2 in the request */
@@ -2425,7 +2436,7 @@ CURL_EXTERN CURLcode curl_mime_name(curl_mimepart *part, const char *name);
  *
  * DESCRIPTION
  *
- * Set mime part remote file name.
+ * Set mime part remote filename.
  */
 CURL_EXTERN CURLcode curl_mime_filename(curl_mimepart *part,
                                         const char *filename);
@@ -2706,10 +2717,10 @@ CURL_EXTERN CURLcode curl_global_init(long flags);
  * DESCRIPTION
  *
  * curl_global_init() or curl_global_init_mem() should be invoked exactly once
- * for each application that uses libcurl.  This function can be used to
+ * for each application that uses libcurl. This function can be used to
  * initialize libcurl and set user defined memory management callback
- * functions.  Users can implement memory management routines to check for
- * memory leaks, check for mis-use of the curl library etc.  User registered
+ * functions. Users can implement memory management routines to check for
+ * memory leaks, check for mis-use of the curl library etc. User registered
  * callback routines will be invoked by this library instead of the system
  * memory management routines like malloc, free etc.
  */
@@ -2827,7 +2838,7 @@ CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
    for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
 struct curl_certinfo {
   int num_of_certs;             /* number of certificates with information */
-  struct curl_slist **certinfo; /* for each index in this array, there's a
+  struct curl_slist **certinfo; /* for each index in this array, there is a
                                    linked list with textual information for a
                                    certificate in the format "name:content".
                                    eg "Subject:foo", "Issuer:bar", etc. */
@@ -3018,7 +3029,7 @@ typedef enum {
 } CURLSHcode;
 
 typedef enum {
-  CURLSHOPT_NONE,  /* don't use */
+  CURLSHOPT_NONE,  /* do not use */
   CURLSHOPT_SHARE,   /* specify a data type to share */
   CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
   CURLSHOPT_LOCKFUNC,   /* pass in a 'curl_lock_function' pointer */
@@ -3177,7 +3188,7 @@ CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
  * DESCRIPTION
  *
  * The curl_easy_strerror function may be used to turn a CURLcode value
- * into the equivalent human readable error string.  This is useful
+ * into the equivalent human readable error string. This is useful
  * for printing meaningful error messages.
  */
 CURL_EXTERN const char *curl_easy_strerror(CURLcode);
@@ -3188,7 +3199,7 @@ CURL_EXTERN const char *curl_easy_strerror(CURLcode);
  * DESCRIPTION
  *
  * The curl_share_strerror function may be used to turn a CURLSHcode value
- * into the equivalent human readable error string.  This is useful
+ * into the equivalent human readable error string. This is useful
  * for printing meaningful error messages.
  */
 CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
@@ -3227,7 +3238,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #include "websockets.h"
 #include "mprintf.h"
 
-/* the typechecker doesn't work in C++ (yet) */
+/* the typechecker does not work in C++ (yet) */
 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
     ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
     !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)

+ 4 - 4
Utilities/cmcurl/include/curl/curlver.h

@@ -32,12 +32,12 @@
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "8.8.0"
+#define LIBCURL_VERSION "8.9.0"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 8
+#define LIBCURL_VERSION_MINOR 9
 #define LIBCURL_VERSION_PATCH 0
 
 /* This is the numeric version of the libcurl version number, meant for easier
@@ -48,7 +48,7 @@
 
    Where XX, YY and ZZ are the main version, release and patch numbers in
    hexadecimal (using 8 bits each). All three numbers are always represented
-   using two digits.  1.2 would appear as "0x010200" while version 9.11.7
+   using two digits. 1.2 would appear as "0x010200" while version 9.11.7
    appears as "0x090b07".
 
    This 6-digit (24 bits) hexadecimal number does not show pre-release number,
@@ -59,7 +59,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x080800
+#define LIBCURL_VERSION_NUM 0x080900
 
 /*
  * This is the date and time when the full source package was created. The

+ 1 - 1
Utilities/cmcurl/include/curl/easy.h

@@ -50,7 +50,7 @@ CURL_EXTERN void curl_easy_cleanup(CURL *curl);
  *
  * Request internal information from the curl session with this function.
  * The third argument MUST be pointing to the specific type of the used option
- * which is documented in each man page of the option. The data pointed to
+ * which is documented in each manpage of the option. The data pointed to
  * will be filled in accordingly and can be relied upon only if the function
  * returns CURLE_OK. This function is intended to get used *AFTER* a performed
  * transfer, all results from this function are undefined until the transfer

+ 2 - 1
Utilities/cmcurl/include/curl/mprintf.h

@@ -32,7 +32,8 @@
 extern "C" {
 #endif
 
-#if (defined(__GNUC__) || defined(__clang__)) &&                        \
+#if (defined(__GNUC__) || defined(__clang__) ||                         \
+  defined(__IAR_SYSTEMS_ICC__)) &&                                      \
   defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) &&         \
   !defined(CURL_NO_FMT_CHECKS)
 #if defined(__MINGW32__) && !defined(__clang__)

+ 8 - 8
Utilities/cmcurl/include/curl/multi.h

@@ -24,7 +24,7 @@
  *
  ***************************************************************************/
 /*
-  This is an "external" header file. Don't give away any internals here!
+  This is an "external" header file. Do not give away any internals here!
 
   GOALS
 
@@ -66,7 +66,7 @@ typedef enum {
   CURLM_OK,
   CURLM_BAD_HANDLE,      /* the passed-in handle is not a valid CURLM handle */
   CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
-  CURLM_OUT_OF_MEMORY,   /* if you ever get this, you're in deep sh*t */
+  CURLM_OUT_OF_MEMORY,   /* if you ever get this, you are in deep sh*t */
   CURLM_INTERNAL_ERROR,  /* this is a libcurl bug */
   CURLM_BAD_SOCKET,      /* the passed in socket argument did not match */
   CURLM_UNKNOWN_OPTION,  /* curl_multi_setopt() with unsupported option */
@@ -109,7 +109,7 @@ struct CURLMsg {
 typedef struct CURLMsg CURLMsg;
 
 /* Based on poll(2) structure and values.
- * We don't use pollfd and POLL* constants explicitly
+ * We do not use pollfd and POLL* constants explicitly
  * to cover platforms without poll(). */
 #define CURL_WAIT_POLLIN    0x0001
 #define CURL_WAIT_POLLPRI   0x0002
@@ -205,7 +205,7 @@ CURL_EXTERN CURLMcode curl_multi_wakeup(CURLM *multi_handle);
  /*
   * Name:    curl_multi_perform()
   *
-  * Desc:    When the app thinks there's data available for curl it calls this
+  * Desc:    When the app thinks there is data available for curl it calls this
   *          function to read/write whatever there is right now. This returns
   *          as soon as the reads and writes are done. This function does not
   *          require that there actually is data available for reading or that
@@ -236,7 +236,7 @@ CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
 /*
  * Name:    curl_multi_info_read()
  *
- * Desc:    Ask the multi handle if there's any messages/informationals from
+ * Desc:    Ask the multi handle if there is any messages/informationals from
  *          the individual transfers. Messages include informationals such as
  *          error code from the transfer or just the fact that a transfer is
  *          completed. More details on these should be written down as well.
@@ -253,7 +253,7 @@ CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
  *          we will provide the particular "transfer handle" in that struct
  *          and that should/could/would be used in subsequent
  *          curl_easy_getinfo() calls (or similar). The point being that we
- *          must never expose complex structs to applications, as then we'll
+ *          must never expose complex structs to applications, as then we will
  *          undoubtably get backwards compatibility problems in the future.
  *
  * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
@@ -268,7 +268,7 @@ CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
  * Name:    curl_multi_strerror()
  *
  * Desc:    The curl_multi_strerror function may be used to turn a CURLMcode
- *          value into the equivalent human readable error string.  This is
+ *          value into the equivalent human readable error string. This is
  *          useful for printing meaningful error messages.
  *
  * Returns: A pointer to a null-terminated error message.
@@ -282,7 +282,7 @@ CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
  * Desc:    An alternative version of curl_multi_perform() that allows the
  *          application to pass in one of the file descriptors that have been
  *          detected to have "action" on them and let libcurl perform.
- *          See man page for details.
+ *          See manpage for details.
  */
 #define CURL_POLL_NONE   0
 #define CURL_POLL_IN     1

+ 2 - 2
Utilities/cmcurl/include/curl/system.h

@@ -46,7 +46,7 @@
  * As a general rule, curl_off_t shall not be mapped to off_t. This rule shall
  * only be violated if off_t is the only 64-bit data type available and the
  * size of off_t is independent of large file support settings. Keep your
- * build on the safe side avoiding an off_t gating.  If you have a 64-bit
+ * build on the safe side avoiding an off_t gating. If you have a 64-bit
  * off_t then take for sure that another 64-bit data type exists, dig deeper
  * and you will find it.
  *
@@ -402,7 +402,7 @@
 #  define CURL_PULL_SYS_SOCKET_H     1
 
 #else
-/* generic "safe guess" on old 32 bit style */
+/* generic "safe guess" on old 32-bit style */
 # define CURL_TYPEOF_CURL_OFF_T     long
 # define CURL_FORMAT_CURL_OFF_T     "ld"
 # define CURL_FORMAT_CURL_OFF_TU    "lu"

+ 5 - 5
Utilities/cmcurl/include/curl/typecheck-gcc.h

@@ -34,11 +34,11 @@
  * _curl_easy_setopt_err_sometype below
  *
  * NOTE: We use two nested 'if' statements here instead of the && operator, in
- *       order to work around gcc bug #32061.  It affects only gcc 4.3.x/4.4.x
+ *       order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x
  *       when compiling with -Wlogical-op.
  *
- * To add an option that uses the same type as an existing option, you'll just
- * need to extend the appropriate _curl_*_option macro
+ * To add an option that uses the same type as an existing option, you will
+ * just need to extend the appropriate _curl_*_option macro
  */
 #define curl_easy_setopt(handle, option, value)                         \
   __extension__({                                                       \
@@ -245,7 +245,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
 
 /* To add a new option to one of the groups, just add
  *   (option) == CURLOPT_SOMETHING
- * to the or-expression. If the option takes a long or curl_off_t, you don't
+ * to the or-expression. If the option takes a long or curl_off_t, you do not
  * have to do anything
  */
 
@@ -678,7 +678,7 @@ typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
                                             const void *);
 #ifdef HEADER_SSL_H
 /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
- * this will of course break if we're included before OpenSSL headers...
+ * this will of course break if we are included before OpenSSL headers...
  */
 typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *);
 typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *);

+ 3 - 2
Utilities/cmcurl/include/curl/urlapi.h

@@ -97,11 +97,12 @@ typedef enum {
 #define CURLU_NO_AUTHORITY (1<<10)      /* Allow empty authority when the
                                            scheme is unknown. */
 #define CURLU_ALLOW_SPACE (1<<11)       /* Allow spaces in the URL */
-#define CURLU_PUNYCODE (1<<12)          /* get the host name in punycode */
+#define CURLU_PUNYCODE (1<<12)          /* get the hostname in punycode */
 #define CURLU_PUNY2IDN (1<<13)          /* punycode => IDN conversion */
 #define CURLU_GET_EMPTY (1<<14)         /* allow empty queries and fragments
                                            when extracting the URL or the
                                            components */
+#define CURLU_NO_GUESS_SCHEME (1<<15)   /* for get, do not accept a guess */
 
 typedef struct Curl_URL CURLU;
 
@@ -142,7 +143,7 @@ CURL_EXTERN CURLUcode curl_url_set(CURLU *handle, CURLUPart what,
 
 /*
  * curl_url_strerror() turns a CURLUcode value into the equivalent human
- * readable error string.  This is useful for printing meaningful error
+ * readable error string. This is useful for printing meaningful error
  * messages.
  */
 CURL_EXTERN const char *curl_url_strerror(CURLUcode);

+ 32 - 33
Utilities/cmcurl/lib/CMakeLists.txt

@@ -103,29 +103,6 @@ if(ENABLE_CURLDEBUG)
   set_source_files_properties(memdebug.c curl_multibyte.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
 endif()
 
-transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
-include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
-
-if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
-  CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
-  CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
-  CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
-  CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR
-
-  # FreeBSD comes with the a.out and elf flavours
-  # but a.out was supported up to version 3.x and
-  # elf from 3.x. I cannot imagine someone running
-  # CMake on those ancient systems
-  CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR
-
-  CMAKE_SYSTEM_NAME STREQUAL "Haiku")
-
-  math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
-  set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")
-else()
-  unset(CMAKESONAME)
-endif()
-
 ## Library definition
 
 # Add "_imp" as a suffix before the extension to avoid conflicting with
@@ -207,10 +184,6 @@ if(BUILD_STATIC_LIBS)
       INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
       INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
   endif()
-  if(CMAKEVERSION AND CMAKESONAME)
-    set_target_properties(${LIB_STATIC} PROPERTIES
-      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
-  endif()
 
   target_include_directories(${LIB_STATIC} INTERFACE
     $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
@@ -223,8 +196,8 @@ if(BUILD_SHARED_LIBS)
   add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
   if(WIN32 OR CYGWIN)
     if(CYGWIN)
-      # For cygwin always compile dllmain.c as a separate unit since it
-      # includes windows.h, which shouldn't be included in other units.
+      # For Cygwin always compile dllmain.c as a separate unit since it
+      # includes windows.h, which should not be included in other units.
       set_source_files_properties(dllmain.c PROPERTIES
         SKIP_UNITY_BUILD_INCLUSION ON)
     endif()
@@ -251,14 +224,40 @@ if(BUILD_SHARED_LIBS)
       INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
       INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
   endif()
-  if(CMAKEVERSION AND CMAKESONAME)
-    set_target_properties(${LIB_SHARED} PROPERTIES
-      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
-  endif()
 
   target_include_directories(${LIB_SHARED} INTERFACE
     $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
     $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+
+  if(CMAKE_DLL_NAME_WITH_SOVERSION OR
+    CYGWIN OR
+    APPLE OR
+    CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
+    CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
+    CMAKE_SYSTEM_NAME STREQUAL "SunOS" OR
+    CMAKE_SYSTEM_NAME STREQUAL "Haiku" OR
+    CMAKE_SYSTEM_NAME STREQUAL "GNU/kFreeBSD" OR
+    # FreeBSD comes with the a.out and ELF flavours but a.out was supported
+    # up to v3.x and ELF from v3.x. I cannot imagine someone running CMake
+    # on those ancient systems.
+    CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
+    set(soversion_default TRUE)
+  else()
+    set(soversion_default FALSE)
+  endif()
+
+  option(CURL_LIBCURL_SOVERSION "Enable libcurl SOVERSION" ${soversion_default})
+
+  if(CURL_LIBCURL_SOVERSION)
+    transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
+    include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
+
+    math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
+    set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")
+
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      VERSION "${CMAKEVERSION}" SOVERSION "${CMAKESONAME}")
+  endif()
 endif()
 
 add_library(${LIB_NAME} ALIAS ${LIB_SELECTED})

+ 12 - 12
Utilities/cmcurl/lib/altsvc.c

@@ -211,7 +211,7 @@ static CURLcode altsvc_load(struct altsvcinfo *asi, const char *file)
   CURLcode result = CURLE_OK;
   FILE *fp;
 
-  /* we need a private copy of the file name so that the altsvc cache file
+  /* we need a private copy of the filename so that the altsvc cache file
      name survives an easy handle reset */
   free(asi->filename);
   asi->filename = strdup(file);
@@ -270,7 +270,7 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
           "%s %s%s%s %u "
           "\"%d%02d%02d "
           "%02d:%02d:%02d\" "
-          "%u %d\n",
+          "%u %u\n",
           Curl_alpnid2str(as->src.alpnid),
           src6_pre, as->src.host, src6_post,
           as->src.port,
@@ -373,7 +373,7 @@ CURLcode Curl_altsvc_save(struct Curl_easy *data,
     file = altsvc->filename;
 
   if((altsvc->flags & CURLALTSVC_READONLYFILE) || !file || !file[0])
-    /* marked as read-only, no file or zero length file name */
+    /* marked as read-only, no file or zero length filename */
     return CURLE_OK;
 
   result = Curl_fopen(data, file, &out, &tempstore);
@@ -430,7 +430,7 @@ static bool hostcompare(const char *host, const char *check)
   if(hlen && (host[hlen - 1] == '.'))
     hlen--;
   if(hlen != clen)
-    /* they can't match if they have different lengths */
+    /* they cannot match if they have different lengths */
     return FALSE;
   return strncasecompare(host, check, hlen);
 }
@@ -462,7 +462,7 @@ static time_t altsvc_debugtime(void *unused)
   char *timestr = getenv("CURL_TIME");
   (void)unused;
   if(timestr) {
-    unsigned long val = strtol(timestr, NULL, 10);
+    long val = strtol(timestr, NULL, 10);
     return (time_t)val;
   }
   return time(NULL);
@@ -477,11 +477,11 @@ static time_t altsvc_debugtime(void *unused)
  * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
  * the data correctly in the cache.
  *
- * 'value' points to the header *value*. That's contents to the right of the
+ * 'value' points to the header *value*. That is contents to the right of the
  * header name.
  *
  * Currently this function rejects invalid data without returning an error.
- * Invalid host name, port number will result in the specific alternative
+ * Invalid hostname, port number will result in the specific alternative
  * being rejected. Unknown protocols are skipped.
  */
 CURLcode Curl_altsvc_parse(struct Curl_easy *data,
@@ -531,7 +531,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
         bool valid = TRUE;
         p++;
         if(*p != ':') {
-          /* host name starts here */
+          /* hostname starts here */
           const char *hostp = p;
           if(*p == '[') {
             /* pass all valid IPv6 letters - does not handle zone id */
@@ -549,7 +549,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
             len = p - hostp;
           }
           if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
-            infof(data, "Excessive alt-svc host name, ignoring.");
+            infof(data, "Excessive alt-svc hostname, ignoring.");
             valid = FALSE;
           }
           else {
@@ -624,7 +624,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
           num = strtoul(value_ptr, &end_ptr, 10);
           if((end_ptr != value_ptr) && (num < ULONG_MAX)) {
             if(strcasecompare("ma", option))
-              maxage = num;
+              maxage = (time_t)num;
             else if(strcasecompare("persist", option) && (num == 1))
               persist = TRUE;
           }
@@ -651,7 +651,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
       }
       else
         break;
-      /* after the double quote there can be a comma if there's another
+      /* after the double quote there can be a comma if there is another
          string or a semicolon if no more */
       if(*p == ',') {
         /* comma means another alternative is presented */
@@ -696,7 +696,7 @@ bool Curl_altsvc_lookup(struct altsvcinfo *asi,
     if((as->src.alpnid == srcalpnid) &&
        hostcompare(srchost, as->src.host) &&
        (as->src.port == srcport) &&
-       (versions & as->dst.alpnid)) {
+       (versions & (int)as->dst.alpnid)) {
       /* match */
       *dstentry = as;
       return TRUE;

+ 1 - 1
Utilities/cmcurl/lib/altsvc.h

@@ -47,7 +47,7 @@ struct altsvc {
   struct althost dst;
   time_t expires;
   bool persist;
-  int prio;
+  unsigned int prio;
   struct Curl_llist_element node;
 };
 

+ 1 - 1
Utilities/cmcurl/lib/amigaos.c

@@ -117,7 +117,7 @@ void Curl_amiga_cleanup(void)
 
 #ifdef CURLRES_AMIGA
 /*
- * Because we need to handle the different cases in hostip4.c at run-time,
+ * Because we need to handle the different cases in hostip4.c at runtime,
  * not at compile-time, based on what was detected in Curl_amiga_init(),
  * we replace it completely with our own as to not complicate the baseline
  * code. Assumes malloc/calloc/free are thread safe because Curl_he2ai()

+ 1 - 1
Utilities/cmcurl/lib/arpa_telnet.h

@@ -77,7 +77,7 @@ static const char * const telnetoptions[]=
 #define CURL_GA   249 /* Go Ahead, reverse the line */
 #define CURL_SB   250 /* SuBnegotiation */
 #define CURL_WILL 251 /* Our side WILL use this option */
-#define CURL_WONT 252 /* Our side WON'T use this option */
+#define CURL_WONT 252 /* Our side will not use this option */
 #define CURL_DO   253 /* DO use this option! */
 #define CURL_DONT 254 /* DON'T use this option! */
 #define CURL_IAC  255 /* Interpret As Command */

+ 46 - 46
Utilities/cmcurl/lib/asyn-ares.c

@@ -65,7 +65,7 @@
 #  define CARES_STATICLIB
 #endif
 #include <ares.h>
-#include <ares_version.h> /* really old c-ares didn't include this by
+#include <ares_version.h> /* really old c-ares did not include this by
                              itself */
 
 #if ARES_VERSION >= 0x010500
@@ -112,8 +112,8 @@ struct thread_data {
 /* How long we are willing to wait for additional parallel responses after
    obtaining a "definitive" one. For old c-ares without getaddrinfo.
 
-   This is intended to equal the c-ares default timeout.  cURL always uses that
-   default value.  Unfortunately, c-ares doesn't expose its default timeout in
+   This is intended to equal the c-ares default timeout. cURL always uses that
+   default value. Unfortunately, c-ares does not expose its default timeout in
    its API, but it is officially documented as 5 seconds.
 
    See query_completed_cb() for an explanation of how this is used.
@@ -126,8 +126,8 @@ static int ares_ver = 0;
 
 /*
  * Curl_resolver_global_init() - the generic low-level asynchronous name
- * resolve API.  Called from curl_global_init() to initialize global resolver
- * environment.  Initializes ares library.
+ * resolve API. Called from curl_global_init() to initialize global resolver
+ * environment. Initializes ares library.
  */
 int Curl_resolver_global_init(void)
 {
@@ -169,7 +169,7 @@ static void sock_state_cb(void *data, ares_socket_t socket_fd,
  *
  * Called from curl_easy_init() -> Curl_open() to initialize resolver
  * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Fills the passed pointer by the initialized ares_channel.
+ * structure). Fills the passed pointer by the initialized ares_channel.
  */
 CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
 {
@@ -211,7 +211,7 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
  *
  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
  * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Destroys the ares channel.
+ * structure). Destroys the ares channel.
  */
 void Curl_resolver_cleanup(void *resolver)
 {
@@ -222,7 +222,7 @@ void Curl_resolver_cleanup(void *resolver)
  * Curl_resolver_duphandle()
  *
  * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
- * environment ('resolver' member of the UrlState structure).  Duplicates the
+ * environment ('resolver' member of the UrlState structure). Duplicates the
  * 'from' ares channel and passes the resulting channel to the 'to' pointer.
  */
 CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to, void *from)
@@ -250,12 +250,12 @@ void Curl_resolver_cancel(struct Curl_easy *data)
 }
 
 /*
- * We're equivalent to Curl_resolver_cancel() for the c-ares resolver.  We
+ * We are equivalent to Curl_resolver_cancel() for the c-ares resolver. We
  * never block.
  */
 void Curl_resolver_kill(struct Curl_easy *data)
 {
-  /* We don't need to check the resolver state because we can be called safely
+  /* We do not need to check the resolver state because we can be called safely
      at any time and we always do the same thing. */
   Curl_resolver_cancel(data);
 }
@@ -280,7 +280,7 @@ static void destroy_async_data(struct Curl_async *async)
 
 /*
  * Curl_resolver_getsock() is called when someone from the outside world
- * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
+ * (using curl_multi_fdset()) wants to get our fd_set setup and we are talking
  * with ares. The caller must make sure that this function is only called when
  * we have a working ares channel.
  *
@@ -350,7 +350,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
   }
 
   if(num) {
-    nfds = Curl_poll(pfd, num, timeout_ms);
+    nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
     if(nfds < 0)
       return -1;
   }
@@ -359,7 +359,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
 
   if(!nfds)
     /* Call ares_process() unconditionally here, even if we simply timed out
-       above, as otherwise the ares name resolve won't timeout! */
+       above, as otherwise the ares name resolve will not timeout! */
     ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
                     ARES_SOCKET_BAD);
   else {
@@ -394,8 +394,8 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
     return CURLE_UNRECOVERABLE_POLL;
 
 #ifndef HAVE_CARES_GETADDRINFO
-  /* Now that we've checked for any last minute results above, see if there are
-     any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
+  /* Now that we have checked for any last minute results above, see if there
+     are any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
      expires. */
   if(res
      && res->num_pending
@@ -410,7 +410,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
       &res->happy_eyeballs_dns_time, 0, sizeof(res->happy_eyeballs_dns_time));
 
     /* Cancel the raw c-ares request, which will fire query_completed_cb() with
-       ARES_ECANCELLED synchronously for all pending responses.  This will
+       ARES_ECANCELLED synchronously for all pending responses. This will
        leave us with res->num_pending == 0, which is perfect for the next
        block. */
     ares_cancel((ares_channel)data->state.async.resolver);
@@ -523,7 +523,7 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
     *entry = data->state.async.dns;
 
   if(result)
-    /* close the connection, since we can't return failure here without
+    /* close the connection, since we cannot return failure here without
        cleaning up this connection properly. */
     connclose(data->conn, "c-ares resolve failed");
 
@@ -603,57 +603,57 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
 
     /* If there are responses still pending, we presume they must be the
        complementary IPv4 or IPv6 lookups that we started in parallel in
-       Curl_resolver_getaddrinfo() (for Happy Eyeballs).  If we've got a
+       Curl_resolver_getaddrinfo() (for Happy Eyeballs). If we have got a
        "definitive" response from one of a set of parallel queries, we need to
-       think about how long we're willing to wait for more responses. */
+       think about how long we are willing to wait for more responses. */
     if(res->num_pending
        /* Only these c-ares status values count as "definitive" for these
-          purposes.  For example, ARES_ENODATA is what we expect when there is
-          no IPv6 entry for a domain name, and that's not a reason to get more
-          aggressive in our timeouts for the other response.  Other errors are
+          purposes. For example, ARES_ENODATA is what we expect when there is
+          no IPv6 entry for a domain name, and that is not a reason to get more
+          aggressive in our timeouts for the other response. Other errors are
           either a result of bad input (which should affect all parallel
           requests), local or network conditions, non-definitive server
           responses, or us cancelling the request. */
        && (status == ARES_SUCCESS || status == ARES_ENOTFOUND)) {
-      /* Right now, there can only be up to two parallel queries, so don't
+      /* Right now, there can only be up to two parallel queries, so do not
          bother handling any other cases. */
       DEBUGASSERT(res->num_pending == 1);
 
-      /* It's possible that one of these parallel queries could succeed
-         quickly, but the other could always fail or timeout (when we're
+      /* it is possible that one of these parallel queries could succeed
+         quickly, but the other could always fail or timeout (when we are
          talking to a pool of DNS servers that can only successfully resolve
          IPv4 address, for example).
 
-         It's also possible that the other request could always just take
+         it is also possible that the other request could always just take
          longer because it needs more time or only the second DNS server can
-         fulfill it successfully.  But, to align with the philosophy of Happy
-         Eyeballs, we don't want to wait _too_ long or users will think
-         requests are slow when IPv6 lookups don't actually work (but IPv4 ones
-         do).
+         fulfill it successfully. But, to align with the philosophy of Happy
+         Eyeballs, we do not want to wait _too_ long or users will think
+         requests are slow when IPv6 lookups do not actually work (but IPv4
+         ones do).
 
          So, now that we have a usable answer (some IPv4 addresses, some IPv6
          addresses, or "no such domain"), we start a timeout for the remaining
-         pending responses.  Even though it is typical that this resolved
-         request came back quickly, that needn't be the case.  It might be that
-         this completing request didn't get a result from the first DNS server
-         or even the first round of the whole DNS server pool.  So it could
-         already be quite some time after we issued the DNS queries in the
-         first place.  Without modifying c-ares, we can't know exactly where in
-         its retry cycle we are.  We could guess based on how much time has
-         gone by, but it doesn't really matter.  Happy Eyeballs tells us that,
-         given usable information in hand, we simply don't want to wait "too
-         much longer" after we get a result.
+         pending responses. Even though it is typical that this resolved
+         request came back quickly, that needn't be the case. It might be that
+         this completing request did not get a result from the first DNS
+         server or even the first round of the whole DNS server pool. So it
+         could already be quite some time after we issued the DNS queries in
+         the first place. Without modifying c-ares, we cannot know exactly
+         where in its retry cycle we are. We could guess based on how much
+         time has gone by, but it does not really matter. Happy Eyeballs tells
+         us that, given usable information in hand, we simply do not want to
+         wait "too much longer" after we get a result.
 
          We simply wait an additional amount of time equal to the default
-         c-ares query timeout.  That is enough time for a typical parallel
-         response to arrive without being "too long".  Even on a network
+         c-ares query timeout. That is enough time for a typical parallel
+         response to arrive without being "too long". Even on a network
          where one of the two types of queries is failing or timing out
          constantly, this will usually mean we wait a total of the default
          c-ares timeout (5 seconds) plus the round trip time for the successful
-         request, which seems bearable.  The downside is that c-ares might race
+         request, which seems bearable. The downside is that c-ares might race
          with us to issue one more retry just before we give up, but it seems
          better to "waste" that request instead of trying to guess the perfect
-         timeout to prevent it.  After all, we don't even know where in the
+         timeout to prevent it. After all, we do not even know where in the
          c-ares retry cycle each request is.
       */
       res->happy_eyeballs_dns_time = Curl_now();
@@ -849,8 +849,8 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
 
   /* If server is NULL or empty, this would purge all DNS servers
    * from ares library, which will cause any and all queries to fail.
-   * So, just return OK if none are configured and don't actually make
-   * any changes to c-ares.  This lets c-ares use its defaults, which
+   * So, just return OK if none are configured and do not actually make
+   * any changes to c-ares. This lets c-ares use its defaults, which
    * it gets from the OS (for instance from /etc/resolv.conf on Linux).
    */
   if(!(servers && servers[0]))

+ 48 - 15
Utilities/cmcurl/lib/asyn-thread.c

@@ -168,7 +168,7 @@ struct thread_sync_data {
                             duplicate */
 #ifndef CURL_DISABLE_SOCKETPAIR
   struct Curl_easy *data;
-  curl_socket_t sock_pair[2]; /* socket pair */
+  curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
 #endif
   int sock_error;
   struct Curl_addrinfo *res;
@@ -251,7 +251,7 @@ int init_thread_sync_data(struct thread_data *td,
 
 #ifndef CURL_DISABLE_SOCKETPAIR
   /* create socket pair or pipe */
-  if(wakeup_create(&tsd->sock_pair[0]) < 0) {
+  if(wakeup_create(tsd->sock_pair, FALSE) < 0) {
     tsd->sock_pair[0] = CURL_SOCKET_BAD;
     tsd->sock_pair[1] = CURL_SOCKET_BAD;
     goto err_exit;
@@ -286,7 +286,7 @@ static CURLcode getaddrinfo_complete(struct Curl_easy *data)
 
   result = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
   /* The tsd->res structure has been copied to async.dns and perhaps the DNS
-     cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
+     cache. Set our copy to NULL so destroy_thread_sync_data does not free it.
   */
   tsd->res = NULL;
 
@@ -302,6 +302,14 @@ query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
   struct Curl_addrinfo *ca;
   struct Curl_addrinfo *cafirst = NULL;
   struct Curl_addrinfo *calast = NULL;
+#ifndef CURL_DISABLE_SOCKETPAIR
+#ifdef USE_EVENTFD
+  const void *buf;
+  const uint64_t val = 1;
+#else
+  char buf[1];
+#endif
+#endif
 #ifdef __clang__
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wcast-align"
@@ -421,11 +429,14 @@ query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
   }
   else {
 #ifndef CURL_DISABLE_SOCKETPAIR
-    char buf[1];
     if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
-      /* DNS has been resolved, signal client task */
+#ifdef USE_EVENTFD
+      buf = &val;
+#else
       buf[0] = 1;
-      if(swrite(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
+#endif
+      /* DNS has been resolved, signal client task */
+      if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
         /* update sock_erro to errno */
         tsd->sock_error = SOCKERRNO;
       }
@@ -447,14 +458,25 @@ query_complete(DWORD err, DWORD bytes, LPWSAOVERLAPPED overlapped)
  * For builds without ARES, but with USE_IPV6, create a resolver thread
  * and wait on it.
  */
-static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
+static
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+DWORD
+#else
+unsigned int
+#endif
+CURL_STDCALL getaddrinfo_thread(void *arg)
 {
   struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
   struct thread_data *td = tsd->td;
   char service[12];
   int rc;
 #ifndef CURL_DISABLE_SOCKETPAIR
+#ifdef USE_EVENTFD
+  const void *buf;
+  const uint64_t val = 1;
+#else
   char buf[1];
+#endif
 #endif
 
   msnprintf(service, sizeof(service), "%d", tsd->port);
@@ -480,9 +502,13 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
   else {
 #ifndef CURL_DISABLE_SOCKETPAIR
     if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
-      /* DNS has been resolved, signal client task */
+#ifdef USE_EVENTFD
+      buf = &val;
+#else
       buf[0] = 1;
-      if(wakeup_write(tsd->sock_pair[1],  buf, sizeof(buf)) < 0) {
+#endif
+      /* DNS has been resolved, signal client task */
+      if(wakeup_write(tsd->sock_pair[1], buf, sizeof(buf)) < 0) {
         /* update sock_erro to errno */
         tsd->sock_error = SOCKERRNO;
       }
@@ -500,7 +526,13 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
 /*
  * gethostbyname_thread() resolves a name and then exits.
  */
-static unsigned int CURL_STDCALL gethostbyname_thread(void *arg)
+static
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+DWORD
+#else
+unsigned int
+#endif
+CURL_STDCALL gethostbyname_thread(void *arg)
 {
   struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
   struct thread_data *td = tsd->td;
@@ -638,7 +670,8 @@ static bool init_resolve_thread(struct Curl_easy *data,
 
 #ifdef _WIN32
   if(Curl_isWindows8OrGreater && Curl_FreeAddrInfoExW &&
-     Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW) {
+     Curl_GetAddrInfoExCancel && Curl_GetAddrInfoExW &&
+     !Curl_win32_impersonating()) {
 #define MAX_NAME_LEN 256 /* max domain name is 253 chars */
 #define MAX_PORT_LEN 8
     WCHAR namebuf[MAX_NAME_LEN];
@@ -664,7 +697,7 @@ static bool init_resolve_thread(struct Curl_easy *data,
                                   NULL, &td->tsd.w8.overlapped,
                                   &query_complete, &td->tsd.w8.cancel_ev);
         if(err != WSA_IO_PENDING)
-          query_complete(err, 0, &td->tsd.w8.overlapped);
+          query_complete((DWORD)err, 0, &td->tsd.w8.overlapped);
         return TRUE;
       }
     }
@@ -757,8 +790,8 @@ void Curl_resolver_kill(struct Curl_easy *data)
 {
   struct thread_data *td = data->state.async.tdata;
 
-  /* If we're still resolving, we must wait for the threads to fully clean up,
-     unfortunately.  Otherwise, we can simply cancel to clean up any resolver
+  /* If we are still resolving, we must wait for the threads to fully clean up,
+     unfortunately. Otherwise, we can simply cancel to clean up any resolver
      data. */
 #ifdef _WIN32
   if(td && td->complete_ev) {
@@ -829,7 +862,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
   }
   else {
     /* poll for name lookup done with exponential backoff up to 250ms */
-    /* should be fine even if this converts to 32 bit */
+    /* should be fine even if this converts to 32-bit */
     timediff_t elapsed = Curl_timediff(Curl_now(),
                                        data->progress.t_startsingle);
     if(elapsed < 0)

+ 8 - 8
Utilities/cmcurl/lib/asyn.h

@@ -58,7 +58,7 @@ void Curl_resolver_global_cleanup(void);
  * Curl_resolver_init()
  * Called from curl_easy_init() -> Curl_open() to initialize resolver
  * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Should fill the passed pointer by the initialized handler.
+ * structure). Should fill the passed pointer by the initialized handler.
  * Returning anything else than CURLE_OK fails curl_easy_init() with the
  * correspondent code.
  */
@@ -68,7 +68,7 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver);
  * Curl_resolver_cleanup()
  * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
  * URL-state specific environment ('resolver' member of the UrlState
- * structure).  Should destroy the handler and free all resources connected to
+ * structure). Should destroy the handler and free all resources connected to
  * it.
  */
 void Curl_resolver_cleanup(void *resolver);
@@ -76,9 +76,9 @@ void Curl_resolver_cleanup(void *resolver);
 /*
  * Curl_resolver_duphandle()
  * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
- * environment ('resolver' member of the UrlState structure).  Should
+ * environment ('resolver' member of the UrlState structure). Should
  * duplicate the 'from' handle and pass the resulting handle to the 'to'
- * pointer.  Returning anything else than CURLE_OK causes failed
+ * pointer. Returning anything else than CURLE_OK causes failed
  * curl_easy_duphandle() call.
  */
 CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
@@ -89,7 +89,7 @@ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
  *
  * It is called from inside other functions to cancel currently performing
  * resolver request. Should also free any temporary resources allocated to
- * perform a request.  This never waits for resolver threads to complete.
+ * perform a request. This never waits for resolver threads to complete.
  *
  * It is safe to call this when conn is in any state.
  */
@@ -99,8 +99,8 @@ void Curl_resolver_cancel(struct Curl_easy *data);
  * Curl_resolver_kill().
  *
  * This acts like Curl_resolver_cancel() except it will block until any threads
- * associated with the resolver are complete.  This never blocks for resolvers
- * that do not use threads.  This is intended to be the "last chance" function
+ * associated with the resolver are complete. This never blocks for resolvers
+ * that do not use threads. This is intended to be the "last chance" function
  * that cleans up an in-progress resolver completely (before its owner is about
  * to die).
  *
@@ -161,7 +161,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 int *waitp);
 
 #ifndef CURLRES_ASYNCH
-/* convert these functions if an asynch resolver isn't used */
+/* convert these functions if an asynch resolver is not used */
 #define Curl_resolver_cancel(x) Curl_nop_stmt
 #define Curl_resolver_kill(x) Curl_nop_stmt
 #define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST

+ 1 - 1
Utilities/cmcurl/lib/bufref.c

@@ -48,7 +48,7 @@ void Curl_bufref_init(struct bufref *br)
 }
 
 /*
- * Free the buffer and re-init the necessary fields. It doesn't touch the
+ * Free the buffer and re-init the necessary fields. It does not touch the
  * 'signature' field and thus this buffer reference can be reused.
  */
 

+ 11 - 10
Utilities/cmcurl/lib/c-hyper.c

@@ -206,7 +206,7 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
   struct SingleRequest *k = &data->req;
   CURLcode result = CURLE_OK;
 
-  if(0 == k->bodywrites) {
+  if(!k->bodywritten) {
 #if defined(USE_NTLM)
     struct connectdata *conn = data->conn;
     if(conn->bits.close &&
@@ -324,7 +324,7 @@ static CURLcode empty_header(struct Curl_easy *data)
     result = hyper_each_header(data, NULL, 0, NULL, 0) ?
       CURLE_WRITE_ERROR : CURLE_OK;
     if(result)
-      failf(data, "hyperstream: couldn't pass blank header");
+      failf(data, "hyperstream: could not pass blank header");
     /* Hyper does chunked decoding itself. If it was added during
      * response header processing, remove it again. */
     Curl_cwriter_remove_by_name(data, "chunked");
@@ -420,8 +420,8 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
         /* end of transfer */
         data->req.done = TRUE;
         infof(data, "hyperstream is done");
-        if(!k->bodywrites) {
-          /* hyper doesn't always call the body write callback */
+        if(!k->bodywritten) {
+          /* hyper does not always call the body write callback */
           result = Curl_http_firstwrite(data);
         }
         break;
@@ -439,7 +439,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
 
     *didwhat = KEEP_RECV;
     if(!resp) {
-      failf(data, "hyperstream: couldn't get response");
+      failf(data, "hyperstream: could not get response");
       return CURLE_RECV_ERROR;
     }
 
@@ -462,7 +462,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
 
     headers = hyper_response_headers(resp);
     if(!headers) {
-      failf(data, "hyperstream: couldn't get response headers");
+      failf(data, "hyperstream: could not get response headers");
       result = CURLE_RECV_ERROR;
       break;
     }
@@ -505,7 +505,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
 
     resp_body = hyper_response_body(resp);
     if(!resp_body) {
-      failf(data, "hyperstream: couldn't get response body");
+      failf(data, "hyperstream: could not get response body");
       result = CURLE_RECV_ERROR;
       break;
     }
@@ -669,7 +669,7 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
       goto out;
     }
     /* increasing the writebytecount here is a little premature but we
-       don't know exactly when the body is sent */
+       do not know exactly when the body is sent */
     data->req.writebytecount += fillcount;
     Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
     rc = HYPER_POLL_READY;
@@ -772,7 +772,7 @@ static void http1xx_cb(void *arg, struct hyper_response *resp)
   if(!result) {
     headers = hyper_response_headers(resp);
     if(!headers) {
-      failf(data, "hyperstream: couldn't get 1xx response headers");
+      failf(data, "hyperstream: could not get 1xx response headers");
       result = CURLE_RECV_ERROR;
     }
   }
@@ -1133,7 +1133,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     Curl_pgrsSetUploadSize(data, 0); /* nothing */
   }
 
-  Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
+  Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
   conn->datastream = Curl_hyper_stream;
 
   /* clear userpwd and proxyuserpwd to avoid reusing old credentials
@@ -1206,6 +1206,7 @@ static const struct Curl_crtype cr_hyper_protocol = {
   Curl_creader_def_resume_from,
   Curl_creader_def_rewind,
   cr_hyper_unpause,
+  Curl_creader_def_is_paused,
   Curl_creader_def_done,
   sizeof(struct Curl_creader)
 };

+ 15 - 15
Utilities/cmcurl/lib/cf-h1-proxy.c

@@ -65,7 +65,6 @@ typedef enum {
 
 /* struct for HTTP CONNECT tunneling */
 struct h1_tunnel_state {
-  struct HTTP CONNECT;
   struct dynbuf rcvbuf;
   struct dynbuf request_data;
   size_t nsent;
@@ -182,8 +181,8 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
     data->info.httpcode = 0; /* clear it as it might've been used for the
                                 proxy */
     /* If a proxy-authorization header was used for the proxy, then we should
-       make sure that it isn't accidentally used for the document request
-       after we've connected. So let's free and clear it here. */
+       make sure that it is not accidentally used for the document request
+       after we have connected. So let's free and clear it here. */
     Curl_safefree(data->state.aptr.proxyuserpwd);
 #ifdef USE_HYPER
     data->state.hconnect = FALSE;
@@ -222,8 +221,8 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
   int http_minor;
   CURLcode result;
 
-    /* This only happens if we've looped here due to authentication
-       reasons, and we don't really use the newly cloned URL here
+    /* This only happens if we have looped here due to authentication
+       reasons, and we do not really use the newly cloned URL here
        then. Just free() it. */
   Curl_safefree(data->req.newurl);
 
@@ -422,7 +421,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
 
       if(ts->cl) {
         /* A Content-Length based body: simply count down the counter
-           and make sure to break out of the loop when we're done! */
+           and make sure to break out of the loop when we are done! */
         ts->cl--;
         if(ts->cl <= 0) {
           ts->keepon = KEEPON_DONE;
@@ -440,7 +439,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
         if(result)
           return result;
         if(Curl_httpchunk_is_done(data, &ts->ch)) {
-          /* we're done reading chunks! */
+          /* we are done reading chunks! */
           infof(data, "chunk reading DONE");
           ts->keepon = KEEPON_DONE;
         }
@@ -475,7 +474,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
     if(result)
       return result;
 
-    /* Newlines are CRLF, so the CR is ignored as the line isn't
+    /* Newlines are CRLF, so the CR is ignored as the line is not
        really terminated until the LF comes. Treat a following CR
        as end-of-headers as well.*/
 
@@ -498,7 +497,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
         }
         else {
           /* without content-length or chunked encoding, we
-             can't keep the connection alive since the close is
+             cannot keep the connection alive since the close is
              the end signal so we bail out at once instead */
           CURL_TRC_CF(data, cf, "CONNECT: no content-length or chunked");
           ts->keepon = KEEPON_DONE;
@@ -518,7 +517,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
       return result;
 
     Curl_dyn_reset(&ts->rcvbuf);
-  } /* while there's buffer left and loop is requested */
+  } /* while there is buffer left and loop is requested */
 
   if(error)
     result = CURLE_RECV_ERROR;
@@ -666,8 +665,8 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
     goto error;
   }
 
-    /* This only happens if we've looped here due to authentication
-       reasons, and we don't really use the newly cloned URL here
+    /* This only happens if we have looped here due to authentication
+       reasons, and we do not really use the newly cloned URL here
        then. Just free() it. */
   Curl_safefree(data->req.newurl);
 
@@ -955,7 +954,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
 
   DEBUGASSERT(ts->tunnel_state == H1_TUNNEL_RESPONSE);
   if(data->info.httpproxycode/100 != 2) {
-    /* a non-2xx response and we have no next url to try. */
+    /* a non-2xx response and we have no next URL to try. */
     Curl_safefree(data->req.newurl);
     /* failure, close this connection to avoid reuse */
     streamclose(conn, "proxy CONNECT failure");
@@ -1034,9 +1033,9 @@ static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
      * and not waiting on something, we are tunneling. */
     curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
     if(ts) {
-      /* when we've sent a CONNECT to a proxy, we should rather either
+      /* when we have sent a CONNECT to a proxy, we should rather either
          wait for the socket to become readable to be able to get the
-         response headers or if we're still sending the request, wait
+         response headers or if we are still sending the request, wait
          for write. */
       if(tunnel_want_send(ts))
         Curl_pollset_set_out_only(data, ps, sock);
@@ -1077,6 +1076,7 @@ struct Curl_cftype Curl_cft_h1_proxy = {
   cf_h1_proxy_destroy,
   cf_h1_proxy_connect,
   cf_h1_proxy_close,
+  Curl_cf_def_shutdown,
   Curl_cf_http_proxy_get_host,
   cf_h1_proxy_adjust_pollset,
   Curl_cf_def_data_pending,

+ 72 - 12
Utilities/cmcurl/lib/cf-h2-proxy.c

@@ -162,8 +162,8 @@ static void h2_tunnel_go_state(struct Curl_cfilter *cf,
       CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id);
     ts->state = new_state;
     /* If a proxy-authorization header was used for the proxy, then we should
-       make sure that it isn't accidentally used for the document request
-       after we've connected. So let's free and clear it here. */
+       make sure that it is not accidentally used for the document request
+       after we have connected. So let's free and clear it here. */
     Curl_safefree(data->state.aptr.proxyuserpwd);
     break;
   }
@@ -181,7 +181,8 @@ struct cf_h2_proxy_ctx {
   int32_t goaway_error;
   int32_t last_stream_id;
   BIT(conn_closed);
-  BIT(goaway);
+  BIT(rcvd_goaway);
+  BIT(sent_goaway);
   BIT(nw_out_blocked);
 };
 
@@ -694,7 +695,7 @@ static int proxy_h2_on_frame_recv(nghttp2_session *session,
       }
       break;
     case NGHTTP2_GOAWAY:
-      ctx->goaway = TRUE;
+      ctx->rcvd_goaway = TRUE;
       break;
     default:
       break;
@@ -1166,6 +1167,49 @@ static void cf_h2_proxy_destroy(struct Curl_cfilter *cf,
   }
 }
 
+static CURLcode cf_h2_proxy_shutdown(struct Curl_cfilter *cf,
+                                     struct Curl_easy *data, bool *done)
+{
+  struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
+  CURLcode result;
+  int rv;
+
+  if(!cf->connected || !ctx->h2 || cf->shutdown || ctx->conn_closed) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  CF_DATA_SAVE(save, cf, data);
+
+  if(!ctx->sent_goaway) {
+    rv = nghttp2_submit_goaway(ctx->h2, NGHTTP2_FLAG_NONE,
+                               0, 0,
+                               (const uint8_t *)"shutown", sizeof("shutown"));
+    if(rv) {
+      failf(data, "nghttp2_submit_goaway() failed: %s(%d)",
+            nghttp2_strerror(rv), rv);
+      result = CURLE_SEND_ERROR;
+      goto out;
+    }
+    ctx->sent_goaway = TRUE;
+  }
+  /* GOAWAY submitted, process egress and ingress until nghttp2 is done. */
+  result = CURLE_OK;
+  if(nghttp2_session_want_write(ctx->h2))
+    result = proxy_h2_progress_egress(cf, data);
+  if(!result && nghttp2_session_want_read(ctx->h2))
+    result = proxy_h2_progress_ingress(cf, data);
+
+  *done = (ctx->conn_closed ||
+           (!result && !nghttp2_session_want_write(ctx->h2) &&
+            !nghttp2_session_want_read(ctx->h2)));
+out:
+  CF_DATA_RESTORE(cf, save);
+  cf->shutdown = (result || *done);
+  return result;
+}
+
 static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf,
                                      const struct Curl_easy *data)
 {
@@ -1182,12 +1226,18 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
                                        struct easy_pollset *ps)
 {
   struct cf_h2_proxy_ctx *ctx = cf->ctx;
+  struct cf_call_data save;
   curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
   bool want_recv, want_send;
 
-  Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
+  if(!cf->connected && ctx->h2) {
+    want_send = nghttp2_session_want_write(ctx->h2);
+    want_recv = nghttp2_session_want_read(ctx->h2);
+  }
+  else
+    Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
+
   if(ctx->h2 && (want_recv || want_send)) {
-    struct cf_call_data save;
     bool c_exhaust, s_exhaust;
 
     CF_DATA_SAVE(save, cf, data);
@@ -1202,6 +1252,14 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
     Curl_pollset_set(data, ps, sock, want_recv, want_send);
     CF_DATA_RESTORE(cf, save);
   }
+  else if(ctx->sent_goaway && !cf->shutdown) {
+    /* shutdown in progress */
+    CF_DATA_SAVE(save, cf, data);
+    want_send = nghttp2_session_want_write(ctx->h2);
+    want_recv = nghttp2_session_want_read(ctx->h2);
+    Curl_pollset_set(data, ps, sock, want_recv, want_send);
+    CF_DATA_RESTORE(cf, save);
+  }
 }
 
 static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
@@ -1214,7 +1272,7 @@ static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
   if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
     CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
                 "connection", ctx->tunnel.stream_id);
-    connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */
+    connclose(cf->conn, "REFUSED_STREAM"); /* do not use this anymore */
     *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
     return -1;
   }
@@ -1259,7 +1317,8 @@ static ssize_t tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
     }
     else if(ctx->tunnel.reset ||
             (ctx->conn_closed && Curl_bufq_is_empty(&ctx->inbufq)) ||
-            (ctx->goaway && ctx->last_stream_id < ctx->tunnel.stream_id)) {
+            (ctx->rcvd_goaway &&
+             ctx->last_stream_id < ctx->tunnel.stream_id)) {
       *err = CURLE_RECV_ERROR;
       nread = -1;
     }
@@ -1306,7 +1365,7 @@ static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
 
   result = proxy_h2_progress_egress(cf, data);
   if(result == CURLE_AGAIN) {
-    /* pending data to send, need to be called again. Ideally, we'd
+    /* pending data to send, need to be called again. Ideally, we would
      * monitor the socket for POLLOUT, but we might not be in SENDING
      * transfer state any longer and are unable to make this happen.
      */
@@ -1418,7 +1477,7 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
     /* Unable to send all data, due to connection blocked or H2 window
      * exhaustion. Data is left in our stream buffer, or nghttp2's internal
      * frame buffer or our network out buffer. */
-    size_t rwin = nghttp2_session_get_stream_remote_window_size(
+    size_t rwin = (size_t)nghttp2_session_get_stream_remote_window_size(
                     ctx->h2, ctx->tunnel.stream_id);
     if(rwin == 0) {
       /* H2 flow window exhaustion.
@@ -1489,8 +1548,8 @@ static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
     return FALSE;
 
   if(*input_pending) {
-    /* This happens before we've sent off a request and the connection is
-       not in use by any other transfer, there shouldn't be any data here,
+    /* This happens before we have sent off a request and the connection is
+       not in use by any other transfer, there should not be any data here,
        only "protocol frames" */
     CURLcode result;
     ssize_t nread = -1;
@@ -1537,6 +1596,7 @@ struct Curl_cftype Curl_cft_h2_proxy = {
   cf_h2_proxy_destroy,
   cf_h2_proxy_connect,
   cf_h2_proxy_close,
+  cf_h2_proxy_shutdown,
   Curl_cf_http_proxy_get_host,
   cf_h2_proxy_adjust_pollset,
   cf_h2_proxy_data_pending,

+ 1 - 0
Utilities/cmcurl/lib/cf-haproxy.c

@@ -194,6 +194,7 @@ struct Curl_cftype Curl_cft_haproxy = {
   cf_haproxy_destroy,
   cf_haproxy_connect,
   cf_haproxy_close,
+  Curl_cf_def_shutdown,
   Curl_cf_def_get_host,
   cf_haproxy_adjust_pollset,
   Curl_cf_def_data_pending,

+ 47 - 2
Utilities/cmcurl/lib/cf-https-connect.c

@@ -55,7 +55,8 @@ struct cf_hc_baller {
   CURLcode result;
   struct curltime started;
   int reply_ms;
-  bool enabled;
+  BIT(enabled);
+  BIT(shutdown);
 };
 
 static void cf_hc_baller_reset(struct cf_hc_baller *b,
@@ -322,6 +323,49 @@ out:
   return result;
 }
 
+static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
+                               struct Curl_easy *data, bool *done)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+  struct cf_hc_baller *ballers[2];
+  size_t i;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  /* shutdown all ballers that have not done so already. If one fails,
+   * continue shutting down others until all are shutdown. */
+  ballers[0] = &ctx->h3_baller;
+  ballers[1] = &ctx->h21_baller;
+  for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
+    struct cf_hc_baller *b = ballers[i];
+    bool bdone = FALSE;
+    if(!cf_hc_baller_is_active(b) || b->shutdown)
+      continue;
+    b->result = b->cf->cft->do_shutdown(b->cf, data, &bdone);
+    if(b->result || bdone)
+      b->shutdown = TRUE; /* treat a failed shutdown as done */
+  }
+
+  *done = TRUE;
+  for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
+    if(ballers[i] && !ballers[i]->shutdown)
+      *done = FALSE;
+  }
+  if(*done) {
+    for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
+      if(ballers[i] && ballers[i]->result)
+        result = ballers[i]->result;
+    }
+  }
+  CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
+  return result;
+}
+
 static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   struct easy_pollset *ps)
@@ -434,6 +478,7 @@ struct Curl_cftype Curl_cft_http_connect = {
   cf_hc_destroy,
   cf_hc_connect,
   cf_hc_close,
+  cf_hc_shutdown,
   Curl_cf_def_get_host,
   cf_hc_adjust_pollset,
   cf_hc_data_pending,
@@ -510,7 +555,7 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
 
   if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
     result = Curl_conn_may_http3(data, conn);
-    if(result) /* can't do it */
+    if(result) /* cannot do it */
       goto out;
     try_h3 = TRUE;
     try_h21 = FALSE;

+ 383 - 203
Utilities/cmcurl/lib/cf-socket.c

@@ -35,6 +35,9 @@
 #elif defined(HAVE_NETINET_TCP_H)
 #include <netinet/tcp.h>
 #endif
+#ifdef HAVE_NETINET_UDP_H
+#include <netinet/udp.h>
+#endif
 #ifdef HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
 #endif
@@ -53,6 +56,11 @@
 #include <inet.h>
 #endif
 
+#ifdef __DragonFly__
+/* Required for __DragonFly_version */
+#include <sys/param.h>
+#endif
+
 #include "urldata.h"
 #include "bufq.h"
 #include "sendf.h"
@@ -73,6 +81,7 @@
 #include "multihandle.h"
 #include "rand.h"
 #include "share.h"
+#include "strdup.h"
 #include "version_win32.h"
 
 /* The last 3 #include files should be in this order */
@@ -137,8 +146,12 @@ static void nosigpipe(struct Curl_easy *data,
 #define nosigpipe(x,y) Curl_nop_stmt
 #endif
 
-#if defined(__DragonFly__) || defined(USE_WINSOCK)
-/* DragonFlyBSD and Windows use millisecond units */
+#if defined(USE_WINSOCK) || \
+   (defined(__sun) && !defined(TCP_KEEPIDLE)) || \
+   (defined(__DragonFly__) && __DragonFly_version < 500702) || \
+   (defined(_WIN32) && !defined(TCP_KEEPIDLE))
+/* Solaris < 11.4, DragonFlyBSD < 500702 and Windows < 10.0.16299
+ * use millisecond units. */
 #define KEEPALIVE_FACTOR(x) (x *= 1000)
 #else
 #define KEEPALIVE_FACTOR(x)
@@ -168,23 +181,50 @@ tcpkeepalive(struct Curl_easy *data,
           sockfd, SOCKERRNO);
   }
   else {
-#if defined(SIO_KEEPALIVE_VALS)
+#if defined(SIO_KEEPALIVE_VALS) /* Windows */
+/* Windows 10, version 1709 (10.0.16299) and later versions */
+#if defined(TCP_KEEPIDLE) && defined(TCP_KEEPINTVL) && defined(TCP_KEEPCNT)
+    optval = curlx_sltosi(data->set.tcp_keepidle);
+    KEEPALIVE_FACTOR(optval);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
+                (const char *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPIDLE on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
+    optval = curlx_sltosi(data->set.tcp_keepintvl);
+    KEEPALIVE_FACTOR(optval);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
+                (const char *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPINTVL on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
+    optval = curlx_sltosi(data->set.tcp_keepcnt);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
+                (const char *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPCNT on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
+#else /* Windows < 10.0.16299 */
     struct tcp_keepalive vals;
     DWORD dummy;
     vals.onoff = 1;
     optval = curlx_sltosi(data->set.tcp_keepidle);
     KEEPALIVE_FACTOR(optval);
-    vals.keepalivetime = optval;
+    vals.keepalivetime = (u_long)optval;
     optval = curlx_sltosi(data->set.tcp_keepintvl);
     KEEPALIVE_FACTOR(optval);
-    vals.keepaliveinterval = optval;
+    vals.keepaliveinterval = (u_long)optval;
     if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
                 NULL, 0, &dummy, NULL, NULL) != 0) {
       infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
                   "%" CURL_FORMAT_SOCKET_T ": errno %d",
                   sockfd, SOCKERRNO);
     }
-#else
+#endif
+#else /* !Windows */
 #ifdef TCP_KEEPIDLE
     optval = curlx_sltosi(data->set.tcp_keepidle);
     KEEPALIVE_FACTOR(optval);
@@ -204,6 +244,16 @@ tcpkeepalive(struct Curl_easy *data,
             "%" CURL_FORMAT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
+#elif defined(TCP_KEEPALIVE_THRESHOLD)
+    /* Solaris <11.4 style */
+    optval = curlx_sltosi(data->set.tcp_keepidle);
+    KEEPALIVE_FACTOR(optval);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_THRESHOLD,
+      (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPALIVE_THRESHOLD on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
 #endif
 #ifdef TCP_KEEPINTVL
     optval = curlx_sltosi(data->set.tcp_keepintvl);
@@ -214,6 +264,36 @@ tcpkeepalive(struct Curl_easy *data,
             "%" CURL_FORMAT_SOCKET_T ": errno %d",
             sockfd, SOCKERRNO);
     }
+#elif defined(TCP_KEEPALIVE_ABORT_THRESHOLD)
+    /* Solaris <11.4 style */
+    /* TCP_KEEPALIVE_ABORT_THRESHOLD should equal to
+     * TCP_KEEPCNT * TCP_KEEPINTVL on other platforms.
+     * The default value of TCP_KEEPCNT is 9 on Linux,
+     * 8 on *BSD/macOS, 5 or 10 on Windows. We use the
+     * default config for Solaris <11.4 because there is
+     * no default value for TCP_KEEPCNT on Solaris 11.4.
+     *
+     * Note that the consequent probes will not be sent
+     * at equal intervals on Solaris, but will be sent
+     * using the exponential backoff algorithm. */
+    optval = curlx_sltosi(data->set.tcp_keepcnt) *
+             curlx_sltosi(data->set.tcp_keepintvl);
+    KEEPALIVE_FACTOR(optval);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE_ABORT_THRESHOLD,
+          (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPALIVE_ABORT_THRESHOLD on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
+#endif
+#ifdef TCP_KEEPCNT
+    optval = curlx_sltosi(data->set.tcp_keepcnt);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT,
+                (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPCNT on fd "
+            "%" CURL_FORMAT_SOCKET_T ": errno %d",
+            sockfd, SOCKERRNO);
+    }
 #endif
 #endif
   }
@@ -249,7 +329,7 @@ void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
     dest->protocol = IPPROTO_UDP;
     break;
   }
-  dest->addrlen = ai->ai_addrlen;
+  dest->addrlen = (unsigned int)ai->ai_addrlen;
 
   if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
     dest->addrlen = sizeof(struct Curl_sockaddr_storage);
@@ -314,7 +394,7 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
   struct Curl_sockaddr_ex dummy;
 
   if(!addr)
-    /* if the caller doesn't want info back, use a local temp copy */
+    /* if the caller does not want info back, use a local temp copy */
     addr = &dummy;
 
   Curl_sock_assign_addr(addr, ai, transport);
@@ -363,14 +443,14 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
    Buffer Size
 
    The problem described in this knowledge-base is applied only to pre-Vista
-   Windows.  Following function trying to detect OS version and skips
+   Windows. Following function trying to detect OS version and skips
    SO_SNDBUF adjustment for Windows Vista and above.
 */
 #define DETECT_OS_NONE 0
 #define DETECT_OS_PREVISTA 1
 #define DETECT_OS_VISTA_OR_LATER 2
 
-void Curl_sndbufset(curl_socket_t sockfd)
+void Curl_sndbuf_init(curl_socket_t sockfd)
 {
   int val = CURL_MAX_WRITE_SIZE + 32;
   int curval = 0;
@@ -395,7 +475,83 @@ void Curl_sndbufset(curl_socket_t sockfd)
 
   setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
 }
-#endif
+#endif /* USE_WINSOCK */
+
+/*
+ * Curl_parse_interface()
+ *
+ * This is used to parse interface argument in the following formats.
+ * In all the examples, `host` can be an IP address or a hostname.
+ *
+ *   <iface_or_host> - can be either an interface name or a host.
+ *   if!<iface> - interface name.
+ *   host!<host> - hostname.
+ *   ifhost!<iface>!<host> - interface name and hostname.
+ *
+ * Parameters:
+ *
+ * input  [in]     - input string.
+ * len    [in]     - length of the input string.
+ * dev    [in/out] - address where a pointer to newly allocated memory
+ *                   holding the interface-or-host will be stored upon
+ *                   completion.
+ * iface  [in/out] - address where a pointer to newly allocated memory
+ *                   holding the interface will be stored upon completion.
+ * host   [in/out] - address where a pointer to newly allocated memory
+ *                   holding the host will be stored upon completion.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_parse_interface(const char *input, size_t len,
+                              char **dev, char **iface, char **host)
+{
+  static const char if_prefix[] = "if!";
+  static const char host_prefix[] = "host!";
+  static const char if_host_prefix[] = "ifhost!";
+
+  DEBUGASSERT(dev);
+  DEBUGASSERT(iface);
+  DEBUGASSERT(host);
+
+  if(strncmp(if_prefix, input, strlen(if_prefix)) == 0) {
+    input += strlen(if_prefix);
+    if(!*input)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    *iface = Curl_memdup0(input, len - strlen(if_prefix));
+    return *iface ? CURLE_OK : CURLE_OUT_OF_MEMORY;
+  }
+  if(strncmp(host_prefix, input, strlen(host_prefix)) == 0) {
+    input += strlen(host_prefix);
+    if(!*input)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    *host = Curl_memdup0(input, len - strlen(host_prefix));
+    return *host ? CURLE_OK : CURLE_OUT_OF_MEMORY;
+  }
+  if(strncmp(if_host_prefix, input, strlen(if_host_prefix)) == 0) {
+    const char *host_part;
+    input += strlen(if_host_prefix);
+    len -= strlen(if_host_prefix);
+    host_part = memchr(input, '!', len);
+    if(!host_part || !*(host_part + 1))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    *iface = Curl_memdup0(input, host_part - input);
+    if(!*iface)
+      return CURLE_OUT_OF_MEMORY;
+    ++host_part;
+    *host = Curl_memdup0(host_part, len - (host_part - input));
+    if(!*host) {
+      free(*iface);
+      *iface = NULL;
+      return CURLE_OUT_OF_MEMORY;
+    }
+    return CURLE_OK;
+  }
+
+  if(!*input)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  *dev = Curl_memdup0(input, len);
+  return *dev ? CURLE_OK : CURLE_OUT_OF_MEMORY;
+}
 
 #ifndef CURL_DISABLE_BINDLOCAL
 static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
@@ -415,6 +571,10 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
   /* how many port numbers to try to bind to, increasing one at a time */
   int portnum = data->set.localportrange;
   const char *dev = data->set.str[STRING_DEVICE];
+  const char *iface_input = data->set.str[STRING_INTERFACE];
+  const char *host_input = data->set.str[STRING_BINDHOST];
+  const char *iface = iface_input ? iface_input : dev;
+  const char *host = host_input ? host_input : dev;
   int error;
 #ifdef IP_BIND_ADDRESS_NO_PORT
   int on = 1;
@@ -426,83 +586,77 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
   /*************************************************************
    * Select device to bind socket to
    *************************************************************/
-  if(!dev && !port)
+  if(!iface && !host && !port)
     /* no local kind of binding was requested */
     return CURLE_OK;
 
   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
 
-  if(dev && (strlen(dev)<255) ) {
+  if(iface && (strlen(iface)<255) ) {
     char myhost[256] = "";
     int done = 0; /* -1 for error, 1 for address found */
-    bool is_interface = FALSE;
-    bool is_host = FALSE;
-    static const char *if_prefix = "if!";
-    static const char *host_prefix = "host!";
-
-    if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
-      dev += strlen(if_prefix);
-      is_interface = TRUE;
-    }
-    else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
-      dev += strlen(host_prefix);
-      is_host = TRUE;
-    }
+    if2ip_result_t if2ip_result = IF2IP_NOT_FOUND;
 
     /* interface */
-    if(!is_host) {
 #ifdef SO_BINDTODEVICE
-      /*
-       * This binds the local socket to a particular interface. This will
-       * force even requests to other local interfaces to go out the external
-       * interface. Only bind to the interface when specified as interface,
-       * not just as a hostname or ip address.
-       *
-       * The interface might be a VRF, eg: vrf-blue, which means it cannot be
-       * converted to an IP address and would fail Curl_if2ip. Simply try to
-       * use it straight away.
-       */
-      if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
-                    dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
-        /* This is often "errno 1, error: Operation not permitted" if you're
-         * not running as root or another suitable privileged user. If it
-         * succeeds it means the parameter was a valid interface and not an IP
-         * address. Return immediately.
-         */
-        infof(data, "socket successfully bound to interface '%s'", dev);
+    /*
+      * This binds the local socket to a particular interface. This will
+      * force even requests to other local interfaces to go out the external
+      * interface. Only bind to the interface when specified as interface,
+      * not just as a hostname or ip address.
+      *
+      * The interface might be a VRF, eg: vrf-blue, which means it cannot be
+      * converted to an IP address and would fail Curl_if2ip. Simply try to
+      * use it straight away.
+      */
+    if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+                  iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
+      /* This is often "errno 1, error: Operation not permitted" if you are
+        * not running as root or another suitable privileged user. If it
+        * succeeds it means the parameter was a valid interface and not an IP
+        * address. Return immediately.
+        */
+      if(!host_input) {
+        infof(data, "socket successfully bound to interface '%s'", iface);
         return CURLE_OK;
       }
+    }
 #endif
-
-      switch(Curl_if2ip(af,
+    if(!host_input) {
+      /* Discover IP from input device, then bind to it */
+      if2ip_result = Curl_if2ip(af,
 #ifdef USE_IPV6
-                        scope, conn->scope_id,
-#endif
-                        dev, myhost, sizeof(myhost))) {
-        case IF2IP_NOT_FOUND:
-          if(is_interface) {
-            /* Do not fall back to treating it as a host name */
-            failf(data, "Couldn't bind to interface '%s'", dev);
-            return CURLE_INTERFACE_FAILED;
-          }
-          break;
-        case IF2IP_AF_NOT_SUPPORTED:
-          /* Signal the caller to try another address family if available */
-          return CURLE_UNSUPPORTED_PROTOCOL;
-        case IF2IP_FOUND:
-          is_interface = TRUE;
-          /*
-           * We now have the numerical IP address in the 'myhost' buffer
-           */
-          infof(data, "Local Interface %s is ip %s using address family %i",
-                dev, myhost, af);
-          done = 1;
-          break;
-      }
+                      scope, conn->scope_id,
+#endif
+                      iface, myhost, sizeof(myhost));
+    }
+    switch(if2ip_result) {
+      case IF2IP_NOT_FOUND:
+        if(iface_input && !host_input) {
+          /* Do not fall back to treating it as a hostname */
+          char buffer[STRERROR_LEN];
+          data->state.os_errno = error = SOCKERRNO;
+          failf(data, "Couldn't bind to interface '%s' with errno %d: %s",
+                iface, error, Curl_strerror(error, buffer, sizeof(buffer)));
+          return CURLE_INTERFACE_FAILED;
+        }
+        break;
+      case IF2IP_AF_NOT_SUPPORTED:
+        /* Signal the caller to try another address family if available */
+        return CURLE_UNSUPPORTED_PROTOCOL;
+      case IF2IP_FOUND:
+        /*
+          * We now have the numerical IP address in the 'myhost' buffer
+          */
+        host = myhost;
+        infof(data, "Local Interface %s is ip %s using address family %i",
+              iface, host, af);
+        done = 1;
+        break;
     }
-    if(!is_interface) {
+    if(!iface_input || host_input) {
       /*
-       * This was not an interface, resolve the name as a host name
+       * This was not an interface, resolve the name as a hostname
        * or IP number
        *
        * Temporarily force name resolution to use only the address type
@@ -519,7 +673,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
         conn->ip_version = CURL_IPRESOLVE_V6;
 #endif
 
-      rc = Curl_resolv(data, dev, 80, FALSE, &h);
+      rc = Curl_resolv(data, host, 80, FALSE, &h);
       if(rc == CURLRESOLV_PENDING)
         (void)Curl_resolver_wait_resolv(data, &h);
       conn->ip_version = ipver;
@@ -528,7 +682,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
         Curl_printable_address(h->addr, myhost, sizeof(myhost));
         infof(data, "Name '%s' family %i resolved to '%s' family %i",
-              dev, af, myhost, h->addr->ai_family);
+              host, af, myhost, h->addr->ai_family);
         Curl_resolv_unlock(data, h);
         if(af != h->addr->ai_family) {
           /* bad IP version combo, signal the caller to try another address
@@ -562,7 +716,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
           if(scope_ptr) {
             /* The "myhost" string either comes from Curl_if2ip or from
                Curl_printable_address. The latter returns only numeric scope
-               IDs and the former returns none at all.  So the scope ID, if
+               IDs and the former returns none at all. So the scope ID, if
                present, is known to be numeric */
             unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
             if(scope_id > UINT_MAX)
@@ -589,8 +743,11 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
       /* errorbuf is set false so failf will overwrite any message already in
          the error buffer, so the user receives this error message instead of a
          generic resolve error. */
+      char buffer[STRERROR_LEN];
       data->state.errorbuf = FALSE;
-      failf(data, "Couldn't bind to '%s'", dev);
+      data->state.os_errno = error = SOCKERRNO;
+      failf(data, "Couldn't bind to '%s' with errno %d: %s",
+            host, error, Curl_strerror(error, buffer, sizeof(buffer)));
       return CURLE_INTERFACE_FAILED;
     }
   }
@@ -667,8 +824,8 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
    * Gisle Vanem could reproduce the former problems with this function, but
    * could avoid them by adding this SleepEx() call below:
    *
-   *    "I don't have Rational Quantify, but the hint from his post was
-   *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
+   *    "I do not have Rational Quantify, but the hint from his post was
+   *    ntdll::NtRemoveIoCompletion(). I would assume the SleepEx (or maybe
    *    just Sleep(0) would be enough?) would release whatever
    *    mutex/critical-section the ntdll call is waiting on.
    *
@@ -686,14 +843,14 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
   if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
     err = SOCKERRNO;
 #ifdef _WIN32_WCE
-  /* Old WinCE versions don't support SO_ERROR */
+  /* Old WinCE versions do not support SO_ERROR */
   if(WSAENOPROTOOPT == err) {
     SET_SOCKERRNO(0);
     err = 0;
   }
 #endif
 #if defined(EBADIOCTL) && defined(__minix)
-  /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
+  /* Minix 3.1.x does not support getsockopt on UDP sockets */
   if(EBADIOCTL == err) {
     SET_SOCKERRNO(0);
     err = 0;
@@ -703,7 +860,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
     /* we are connected, awesome! */
     rc = TRUE;
   else
-    /* This wasn't a successful connect */
+    /* This was not a successful connect */
     rc = FALSE;
   if(error)
     *error = err;
@@ -765,11 +922,14 @@ struct cf_socket_ctx {
   int transport;
   struct Curl_sockaddr_ex addr;      /* address to connect to */
   curl_socket_t sock;                /* current attempt socket */
-  struct bufq recvbuf;               /* used when `buffer_recv` is set */
   struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
   struct curltime started_at;        /* when socket was created */
   struct curltime connected_at;      /* when socket connected/got first byte */
   struct curltime first_byte_at;     /* when first byte was recvd */
+#ifdef USE_WINSOCK
+  struct curltime last_sndbuf_query_at;  /* when SO_SNDBUF last queried */
+  ULONG sndbuf_size;                     /* the last set SO_SNDBUF size */
+#endif
   int error;                         /* errno of last failure or 0 */
 #ifdef DEBUGBUILD
   int wblock_percent;                /* percent of writes doing EAGAIN */
@@ -781,7 +941,6 @@ struct cf_socket_ctx {
   BIT(accepted);                     /* socket was accepted, not connected */
   BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
   BIT(active);
-  BIT(buffer_recv);
 };
 
 static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
@@ -792,7 +951,6 @@ static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
   ctx->sock = CURL_SOCKET_BAD;
   ctx->transport = transport;
   Curl_sock_assign_addr(&ctx->addr, ai, transport);
-  Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
 #ifdef DEBUGBUILD
   {
     char *p = getenv("CURL_DBG_SOCK_WBLOCK");
@@ -823,56 +981,6 @@ static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
 #endif
 }
 
-struct reader_ctx {
-  struct Curl_cfilter *cf;
-  struct Curl_easy *data;
-};
-
-static ssize_t nw_in_read(void *reader_ctx,
-                           unsigned char *buf, size_t len,
-                           CURLcode *err)
-{
-  struct reader_ctx *rctx = reader_ctx;
-  struct cf_socket_ctx *ctx = rctx->cf->ctx;
-  ssize_t nread;
-
-  *err = CURLE_OK;
-  nread = sread(ctx->sock, buf, len);
-
-  if(-1 == nread) {
-    int sockerr = SOCKERRNO;
-
-    if(
-#ifdef WSAEWOULDBLOCK
-      /* This is how Windows does it */
-      (WSAEWOULDBLOCK == sockerr)
-#else
-      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
-         due to its inability to send off data without blocking. We therefore
-         treat both error codes the same here */
-      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
-#endif
-      ) {
-      /* this is just a case of EWOULDBLOCK */
-      *err = CURLE_AGAIN;
-      nread = -1;
-    }
-    else {
-      char buffer[STRERROR_LEN];
-
-      failf(rctx->data, "Recv failure: %s",
-            Curl_strerror(sockerr, buffer, sizeof(buffer)));
-      rctx->data->state.os_errno = sockerr;
-      *err = CURLE_RECV_ERROR;
-      nread = -1;
-    }
-  }
-  CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu, fd=%"
-              CURL_FORMAT_SOCKET_T ") -> %d, err=%d",
-              len, ctx->sock, (int)nread, *err);
-  return nread;
-}
-
 static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
@@ -886,9 +994,7 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
     ctx->sock = CURL_SOCKET_BAD;
     if(ctx->active && cf->sockindex == FIRSTSOCKET)
       cf->conn->remote_addr = NULL;
-    Curl_bufq_reset(&ctx->recvbuf);
     ctx->active = FALSE;
-    ctx->buffer_recv = FALSE;
     memset(&ctx->started_at, 0, sizeof(ctx->started_at));
     memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
   }
@@ -896,13 +1002,35 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
   cf->connected = FALSE;
 }
 
+static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   bool *done)
+{
+  if(cf->connected) {
+    struct cf_socket_ctx *ctx = cf->ctx;
+
+    CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" CURL_FORMAT_SOCKET_T
+                ")", ctx->sock);
+    /* On TCP, and when the socket looks well and non-blocking mode
+     * can be enabled, receive dangling bytes before close to avoid
+     * entering RST states unnecessarily. */
+    if(ctx->sock != CURL_SOCKET_BAD &&
+       ctx->transport == TRNSPRT_TCP &&
+       (curlx_nonblock(ctx->sock, TRUE) >= 0)) {
+      unsigned char buf[1024];
+      (void)sread(ctx->sock, buf, sizeof(buf));
+    }
+  }
+  *done = TRUE;
+  return CURLE_OK;
+}
+
 static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
 
   cf_socket_close(cf, data);
   CURL_TRC_CF(data, cf, "destroy");
-  Curl_bufq_free(&ctx->recvbuf);
   free(ctx);
   cf->ctx = NULL;
 }
@@ -949,7 +1077,7 @@ static CURLcode set_remote_ip(struct Curl_cfilter *cf,
   struct cf_socket_ctx *ctx = cf->ctx;
 
   /* store remote address and port used in this connection attempt */
-  if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
+  if(!Curl_addr2string(&ctx->addr.sa_addr, (curl_socklen_t)ctx->addr.addrlen,
                        ctx->ip.remote_ip, &ctx->ip.remote_port)) {
     char buffer[STRERROR_LEN];
 
@@ -974,7 +1102,20 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
   (void)data;
   DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
   ctx->started_at = Curl_now();
+#ifdef SOCK_NONBLOCK
+  /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
+   * because we would not know how socketype is about to be used in the
+   * callback, SOCK_NONBLOCK might get factored out before calling socket().
+   */
+  if(!data->set.fopensocket)
+    ctx->addr.socktype |= SOCK_NONBLOCK;
+#endif
   result = socket_open(data, &ctx->addr, &ctx->sock);
+#ifdef SOCK_NONBLOCK
+  /* Restore the socktype after the socket is created. */
+  if(!data->set.fopensocket)
+    ctx->addr.socktype &= ~SOCK_NONBLOCK;
+#endif
   if(result)
     goto out;
 
@@ -1004,7 +1145,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
 
   nosigpipe(data, ctx->sock);
 
-  Curl_sndbufset(ctx->sock);
+  Curl_sndbuf_init(ctx->sock);
 
   if(is_tcp && data->set.tcp_keepalive)
     tcpkeepalive(data, ctx->sock);
@@ -1045,8 +1186,27 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
   }
 #endif
 
-  /* set socket non-blocking */
-  (void)curlx_nonblock(ctx->sock, TRUE);
+#ifndef SOCK_NONBLOCK
+  /* Set socket non-blocking, must be a non-blocking socket for
+   * a non-blocking connect. */
+  error = curlx_nonblock(ctx->sock, TRUE);
+  if(error < 0) {
+    result = CURLE_UNSUPPORTED_PROTOCOL;
+    ctx->error = SOCKERRNO;
+    goto out;
+  }
+#else
+  if(data->set.fopensocket) {
+    /* Set socket non-blocking, must be a non-blocking socket for
+     * a non-blocking connect. */
+    error = curlx_nonblock(ctx->sock, TRUE);
+    if(error < 0) {
+      result = CURLE_UNSUPPORTED_PROTOCOL;
+      ctx->error = SOCKERRNO;
+      goto out;
+    }
+  }
+#endif
   ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
 out:
   if(result) {
@@ -1114,7 +1274,8 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
 #endif
   }
   else {
-    rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+    rc = connect(ctx->sock, &ctx->addr.sa_addr,
+                 (curl_socklen_t)ctx->addr.addrlen);
   }
   return rc;
 }
@@ -1257,13 +1418,36 @@ static bool cf_socket_data_pending(struct Curl_cfilter *cf,
   int readable;
 
   (void)data;
-  if(!Curl_bufq_is_empty(&ctx->recvbuf))
-    return TRUE;
-
   readable = SOCKET_READABLE(ctx->sock, 0);
   return (readable > 0 && (readable & CURL_CSELECT_IN));
 }
 
+#ifdef USE_WINSOCK
+
+#ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
+#define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
+#endif
+
+static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
+{
+  ULONG ideal;
+  DWORD ideallen;
+  struct curltime n = Curl_now();
+
+  if(Curl_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
+    if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
+                  &ideal, sizeof(ideal), &ideallen, 0, 0) &&
+       ideal != ctx->sndbuf_size &&
+       !setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF,
+                   (const char *)&ideal, sizeof(ideal))) {
+      ctx->sndbuf_size = ideal;
+    }
+    ctx->last_sndbuf_query_at = n;
+  }
+}
+
+#endif /* USE_WINSOCK */
+
 static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
                               const void *buf, size_t len, CURLcode *err)
 {
@@ -1336,6 +1520,11 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
     }
   }
 
+#if defined(USE_WINSOCK)
+  if(!*err)
+    win_update_sndbuf_size(ctx);
+#endif
+
   CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
               orig_len, (int)nwritten, *err);
   cf->conn->sock[cf->sockindex] = fdsave;
@@ -1346,14 +1535,10 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
                               char *buf, size_t len, CURLcode *err)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
-  curl_socket_t fdsave;
   ssize_t nread;
 
   *err = CURLE_OK;
 
-  fdsave = cf->conn->sock[cf->sockindex];
-  cf->conn->sock[cf->sockindex] = ctx->sock;
-
 #ifdef DEBUGBUILD
   /* simulate network blocking/partial reads */
   if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
@@ -1362,9 +1547,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
     if(c >= ((100-ctx->rblock_percent)*256/100)) {
       CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
       *err = CURLE_AGAIN;
-      nread = -1;
-      cf->conn->sock[cf->sockindex] = fdsave;
-      return nread;
+      return -1;
     }
   }
   if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
@@ -1375,54 +1558,42 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   }
 #endif
 
-  if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
-    CURL_TRC_CF(data, cf, "recv from buffer");
-    nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
-  }
-  else {
-    struct reader_ctx rctx;
-
-    rctx.cf = cf;
-    rctx.data = data;
-
-    /* "small" reads may trigger filling our buffer, "large" reads
-     * are probably not worth the additional copy */
-    if(ctx->buffer_recv && len < NW_SMALL_READS) {
-      ssize_t nwritten;
-      nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err);
-      if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
-        /* we have a partial read with an error. need to deliver
-         * what we got, return the error later. */
-        CURL_TRC_CF(data, cf, "partial read: empty buffer first");
-        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
-      }
-      else if(nwritten < 0) {
-        nread = -1;
-        goto out;
-      }
-      else if(nwritten == 0) {
-        /* eof */
-        *err = CURLE_OK;
-        nread = 0;
-      }
-      else {
-        CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
-        nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
-      }
+  *err = CURLE_OK;
+  nread = sread(ctx->sock, buf, len);
+
+  if(-1 == nread) {
+    int sockerr = SOCKERRNO;
+
+    if(
+#ifdef WSAEWOULDBLOCK
+      /* This is how Windows does it */
+      (WSAEWOULDBLOCK == sockerr)
+#else
+      /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+         due to its inability to send off data without blocking. We therefore
+         treat both error codes the same here */
+      (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
+#endif
+      ) {
+      /* this is just a case of EWOULDBLOCK */
+      *err = CURLE_AGAIN;
     }
     else {
-      nread = nw_in_read(&rctx, (unsigned char *)buf, len, err);
+      char buffer[STRERROR_LEN];
+
+      failf(data, "Recv failure: %s",
+            Curl_strerror(sockerr, buffer, sizeof(buffer)));
+      data->state.os_errno = sockerr;
+      *err = CURLE_RECV_ERROR;
     }
   }
 
-out:
   CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
               *err);
   if(nread > 0 && !ctx->got_first_byte) {
     ctx->first_byte_at = Curl_now();
     ctx->got_first_byte = TRUE;
   }
-  cf->conn->sock[cf->sockindex] = fdsave;
   return nread;
 }
 
@@ -1444,11 +1615,6 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
     cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
   #endif
     Curl_persistconninfo(data, cf->conn, &ctx->ip);
-    /* buffering is currently disabled by default because we have stalls
-     * in parallel transfers where not all buffered data is consumed and no
-     * socket events happen.
-     */
-    ctx->buffer_recv = FALSE;
   }
   ctx->active = TRUE;
 }
@@ -1564,6 +1730,7 @@ struct Curl_cftype Curl_cft_tcp = {
   cf_socket_destroy,
   cf_tcp_connect,
   cf_socket_close,
+  cf_socket_shutdown,
   cf_socket_get_host,
   cf_socket_adjust_pollset,
   cf_socket_data_pending,
@@ -1608,25 +1775,23 @@ out:
 }
 
 static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
-                               struct Curl_easy *data)
+                                  struct Curl_easy *data)
 {
   struct cf_socket_ctx *ctx = cf->ctx;
   int rc;
+  int one = 1;
+
+  (void)one;
 
   /* QUIC needs a connected socket, nonblocking */
   DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
 
-#if defined(__APPLE__) && defined(USE_OPENSSL_QUIC)
-  (void)rc;
-  /* On macOS OpenSSL QUIC fails on connected sockets.
-   * see: <https://github.com/openssl/openssl/issues/23251> */
-#else
-  rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
+  rc = connect(ctx->sock, &ctx->addr.sa_addr,
+               (curl_socklen_t)ctx->addr.addrlen);
   if(-1 == rc) {
     return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
   }
   ctx->sock_connected = TRUE;
-#endif
   set_local_ip(cf, data);
   CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
               " connected: [%s:%d] -> [%s:%d]",
@@ -1634,7 +1799,11 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
               ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
               ctx->ip.remote_ip, ctx->ip.remote_port);
 
-  (void)curlx_nonblock(ctx->sock, TRUE);
+  /* Currently, cf->ctx->sock is always non-blocking because the only
+   * caller to cf_udp_setup_quic() is cf_udp_connect() that passes the
+   * non-blocking socket created by cf_socket_open() to it. Thus, we
+   * do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
+   */
   switch(ctx->addr.family) {
 #if defined(__linux__) && defined(IP_MTU_DISCOVER)
   case AF_INET: {
@@ -1653,6 +1822,14 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
   }
 #endif
   }
+
+#if defined(__linux__) && defined(UDP_GRO) &&                                 \
+  (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) &&                        \
+  ((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
+  (void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
+                   (socklen_t)sizeof(one));
+#endif
+
   return CURLE_OK;
 }
 
@@ -1702,6 +1879,7 @@ struct Curl_cftype Curl_cft_udp = {
   cf_socket_destroy,
   cf_udp_connect,
   cf_socket_close,
+  cf_socket_shutdown,
   cf_socket_get_host,
   cf_socket_adjust_pollset,
   cf_socket_data_pending,
@@ -1753,6 +1931,7 @@ struct Curl_cftype Curl_cft_unix = {
   cf_socket_destroy,
   cf_tcp_connect,
   cf_socket_close,
+  cf_socket_shutdown,
   cf_socket_get_host,
   cf_socket_adjust_pollset,
   cf_socket_data_pending,
@@ -1817,6 +1996,7 @@ struct Curl_cftype Curl_cft_tcp_accept = {
   cf_socket_destroy,
   cf_tcp_accept_connect,
   cf_socket_close,
+  cf_socket_shutdown,
   cf_socket_get_host,              /* TODO: not accurate */
   cf_socket_adjust_pollset,
   cf_socket_data_pending,

+ 7 - 2
Utilities/cmcurl/lib/cf-socket.h

@@ -54,6 +54,11 @@ struct Curl_sockaddr_ex {
 };
 #define sa_addr _sa_ex_u.addr
 
+/*
+ * Parse interface option, and return the interface name and the host part.
+*/
+CURLcode Curl_parse_interface(const char *input, size_t len,
+                              char **dev, char **iface, char **host);
 
 /*
  * Create a socket based on info from 'conn' and 'ai'.
@@ -81,9 +86,9 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
    Buffer Size
 
 */
-void Curl_sndbufset(curl_socket_t sockfd);
+void Curl_sndbuf_init(curl_socket_t sockfd);
 #else
-#define Curl_sndbufset(y) Curl_nop_stmt
+#define Curl_sndbuf_init(y) Curl_nop_stmt
 #endif
 
 /**

+ 108 - 3
Utilities/cmcurl/lib/cfilters.c

@@ -45,7 +45,7 @@
 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
 #endif
 
-#ifdef DEBUGBUILD
+#ifdef UNITTESTS
 /* used by unit2600.c */
 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
@@ -55,6 +55,15 @@ void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 }
 #endif
 
+CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
+                              struct Curl_easy *data, bool *done)
+{
+  (void)cf;
+  (void)data;
+  *done = TRUE;
+  return CURLE_OK;
+}
+
 static void conn_report_connect_stats(struct Curl_easy *data,
                                       struct connectdata *conn);
 
@@ -166,6 +175,61 @@ void Curl_conn_close(struct Curl_easy *data, int index)
   if(cf) {
     cf->cft->do_close(cf, data);
   }
+  Curl_shutdown_clear(data, index);
+}
+
+CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result = CURLE_OK;
+  timediff_t timeout_ms;
+  struct curltime now;
+
+  DEBUGASSERT(data->conn);
+  /* Get the first connected filter that is not shut down already. */
+  cf = data->conn->cfilter[sockindex];
+  while(cf && (!cf->connected || cf->shutdown))
+    cf = cf->next;
+
+  if(!cf) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  *done = FALSE;
+  now = Curl_now();
+  if(!Curl_shutdown_started(data, sockindex)) {
+    DEBUGF(infof(data, "shutdown start on%s connection",
+           sockindex? " secondary" : ""));
+    Curl_shutdown_start(data, sockindex, &now);
+  }
+  else {
+    timeout_ms = Curl_shutdown_timeleft(data->conn, sockindex, &now);
+    if(timeout_ms < 0) {
+      failf(data, "SSL shutdown timeout");
+      return CURLE_OPERATION_TIMEDOUT;
+    }
+  }
+
+  while(cf) {
+    if(!cf->shutdown) {
+      bool cfdone = FALSE;
+      result = cf->cft->do_shutdown(cf, data, &cfdone);
+      if(result) {
+        CURL_TRC_CF(data, cf, "shut down failed with %d", result);
+        return result;
+      }
+      else if(!cfdone) {
+        CURL_TRC_CF(data, cf, "shut down not done yet");
+        return CURLE_OK;
+      }
+      CURL_TRC_CF(data, cf, "shut down successfully");
+      cf->shutdown = TRUE;
+    }
+    cf = cf->next;
+  }
+  *done = (!result);
+  return result;
 }
 
 ssize_t Curl_cf_recv(struct Curl_easy *data, int num, char *buf,
@@ -345,8 +409,10 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
 
   cf = data->conn->cfilter[sockindex];
   DEBUGASSERT(cf);
-  if(!cf)
+  if(!cf) {
+    *done = FALSE;
     return CURLE_FAILED_INIT;
+  }
 
   *done = cf->connected;
   if(!*done) {
@@ -442,6 +508,9 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
   /* Get the lowest not-connected filter, if there are any */
   while(cf && !cf->connected && cf->next && !cf->next->connected)
     cf = cf->next;
+  /* Skip all filters that have already shut down */
+  while(cf && cf->shutdown)
+    cf = cf->next;
   /* From there on, give all filters a chance to adjust the pollset.
    * Lower filters are called later, so they may override */
   while(cf) {
@@ -462,6 +531,42 @@ void Curl_conn_adjust_pollset(struct Curl_easy *data,
   }
 }
 
+int Curl_conn_cf_poll(struct Curl_cfilter *cf,
+                      struct Curl_easy *data,
+                      timediff_t timeout_ms)
+{
+  struct easy_pollset ps;
+  struct pollfd pfds[MAX_SOCKSPEREASYHANDLE];
+  unsigned int i, npfds = 0;
+
+  DEBUGASSERT(cf);
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  memset(&ps, 0, sizeof(ps));
+  memset(pfds, 0, sizeof(pfds));
+
+  Curl_conn_cf_adjust_pollset(cf, data, &ps);
+  DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE);
+  for(i = 0; i < ps.num; ++i) {
+    short events = 0;
+    if(ps.actions[i] & CURL_POLL_IN) {
+      events |= POLLIN;
+    }
+    if(ps.actions[i] & CURL_POLL_OUT) {
+      events |= POLLOUT;
+    }
+    if(events) {
+      pfds[npfds].fd = ps.sockets[i];
+      pfds[npfds].events = events;
+      ++npfds;
+    }
+  }
+
+  if(!npfds)
+    DEBUGF(infof(data, "no sockets to poll!"));
+  return Curl_poll(pfds, npfds, timeout_ms);
+}
+
 void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
                         const char **phost, const char **pdisplay_host,
                         int *pport)
@@ -718,7 +823,7 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
   DEBUGASSERT(data);
   DEBUGASSERT(data->conn);
   conn = data->conn;
-#ifdef CURLDEBUG
+#ifdef DEBUGBUILD
   {
     /* Allow debug builds to override this logic to force short sends
     */

+ 35 - 4
Utilities/cmcurl/lib/cfilters.h

@@ -24,6 +24,7 @@
  *
  ***************************************************************************/
 
+#include "timediff.h"
 
 struct Curl_cfilter;
 struct Curl_easy;
@@ -36,9 +37,17 @@ struct connectdata;
 typedef void     Curl_cft_destroy_this(struct Curl_cfilter *cf,
                                        struct Curl_easy *data);
 
+/* Callback to close the connection immediately. */
 typedef void     Curl_cft_close(struct Curl_cfilter *cf,
                                 struct Curl_easy *data);
 
+/* Callback to close the connection filter gracefully, non-blocking.
+ * Implementations MUST NOT chain calls to cf->next.
+ */
+typedef CURLcode Curl_cft_shutdown(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data,
+                                   bool *done);
+
 typedef CURLcode Curl_cft_connect(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   bool blocking, bool *done);
@@ -76,10 +85,10 @@ struct easy_pollset;
  * the pollset. Filters, whose filter "below" is not connected, should
  * also do no adjustments.
  *
- * Examples: a TLS handshake, while ongoing, might remove POLL_IN
- * when it needs to write, or vice versa. A HTTP/2 filter might remove
- * POLL_OUT when a stream window is exhausted and a WINDOW_UPDATE needs
- * to be received first and add instead POLL_IN.
+ * Examples: a TLS handshake, while ongoing, might remove POLL_IN when it
+ * needs to write, or vice versa. An HTTP/2 filter might remove POLL_OUT when
+ * a stream window is exhausted and a WINDOW_UPDATE needs to be received first
+ * and add instead POLL_IN.
  *
  * @param cf     the filter to ask
  * @param data   the easy handle the pollset is about
@@ -194,6 +203,7 @@ struct Curl_cftype {
   Curl_cft_destroy_this *destroy;         /* destroy resources of this cf */
   Curl_cft_connect *do_connect;           /* establish connection */
   Curl_cft_close *do_close;               /* close conn */
+  Curl_cft_shutdown *do_shutdown;         /* shutdown conn */
   Curl_cft_get_host *get_host;            /* host filter talks to */
   Curl_cft_adjust_pollset *adjust_pollset; /* adjust transfer poll set */
   Curl_cft_data_pending *has_data_pending;/* conn has data pending */
@@ -213,6 +223,7 @@ struct Curl_cfilter {
   struct connectdata *conn;      /* the connection this filter belongs to */
   int sockindex;                 /* the index the filter is installed at */
   BIT(connected);                /* != 0 iff this filter is connected */
+  BIT(shutdown);                 /* != 0 iff this filter has shut down */
 };
 
 /* Default implementations for the type functions, implementing nop. */
@@ -244,6 +255,8 @@ CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
 CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            int query, int *pres1, void *pres2);
+CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
+                              struct Curl_easy *data, bool *done);
 
 /**
  * Create a new filter instance, unattached to the filter chain.
@@ -371,6 +384,13 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
  */
 void Curl_conn_close(struct Curl_easy *data, int sockindex);
 
+/**
+ * Shutdown the connection at `sockindex` non-blocking, using timeout
+ * from `data->set.shutdowntimeout`, default DEFAULT_SHUTDOWN_TIMEOUT_MS.
+ * Will return CURLE_OK and *done == FALSE if not finished.
+ */
+CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done);
+
 /**
  * Return if data is pending in some connection filter at chain
  * `sockindex` for connection `data->conn`.
@@ -402,6 +422,15 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
 void Curl_conn_adjust_pollset(struct Curl_easy *data,
                                struct easy_pollset *ps);
 
+/**
+ * Curl_poll() the filter chain at `cf` with timeout `timeout_ms`.
+ * Returns 0 on timeout, negative on error or number of sockets
+ * with requested poll events.
+ */
+int Curl_conn_cf_poll(struct Curl_cfilter *cf,
+                      struct Curl_easy *data,
+                      timediff_t timeout_ms);
+
 /**
  * Receive data through the filter chain at `sockindex` for connection
  * `data->conn`. Copy at most `len` bytes into `buf`. Return the
@@ -486,7 +515,9 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
                               struct connectdata *conn,
                               int sockindex);
 
+#ifdef UNITTESTS
 void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data);
+#endif
 void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
                         const char **phost, const char **pdisplay_host,
                         int *pport);

+ 632 - 41
Utilities/cmcurl/lib/conncache.c

@@ -29,13 +29,17 @@
 
 #include "urldata.h"
 #include "url.h"
+#include "cfilters.h"
 #include "progress.h"
 #include "multiif.h"
 #include "sendf.h"
 #include "conncache.h"
+#include "http_negotiate.h"
+#include "http_ntlm.h"
 #include "share.h"
 #include "sigpipe.h"
 #include "connect.h"
+#include "select.h"
 #include "strcase.h"
 
 /* The last 3 #include files should be in this order */
@@ -45,6 +49,24 @@
 
 #define HASHKEY_SIZE 128
 
+static void connc_discard_conn(struct conncache *connc,
+                               struct Curl_easy *last_data,
+                               struct connectdata *conn,
+                               bool aborted);
+static void connc_disconnect(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             struct conncache *connc,
+                             bool do_shutdown);
+static void connc_run_conn_shutdown(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    bool *done);
+static void connc_run_conn_shutdown_handler(struct Curl_easy *data,
+                                            struct connectdata *conn);
+static CURLMcode connc_update_shutdown_ev(struct Curl_multi *multi,
+                                          struct Curl_easy *data,
+                                          struct connectdata *conn);
+static void connc_shutdown_all(struct conncache *connc, int timeout_ms);
+
 static CURLcode bundle_create(struct connectbundle **bundlep)
 {
   DEBUGASSERT(*bundlep == NULL);
@@ -100,25 +122,35 @@ static void free_bundle_hash_entry(void *freethis)
   bundle_destroy(b);
 }
 
-int Curl_conncache_init(struct conncache *connc, size_t size)
+int Curl_conncache_init(struct conncache *connc,
+                        struct Curl_multi *multi, size_t size)
 {
   /* allocate a new easy handle to use when closing cached connections */
   connc->closure_handle = curl_easy_init();
   if(!connc->closure_handle)
     return 1; /* bad */
   connc->closure_handle->state.internal = true;
+ #ifdef DEBUGBUILD
+  if(getenv("CURL_DEBUG"))
+    connc->closure_handle->set.verbose = true;
+#endif
 
   Curl_hash_init(&connc->hash, size, Curl_hash_str,
                  Curl_str_key_compare, free_bundle_hash_entry);
   connc->closure_handle->state.conn_cache = connc;
+  connc->multi = multi;
+  Curl_llist_init(&connc->shutdowns.conn_list, NULL);
 
   return 0; /* good */
 }
 
 void Curl_conncache_destroy(struct conncache *connc)
 {
-  if(connc)
+  if(connc) {
     Curl_hash_destroy(&connc->hash);
+    connc->multi = NULL;
+    DEBUGASSERT(!Curl_llist_count(&connc->shutdowns.conn_list));
+  }
 }
 
 /* creates a key to find a bundle for this connection */
@@ -180,15 +212,14 @@ Curl_conncache_find_bundle(struct Curl_easy *data,
   return bundle;
 }
 
-static void *conncache_add_bundle(struct conncache *connc,
-                                  char *key,
-                                  struct connectbundle *bundle)
+static void *connc_add_bundle(struct conncache *connc,
+                              char *key, struct connectbundle *bundle)
 {
   return Curl_hash_add(&connc->hash, key, strlen(key), bundle);
 }
 
-static void conncache_remove_bundle(struct conncache *connc,
-                                    struct connectbundle *bundle)
+static void connc_remove_bundle(struct conncache *connc,
+                                struct connectbundle *bundle)
 {
   struct Curl_hash_iterator iter;
   struct Curl_hash_element *he;
@@ -231,7 +262,7 @@ CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
 
     hashkey(conn, key, sizeof(key));
 
-    if(!conncache_add_bundle(data->state.conn_cache, key, bundle)) {
+    if(!connc_add_bundle(data->state.conn_cache, key, bundle)) {
       bundle_destroy(bundle);
       result = CURLE_OUT_OF_MEMORY;
       goto unlock;
@@ -252,6 +283,23 @@ unlock:
   return result;
 }
 
+static void connc_remove_conn(struct conncache *connc,
+                              struct connectdata *conn)
+{
+  struct connectbundle *bundle = conn->bundle;
+
+  /* The bundle pointer can be NULL, since this function can be called
+     due to a failed connection attempt, before being added to a bundle */
+  if(bundle) {
+    bundle_remove_conn(bundle, conn);
+    if(connc && bundle->num_connections == 0)
+      connc_remove_bundle(connc, bundle);
+    conn->bundle = NULL; /* removed from it */
+    if(connc)
+      connc->num_conn--;
+  }
+}
+
 /*
  * Removes the connectdata object from the connection cache, but the transfer
  * still owns this connection.
@@ -262,28 +310,16 @@ unlock:
 void Curl_conncache_remove_conn(struct Curl_easy *data,
                                 struct connectdata *conn, bool lock)
 {
-  struct connectbundle *bundle = conn->bundle;
   struct conncache *connc = data->state.conn_cache;
 
-  /* The bundle pointer can be NULL, since this function can be called
-     due to a failed connection attempt, before being added to a bundle */
-  if(bundle) {
-    if(lock) {
-      CONNCACHE_LOCK(data);
-    }
-    bundle_remove_conn(bundle, conn);
-    if(bundle->num_connections == 0)
-      conncache_remove_bundle(connc, bundle);
-    conn->bundle = NULL; /* removed from it */
-    if(connc) {
-      connc->num_conn--;
-      DEBUGF(infof(data, "The cache now contains %zu members",
-                   connc->num_conn));
-    }
-    if(lock) {
-      CONNCACHE_UNLOCK(data);
-    }
-  }
+  if(lock)
+    CONNCACHE_LOCK(data);
+  connc_remove_conn(connc, conn);
+  if(lock)
+    CONNCACHE_UNLOCK(data);
+  if(connc)
+    DEBUGF(infof(data, "The cache now contains %zu members",
+                 connc->num_conn));
 }
 
 /* This function iterates the entire connection cache and calls the function
@@ -345,7 +381,7 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
    up a cache!
 */
 static struct connectdata *
-conncache_find_first_connection(struct conncache *connc)
+connc_find_first_connection(struct conncache *connc)
 {
   struct Curl_hash_iterator iter;
   struct Curl_hash_element *he;
@@ -394,8 +430,7 @@ bool Curl_conncache_return_conn(struct Curl_easy *data,
          important that details from this (unrelated) disconnect does not
          taint meta-data in the data handle. */
       struct conncache *connc = data->state.conn_cache;
-      Curl_disconnect(connc->closure_handle, conn_candidate,
-                      /* dead_connection */ FALSE);
+      connc_disconnect(NULL, conn_candidate, connc, TRUE);
     }
   }
 
@@ -516,33 +551,589 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
   return conn_candidate;
 }
 
-void Curl_conncache_close_all_connections(struct conncache *connc)
+static void connc_shutdown_discard_all(struct conncache *connc)
+{
+  struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
+  struct connectdata *conn;
+
+  if(!e)
+    return;
+
+  DEBUGF(infof(connc->closure_handle, "conncache_shutdown_discard_all"));
+  DEBUGASSERT(!connc->shutdowns.iter_locked);
+  connc->shutdowns.iter_locked = TRUE;
+  while(e) {
+    conn = e->ptr;
+    Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
+    DEBUGF(infof(connc->closure_handle, "discard connection #%"
+                 CURL_FORMAT_CURL_OFF_T, conn->connection_id));
+    connc_disconnect(NULL, conn, connc, FALSE);
+    e = connc->shutdowns.conn_list.head;
+  }
+  connc->shutdowns.iter_locked = FALSE;
+}
+
+static void connc_close_all(struct conncache *connc)
 {
+  struct Curl_easy *data = connc->closure_handle;
   struct connectdata *conn;
+  int timeout_ms = 0;
   SIGPIPE_VARIABLE(pipe_st);
-  if(!connc->closure_handle)
+
+  if(!data)
     return;
 
-  conn = conncache_find_first_connection(connc);
+  /* Move all connections to the shutdown list */
+  conn = connc_find_first_connection(connc);
   while(conn) {
-    sigpipe_ignore(connc->closure_handle, &pipe_st);
+    connc_remove_conn(connc, conn);
+    sigpipe_ignore(data, &pipe_st);
     /* This will remove the connection from the cache */
     connclose(conn, "kill all");
     Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
-    Curl_disconnect(connc->closure_handle, conn, FALSE);
+    connc_discard_conn(connc, connc->closure_handle, conn, FALSE);
     sigpipe_restore(&pipe_st);
 
-    conn = conncache_find_first_connection(connc);
+    conn = connc_find_first_connection(connc);
   }
 
-  sigpipe_ignore(connc->closure_handle, &pipe_st);
+    /* Just for testing, run graceful shutdown */
+#ifdef DEBUGBUILD
+  {
+    char *p = getenv("CURL_GRACEFUL_SHUTDOWN");
+    if(p) {
+      long l = strtol(p, NULL, 10);
+      if(l > 0 && l < INT_MAX)
+        timeout_ms = (int)l;
+    }
+  }
+#endif
+  connc_shutdown_all(connc, timeout_ms);
+
+  /* discard all connections in the shutdown list */
+  connc_shutdown_discard_all(connc);
 
-  Curl_hostcache_clean(connc->closure_handle,
-                       connc->closure_handle->dns.hostcache);
-  Curl_close(&connc->closure_handle);
+  sigpipe_ignore(data, &pipe_st);
+  Curl_hostcache_clean(data, data->dns.hostcache);
+  Curl_close(&data);
   sigpipe_restore(&pipe_st);
 }
 
+void Curl_conncache_close_all_connections(struct conncache *connc)
+{
+  connc_close_all(connc);
+}
+
+static void connc_shutdown_discard_oldest(struct conncache *connc)
+{
+  struct Curl_llist_element *e;
+  struct connectdata *conn;
+  SIGPIPE_VARIABLE(pipe_st);
+
+  DEBUGASSERT(!connc->shutdowns.iter_locked);
+  if(connc->shutdowns.iter_locked)
+    return;
+
+  e = connc->shutdowns.conn_list.head;
+  if(e) {
+    conn = e->ptr;
+    Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
+    sigpipe_ignore(connc->closure_handle, &pipe_st);
+    connc_disconnect(NULL, conn, connc, FALSE);
+    sigpipe_restore(&pipe_st);
+  }
+}
+
+static void connc_discard_conn(struct conncache *connc,
+                               struct Curl_easy *last_data,
+                               struct connectdata *conn,
+                               bool aborted)
+{
+  /* `last_data`, if present, is the transfer that last worked with
+   * the connection. It is present when the connection is being shut down
+   * via `Curl_conncache_discard_conn()`, e.g. when the transfer failed
+   * or does not allow connection reuse.
+   * Using the original handle is necessary for shutting down the protocol
+   * handler belonging to the connection. Protocols like 'file:' rely on
+   * being invoked to clean up their allocations in the easy handle.
+   * When a connection comes from the cache, the transfer is no longer
+   * there and we use the cache is own closure handle.
+   */
+  struct Curl_easy *data = last_data? last_data : connc->closure_handle;
+  bool done = FALSE;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(connc);
+  DEBUGASSERT(!conn->bundle);
+
+  /*
+   * If this connection is not marked to force-close, leave it open if there
+   * are other users of it
+   */
+  if(CONN_INUSE(conn) && !aborted) {
+    DEBUGF(infof(data, "[CCACHE] not discarding #%" CURL_FORMAT_CURL_OFF_T
+                       " still in use by %zu transfers", conn->connection_id,
+                       CONN_INUSE(conn)));
+    return;
+  }
+
+  /* treat the connection as aborted in CONNECT_ONLY situations, we do
+   * not know what the APP did with it. */
+  if(conn->connect_only)
+    aborted = TRUE;
+  conn->bits.aborted = aborted;
+
+  /* We do not shutdown dead connections. The term 'dead' can be misleading
+   * here, as we also mark errored connections/transfers as 'dead'.
+   * If we do a shutdown for an aborted transfer, the server might think
+   * it was successful otherwise (for example an ftps: upload). This is
+   * not what we want. */
+  if(aborted)
+    done = TRUE;
+  if(!done) {
+    /* Attempt to shutdown the connection right away. */
+    Curl_attach_connection(data, conn);
+    connc_run_conn_shutdown(data, conn, &done);
+    DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
+                       ", done=%d",conn->connection_id, done));
+    Curl_detach_connection(data);
+  }
+
+  if(done) {
+    connc_disconnect(data, conn, connc, FALSE);
+    return;
+  }
+
+  DEBUGASSERT(!connc->shutdowns.iter_locked);
+  if(connc->shutdowns.iter_locked) {
+    DEBUGF(infof(data, "[CCACHE] discarding #%" CURL_FORMAT_CURL_OFF_T
+                       ", list locked", conn->connection_id));
+    connc_disconnect(data, conn, connc, FALSE);
+    return;
+  }
+
+  /* Add the connection to our shutdown list for non-blocking shutdown
+   * during multi processing. */
+  if(data->multi && data->multi->max_shutdown_connections > 0 &&
+     (data->multi->max_shutdown_connections >=
+      (long)Curl_llist_count(&connc->shutdowns.conn_list))) {
+    DEBUGF(infof(data, "[CCACHE] discarding oldest shutdown connection "
+                       "due to limit of %ld",
+                       data->multi->max_shutdown_connections));
+    connc_shutdown_discard_oldest(connc);
+  }
+
+  if(data->multi && data->multi->socket_cb) {
+    DEBUGASSERT(connc == &data->multi->conn_cache);
+    /* Start with an empty shutdown pollset, so out internal closure handle
+     * is added to the sockets. */
+    memset(&conn->shutdown_poll, 0, sizeof(conn->shutdown_poll));
+    if(connc_update_shutdown_ev(data->multi, connc->closure_handle, conn)) {
+      DEBUGF(infof(data, "[CCACHE] update events for shutdown failed, "
+                         "discarding #%" CURL_FORMAT_CURL_OFF_T,
+                         conn->connection_id));
+      connc_disconnect(data, conn, connc, FALSE);
+      return;
+    }
+  }
+
+  Curl_llist_append(&connc->shutdowns.conn_list, conn, &conn->bundle_node);
+  DEBUGF(infof(data, "[CCACHE] added #%" CURL_FORMAT_CURL_OFF_T
+                     " to shutdown list of length %zu", conn->connection_id,
+                     Curl_llist_count(&connc->shutdowns.conn_list)));
+}
+
+void Curl_conncache_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool aborted)
+{
+  DEBUGASSERT(data);
+  /* Connection must no longer be in and connection cache */
+  DEBUGASSERT(!conn->bundle);
+
+  if(data->multi) {
+    /* Add it to the multi's conncache for shutdown handling */
+    infof(data, "%s connection #%" CURL_FORMAT_CURL_OFF_T,
+          aborted? "closing" : "shutting down", conn->connection_id);
+    connc_discard_conn(&data->multi->conn_cache, data, conn, aborted);
+  }
+  else {
+    /* No multi available. Make a best-effort shutdown + close */
+    infof(data, "closing connection #%" CURL_FORMAT_CURL_OFF_T,
+          conn->connection_id);
+    DEBUGASSERT(!conn->bundle);
+    connc_run_conn_shutdown_handler(data, conn);
+    connc_disconnect(data, conn, NULL, !aborted);
+  }
+}
+
+static void connc_run_conn_shutdown_handler(struct Curl_easy *data,
+                                            struct connectdata *conn)
+{
+  if(!conn->bits.shutdown_handler) {
+    if(conn->dns_entry) {
+      Curl_resolv_unlock(data, conn->dns_entry);
+      conn->dns_entry = NULL;
+    }
+
+    /* Cleanup NTLM connection-related data */
+    Curl_http_auth_cleanup_ntlm(conn);
+
+    /* Cleanup NEGOTIATE connection-related data */
+    Curl_http_auth_cleanup_negotiate(conn);
+
+    if(conn->handler && conn->handler->disconnect) {
+      /* This is set if protocol-specific cleanups should be made */
+      DEBUGF(infof(data, "connection #%" CURL_FORMAT_CURL_OFF_T
+                   ", shutdown protocol handler (aborted=%d)",
+                   conn->connection_id, conn->bits.aborted));
+      conn->handler->disconnect(data, conn, conn->bits.aborted);
+    }
+
+    /* possible left-overs from the async name resolvers */
+    Curl_resolver_cancel(data);
+
+    conn->bits.shutdown_handler = TRUE;
+  }
+}
+
+static void connc_run_conn_shutdown(struct Curl_easy *data,
+                                    struct connectdata *conn,
+                                    bool *done)
+{
+  CURLcode r1, r2;
+  bool done1, done2;
+
+  /* We expect to be attached when called */
+  DEBUGASSERT(data->conn == conn);
+
+  connc_run_conn_shutdown_handler(data, conn);
+
+  if(conn->bits.shutdown_filters) {
+    *done = TRUE;
+    return;
+  }
+
+  if(!conn->connect_only && Curl_conn_is_connected(conn, FIRSTSOCKET))
+    r1 = Curl_conn_shutdown(data, FIRSTSOCKET, &done1);
+  else {
+    r1 = CURLE_OK;
+    done1 = TRUE;
+  }
+
+  if(!conn->connect_only && Curl_conn_is_connected(conn, SECONDARYSOCKET))
+    r2 = Curl_conn_shutdown(data, SECONDARYSOCKET, &done2);
+  else {
+    r2 = CURLE_OK;
+    done2 = TRUE;
+  }
+
+  /* we are done when any failed or both report success */
+  *done = (r1 || r2 || (done1 && done2));
+  if(*done)
+    conn->bits.shutdown_filters = TRUE;
+}
+
+CURLcode Curl_conncache_add_pollfds(struct conncache *connc,
+                                    struct curl_pollfds *cpfds)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(!connc->shutdowns.iter_locked);
+  connc->shutdowns.iter_locked = TRUE;
+  if(connc->shutdowns.conn_list.head) {
+    struct Curl_llist_element *e;
+    struct easy_pollset ps;
+    struct connectdata *conn;
+
+    for(e = connc->shutdowns.conn_list.head; e; e = e->next) {
+      conn = e->ptr;
+      memset(&ps, 0, sizeof(ps));
+      Curl_attach_connection(connc->closure_handle, conn);
+      Curl_conn_adjust_pollset(connc->closure_handle, &ps);
+      Curl_detach_connection(connc->closure_handle);
+
+      result = Curl_pollfds_add_ps(cpfds, &ps);
+      if(result) {
+        Curl_pollfds_cleanup(cpfds);
+        goto out;
+      }
+    }
+  }
+out:
+  connc->shutdowns.iter_locked = FALSE;
+  return result;
+}
+
+CURLcode Curl_conncache_add_waitfds(struct conncache *connc,
+                                    struct curl_waitfds *cwfds)
+{
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(!connc->shutdowns.iter_locked);
+  connc->shutdowns.iter_locked = TRUE;
+  if(connc->shutdowns.conn_list.head) {
+    struct Curl_llist_element *e;
+    struct easy_pollset ps;
+    struct connectdata *conn;
+
+    for(e = connc->shutdowns.conn_list.head; e; e = e->next) {
+      conn = e->ptr;
+      memset(&ps, 0, sizeof(ps));
+      Curl_attach_connection(connc->closure_handle, conn);
+      Curl_conn_adjust_pollset(connc->closure_handle, &ps);
+      Curl_detach_connection(connc->closure_handle);
+
+      result = Curl_waitfds_add_ps(cwfds, &ps);
+      if(result)
+        goto out;
+    }
+  }
+out:
+  connc->shutdowns.iter_locked = FALSE;
+  return result;
+}
+
+static void connc_perform(struct conncache *connc)
+{
+  struct Curl_easy *data = connc->closure_handle;
+  struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
+  struct Curl_llist_element *enext;
+  struct connectdata *conn;
+  bool done;
+
+  if(!e)
+    return;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(!connc->shutdowns.iter_locked);
+  DEBUGF(infof(data, "[CCACHE] perform, %zu connections being shutdown",
+               Curl_llist_count(&connc->shutdowns.conn_list)));
+  connc->shutdowns.iter_locked = TRUE;
+  while(e) {
+    enext = e->next;
+    conn = e->ptr;
+    Curl_attach_connection(data, conn);
+    connc_run_conn_shutdown(data, conn, &done);
+    DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
+                 ", done=%d", conn->connection_id, done));
+    Curl_detach_connection(data);
+    if(done) {
+      Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
+      connc_disconnect(NULL, conn, connc, FALSE);
+    }
+    e = enext;
+  }
+  connc->shutdowns.iter_locked = FALSE;
+}
+
+void Curl_conncache_multi_perform(struct Curl_multi *multi)
+{
+  connc_perform(&multi->conn_cache);
+}
+
+
+/*
+ * Disconnects the given connection. Note the connection may not be the
+ * primary connection, like when freeing room in the connection cache or
+ * killing of a dead old connection.
+ *
+ * A connection needs an easy handle when closing down. We support this passed
+ * in separately since the connection to get closed here is often already
+ * disassociated from an easy handle.
+ *
+ * This function MUST NOT reset state in the Curl_easy struct if that
+ * is not strictly bound to the life-time of *this* particular connection.
+ *
+ */
+static void connc_disconnect(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             struct conncache *connc,
+                             bool do_shutdown)
+{
+  bool done;
+
+  /* there must be a connection to close */
+  DEBUGASSERT(conn);
+  /* it must be removed from the connection cache */
+  DEBUGASSERT(!conn->bundle);
+  /* there must be an associated transfer */
+  DEBUGASSERT(data || connc);
+  if(!data)
+    data = connc->closure_handle;
+
+  /* the transfer must be detached from the connection */
+  DEBUGASSERT(data && !data->conn);
+
+  Curl_attach_connection(data, conn);
+
+  if(connc && connc->multi && connc->multi->socket_cb) {
+    struct easy_pollset ps;
+    /* With an empty pollset, all previously polled sockets will be removed
+     * via the multi_socket API callback. */
+    memset(&ps, 0, sizeof(ps));
+    (void)Curl_multi_pollset_ev(connc->multi, data, &ps, &conn->shutdown_poll);
+  }
+
+  connc_run_conn_shutdown_handler(data, conn);
+  if(do_shutdown) {
+    /* Make a last attempt to shutdown handlers and filters, if
+     * not done so already. */
+    connc_run_conn_shutdown(data, conn, &done);
+  }
+
+  if(connc)
+    DEBUGF(infof(data, "[CCACHE] closing #%" CURL_FORMAT_CURL_OFF_T,
+                 conn->connection_id));
+  else
+    DEBUGF(infof(data, "closing connection #%" CURL_FORMAT_CURL_OFF_T,
+                 conn->connection_id));
+  Curl_conn_close(data, SECONDARYSOCKET);
+  Curl_conn_close(data, FIRSTSOCKET);
+  Curl_detach_connection(data);
+
+  Curl_conn_free(data, conn);
+}
+
+
+static CURLMcode connc_update_shutdown_ev(struct Curl_multi *multi,
+                                          struct Curl_easy *data,
+                                          struct connectdata *conn)
+{
+  struct easy_pollset ps;
+  CURLMcode mresult;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(multi);
+  DEBUGASSERT(multi->socket_cb);
+
+  memset(&ps, 0, sizeof(ps));
+  Curl_attach_connection(data, conn);
+  Curl_conn_adjust_pollset(data, &ps);
+  Curl_detach_connection(data);
+
+  mresult = Curl_multi_pollset_ev(multi, data, &ps, &conn->shutdown_poll);
+
+  if(!mresult) /* Remember for next time */
+    memcpy(&conn->shutdown_poll, &ps, sizeof(ps));
+  return mresult;
+}
+
+void Curl_conncache_multi_socket(struct Curl_multi *multi,
+                                 curl_socket_t s, int ev_bitmask)
+{
+  struct conncache *connc = &multi->conn_cache;
+  struct Curl_easy *data = connc->closure_handle;
+  struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
+  struct connectdata *conn;
+  bool done;
+
+  (void)ev_bitmask;
+  DEBUGASSERT(multi->socket_cb);
+  if(!e)
+    return;
+
+  connc->shutdowns.iter_locked = TRUE;
+  while(e) {
+    conn = e->ptr;
+    if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
+      Curl_attach_connection(data, conn);
+      connc_run_conn_shutdown(data, conn, &done);
+      DEBUGF(infof(data, "[CCACHE] shutdown #%" CURL_FORMAT_CURL_OFF_T
+                   ", done=%d", conn->connection_id, done));
+      Curl_detach_connection(data);
+      if(done || connc_update_shutdown_ev(multi, data, conn)) {
+        Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
+        connc_disconnect(NULL, conn, connc, FALSE);
+      }
+      break;
+    }
+    e = e->next;
+  }
+  connc->shutdowns.iter_locked = FALSE;
+}
+
+void Curl_conncache_multi_close_all(struct Curl_multi *multi)
+{
+  connc_close_all(&multi->conn_cache);
+}
+
+
+#define NUM_POLLS_ON_STACK 10
+
+static CURLcode connc_shutdown_wait(struct conncache *connc, int timeout_ms)
+{
+  struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
+  struct curl_pollfds cpfds;
+  CURLcode result;
+
+  Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
+
+  result = Curl_conncache_add_pollfds(connc, &cpfds);
+  if(result)
+    goto out;
+
+  Curl_poll(cpfds.pfds, cpfds.n, CURLMIN(timeout_ms, 1000));
+
+out:
+  Curl_pollfds_cleanup(&cpfds);
+  return result;
+}
+
+static void connc_shutdown_all(struct conncache *connc, int timeout_ms)
+{
+  struct Curl_easy *data = connc->closure_handle;
+  struct connectdata *conn;
+  struct curltime started = Curl_now();
+
+  if(!data)
+    return;
+  (void)data;
+
+  DEBUGF(infof(data, "conncache shutdown all"));
+
+  /* Move all connections into the shutdown queue */
+  conn = connc_find_first_connection(connc);
+  while(conn) {
+    /* This will remove the connection from the cache */
+    DEBUGF(infof(data, "moving connection %" CURL_FORMAT_CURL_OFF_T
+                 " to shutdown queue", conn->connection_id));
+    connc_remove_conn(connc, conn);
+    connc_discard_conn(connc, NULL, conn, FALSE);
+    conn = connc_find_first_connection(connc);
+  }
+
+  DEBUGASSERT(!connc->shutdowns.iter_locked);
+  while(connc->shutdowns.conn_list.head) {
+    timediff_t timespent;
+    int remain_ms;
+
+    connc_perform(connc);
+
+    if(!connc->shutdowns.conn_list.head) {
+      DEBUGF(infof(data, "conncache shutdown ok"));
+      break;
+    }
+
+    /* wait for activity, timeout or "nothing" */
+    timespent = Curl_timediff(Curl_now(), started);
+    if(timespent >= (timediff_t)timeout_ms) {
+      DEBUGF(infof(data, "conncache shutdown %s",
+                   (timeout_ms > 0)? "timeout" : "best effort done"));
+      break;
+    }
+
+    remain_ms = timeout_ms - (int)timespent;
+    if(connc_shutdown_wait(connc, remain_ms)) {
+      DEBUGF(infof(data, "conncache shutdown all, abort"));
+      break;
+    }
+  }
+
+  /* Due to errors/timeout, we might come here without being full ydone. */
+  connc_shutdown_discard_all(connc);
+}
+
 #if 0
 /* Useful for debugging the connection cache */
 void Curl_conncache_print(struct conncache *connc)

+ 45 - 3
Utilities/cmcurl/lib/conncache.h

@@ -35,6 +35,14 @@
 #include "timeval.h"
 
 struct connectdata;
+struct curl_pollfds;
+struct curl_waitfds;
+struct Curl_multi;
+
+struct connshutdowns {
+  struct Curl_llist conn_list;  /* The connectdata to shut down */
+  BIT(iter_locked);  /* TRUE while iterating the list */
+};
 
 struct conncache {
   struct Curl_hash hash;
@@ -42,15 +50,17 @@ struct conncache {
   curl_off_t next_connection_id;
   curl_off_t next_easy_id;
   struct curltime last_cleanup;
+  struct connshutdowns shutdowns;
   /* handle used for closing cached connections */
   struct Curl_easy *closure_handle;
+  struct Curl_multi *multi; /* Optional, set if cache belongs to multi */
 };
 
 #define BUNDLE_NO_MULTIUSE -1
 #define BUNDLE_UNKNOWN     0  /* initial value */
 #define BUNDLE_MULTIPLEX   2
 
-#ifdef CURLDEBUG
+#ifdef DEBUGBUILD
 /* the debug versions of these macros make extra certain that the lock is
    never doubly locked or unlocked */
 #define CONNCACHE_LOCK(x)                                               \
@@ -84,8 +94,12 @@ struct connectbundle {
   struct Curl_llist conn_list;  /* The connectdata members of the bundle */
 };
 
-/* returns 1 on error, 0 is fine */
-int Curl_conncache_init(struct conncache *, size_t size);
+/* Init the cache, pass multi only if cache is owned by it.
+ * returns 1 on error, 0 is fine.
+ */
+int Curl_conncache_init(struct conncache *,
+                        struct Curl_multi *multi,
+                        size_t size);
 void Curl_conncache_destroy(struct conncache *connc);
 
 /* return the correct bundle, to a host or a proxy */
@@ -119,4 +133,32 @@ Curl_conncache_extract_oldest(struct Curl_easy *data);
 void Curl_conncache_close_all_connections(struct conncache *connc);
 void Curl_conncache_print(struct conncache *connc);
 
+/**
+ * Tear down the connection. If `aborted` is FALSE, the connection
+ * will be shut down first before discarding. If the shutdown
+ * is not immediately complete, the connection
+ * will be placed into the cache is shutdown queue.
+ */
+void Curl_conncache_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               bool aborted);
+
+/**
+ * Add sockets and POLLIN/OUT flags for connections handled by the cache.
+ */
+CURLcode Curl_conncache_add_pollfds(struct conncache *connc,
+                                    struct curl_pollfds *cpfds);
+CURLcode Curl_conncache_add_waitfds(struct conncache *connc,
+                                    struct curl_waitfds *cwfds);
+
+/**
+ * Perform maintenance on connections in the cache. Specifically,
+ * progress the shutdown of connections in the queue.
+ */
+void Curl_conncache_multi_perform(struct Curl_multi *multi);
+
+void Curl_conncache_multi_socket(struct Curl_multi *multi,
+                                 curl_socket_t s, int ev_bitmask);
+void Curl_conncache_multi_close_all(struct Curl_multi *multi);
+
 #endif /* HEADER_CURL_CONNCACHE_H */

+ 94 - 8
Utilities/cmcurl/lib/connect.c

@@ -90,7 +90,7 @@
 
 /*
  * Curl_timeleft() returns the amount of milliseconds left allowed for the
- * transfer/connection. If the value is 0, there's no timeout (ie there's
+ * transfer/connection. If the value is 0, there is no timeout (ie there is
  * infinite time left). If the value is negative, the timeout time has already
  * elapsed.
  * @param data the transfer to check on
@@ -142,6 +142,49 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
   return (ctimeleft_ms < timeleft_ms)? ctimeleft_ms : timeleft_ms;
 }
 
+void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
+                         struct curltime *nowp)
+{
+  struct curltime now;
+
+  DEBUGASSERT(data->conn);
+  if(!nowp) {
+    now = Curl_now();
+    nowp = &now;
+  }
+  data->conn->shutdown.start[sockindex] = *nowp;
+  data->conn->shutdown.timeout_ms = (data->set.shutdowntimeout > 0) ?
+    data->set.shutdowntimeout : DEFAULT_SHUTDOWN_TIMEOUT_MS;
+}
+
+timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
+                                  struct curltime *nowp)
+{
+  struct curltime now;
+
+  if(!conn->shutdown.start[sockindex].tv_sec || !conn->shutdown.timeout_ms)
+    return 0; /* not started or no limits */
+
+  if(!nowp) {
+    now = Curl_now();
+    nowp = &now;
+  }
+  return conn->shutdown.timeout_ms -
+         Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
+}
+
+void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
+{
+  struct curltime *pt = &data->conn->shutdown.start[sockindex];
+  memset(pt, 0, sizeof(*pt));
+}
+
+bool Curl_shutdown_started(struct Curl_easy *data, int sockindex)
+{
+  struct curltime *pt = &data->conn->shutdown.start[sockindex];
+  return (pt->tv_sec > 0) || (pt->tv_usec > 0);
+}
+
 /* Copies connection info into the transfer handle to make it available when
    the transfer handle is no longer associated with the connection. */
 void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
@@ -317,7 +360,7 @@ void Curl_conncontrol(struct connectdata *conn,
 #endif
   )
 {
-  /* close if a connection, or a stream that isn't multiplexed. */
+  /* close if a connection, or a stream that is not multiplexed. */
   /* This function will be called both before and after this connection is
      associated with a transfer. */
   bool closeit, is_multiplex;
@@ -358,6 +401,7 @@ struct eyeballer {
   BIT(has_started);                  /* attempts have started */
   BIT(is_done);                      /* out of addresses/time */
   BIT(connected);                    /* cf has connected */
+  BIT(shutdown);                     /* cf has shutdown */
   BIT(inconclusive);                 /* connect was not a hard failure, we
                                       * might talk to a restarting server */
 };
@@ -464,7 +508,7 @@ static void baller_initiate(struct Curl_cfilter *cf,
   CURLcode result;
 
 
-  /* Don't close a previous cfilter yet to ensure that the next IP's
+  /* Do not close a previous cfilter yet to ensure that the next IP's
      socket gets a different file descriptor, which can prevent bugs when
      the curl_multi_socket_action interface is used with certain select()
      replacements such as kqueue. */
@@ -744,7 +788,7 @@ evaluate:
 }
 
 /*
- * Connect to the given host with timeout, proxy or remote doesn't matter.
+ * Connect to the given host with timeout, proxy or remote does not matter.
  * There might be more than one IP address to try out.
  */
 static CURLcode start_connect(struct Curl_cfilter *cf,
@@ -857,6 +901,46 @@ static void cf_he_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data)
   ctx->winner = NULL;
 }
 
+static CURLcode cf_he_shutdown(struct Curl_cfilter *cf,
+                               struct Curl_easy *data, bool *done)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  size_t i;
+  CURLcode result = CURLE_OK;
+
+  DEBUGASSERT(data);
+  if(cf->connected) {
+    *done = TRUE;
+    return CURLE_OK;
+  }
+
+  /* shutdown all ballers that have not done so already. If one fails,
+   * continue shutting down others until all are shutdown. */
+  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+    struct eyeballer *baller = ctx->baller[i];
+    bool bdone = FALSE;
+    if(!baller || !baller->cf || baller->shutdown)
+      continue;
+    baller->result = baller->cf->cft->do_shutdown(baller->cf, data, &bdone);
+    if(baller->result || bdone)
+      baller->shutdown = TRUE; /* treat a failed shutdown as done */
+  }
+
+  *done = TRUE;
+  for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+    if(ctx->baller[i] && !ctx->baller[i]->shutdown)
+      *done = FALSE;
+  }
+  if(*done) {
+    for(i = 0; i < ARRAYSIZE(ctx->baller); i++) {
+      if(ctx->baller[i] && ctx->baller[i]->result)
+        result = ctx->baller[i]->result;
+    }
+  }
+  CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
+  return result;
+}
+
 static void cf_he_adjust_pollset(struct Curl_cfilter *cf,
                                   struct Curl_easy *data,
                                   struct easy_pollset *ps)
@@ -917,7 +1001,7 @@ static CURLcode cf_he_connect(struct Curl_cfilter *cf,
                            CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
 
         if(cf->conn->handler->protocol & PROTO_FAMILY_SSH)
-          Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+          Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */
         Curl_verboseconnect(data, cf->conn, cf->sockindex);
         data->info.numconnects++; /* to track the # of connections made */
       }
@@ -1052,6 +1136,7 @@ struct Curl_cftype Curl_cft_happy_eyeballs = {
   cf_he_destroy,
   cf_he_connect,
   cf_he_close,
+  cf_he_shutdown,
   Curl_cf_def_get_host,
   cf_he_adjust_pollset,
   cf_he_data_pending,
@@ -1112,7 +1197,7 @@ struct transport_provider {
 };
 
 static
-#ifndef DEBUGBUILD
+#ifndef UNITTESTS
 const
 #endif
 struct transport_provider transport_providers[] = {
@@ -1316,6 +1401,7 @@ struct Curl_cftype Curl_cft_setup = {
   cf_setup_destroy,
   cf_setup_connect,
   cf_setup_close,
+  Curl_cf_def_shutdown,
   Curl_cf_def_get_host,
   Curl_cf_def_adjust_pollset,
   Curl_cf_def_data_pending,
@@ -1378,7 +1464,7 @@ out:
   return result;
 }
 
-#ifdef DEBUGBUILD
+#ifdef UNITTESTS
 /* used by unit2600.c */
 void Curl_debug_set_transport_provider(int transport,
                                        cf_ip_connect_create *cf_create)
@@ -1391,7 +1477,7 @@ void Curl_debug_set_transport_provider(int transport,
     }
   }
 }
-#endif /* DEBUGBUILD */
+#endif /* UNITTESTS */
 
 CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at,
                                     struct Curl_easy *data,

+ 17 - 2
Utilities/cmcurl/lib/connect.h

@@ -32,7 +32,7 @@
 struct Curl_dns_entry;
 struct ip_quadruple;
 
-/* generic function that returns how much time there's left to run, according
+/* generic function that returns how much time there is left to run, according
    to the timeouts set */
 timediff_t Curl_timeleft(struct Curl_easy *data,
                          struct curltime *nowp,
@@ -40,6 +40,21 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
 
 #define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
 
+#define DEFAULT_SHUTDOWN_TIMEOUT_MS   (2 * 1000)
+
+void Curl_shutdown_start(struct Curl_easy *data, int sockindex,
+                         struct curltime *nowp);
+
+/* return how much time there is left to shutdown the connection at
+ * sockindex. */
+timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
+                                  struct curltime *nowp);
+
+void Curl_shutdown_clear(struct Curl_easy *data, int sockindex);
+
+/* TRUE iff shutdown has been started */
+bool Curl_shutdown_started(struct Curl_easy *data, int sockindex);
+
 /*
  * Used to extract socket and connectdata struct for the most recent
  * transfer on the given Curl_easy.
@@ -125,7 +140,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
 extern struct Curl_cftype Curl_cft_happy_eyeballs;
 extern struct Curl_cftype Curl_cft_setup;
 
-#ifdef DEBUGBUILD
+#ifdef UNITTESTS
 void Curl_debug_set_transport_provider(int transport,
                                        cf_ip_connect_create *cf_create);
 #endif

+ 28 - 21
Utilities/cmcurl/lib/content_encoding.c

@@ -82,7 +82,7 @@
 #define ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
 #define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
 #define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08 /* bit 3 set: original file name present */
+#define ORIG_NAME    0x08 /* bit 3 set: original filename present */
 #define COMMENT      0x10 /* bit 4 set: file comment present */
 #define RESERVED     0xE0 /* bits 5..7: reserved */
 
@@ -192,7 +192,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
      zp->zlib_init != ZLIB_GZIP_INFLATING)
     return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
 
-  /* Dynamically allocate a buffer for decompression because it's uncommonly
+  /* Dynamically allocate a buffer for decompression because it is uncommonly
      large to hold on the stack */
   decomp = malloc(DSIZ);
   if(!decomp)
@@ -246,7 +246,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
          to fix and continue anyway */
       if(zp->zlib_init == ZLIB_INIT) {
         /* Do not use inflateReset2(): only available since zlib 1.2.3.4. */
-        (void) inflateEnd(z);     /* don't care about the return code */
+        (void) inflateEnd(z);     /* do not care about the return code */
         if(inflateInit2(z, -MAX_WBITS) == Z_OK) {
           z->next_in = orig_in;
           z->avail_in = nread;
@@ -266,7 +266,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
   }
   free(decomp);
 
-  /* We're about to leave this call so the `nread' data bytes won't be seen
+  /* We are about to leave this call so the `nread' data bytes will not be seen
      again. If we are in a state that would wrongly allow restart in raw mode
      at the next call, assume output has already started. */
   if(nread && zp->zlib_init == ZLIB_INIT)
@@ -388,7 +388,7 @@ static gzip_status check_gzip_header(unsigned char const *data, ssize_t len,
   flags = data[3];
 
   if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
-    /* Can't handle this compression method or unknown flag */
+    /* cannot handle this compression method or unknown flag */
     return GZIP_BAD;
   }
 
@@ -412,7 +412,7 @@ static gzip_status check_gzip_header(unsigned char const *data, ssize_t len,
   }
 
   if(flags & ORIG_NAME) {
-    /* Skip over NUL-terminated file name */
+    /* Skip over NUL-terminated filename */
     while(len && *data) {
       --len;
       ++data;
@@ -474,10 +474,10 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
   return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
 
 #else
-  /* This next mess is to get around the potential case where there isn't
-   * enough data passed in to skip over the gzip header.  If that happens, we
-   * malloc a block and copy what we have then wait for the next call.  If
-   * there still isn't enough (this is definitely a worst-case scenario), we
+  /* This next mess is to get around the potential case where there is not
+   * enough data passed in to skip over the gzip header. If that happens, we
+   * malloc a block and copy what we have then wait for the next call. If
+   * there still is not enough (this is definitely a worst-case scenario), we
    * make the block bigger, copy the next part in and keep waiting.
    *
    * This is only required with zlib versions < 1.2.0.4 as newer versions
@@ -499,11 +499,11 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
       break;
 
     case GZIP_UNDERFLOW:
-      /* We need more data so we can find the end of the gzip header.  It's
+      /* We need more data so we can find the end of the gzip header. it is
        * possible that the memory block we malloc here will never be freed if
-       * the transfer abruptly aborts after this point.  Since it's unlikely
+       * the transfer abruptly aborts after this point. Since it is unlikely
        * that circumstances will be right for this code path to be followed in
-       * the first place, and it's even more unlikely for a transfer to fail
+       * the first place, and it is even more unlikely for a transfer to fail
        * immediately afterwards, it should seldom be a problem.
        */
       z->avail_in = (uInt) nbytes;
@@ -513,7 +513,7 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
       }
       memcpy(z->next_in, buf, z->avail_in);
       zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
-      /* We don't have any data to inflate yet */
+      /* We do not have any data to inflate yet */
       return CURLE_OK;
 
     case GZIP_BAD:
@@ -536,18 +536,18 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
     /* Append the new block of data to the previous one */
     memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
 
-    switch(check_gzip_header(z->next_in, z->avail_in, &hlen)) {
+    switch(check_gzip_header(z->next_in, (ssize_t)z->avail_in, &hlen)) {
     case GZIP_OK:
       /* This is the zlib stream data */
       free(z->next_in);
-      /* Don't point into the malloced block since we just freed it */
+      /* Do not point into the malloced block since we just freed it */
       z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
-      z->avail_in = (uInt) (z->avail_in - hlen);
+      z->avail_in = z->avail_in - (uInt)hlen;
       zp->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
       break;
 
     case GZIP_UNDERFLOW:
-      /* We still don't have any data to inflate! */
+      /* We still do not have any data to inflate! */
       return CURLE_OK;
 
     case GZIP_BAD:
@@ -572,11 +572,11 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
   }
 
   if(z->avail_in == 0) {
-    /* We don't have any data to inflate; wait until next time */
+    /* We do not have any data to inflate; wait until next time */
     return CURLE_OK;
   }
 
-  /* We've parsed the header, now uncompress the data */
+  /* We have parsed the header, now uncompress the data */
   return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING);
 #endif
 }
@@ -966,7 +966,7 @@ static const struct Curl_cwtype *find_unencode_writer(const char *name,
   return NULL;
 }
 
-/* Set-up the unencoding stack from the Content-Encoding header value.
+/* Setup the unencoding stack from the Content-Encoding header value.
  * See RFC 7231 section 3.1.2.2. */
 CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int is_transfer)
@@ -994,6 +994,8 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
       const struct Curl_cwtype *cwt;
       struct Curl_cwriter *writer;
 
+      CURL_TRC_WRITE(data, "looking for %s decoder: %.*s",
+                     is_transfer? "transfer" : "content", (int)namelen, name);
       is_chunked = (is_transfer && (namelen == 7) &&
                     strncasecompare(name, "chunked", 7));
       /* if we skip the decoding in this phase, do not look further.
@@ -1001,6 +1003,8 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
       if((is_transfer && !data->set.http_transfer_encoding && !is_chunked) ||
          (!is_transfer && data->set.http_ce_skip)) {
         /* not requested, ignore */
+        CURL_TRC_WRITE(data, "decoder not requested, ignored: %.*s",
+                       (int)namelen, name);
         return CURLE_OK;
       }
 
@@ -1018,6 +1022,7 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
          * "A sender MUST NOT apply the chunked transfer coding more than
          *  once to a message body."
          */
+        CURL_TRC_WRITE(data, "ignoring duplicate 'chunked' decoder");
         return CURLE_OK;
       }
 
@@ -1040,6 +1045,8 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
         cwt = &error_writer;  /* Defer error at use. */
 
       result = Curl_cwriter_create(&writer, data, cwt, phase);
+      CURL_TRC_WRITE(data, "added %s decoder %s -> %d",
+                     is_transfer? "transfer" : "content", cwt->name, result);
       if(result)
         return result;
 

+ 39 - 38
Utilities/cmcurl/lib/cookie.c

@@ -61,7 +61,7 @@ struct Cookies *Curl_cookie_getlist(struct CookieInfo *cookie,
         boolean informs the cookie if a secure connection is achieved or
         not.
 
-        It shall only return cookies that haven't expired.
+        It shall only return cookies that have not expired.
 
 
 Example set of cookies:
@@ -150,7 +150,7 @@ static bool cookie_tailmatch(const char *cookie_domain,
 }
 
 /*
- * matching cookie path and url path
+ * matching cookie path and URL path
  * RFC6265 5.1.4 Paths and Path-Match
  */
 static bool pathmatch(const char *cookie_path, const char *request_uri)
@@ -262,8 +262,9 @@ static size_t cookie_hash_domain(const char *domain, const size_t len)
   size_t h = 5381;
 
   while(domain < end) {
+    size_t j = (size_t)Curl_raw_toupper(*domain++);
     h += h << 5;
-    h ^= Curl_raw_toupper(*domain++);
+    h ^= j;
   }
 
   return (h % COOKIE_HASH_SIZE);
@@ -373,7 +374,7 @@ static void strstore(char **str, const char *newstr, size_t len)
  *
  * Remove expired cookies from the hash by inspecting the expires timestamp on
  * each cookie in the hash, freeing and deleting any where the timestamp is in
- * the past.  If the cookiejar has recorded the next timestamp at which one or
+ * the past. If the cookiejar has recorded the next timestamp at which one or
  * more cookies expire, then processing will exit early in case this timestamp
  * is in the future.
  */
@@ -385,11 +386,11 @@ static void remove_expired(struct CookieInfo *cookies)
 
   /*
    * If the earliest expiration timestamp in the jar is in the future we can
-   * skip scanning the whole jar and instead exit early as there won't be any
-   * cookies to evict.  If we need to evict however, reset the next_expiration
-   * counter in order to track the next one. In case the recorded first
-   * expiration is the max offset, then perform the safe fallback of checking
-   * all cookies.
+   * skip scanning the whole jar and instead exit early as there will not be
+   * any cookies to evict. If we need to evict however, reset the
+   * next_expiration counter in order to track the next one. In case the
+   * recorded first expiration is the max offset, then perform the safe
+   * fallback of checking all cookies.
    */
   if(now < cookies->next_expiration &&
       cookies->next_expiration != CURL_OFF_T_MAX)
@@ -414,7 +415,7 @@ static void remove_expired(struct CookieInfo *cookies)
       }
       else {
         /*
-         * If this cookie has an expiration timestamp earlier than what we've
+         * If this cookie has an expiration timestamp earlier than what we have
          * seen so far then record it for the next round of expirations.
          */
         if(co->expires && co->expires < cookies->next_expiration)
@@ -473,7 +474,7 @@ static int invalid_octets(const char *p)
  * Curl_cookie_add
  *
  * Add a single cookie line to the cookie keeping object. Be aware that
- * sometimes we get an IP-only host name, and that might also be a numerical
+ * sometimes we get an IP-only hostname, and that might also be a numerical
  * IPv6 address.
  *
  * Returns NULL on out of memory or invalid cookie. This is suboptimal,
@@ -509,7 +510,7 @@ Curl_cookie_add(struct Curl_easy *data,
   /* First, alloc and init a new struct for it */
   co = calloc(1, sizeof(struct Cookie));
   if(!co)
-    return NULL; /* bail out if we're this low on memory */
+    return NULL; /* bail out if we are this low on memory */
 
   if(httpheader) {
     /* This line was read off an HTTP-header */
@@ -647,7 +648,7 @@ Curl_cookie_add(struct Curl_easy *data,
           else if((nlen == 8) && strncasecompare("httponly", namep, 8))
             co->httponly = TRUE;
           else if(sep)
-            /* there was a '=' so we're not done parsing this field */
+            /* there was a '=' so we are not done parsing this field */
             done = FALSE;
         }
         if(done)
@@ -681,9 +682,9 @@ Curl_cookie_add(struct Curl_easy *data,
 
 #ifndef USE_LIBPSL
           /*
-           * Without PSL we don't know when the incoming cookie is set on a
+           * Without PSL we do not know when the incoming cookie is set on a
            * TLD or otherwise "protected" suffix. To reduce risk, we require a
-           * dot OR the exact host name being "localhost".
+           * dot OR the exact hostname being "localhost".
            */
           if(bad_domain(valuep, vlen))
             domain = ":";
@@ -721,10 +722,10 @@ Curl_cookie_add(struct Curl_easy *data,
           /*
            * Defined in RFC2109:
            *
-           * Optional.  The Max-Age attribute defines the lifetime of the
-           * cookie, in seconds.  The delta-seconds value is a decimal non-
-           * negative integer.  After delta-seconds seconds elapse, the
-           * client should discard the cookie.  A value of zero means the
+           * Optional. The Max-Age attribute defines the lifetime of the
+           * cookie, in seconds. The delta-seconds value is a decimal non-
+           * negative integer. After delta-seconds seconds elapse, the
+           * client should discard the cookie. A value of zero means the
            * cookie should be discarded immediately.
            */
           CURLofft offt;
@@ -780,7 +781,7 @@ Curl_cookie_add(struct Curl_easy *data,
         }
 
         /*
-         * Else, this is the second (or more) name we don't know about!
+         * Else, this is the second (or more) name we do not know about!
          */
       }
       else {
@@ -806,7 +807,7 @@ Curl_cookie_add(struct Curl_easy *data,
 
     if(!badcookie && !co->path && path) {
       /*
-       * No path was given in the header line, set the default.  Note that the
+       * No path was given in the header line, set the default. Note that the
        * passed-in path to this function MAY have a '?' and following part that
        * MUST NOT be stored as part of the path.
        */
@@ -835,7 +836,7 @@ Curl_cookie_add(struct Curl_easy *data,
     }
 
     /*
-     * If we didn't get a cookie name, or a bad one, the this is an illegal
+     * If we did not get a cookie name, or a bad one, the this is an illegal
      * line so bail out.
      */
     if(badcookie || !co->name) {
@@ -868,7 +869,7 @@ Curl_cookie_add(struct Curl_easy *data,
     }
 
     if(lineptr[0]=='#') {
-      /* don't even try the comments */
+      /* do not even try the comments */
       free(co);
       return NULL;
     }
@@ -908,7 +909,7 @@ Curl_cookie_add(struct Curl_easy *data,
       case 2:
         /* The file format allows the path field to remain not filled in */
         if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
-          /* only if the path doesn't look like a boolean option! */
+          /* only if the path does not look like a boolean option! */
           co->path = strdup(ptr);
           if(!co->path)
             badcookie = TRUE;
@@ -920,7 +921,7 @@ Curl_cookie_add(struct Curl_easy *data,
           }
           break;
         }
-        /* this doesn't look like a path, make one up! */
+        /* this does not look like a path, make one up! */
         co->path = strdup("/");
         if(!co->path)
           badcookie = TRUE;
@@ -1003,7 +1004,7 @@ Curl_cookie_add(struct Curl_easy *data,
 
   if(!c->running &&    /* read from a file */
      c->newsession &&  /* clean session cookies */
-     !co->expires) {   /* this is a session cookie since it doesn't expire! */
+     !co->expires) {   /* this is a session cookie since it does not expire! */
     freecookie(co);
     return NULL;
   }
@@ -1024,7 +1025,7 @@ Curl_cookie_add(struct Curl_easy *data,
 #ifdef USE_LIBPSL
   /*
    * Check if the domain is a Public Suffix and if yes, ignore the cookie. We
-   * must also check that the data handle isn't NULL since the psl code will
+   * must also check that the data handle is not NULL since the psl code will
    * dereference it.
    */
   if(data && (domain && co->domain && !Curl_host_is_ipnum(co->domain))) {
@@ -1124,10 +1125,10 @@ Curl_cookie_add(struct Curl_easy *data,
 
       if(replace_old && !co->livecookie && clist->livecookie) {
         /*
-         * Both cookies matched fine, except that the already present cookie is
-         * "live", which means it was set from a header, while the new one was
-         * read from a file and thus isn't "live". "live" cookies are preferred
-         * so the new cookie is freed.
+         * Both cookies matched fine, except that the already present cookie
+         * is "live", which means it was set from a header, while the new one
+         * was read from a file and thus is not "live". "live" cookies are
+         * preferred so the new cookie is freed.
          */
         freecookie(co);
         return NULL;
@@ -1178,7 +1179,7 @@ Curl_cookie_add(struct Curl_easy *data,
   }
 
   /*
-   * Now that we've added a new cookie to the jar, update the expiration
+   * Now that we have added a new cookie to the jar, update the expiration
    * tracker in case it is the next one to expire.
    */
   if(co->expires && (co->expires < c->next_expiration))
@@ -1211,12 +1212,12 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
   FILE *handle = NULL;
 
   if(!inc) {
-    /* we didn't get a struct, create one */
+    /* we did not get a struct, create one */
     c = calloc(1, sizeof(struct CookieInfo));
     if(!c)
       return NULL; /* failed to get memory */
     /*
-     * Initialize the next_expiration time to signal that we don't have enough
+     * Initialize the next_expiration time to signal that we do not have enough
      * information yet.
      */
     c->next_expiration = CURL_OFF_T_MAX;
@@ -1271,7 +1272,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
     }
     data->state.cookie_engine = TRUE;
   }
-  c->running = TRUE;          /* now, we're running */
+  c->running = TRUE;          /* now, we are running */
 
   return c;
 }
@@ -1367,7 +1368,7 @@ fail:
  * should send to the server if used now. The secure boolean informs the cookie
  * if a secure connection is achieved or not.
  *
- * It shall only return cookies that haven't expired.
+ * It shall only return cookies that have not expired.
  */
 struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
                                    struct CookieInfo *c,
@@ -1393,7 +1394,7 @@ struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
   co = c->cookies[myhash];
 
   while(co) {
-    /* if the cookie requires we're secure we must only continue if we are! */
+    /* if the cookie requires we are secure we must only continue if we are! */
     if(co->secure?secure:TRUE) {
 
       /* now check if the domain is correct */
@@ -1605,7 +1606,7 @@ static char *get_netscape_format(const struct Cookie *co)
  * cookie_output()
  *
  * Writes all internally known cookies to the specified file. Specify
- * "-" as file name to write to stdout.
+ * "-" as filename to write to stdout.
  *
  * The function returns non-zero on write failure.
  */

+ 1 - 1
Utilities/cmcurl/lib/cookie.h

@@ -75,7 +75,7 @@ struct CookieInfo {
 
 /** Limits for INCOMING cookies **/
 
-/* The longest we allow a line to be when reading a cookie from a HTTP header
+/* The longest we allow a line to be when reading a cookie from an HTTP header
    or from a cookie jar */
 #define MAX_COOKIE_LINE 5000
 

+ 13 - 5
Utilities/cmcurl/lib/curl_addrinfo.c

@@ -95,7 +95,7 @@ Curl_freeaddrinfo(struct Curl_addrinfo *cahead)
  * the only difference that instead of returning a linked list of
  * addrinfo structs this one returns a linked list of Curl_addrinfo
  * ones. The memory allocated by this function *MUST* be free'd with
- * Curl_freeaddrinfo().  For each successful call to this function
+ * Curl_freeaddrinfo(). For each successful call to this function
  * there must be an associated call later to Curl_freeaddrinfo().
  *
  * There should be no single call to system's getaddrinfo() in the
@@ -221,7 +221,7 @@ Curl_getaddrinfo_ex(const char *nodename,
  * stack, but usable also for IPv4, all hosts and environments.
  *
  * The memory allocated by this function *MUST* be free'd later on calling
- * Curl_freeaddrinfo().  For each successful call to this function there
+ * Curl_freeaddrinfo(). For each successful call to this function there
  * must be an associated call later to Curl_freeaddrinfo().
  *
  *   Curl_addrinfo defined in "lib/curl_addrinfo.h"
@@ -317,7 +317,11 @@ Curl_he2ai(const struct hostent *he, int port)
       addr = (void *)ai->ai_addr; /* storage area for this info */
 
       memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
+#ifdef __MINGW32__
+      addr->sin_family = (short)(he->h_addrtype);
+#else
       addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
+#endif
       addr->sin_port = htons((unsigned short)port);
       break;
 
@@ -326,7 +330,11 @@ Curl_he2ai(const struct hostent *he, int port)
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
 
       memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
+#ifdef __MINGW32__
+      addr6->sin6_family = (short)(he->h_addrtype);
+#else
       addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
+#endif
       addr6->sin6_port = htons((unsigned short)port);
       break;
 #endif
@@ -359,7 +367,7 @@ struct namebuff {
 /*
  * Curl_ip2addr()
  *
- * This function takes an internet address, in binary form, as input parameter
+ * This function takes an Internet address, in binary form, as input parameter
  * along with its address family and the string version of the address, and it
  * returns a Curl_addrinfo chain filled in correctly with information for the
  * given address/host
@@ -511,7 +519,7 @@ struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
  *
  * This is strictly for memory tracing and are using the same style as the
  * family otherwise present in memdebug.c. I put these ones here since they
- * require a bunch of structs I didn't want to include in memdebug.c
+ * require a bunch of structs I did not want to include in memdebug.c
  */
 
 void
@@ -535,7 +543,7 @@ curl_dbg_freeaddrinfo(struct addrinfo *freethis,
  *
  * This is strictly for memory tracing and are using the same style as the
  * family otherwise present in memdebug.c. I put these ones here since they
- * require a bunch of structs I didn't want to include in memdebug.c
+ * require a bunch of structs I did not want to include in memdebug.c
  */
 
 int

+ 3 - 3
Utilities/cmcurl/lib/curl_addrinfo.h

@@ -44,9 +44,9 @@
 
 /*
  * Curl_addrinfo is our internal struct definition that we use to allow
- * consistent internal handling of this data. We use this even when the
- * system provides an addrinfo structure definition. And we use this for
- * all sorts of IPv4 and IPV6 builds.
+ * consistent internal handling of this data. We use this even when the system
+ * provides an addrinfo structure definition. We use this for all sorts of
+ * IPv4 and IPV6 builds.
  */
 
 struct Curl_addrinfo {

+ 21 - 12
Utilities/cmcurl/lib/curl_config.h.cmake

@@ -21,7 +21,7 @@
  * SPDX-License-Identifier: curl
  *
  ***************************************************************************/
-/* lib/curl_config.h.in.  Generated somehow by cmake.  */
+/* lib/curl_config.h.in. Generated somehow by cmake.  */
 
 #include <cm3p/kwiml/abi.h>
 
@@ -361,12 +361,6 @@
 /* Define to 1 if you have the idn2.h header file. */
 #cmakedefine HAVE_IDN2_H 1
 
-/* Define to 1 if you have the `socket' library (-lsocket). */
-#cmakedefine HAVE_LIBSOCKET 1
-
-/* Define to 1 if you have the `ssh2' library (-lssh2). */
-#cmakedefine HAVE_LIBSSH2 1
-
 /* if zlib is available */
 #cmakedefine HAVE_LIBZ 1
 
@@ -414,6 +408,9 @@
 /* Define to 1 if you have the `pipe' function. */
 #cmakedefine HAVE_PIPE 1
 
+/* Define to 1 if you have the `eventfd' function. */
+#cmakedefine HAVE_EVENTFD 1
+
 /* If you have a fine poll */
 #cmakedefine HAVE_POLL_FINE 1
 
@@ -534,6 +531,9 @@
 /* Define to 1 if you have the timeval struct. */
 #cmakedefine HAVE_STRUCT_TIMEVAL 1
 
+/* Define to 1 if you have the <sys/eventfd.h> header file. */
+#cmakedefine HAVE_SYS_EVENTFD_H 1
+
 /* Define to 1 if you have the <sys/filio.h> header file. */
 #cmakedefine HAVE_SYS_FILIO_H 1
 
@@ -701,16 +701,22 @@ ${SIZEOF_TIME_T_CODE}
 /* if BearSSL is enabled */
 #cmakedefine USE_BEARSSL 1
 
-/* if WolfSSL is enabled */
+/* if wolfSSL is enabled */
 #cmakedefine USE_WOLFSSL 1
 
-/* if libSSH is in use */
+/* if wolfSSL has the wolfSSL_DES_ecb_encrypt function. */
+#cmakedefine HAVE_WOLFSSL_DES_ECB_ENCRYPT 1
+
+/* if wolfSSL has the wolfSSL_BIO_set_shutdown function. */
+#cmakedefine HAVE_WOLFSSL_FULL_BIO 1
+
+/* if libssh is in use */
 #cmakedefine USE_LIBSSH 1
 
-/* if libSSH2 is in use */
+/* if libssh2 is in use */
 #cmakedefine USE_LIBSSH2 1
 
-/* if libPSL is in use */
+/* if libpsl is in use */
 #cmakedefine USE_LIBPSL 1
 
 /* if you want to use OpenLDAP code instead of legacy ldap implementation */
@@ -722,7 +728,10 @@ ${SIZEOF_TIME_T_CODE}
 /* if librtmp/rtmpdump is in use */
 #cmakedefine USE_LIBRTMP 1
 
-/* Define to 1 if you don't want the OpenSSL configuration to be loaded
+/* if GSASL is in use */
+#cmakedefine USE_GSASL 1
+
+/* Define to 1 if you do not want the OpenSSL configuration to be loaded
    automatically */
 #cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1
 

+ 1 - 1
Utilities/cmcurl/lib/curl_des.c

@@ -36,7 +36,7 @@
  * Curl_des_set_odd_parity()
  *
  * This is used to apply odd parity to the given byte array. It is typically
- * used by when a cryptography engine doesn't have its own version.
+ * used by when a cryptography engine does not have its own version.
  *
  * The function is a port of the Java based oddParity() function over at:
  *

+ 3 - 3
Utilities/cmcurl/lib/curl_endian.c

@@ -30,7 +30,7 @@
  * Curl_read16_le()
  *
  * This function converts a 16-bit integer from the little endian format, as
- * used in the incoming package to whatever endian format we're using
+ * used in the incoming package to whatever endian format we are using
  * natively.
  *
  * Parameters:
@@ -49,7 +49,7 @@ unsigned short Curl_read16_le(const unsigned char *buf)
  * Curl_read32_le()
  *
  * This function converts a 32-bit integer from the little endian format, as
- * used in the incoming package to whatever endian format we're using
+ * used in the incoming package to whatever endian format we are using
  * natively.
  *
  * Parameters:
@@ -68,7 +68,7 @@ unsigned int Curl_read32_le(const unsigned char *buf)
  * Curl_read16_be()
  *
  * This function converts a 16-bit integer from the big endian format, as
- * used in the incoming package to whatever endian format we're using
+ * used in the incoming package to whatever endian format we are using
  * natively.
  *
  * Parameters:

+ 1 - 1
Utilities/cmcurl/lib/curl_fnmatch.c

@@ -80,7 +80,7 @@ static int parsekeyword(unsigned char **pattern, unsigned char *charset)
   unsigned char *p = *pattern;
   bool found = FALSE;
   for(i = 0; !found; i++) {
-    char c = *p++;
+    char c = (char)*p++;
     if(i >= KEYLEN)
       return SETCHARSET_FAIL;
     switch(state) {

+ 5 - 5
Utilities/cmcurl/lib/curl_gethostname.c

@@ -28,14 +28,14 @@
 
 /*
  * Curl_gethostname() is a wrapper around gethostname() which allows
- * overriding the host name that the function would normally return.
+ * overriding the hostname that the function would normally return.
  * This capability is used by the test suite to verify exact matching
  * of NTLM authentication, which exercises libcurl's MD4 and DES code
  * as well as by the SMTP module when a hostname is not provided.
  *
- * For libcurl debug enabled builds host name overriding takes place
+ * For libcurl debug enabled builds hostname overriding takes place
  * when environment variable CURL_GETHOSTNAME is set, using the value
- * held by the variable to override returned host name.
+ * held by the variable to override returned hostname.
  *
  * Note: The function always returns the un-qualified hostname rather
  * than being provider dependent.
@@ -45,7 +45,7 @@
  * mechanism which intercepts, and might override, the gethostname()
  * function call. In this case a given platform must support the
  * LD_PRELOAD mechanism and additionally have environment variable
- * CURL_GETHOSTNAME set in order to override the returned host name.
+ * CURL_GETHOSTNAME set in order to override the returned hostname.
  *
  * For libcurl static library release builds no overriding takes place.
  */
@@ -65,7 +65,7 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
 
 #ifdef DEBUGBUILD
 
-  /* Override host name when environment variable CURL_GETHOSTNAME is set */
+  /* Override hostname when environment variable CURL_GETHOSTNAME is set */
   const char *force_hostname = getenv("CURL_GETHOSTNAME");
   if(force_hostname) {
     strncpy(name, force_hostname, namelen - 1);

+ 4 - 3
Utilities/cmcurl/lib/curl_multibyte.h

@@ -49,9 +49,10 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
  * Allocated memory should be free'd with curlx_unicodefree().
  *
  * Note: Because these are curlx functions their memory usage is not tracked
- * by the curl memory tracker memdebug. You'll notice that curlx function-like
- * macros call free and strdup in parentheses, eg (strdup)(ptr), and that's to
- * ensure that the curl memdebug override macros do not replace them.
+ * by the curl memory tracker memdebug. you will notice that curlx
+ * function-like macros call free and strdup in parentheses, eg (strdup)(ptr),
+ * and that is to ensure that the curl memdebug override macros do not replace
+ * them.
  */
 
 #if defined(UNICODE) && defined(_WIN32)

+ 18 - 18
Utilities/cmcurl/lib/curl_ntlm_core.c

@@ -110,7 +110,7 @@
 #elif defined(USE_WIN32_CRYPTO)
 #  include <wincrypt.h>
 #else
-#  error "Can't compile NTLM support without a crypto library with DES."
+#  error "cannot compile NTLM support without a crypto library with DES."
 #  define CURL_NTLM_NOT_SUPPORTED
 #endif
 
@@ -137,20 +137,20 @@
 */
 static void extend_key_56_to_64(const unsigned char *key_56, char *key)
 {
-  key[0] = key_56[0];
-  key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
-  key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
-  key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
-  key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
-  key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
-  key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
-  key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
+  key[0] = (char)key_56[0];
+  key[1] = (char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+  key[2] = (char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+  key[3] = (char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+  key[4] = (char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+  key[5] = (char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+  key[6] = (char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+  key[7] = (char) ((key_56[6] << 1) & 0xFF);
 }
 #endif
 
 #if defined(USE_OPENSSL_DES) || defined(USE_WOLFSSL)
 /*
- * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.  The
+ * Turns a 56-bit key into a 64-bit, odd parity key and sets the key. The
  * key schedule ks is also set.
  */
 static void setup_des_key(const unsigned char *key_56,
@@ -158,7 +158,7 @@ static void setup_des_key(const unsigned char *key_56,
 {
   DES_cblock key;
 
-  /* Expand the 56-bit key to 64-bits */
+  /* Expand the 56-bit key to 64 bits */
   extend_key_56_to_64(key_56, (char *) &key);
 
   /* Set the key parity to odd */
@@ -175,7 +175,7 @@ static void setup_des_key(const unsigned char *key_56,
 {
   char key[8];
 
-  /* Expand the 56-bit key to 64-bits */
+  /* Expand the 56-bit key to 64 bits */
   extend_key_56_to_64(key_56, key);
 
   /* Set the key parity to odd */
@@ -193,7 +193,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
   mbedtls_des_context ctx;
   char key[8];
 
-  /* Expand the 56-bit key to 64-bits */
+  /* Expand the 56-bit key to 64 bits */
   extend_key_56_to_64(key_56, key);
 
   /* Set the key parity to odd */
@@ -214,7 +214,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
   size_t out_len;
   CCCryptorStatus err;
 
-  /* Expand the 56-bit key to 64-bits */
+  /* Expand the 56-bit key to 64 bits */
   extend_key_56_to_64(key_56, key);
 
   /* Set the key parity to odd */
@@ -240,7 +240,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
   ctl.Func_ID = ENCRYPT_ONLY;
   ctl.Data_Len = sizeof(key);
 
-  /* Expand the 56-bit key to 64-bits */
+  /* Expand the 56-bit key to 64 bits */
   extend_key_56_to_64(key_56, ctl.Crypto_Key);
 
   /* Set the key parity to odd */
@@ -278,7 +278,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out,
   blob.hdr.aiKeyAlg = CALG_DES;
   blob.len = sizeof(blob.key);
 
-  /* Expand the 56-bit key to 64-bits */
+  /* Expand the 56-bit key to 64 bits */
   extend_key_56_to_64(key_56, blob.key);
 
   /* Set the key parity to odd */
@@ -466,13 +466,13 @@ static void time2filetime(struct ms_filetime *ft, time_t t)
   unsigned int r, s;
   unsigned int i;
 
-  ft->dwLowDateTime = t & 0xFFFFFFFF;
+  ft->dwLowDateTime = (unsigned int)t & 0xFFFFFFFF;
   ft->dwHighDateTime = 0;
 
 # ifndef HAVE_TIME_T_UNSIGNED
   /* Extend sign if needed. */
   if(ft->dwLowDateTime & 0x80000000)
-    ft->dwHighDateTime = ~0;
+    ft->dwHighDateTime = ~(unsigned int)0;
 # endif
 
   /* Bias seconds to Jan 1, 1601.

+ 0 - 7
Utilities/cmcurl/lib/curl_ntlm_core.h

@@ -28,13 +28,6 @@
 
 #if defined(USE_CURL_NTLM_CORE)
 
-#if defined(USE_OPENSSL)
-#  include <openssl/ssl.h>
-#elif defined(USE_WOLFSSL)
-#  include <wolfssl/options.h>
-#  include <wolfssl/openssl/ssl.h>
-#endif
-
 /* Helpers to generate function byte arguments in little endian order */
 #define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
 #define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \

+ 3 - 3
Utilities/cmcurl/lib/curl_rtmp.c

@@ -236,7 +236,7 @@ static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
 
   r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
 
-  /* We have to know if it's a write before we send the
+  /* We have to know if it is a write before we send the
    * connect request packet
    */
   if(data->state.upload)
@@ -273,10 +273,10 @@ static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
 
   if(data->state.upload) {
     Curl_pgrsSetUploadSize(data, data->state.infilesize);
-    Curl_xfer_setup(data, -1, -1, FALSE, FIRSTSOCKET);
+    Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE);
   }
   else
-    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+    Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
   *done = TRUE;
   return CURLE_OK;
 }

+ 1 - 1
Utilities/cmcurl/lib/curl_sasl.c

@@ -328,7 +328,7 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
   if(data->state.aptr.user)
     return TRUE;
 
-  /* EXTERNAL can authenticate without a user name and/or password */
+  /* EXTERNAL can authenticate without a username and/or password */
   if(sasl->authmechs & sasl->prefmech & SASL_MECH_EXTERNAL)
     return TRUE;
 

+ 60 - 11
Utilities/cmcurl/lib/curl_setup.h

@@ -40,6 +40,43 @@
 #include <_mingw.h>
 #endif
 
+/* Workaround for Homebrew gcc 12.4.0, 13.3.0, 14.1.0 and newer (as of 14.1.0)
+   that started advertising the `availability` attribute, which then gets used
+   by Apple SDK, but, in a way incompatible with gcc, resulting in a misc
+   errors inside SDK headers, e.g.:
+     error: attributes should be specified before the declarator in a function
+            definition
+     error: expected ',' or '}' before
+   Followed by missing declarations.
+   Fix it by overriding the built-in feature-check macro used by the headers
+   to enable the problematic attributes. This makes the feature check fail. */
+#if defined(__APPLE__) &&                \
+  !defined(__clang__) &&                 \
+  defined(__GNUC__) && __GNUC__ >= 12 && \
+  defined(__has_attribute)
+#define availability curl_pp_attribute_disabled
+#endif
+
+#if defined(__APPLE__)
+#include <sys/types.h>
+#include <TargetConditionals.h>
+/* Fixup faulty target macro initialization in macOS SDK since v14.4 (as of
+   15.0 beta). The SDK target detection in `TargetConditionals.h` correctly
+   detects macOS, but fails to set the macro's old name `TARGET_OS_OSX`, then
+   continues to set it to a default value of 0. Other parts of the SDK still
+   rely on the old name, and with this inconsistency our builds fail due to
+   missing declarations. It happens when using mainline llvm older than v18.
+   Later versions fixed it by predefining these target macros, avoiding the
+   faulty dynamic detection. gcc is not affected (for now) because it lacks
+   the necessary dynamic detection features, so the SDK falls back to
+   a codepath that sets both the old and new macro to 1. */
+#if defined(TARGET_OS_MAC) && TARGET_OS_MAC && \
+  defined(TARGET_OS_OSX) && !TARGET_OS_OSX
+#undef TARGET_OS_OSX
+#define TARGET_OS_OSX TARGET_OS_MAC
+#endif
+#endif
+
 /*
  * Disable Visual Studio warnings:
  * 4127 "conditional expression is constant"
@@ -50,7 +87,7 @@
 
 #ifdef _WIN32
 /*
- * Don't include unneeded stuff in Windows headers to avoid compiler
+ * Do not include unneeded stuff in Windows headers to avoid compiler
  * warnings and macro clashes.
  * Make sure to define this macro before including any Windows headers.
  */
@@ -310,13 +347,25 @@
 #define CURL_PRINTF(fmt, arg)
 #endif
 
+/* Workaround for mainline llvm v16 and earlier missing a built-in macro
+   expected by macOS SDK v14 / Xcode v15 (2023) and newer.
+   gcc (as of v14) is also missing it. */
+#if defined(__APPLE__) &&                                   \
+  ((!defined(__apple_build_version__) &&                    \
+    defined(__clang__) && __clang_major__ < 17) ||          \
+   (defined(__GNUC__) && __GNUC__ <= 14)) &&                \
+  defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
+  !defined(__ENVIRONMENT_OS_VERSION_MIN_REQUIRED__)
+#define __ENVIRONMENT_OS_VERSION_MIN_REQUIRED__             \
+  __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__
+#endif
+
 /*
  * Use getaddrinfo to resolve the IPv4 address literal. If the current network
- * interface doesn't support IPv4, but supports IPv6, NAT64, and DNS64,
+ * interface does not support IPv4, but supports IPv6, NAT64, and DNS64,
  * performing this task will result in a synthesized IPv6 address.
  */
 #if defined(__APPLE__) && !defined(USE_ARES)
-#include <TargetConditionals.h>
 #define USE_RESOLVE_ON_IPS 1
 #  if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \
      defined(USE_IPV6)
@@ -462,7 +511,7 @@
 #endif
 
 #ifndef SIZEOF_TIME_T
-/* assume default size of time_t to be 32 bit */
+/* assume default size of time_t to be 32 bits */
 #define SIZEOF_TIME_T 4
 #endif
 
@@ -485,7 +534,7 @@
 #endif
 
 /*
- * Default sizeof(off_t) in case it hasn't been defined in config file.
+ * Default sizeof(off_t) in case it has not been defined in config file.
  */
 
 #ifndef SIZEOF_OFF_T
@@ -552,7 +601,7 @@
 #endif
 
 #ifndef SIZE_T_MAX
-/* some limits.h headers have this defined, some don't */
+/* some limits.h headers have this defined, some do not */
 #if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
 #define SIZE_T_MAX 18446744073709551615U
 #else
@@ -561,7 +610,7 @@
 #endif
 
 #ifndef SSIZE_T_MAX
-/* some limits.h headers have this defined, some don't */
+/* some limits.h headers have this defined, some do not */
 #if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4)
 #define SSIZE_T_MAX 9223372036854775807
 #else
@@ -570,7 +619,7 @@
 #endif
 
 /*
- * Arg 2 type for gethostname in case it hasn't been defined in config file.
+ * Arg 2 type for gethostname in case it has not been defined in config file.
  */
 
 #ifndef GETHOSTNAME_TYPE_ARG2
@@ -785,7 +834,7 @@
 #endif
 
 /*
- * shutdown() flags for systems that don't define them
+ * shutdown() flags for systems that do not define them
  */
 
 #ifndef SHUT_RD
@@ -833,7 +882,7 @@ endings either CRLF or LF so 't' is appropriate.
 #define FOPEN_APPENDTEXT "a"
 #endif
 
-/* for systems that don't detect this in configure */
+/* for systems that do not detect this in configure */
 #ifndef CURL_SA_FAMILY_T
 #  if defined(HAVE_SA_FAMILY_T)
 #    define CURL_SA_FAMILY_T sa_family_t
@@ -862,7 +911,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
                size_t buflen, struct passwd **result);
 #endif
 
-#ifdef DEBUGBUILD
+#ifdef UNITTESTS
 #define UNITTEST
 #else
 #define UNITTEST static

+ 7 - 7
Utilities/cmcurl/lib/curl_setup_once.h

@@ -106,7 +106,7 @@
 #endif
 
 /*
- * Definition of timeval struct for platforms that don't have it.
+ * Definition of timeval struct for platforms that do not have it.
  */
 
 #ifndef HAVE_STRUCT_TIMEVAL
@@ -130,7 +130,7 @@ struct timeval {
 
 
 #if defined(__minix)
-/* Minix doesn't support recv on TCP sockets */
+/* Minix does not support recv on TCP sockets */
 #define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
                                    (RECV_TYPE_ARG2)(y), \
                                    (RECV_TYPE_ARG3)(z))
@@ -143,7 +143,7 @@ struct timeval {
  *
  * HAVE_RECV is defined if you have a function named recv()
  * which is used to read incoming data from sockets. If your
- * function has another name then don't define HAVE_RECV.
+ * function has another name then do not define HAVE_RECV.
  *
  * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
  * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
@@ -151,7 +151,7 @@ struct timeval {
  *
  * HAVE_SEND is defined if you have a function named send()
  * which is used to write outgoing data on a connected socket.
- * If yours has another name then don't define HAVE_SEND.
+ * If yours has another name then do not define HAVE_SEND.
  *
  * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
  * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
@@ -170,7 +170,7 @@ struct timeval {
 
 
 #if defined(__minix)
-/* Minix doesn't support send on TCP sockets */
+/* Minix does not support send on TCP sockets */
 #define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
                                     (SEND_TYPE_ARG2)(y), \
                                     (SEND_TYPE_ARG3)(z))
@@ -226,7 +226,7 @@ struct timeval {
 
 /*
  * 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
- * On non-C99 platforms there's no bool, so define an enum for that.
+ * On non-C99 platforms there is no bool, so define an enum for that.
  * On C99 platforms 'false' and 'true' also exist. Enum uses a
  * global namespace though, so use bool_false and bool_true.
  */
@@ -238,7 +238,7 @@ struct timeval {
   } bool;
 
 /*
- * Use a define to let 'true' and 'false' use those enums.  There
+ * Use a define to let 'true' and 'false' use those enums. There
  * are currently no use of true and false in libcurl proper, but
  * there are some in the examples. This will cater for any later
  * code happening to use true and false.

+ 9 - 9
Utilities/cmcurl/lib/curl_sha512_256.c

@@ -270,9 +270,9 @@ Curl_sha512_256_finish(unsigned char *digest,
  * ** written by Evgeny Grin (Karlson2k) for GNU libmicrohttpd.          ** *
  * ** The author ported the code to libcurl. The ported code is provided ** *
  * ** under curl license.                                                ** *
- * ** This is a minimal version with minimal optimisations. Performance  ** *
+ * ** This is a minimal version with minimal optimizations. Performance  ** *
  * ** can be significantly improved. Big-endian store and load macros    ** *
- * ** are obvious targets for optimisation.                              ** */
+ * ** are obvious targets for optimization.                              ** */
 
 #ifdef __GNUC__
 #  if defined(__has_attribute) && defined(__STDC_VERSION__)
@@ -328,7 +328,7 @@ MHDx_rotr64(curl_uint64_t value, unsigned int bits)
   bits %= 64;
   if(0 == bits)
     return value;
-  /* Defined in a form which modern compiler could optimise. */
+  /* Defined in a form which modern compiler could optimize. */
   return (value >> bits) | (value << (64 - bits));
 }
 
@@ -474,10 +474,10 @@ MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
      See FIPS PUB 180-4 section 5.2.2, 6.7, 6.4. */
   curl_uint64_t W[16];
 
-  /* 'Ch' and 'Maj' macro functions are defined with widely-used optimisation.
+  /* 'Ch' and 'Maj' macro functions are defined with widely-used optimization.
      See FIPS PUB 180-4 formulae 4.8, 4.9. */
-#define Ch(x,y,z)     ( (z) ^ ((x) & ((y) ^ (z))) )
-#define Maj(x,y,z)    ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
+#define Sha512_Ch(x,y,z)     ( (z) ^ ((x) & ((y) ^ (z))) )
+#define Sha512_Maj(x,y,z)    ( ((x) & (y)) ^ ((z) & ((x) ^ (y))) )
 
   /* Four 'Sigma' macro functions.
      See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
@@ -547,9 +547,9 @@ MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
        * Note: 'wt' must be used exactly one time in this macro as macro for
        'wt' calculation may change other data as well every time when
        used. */
-#define SHA2STEP64(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do {                  \
-      (vD) += ((vH) += SIG1 ((vE)) + Ch ((vE),(vF),(vG)) + (kt) + (wt)); \
-      (vH) += SIG0 ((vA)) + Maj ((vA),(vB),(vC)); } while (0)
+#define SHA2STEP64(vA,vB,vC,vD,vE,vF,vG,vH,kt,wt) do {                       \
+     (vD) += ((vH) += SIG1((vE)) + Sha512_Ch((vE),(vF),(vG)) + (kt) + (wt)); \
+     (vH) += SIG0((vA)) + Sha512_Maj((vA),(vB),(vC)); } while (0)
 
     /* One step of SHA-512/256 computation with working variables rotation,
        see FIPS PUB 180-4 section 6.4.2 step 3. This macro version reassigns

+ 1 - 1
Utilities/cmcurl/lib/curl_sspi.c

@@ -134,7 +134,7 @@ void Curl_sspi_global_cleanup(void)
  *
  * Parameters:
  *
- * userp    [in]     - The user name in the format User or Domain\User.
+ * userp    [in]     - The username in the format User or Domain\User.
  * passwdp  [in]     - The user's password.
  * identity [in/out] - The identity structure.
  *

+ 9 - 4
Utilities/cmcurl/lib/curl_threads.c

@@ -100,18 +100,23 @@ int Curl_thread_join(curl_thread_t *hnd)
 
 #elif defined(USE_THREADS_WIN32)
 
-/* !checksrc! disable SPACEBEFOREPAREN 1 */
-curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
+curl_thread_t Curl_thread_create(
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+                                 DWORD
+#else
+                                 unsigned int
+#endif
+                                 (CURL_STDCALL *func) (void *),
                                  void *arg)
 {
-#ifdef _WIN32_WCE
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
   typedef HANDLE curl_win_thread_handle_t;
 #else
   typedef uintptr_t curl_win_thread_handle_t;
 #endif
   curl_thread_t t;
   curl_win_thread_handle_t thread_handle;
-#ifdef _WIN32_WCE
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
   thread_handle = CreateThread(NULL, 0, func, arg, 0, NULL);
 #else
   thread_handle = _beginthreadex(NULL, 0, func, arg, 0, NULL);

+ 7 - 2
Utilities/cmcurl/lib/curl_threads.h

@@ -52,8 +52,13 @@
 
 #if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
 
-/* !checksrc! disable SPACEBEFOREPAREN 1 */
-curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void *),
+curl_thread_t Curl_thread_create(
+#if defined(_WIN32_WCE) || defined(CURL_WINDOWS_APP)
+                                 DWORD
+#else
+                                 unsigned int
+#endif
+                                 (CURL_STDCALL *func) (void *),
                                  void *arg);
 
 void Curl_thread_destroy(curl_thread_t hnd);

+ 2 - 2
Utilities/cmcurl/lib/cw-out.c

@@ -228,8 +228,8 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx,
     if(CURL_WRITEFUNC_PAUSE == nwritten) {
       if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) {
         /* Protocols that work without network cannot be paused. This is
-           actually only FILE:// just now, and it can't pause since the
-           transfer isn't done using the "normal" procedure. */
+           actually only FILE:// just now, and it cannot pause since the
+           transfer is not done using the "normal" procedure. */
         failf(data, "Write callback asked for PAUSE when not supported");
         return CURLE_WRITE_ERROR;
       }

+ 3 - 3
Utilities/cmcurl/lib/dict.c

@@ -241,7 +241,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
       failf(data, "Failed sending DICT request");
       goto error;
     }
-    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1); /* no upload */
+    Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */
   }
   else if(strncasecompare(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
           strncasecompare(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
@@ -287,7 +287,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
       failf(data, "Failed sending DICT request");
       goto error;
     }
-    Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+    Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
   }
   else {
 
@@ -309,7 +309,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
         goto error;
       }
 
-      Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+      Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
     }
   }
 

+ 81 - 48
Utilities/cmcurl/lib/doh.c

@@ -93,21 +93,21 @@ UNITTEST DOHcode doh_encode(const char *host,
   const char *hostp = host;
 
   /* The expected output length is 16 bytes more than the length of
-   * the QNAME-encoding of the host name.
+   * the QNAME-encoding of the hostname.
    *
    * A valid DNS name may not contain a zero-length label, except at
-   * the end.  For this reason, a name beginning with a dot, or
+   * the end. For this reason, a name beginning with a dot, or
    * containing a sequence of two or more consecutive dots, is invalid
    * and cannot be encoded as a QNAME.
    *
-   * If the host name ends with a trailing dot, the corresponding
-   * QNAME-encoding is one byte longer than the host name. If (as is
+   * If the hostname ends with a trailing dot, the corresponding
+   * QNAME-encoding is one byte longer than the hostname. If (as is
    * also valid) the hostname is shortened by the omission of the
    * trailing dot, then its QNAME-encoding will be two bytes longer
-   * than the host name.
+   * than the hostname.
    *
    * Each [ label, dot ] pair is encoded as [ length, label ],
-   * preserving overall length.  A final [ label ] without a dot is
+   * preserving overall length. A final [ label ] without a dot is
    * also encoded as [ length, label ], increasing overall length
    * by one. The encoding is completed by appending a zero byte,
    * representing the zero-length root label, again increasing
@@ -191,7 +191,7 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
   return realsize;
 }
 
-#if defined(USE_HTTPSRR) && defined(CURLDEBUG)
+#if defined(USE_HTTPSRR) && defined(DEBUGBUILD)
 static void local_print_buf(struct Curl_easy *data,
                             const char *prefix,
                             unsigned char *buf, size_t len)
@@ -285,7 +285,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
     ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
     ERROR_CHECK_SETOPT(CURLOPT_PIPEWAIT, 1L);
 #endif
-#ifndef CURLDEBUG
+#ifndef DEBUGBUILD
     /* enforce HTTPS if not debug */
     ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
 #else
@@ -400,7 +400,6 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
                                int *waitp)
 {
   CURLcode result = CURLE_OK;
-  int slot;
   struct dohdata *dohp;
   struct connectdata *conn = data->conn;
 #ifdef USE_HTTPSRR
@@ -455,9 +454,9 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
    * TODO: Figure out the conditions under which we want to make
    * a request for an HTTPS RR when we are not doing ECH. For now,
    * making this request breaks a bunch of DoH tests, e.g. test2100,
-   * where the additional request doesn't match the pre-cooked data
-   * files, so there's a bit of work attached to making the request
-   * in a non-ECH use-case. For the present, we'll only make the
+   * where the additional request does not match the pre-cooked data
+   * files, so there is a bit of work attached to making the request
+   * in a non-ECH use-case. For the present, we will only make the
    * request when ECH is enabled in the build and is being used for
    * the curl operation.
    */
@@ -473,7 +472,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
     result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_HTTPS],
                       DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
                       data->multi, dohp->headers);
-    free(qname);
+    Curl_safefree(qname);
     if(result)
       goto error;
     dohp->pending++;
@@ -484,13 +483,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
   return NULL;
 
 error:
-  curl_slist_free_all(dohp->headers);
-  data->req.doh->headers = NULL;
-  for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-    (void)curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
-    Curl_close(&dohp->probe[slot].easy);
-  }
-  Curl_safefree(data->req.doh);
+  Curl_doh_cleanup(data);
   return NULL;
 }
 
@@ -518,12 +511,12 @@ static DOHcode skipqname(const unsigned char *doh, size_t dohlen,
   return DOH_OK;
 }
 
-static unsigned short get16bit(const unsigned char *doh, int index)
+static unsigned short get16bit(const unsigned char *doh, unsigned int index)
 {
   return (unsigned short)((doh[index] << 8) | doh[index + 1]);
 }
 
-static unsigned int get32bit(const unsigned char *doh, int index)
+static unsigned int get32bit(const unsigned char *doh, unsigned int index)
 {
   /* make clang and gcc optimize this to bswap by incrementing
      the pointer first. */
@@ -531,7 +524,7 @@ static unsigned int get32bit(const unsigned char *doh, int index)
 
   /* avoid undefined behavior by casting to unsigned before shifting
      24 bits, possibly into the sign bit. codegen is same, but
-     ub sanitizer won't be upset */
+     ub sanitizer will not be upset */
   return ((unsigned)doh[0] << 24) | ((unsigned)doh[1] << 16) |
          ((unsigned)doh[2] << 8) | doh[3];
 }
@@ -606,7 +599,7 @@ static DOHcode store_cname(const unsigned char *doh,
 
       /* move to the new index */
       newpos = (length & 0x3f) << 8 | doh[index + 1];
-      index = newpos;
+      index = (unsigned int)newpos;
       continue;
     }
     else if(length & 0xc0)
@@ -670,7 +663,7 @@ static DOHcode rdata(const unsigned char *doh,
     break;
 #endif
   case DNS_TYPE_CNAME:
-    rc = store_cname(doh, dohlen, index, d);
+    rc = store_cname(doh, dohlen, (unsigned int)index, d);
     if(rc)
       return rc;
     break;
@@ -771,7 +764,7 @@ UNITTEST DOHcode doh_decode(const unsigned char *doh,
     if(dohlen < (index + rdlength))
       return DOH_DNS_OUT_OF_RANGE;
 
-    rc = rdata(doh, dohlen, rdlength, type, index, d);
+    rc = rdata(doh, dohlen, rdlength, type, (int)index, d);
     if(rc)
       return rc; /* bad rdata */
     index += rdlength;
@@ -870,7 +863,7 @@ static void showdoh(struct Curl_easy *data,
   }
 #ifdef USE_HTTPSRR
   for(i = 0; i < d->numhttps_rrs; i++) {
-# ifdef CURLDEBUG
+# ifdef DEBUGBUILD
     local_print_buf(data, "DoH HTTPS",
                     d->https_rrs[i].val, d->https_rrs[i].len);
 # else
@@ -891,11 +884,11 @@ static void showdoh(struct Curl_easy *data,
  *
  * This function returns a pointer to the first element of a newly allocated
  * Curl_addrinfo struct linked list filled with the data from a set of DoH
- * lookups.  Curl_addrinfo is meant to work like the addrinfo struct does for
+ * lookups. Curl_addrinfo is meant to work like the addrinfo struct does for
  * a IPv6 stack, but usable also for IPv4, all hosts and environments.
  *
  * The memory allocated by this function *MUST* be free'd later on calling
- * Curl_freeaddrinfo().  For each successful call to this function there
+ * Curl_freeaddrinfo(). For each successful call to this function there
  * must be an associated call later to Curl_freeaddrinfo().
  */
 
@@ -923,7 +916,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
     CURL_SA_FAMILY_T addrtype;
     if(de->addr[i].type == DNS_TYPE_AAAA) {
 #ifndef USE_IPV6
-      /* we can't handle IPv6 addresses */
+      /* we cannot handle IPv6 addresses */
       continue;
 #else
       ss_size = sizeof(struct sockaddr_in6);
@@ -967,7 +960,11 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
       addr = (void *)ai->ai_addr; /* storage area for this info */
       DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
       memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
+#ifdef __MINGW32__
+      addr->sin_family = (short)addrtype;
+#else
       addr->sin_family = addrtype;
+#endif
       addr->sin_port = htons((unsigned short)port);
       break;
 
@@ -976,7 +973,11 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
       DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
       memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
+#ifdef __MINGW32__
+      addr6->sin6_family = (short)addrtype;
+#else
       addr6->sin6_family = addrtype;
+#endif
       addr6->sin6_port = htons((unsigned short)port);
       break;
 #endif
@@ -1020,7 +1021,7 @@ UNITTEST void de_cleanup(struct dohentry *d)
   }
 #ifdef USE_HTTPSRR
   for(i = 0; i < d->numhttps_rrs; i++)
-    free(d->https_rrs[i].val);
+    Curl_safefree(d->https_rrs[i].val);
 #endif
 }
 
@@ -1038,7 +1039,7 @@ UNITTEST void de_cleanup(struct dohentry *d)
  *
  * The input buffer pointer will be modified so it points to
  * just after the end of the DNS name encoding on output. (And
- * that's why it's an "unsigned char **" :-)
+ * that is why it is an "unsigned char **" :-)
  */
 static CURLcode local_decode_rdata_name(unsigned char **buf, size_t *remaining,
                                         char **dnsname)
@@ -1097,7 +1098,7 @@ static CURLcode local_decode_rdata_alpn(unsigned char *rrval, size_t len,
    * output is comma-sep list of the strings
    * implementations may or may not handle quoting of comma within
    * string values, so we might see a comma within the wire format
-   * version of a string, in which case we'll precede that by a
+   * version of a string, in which case we will precede that by a
    * backslash - same goes for a backslash character, and of course
    * we need to use two backslashes in strings when we mean one;-)
    */
@@ -1143,10 +1144,10 @@ err:
   return CURLE_BAD_CONTENT_ENCODING;
 }
 
-#ifdef CURLDEBUG
+#ifdef DEBUGBUILD
 static CURLcode test_alpn_escapes(void)
 {
-  /* we'll use an example from draft-ietf-dnsop-svcb, figure 10 */
+  /* we will use an example from draft-ietf-dnsop-svcb, figure 10 */
   static unsigned char example[] = {
     0x08,                                           /* length 8 */
     0x66, 0x5c, 0x6f, 0x6f, 0x2c, 0x62, 0x61, 0x72, /* value "f\\oo,bar" */
@@ -1176,8 +1177,8 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
   struct Curl_https_rrinfo *lhrr = NULL;
   char *dnsname = NULL;
 
-#ifdef CURLDEBUG
-  /* a few tests of escaping, shouldn't be here but ok for now */
+#ifdef DEBUGBUILD
+  /* a few tests of escaping, should not be here but ok for now */
   if(test_alpn_escapes() != CURLE_OK)
     return CURLE_OUT_OF_MEMORY;
 #endif
@@ -1209,18 +1210,24 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
     if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
       lhrr->no_def_alpn = TRUE;
     else if(pcode == HTTPS_RR_CODE_IPV4) {
+      if(!plen)
+        goto err;
       lhrr->ipv4hints = Curl_memdup(cp, plen);
       if(!lhrr->ipv4hints)
         goto err;
       lhrr->ipv4hints_len = (size_t)plen;
     }
     else if(pcode == HTTPS_RR_CODE_ECH) {
+      if(!plen)
+        goto err;
       lhrr->echconfiglist = Curl_memdup(cp, plen);
       if(!lhrr->echconfiglist)
         goto err;
       lhrr->echconfiglist_len = (size_t)plen;
     }
     else if(pcode == HTTPS_RR_CODE_IPV6) {
+      if(!plen)
+        goto err;
       lhrr->ipv6hints = Curl_memdup(cp, plen);
       if(!lhrr->ipv6hints)
         goto err;
@@ -1236,15 +1243,16 @@ static CURLcode Curl_doh_decode_httpsrr(unsigned char *rrval, size_t len,
   return CURLE_OK;
 err:
   if(lhrr) {
-    free(lhrr->target);
-    free(lhrr->echconfiglist);
-    free(lhrr->val);
-    free(lhrr);
+    Curl_safefree(lhrr->target);
+    Curl_safefree(lhrr->echconfiglist);
+    Curl_safefree(lhrr->val);
+    Curl_safefree(lhrr->alpns);
+    Curl_safefree(lhrr);
   }
   return CURLE_OUT_OF_MEMORY;
 }
 
-# ifdef CURLDEBUG
+# ifdef DEBUGBUILD
 static void local_print_httpsrr(struct Curl_easy *data,
                                 struct Curl_https_rrinfo *hrr)
 {
@@ -1310,10 +1318,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
     struct dohentry de;
     int slot;
     /* remove DoH handles from multi handle and close them */
-    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-      curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
-      Curl_close(&dohp->probe[slot].easy);
-    }
+    Curl_doh_close(data);
     /* parse the responses, create the struct and return it! */
     de_init(&de);
     for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
@@ -1341,7 +1346,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
 
 
       if(Curl_trc_ft_is_verbose(data, &Curl_doh_trc)) {
-        infof(data, "[DoH] Host name: %s", dohp->host);
+        infof(data, "[DoH] hostname: %s", dohp->host);
         showdoh(data, &de);
       }
 
@@ -1382,7 +1387,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
         return result;
       }
       infof(data, "Some HTTPS RR to process");
-# ifdef CURLDEBUG
+# ifdef DEBUGBUILD
       local_print_httpsrr(data, hrr);
 # endif
       (*dnsp)->hinfo = hrr;
@@ -1400,4 +1405,32 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
   return CURLE_OK;
 }
 
+void Curl_doh_close(struct Curl_easy *data)
+{
+  struct dohdata *doh = data->req.doh;
+  if(doh) {
+    size_t slot;
+    for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
+      if(!doh->probe[slot].easy)
+        continue;
+      /* data->multi might already be reset at this time */
+      if(doh->probe[slot].easy->multi)
+        curl_multi_remove_handle(doh->probe[slot].easy->multi,
+                                 doh->probe[slot].easy);
+      Curl_close(&doh->probe[slot].easy);
+    }
+  }
+}
+
+void Curl_doh_cleanup(struct Curl_easy *data)
+{
+  struct dohdata *doh = data->req.doh;
+  if(doh) {
+    Curl_doh_close(data);
+    curl_slist_free_all(doh->headers);
+    data->req.doh->headers = NULL;
+    Curl_safefree(data->req.doh);
+  }
+}
+
 #endif /* CURL_DISABLE_DOH */

+ 16 - 13
Utilities/cmcurl/lib/doh.h

@@ -140,19 +140,22 @@ struct dohentry {
 #endif
 };
 
-
-#ifdef DEBUGBUILD
-DOHcode doh_encode(const char *host,
-                   DNStype dnstype,
-                   unsigned char *dnsp, /* buffer */
-                   size_t len,  /* buffer size */
-                   size_t *olen); /* output length */
-DOHcode doh_decode(const unsigned char *doh,
-                   size_t dohlen,
-                   DNStype dnstype,
-                   struct dohentry *d);
-void de_init(struct dohentry *d);
-void de_cleanup(struct dohentry *d);
+void Curl_doh_close(struct Curl_easy *data);
+void Curl_doh_cleanup(struct Curl_easy *data);
+
+#ifdef UNITTESTS
+UNITTEST DOHcode doh_encode(const char *host,
+                            DNStype dnstype,
+                            unsigned char *dnsp,  /* buffer */
+                            size_t len,  /* buffer size */
+                            size_t *olen);  /* output length */
+UNITTEST DOHcode doh_decode(const unsigned char *doh,
+                            size_t dohlen,
+                            DNStype dnstype,
+                            struct dohentry *d);
+
+UNITTEST void de_init(struct dohentry *d);
+UNITTEST void de_cleanup(struct dohentry *d);
 #endif
 
 extern struct curl_trc_feat Curl_doh_trc;

+ 2 - 2
Utilities/cmcurl/lib/dynbuf.c

@@ -51,7 +51,7 @@ void Curl_dyn_init(struct dynbuf *s, size_t toobig)
 }
 
 /*
- * free the buffer and re-init the necessary fields. It doesn't touch the
+ * free the buffer and re-init the necessary fields. It does not touch the
  * 'init' field and thus this buffer can be reused to add data to again.
  */
 void Curl_dyn_free(struct dynbuf *s)
@@ -71,7 +71,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
   size_t a = s->allc;
   size_t fit = len + indx + 1; /* new string + old string + zero byte */
 
-  /* try to detect if there's rubbish in the struct */
+  /* try to detect if there is rubbish in the struct */
   DEBUGASSERT(s->init == DYNINIT);
   DEBUGASSERT(s->toobig);
   DEBUGASSERT(indx < s->toobig);

+ 1 - 1
Utilities/cmcurl/lib/dynhds.c

@@ -275,7 +275,7 @@ CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line)
   return Curl_dynhds_h1_add_line(dynhds, line, line? strlen(line) : 0);
 }
 
-#ifdef DEBUGBUILD
+#ifdef UNITTESTS
 /* used by unit2602.c */
 
 bool Curl_dynhds_contains(struct dynhds *dynhds,

+ 20 - 16
Utilities/cmcurl/lib/dynhds.h

@@ -95,6 +95,9 @@ struct dynhds_entry *Curl_dynhds_get(struct dynhds *dynhds,
                                      const char *name, size_t namelen);
 struct dynhds_entry *Curl_dynhds_cget(struct dynhds *dynhds, const char *name);
 
+#ifdef UNITTESTS
+/* used by unit2602.c */
+
 /**
  * Return TRUE iff one or more headers with the given name exist.
  */
@@ -115,20 +118,6 @@ size_t Curl_dynhds_count_name(struct dynhds *dynhds,
  */
 size_t Curl_dynhds_ccount_name(struct dynhds *dynhds, const char *name);
 
-/**
- * Add a header, name + value, to `dynhds` at the end. Does *not*
- * check for duplicate names.
- */
-CURLcode Curl_dynhds_add(struct dynhds *dynhds,
-                         const char *name, size_t namelen,
-                         const char *value, size_t valuelen);
-
-/**
- * Add a header, c-string name + value, to `dynhds` at the end.
- */
-CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
-                          const char *name, const char *value);
-
 /**
  * Remove all entries with the given name.
  * Returns number of entries removed.
@@ -146,19 +135,34 @@ size_t Curl_dynhds_cremove(struct dynhds *dynhds, const char *name);
 CURLcode Curl_dynhds_set(struct dynhds *dynhds,
                          const char *name, size_t namelen,
                          const char *value, size_t valuelen);
+#endif
 
 CURLcode Curl_dynhds_cset(struct dynhds *dynhds,
                           const char *name, const char *value);
 
 /**
- * Add a single header from a HTTP/1.1 formatted line at the end. Line
+ * Add a header, name + value, to `dynhds` at the end. Does *not*
+ * check for duplicate names.
+ */
+CURLcode Curl_dynhds_add(struct dynhds *dynhds,
+                         const char *name, size_t namelen,
+                         const char *value, size_t valuelen);
+
+/**
+ * Add a header, c-string name + value, to `dynhds` at the end.
+ */
+CURLcode Curl_dynhds_cadd(struct dynhds *dynhds,
+                          const char *name, const char *value);
+
+/**
+ * Add a single header from an HTTP/1.1 formatted line at the end. Line
  * may contain a delimiting \r\n or just \n. Any characters after
  * that will be ignored.
  */
 CURLcode Curl_dynhds_h1_cadd_line(struct dynhds *dynhds, const char *line);
 
 /**
- * Add a single header from a HTTP/1.1 formatted line at the end. Line
+ * Add a single header from an HTTP/1.1 formatted line at the end. Line
  * may contain a delimiting \r\n or just \n. Any characters after
  * that will be ignored.
  */

+ 17 - 11
Utilities/cmcurl/lib/easy.c

@@ -242,7 +242,7 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
   global_init_lock();
 
   if(initialized) {
-    /* Already initialized, don't do it again, but bump the variable anyway to
+    /* Already initialized, do not do it again, but bump the variable anyway to
        work like curl_global_init() and require the same amount of cleanup
        calls. */
     initialized++;
@@ -268,7 +268,8 @@ CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
 
 /**
  * curl_global_cleanup() globally cleanups curl, uses the value of
- * "easy_init_flags" to determine what needs to be cleaned up and what doesn't.
+ * "easy_init_flags" to determine what needs to be cleaned up and what does
+ * not.
  */
 void curl_global_cleanup(void)
 {
@@ -374,7 +375,7 @@ struct Curl_easy *curl_easy_init(void)
   return data;
 }
 
-#ifdef CURLDEBUG
+#ifdef DEBUGBUILD
 
 struct socketmonitor {
   struct socketmonitor *next; /* the next node in the list or NULL */
@@ -579,7 +580,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
     before = Curl_now();
 
     /* wait for activity or timeout */
-    pollrc = Curl_poll(fds, numfds, ev->ms);
+    pollrc = Curl_poll(fds, (unsigned int)numfds, ev->ms);
     if(pollrc < 0)
       return CURLE_UNRECOVERABLE_POLL;
 
@@ -627,7 +628,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
     if(mcode)
       return CURLE_URL_MALFORMAT;
 
-    /* we don't really care about the "msgs_in_queue" value returned in the
+    /* we do not really care about the "msgs_in_queue" value returned in the
        second argument */
     msg = curl_multi_info_read(multi, &pollrc);
     if(msg) {
@@ -655,8 +656,8 @@ static CURLcode easy_events(struct Curl_multi *multi)
 
   return wait_or_timeout(multi, &evs);
 }
-#else /* CURLDEBUG */
-/* when not built with debug, this function doesn't exist */
+#else /* DEBUGBUILD */
+/* when not built with debug, this function does not exist */
 #define easy_events(x) CURLE_NOT_BUILT_IN
 #endif
 
@@ -706,7 +707,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
  * easy handle, destroys the multi handle and returns the easy handle's return
  * code.
  *
- * REALITY: it can't just create and destroy the multi handle that easily. It
+ * REALITY: it cannot just create and destroy the multi handle that easily. It
  * needs to keep it around since if this easy handle is used again by this
  * function, the same multi handle must be reused so that the same pools and
  * caches can be used.
@@ -768,7 +769,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
   /* run the transfer */
   result = events ? easy_events(multi) : easy_transfer(multi);
 
-  /* ignoring the return code isn't nice, but atm we can't really handle
+  /* ignoring the return code is not nice, but atm we cannot really handle
      a failure here, room for future improvement! */
   (void)curl_multi_remove_handle(multi, data);
 
@@ -788,7 +789,7 @@ CURLcode curl_easy_perform(struct Curl_easy *data)
   return easy_perform(data, FALSE);
 }
 
-#ifdef CURLDEBUG
+#ifdef DEBUGBUILD
 /*
  * curl_easy_perform_ev() is the external interface that performs a blocking
  * transfer using the event-based API internally.
@@ -1090,7 +1091,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
   bool keep_changed, unpause_read, not_all_paused;
 
   if(!GOOD_EASY_HANDLE(data) || !data->conn)
-    /* crazy input, don't continue */
+    /* crazy input, do not continue */
     return CURLE_BAD_FUNCTION_ARGUMENT;
 
   if(Curl_is_in_callback(data))
@@ -1142,6 +1143,11 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
       goto out;
   }
 
+  if(!(k->keepon & KEEP_RECV_PAUSE) && Curl_cwriter_is_paused(data)) {
+    Curl_conn_ev_data_pause(data, FALSE);
+    result = Curl_cwriter_unpause(data);
+  }
+
 out:
   if(!result && !data->state.done && keep_changed)
     /* This transfer may have been moved in or out of the bundle, update the

+ 1 - 1
Utilities/cmcurl/lib/easygetopt.c

@@ -42,7 +42,7 @@ static struct curl_easyoption *lookup(const char *name, CURLoption id)
       }
       else {
         if((o->id == id) && !(o->flags & CURLOT_FLAG_ALIAS))
-          /* don't match alias options */
+          /* do not match alias options */
           return o;
       }
       o++;

+ 1 - 1
Utilities/cmcurl/lib/easyif.h

@@ -34,7 +34,7 @@ CURLcode Curl_senddata(struct Curl_easy *data, const void *buffer,
 CURLcode Curl_connect_only_attach(struct Curl_easy *data);
 #endif
 
-#ifdef CURLDEBUG
+#ifdef DEBUGBUILD
 CURL_EXTERN CURLcode curl_easy_perform_ev(struct Curl_easy *easy);
 #endif
 

+ 2 - 1
Utilities/cmcurl/lib/easyoptions.c

@@ -328,6 +328,7 @@ struct curl_easyoption Curl_easyopts[] = {
    CURLOT_LONG, 0},
   {"TCP_FASTOPEN", CURLOPT_TCP_FASTOPEN, CURLOT_LONG, 0},
   {"TCP_KEEPALIVE", CURLOPT_TCP_KEEPALIVE, CURLOT_LONG, 0},
+  {"TCP_KEEPCNT", CURLOPT_TCP_KEEPCNT, CURLOT_LONG, 0},
   {"TCP_KEEPIDLE", CURLOPT_TCP_KEEPIDLE, CURLOT_LONG, 0},
   {"TCP_KEEPINTVL", CURLOPT_TCP_KEEPINTVL, CURLOT_LONG, 0},
   {"TCP_NODELAY", CURLOPT_TCP_NODELAY, CURLOT_LONG, 0},
@@ -376,6 +377,6 @@ struct curl_easyoption Curl_easyopts[] = {
  */
 int Curl_easyopts_check(void)
 {
-  return ((CURLOPT_LASTENTRY%10000) != (325 + 1));
+  return ((CURLOPT_LASTENTRY%10000) != (326 + 1));
 }
 #endif

+ 6 - 5
Utilities/cmcurl/lib/escape.c

@@ -70,7 +70,8 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
     return strdup("");
 
   while(length--) {
-    unsigned char in = *string++; /* treat the characters unsigned */
+    /* treat the characters unsigned */
+    unsigned char in = (unsigned char)*string++;
 
     if(ISUNRESERVED(in)) {
       /* append this */
@@ -137,7 +138,7 @@ CURLcode Curl_urldecode(const char *string, size_t length,
   *ostring = ns;
 
   while(alloc) {
-    unsigned char in = *string;
+    unsigned char in = (unsigned char)*string;
     if(('%' == in) && (alloc > 2) &&
        ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
       /* this is two hexadecimal digits following a '%' */
@@ -157,7 +158,7 @@ CURLcode Curl_urldecode(const char *string, size_t length,
       return CURLE_URL_MALFORMAT;
     }
 
-    *ns++ = in;
+    *ns++ = (char)in;
   }
   *ns = 0; /* terminate it */
 
@@ -222,8 +223,8 @@ void Curl_hexencode(const unsigned char *src, size_t len, /* input length */
     while(len-- && (olen >= 3)) {
       /* clang-tidy warns on this line without this comment: */
       /* NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult) */
-      *out++ = hex[(*src & 0xF0)>>4];
-      *out++ = hex[*src & 0x0F];
+      *out++ = (unsigned char)hex[(*src & 0xF0)>>4];
+      *out++ = (unsigned char)hex[*src & 0x0F];
       ++src;
       olen -= 2;
     }

+ 33 - 29
Utilities/cmcurl/lib/file.c

@@ -147,7 +147,7 @@ static CURLcode file_setup_connection(struct Curl_easy *data,
 
 /*
  * file_connect() gets called from Curl_protocol_connect() to allow us to
- * do protocol-specific actions at connect-time.  We emulate a
+ * do protocol-specific actions at connect-time. We emulate a
  * connect-then-transfer protocol and "connect" to the file here
  */
 static CURLcode file_connect(struct Curl_easy *data, bool *done)
@@ -177,18 +177,18 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
     return result;
 
 #ifdef DOS_FILESYSTEM
-  /* If the first character is a slash, and there's
+  /* If the first character is a slash, and there is
      something that looks like a drive at the beginning of
-     the path, skip the slash.  If we remove the initial
+     the path, skip the slash. If we remove the initial
      slash in all cases, paths without drive letters end up
-     relative to the current directory which isn't how
+     relative to the current directory which is not how
      browsers work.
 
      Some browsers accept | instead of : as the drive letter
      separator, so we do too.
 
      On other platforms, we need the slash to indicate an
-     absolute pathname.  On Windows, absolute paths start
+     absolute pathname. On Windows, absolute paths start
      with a drive letter.
   */
   actual_path = real_path;
@@ -308,7 +308,7 @@ static CURLcode file_upload(struct Curl_easy *data)
   bool eos = FALSE;
 
   /*
-   * Since FILE: doesn't do the full init, we need to provide some extra
+   * Since FILE: does not do the full init, we need to provide some extra
    * assignments here.
    */
 
@@ -331,7 +331,7 @@ static CURLcode file_upload(struct Curl_easy *data)
 
   fd = open(file->path, mode, data->set.new_file_perms);
   if(fd < 0) {
-    failf(data, "Can't open %s for writing", file->path);
+    failf(data, "cannot open %s for writing", file->path);
     return CURLE_WRITE_ERROR;
   }
 
@@ -343,7 +343,7 @@ static CURLcode file_upload(struct Curl_easy *data)
   if(data->state.resume_from < 0) {
     if(fstat(fd, &file_stat)) {
       close(fd);
-      failf(data, "Can't get the size of %s", file->path);
+      failf(data, "cannot get the size of %s", file->path);
       return CURLE_WRITE_ERROR;
     }
     data->state.resume_from = (curl_off_t)file_stat.st_size;
@@ -413,13 +413,13 @@ out:
  * file_do() is the protocol-specific function for the do-phase, separated
  * from the connect-phase above. Other protocols merely setup the transfer in
  * the do-phase, to have it done in the main transfer loop but since some
- * platforms we support don't allow select()ing etc on file handles (as
+ * platforms we support do not allow select()ing etc on file handles (as
  * opposed to sockets) we instead perform the whole do-operation in this
  * function.
  */
 static CURLcode file_do(struct Curl_easy *data, bool *done)
 {
-  /* This implementation ignores the host name in conformance with
+  /* This implementation ignores the hostname in conformance with
      RFC 1738. Only local files (reachable via the standard file system)
      are supported. This means that files on remotely mounted directories
      (via NFS, Samba, NT sharing) can be accessed through a file:// URL
@@ -465,17 +465,18 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
     const struct tm *tm = &buffer;
     char header[80];
     int headerlen;
-    char accept_ranges[24]= { "Accept-ranges: bytes\r\n" };
+    static const char accept_ranges[]= { "Accept-ranges: bytes\r\n" };
     if(expected_size >= 0) {
-      headerlen = msnprintf(header, sizeof(header),
-                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
-                expected_size);
+      headerlen =
+        msnprintf(header, sizeof(header),
+                  "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
+                  expected_size);
       result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
       if(result)
         return result;
 
       result = Curl_client_write(data, CLIENTWRITE_HEADER,
-                                 accept_ranges, strlen(accept_ranges));
+                                 accept_ranges, sizeof(accept_ranges) - 1);
       if(result != CURLE_OK)
         return result;
     }
@@ -486,23 +487,26 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
       return result;
 
     /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
-    headerlen = msnprintf(header, sizeof(header),
-              "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
-              Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
-              tm->tm_mday,
-              Curl_month[tm->tm_mon],
-              tm->tm_year + 1900,
-              tm->tm_hour,
-              tm->tm_min,
-              tm->tm_sec,
-              data->req.no_body ? "": "\r\n");
+    headerlen =
+      msnprintf(header, sizeof(header),
+                "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+                Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+                tm->tm_mday,
+                Curl_month[tm->tm_mon],
+                tm->tm_year + 1900,
+                tm->tm_hour,
+                tm->tm_min,
+                tm->tm_sec);
     result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
+    if(!result)
+      /* end of headers */
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, "\r\n", 2);
     if(result)
       return result;
     /* set the file size to make it available post transfer */
     Curl_pgrsSetDownloadSize(data, expected_size);
     if(data->req.no_body)
-      return result;
+      return CURLE_OK;
   }
 
   /* Check whether file range has been specified */
@@ -514,7 +518,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
    * of the stream if the filesize could be determined */
   if(data->state.resume_from < 0) {
     if(!fstated) {
-      failf(data, "Can't get the size of file.");
+      failf(data, "cannot get the size of file.");
       return CURLE_READ_ERROR;
     }
     data->state.resume_from += (curl_off_t)statbuf.st_size;
@@ -522,7 +526,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
 
   if(data->state.resume_from > 0) {
     /* We check explicitly if we have a start offset, because
-     * expected_size may be -1 if we don't know how large the file is,
+     * expected_size may be -1 if we do not know how large the file is,
      * in which case we should not adjust it. */
     if(data->state.resume_from <= expected_size)
       expected_size -= data->state.resume_from;
@@ -566,7 +570,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
   if(!S_ISDIR(statbuf.st_mode)) {
     while(!result) {
       ssize_t nread;
-      /* Don't fill a whole buffer if we want less than all data */
+      /* Do not fill a whole buffer if we want less than all data */
       size_t bytestoread;
 
       if(size_known) {

+ 4 - 4
Utilities/cmcurl/lib/fopen.c

@@ -42,12 +42,12 @@
 /*
   The dirslash() function breaks a null-terminated pathname string into
   directory and filename components then returns the directory component up
-  to, *AND INCLUDING*, a final '/'.  If there is no directory in the path,
+  to, *AND INCLUDING*, a final '/'. If there is no directory in the path,
   this instead returns a "" string.
 
   This function returns a pointer to malloc'ed memory.
 
-  The input path to this function is expected to have a file name part.
+  The input path to this function is expected to have a filename part.
 */
 
 #ifdef _WIN32
@@ -88,7 +88,7 @@ static char *dirslash(const char *path)
  * Curl_fopen() opens a file for writing with a temp name, to be renamed
  * to the final name when completed. If there is an existing file using this
  * name at the time of the open, this function will clone the mode from that
- * file.  if 'tempname' is non-NULL, it needs a rename after the file is
+ * file. if 'tempname' is non-NULL, it needs a rename after the file is
  * written.
  */
 CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
@@ -117,7 +117,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename,
 
   dir = dirslash(filename);
   if(dir) {
-    /* The temp file name should not end up too long for the target file
+    /* The temp filename should not end up too long for the target file
        system */
     tempstore = aprintf("%s%s.tmp", dir, randbuf);
     free(dir);

+ 10 - 10
Utilities/cmcurl/lib/formdata.c

@@ -216,8 +216,8 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
   struct curl_forms *forms = NULL;
   char *array_value = NULL; /* value read from an array */
 
-  /* This is a state variable, that if TRUE means that we're parsing an
-     array that we got passed to us. If FALSE we're parsing the input
+  /* This is a state variable, that if TRUE means that we are parsing an
+     array that we got passed to us. If FALSE we are parsing the input
      va_list arguments. */
   bool array_state = FALSE;
 
@@ -260,7 +260,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
     switch(option) {
     case CURLFORM_ARRAY:
       if(array_state)
-        /* we don't support an array from within an array */
+        /* we do not support an array from within an array */
         return_value = CURL_FORMADD_ILLEGAL_ARRAY;
       else {
         forms = va_arg(params, struct curl_forms *);
@@ -327,7 +327,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
         array_state?(curl_off_t)(size_t)array_value:va_arg(params, curl_off_t);
       break;
 
-      /* Get contents from a given file name */
+      /* Get contents from a given filename */
     case CURLFORM_FILECONTENT:
       if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
         return_value = CURL_FORMADD_OPTION_TWICE;
@@ -429,7 +429,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
           array_state?array_value:va_arg(params, char *);
         if(userp) {
           current_form->userp = userp;
-          current_form->value = userp; /* this isn't strictly true but we
+          current_form->value = userp; /* this is not strictly true but we
                                           derive a value from this later on
                                           and we need this non-NULL to be
                                           accepted as a fine form part */
@@ -599,7 +599,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
       }
       if(!(form->flags & HTTPPOST_PTRNAME) &&
          (form == first_form) ) {
-        /* Note that there's small risk that form->name is NULL here if the
+        /* Note that there is small risk that form->name is NULL here if the
            app passed in a bad combo, so we better check for that first. */
         if(form->name) {
           /* copy name (without strdup; possibly not null-terminated) */
@@ -764,7 +764,7 @@ void curl_formfree(struct curl_httppost *form)
       )
       free(form->contents); /* free the contents */
     free(form->contenttype); /* free the content type */
-    free(form->showfilename); /* free the faked file name */
+    free(form->showfilename); /* free the faked filename */
     free(form);       /* free the struct */
     form = next;
   } while(form); /* continue */
@@ -880,10 +880,10 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
 
         if(post->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE)) {
           if(!strcmp(file->contents, "-")) {
-            /* There are a few cases where the code below won't work; in
+            /* There are a few cases where the code below will not work; in
                particular, freopen(stdin) by the caller is not guaranteed
                to result as expected. This feature has been kept for backward
-               compatibility: use of "-" pseudo file name should be avoided. */
+               compatibility: use of "-" pseudo filename should be avoided. */
             result = curl_mime_data_cb(part, (curl_off_t) -1,
                                        (curl_read_callback) fread,
                                        fseeko_wrapper,
@@ -915,7 +915,7 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
         }
       }
 
-      /* Set fake file name. */
+      /* Set fake filename. */
       if(!result && post->showfilename)
         if(post->more || (post->flags & (HTTPPOST_FILENAME | HTTPPOST_BUFFER |
                                         HTTPPOST_CALLBACK)))

+ 2 - 2
Utilities/cmcurl/lib/formdata.h

@@ -38,8 +38,8 @@ struct FormInfo {
   long flags;
   char *buffer;      /* pointer to existing buffer used for file upload */
   size_t bufferlength;
-  char *showfilename; /* The file name to show. If not set, the actual
-                         file name will be used */
+  char *showfilename; /* The filename to show. If not set, the actual
+                         filename will be used */
   char *userp;        /* pointer for the read callback */
   struct curl_slist *contentheader;
   struct FormInfo *more;

+ 96 - 90
Utilities/cmcurl/lib/ftp.c

@@ -290,12 +290,11 @@ const struct Curl_handler Curl_handler_ftps = {
 };
 #endif
 
-static void close_secondarysocket(struct Curl_easy *data,
-                                  struct connectdata *conn)
+static void close_secondarysocket(struct Curl_easy *data)
 {
   CURL_TRC_FTP(data, "[%s] closing DATA connection", FTP_DSTATE(data));
   Curl_conn_close(data, SECONDARYSOCKET);
-  Curl_conn_cf_discard_all(data, conn, SECONDARYSOCKET);
+  Curl_conn_cf_discard_all(data, data->conn, SECONDARYSOCKET);
 }
 
 /*
@@ -475,7 +474,7 @@ static CURLcode AcceptServerConnect(struct Curl_easy *data)
     Curl_set_in_callback(data, false);
 
     if(error) {
-      close_secondarysocket(data, conn);
+      close_secondarysocket(data);
       return CURLE_ABORTED_BY_CALLBACK;
     }
   }
@@ -649,19 +648,19 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
     return result;
 
   if(conn->proto.ftpc.state_saved == FTP_STOR) {
-    /* When we know we're uploading a specified file, we can get the file
+    /* When we know we are uploading a specified file, we can get the file
        size prior to the actual upload. */
     Curl_pgrsSetUploadSize(data, data->state.infilesize);
 
     /* set the SO_SNDBUF for the secondary socket for those who need it */
-    Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
+    Curl_sndbuf_init(conn->sock[SECONDARYSOCKET]);
 
-    Curl_xfer_setup(data, -1, -1, FALSE, SECONDARYSOCKET);
+    Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE);
   }
   else {
     /* FTP download: */
-    Curl_xfer_setup(data, SECONDARYSOCKET,
-                    conn->proto.ftpc.retr_size_saved, FALSE, -1);
+    Curl_xfer_setup2(data, CURL_XFER_RECV,
+                     conn->proto.ftpc.retr_size_saved, TRUE);
   }
 
   conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
@@ -674,7 +673,7 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
  *
  * AllowServerConnect()
  *
- * When we've issue the PORT command, we have told the server to connect to
+ * When we have issue the PORT command, we have told the server to connect to
  * us. This function checks whether data connection is established if so it is
  * accepted.
  *
@@ -806,7 +805,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
 {
   /*
    * We cannot read just one byte per read() and then go back to select() as
-   * the OpenSSL read() doesn't grok that properly.
+   * the OpenSSL read() does not grok that properly.
    *
    * Alas, read as much as possible, split up into lines, use the ending
    * line in a response or continue reading.  */
@@ -849,16 +848,16 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
      *
      * A caution here is that the ftp_readresp() function has a cache that may
      * contain pieces of a response from the previous invoke and we need to
-     * make sure we don't just wait for input while there is unhandled data in
+     * make sure we do not just wait for input while there is unhandled data in
      * that cache. But also, if the cache is there, we call ftp_readresp() and
-     * the cache wasn't good enough to continue we must not just busy-loop
+     * the cache was not good enough to continue we must not just busy-loop
      * around this function.
      *
      */
 
     if(Curl_dyn_len(&pp->recvbuf) && (cache_skip < 2)) {
       /*
-       * There's a cache left since before. We then skipping the wait for
+       * There is a cache left since before. We then skipping the wait for
        * socket action, unless this is the same cache like the previous round
        * as then the cache was deemed not enough to act on and we then need to
        * wait for more data anyway.
@@ -895,7 +894,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data,
 
     *nreadp += nread;
 
-  } /* while there's buffer left and loop is requested */
+  } /* while there is buffer left and loop is requested */
 
   pp->pending_resp = FALSE;
 
@@ -948,7 +947,7 @@ static int ftp_domore_getsock(struct Curl_easy *data,
   CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_DSTATE(data));
 
   if(FTP_STOP == ftpc->state) {
-    /* if stopped and still in this state, then we're also waiting for a
+    /* if stopped and still in this state, then we are also waiting for a
        connect on the secondary connection */
     DEBUGASSERT(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD ||
                (conn->cfilter[SECONDARYSOCKET] &&
@@ -1136,13 +1135,13 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
 #endif
                         ipstr, hbuf, sizeof(hbuf))) {
         case IF2IP_NOT_FOUND:
-          /* not an interface, use the given string as host name instead */
+          /* not an interface, use the given string as hostname instead */
           host = ipstr;
           break;
         case IF2IP_AF_NOT_SUPPORTED:
           goto out;
         case IF2IP_FOUND:
-          host = hbuf; /* use the hbuf for host name */
+          host = hbuf; /* use the hbuf for hostname */
           break;
       }
     }
@@ -1153,7 +1152,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
 
   if(!host) {
     const char *r;
-    /* not an interface and not a host name, get default by extracting
+    /* not an interface and not a hostname, get default by extracting
        the IP from the control connection */
     sslen = sizeof(ss);
     if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
@@ -1174,7 +1173,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
     if(!r) {
       goto out;
     }
-    host = hbuf; /* use this host name */
+    host = hbuf; /* use this hostname */
     possibly_non_local = FALSE; /* we know it is local now */
   }
 
@@ -1232,7 +1231,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
       /* It failed. */
       error = SOCKERRNO;
       if(possibly_non_local && (error == EADDRNOTAVAIL)) {
-        /* The requested bind address is not local.  Use the address used for
+        /* The requested bind address is not local. Use the address used for
          * the control connection instead and restart the port loop
          */
         infof(data, "bind(port=%hu) on non-local address failed: %s", port,
@@ -1245,7 +1244,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
           goto out;
         }
         port = port_min;
-        possibly_non_local = FALSE; /* don't try this again */
+        possibly_non_local = FALSE; /* do not try this again */
         continue;
       }
       if(error != EADDRINUSE && error != EACCES) {
@@ -1355,7 +1354,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
       char *dest = target;
 
       /* translate x.x.x.x to x,x,x,x */
-      while(source && *source) {
+      while(*source) {
         if(*source == '.')
           *dest = ',';
         else
@@ -1444,7 +1443,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
   struct connectdata *conn = data->conn;
 
   if(ftp->transfer != PPTRANSFER_BODY) {
-    /* doesn't transfer any data */
+    /* does not transfer any data */
 
     /* still possibly do PRE QUOTE jobs */
     ftp_state(data, FTP_RETR_PREQUOTE);
@@ -1512,7 +1511,7 @@ static CURLcode ftp_state_size(struct Curl_easy *data,
   if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
     /* if a "head"-like request is being made (on a file) */
 
-    /* we know ftpc->file is a valid pointer to a file name */
+    /* we know ftpc->file is a valid pointer to a filename */
     result = Curl_pp_sendf(data, &ftpc->pp, "SIZE %s", ftpc->file);
     if(!result)
       ftp_state(data, FTP_SIZE);
@@ -1590,13 +1589,13 @@ static CURLcode ftp_state_list(struct Curl_easy *data)
 
 static CURLcode ftp_state_retr_prequote(struct Curl_easy *data)
 {
-  /* We've sent the TYPE, now we must send the list of prequote strings */
+  /* We have sent the TYPE, now we must send the list of prequote strings */
   return ftp_state_quote(data, TRUE, FTP_RETR_PREQUOTE);
 }
 
 static CURLcode ftp_state_stor_prequote(struct Curl_easy *data)
 {
-  /* We've sent the TYPE, now we must send the list of prequote strings */
+  /* We have sent the TYPE, now we must send the list of prequote strings */
   return ftp_state_quote(data, TRUE, FTP_STOR_PREQUOTE);
 }
 
@@ -1608,7 +1607,7 @@ static CURLcode ftp_state_type(struct Curl_easy *data)
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
   /* If we have selected NOBODY and HEADER, it means that we only want file
-     information. Which in FTP can't be much more than the file size and
+     information. Which in FTP cannot be much more than the file size and
      date. */
   if(data->req.no_body && ftpc->file &&
      ftp_need_type(conn, data->state.prefer_ascii)) {
@@ -1668,13 +1667,13 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
 
   if((data->state.resume_from && !sizechecked) ||
      ((data->state.resume_from > 0) && sizechecked)) {
-    /* we're about to continue the uploading of a file */
+    /* we are about to continue the uploading of a file */
     /* 1. get already existing file's size. We use the SIZE command for this
        which may not exist in the server!  The SIZE command is not in
        RFC959. */
 
     /* 2. This used to set REST. But since we can do append, we
-       don't another ftp command. We just skip the source file
+       do not another ftp command. We just skip the source file
        offset and then we APPEND the rest on the file instead */
 
     /* 3. pass file-size number of bytes in the source file */
@@ -1707,7 +1706,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
         failf(data, "Could not seek stream");
         return CURLE_FTP_COULDNT_USE_REST;
       }
-      /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+      /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */
       do {
         char scratch[4*1024];
         size_t readthisamountnow =
@@ -1736,17 +1735,17 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
         infof(data, "File already completely uploaded");
 
         /* no data to transfer */
-        Curl_xfer_setup(data, -1, -1, FALSE, -1);
+        Curl_xfer_setup_nop(data);
 
-        /* Set ->transfer so that we won't get any error in
-         * ftp_done() because we didn't transfer anything! */
+        /* Set ->transfer so that we will not get any error in
+         * ftp_done() because we did not transfer anything! */
         ftp->transfer = PPTRANSFER_NONE;
 
         ftp_state(data, FTP_STOP);
         return CURLE_OK;
       }
     }
-    /* we've passed, proceed as normal */
+    /* we have passed, proceed as normal */
   } /* resume_from */
 
   result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
@@ -1835,16 +1834,16 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
         }
         else {
           if(data->set.ignorecl || data->state.prefer_ascii) {
-            /* 'ignorecl' is used to support download of growing files.  It
+            /* 'ignorecl' is used to support download of growing files. It
                prevents the state machine from requesting the file size from
-               the server.  With an unknown file size the download continues
+               the server. With an unknown file size the download continues
                until the server terminates it, otherwise the client stops if
-               the received byte count exceeds the reported file size.  Set
+               the received byte count exceeds the reported file size. Set
                option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
                behavior.
 
                In addition: asking for the size for 'TYPE A' transfers is not
-               constructive since servers don't report the converted size. So
+               constructive since servers do not report the converted size. So
                skip it.
             */
             result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
@@ -1882,7 +1881,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
      && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
 #endif
     ) {
-    /* We can't disable EPSV when doing IPv6, so this is instead a fail */
+    /* We cannot disable EPSV when doing IPv6, so this is instead a fail */
     failf(data, "Failed EPSV attempt, exiting");
     return CURLE_WEIRD_SERVER_REPLY;
   }
@@ -1907,7 +1906,7 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data,
 static char *control_address(struct connectdata *conn)
 {
   /* Returns the control connection IP address.
-     If a proxy tunnel is used, returns the original host name instead, because
+     If a proxy tunnel is used, returns the original hostname instead, because
      the effective control connection address is the proxy address,
      not the ftp host. */
 #ifndef CURL_DISABLE_PROXY
@@ -2046,7 +2045,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
   if(conn->bits.proxy) {
     /*
      * This connection uses a proxy and we need to connect to the proxy again
-     * here. We don't want to rely on a former host lookup that might've
+     * here. We do not want to rely on a former host lookup that might've
      * expired now, instead we remake the lookup here and now!
      */
     const char * const host_name = conn->bits.socksproxy ?
@@ -2061,7 +2060,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     connectport = (unsigned short)conn->primary.remote_port;
 
     if(!addr) {
-      failf(data, "Can't resolve proxy host %s:%hu", host_name, connectport);
+      failf(data, "cannot resolve proxy host %s:%hu", host_name, connectport);
       return CURLE_COULDNT_RESOLVE_PROXY;
     }
   }
@@ -2088,7 +2087,8 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     connectport = ftpc->newport; /* we connect to the remote port */
 
     if(!addr) {
-      failf(data, "Can't resolve new host %s:%hu", ftpc->newhost, connectport);
+      failf(data, "cannot resolve new host %s:%hu",
+            ftpc->newhost, connectport);
       return CURLE_FTP_CANT_GET_HOST;
     }
   }
@@ -2098,7 +2098,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
                            CURL_CF_SSL_ENABLE : CURL_CF_SSL_DISABLE);
 
   if(result) {
-    Curl_resolv_unlock(data, addr); /* we're done using this address */
+    Curl_resolv_unlock(data, addr); /* we are done using this address */
     if(ftpc->count1 == 0 && ftpcode == 229)
       return ftp_epsv_disable(data, conn);
 
@@ -2116,7 +2116,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     /* this just dumps information about this second connection */
     ftp_pasv_verbose(data, addr->addr, ftpc->newhost, connectport);
 
-  Curl_resolv_unlock(data, addr); /* we're done using this address */
+  Curl_resolv_unlock(data, addr); /* we are done using this address */
 
   Curl_safefree(conn->secondaryhostname);
   conn->secondary_port = ftpc->newport;
@@ -2204,7 +2204,7 @@ static CURLcode client_write_header(struct Curl_easy *data,
    * call to Curl_client_write() so it does the right thing.
    *
    * Notice that we cannot enable this flag for FTP in general,
-   * as an FTP transfer might involve a HTTP proxy connection and
+   * as an FTP transfer might involve an HTTP proxy connection and
    * headers from CONNECT should not automatically be part of the
    * output. */
   CURLcode result;
@@ -2371,17 +2371,17 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
     /* We always (attempt to) get the size of downloads, so it is done before
        this even when not doing resumes. */
     if(filesize == -1) {
-      infof(data, "ftp server doesn't support SIZE");
-      /* We couldn't get the size and therefore we can't know if there really
+      infof(data, "ftp server does not support SIZE");
+      /* We could not get the size and therefore we cannot know if there really
          is a part of the file left to get, although the server will just
-         close the connection when we start the connection so it won't cause
+         close the connection when we start the connection so it will not cause
          us any harm, just not make us exit as nicely. */
     }
     else {
       /* We got a file size report, so we check that there actually is a
          part of the file left to get, or else we go home.  */
       if(data->state.resume_from< 0) {
-        /* We're supposed to download the last abs(from) bytes */
+        /* We are supposed to download the last abs(from) bytes */
         if(filesize < -data->state.resume_from) {
           failf(data, "Offset (%" CURL_FORMAT_CURL_OFF_T
                 ") was beyond file size (%" CURL_FORMAT_CURL_OFF_T ")",
@@ -2407,11 +2407,11 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
 
     if(ftp->downloadsize == 0) {
       /* no data to transfer */
-      Curl_xfer_setup(data, -1, -1, FALSE, -1);
+      Curl_xfer_setup_nop(data);
       infof(data, "File already completely downloaded");
 
-      /* Set ->transfer so that we won't get any error in ftp_done()
-       * because we didn't transfer the any file */
+      /* Set ->transfer so that we will not get any error in ftp_done()
+       * because we did not transfer the any file */
       ftp->transfer = PPTRANSFER_NONE;
       ftp_state(data, FTP_STOP);
       return CURLE_OK;
@@ -2619,7 +2619,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
        !data->set.ignorecl &&
        (ftp->downloadsize < 1)) {
       /*
-       * It seems directory listings either don't show the size or very
+       * It seems directory listings either do not show the size or very
        * often uses size 0 anyway. ASCII transfers may very well turn out
        * that the transferred amount of data is not the same as this line
        * tells, why using this number in those cases only confuses us.
@@ -2690,7 +2690,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
   else {
     if((instate == FTP_LIST) && (ftpcode == 450)) {
       /* simply no matching files in the dir listing */
-      ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
+      ftp->transfer = PPTRANSFER_NONE; /* do not download anything */
       ftp_state(data, FTP_STOP); /* this phase is over */
     }
     else {
@@ -2777,7 +2777,7 @@ static CURLcode ftp_state_user_resp(struct Curl_easy *data,
 
     if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
        !ftpc->ftp_trying_alternative) {
-      /* Ok, USER failed.  Let's try the supplied command. */
+      /* Ok, USER failed. Let's try the supplied command. */
       result =
         Curl_pp_sendf(data, &ftpc->pp, "%s",
                       data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
@@ -2863,7 +2863,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
 #endif
 
       if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) {
-        /* We don't have a SSL/TLS control connection yet, but FTPS is
+        /* We do not have a SSL/TLS control connection yet, but FTPS is
            requested. Try a FTPS connection now */
 
         ftpc->count3 = 0;
@@ -2880,7 +2880,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
         default:
           failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
                 (int)data->set.ftpsslauth);
-          return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
+          return CURLE_UNKNOWN_OPTION; /* we do not know what to do */
         }
         result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s",
                                ftpauth[ftpc->count1]);
@@ -2980,7 +2980,13 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
     case FTP_CCC:
       if(ftpcode < 500) {
         /* First shut down the SSL layer (note: this call will block) */
-        result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET);
+        /* This has only been tested on the proftpd server, and the mod_tls
+         * code sends a close notify alert without waiting for a close notify
+         * alert in response. Thus we wait for a close notify alert from the
+         * server, but we do not send one. Let's hope other servers do
+         * the same... */
+        result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET,
+          (data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE));
 
         if(result)
           failf(data, "Failed to clear the command channel (CCC)");
@@ -3069,7 +3075,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
           data->state.most_recent_ftp_entrypath = ftpc->entrypath;
         }
         else {
-          /* couldn't get the path */
+          /* could not get the path */
           Curl_dyn_free(&out);
           infof(data, "Failed to figure out path");
         }
@@ -3168,7 +3174,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
         else {
           /* return failure */
           failf(data, "Server denied you to change to the given directory");
-          ftpc->cwdfail = TRUE; /* don't remember this path as we failed
+          ftpc->cwdfail = TRUE; /* do not remember this path as we failed
                                    to enter it */
           result = CURLE_REMOTE_ACCESS_DENIED;
         }
@@ -3373,7 +3379,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
   case CURLE_REMOTE_FILE_NOT_FOUND:
   case CURLE_WRITE_ERROR:
     /* the connection stays alive fine even though this happened */
-  case CURLE_OK: /* doesn't affect the control connection's status */
+  case CURLE_OK: /* does not affect the control connection's status */
     if(!premature)
       break;
 
@@ -3439,7 +3445,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
   /* free the dir tree and file parts */
   freedirs(ftpc);
 
-  /* shut down the socket to inform the server we're done */
+  /* shut down the socket to inform the server we are done */
 
 #ifdef _WIN32_WCE
   shutdown(conn->sock[SECONDARYSOCKET], 2);  /* SD_BOTH */
@@ -3457,7 +3463,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
       }
     }
 
-    close_secondarysocket(data, conn);
+    close_secondarysocket(data);
   }
 
   if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
@@ -3533,9 +3539,9 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
     if((-1 != data->req.size) &&
        (data->req.size != data->req.bytecount) &&
 #ifdef CURL_DO_LINEEND_CONV
-       /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
-        * we'll check to see if the discrepancy can be explained by the number
-        * of CRLFs we've changed to LFs.
+       /* Most FTP servers do not adjust their file SIZE response for CRLFs,
+        * so we will check to see if the discrepancy can be explained by the
+        * number of CRLFs we have changed to LFs.
         */
        ((data->req.size + data->state.crlf_conversions) !=
         data->req.bytecount) &&
@@ -3670,7 +3676,7 @@ static CURLcode ftp_nb_type(struct Curl_easy *data,
  * ftp_pasv_verbose()
  *
  * This function only outputs some informationals about this second connection
- * when we've issued a PASV command before and thus we have connected to a
+ * when we have issued a PASV command before and thus we have connected to a
  * possibly new IP address.
  *
  */
@@ -3711,7 +3717,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
    * complete */
   struct FTP *ftp = NULL;
 
-  /* if the second connection isn't done yet, wait for it to have
+  /* if the second connection is not done yet, wait for it to have
    * connected to the remote host. When using proxy tunneling, this
    * means the tunnel needs to have been establish. However, we
    * can not expect the remote host to talk to us in any way yet.
@@ -3739,20 +3745,20 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
 
     *completep = (int)complete;
 
-    /* if we got an error or if we don't wait for a data connection return
+    /* if we got an error or if we do not wait for a data connection return
        immediately */
     if(result || !ftpc->wait_data_conn)
       return result;
 
     /* if we reach the end of the FTP state machine here, *complete will be
        TRUE but so is ftpc->wait_data_conn, which says we need to wait for the
-       data connection and therefore we're not actually complete */
+       data connection and therefore we are not actually complete */
     *completep = 0;
   }
 
   if(ftp->transfer <= PPTRANSFER_INFO) {
-    /* a transfer is about to take place, or if not a file name was given
-       so we'll do a SIZE on it later and then we need the right TYPE first */
+    /* a transfer is about to take place, or if not a filename was given so we
+       will do a SIZE on it later and then we need the right TYPE first */
 
     if(ftpc->wait_data_conn) {
       bool serv_conned;
@@ -3791,7 +3797,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
       result = Curl_range(data);
 
       if(result == CURLE_OK && data->req.maxdownload >= 0) {
-        /* Don't check for successful transfer */
+        /* Do not check for successful transfer */
         ftpc->dont_check = TRUE;
       }
 
@@ -3824,7 +3830,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
   }
 
   /* no data to transfer */
-  Curl_xfer_setup(data, -1, -1, FALSE, -1);
+  Curl_xfer_setup_nop(data);
 
   if(!ftpc->wait_data_conn) {
     /* no waiting for the data connection so this is now complete */
@@ -3956,7 +3962,7 @@ static CURLcode init_wc_data(struct Curl_easy *data)
   if(data->set.ftp_filemethod == FTPFILE_NOCWD)
     data->set.ftp_filemethod = FTPFILE_MULTICWD;
 
-  /* try to parse ftp url */
+  /* try to parse ftp URL */
   result = ftp_parse_url_path(data);
   if(result) {
     goto fail;
@@ -4074,7 +4080,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
       if(result)
         return result;
 
-      /* we don't need the Curl_fileinfo of first file anymore */
+      /* we do not need the Curl_fileinfo of first file anymore */
       Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
 
       if(wildcard->filelist.size == 0) { /* remains only one file to down. */
@@ -4229,7 +4235,7 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
      bad in any way, sending quit and waiting around here will make the
      disconnect wait in vain and cause more problems than we need to.
 
-     ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
+     ftp_quit() will check the state of ftp->ctl_valid. If it is ok it
      will try to send the QUIT command, otherwise it will just return.
   */
   if(dead_connection)
@@ -4324,10 +4330,10 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
         }
 
         ftpc->dirdepth = 1; /* we consider it to be a single dir */
-        fileName = slashPos + 1; /* rest is file name */
+        fileName = slashPos + 1; /* rest is filename */
       }
       else
-        fileName = rawPath; /* file name only (or empty) */
+        fileName = rawPath; /* filename only (or empty) */
       break;
 
     default: /* allow pretty much anything */
@@ -4358,7 +4364,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
             ++compLen;
 
           /* we skip empty path components, like "x//y" since the FTP command
-             CWD requires a parameter and a non-existent parameter a) doesn't
+             CWD requires a parameter and a non-existent parameter a) does not
              work on many servers and b) has no effect on the others. */
           if(compLen > 0) {
             char *comp = Curl_memdup0(curPos, compLen);
@@ -4372,7 +4378,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
         }
       }
       DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc);
-      fileName = curPos; /* the rest is the file name (or empty) */
+      fileName = curPos; /* the rest is the filename (or empty) */
     }
     break;
   } /* switch */
@@ -4384,8 +4390,8 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
                             we make it a NULL pointer */
 
   if(data->state.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
-    /* We need a file name when uploading. Return error! */
-    failf(data, "Uploading to a URL without a file name");
+    /* We need a filename when uploading. Return error! */
+    failf(data, "Uploading to a URL without a filename");
     free(rawPath);
     return CURLE_URL_MALFORMAT;
   }
@@ -4426,16 +4432,16 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
     CURLcode result = ftp_do_more(data, &completed);
 
     if(result) {
-      close_secondarysocket(data, conn);
+      close_secondarysocket(data);
       return result;
     }
   }
 
   if(ftp->transfer != PPTRANSFER_BODY)
     /* no data to transfer */
-    Curl_xfer_setup(data, -1, -1, FALSE, -1);
+    Curl_xfer_setup_nop(data);
   else if(!connected)
-    /* since we didn't connect now, we want do_more to get called */
+    /* since we did not connect now, we want do_more to get called */
     conn->bits.do_more = TRUE;
 
   ftpc->ctl_valid = TRUE; /* seems good */
@@ -4540,10 +4546,10 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
   }
   data->req.p.ftp = ftp;
 
-  ftp->path = &data->state.up.path[1]; /* don't include the initial slash */
+  ftp->path = &data->state.up.path[1]; /* do not include the initial slash */
 
   /* FTP URLs support an extension like ";type=<typecode>" that
-   * we'll try to get now! */
+   * we will try to get now! */
   type = strstr(ftp->path, ";type=");
 
   if(!type)

+ 3 - 3
Utilities/cmcurl/lib/ftp.h

@@ -61,7 +61,7 @@ enum {
   FTP_STOR_PREQUOTE,
   FTP_POSTQUOTE,
   FTP_CWD,  /* change dir */
-  FTP_MKD,  /* if the dir didn't exist */
+  FTP_MKD,  /* if the dir did not exist */
   FTP_MDTM, /* to figure out the datestamp */
   FTP_TYPE, /* to set type when doing a head-like request */
   FTP_LIST_TYPE, /* set type when about to do a dir list */
@@ -123,7 +123,7 @@ struct ftp_conn {
   char *account;
   char *alternative_to_user;
   char *entrypath; /* the PWD reply when we logged on */
-  char *file;    /* url-decoded file name (or path) */
+  char *file;    /* url-decoded filename (or path) */
   char **dirs;   /* realloc()ed array for path components */
   char *newhost;
   char *prevpath;   /* url-decoded conn->path from the previous transfer */
@@ -139,7 +139,7 @@ struct ftp_conn {
   int count1; /* general purpose counter for the state machine */
   int count2; /* general purpose counter for the state machine */
   int count3; /* general purpose counter for the state machine */
-  /* newhost is the (allocated) IP addr or host name to connect the data
+  /* newhost is the (allocated) IP addr or hostname to connect the data
      connection to */
   unsigned short newport;
   ftpstate state; /* always use ftp.c:state() to change state! */

+ 3 - 3
Utilities/cmcurl/lib/getenv.c

@@ -37,7 +37,7 @@ static char *GetEnv(const char *variable)
   return NULL;
 #elif defined(_WIN32)
   /* This uses Windows API instead of C runtime getenv() to get the environment
-     variable since some changes aren't always visible to the latter. #4774 */
+     variable since some changes are not always visible to the latter. #4774 */
   char *buf = NULL;
   char *tmp;
   DWORD bufsize;
@@ -54,8 +54,8 @@ static char *GetEnv(const char *variable)
     buf = tmp;
     bufsize = rc;
 
-    /* It's possible for rc to be 0 if the variable was found but empty.
-       Since getenv doesn't make that distinction we ignore it as well. */
+    /* it is possible for rc to be 0 if the variable was found but empty.
+       Since getenv does not make that distinction we ignore it as well. */
     rc = GetEnvironmentVariableA(variable, buf, bufsize);
     if(!rc || rc == bufsize || rc > max) {
       free(buf);

+ 7 - 7
Utilities/cmcurl/lib/getinfo.c

@@ -204,7 +204,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
 #ifdef DEBUGBUILD
   char *timestr = getenv("CURL_TIME");
   if(timestr) {
-    unsigned long val = strtol(timestr, NULL, 10);
+    unsigned long val = strtoul(timestr, NULL, 10);
     switch(info) {
     case CURLINFO_LOCAL_PORT:
       *param_longp = (long)val;
@@ -216,7 +216,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
   /* use another variable for this to allow different values */
   timestr = getenv("CURL_DEBUG_SIZE");
   if(timestr) {
-    unsigned long val = strtol(timestr, NULL, 10);
+    unsigned long val = strtoul(timestr, NULL, 10);
     switch(info) {
     case CURLINFO_HEADER_SIZE:
     case CURLINFO_REQUEST_SIZE:
@@ -277,8 +277,8 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
   case CURLINFO_LASTSOCKET:
     sockfd = Curl_getconnectinfo(data, NULL);
 
-    /* note: this is not a good conversion for systems with 64 bit sockets and
-       32 bit longs */
+    /* note: this is not a good conversion for systems with 64-bit sockets and
+       32-bit longs */
     if(sockfd != CURL_SOCKET_BAD)
       *param_longp = (long)sockfd;
     else
@@ -335,7 +335,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
     }
     break;
   case CURLINFO_PROTOCOL:
-    *param_longp = data->info.conn_protocol;
+    *param_longp = (long)data->info.conn_protocol;
     break;
   case CURLINFO_USED_PROXY:
     *param_longp =
@@ -361,7 +361,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
 #ifdef DEBUGBUILD
   char *timestr = getenv("CURL_TIME");
   if(timestr) {
-    unsigned long val = strtol(timestr, NULL, 10);
+    unsigned long val = strtoul(timestr, NULL, 10);
     switch(info) {
     case CURLINFO_TOTAL_TIME_T:
     case CURLINFO_NAMELOOKUP_TIME_T:
@@ -450,7 +450,7 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
 #ifdef DEBUGBUILD
   char *timestr = getenv("CURL_TIME");
   if(timestr) {
-    unsigned long val = strtol(timestr, NULL, 10);
+    unsigned long val = strtoul(timestr, NULL, 10);
     switch(info) {
     case CURLINFO_TOTAL_TIME:
     case CURLINFO_NAMELOOKUP_TIME:

+ 3 - 3
Utilities/cmcurl/lib/gopher.c

@@ -209,9 +209,9 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
     if(!timeout_ms)
       timeout_ms = TIMEDIFF_T_MAX;
 
-    /* Don't busyloop. The entire loop thing is a work-around as it causes a
+    /* Do not busyloop. The entire loop thing is a work-around as it causes a
        BLOCKING behavior which is a NO-NO. This function should rather be
-       split up in a do and a doing piece where the pieces that aren't
+       split up in a do and a doing piece where the pieces that are not
        possible to send now will be sent in the doing function repeatedly
        until the entire request is sent.
     */
@@ -238,7 +238,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
   if(result)
     return result;
 
-  Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
+  Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE);
   return CURLE_OK;
 }
 #endif /* CURL_DISABLE_GOPHER */

+ 26 - 14
Utilities/cmcurl/lib/hash.c

@@ -40,7 +40,10 @@ hash_element_dtor(void *user, void *element)
   struct Curl_hash_element *e = (struct Curl_hash_element *) element;
 
   if(e->ptr) {
-    h->dtor(e->ptr);
+    if(e->dtor)
+      e->dtor(e->key, e->key_len, e->ptr);
+    else
+      h->dtor(e->ptr);
     e->ptr = NULL;
   }
 
@@ -77,7 +80,8 @@ Curl_hash_init(struct Curl_hash *h,
 }
 
 static struct Curl_hash_element *
-mk_hash_element(const void *key, size_t key_len, const void *p)
+mk_hash_element(const void *key, size_t key_len, const void *p,
+                Curl_hash_elem_dtor dtor)
 {
   /* allocate the struct plus memory after it to store the key */
   struct Curl_hash_element *he = malloc(sizeof(struct Curl_hash_element) +
@@ -87,22 +91,15 @@ mk_hash_element(const void *key, size_t key_len, const void *p)
     memcpy(he->key, key, key_len);
     he->key_len = key_len;
     he->ptr = (void *) p;
+    he->dtor = dtor;
   }
   return he;
 }
 
 #define FETCH_LIST(x,y,z) &x->table[x->hash_func(y, z, x->slots)]
 
-/* Insert the data in the hash. If there already was a match in the hash, that
- * data is replaced. This function also "lazily" allocates the table if
- * needed, as it isn't done in the _init function (anymore).
- *
- * @unittest: 1305
- * @unittest: 1602
- * @unittest: 1603
- */
-void *
-Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
+void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
+                     Curl_hash_elem_dtor dtor)
 {
   struct Curl_hash_element  *he;
   struct Curl_llist_element *le;
@@ -130,7 +127,7 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
     }
   }
 
-  he = mk_hash_element(key, key_len, p);
+  he = mk_hash_element(key, key_len, p, dtor);
   if(he) {
     Curl_llist_append(l, he, &he->list);
     ++h->size;
@@ -140,6 +137,20 @@ Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
   return NULL; /* failure */
 }
 
+/* Insert the data in the hash. If there already was a match in the hash, that
+ * data is replaced. This function also "lazily" allocates the table if
+ * needed, as it is not done in the _init function (anymore).
+ *
+ * @unittest: 1305
+ * @unittest: 1602
+ * @unittest: 1603
+ */
+void *
+Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p)
+{
+  return Curl_hash_add2(h, key, key_len, p, NULL);
+}
+
 /* Remove the identified hash entry.
  * Returns non-zero on failure.
  *
@@ -259,8 +270,9 @@ size_t Curl_hash_str(void *key, size_t key_length, size_t slots_num)
   size_t h = 5381;
 
   while(key_str < end) {
+    size_t j = (size_t)*key_str++;
     h += h << 5;
-    h ^= *key_str++;
+    h ^= j;
   }
 
   return (h % slots_num);

+ 5 - 0
Utilities/cmcurl/lib/hash.h

@@ -58,9 +58,12 @@ struct Curl_hash {
   size_t size;
 };
 
+typedef void (*Curl_hash_elem_dtor)(void *key, size_t key_len, void *p);
+
 struct Curl_hash_element {
   struct Curl_llist_element list;
   void   *ptr;
+  Curl_hash_elem_dtor dtor;
   size_t key_len;
   char   key[1]; /* allocated memory following the struct */
 };
@@ -78,6 +81,8 @@ void Curl_hash_init(struct Curl_hash *h,
                     Curl_hash_dtor dtor);
 
 void *Curl_hash_add(struct Curl_hash *h, void *key, size_t key_len, void *p);
+void *Curl_hash_add2(struct Curl_hash *h, void *key, size_t key_len, void *p,
+                     Curl_hash_elem_dtor dtor);
 int Curl_hash_delete(struct Curl_hash *h, void *key, size_t key_len);
 void *Curl_hash_pick(struct Curl_hash *, void *key, size_t key_len);
 #define Curl_hash_count(h) ((h)->size)

+ 3 - 3
Utilities/cmcurl/lib/headers.c

@@ -54,7 +54,7 @@ static void copy_header_external(struct Curl_header_store *hs,
      impossible for applications to do == comparisons, as that would otherwise
      be very tempting and then lead to the reserved bits not being reserved
      anymore. */
-  h->origin = hs->type | (1<<27);
+  h->origin = (unsigned int)(hs->type | (1<<27));
   h->anchor = e;
 }
 
@@ -114,7 +114,7 @@ CURLHcode curl_easy_header(CURL *easy,
         break;
       }
     }
-    if(!e) /* this shouldn't happen */
+    if(!e) /* this should not happen */
       return CURLHE_MISSING;
   }
   /* this is the name we want */
@@ -302,7 +302,7 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
       /* line folding, append value to the previous header's value */
       return unfold_value(data, header, hlen);
     else {
-      /* Can't unfold without a previous header. Instead of erroring, just
+      /* cannot unfold without a previous header. Instead of erroring, just
          pass the leading blanks. */
       while(hlen && ISBLANK(*header)) {
         header++;

+ 1 - 1
Utilities/cmcurl/lib/hmac.c

@@ -42,7 +42,7 @@
  * Generic HMAC algorithm.
  *
  *   This module computes HMAC digests based on any hash function. Parameters
- * and computing procedures are set-up dynamically at HMAC computation context
+ * and computing procedures are setup dynamically at HMAC computation context
  * initialization.
  */
 

+ 25 - 25
Utilities/cmcurl/lib/hostip.c

@@ -84,8 +84,8 @@
  * source file are these:
  *
  * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
- * that. The host may not be able to resolve IPv6, but we don't really have to
- * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
+ * that. The host may not be able to resolve IPv6, but we do not really have to
+ * take that into account. Hosts that are not IPv6-enabled have CURLRES_IPV4
  * defined.
  *
  * CURLRES_ARES - is defined if libcurl is built to use c-ares for
@@ -238,7 +238,7 @@ void Curl_hostcache_prune(struct Curl_easy *data)
   int timeout = data->set.dns_cache_timeout;
 
   if(!data->dns.hostcache)
-    /* NULL hostcache means we can't do it */
+    /* NULL hostcache means we cannot do it */
     return;
 
   if(data->share)
@@ -283,14 +283,14 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
   size_t entry_len = create_hostcache_id(hostname, 0, port,
                                          entry_id, sizeof(entry_id));
 
-  /* See if it's already in our dns cache */
+  /* See if it is already in our dns cache */
   dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
   /* No entry found in cache, check if we might have a wildcard entry */
   if(!dns && data->state.wildcard_resolve) {
     entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id));
 
-    /* See if it's already in our dns cache */
+    /* See if it is already in our dns cache */
     dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
   }
 
@@ -329,7 +329,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
     }
 
     if(!found) {
-      infof(data, "Hostname in DNS cache doesn't have needed family, zapped");
+      infof(data, "Hostname in DNS cache does not have needed family, zapped");
       dns = NULL; /* the memory deallocation is being handled by the hash */
       Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
     }
@@ -349,7 +349,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
  * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
  *
  * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
- * use, or we'll leak memory!
+ * use, or we will leak memory!
  */
 struct Curl_dns_entry *
 Curl_fetch_addr(struct Curl_easy *data,
@@ -428,8 +428,8 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
         if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) {
           struct Curl_addrinfo *swap_tmp;
           for(i = num_addrs - 1; i > 0; i--) {
-            swap_tmp = nodes[rnd[i] % (i + 1)];
-            nodes[rnd[i] % (i + 1)] = nodes[i];
+            swap_tmp = nodes[rnd[i] % (unsigned int)(i + 1)];
+            nodes[rnd[i] % (unsigned int)(i + 1)] = nodes[i];
             nodes[i] = swap_tmp;
           }
 
@@ -536,8 +536,8 @@ static struct Curl_addrinfo *get_localhost6(int port, const char *name)
   sa6.sin6_port = htons(port16);
   sa6.sin6_flowinfo = 0;
   sa6.sin6_scope_id = 0;
-  if(Curl_inet_pton(AF_INET6, "::1", ipv6) < 1)
-    return NULL;
+
+  (void)Curl_inet_pton(AF_INET6, "::1", ipv6);
   memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
 
   ca->ai_flags     = 0;
@@ -602,7 +602,7 @@ static struct Curl_addrinfo *get_localhost(int port, const char *name)
 bool Curl_ipv6works(struct Curl_easy *data)
 {
   if(data) {
-    /* the nature of most system is that IPv6 status doesn't come and go
+    /* the nature of most system is that IPv6 status does not come and go
        during a program's lifetime so we only probe the first time and then we
        have the info kept for fast reuse */
     DEBUGASSERT(data);
@@ -618,7 +618,7 @@ bool Curl_ipv6works(struct Curl_easy *data)
     /* probe to see if we have a working IPv6 stack */
     curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
     if(s == CURL_SOCKET_BAD)
-      /* an IPv6 address was requested but we can't get/use one */
+      /* an IPv6 address was requested but we cannot get/use one */
       ipv6_works = 0;
     else {
       ipv6_works = 1;
@@ -662,11 +662,11 @@ static bool tailmatch(const char *full, const char *part)
 /*
  * Curl_resolv() is the main name resolve function within libcurl. It resolves
  * a name and returns a pointer to the entry in the 'entry' argument (if one
- * is provided). This function might return immediately if we're using asynch
+ * is provided). This function might return immediately if we are using asynch
  * resolves. See the return codes.
  *
  * The cache entry we return will get its 'inuse' counter increased when this
- * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * function is used. You MUST call Curl_resolv_unlock() later (when you are
  * done using this struct) to decrease the counter again.
  *
  * Return codes:
@@ -813,7 +813,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
       if(respwait) {
         /* the response to our resolve call will come asynchronously at
            a later time, good or bad */
-        /* First, check that we haven't received the info by now */
+        /* First, check that we have not received the info by now */
         result = Curl_resolv_check(data, &dns);
         if(result) /* error detected */
           return CURLRESOLV_ERROR;
@@ -851,7 +851,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
 #ifdef USE_ALARM_TIMEOUT
 /*
  * This signal handler jumps back into the main libcurl code and continues
- * execution.  This effectively causes the remainder of the application to run
+ * execution. This effectively causes the remainder of the application to run
  * within a signal handler which is nonportable and could lead to problems.
  */
 CURL_NORETURN static
@@ -864,11 +864,11 @@ void alarmfunc(int sig)
 
 /*
  * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
- * timeout.  This function might return immediately if we're using asynch
+ * timeout. This function might return immediately if we are using asynch
  * resolves. See the return codes.
  *
  * The cache entry we return will get its 'inuse' counter increased when this
- * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * function is used. You MUST call Curl_resolv_unlock() later (when you are
  * done using this struct) to decrease the counter again.
  *
  * If built with a synchronous resolver and use of signals is not
@@ -934,7 +934,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
      will generate a signal and we will siglongjmp() from that here.
      This technique has problems (see alarmfunc).
      This should be the last thing we do before calling Curl_resolv(),
-     as otherwise we'd have to worry about variables that get modified
+     as otherwise we would have to worry about variables that get modified
      before we invoke Curl_resolv() (and thus use "volatile"). */
   curl_simple_lock_lock(&curl_jmpenv_lock);
 
@@ -955,7 +955,7 @@ enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
     keep_copysig = TRUE; /* yes, we have a copy */
     sigact.sa_handler = alarmfunc;
 #ifdef SA_RESTART
-    /* HPUX doesn't have SA_RESTART but defaults to that behavior! */
+    /* HPUX does not have SA_RESTART but defaults to that behavior! */
     sigact.sa_flags &= ~SA_RESTART;
 #endif
     /* now set the new struct */
@@ -1022,7 +1022,7 @@ clean_up:
        ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
       /* if the alarm time-left reached zero or turned "negative" (counted
          with unsigned values), we should fire off a SIGALRM here, but we
-         won't, and zero would be to switch it off so we never set it to
+         will not, and zero would be to switch it off so we never set it to
          less than 1! */
       alarm(1);
       rc = CURLRESOLV_TIMEDOUT;
@@ -1150,7 +1150,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-      /* delete entry, ignore if it didn't exist */
+      /* delete entry, ignore if it did not exist */
       Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
 
       if(data->share)
@@ -1264,7 +1264,7 @@ err:
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-      /* See if it's already in our dns cache */
+      /* See if it is already in our dns cache */
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
       if(dns) {
@@ -1362,7 +1362,7 @@ static void show_resolve_info(struct Curl_easy *data,
       if(!result)
         result = Curl_dyn_add(d, buf);
       if(result) {
-        infof(data, "too many IP, can't show");
+        infof(data, "too many IP, cannot show");
         goto fail;
       }
     }

+ 4 - 4
Utilities/cmcurl/lib/hostip.h

@@ -80,7 +80,7 @@ struct Curl_https_rrinfo {
   char *alpns; /* keytag = 1 */
   bool no_def_alpn; /* keytag = 2 */
   /*
-   * we don't support ports (keytag = 3) as we don't support
+   * we do not support ports (keytag = 3) as we do not support
    * port-switching yet
    */
   unsigned char *ipv4hints; /* keytag = 4 */
@@ -97,7 +97,7 @@ struct Curl_dns_entry {
 #ifdef USE_HTTPSRR
   struct Curl_https_rrinfo *hinfo;
 #endif
-  /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
+  /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (does not time out) */
   time_t timestamp;
   /* use-counter, use Curl_resolv_unlock to release reference */
   long inuse;
@@ -114,7 +114,7 @@ bool Curl_host_is_ipnum(const char *hostname);
  * and port.
  *
  * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
- * use, or we'll leak memory!
+ * use, or we will leak memory!
  */
 /* return codes */
 enum resolve_t {
@@ -200,7 +200,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ip,
  * Returns the Curl_dns_entry entry pointer or NULL if not in the cache.
  *
  * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
- * use, or we'll leak memory!
+ * use, or we will leak memory!
  */
 struct Curl_dns_entry *
 Curl_fetch_addr(struct Curl_easy *data,

+ 11 - 11
Utilities/cmcurl/lib/hostip4.c

@@ -62,7 +62,7 @@ bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
 {
   (void)data;
   if(conn->ip_version == CURL_IPRESOLVE_V6)
-    /* An IPv6 address was requested and we can't get/use one */
+    /* An IPv6 address was requested and we cannot get/use one */
     return FALSE;
 
   return TRUE; /* OK, proceed */
@@ -193,8 +193,8 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
    * small. Previous versions are known to return ERANGE for the same
    * problem.
    *
-   * This wouldn't be such a big problem if older versions wouldn't
-   * sometimes return EAGAIN on a common failure case. Alas, we can't
+   * This would not be such a big problem if older versions would not
+   * sometimes return EAGAIN on a common failure case. Alas, we cannot
    * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
    * glibc.
    *
@@ -210,9 +210,9 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
    * gethostbyname_r() in glibc:
    *
    * In glibc 2.2.5 the interface is different (this has also been
-   * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
+   * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I cannot
    * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
-   * (shipped/upgraded by Redhat 7.2) don't show this behavior!
+   * (shipped/upgraded by Redhat 7.2) do not show this behavior!
    *
    * In this "buggy" version, the return code is -1 on error and 'errno'
    * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
@@ -223,7 +223,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
 #elif defined(HAVE_GETHOSTBYNAME_R_3)
   /* AIX, Digital Unix/Tru64, HPUX 10, more? */
 
-  /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
+  /* For AIX 4.3 or later, we do not use gethostbyname_r() at all, because of
    * the plain fact that it does not return unique full buffers on each
    * call, but instead several of the pointers in the hostent structs will
    * point to the same actual data! This have the unfortunate down-side that
@@ -237,7 +237,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
    *
    * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
    *
-   * [*] = much later we've found out that it isn't at all "completely
+   * [*] = much later we have found out that it is not at all "completely
    * thread-safe", but at least the gethostbyname() function is.
    */
 
@@ -253,7 +253,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
                           (struct hostent *)buf,
                           (struct hostent_data *)((char *)buf +
                                                   sizeof(struct hostent)));
-    h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
+    h_errnop = SOCKERRNO; /* we do not deal with this, but set it anyway */
   }
   else
     res = -1; /* failure, too smallish buffer size */
@@ -263,8 +263,8 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
     h = buf; /* result expected in h */
 
     /* This is the worst kind of the different gethostbyname_r() interfaces.
-     * Since we don't know how big buffer this particular lookup required,
-     * we can't realloc down the huge alloc without doing closer analysis of
+     * Since we do not know how big buffer this particular lookup required,
+     * we cannot realloc down the huge alloc without doing closer analysis of
      * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
      * name lookup. Fixing this would require an extra malloc() and then
      * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
@@ -280,7 +280,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
 #else /* (HAVE_GETADDRINFO && HAVE_GETADDRINFO_THREADSAFE) ||
           HAVE_GETHOSTBYNAME_R */
   /*
-   * Here is code for platforms that don't have a thread safe
+   * Here is code for platforms that do not have a thread safe
    * getaddrinfo() nor gethostbyname_r() function or for which
    * gethostbyname() is the preferred one.
    */

+ 6 - 6
Utilities/cmcurl/lib/hsts.c

@@ -54,7 +54,7 @@
 #define MAX_HSTS_DATELENSTR "64"
 #define UNLIMITED "unlimited"
 
-#ifdef DEBUGBUILD
+#if defined(DEBUGBUILD) || defined(UNITTESTS)
 /* to play well with debug builds, we can *set* a fixed time this will
    return */
 time_t deltatime; /* allow for "adjustments" for unit test purposes */
@@ -241,7 +241,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
 }
 
 /*
- * Return TRUE if the given host name is currently an HSTS one.
+ * Return TRUE if the given hostname is currently an HSTS one.
  *
  * The 'subdomain' argument tells the function if subdomain matching should be
  * attempted.
@@ -368,7 +368,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
     file = h->filename;
 
   if((h->flags & CURLHSTS_READONLYFILE) || !file || !file[0])
-    /* marked as read-only, no file or zero length file name */
+    /* marked as read-only, no file or zero length filename */
     goto skipsave;
 
   result = Curl_fopen(data, file, &out, &tempstore);
@@ -393,7 +393,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
   free(tempstore);
 skipsave:
   if(data->set.hsts_write) {
-    /* if there's a write callback */
+    /* if there is a write callback */
     struct curl_index i; /* count */
     i.total = h->list.size;
     i.index = 0;
@@ -440,7 +440,7 @@ static CURLcode hsts_add(struct hsts *h, char *line)
     if(!e)
       result = hsts_create(h, p, subdomain, expires);
     else {
-      /* the same host name, use the largest expire time */
+      /* the same hostname, use the largest expire time */
       if(expires > e->expires)
         e->expires = expires;
     }
@@ -508,7 +508,7 @@ static CURLcode hsts_load(struct hsts *h, const char *file)
   CURLcode result = CURLE_OK;
   FILE *fp;
 
-  /* we need a private copy of the file name so that the hsts cache file
+  /* we need a private copy of the filename so that the hsts cache file
      name survives an easy handle reset */
   free(h->filename);
   h->filename = strdup(file);

+ 2 - 2
Utilities/cmcurl/lib/hsts.h

@@ -29,7 +29,7 @@
 #include <curl/curl.h>
 #include "llist.h"
 
-#ifdef DEBUGBUILD
+#if defined(DEBUGBUILD) || defined(UNITTESTS)
 extern time_t deltatime;
 #endif
 
@@ -40,7 +40,7 @@ struct stsentry {
   curl_off_t expires; /* the timestamp of this entry's expiry */
 };
 
-/* The HSTS cache. Needs to be able to tailmatch host names. */
+/* The HSTS cache. Needs to be able to tailmatch hostnames. */
 struct hsts {
   struct Curl_llist list;
   char *filename;

+ 158 - 131
Utilities/cmcurl/lib/http.c

@@ -169,14 +169,6 @@ CURLcode Curl_http_setup_conn(struct Curl_easy *data,
 {
   /* allocate the HTTP-specific struct for the Curl_easy, only to survive
      during this request */
-  struct HTTP *http;
-  DEBUGASSERT(data->req.p.http == NULL);
-
-  http = calloc(1, sizeof(struct HTTP));
-  if(!http)
-    return CURLE_OUT_OF_MEMORY;
-
-  data->req.p.http = http;
   connkeep(conn, "HTTP default");
 
   if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
@@ -418,9 +410,9 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
   curl_off_t upload_remain = (expectsend >= 0)? (expectsend - bytessent) : -1;
   bool little_upload_remains = (upload_remain >= 0 && upload_remain < 2000);
   bool needs_rewind = Curl_creader_needs_rewind(data);
-  /* By default, we'd like to abort the transfer when little or
-   * unknown amount remains. But this may be overridden by authentications
-   * further below! */
+  /* By default, we would like to abort the transfer when little or unknown
+   * amount remains. This may be overridden by authentications further
+   * below! */
   bool abort_upload = (!data->req.upload_done && !little_upload_remains);
   const char *ongoing_auth = NULL;
 
@@ -483,7 +475,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data,
     /* We decided to abort the ongoing transfer */
     streamclose(conn, "Mid-auth HTTP and much data left to send");
     /* FIXME: questionable manipulation here, can we do this differently? */
-    data->req.size = 0; /* don't download any more than 0 bytes */
+    data->req.size = 0; /* do not download any more than 0 bytes */
   }
   return CURLE_OK;
 }
@@ -556,7 +548,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
     /* no (known) authentication available,
        authentication is not "done" yet and
        no authentication seems to be required and
-       we didn't try HEAD or GET */
+       we did not try HEAD or GET */
     if((data->state.httpreq != HTTPREQ_GET) &&
        (data->state.httpreq != HTTPREQ_HEAD)) {
       data->req.newurl = strdup(data->state.url); /* clone URL */
@@ -746,13 +738,13 @@ Curl_http_output_auth(struct Curl_easy *data,
   if(authhost->want && !authhost->picked)
     /* The app has selected one or more methods, but none has been picked
        so far by a server round-trip. Then we set the picked one to the
-       want one, and if this is one single bit it'll be used instantly. */
+       want one, and if this is one single bit it will be used instantly. */
     authhost->picked = authhost->want;
 
   if(authproxy->want && !authproxy->picked)
     /* The app has selected one or more methods, but none has been picked so
        far by a proxy round-trip. Then we set the picked one to the want one,
-       and if this is one single bit it'll be used instantly. */
+       and if this is one single bit it will be used instantly. */
     authproxy->picked = authproxy->want;
 
 #ifndef CURL_DISABLE_PROXY
@@ -767,7 +759,7 @@ Curl_http_output_auth(struct Curl_easy *data,
 #else
   (void)proxytunnel;
 #endif /* CURL_DISABLE_PROXY */
-    /* we have no proxy so let's pretend we're done authenticating
+    /* we have no proxy so let's pretend we are done authenticating
        with it */
     authproxy->done = TRUE;
 
@@ -941,7 +933,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
             authp->avail |= CURLAUTH_DIGEST;
 
             /* We call this function on input Digest headers even if Digest
-             * authentication isn't activated yet, as we need to store the
+             * authentication is not activated yet, as we need to store the
              * incoming data from this header in case we are going to use
              * Digest */
             result = Curl_input_digest(data, proxy, auth);
@@ -960,7 +952,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
             authp->avail |= CURLAUTH_BASIC;
             if(authp->picked == CURLAUTH_BASIC) {
               /* We asked for Basic authentication but got a 40X back
-                 anyway, which basically means our name+password isn't
+                 anyway, which basically means our name+password is not
                  valid. */
               authp->avail = CURLAUTH_NONE;
               infof(data, "Authentication problem. Ignoring this.");
@@ -976,7 +968,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
               authp->avail |= CURLAUTH_BEARER;
               if(authp->picked == CURLAUTH_BEARER) {
                 /* We asked for Bearer authentication but got a 40X back
-                  anyway, which basically means our token isn't valid. */
+                  anyway, which basically means our token is not valid. */
                 authp->avail = CURLAUTH_NONE;
                 infof(data, "Authentication problem. Ignoring this.");
                 data->state.authproblem = TRUE;
@@ -996,7 +988,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
     /* there may be multiple methods on one line, so keep reading */
     while(*auth && *auth != ',') /* read up to the next comma */
       auth++;
-    if(*auth == ',') /* if we're on a comma, skip it */
+    if(*auth == ',') /* if we are on a comma, skip it */
       auth++;
     while(*auth && ISSPACE(*auth))
       auth++;
@@ -1019,8 +1011,8 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
   DEBUGASSERT(data->conn);
 
   /*
-  ** If we haven't been asked to fail on error,
-  ** don't fail.
+  ** If we have not been asked to fail on error,
+  ** do not fail.
   */
   if(!data->set.http_fail_on_error)
     return FALSE;
@@ -1040,7 +1032,7 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
     return FALSE;
 
   /*
-  ** Any code >= 400 that's not 401 or 407 is always
+  ** Any code >= 400 that is not 401 or 407 is always
   ** a terminal error
   */
   if((httpcode != 401) && (httpcode != 407))
@@ -1052,22 +1044,19 @@ static bool http_should_fail(struct Curl_easy *data, int httpcode)
   DEBUGASSERT((httpcode == 401) || (httpcode == 407));
 
   /*
-  ** Examine the current authentication state to see if this
-  ** is an error.  The idea is for this function to get
-  ** called after processing all the headers in a response
-  ** message.  So, if we've been to asked to authenticate a
-  ** particular stage, and we've done it, we're OK.  But, if
-  ** we're already completely authenticated, it's not OK to
-  ** get another 401 or 407.
+  ** Examine the current authentication state to see if this is an error. The
+  ** idea is for this function to get called after processing all the headers
+  ** in a response message. So, if we have been to asked to authenticate a
+  ** particular stage, and we have done it, we are OK. If we are already
+  ** completely authenticated, it is not OK to get another 401 or 407.
   **
-  ** It is possible for authentication to go stale such that
-  ** the client needs to reauthenticate.  Once that info is
-  ** available, use it here.
+  ** It is possible for authentication to go stale such that the client needs
+  ** to reauthenticate. Once that info is available, use it here.
   */
 
   /*
-  ** Either we're not authenticating, or we're supposed to
-  ** be authenticating something else.  This is an error.
+  ** Either we are not authenticating, or we are supposed to be authenticating
+  ** something else. This is an error.
   */
   if((httpcode == 401) && !data->state.aptr.user)
     return TRUE;
@@ -1106,7 +1095,7 @@ Curl_compareheader(const char *headerline, /* line to check */
   DEBUGASSERT(content);
 
   if(!strncasecompare(headerline, header, hlen))
-    return FALSE; /* doesn't start with header */
+    return FALSE; /* does not start with header */
 
   /* pass the header */
   start = &headerline[hlen];
@@ -1118,11 +1107,11 @@ Curl_compareheader(const char *headerline, /* line to check */
   /* find the end of the header line */
   end = strchr(start, '\r'); /* lines end with CRLF */
   if(!end) {
-    /* in case there's a non-standard compliant line here */
+    /* in case there is a non-standard compliant line here */
     end = strchr(start, '\n');
 
     if(!end)
-      /* hm, there's no line ending here, use the zero byte! */
+      /* hm, there is no line ending here, use the zero byte! */
       end = strchr(start, '\0');
   }
 
@@ -1153,7 +1142,7 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
 }
 
 /* this returns the socket to wait for in the DO and DOING state for the multi
-   interface and then we're always _sending_ a request and thus we wait for
+   interface and then we are always _sending_ a request and thus we wait for
    the single socket to become writable only */
 int Curl_http_getsock_do(struct Curl_easy *data,
                          struct connectdata *conn,
@@ -1174,16 +1163,12 @@ CURLcode Curl_http_done(struct Curl_easy *data,
                         CURLcode status, bool premature)
 {
   struct connectdata *conn = data->conn;
-  struct HTTP *http = data->req.p.http;
 
-  /* Clear multipass flag. If authentication isn't done yet, then it will get
+  /* Clear multipass flag. If authentication is not done yet, then it will get
    * a chance to be set back to true when we output the next auth header */
   data->state.authhost.multipass = FALSE;
   data->state.authproxy.multipass = FALSE;
 
-  if(!http)
-    return CURLE_OK;
-
   Curl_dyn_reset(&data->state.headerb);
   Curl_hyper_done(data);
 
@@ -1197,8 +1182,8 @@ CURLcode Curl_http_done(struct Curl_easy *data,
      (data->req.bytecount +
       data->req.headerbytecount -
       data->req.deductheadercount) <= 0) {
-    /* If this connection isn't simply closed to be retried, AND nothing was
-       read from the HTTP server (that counts), this can't be right so we
+    /* If this connection is not simply closed to be retried, AND nothing was
+       read from the HTTP server (that counts), this cannot be right so we
        return an error here */
     failf(data, "Empty reply from server");
     /* Mark it as closed to avoid the "left intact" message */
@@ -1357,7 +1342,7 @@ CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
 
       DEBUGASSERT(name && value);
       if(data->state.aptr.host &&
-         /* a Host: header was sent already, don't pass on any custom Host:
+         /* a Host: header was sent already, do not pass on any custom Host:
             header as that will produce *two* in the same request! */
          hd_name_eq(name, namelen, STRCONST("Host:")))
         ;
@@ -1370,18 +1355,18 @@ CURLcode Curl_dynhds_add_custom(struct Curl_easy *data,
               hd_name_eq(name, namelen, STRCONST("Content-Type:")))
         ;
       else if(data->req.authneg &&
-              /* while doing auth neg, don't allow the custom length since
+              /* while doing auth neg, do not allow the custom length since
                  we will force length zero then */
               hd_name_eq(name, namelen, STRCONST("Content-Length:")))
         ;
       else if(data->state.aptr.te &&
-              /* when asking for Transfer-Encoding, don't pass on a custom
+              /* when asking for Transfer-Encoding, do not pass on a custom
                  Connection: */
               hd_name_eq(name, namelen, STRCONST("Connection:")))
         ;
       else if((conn->httpversion >= 20) &&
               hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:")))
-        /* HTTP/2 doesn't support chunked requests */
+        /* HTTP/2 does not support chunked requests */
         ;
       else if((hd_name_eq(name, namelen, STRCONST("Authorization:")) ||
                hd_name_eq(name, namelen, STRCONST("Cookie:"))) &&
@@ -1503,8 +1488,9 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
           char *compare = semicolonp ? semicolonp : headers->data;
 
           if(data->state.aptr.host &&
-             /* a Host: header was sent already, don't pass on any custom Host:
-                header as that will produce *two* in the same request! */
+             /* a Host: header was sent already, do not pass on any custom
+                Host: header as that will produce *two* in the same
+                request! */
              checkprefix("Host:", compare))
             ;
           else if(data->state.httpreq == HTTPREQ_POST_FORM &&
@@ -1516,18 +1502,18 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
                   checkprefix("Content-Type:", compare))
             ;
           else if(data->req.authneg &&
-                  /* while doing auth neg, don't allow the custom length since
+                  /* while doing auth neg, do not allow the custom length since
                      we will force length zero then */
                   checkprefix("Content-Length:", compare))
             ;
           else if(data->state.aptr.te &&
-                  /* when asking for Transfer-Encoding, don't pass on a custom
+                  /* when asking for Transfer-Encoding, do not pass on a custom
                      Connection: */
                   checkprefix("Connection:", compare))
             ;
           else if((conn->httpversion >= 20) &&
                   checkprefix("Transfer-Encoding:", compare))
-            /* HTTP/2 doesn't support chunked requests */
+            /* HTTP/2 does not support chunked requests */
             ;
           else if((checkprefix("Authorization:", compare) ||
                    checkprefix("Cookie:", compare)) &&
@@ -1719,10 +1705,10 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
   if(ptr && (!data->state.this_is_a_follow ||
              strcasecompare(data->state.first_host, conn->host.name))) {
 #if !defined(CURL_DISABLE_COOKIES)
-    /* If we have a given custom Host: header, we extract the host name in
+    /* If we have a given custom Host: header, we extract the hostname in
        order to possibly use it for cookie reasons later on. We only allow the
        custom Host: header if this is NOT a redirect, as setting Host: in the
-       redirected request is being out on thin ice. Except if the host name
+       redirected request is being out on thin ice. Except if the hostname
        is the same as the first one! */
     char *cookiehost = Curl_copy_header_value(ptr);
     if(!cookiehost)
@@ -1760,15 +1746,15 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
     }
   }
   else {
-    /* When building Host: headers, we must put the host name within
-       [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
+    /* When building Host: headers, we must put the hostname within
+       [brackets] if the hostname is a plain IPv6-address. RFC2732-style. */
     const char *host = conn->host.name;
 
     if(((conn->given->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS)) &&
         (conn->remote_port == PORT_HTTPS)) ||
        ((conn->given->protocol&(CURLPROTO_HTTP|CURLPROTO_WS)) &&
         (conn->remote_port == PORT_HTTP)) )
-      /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
+      /* if(HTTPS on port 443) OR (HTTP on port 80) then do not include
          the port number in the host string */
       aptr->host = aprintf("Host: %s%s%s\r\n", conn->bits.ipv6_ip?"[":"",
                            host, conn->bits.ipv6_ip?"]":"");
@@ -1778,7 +1764,7 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
                            conn->remote_port);
 
     if(!aptr->host)
-      /* without Host: we can't make a nice request */
+      /* without Host: we cannot make a nice request */
       return CURLE_OUT_OF_MEMORY;
   }
   return CURLE_OK;
@@ -1806,7 +1792,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
 
     /* The path sent to the proxy is in fact the entire URL. But if the remote
        host is a IDN-name, we must make sure that the request we produce only
-       uses the encoded host name! */
+       uses the encoded hostname! */
 
     /* and no fragment part */
     CURLUcode uc;
@@ -1829,7 +1815,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
     }
 
     if(strcasecompare("http", data->state.up.scheme)) {
-      /* when getting HTTP, we don't want the userinfo the URL */
+      /* when getting HTTP, we do not want the userinfo the URL */
       uc = curl_url_set(h, CURLUPART_USER, NULL, 0);
       if(uc) {
         curl_url_cleanup(h);
@@ -1850,7 +1836,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
 
     curl_url_cleanup(h);
 
-    /* target or url */
+    /* target or URL */
     result = Curl_dyn_add(r, data->set.str[STRING_TARGET]?
       data->set.str[STRING_TARGET]:url);
     free(url);
@@ -2053,7 +2039,7 @@ static CURLcode http_resume(struct Curl_easy *data, Curl_HttpReq httpreq)
     if(data->state.resume_from < 0) {
       /*
        * This is meant to get the size of the present remote-file by itself.
-       * We don't support this now. Bail out!
+       * We do not support this now. Bail out!
        */
       data->state.resume_from = 0;
     }
@@ -2138,7 +2124,7 @@ static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r,
   if(data->req.upgr101 != UPGR101_INIT)
     return CURLE_OK;
 
-  /* For really small puts we don't use Expect: headers at all, and for
+  /* For really small puts we do not use Expect: headers at all, and for
      the somewhat bigger ones we allow the app to disable it. Just make
      sure that the expect100header is always set to the preferred value
      here. */
@@ -2190,7 +2176,7 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
   case HTTPREQ_POST_MIME:
 #endif
     /* We only set Content-Length and allow a custom Content-Length if
-       we don't upload data chunked, as RFC2616 forbids us to set both
+       we do not upload data chunked, as RFC2616 forbids us to set both
        kinds of headers (Transfer-Encoding: chunked and Content-Length).
        We do not override a custom "Content-Length" header, but during
        authentication negotiation that header is suppressed.
@@ -2199,7 +2185,7 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
        (data->req.authneg ||
         !Curl_checkheaders(data, STRCONST("Content-Length")))) {
       /* we allow replacing this header if not during auth negotiation,
-         although it isn't very wise to actually set your own */
+         although it is not very wise to actually set your own */
       result = Curl_dyn_addf(r,
                              "Content-Length: %" CURL_FORMAT_CURL_OFF_T
                              "\r\n", req_clen);
@@ -2247,7 +2233,7 @@ CURLcode Curl_http_req_complete(struct Curl_easy *data,
 out:
   if(!result) {
     /* setup variables for the upcoming transfer */
-    Curl_xfer_setup(data, FIRSTSOCKET, -1, TRUE, FIRSTSOCKET);
+    Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
   }
   return result;
 }
@@ -2335,7 +2321,7 @@ CURLcode Curl_http_range(struct Curl_easy *data,
 {
   if(data->state.use_range) {
     /*
-     * A range is selected. We use different headers whether we're downloading
+     * A range is selected. We use different headers whether we are downloading
      * or uploading and we always let customized headers override our internal
      * ones if any such are specified.
      */
@@ -2353,7 +2339,7 @@ CURLcode Curl_http_range(struct Curl_easy *data,
       free(data->state.aptr.rangeline);
 
       if(data->set.set_resume_from < 0) {
-        /* Upload resume was asked for, but we don't know the size of the
+        /* Upload resume was asked for, but we do not know the size of the
            remote part so we tell the server (and act accordingly) that we
            upload the whole file (again) */
         data->state.aptr.rangeline =
@@ -2397,12 +2383,12 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data)
   if(data->req.newurl) {
     if(conn->bits.close) {
       /* Abort after the headers if "follow Location" is set
-         and we're set to close anyway. */
+         and we are set to close anyway. */
       k->keepon &= ~KEEP_RECV;
       k->done = TRUE;
       return CURLE_OK;
     }
-    /* We have a new url to load, but since we want to be able to reuse this
+    /* We have a new URL to load, but since we want to be able to reuse this
        connection properly, we read the full response in "ignore more" */
     k->ignorebody = TRUE;
     infof(data, "Ignoring the response-body");
@@ -2413,7 +2399,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data)
 
     if(k->size == data->state.resume_from) {
       /* The resume point is at the end of file, consider this fine even if it
-         doesn't allow resume from here. */
+         does not allow resume from here. */
       infof(data, "The entire document is already downloaded");
       streamclose(conn, "already downloaded");
       /* Abort download */
@@ -2422,10 +2408,10 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data)
       return CURLE_OK;
     }
 
-    /* we wanted to resume a download, although the server doesn't seem to
-     * support this and we did this with a GET (if it wasn't a GET we did a
+    /* we wanted to resume a download, although the server does not seem to
+     * support this and we did this with a GET (if it was not a GET we did a
      * POST or PUT resume) */
-    failf(data, "HTTP server doesn't seem to support "
+    failf(data, "HTTP server does not seem to support "
           "byte ranges. Cannot resume.");
     return CURLE_RANGE_ERROR;
   }
@@ -2437,7 +2423,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data)
 
     if(!Curl_meets_timecondition(data, k->timeofdoc)) {
       k->done = TRUE;
-      /* We're simulating an HTTP 304 from server so we return
+      /* We are simulating an HTTP 304 from server so we return
          what should have been returned from the server */
       data->info.httpcode = 304;
       infof(data, "Simulate an HTTP 304 response");
@@ -2459,7 +2445,7 @@ CURLcode Curl_transferencode(struct Curl_easy *data)
     /* When we are to insert a TE: header in the request, we must also insert
        TE in a Connection: header, so we need to merge the custom provided
        Connection: header and prevent the original to get sent. Note that if
-       the user has inserted his/her own TE: header we don't do this magic
+       the user has inserted his/her own TE: header we do not do this magic
        but then assume that the user will handle it all! */
     char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
 #define TE_HEADER "TE: gzip\r\n"
@@ -2705,7 +2691,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(!(conn->handler->flags&PROTOPT_SSL) &&
      conn->httpversion < 20 &&
      (data->state.httpwant == CURL_HTTP_VERSION_2)) {
-    /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
+    /* append HTTP2 upgrade magic stuff to the HTTP request if it is not done
        over SSL */
     result = Curl_http2_request_upgrade(&req, data);
     if(result) {
@@ -2849,7 +2835,7 @@ CURLcode Curl_http_header(struct Curl_easy *data,
 #ifndef CURL_DISABLE_ALTSVC
     v = (data->asi &&
          ((data->conn->handler->flags & PROTOPT_SSL) ||
-#ifdef CURLDEBUG
+#ifdef DEBUGBUILD
           /* allow debug builds to circumvent the HTTPS restriction */
           getenv("CURL_ALTSVC_HTTP")
 #else
@@ -2901,7 +2887,7 @@ CURLcode Curl_http_header(struct Curl_easy *data,
        * Process Content-Encoding. Look for the values: identity,
        * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
        * x-compress are the same as gzip and compress. (Sec 3.5 RFC
-       * 2616). zlib cannot handle compress.  However, errors are
+       * 2616). zlib cannot handle compress. However, errors are
        * handled further down when the response body is processed
        */
       return Curl_build_unencoding_stack(data, v, FALSE);
@@ -2936,7 +2922,7 @@ CURLcode Curl_http_header(struct Curl_easy *data,
       /*
        * An HTTP/1.0 reply with the 'Connection: keep-alive' line
        * tells us the connection will be kept alive for our
-       * pleasure.  Default action for 1.0 is to close.
+       * pleasure. Default action for 1.0 is to close.
        *
        * [RFC2068, section 19.7.1] */
       connkeep(conn, "Connection keep-alive");
@@ -3029,13 +3015,13 @@ CURLcode Curl_http_header(struct Curl_easy *data,
          * connection will be kept alive for our pleasure.
          * Default action for 1.0 is to close.
          */
-        connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
+        connkeep(conn, "Proxy-Connection keep-alive"); /* do not close */
         infof(data, "HTTP/1.0 proxy connection set to keep alive");
       }
       else if((conn->httpversion == 11) && conn->bits.httpproxy &&
               HD_IS_AND_SAYS(hd, hdlen, "Proxy-Connection:", "close")) {
         /*
-         * We get an HTTP/1.1 response from a proxy and it says it'll
+         * We get an HTTP/1.1 response from a proxy and it says it will
          * close down after this transfer.
          */
         connclose(conn, "Proxy-Connection: asked to close after done");
@@ -3095,7 +3081,7 @@ CURLcode Curl_http_header(struct Curl_easy *data,
         HD_VAL(hd, hdlen, "Set-Cookie:") : NULL;
     if(v) {
       /* If there is a custom-set Host: name, use it here, or else use
-       * real peer host name. */
+       * real peer hostname. */
       const char *host = data->state.aptr.cookiehost?
         data->state.aptr.cookiehost:conn->host.name;
       const bool secure_context =
@@ -3116,7 +3102,7 @@ CURLcode Curl_http_header(struct Curl_easy *data,
     /* If enabled, the header is incoming and this is over HTTPS */
     v = (data->hsts &&
          ((conn->handler->flags & PROTOPT_SSL) ||
-#ifdef CURLDEBUG
+#ifdef DEBUGBUILD
            /* allow debug builds to circumvent the HTTPS restriction */
            getenv("CURL_HSTS_HTTP")
 #else
@@ -3160,7 +3146,7 @@ CURLcode Curl_http_header(struct Curl_easy *data,
       if(result)
         return result;
       if(!k->chunk && data->set.http_transfer_encoding) {
-        /* if this isn't chunked, only close can signal the end of this
+        /* if this is not chunked, only close can signal the end of this
          * transfer as Content-Length is said not to be trusted for
          * transfer-encoding! */
         connclose(conn, "HTTP/1.1 transfer-encoding without chunks");
@@ -3231,11 +3217,11 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
     data->state.httpversion = (unsigned char)k->httpversion;
 
   /*
-   * This code executes as part of processing the header.  As a
-   * result, it's not totally clear how to interpret the
+   * This code executes as part of processing the header. As a
+   * result, it is not totally clear how to interpret the
    * response code yet as that depends on what other headers may
-   * be present.  401 and 407 may be errors, but may be OK
-   * depending on how authentication is working.  Other codes
+   * be present. 401 and 407 may be errors, but may be OK
+   * depending on how authentication is working. Other codes
    * are definitely errors, so give up here.
    */
   if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
@@ -3287,7 +3273,7 @@ CURLcode Curl_http_statusline(struct Curl_easy *data,
 }
 
 /* Content-Length must be ignored if any Transfer-Encoding is present in the
-   response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4.  This is
+   response. Refer to RFC 7230 section 3.3.3 and RFC2616 section 4.4. This is
    figured out here after all headers have been received but before the final
    call to the user's header callback, so that a valid content length can be
    retrieved by the user in the final call. */
@@ -3323,7 +3309,7 @@ static CURLcode verify_header(struct Curl_easy *data,
     /* the first "header" is the status-line and it has no colon */
     return CURLE_OK;
   if(((hd[0] == ' ') || (hd[0] == '\t')) && k->headerline > 2)
-    /* line folding, can't happen on line 2 */
+    /* line folding, cannot happen on line 2 */
     ;
   else {
     ptr = memchr(hd, ':', hdlen);
@@ -3363,8 +3349,35 @@ CURLcode Curl_bump_headersize(struct Curl_easy *data,
   return CURLE_OK;
 }
 
+static CURLcode http_write_header(struct Curl_easy *data,
+                                  const char *hd, size_t hdlen)
+{
+  CURLcode result;
+  int writetype;
+
+  /* now, only output this if the header AND body are requested:
+   */
+  Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
+
+  writetype = CLIENTWRITE_HEADER |
+    ((data->req.httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
+
+  result = Curl_client_write(data, writetype, hd, hdlen);
+  if(result)
+    return result;
+
+  result = Curl_bump_headersize(data, hdlen, FALSE);
+  if(result)
+    return result;
+
+  data->req.deductheadercount = (100 <= data->req.httpcode &&
+                                 199 >= data->req.httpcode)?
+                                data->req.headerbytecount:0;
+  return result;
+}
 
 static CURLcode http_on_response(struct Curl_easy *data,
+                                 const char *last_hd, size_t last_hd_len,
                                  const char *buf, size_t blen,
                                  size_t *pconsumed)
 {
@@ -3384,9 +3397,20 @@ static CURLcode http_on_response(struct Curl_easy *data,
     conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
   }
 
+  if(k->httpcode < 200 && last_hd) {
+    /* Intermediate responses might trigger processing of more
+     * responses, write the last header to the client before
+     * proceeding. */
+    result = http_write_header(data, last_hd, last_hd_len);
+    last_hd = NULL; /* handled it */
+    if(result)
+      goto out;
+  }
+
   if(k->httpcode < 100) {
     failf(data, "Unsupported response code in HTTP response");
-    return CURLE_UNSUPPORTED_PROTOCOL;
+    result = CURLE_UNSUPPORTED_PROTOCOL;
+    goto out;
   }
   else if(k->httpcode < 200) {
     /* "A user agent MAY ignore unexpected 1xx status responses."
@@ -3405,10 +3429,12 @@ static CURLcode http_on_response(struct Curl_easy *data,
       break;
     case 101:
       /* Switching Protocols only allowed from HTTP/1.1 */
+
       if(conn->httpversion != 11) {
         /* invalid for other HTTP versions */
         failf(data, "unexpected 101 response code");
-        return CURLE_WEIRD_SERVER_REPLY;
+        result = CURLE_WEIRD_SERVER_REPLY;
+        goto out;
       }
       if(k->upgr101 == UPGR101_H2) {
         /* Switching to HTTP/2, where we will get more responses */
@@ -3421,7 +3447,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
          * be processed. */
         result = Curl_http2_upgrade(data, conn, FIRSTSOCKET, buf, blen);
         if(result)
-          return result;
+          goto out;
         *pconsumed += blen;
       }
 #ifdef USE_WEBSOCKETS
@@ -3430,7 +3456,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
          * WebSockets format and taken in by the protocol handler. */
         result = Curl_ws_accept(data, buf, blen);
         if(result)
-          return result;
+          goto out;
         *pconsumed += blen; /* ws accept handled the data */
         k->header = FALSE; /* we will not get more responses */
         if(data->set.connect_only)
@@ -3451,7 +3477,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
        * to receive a final response eventually. */
       break;
     }
-    return result;
+    goto out;
   }
 
   /* k->httpcode >= 200, final response */
@@ -3512,7 +3538,8 @@ static CURLcode http_on_response(struct Curl_easy *data,
   /* All >=200 HTTP status codes are errors when wanting websockets */
   if(data->req.upgr101 == UPGR101_WS) {
     failf(data, "Refused WebSockets upgrade: %d", k->httpcode);
-    return CURLE_HTTP_RETURNED_ERROR;
+    result = CURLE_HTTP_RETURNED_ERROR;
+    goto out;
   }
 #endif
 
@@ -3520,7 +3547,8 @@ static CURLcode http_on_response(struct Curl_easy *data,
   if(http_should_fail(data, data->req.httpcode)) {
     failf(data, "The requested URL returned error: %d",
           k->httpcode);
-    return CURLE_HTTP_RETURNED_ERROR;
+    result = CURLE_HTTP_RETURNED_ERROR;
+    goto out;
   }
 
   /* Curl_http_auth_act() checks what authentication methods
@@ -3528,7 +3556,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
    * use. It will set 'newurl' if an auth method was picked. */
   result = Curl_http_auth_act(data);
   if(result)
-    return result;
+    goto out;
 
   if(k->httpcode >= 300) {
     if((!data->req.authneg) && !conn->bits.close &&
@@ -3551,7 +3579,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
       case HTTPREQ_POST_MIME:
         /* We got an error response. If this happened before the whole
          * request body has been sent we stop sending and mark the
-         * connection for closure after we've read the entire response.
+         * connection for closure after we have read the entire response.
          */
         if(!Curl_req_done_sending(data)) {
           if((k->httpcode == 417) && Curl_http_exp100_is_selected(data)) {
@@ -3566,7 +3594,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
                           "Stop sending data before everything sent");
               result = http_perhapsrewind(data, conn);
               if(result)
-                return result;
+                goto out;
             }
             data->state.disableexpect = TRUE;
             DEBUGASSERT(!data->req.newurl);
@@ -3582,7 +3610,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
             streamclose(conn, "Stop sending data before everything sent");
             result = Curl_req_abort_sending(data);
             if(result)
-              return result;
+              goto out;
           }
         }
         break;
@@ -3605,7 +3633,7 @@ static CURLcode http_on_response(struct Curl_easy *data,
    */
   result = Curl_http_size(data);
   if(result)
-    return result;
+    goto out;
 
   /* If we requested a "no body", this is a good time to get
    * out and return home.
@@ -3614,9 +3642,9 @@ static CURLcode http_on_response(struct Curl_easy *data,
     k->download_done = TRUE;
 
   /* If max download size is *zero* (nothing) we already have
-     nothing and can safely return ok now!  But for HTTP/2, we'd
+     nothing and can safely return ok now!  But for HTTP/2, we would
      like to call http2_handle_stream_close to properly close a
-     stream.  In order to do this, we keep reading until we
+     stream. In order to do this, we keep reading until we
      close the stream. */
   if(0 == k->maxdownload
      && !Curl_conn_is_http2(data, conn, FIRSTSOCKET)
@@ -3624,7 +3652,16 @@ static CURLcode http_on_response(struct Curl_easy *data,
     k->download_done = TRUE;
 
   /* final response without error, prepare to receive the body */
-  return Curl_http_firstwrite(data);
+  result = Curl_http_firstwrite(data);
+
+out:
+  if(last_hd) {
+    /* if not written yet, write it now */
+    CURLcode r2 = http_write_header(data, last_hd, last_hd_len);
+    if(!result)
+      result = r2;
+  }
+  return result;
 }
 
 static CURLcode http_rw_hd(struct Curl_easy *data,
@@ -3639,36 +3676,25 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
   *pconsumed = 0;
   if((0x0a == *hd) || (0x0d == *hd)) {
     /* Empty header line means end of headers! */
+    struct dynbuf last_header;
     size_t consumed;
 
-    /* now, only output this if the header AND body are requested:
-     */
-    Curl_debug(data, CURLINFO_HEADER_IN, (char *)hd, hdlen);
-
-    writetype = CLIENTWRITE_HEADER |
-      ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
-
-    result = Curl_client_write(data, writetype, hd, hdlen);
+    Curl_dyn_init(&last_header, hdlen + 1);
+    result = Curl_dyn_addn(&last_header, hd, hdlen);
     if(result)
       return result;
 
-    result = Curl_bump_headersize(data, hdlen, FALSE);
-    if(result)
-      return result;
-
-    data->req.deductheadercount =
-      (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
-
     /* analyze the response to find out what to do. */
     /* Caveat: we clear anything in the header brigade, because a
      * response might switch HTTP version which may call use recursively.
      * Not nice, but that is currently the way of things. */
     Curl_dyn_reset(&data->state.headerb);
-    result = http_on_response(data, buf_remain, blen, &consumed);
-    if(result)
-      return result;
+    result = http_on_response(data, Curl_dyn_ptr(&last_header),
+                              Curl_dyn_len(&last_header),
+                              buf_remain, blen, &consumed);
     *pconsumed += consumed;
-    return CURLE_OK;
+    Curl_dyn_free(&last_header);
+    return result;
   }
 
   /*
@@ -3681,14 +3707,14 @@ static CURLcode http_rw_hd(struct Curl_easy *data,
        or else we consider this to be the body right away! */
     bool fine_statusline = FALSE;
 
-    k->httpversion = 0; /* Don't know yet */
+    k->httpversion = 0; /* Do not know yet */
     if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
       /*
        * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
        *
        * The response code is always a three-digit number in HTTP as the spec
        * says. We allow any three-digit number here, but we cannot make
-       * guarantees on future behaviors since it isn't within the protocol.
+       * guarantees on future behaviors since it is not within the protocol.
        */
       const char *p = hd;
 
@@ -4431,7 +4457,7 @@ static CURLcode cr_exp100_read(struct Curl_easy *data,
       *eos = FALSE;
       return CURLE_OK;
     }
-    /* we've waited long enough, continue anyway */
+    /* we have waited long enough, continue anyway */
     http_exp100_continue(data, reader);
     infof(data, "Done waiting for 100-continue");
     FALLTHROUGH();
@@ -4460,6 +4486,7 @@ static const struct Curl_crtype cr_exp100 = {
   Curl_creader_def_resume_from,
   Curl_creader_def_rewind,
   Curl_creader_def_unpause,
+  Curl_creader_def_is_paused,
   cr_exp100_done,
   sizeof(struct cr_exp100_ctx)
 };

+ 3 - 8
Utilities/cmcurl/lib/http.h

@@ -73,7 +73,6 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
                              const struct connectdata *conn,
                              const char *thisheader,
                              const size_t thislen);
-struct HTTP; /* see below */
 
 CURLcode Curl_add_timecondition(struct Curl_easy *data,
 #ifndef USE_HYPER
@@ -147,7 +146,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
    selected to use no auth at all. Ie, we actively select no auth, as opposed
    to not having one selected. The other CURLAUTH_* defines are present in the
    public curl/curl.h header. */
-#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
+#define CURLAUTH_PICKNONE (1<<30) /* do not use auth */
 
 /* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
    data get included in the initial data chunk sent to the server. If the
@@ -187,10 +186,6 @@ void Curl_http_exp100_got100(struct Curl_easy *data);
 /****************************************************************************
  * HTTP unique setup
  ***************************************************************************/
-struct HTTP {
-  /* TODO: no longer used, we should remove it from SingleRequest */
-  char unused;
-};
 
 CURLcode Curl_http_size(struct Curl_easy *data);
 
@@ -240,7 +235,7 @@ struct httpreq {
 };
 
 /**
- * Create a HTTP request struct.
+ * Create an HTTP request struct.
  */
 CURLcode Curl_http_req_make(struct httpreq **preq,
                             const char *method, size_t m_len,
@@ -290,7 +285,7 @@ struct http_resp {
 };
 
 /**
- * Create a HTTP response struct.
+ * Create an HTTP response struct.
  */
 CURLcode Curl_http_resp_make(struct http_resp **presp,
                              int status,

+ 1 - 1
Utilities/cmcurl/lib/http1.c

@@ -217,7 +217,7 @@ static CURLcode start_req(struct h1_req_parser *parser,
     tmp[target_len] = '\0';
     /* See if treating TARGET as an absolute URL makes sense */
     if(Curl_is_absolute_url(tmp, NULL, 0, FALSE)) {
-      int url_options;
+      unsigned int url_options;
 
       url = curl_url();
       if(!url) {

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است