浏览代码

Merge branch 'upstream-curl' into update-curl

* upstream-curl:
  curl 2023-03-20 (b16d1fa8)
Brad King 2 年之前
父节点
当前提交
e3dc4df9b9
共有 76 个文件被更改,包括 1934 次插入1538 次删除
  1. 1 1
      Utilities/cmcurl/CMake/FindNGTCP2.cmake
  2. 0 2
      Utilities/cmcurl/CMake/Platforms/WindowsCache.cmake
  3. 84 66
      Utilities/cmcurl/CMakeLists.txt
  4. 4 3
      Utilities/cmcurl/include/curl/curl.h
  5. 4 4
      Utilities/cmcurl/include/curl/curlver.h
  6. 2 2
      Utilities/cmcurl/include/curl/urlapi.h
  7. 0 23
      Utilities/cmcurl/lib/CMakeLists.txt
  8. 2 4
      Utilities/cmcurl/lib/Makefile.inc
  9. 55 4
      Utilities/cmcurl/lib/cf-https-connect.c
  10. 0 0
      Utilities/cmcurl/lib/cf-https-connect.h
  11. 80 67
      Utilities/cmcurl/lib/cf-socket.c
  12. 0 7
      Utilities/cmcurl/lib/cf-socket.h
  13. 28 8
      Utilities/cmcurl/lib/cfilters.c
  14. 11 8
      Utilities/cmcurl/lib/cfilters.h
  15. 1 13
      Utilities/cmcurl/lib/conncache.c
  16. 33 2
      Utilities/cmcurl/lib/connect.c
  17. 8 0
      Utilities/cmcurl/lib/content_encoding.c
  18. 121 125
      Utilities/cmcurl/lib/cookie.c
  19. 8 2
      Utilities/cmcurl/lib/curl_gssapi.c
  20. 1 1
      Utilities/cmcurl/lib/curl_log.c
  21. 35 40
      Utilities/cmcurl/lib/curl_path.c
  22. 2 2
      Utilities/cmcurl/lib/curl_setup.h
  23. 8 0
      Utilities/cmcurl/lib/curl_setup_once.h
  24. 1 1
      Utilities/cmcurl/lib/doh.c
  25. 1 2
      Utilities/cmcurl/lib/dynbuf.c
  26. 0 1
      Utilities/cmcurl/lib/easy.c
  27. 109 45
      Utilities/cmcurl/lib/ftp.c
  28. 5 0
      Utilities/cmcurl/lib/ftp.h
  29. 40 3
      Utilities/cmcurl/lib/ftplistparser.c
  30. 34 0
      Utilities/cmcurl/lib/ftplistparser.h
  31. 9 8
      Utilities/cmcurl/lib/headers.c
  32. 1 1
      Utilities/cmcurl/lib/hostasyn.c
  33. 50 41
      Utilities/cmcurl/lib/hostip.c
  34. 1 1
      Utilities/cmcurl/lib/hostip.h
  35. 99 76
      Utilities/cmcurl/lib/http.c
  36. 192 159
      Utilities/cmcurl/lib/http2.c
  37. 135 55
      Utilities/cmcurl/lib/http_aws_sigv4.c
  38. 7 5
      Utilities/cmcurl/lib/http_proxy.c
  39. 5 0
      Utilities/cmcurl/lib/idn.c
  40. 9 4
      Utilities/cmcurl/lib/inet_ntop.c
  41. 9 6
      Utilities/cmcurl/lib/inet_pton.c
  42. 4 4
      Utilities/cmcurl/lib/krb5.c
  43. 8 0
      Utilities/cmcurl/lib/ldap.c
  44. 3 2
      Utilities/cmcurl/lib/mqtt.c
  45. 57 46
      Utilities/cmcurl/lib/multi.c
  46. 100 59
      Utilities/cmcurl/lib/parsedate.c
  47. 2 11
      Utilities/cmcurl/lib/progress.c
  48. 9 0
      Utilities/cmcurl/lib/rand.c
  49. 9 6
      Utilities/cmcurl/lib/rtsp.c
  50. 2 2
      Utilities/cmcurl/lib/select.c
  51. 3 3
      Utilities/cmcurl/lib/setopt.c
  52. 0 1
      Utilities/cmcurl/lib/sigpipe.h
  53. 1 2
      Utilities/cmcurl/lib/smb.c
  54. 109 70
      Utilities/cmcurl/lib/telnet.c
  55. 17 4
      Utilities/cmcurl/lib/transfer.c
  56. 48 48
      Utilities/cmcurl/lib/url.c
  57. 18 13
      Utilities/cmcurl/lib/urlapi.c
  58. 11 5
      Utilities/cmcurl/lib/urldata.h
  59. 9 2
      Utilities/cmcurl/lib/version.c
  60. 16 7
      Utilities/cmcurl/lib/vquic/curl_msh3.c
  61. 48 13
      Utilities/cmcurl/lib/vquic/curl_ngtcp2.c
  62. 41 10
      Utilities/cmcurl/lib/vquic/curl_quiche.c
  63. 6 1
      Utilities/cmcurl/lib/vquic/vquic.c
  64. 17 37
      Utilities/cmcurl/lib/vssh/libssh.c
  65. 10 5
      Utilities/cmcurl/lib/vssh/libssh2.c
  66. 2 2
      Utilities/cmcurl/lib/vssh/ssh.h
  67. 1 31
      Utilities/cmcurl/lib/vtls/nss.c
  68. 1 58
      Utilities/cmcurl/lib/vtls/openssl.c
  69. 74 67
      Utilities/cmcurl/lib/vtls/schannel.c
  70. 39 68
      Utilities/cmcurl/lib/vtls/sectransp.c
  71. 38 10
      Utilities/cmcurl/lib/vtls/vtls.c
  72. 34 5
      Utilities/cmcurl/lib/vtls/wolfssl.c
  73. 2 2
      Utilities/cmcurl/lib/vtls/x509asn1.c
  74. 0 75
      Utilities/cmcurl/lib/wildcard.c
  75. 0 70
      Utilities/cmcurl/lib/wildcard.h
  76. 0 7
      Utilities/cmcurl/lib/ws.c

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

@@ -71,7 +71,7 @@ endif()
 if(NGTCP2_FIND_COMPONENTS)
 if(NGTCP2_FIND_COMPONENTS)
   set(NGTCP2_CRYPTO_BACKEND "")
   set(NGTCP2_CRYPTO_BACKEND "")
   foreach(component IN LISTS NGTCP2_FIND_COMPONENTS)
   foreach(component IN LISTS NGTCP2_FIND_COMPONENTS)
-    if(component MATCHES "^(BoringSSL|OpenSSL|GnuTLS)")
+    if(component MATCHES "^(BoringSSL|OpenSSL|wolfSSL|GnuTLS)")
       if(NGTCP2_CRYPTO_BACKEND)
       if(NGTCP2_CRYPTO_BACKEND)
         message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
         message(FATAL_ERROR "NGTCP2: Only one crypto library can be selected")
       endif()
       endif()

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

@@ -29,7 +29,6 @@ if(NOT UNIX)
 
 
     set(HAVE_ARPA_INET_H 0)
     set(HAVE_ARPA_INET_H 0)
     set(HAVE_FCNTL_H 1)
     set(HAVE_FCNTL_H 1)
-    set(HAVE_INTTYPES_H 0)
     set(HAVE_IO_H 1)
     set(HAVE_IO_H 1)
     set(HAVE_NETDB_H 0)
     set(HAVE_NETDB_H 0)
     set(HAVE_NETINET_IN_H 0)
     set(HAVE_NETINET_IN_H 0)
@@ -37,7 +36,6 @@ if(NOT UNIX)
     set(HAVE_PWD_H 0)
     set(HAVE_PWD_H 0)
     set(HAVE_SETJMP_H 1)
     set(HAVE_SETJMP_H 1)
     set(HAVE_SIGNAL_H 1)
     set(HAVE_SIGNAL_H 1)
-    set(HAVE_STDINT_H 0)
     set(HAVE_STDLIB_H 1)
     set(HAVE_STDLIB_H 1)
     set(HAVE_STRINGS_H 0)
     set(HAVE_STRINGS_H 0)
     set(HAVE_STRING_H 1)
     set(HAVE_STRING_H 1)

+ 84 - 66
Utilities/cmcurl/CMakeLists.txt

@@ -197,7 +197,7 @@ endif()
 #   HAVE_RAND_EGD: `RAND_egd` present in OpenSSL
 #   HAVE_RAND_EGD: `RAND_egd` present in OpenSSL
 #   HAVE_BORINGSSL: OpenSSL is BoringSSL
 #   HAVE_BORINGSSL: OpenSSL is BoringSSL
 #   HAVE_PK11_CREATEMANAGEDGENERICOBJECTL: `PK11_CreateManagedGenericObject` present in NSS
 #   HAVE_PK11_CREATEMANAGEDGENERICOBJECTL: `PK11_CreateManagedGenericObject` present in NSS
-#   HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL
+#   HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL/wolfSSL
 #   HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in QUICHE
 #   HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in QUICHE
 #   HAVE_ZSTD_CREATEDSTREAM: `ZSTD_createDStream` present in Zstd
 #   HAVE_ZSTD_CREATEDSTREAM: `ZSTD_createDStream` present in Zstd
 #
 #
@@ -523,7 +523,7 @@ if(APPLE)
 endif()
 endif()
 if(WIN32)
 if(WIN32)
   cmake_dependent_option(CURL_USE_SCHANNEL "enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
   cmake_dependent_option(CURL_USE_SCHANNEL "enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
-  cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without openssl" ON
+  cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without OpenSSL" ON
     CURL_USE_SCHANNEL OFF)
     CURL_USE_SCHANNEL OFF)
 endif()
 endif()
 cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
@@ -583,6 +583,58 @@ if(use_core_foundation)
   list(APPEND CURL_LIBS "-framework CoreFoundation")
   list(APPEND CURL_LIBS "-framework CoreFoundation")
 endif()
 endif()
 
 
+# Keep compression lib detection before TLS detection, which
+# might depend on it.
+
+set(HAVE_LIBZ OFF)
+set(USE_ZLIB OFF)
+optional_dependency(ZLIB)
+if(ZLIB_FOUND)
+  set(HAVE_LIBZ ON)
+  set(USE_ZLIB ON)
+
+  # Depend on ZLIB via imported targets if supported by the running
+  # version of CMake.  This allows our dependents to get our dependencies
+  # transitively.
+  if(NOT CMAKE_VERSION VERSION_LESS 3.4)
+    list(APPEND CURL_LIBS ZLIB::ZLIB)
+  else()
+    list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
+    include_directories(${ZLIB_INCLUDE_DIRS})
+  endif()
+  list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
+endif()
+
+option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
+set(HAVE_BROTLI OFF)
+if(CURL_BROTLI)
+  find_package(Brotli QUIET)
+  if(BROTLI_FOUND)
+    set(HAVE_BROTLI ON)
+    list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
+    include_directories(${BROTLI_INCLUDE_DIRS})
+    list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
+  endif()
+endif()
+
+option(CURL_ZSTD "Set to ON to enable building curl with zstd support." OFF)
+set(HAVE_ZSTD OFF)
+if(CURL_ZSTD)
+  find_package(Zstd REQUIRED)
+  if (NOT DEFINED HAVE_ZSTD_CREATEDSTREAM)
+    cmake_push_check_state()
+    set(CMAKE_REQUIRED_INCLUDES ${Zstd_INCLUDE_DIRS})
+    set(CMAKE_REQUIRED_LIBRARIES ${Zstd_LIBRARIES})
+    check_symbol_exists(ZSTD_createDStream "zstd.h" HAVE_ZSTD_CREATEDSTREAM)
+    cmake_pop_check_state()
+  endif()
+  if(Zstd_FOUND AND HAVE_ZSTD_CREATEDSTREAM)
+    set(HAVE_ZSTD ON)
+    list(APPEND CURL_LIBS ${Zstd_LIBRARIES})
+    include_directories(${Zstd_INCLUDE_DIRS})
+  endif()
+endif()
+
 if(CURL_USE_OPENSSL)
 if(CURL_USE_OPENSSL)
   find_package(OpenSSL)
   find_package(OpenSSL)
   if(NOT OpenSSL_FOUND)
   if(NOT OpenSSL_FOUND)
@@ -660,23 +712,39 @@ if(USE_NGHTTP2)
 endif()
 endif()
 
 
 function(CheckQuicSupportInOpenSSL)
 function(CheckQuicSupportInOpenSSL)
-  # Be sure that the OpenSSL library actually supports QUIC.
+  # Be sure that the OpenSSL/wolfSSL library actually supports QUIC.
   if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD)
   if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD)
     cmake_push_check_state()
     cmake_push_check_state()
-    set(CMAKE_REQUIRED_INCLUDES   "${OPENSSL_INCLUDE_DIR}")
-    set(CMAKE_REQUIRED_LIBRARIES  "${OPENSSL_LIBRARIES}")
-    check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
+    if(USE_WOLFSSL)
+      set(CMAKE_REQUIRED_INCLUDES   "${WolfSSL_INCLUDE_DIRS}")
+      set(CMAKE_REQUIRED_LIBRARIES  "${WolfSSL_LIBRARIES}")
+      if(HAVE_LIBZ)
+        list(APPEND CMAKE_REQUIRED_INCLUDES  "${ZLIB_INCLUDE_DIRS}")
+        list(APPEND CMAKE_REQUIRED_LIBRARIES "${ZLIB_LIBRARIES}")
+      endif()
+      if(WIN32)
+        list(APPEND CMAKE_REQUIRED_LIBRARIES "crypt32")
+      endif()
+      list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_UINTPTR_T)  # to pull in stdint.h (as of wolfSSL v5.5.4)
+      check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
+    else()
+      set(CMAKE_REQUIRED_INCLUDES   "${OPENSSL_INCLUDE_DIR}")
+      set(CMAKE_REQUIRED_LIBRARIES  "${OPENSSL_LIBRARIES}")
+      check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
+    endif()
     cmake_pop_check_state()
     cmake_pop_check_state()
   endif()
   endif()
   if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD)
   if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD)
-    message(FATAL_ERROR "QUIC support is missing in OpenSSL/BoringSSL. Try setting -DOPENSSL_ROOT_DIR")
+    message(FATAL_ERROR "QUIC support is missing in OpenSSL/BoringSSL/wolfSSL. Try setting -DOPENSSL_ROOT_DIR")
   endif()
   endif()
 endfunction()
 endfunction()
 
 
 option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF)
 option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF)
 if(USE_NGTCP2)
 if(USE_NGTCP2)
-  if(USE_OPENSSL)
-    if(HAVE_BORINGSSL)
+  if(USE_OPENSSL OR USE_WOLFSSL)
+    if(USE_WOLFSSL)
+      find_package(NGTCP2 REQUIRED wolfSSL)
+    elseif(HAVE_BORINGSSL)
       find_package(NGTCP2 REQUIRED BoringSSL)
       find_package(NGTCP2 REQUIRED BoringSSL)
     else()
     else()
       find_package(NGTCP2 REQUIRED OpenSSL)
       find_package(NGTCP2 REQUIRED OpenSSL)
@@ -686,7 +754,7 @@ if(USE_NGTCP2)
     # TODO add GnuTLS support as vtls library.
     # TODO add GnuTLS support as vtls library.
     find_package(NGTCP2 REQUIRED GnuTLS)
     find_package(NGTCP2 REQUIRED GnuTLS)
   else()
   else()
-    message(FATAL_ERROR "ngtcp2 requires OpenSSL or GnuTLS")
+    message(FATAL_ERROR "ngtcp2 requires OpenSSL, wolfSSL or GnuTLS")
   endif()
   endif()
   set(USE_NGTCP2 ON)
   set(USE_NGTCP2 ON)
   include_directories(${NGTCP2_INCLUDE_DIRS})
   include_directories(${NGTCP2_INCLUDE_DIRS})
@@ -734,6 +802,8 @@ if(NOT CURL_DISABLE_LDAP)
       check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32)
       check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32)
       if(NOT HAVE_WLDAP32)
       if(NOT HAVE_WLDAP32)
         set(USE_WIN32_LDAP OFF)
         set(USE_WIN32_LDAP OFF)
+      elseif(NOT CURL_DISABLE_LDAPS)
+        set(HAVE_LDAP_SSL ON)
       endif()
       endif()
     endif()
     endif()
   endif()
   endif()
@@ -849,56 +919,6 @@ if(WIN32)
   endif()
   endif()
 endif()
 endif()
 
 
-set(HAVE_LIBZ OFF)
-set(USE_ZLIB OFF)
-#optional_dependency(ZLIB)
-find_package(ZLIB)
-if(ZLIB_FOUND)
-  set(HAVE_LIBZ ON)
-  set(USE_ZLIB ON)
-
-  # Depend on ZLIB via imported targets if supported by the running
-  # version of CMake.  This allows our dependents to get our dependencies
-  # transitively.
-  if(NOT CMAKE_VERSION VERSION_LESS 3.4)
-    list(APPEND CURL_LIBS ZLIB::ZLIB)
-  else()
-    list(APPEND CURL_LIBS ${ZLIB_LIBRARIES})
-    include_directories(${ZLIB_INCLUDE_DIRS})
-    list(APPEND CMAKE_REQUIRED_INCLUDES ${ZLIB_INCLUDE_DIRS})
-  endif()
-endif()
-
-option(CURL_BROTLI "Set to ON to enable building curl with brotli support." OFF)
-set(HAVE_BROTLI OFF)
-if(CURL_BROTLI)
-  find_package(Brotli QUIET)
-  if(BROTLI_FOUND)
-    set(HAVE_BROTLI ON)
-    list(APPEND CURL_LIBS ${BROTLI_LIBRARIES})
-    include_directories(${BROTLI_INCLUDE_DIRS})
-    list(APPEND CMAKE_REQUIRED_INCLUDES ${BROTLI_INCLUDE_DIRS})
-  endif()
-endif()
-
-option(CURL_ZSTD "Set to ON to enable building curl with zstd support." OFF)
-set(HAVE_ZSTD OFF)
-if(CURL_ZSTD)
-  find_package(Zstd REQUIRED)
-  if (NOT DEFINED HAVE_ZSTD_CREATEDSTREAM)
-    cmake_push_check_state()
-    set(CMAKE_REQUIRED_INCLUDES ${Zstd_INCLUDE_DIRS})
-    set(CMAKE_REQUIRED_LIBRARIES ${Zstd_LIBRARIES})
-    check_symbol_exists(ZSTD_createDStream "zstd.h" HAVE_ZSTD_CREATEDSTREAM)
-    cmake_pop_check_state()
-  endif()
-  if(Zstd_FOUND AND HAVE_ZSTD_CREATEDSTREAM)
-    set(HAVE_ZSTD ON)
-    list(APPEND CURL_LIBS ${Zstd_LIBRARIES})
-    include_directories(${Zstd_INCLUDE_DIRS})
-  endif()
-endif()
-
 #libpsl
 #libpsl
 option(CURL_USE_LIBPSL "Use libPSL" ON)
 option(CURL_USE_LIBPSL "Use libPSL" ON)
 mark_as_advanced(CURL_USE_LIBPSL)
 mark_as_advanced(CURL_USE_LIBPSL)
@@ -1035,7 +1055,9 @@ elseif("${CURL_CA_BUNDLE}" STREQUAL "none")
   unset(CURL_CA_BUNDLE CACHE)
   unset(CURL_CA_BUNDLE CACHE)
 elseif("${CURL_CA_BUNDLE}" STREQUAL "auto")
 elseif("${CURL_CA_BUNDLE}" STREQUAL "auto")
   unset(CURL_CA_BUNDLE CACHE)
   unset(CURL_CA_BUNDLE CACHE)
-  set(CURL_CA_BUNDLE_AUTODETECT TRUE)
+  if(NOT CMAKE_CROSSCOMPILING)
+    set(CURL_CA_BUNDLE_AUTODETECT TRUE)
+  endif()
 else()
 else()
   set(CURL_CA_BUNDLE_SET TRUE)
   set(CURL_CA_BUNDLE_SET TRUE)
 endif()
 endif()
@@ -1046,7 +1068,7 @@ elseif("${CURL_CA_PATH}" STREQUAL "none")
   unset(CURL_CA_PATH CACHE)
   unset(CURL_CA_PATH CACHE)
 elseif("${CURL_CA_PATH}" STREQUAL "auto")
 elseif("${CURL_CA_PATH}" STREQUAL "auto")
   unset(CURL_CA_PATH CACHE)
   unset(CURL_CA_PATH CACHE)
-  if(NOT USE_NSS)
+  if(NOT CMAKE_CROSSCOMPILING AND NOT USE_NSS)
     set(CURL_CA_PATH_AUTODETECT TRUE)
     set(CURL_CA_PATH_AUTODETECT TRUE)
   endif()
   endif()
 else()
 else()
@@ -1156,7 +1178,6 @@ check_include_file_concat("unistd.h"         HAVE_UNISTD_H)
 check_include_file_concat("utime.h"          HAVE_UTIME_H)
 check_include_file_concat("utime.h"          HAVE_UTIME_H)
 
 
 check_include_file_concat("stddef.h"         HAVE_STDDEF_H)
 check_include_file_concat("stddef.h"         HAVE_STDDEF_H)
-check_include_file_concat("stdint.h"        HAVE_STDINT_H)
 check_include_file_concat("sys/utsname.h"   HAVE_SYS_UTSNAME_H)
 check_include_file_concat("sys/utsname.h"   HAVE_SYS_UTSNAME_H)
 
 
 check_type_size(size_t  SIZEOF_SIZE_T)
 check_type_size(size_t  SIZEOF_SIZE_T)
@@ -1208,7 +1229,6 @@ check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R)
 
 
 check_symbol_exists(signal         "${CURL_INCLUDES}" HAVE_SIGNAL)
 check_symbol_exists(signal         "${CURL_INCLUDES}" HAVE_SIGNAL)
 check_symbol_exists(strtoll        "${CURL_INCLUDES}" HAVE_STRTOLL)
 check_symbol_exists(strtoll        "${CURL_INCLUDES}" HAVE_STRTOLL)
-check_symbol_exists(_strtoi64      "${CURL_INCLUDES}" HAVE__STRTOI64)
 check_symbol_exists(strerror_r     "${CURL_INCLUDES}" HAVE_STRERROR_R)
 check_symbol_exists(strerror_r     "${CURL_INCLUDES}" HAVE_STRERROR_R)
 check_symbol_exists(siginterrupt   "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
 check_symbol_exists(siginterrupt   "${CURL_INCLUDES}" HAVE_SIGINTERRUPT)
 check_symbol_exists(getaddrinfo    "${CURL_INCLUDES}" HAVE_GETADDRINFO)
 check_symbol_exists(getaddrinfo    "${CURL_INCLUDES}" HAVE_GETADDRINFO)
@@ -1415,8 +1435,6 @@ else()
   set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H})
   set(CURL_PULL_SYS_SOCKET_H ${HAVE_SYS_SOCKET_H})
   set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H})
   set(CURL_PULL_SYS_POLL_H ${HAVE_SYS_POLL_H})
 endif()
 endif()
-set(CURL_PULL_STDINT_H ${HAVE_STDINT_H})
-set(CURL_PULL_INTTYPES_H ${HAVE_INTTYPES_H})
 
 
 include(CMake/OtherTests.cmake)
 include(CMake/OtherTests.cmake)
 
 

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

@@ -34,11 +34,12 @@
 #endif
 #endif
 
 
 /* Compile-time deprecation macros. */
 /* Compile-time deprecation macros. */
-#if defined(__GNUC__) && (__GNUC__ >= 6) &&                             \
+#if defined(__GNUC__) &&                                                \
+  ((__GNUC__ > 12) || ((__GNUC__ == 12) && (__GNUC_MINOR__ >= 1 ))) &&  \
   !defined(__INTEL_COMPILER) &&                                         \
   !defined(__INTEL_COMPILER) &&                                         \
   !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
   !defined(CURL_DISABLE_DEPRECATION) && !defined(BUILDING_LIBCURL)
-#define CURL_DEPRECATED(version, message) \
-    __attribute__((deprecated("since " # version ". " message)))
+#define CURL_DEPRECATED(version, message)                       \
+  __attribute__((deprecated("since " # version ". " message)))
 #define CURL_IGNORE_DEPRECATION(statements) \
 #define CURL_IGNORE_DEPRECATION(statements) \
       _Pragma("GCC diagnostic push") \
       _Pragma("GCC diagnostic push") \
       _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \
       _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") \

+ 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
 /* This is the version number of the libcurl package from which this header
    file origins: */
    file origins: */
-#define LIBCURL_VERSION "7.88.1"
+#define LIBCURL_VERSION "8.0.1"
 
 
 /* The numeric version number is also available "in parts" by using these
 /* The numeric version number is also available "in parts" by using these
    defines: */
    defines: */
-#define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 88
+#define LIBCURL_VERSION_MAJOR 8
+#define LIBCURL_VERSION_MINOR 0
 #define LIBCURL_VERSION_PATCH 1
 #define LIBCURL_VERSION_PATCH 1
 
 
 /* This is the numeric version of the libcurl version number, meant for easier
 /* This is the numeric version of the libcurl version number, meant for easier
@@ -59,7 +59,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
    and needs it to contain the full number.
 */
 */
-#define LIBCURL_VERSION_NUM 0x075801
+#define LIBCURL_VERSION_NUM 0x080001
 
 
 /*
 /*
  * This is the date and time when the full source package was created. The
  * This is the date and time when the full source package was created. The

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

@@ -117,14 +117,14 @@ CURL_EXTERN void curl_url_cleanup(CURLU *handle);
  * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new
  * curl_url_dup() duplicates a CURLU handle and returns a new copy. The new
  * handle must also be freed with curl_url_cleanup().
  * handle must also be freed with curl_url_cleanup().
  */
  */
-CURL_EXTERN CURLU *curl_url_dup(CURLU *in);
+CURL_EXTERN CURLU *curl_url_dup(const CURLU *in);
 
 
 /*
 /*
  * curl_url_get() extracts a specific part of the URL from a CURLU
  * curl_url_get() extracts a specific part of the URL from a CURLU
  * handle. Returns error code. The returned pointer MUST be freed with
  * handle. Returns error code. The returned pointer MUST be freed with
  * curl_free() afterwards.
  * curl_free() afterwards.
  */
  */
-CURL_EXTERN CURLUcode curl_url_get(CURLU *handle, CURLUPart what,
+CURL_EXTERN CURLUcode curl_url_get(const CURLU *handle, CURLUPart what,
                                    char **part, unsigned int flags);
                                    char **part, unsigned int flags);
 
 
 /*
 /*

+ 0 - 23
Utilities/cmcurl/lib/CMakeLists.txt

@@ -47,29 +47,6 @@ if(WIN32 AND NOT CURL_STATICLIB)
   list(APPEND CSOURCES libcurl.rc)
   list(APPEND CSOURCES libcurl.rc)
 endif()
 endif()
 
 
-# SET(CSOURCES
-# #  memdebug.c -not used
-# # nwlib.c - Not used
-# # strtok.c - specify later
-# # strtoofft.c - specify later
-# )
-
-# #OPTION(CURL_MALLOC_DEBUG "Debug mallocs in Curl" OFF)
-# MARK_AS_ADVANCED(CURL_MALLOC_DEBUG)
-# IF(CURL_MALLOC_DEBUG)
-# SET(CSOURCES ${CSOURCES}
-# memdebug.c
-# )
-# ENDIF(CURL_MALLOC_DEBUG)
-
-# # only build compat strtoofft if we need to
-# IF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
-# SET(CSOURCES ${CSOURCES}
-# strtoofft.c
-# )
-# ENDIF(NOT HAVE_STRTOLL AND NOT HAVE__STRTOI64)
-
-
 # The rest of the build
 # The rest of the build
 
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include)
 include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include)

+ 2 - 4
Utilities/cmcurl/lib/Makefile.inc

@@ -107,7 +107,7 @@ LIB_CFILES =         \
   base64.c           \
   base64.c           \
   bufref.c           \
   bufref.c           \
   c-hyper.c          \
   c-hyper.c          \
-  cf-http.c          \
+  cf-https-connect.c \
   cf-socket.c        \
   cf-socket.c        \
   cfilters.c         \
   cfilters.c         \
   conncache.c        \
   conncache.c        \
@@ -223,7 +223,6 @@ LIB_CFILES =         \
   version.c          \
   version.c          \
   version_win32.c    \
   version_win32.c    \
   warnless.c         \
   warnless.c         \
-  wildcard.c         \
   ws.c
   ws.c
 
 
 LIB_HFILES =         \
 LIB_HFILES =         \
@@ -233,7 +232,7 @@ LIB_HFILES =         \
   asyn.h             \
   asyn.h             \
   bufref.h           \
   bufref.h           \
   c-hyper.h          \
   c-hyper.h          \
-  cf-http.h          \
+  cf-https-connect.h \
   cf-socket.h        \
   cf-socket.h        \
   cfilters.h         \
   cfilters.h         \
   conncache.h        \
   conncache.h        \
@@ -352,7 +351,6 @@ LIB_HFILES =         \
   urldata.h          \
   urldata.h          \
   version_win32.h    \
   version_win32.h    \
   warnless.h         \
   warnless.h         \
-  wildcard.h         \
   ws.h
   ws.h
 
 
 LIB_RCFILES = libcurl.rc
 LIB_RCFILES = libcurl.rc

+ 55 - 4
Utilities/cmcurl/lib/cf-http.c → Utilities/cmcurl/lib/cf-https-connect.c

@@ -32,7 +32,7 @@
 #include "cfilters.h"
 #include "cfilters.h"
 #include "connect.h"
 #include "connect.h"
 #include "multiif.h"
 #include "multiif.h"
-#include "cf-http.h"
+#include "cf-https-connect.h"
 #include "http2.h"
 #include "http2.h"
 #include "vquic/vquic.h"
 #include "vquic/vquic.h"
 
 
@@ -266,7 +266,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
         Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
         Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
     }
     }
     else if(ctx->h21_baller.enabled)
     else if(ctx->h21_baller.enabled)
-      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", TRNSPRT_TCP);
+      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
+                       cf->conn->transport);
     ctx->state = CF_HC_CONNECT;
     ctx->state = CF_HC_CONNECT;
     /* FALLTHROUGH */
     /* FALLTHROUGH */
 
 
@@ -280,7 +281,8 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
     }
     }
 
 
     if(time_to_start_h21(cf, data, now)) {
     if(time_to_start_h21(cf, data, now)) {
-      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21", TRNSPRT_TCP);
+      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
+                        cf->conn->transport);
     }
     }
 
 
     if(cf_hc_baller_is_active(&ctx->h21_baller)) {
     if(cf_hc_baller_is_active(&ctx->h21_baller)) {
@@ -374,6 +376,55 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
          || cf_hc_baller_data_pending(&ctx->h21_baller, data);
          || cf_hc_baller_data_pending(&ctx->h21_baller, data);
 }
 }
 
 
+static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data,
+                                          int query)
+{
+  struct cf_hc_ctx *ctx = cf->ctx;
+  struct Curl_cfilter *cfb;
+  struct curltime t, tmax;
+
+  memset(&tmax, 0, sizeof(tmax));
+  memset(&t, 0, sizeof(t));
+  cfb = ctx->h21_baller.enabled? ctx->h21_baller.cf : NULL;
+  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
+    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+      tmax = t;
+  }
+  memset(&t, 0, sizeof(t));
+  cfb = ctx->h3_baller.enabled? ctx->h3_baller.cf : NULL;
+  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
+    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+      tmax = t;
+  }
+  return tmax;
+}
+
+static CURLcode cf_hc_query(struct Curl_cfilter *cf,
+                            struct Curl_easy *data,
+                            int query, int *pres1, void *pres2)
+{
+  if(!cf->connected) {
+    switch(query) {
+    case CF_QUERY_TIMER_CONNECT: {
+      struct curltime *when = pres2;
+      *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
+      return CURLE_OK;
+    }
+    case CF_QUERY_TIMER_APPCONNECT: {
+      struct curltime *when = pres2;
+      *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
+      return CURLE_OK;
+    }
+    default:
+      break;
+    }
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
 static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
 {
   DEBUGF(LOG_CF(data, cf, "close"));
   DEBUGF(LOG_CF(data, cf, "close"));
@@ -411,7 +462,7 @@ struct Curl_cftype Curl_cft_http_connect = {
   Curl_cf_def_cntrl,
   Curl_cf_def_cntrl,
   Curl_cf_def_conn_is_alive,
   Curl_cf_def_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
   Curl_cf_def_conn_keep_alive,
-  Curl_cf_def_query,
+  cf_hc_query,
 };
 };
 
 
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,

+ 0 - 0
Utilities/cmcurl/lib/cf-http.h → Utilities/cmcurl/lib/cf-https-connect.h


+ 80 - 67
Utilities/cmcurl/lib/cf-socket.c

@@ -253,19 +253,6 @@ static CURLcode socket_open(struct Curl_easy *data,
   else {
   else {
     /* opensocket callback not set, so simply create the socket now */
     /* opensocket callback not set, so simply create the socket now */
     *sockfd = socket(addr->family, addr->socktype, addr->protocol);
     *sockfd = socket(addr->family, addr->socktype, addr->protocol);
-    if(!*sockfd && addr->socktype == SOCK_DGRAM) {
-      /* This is icky and seems, at least, to happen on macOS:
-       * we get sockfd == 0 and if called again, we get a valid one > 0.
-       * If we close the 0, we sometimes get failures in multi poll, as
-       * 0 seems also be the fd for the sockpair used for WAKEUP polling.
-       * Very strange. Maybe this code should be ifdef'ed for macOS, but
-       * on "real" OS, fd 0 is stdin and we never see that. So...
-       */
-      fake_sclose(*sockfd);
-      *sockfd = socket(addr->family, addr->socktype, addr->protocol);
-      DEBUGF(infof(data, "QUIRK: UDP socket() gave handle 0, 2nd attempt %d",
-                   (int)*sockfd));
-    }
   }
   }
 
 
   if(*sockfd == CURL_SOCKET_BAD)
   if(*sockfd == CURL_SOCKET_BAD)
@@ -338,20 +325,6 @@ int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
   return socket_close(data, conn, FALSE, sock);
   return socket_close(data, conn, FALSE, sock);
 }
 }
 
 
-bool Curl_socket_is_dead(curl_socket_t sock)
-{
-  int sval;
-  bool ret_val = TRUE;
-
-  sval = SOCKET_READABLE(sock, 0);
-  if(sval == 0)
-    /* timeout */
-    ret_val = FALSE;
-
-  return ret_val;
-}
-
-
 #ifdef USE_WINSOCK
 #ifdef USE_WINSOCK
 /* When you run a program that uses the Windows Sockets API, you may
 /* When you run a program that uses the Windows Sockets API, you may
    experience slow performance when you copy data to a TCP server.
    experience slow performance when you copy data to a TCP server.
@@ -522,7 +495,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
         conn->ip_version = CURL_IPRESOLVE_V6;
         conn->ip_version = CURL_IPRESOLVE_V6;
 #endif
 #endif
 
 
-      rc = Curl_resolv(data, dev, 0, FALSE, &h);
+      rc = Curl_resolv(data, dev, 80, FALSE, &h);
       if(rc == CURLRESOLV_PENDING)
       if(rc == CURLRESOLV_PENDING)
         (void)Curl_resolver_wait_resolv(data, &h);
         (void)Curl_resolver_wait_resolv(data, &h);
       conn->ip_version = ipver;
       conn->ip_version = ipver;
@@ -1084,6 +1057,11 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
     if(result)
     if(result)
       goto out;
       goto out;
 
 
+    if(cf->connected) {
+      *done = TRUE;
+      return CURLE_OK;
+    }
+
     /* Connect TCP socket */
     /* Connect TCP socket */
     rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
     rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
     if(-1 == rc) {
     if(-1 == rc) {
@@ -1449,22 +1427,6 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
   case CF_CTRL_CONN_INFO_UPDATE:
   case CF_CTRL_CONN_INFO_UPDATE:
     cf_socket_active(cf, data);
     cf_socket_active(cf, data);
     break;
     break;
-  case CF_CTRL_CONN_REPORT_STATS:
-    switch(ctx->transport) {
-    case TRNSPRT_UDP:
-    case TRNSPRT_QUIC:
-      /* Since UDP connected sockets work different from TCP, we use the
-       * time of the first byte from the peer as the "connect" time. */
-      if(ctx->got_first_byte) {
-        Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at);
-        break;
-      }
-      /* FALLTHROUGH */
-    default:
-      Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->connected_at);
-      break;
-    }
-    break;
   case CF_CTRL_DATA_SETUP:
   case CF_CTRL_DATA_SETUP:
     Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
     Curl_persistconninfo(data, cf->conn, ctx->l_ip, ctx->l_port);
     break;
     break;
@@ -1473,38 +1435,39 @@ static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
 }
 }
 
 
 static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
 static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
-                                    struct Curl_easy *data)
+                                    struct Curl_easy *data,
+                                    bool *input_pending)
 {
 {
   struct cf_socket_ctx *ctx = cf->ctx;
   struct cf_socket_ctx *ctx = cf->ctx;
-  int sval;
+  struct pollfd pfd[1];
+  int r;
 
 
+  *input_pending = FALSE;
   (void)data;
   (void)data;
   if(!ctx || ctx->sock == CURL_SOCKET_BAD)
   if(!ctx || ctx->sock == CURL_SOCKET_BAD)
     return FALSE;
     return FALSE;
 
 
-  sval = SOCKET_READABLE(ctx->sock, 0);
-  if(sval == 0) {
-    /* timeout */
-    return TRUE;
-  }
-  else if(sval & CURL_CSELECT_ERR) {
-    /* socket is in an error state */
+  /* Check with 0 timeout if there are any events pending on the socket */
+  pfd[0].fd = ctx->sock;
+  pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+  pfd[0].revents = 0;
+
+  r = Curl_poll(pfd, 1, 0);
+  if(r < 0) {
+    DEBUGF(LOG_CF(data, cf, "is_alive: poll error, assume dead"));
     return FALSE;
     return FALSE;
   }
   }
-  else if(sval & CURL_CSELECT_IN) {
-    /* readable with no error. could still be closed */
-/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
-#ifdef MSG_PEEK
-    /* use the socket */
-    char buf;
-    if(recv((RECV_TYPE_ARG1)ctx->sock, (RECV_TYPE_ARG2)&buf,
-            (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
-      return FALSE;   /* FIN received */
-    }
-#endif
+  else if(r == 0) {
+    DEBUGF(LOG_CF(data, cf, "is_alive: poll timeout, assume alive"));
     return TRUE;
     return TRUE;
   }
   }
+  else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
+    DEBUGF(LOG_CF(data, cf, "is_alive: err/hup/etc events, assume dead"));
+    return FALSE;
+  }
 
 
+  DEBUGF(LOG_CF(data, cf, "is_alive: valid events, looks alive"));
+  *input_pending = TRUE;
   return TRUE;
   return TRUE;
 }
 }
 
 
@@ -1527,6 +1490,24 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
     else
     else
       *pres1 = -1;
       *pres1 = -1;
     return CURLE_OK;
     return CURLE_OK;
+  case CF_QUERY_TIMER_CONNECT: {
+    struct curltime *when = pres2;
+    switch(ctx->transport) {
+    case TRNSPRT_UDP:
+    case TRNSPRT_QUIC:
+      /* Since UDP connected sockets work different from TCP, we use the
+       * time of the first byte from the peer as the "connect" time. */
+      if(ctx->got_first_byte) {
+        *when = ctx->first_byte_at;
+        break;
+      }
+      /* FALLTHROUGH */
+    default:
+      *when = ctx->connected_at;
+      break;
+    }
+    return CURLE_OK;
+  }
   default:
   default:
     break;
     break;
   }
   }
@@ -1826,7 +1807,6 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
   Curl_conn_cf_add(data, conn, sockindex, cf);
   Curl_conn_cf_add(data, conn, sockindex, cf);
 
 
   conn->sock[sockindex] = ctx->sock;
   conn->sock[sockindex] = ctx->sock;
-  set_remote_ip(cf, data);
   set_local_ip(cf, data);
   set_local_ip(cf, data);
   ctx->active = TRUE;
   ctx->active = TRUE;
   ctx->connected_at = Curl_now();
   ctx->connected_at = Curl_now();
@@ -1841,6 +1821,38 @@ out:
   return result;
   return result;
 }
 }
 
 
+static void set_accepted_remote_ip(struct Curl_cfilter *cf,
+                                   struct Curl_easy *data)
+{
+  struct cf_socket_ctx *ctx = cf->ctx;
+#ifdef HAVE_GETPEERNAME
+  char buffer[STRERROR_LEN];
+  struct Curl_sockaddr_storage ssrem;
+  curl_socklen_t plen;
+
+  ctx->r_ip[0] = 0;
+  ctx->r_port = 0;
+  plen = sizeof(ssrem);
+  memset(&ssrem, 0, plen);
+  if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
+    int error = SOCKERRNO;
+    failf(data, "getpeername() failed with errno %d: %s",
+          error, Curl_strerror(error, buffer, sizeof(buffer)));
+    return;
+  }
+  if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
+                       ctx->r_ip, &ctx->r_port)) {
+    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
+          errno, Curl_strerror(errno, buffer, sizeof(buffer)));
+    return;
+  }
+#else
+  ctx->r_ip[0] = 0;
+  ctx->r_port = 0;
+  (void)data;
+#endif
+}
+
 CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
 CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     struct connectdata *conn,
                                     int sockindex, curl_socket_t *s)
                                     int sockindex, curl_socket_t *s)
@@ -1857,13 +1869,14 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
   socket_close(data, conn, TRUE, ctx->sock);
   socket_close(data, conn, TRUE, ctx->sock);
   ctx->sock = *s;
   ctx->sock = *s;
   conn->sock[sockindex] = ctx->sock;
   conn->sock[sockindex] = ctx->sock;
-  set_remote_ip(cf, data);
+  set_accepted_remote_ip(cf, data);
   set_local_ip(cf, data);
   set_local_ip(cf, data);
   ctx->active = TRUE;
   ctx->active = TRUE;
   ctx->accepted = TRUE;
   ctx->accepted = TRUE;
   ctx->connected_at = Curl_now();
   ctx->connected_at = Curl_now();
   cf->connected = TRUE;
   cf->connected = TRUE;
-  DEBUGF(LOG_CF(data, cf, "Curl_conn_tcp_accepted_set(%d)", (int)ctx->sock));
+  DEBUGF(LOG_CF(data, cf, "accepted_set(sock=%d, remote=%s port=%d)",
+         (int)ctx->sock, ctx->r_ip, ctx->r_port));
 
 
   return CURLE_OK;
   return CURLE_OK;
 }
 }

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

@@ -70,13 +70,6 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
 int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
 int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
                       curl_socket_t sock);
                       curl_socket_t sock);
 
 
-/*
- * This function should return TRUE if the socket is to be assumed to
- * be dead. Most commonly this happens when the server has closed the
- * connection due to inactivity.
- */
-bool Curl_socket_is_dead(curl_socket_t sock);
-
 /**
 /**
  * Determine the curl code for a socket connect() == -1 with errno.
  * Determine the curl code for a socket connect() == -1 with errno.
  */
  */

+ 28 - 8
Utilities/cmcurl/lib/cfilters.c

@@ -124,10 +124,11 @@ ssize_t  Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
 }
 }
 
 
 bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
 bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
-                               struct Curl_easy *data)
+                               struct Curl_easy *data,
+                               bool *input_pending)
 {
 {
   return cf->next?
   return cf->next?
-    cf->next->cft->is_alive(cf->next, data) :
+    cf->next->cft->is_alive(cf->next, data, input_pending) :
     FALSE; /* pessimistic in absence of data */
     FALSE; /* pessimistic in absence of data */
 }
 }
 
 
@@ -370,9 +371,12 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
     result = cf->cft->connect(cf, data, blocking, done);
     result = cf->cft->connect(cf, data, blocking, done);
     if(!result && *done) {
     if(!result && *done) {
       Curl_conn_ev_update_info(data, data->conn);
       Curl_conn_ev_update_info(data, data->conn);
-      Curl_conn_ev_report_stats(data, data->conn);
+      Curl_conn_report_connect_stats(data, data->conn);
       data->conn->keepalive = Curl_now();
       data->conn->keepalive = Curl_now();
     }
     }
+    else if(result) {
+      Curl_conn_report_connect_stats(data, data->conn);
+    }
   }
   }
 
 
   return result;
   return result;
@@ -608,16 +612,32 @@ void Curl_conn_ev_update_info(struct Curl_easy *data,
   cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
   cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
 }
 }
 
 
-void Curl_conn_ev_report_stats(struct Curl_easy *data,
-                               struct connectdata *conn)
+void Curl_conn_report_connect_stats(struct Curl_easy *data,
+                                    struct connectdata *conn)
 {
 {
-  cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_REPORT_STATS, 0, NULL);
+  struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
+  if(cf) {
+    struct curltime connected;
+    struct curltime appconnected;
+
+    memset(&connected, 0, sizeof(connected));
+    cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
+    if(connected.tv_sec || connected.tv_usec)
+      Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
+
+    memset(&appconnected, 0, sizeof(appconnected));
+    cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
+    if(appconnected.tv_sec || appconnected.tv_usec)
+      Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
+  }
 }
 }
 
 
-bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn)
+bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
+                        bool *input_pending)
 {
 {
   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
   struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
-  return cf && !cf->conn->bits.close && cf->cft->is_alive(cf, data);
+  return cf && !cf->conn->bits.close &&
+         cf->cft->is_alive(cf, data, input_pending);
 }
 }
 
 
 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
 CURLcode Curl_conn_keep_alive(struct Curl_easy *data,

+ 11 - 8
Utilities/cmcurl/lib/cfilters.h

@@ -85,7 +85,8 @@ typedef ssize_t  Curl_cft_recv(struct Curl_cfilter *cf,
                                CURLcode *err);         /* error to return */
                                CURLcode *err);         /* error to return */
 
 
 typedef bool     Curl_cft_conn_is_alive(struct Curl_cfilter *cf,
 typedef bool     Curl_cft_conn_is_alive(struct Curl_cfilter *cf,
-                                        struct Curl_easy *data);
+                                        struct Curl_easy *data,
+                                        bool *input_pending);
 
 
 typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
 typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
                                           struct Curl_easy *data);
                                           struct Curl_easy *data);
@@ -109,8 +110,6 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
 #define CF_CTRL_DATA_DONE_SEND        8  /* 0          NULL     ignored */
 #define CF_CTRL_DATA_DONE_SEND        8  /* 0          NULL     ignored */
 /* update conn info at connection and data */
 /* update conn info at connection and data */
 #define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0          NULL     ignored */
 #define CF_CTRL_CONN_INFO_UPDATE (256+0) /* 0          NULL     ignored */
-/* report conn statistics (timers) for connection and data */
-#define CF_CTRL_CONN_REPORT_STATS (256+1) /* 0         NULL     ignored */
 
 
 /**
 /**
  * Handle event/control for the filter.
  * Handle event/control for the filter.
@@ -138,6 +137,8 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
 #define CF_QUERY_MAX_CONCURRENT     1  /* number     -        */
 #define CF_QUERY_MAX_CONCURRENT     1  /* number     -        */
 #define CF_QUERY_CONNECT_REPLY_MS   2  /* number     -        */
 #define CF_QUERY_CONNECT_REPLY_MS   2  /* number     -        */
 #define CF_QUERY_SOCKET             3  /* -          curl_socket_t */
 #define CF_QUERY_SOCKET             3  /* -          curl_socket_t */
+#define CF_QUERY_TIMER_CONNECT      4  /* -          struct curltime */
+#define CF_QUERY_TIMER_APPCONNECT   5  /* -          struct curltime */
 
 
 /**
 /**
  * Query the cfilter for properties. Filters ignorant of a query will
  * Query the cfilter for properties. Filters ignorant of a query will
@@ -216,7 +217,8 @@ CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
                                 struct Curl_easy *data,
                                 struct Curl_easy *data,
                                 int event, int arg1, void *arg2);
                                 int event, int arg1, void *arg2);
 bool     Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
 bool     Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
-                                   struct Curl_easy *data);
+                                   struct Curl_easy *data,
+                                   bool *input_pending);
 CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
 CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
                                      struct Curl_easy *data);
                                      struct Curl_easy *data);
 CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
 CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
@@ -435,15 +437,16 @@ void Curl_conn_ev_update_info(struct Curl_easy *data,
                               struct connectdata *conn);
                               struct connectdata *conn);
 
 
 /**
 /**
- * Inform connection filters to report statistics.
+ * Update connection statistics
  */
  */
-void Curl_conn_ev_report_stats(struct Curl_easy *data,
-                               struct connectdata *conn);
+void Curl_conn_report_connect_stats(struct Curl_easy *data,
+                                    struct connectdata *conn);
 
 
 /**
 /**
  * Check if FIRSTSOCKET's cfilter chain deems connection alive.
  * Check if FIRSTSOCKET's cfilter chain deems connection alive.
  */
  */
-bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn);
+bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
+                        bool *input_pending);
 
 
 /**
 /**
  * Try to upkeep the connection filters at sockindex.
  * Try to upkeep the connection filters at sockindex.

+ 1 - 13
Utilities/cmcurl/lib/conncache.c

@@ -45,13 +45,6 @@
 
 
 #define HASHKEY_SIZE 128
 #define HASHKEY_SIZE 128
 
 
-static void conn_llist_dtor(void *user, void *element)
-{
-  struct connectdata *conn = element;
-  (void)user;
-  conn->bundle = NULL;
-}
-
 static CURLcode bundle_create(struct connectbundle **bundlep)
 static CURLcode bundle_create(struct connectbundle **bundlep)
 {
 {
   DEBUGASSERT(*bundlep == NULL);
   DEBUGASSERT(*bundlep == NULL);
@@ -62,17 +55,12 @@ static CURLcode bundle_create(struct connectbundle **bundlep)
   (*bundlep)->num_connections = 0;
   (*bundlep)->num_connections = 0;
   (*bundlep)->multiuse = BUNDLE_UNKNOWN;
   (*bundlep)->multiuse = BUNDLE_UNKNOWN;
 
 
-  Curl_llist_init(&(*bundlep)->conn_list, (Curl_llist_dtor) conn_llist_dtor);
+  Curl_llist_init(&(*bundlep)->conn_list, NULL);
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
 static void bundle_destroy(struct connectbundle *bundle)
 static void bundle_destroy(struct connectbundle *bundle)
 {
 {
-  if(!bundle)
-    return;
-
-  Curl_llist_destroy(&bundle->conn_list, NULL);
-
   free(bundle);
   free(bundle);
 }
 }
 
 

+ 33 - 2
Utilities/cmcurl/lib/connect.c

@@ -59,7 +59,7 @@
 #include "strerror.h"
 #include "strerror.h"
 #include "cfilters.h"
 #include "cfilters.h"
 #include "connect.h"
 #include "connect.h"
-#include "cf-http.h"
+#include "cf-https-connect.h"
 #include "cf-socket.h"
 #include "cf-socket.h"
 #include "select.h"
 #include "select.h"
 #include "url.h" /* for Curl_safefree() */
 #include "url.h" /* for Curl_safefree() */
@@ -957,6 +957,28 @@ static bool cf_he_data_pending(struct Curl_cfilter *cf,
   return FALSE;
   return FALSE;
 }
 }
 
 
+static struct curltime get_max_baller_time(struct Curl_cfilter *cf,
+                                          struct Curl_easy *data,
+                                          int query)
+{
+  struct cf_he_ctx *ctx = cf->ctx;
+  struct curltime t, tmax;
+  size_t i;
+
+  memset(&tmax, 0, sizeof(tmax));
+  for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
+    struct eyeballer *baller = ctx->baller[i];
+
+    memset(&t, 0, sizeof(t));
+    if(baller && baller->cf &&
+       !baller->cf->cft->query(baller->cf, data, query, NULL, &t)) {
+      if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+        tmax = t;
+    }
+  }
+  return tmax;
+}
+
 static CURLcode cf_he_query(struct Curl_cfilter *cf,
 static CURLcode cf_he_query(struct Curl_cfilter *cf,
                             struct Curl_easy *data,
                             struct Curl_easy *data,
                             int query, int *pres1, void *pres2)
                             int query, int *pres1, void *pres2)
@@ -984,7 +1006,16 @@ static CURLcode cf_he_query(struct Curl_cfilter *cf,
       DEBUGF(LOG_CF(data, cf, "query connect reply: %dms", *pres1));
       DEBUGF(LOG_CF(data, cf, "query connect reply: %dms", *pres1));
       return CURLE_OK;
       return CURLE_OK;
     }
     }
-
+    case CF_QUERY_TIMER_CONNECT: {
+      struct curltime *when = pres2;
+      *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT);
+      return CURLE_OK;
+    }
+    case CF_QUERY_TIMER_APPCONNECT: {
+      struct curltime *when = pres2;
+      *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT);
+      return CURLE_OK;
+    }
     default:
     default:
       break;
       break;
     }
     }

+ 8 - 0
Utilities/cmcurl/lib/content_encoding.c

@@ -33,7 +33,15 @@
 #endif
 #endif
 
 
 #ifdef HAVE_BROTLI
 #ifdef HAVE_BROTLI
+#if defined(__GNUC__)
+/* Ignore -Wvla warnings in brotli headers */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wvla"
+#endif
 #include <brotli/decode.h>
 #include <brotli/decode.h>
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
 #endif
 #endif
 
 
 #ifdef HAVE_ZSTD
 #ifdef HAVE_ZSTD

+ 121 - 125
Utilities/cmcurl/lib/cookie.c

@@ -101,13 +101,14 @@ Example set of cookies:
 #include "parsedate.h"
 #include "parsedate.h"
 #include "rename.h"
 #include "rename.h"
 #include "fopen.h"
 #include "fopen.h"
+#include "strdup.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 #include "memdebug.h"
 
 
-static void strstore(char **str, const char *newstr);
+static void strstore(char **str, const char *newstr, size_t len);
 
 
 static void freecookie(struct Cookie *co)
 static void freecookie(struct Cookie *co)
 {
 {
@@ -122,15 +123,17 @@ static void freecookie(struct Cookie *co)
   free(co);
   free(co);
 }
 }
 
 
-static bool tailmatch(const char *cooke_domain, const char *hostname)
+static bool tailmatch(const char *cookie_domain, size_t cookie_domain_len,
+                      const char *hostname)
 {
 {
-  size_t cookie_domain_len = strlen(cooke_domain);
   size_t hostname_len = strlen(hostname);
   size_t hostname_len = strlen(hostname);
 
 
   if(hostname_len < cookie_domain_len)
   if(hostname_len < cookie_domain_len)
     return FALSE;
     return FALSE;
 
 
-  if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
+  if(!strncasecompare(cookie_domain,
+                      hostname + hostname_len-cookie_domain_len,
+                      cookie_domain_len))
     return FALSE;
     return FALSE;
 
 
   /*
   /*
@@ -176,7 +179,7 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
 
 
   /* #-fragments are already cut off! */
   /* #-fragments are already cut off! */
   if(0 == strlen(uri_path) || uri_path[0] != '/') {
   if(0 == strlen(uri_path) || uri_path[0] != '/') {
-    strstore(&uri_path, "/");
+    strstore(&uri_path, "/", 1);
     if(!uri_path)
     if(!uri_path)
       return FALSE;
       return FALSE;
   }
   }
@@ -310,7 +313,7 @@ static char *sanitize_cookie_path(const char *cookie_path)
   /* RFC6265 5.2.4 The Path Attribute */
   /* RFC6265 5.2.4 The Path Attribute */
   if(new_path[0] != '/') {
   if(new_path[0] != '/') {
     /* Let cookie-path be the default-path. */
     /* Let cookie-path be the default-path. */
-    strstore(&new_path, "/");
+    strstore(&new_path, "/", 1);
     return new_path;
     return new_path;
   }
   }
 
 
@@ -333,10 +336,9 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
   if(list) {
   if(list) {
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
     while(list) {
     while(list) {
-      struct CookieInfo *newcookies = Curl_cookie_init(data,
-                                        list->data,
-                                        data->cookies,
-                                        data->set.cookiesession);
+      struct CookieInfo *newcookies =
+        Curl_cookie_init(data, list->data, data->cookies,
+                         data->set.cookiesession);
       if(!newcookies)
       if(!newcookies)
         /*
         /*
          * Failure may be due to OOM or a bad cookie; both are ignored
          * Failure may be due to OOM or a bad cookie; both are ignored
@@ -360,10 +362,14 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
  * parsing in a last-wins scenario. The caller is responsible for checking
  * parsing in a last-wins scenario. The caller is responsible for checking
  * for OOM errors.
  * for OOM errors.
  */
  */
-static void strstore(char **str, const char *newstr)
+static void strstore(char **str, const char *newstr, size_t len)
 {
 {
+  DEBUGASSERT(newstr);
+  DEBUGASSERT(str);
   free(*str);
   free(*str);
-  *str = strdup(newstr);
+  *str = Curl_memdup(newstr, len + 1);
+  if(*str)
+    (*str)[len] = 0;
 }
 }
 
 
 /*
 /*
@@ -425,15 +431,19 @@ static void remove_expired(struct CookieInfo *cookies)
 }
 }
 
 
 /* Make sure domain contains a dot or is localhost. */
 /* Make sure domain contains a dot or is localhost. */
-static bool bad_domain(const char *domain)
+static bool bad_domain(const char *domain, size_t len)
 {
 {
-  if(strcasecompare(domain, "localhost"))
+  if((len == 9) && strncasecompare(domain, "localhost", 9))
     return FALSE;
     return FALSE;
   else {
   else {
     /* there must be a dot present, but that dot must not be a trailing dot */
     /* there must be a dot present, but that dot must not be a trailing dot */
-    char *dot = strchr(domain, '.');
-    if(dot)
-      return dot[1] ? FALSE : TRUE;
+    char *dot = memchr(domain, '.', len);
+    if(dot) {
+      size_t i = dot - domain;
+      if((len - i) > 1)
+        /* the dot is not the last byte */
+        return FALSE;
+    }
   }
   }
   return TRUE;
   return TRUE;
 }
 }
@@ -513,10 +523,9 @@ Curl_cookie_add(struct Curl_easy *data,
 
 
   if(httpheader) {
   if(httpheader) {
     /* This line was read off an HTTP-header */
     /* This line was read off an HTTP-header */
-    char name[MAX_NAME];
-    char what[MAX_NAME];
+    const char *namep;
+    const char *valuep;
     const char *ptr;
     const char *ptr;
-    const char *semiptr;
 
 
     size_t linelength = strlen(lineptr);
     size_t linelength = strlen(lineptr);
     if(linelength > MAX_COOKIE_LINE) {
     if(linelength > MAX_COOKIE_LINE) {
@@ -525,73 +534,65 @@ Curl_cookie_add(struct Curl_easy *data,
       return NULL;
       return NULL;
     }
     }
 
 
-    semiptr = strchr(lineptr, ';'); /* first, find a semicolon */
-
-    while(*lineptr && ISBLANK(*lineptr))
-      lineptr++;
-
     ptr = lineptr;
     ptr = lineptr;
     do {
     do {
-      /* we have a <what>=<this> pair or a stand-alone word here */
-      name[0] = what[0] = 0; /* init the buffers */
-      if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\t\r\n=] =%"
-                     MAX_NAME_TXT "[^;\r\n]",
-                     name, what)) {
-        /*
-         * Use strstore() below to properly deal with received cookie
-         * headers that have the same string property set more than once,
-         * and then we use the last one.
-         */
-        const char *whatptr;
+      size_t vlen;
+      size_t nlen;
+
+      while(*ptr && ISBLANK(*ptr))
+        ptr++;
+
+      /* we have a <name>=<value> pair or a stand-alone word here */
+      nlen = strcspn(ptr, ";\t\r\n=");
+      if(nlen) {
         bool done = FALSE;
         bool done = FALSE;
-        bool sep;
-        size_t len = strlen(what);
-        size_t nlen = strlen(name);
-        const char *endofn = &ptr[ nlen ];
+        bool sep = FALSE;
 
 
-        /*
-         * Check for too long individual name or contents, or too long
-         * combination of name + contents. Chrome and Firefox support 4095 or
-         * 4096 bytes combo
-         */
-        if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
-           ((nlen + len) > MAX_NAME)) {
-          freecookie(co);
-          infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
-                nlen, len);
-          return NULL;
-        }
+        namep = ptr;
+        ptr += nlen;
 
 
-        /* name ends with a '=' ? */
-        sep = (*endofn == '=')?TRUE:FALSE;
+        /* trim trailing spaces and tabs after name */
+        while(nlen && ISBLANK(namep[nlen - 1]))
+          nlen--;
 
 
-        if(nlen) {
-          endofn--; /* move to the last character */
-          if(ISBLANK(*endofn)) {
-            /* skip trailing spaces in name */
-            while(*endofn && ISBLANK(*endofn) && nlen) {
-              endofn--;
-              nlen--;
-            }
-            name[nlen] = 0; /* new end of name */
+        if(*ptr == '=') {
+          vlen = strcspn(++ptr, ";\r\n");
+          valuep = ptr;
+          sep = TRUE;
+          ptr = &valuep[vlen];
+
+          /* Strip off trailing whitespace from the value */
+          while(vlen && ISBLANK(valuep[vlen-1]))
+            vlen--;
+
+          /* Skip leading whitespace from the value */
+          while(vlen && ISBLANK(*valuep)) {
+            valuep++;
+            vlen--;
           }
           }
-        }
 
 
-        /* Strip off trailing whitespace from the 'what' */
-        while(len && ISBLANK(what[len-1])) {
-          what[len-1] = 0;
-          len--;
+          /* Reject cookies with a TAB inside the value */
+          if(memchr(valuep, '\t', vlen)) {
+            freecookie(co);
+            infof(data, "cookie contains TAB, dropping");
+            return NULL;
+          }
+        }
+        else {
+          valuep = NULL;
+          vlen = 0;
         }
         }
 
 
-        /* Skip leading whitespace from the 'what' */
-        whatptr = what;
-        while(*whatptr && ISBLANK(*whatptr))
-          whatptr++;
-
-        /* Reject cookies with a TAB inside the content */
-        if(strchr(whatptr, '\t')) {
+        /*
+         * Check for too long individual name or contents, or too long
+         * combination of name + contents. Chrome and Firefox support 4095 or
+         * 4096 bytes combo
+         */
+        if(nlen >= (MAX_NAME-1) || vlen >= (MAX_NAME-1) ||
+           ((nlen + vlen) > MAX_NAME)) {
           freecookie(co);
           freecookie(co);
-          infof(data, "cookie contains TAB, dropping");
+          infof(data, "oversized cookie dropped, name/val %zu + %zu bytes",
+                nlen, vlen);
           return NULL;
           return NULL;
         }
         }
 
 
@@ -601,13 +602,19 @@ Curl_cookie_add(struct Curl_easy *data,
          * "the rest". Prefixes must start with '__' and end with a '-', so
          * "the rest". Prefixes must start with '__' and end with a '-', so
          * only test for names where that can possibly be true.
          * only test for names where that can possibly be true.
          */
          */
-        if(nlen > 3 && name[0] == '_' && name[1] == '_') {
-          if(strncasecompare("__Secure-", name, 9))
+        if(nlen >= 7 && namep[0] == '_' && namep[1] == '_') {
+          if(strncasecompare("__Secure-", namep, 9))
             co->prefix |= COOKIE_PREFIX__SECURE;
             co->prefix |= COOKIE_PREFIX__SECURE;
-          else if(strncasecompare("__Host-", name, 7))
+          else if(strncasecompare("__Host-", namep, 7))
             co->prefix |= COOKIE_PREFIX__HOST;
             co->prefix |= COOKIE_PREFIX__HOST;
         }
         }
 
 
+        /*
+         * Use strstore() below to properly deal with received cookie
+         * headers that have the same string property set more than once,
+         * and then we use the last one.
+         */
+
         if(!co->name) {
         if(!co->name) {
           /* The very first name/value pair is the actual cookie name */
           /* The very first name/value pair is the actual cookie name */
           if(!sep) {
           if(!sep) {
@@ -615,20 +622,20 @@ Curl_cookie_add(struct Curl_easy *data,
             badcookie = TRUE;
             badcookie = TRUE;
             break;
             break;
           }
           }
-          co->name = strdup(name);
-          co->value = strdup(whatptr);
+          strstore(&co->name, namep, nlen);
+          strstore(&co->value, valuep, vlen);
           done = TRUE;
           done = TRUE;
           if(!co->name || !co->value) {
           if(!co->name || !co->value) {
             badcookie = TRUE;
             badcookie = TRUE;
             break;
             break;
           }
           }
-          if(invalid_octets(whatptr) || invalid_octets(name)) {
+          if(invalid_octets(co->value) || invalid_octets(co->name)) {
             infof(data, "invalid octets in name/value, cookie dropped");
             infof(data, "invalid octets in name/value, cookie dropped");
             badcookie = TRUE;
             badcookie = TRUE;
             break;
             break;
           }
           }
         }
         }
-        else if(!len) {
+        else if(!vlen) {
           /*
           /*
            * this was a "<name>=" with no content, and we must allow
            * this was a "<name>=" with no content, and we must allow
            * 'secure' and 'httponly' specified this weirdly
            * 'secure' and 'httponly' specified this weirdly
@@ -639,7 +646,7 @@ Curl_cookie_add(struct Curl_easy *data,
            * using a secure protocol, or when the cookie is being set by
            * using a secure protocol, or when the cookie is being set by
            * reading from file
            * reading from file
            */
            */
-          if(strcasecompare("secure", name)) {
+          if((nlen == 6) && strncasecompare("secure", namep, 6)) {
             if(secure || !c->running) {
             if(secure || !c->running) {
               co->secure = TRUE;
               co->secure = TRUE;
             }
             }
@@ -648,7 +655,7 @@ Curl_cookie_add(struct Curl_easy *data,
               break;
               break;
             }
             }
           }
           }
-          else if(strcasecompare("httponly", name))
+          else if((nlen == 8) && strncasecompare("httponly", namep, 8))
             co->httponly = TRUE;
             co->httponly = TRUE;
           else if(sep)
           else if(sep)
             /* there was a '=' so we're not done parsing this field */
             /* there was a '=' so we're not done parsing this field */
@@ -656,8 +663,8 @@ Curl_cookie_add(struct Curl_easy *data,
         }
         }
         if(done)
         if(done)
           ;
           ;
-        else if(strcasecompare("path", name)) {
-          strstore(&co->path, whatptr);
+        else if((nlen == 4) && strncasecompare("path", namep, 4)) {
+          strstore(&co->path, valuep, vlen);
           if(!co->path) {
           if(!co->path) {
             badcookie = TRUE; /* out of memory bad */
             badcookie = TRUE; /* out of memory bad */
             break;
             break;
@@ -669,7 +676,8 @@ Curl_cookie_add(struct Curl_easy *data,
             break;
             break;
           }
           }
         }
         }
-        else if(strcasecompare("domain", name) && whatptr[0]) {
+        else if((nlen == 6) &&
+                strncasecompare("domain", namep, 6) && vlen) {
           bool is_ip;
           bool is_ip;
 
 
           /*
           /*
@@ -677,8 +685,10 @@ Curl_cookie_add(struct Curl_easy *data,
            * the given domain is not valid and thus cannot be set.
            * the given domain is not valid and thus cannot be set.
            */
            */
 
 
-          if('.' == whatptr[0])
-            whatptr++; /* ignore preceding dot */
+          if('.' == valuep[0]) {
+            valuep++; /* ignore preceding dot */
+            vlen--;
+          }
 
 
 #ifndef USE_LIBPSL
 #ifndef USE_LIBPSL
           /*
           /*
@@ -686,16 +696,17 @@ Curl_cookie_add(struct Curl_easy *data,
            * TLD or otherwise "protected" suffix. To reduce risk, we require a
            * TLD or otherwise "protected" suffix. To reduce risk, we require a
            * dot OR the exact host name being "localhost".
            * dot OR the exact host name being "localhost".
            */
            */
-          if(bad_domain(whatptr))
+          if(bad_domain(valuep, vlen))
             domain = ":";
             domain = ":";
 #endif
 #endif
 
 
-          is_ip = Curl_host_is_ipnum(domain ? domain : whatptr);
+          is_ip = Curl_host_is_ipnum(domain ? domain : valuep);
 
 
           if(!domain
           if(!domain
-             || (is_ip && !strcmp(whatptr, domain))
-             || (!is_ip && tailmatch(whatptr, domain))) {
-            strstore(&co->domain, whatptr);
+             || (is_ip && !strncmp(valuep, domain, vlen) &&
+                 (vlen == strlen(domain)))
+             || (!is_ip && tailmatch(valuep, vlen, domain))) {
+            strstore(&co->domain, valuep, vlen);
             if(!co->domain) {
             if(!co->domain) {
               badcookie = TRUE;
               badcookie = TRUE;
               break;
               break;
@@ -711,17 +722,17 @@ Curl_cookie_add(struct Curl_easy *data,
              */
              */
             badcookie = TRUE;
             badcookie = TRUE;
             infof(data, "skipped cookie with bad tailmatch domain: %s",
             infof(data, "skipped cookie with bad tailmatch domain: %s",
-                  whatptr);
+                  valuep);
           }
           }
         }
         }
-        else if(strcasecompare("version", name)) {
-          strstore(&co->version, whatptr);
+        else if((nlen == 7) && strncasecompare("version", namep, 7)) {
+          strstore(&co->version, valuep, vlen);
           if(!co->version) {
           if(!co->version) {
             badcookie = TRUE;
             badcookie = TRUE;
             break;
             break;
           }
           }
         }
         }
-        else if(strcasecompare("max-age", name)) {
+        else if((nlen == 7) && strncasecompare("max-age", namep, 7)) {
           /*
           /*
            * Defined in RFC2109:
            * Defined in RFC2109:
            *
            *
@@ -731,14 +742,14 @@ Curl_cookie_add(struct Curl_easy *data,
            * client should discard the cookie.  A value of zero means the
            * client should discard the cookie.  A value of zero means the
            * cookie should be discarded immediately.
            * cookie should be discarded immediately.
            */
            */
-          strstore(&co->maxage, whatptr);
+          strstore(&co->maxage, valuep, vlen);
           if(!co->maxage) {
           if(!co->maxage) {
             badcookie = TRUE;
             badcookie = TRUE;
             break;
             break;
           }
           }
         }
         }
-        else if(strcasecompare("expires", name)) {
-          strstore(&co->expirestr, whatptr);
+        else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
+          strstore(&co->expirestr, valuep, vlen);
           if(!co->expirestr) {
           if(!co->expirestr) {
             badcookie = TRUE;
             badcookie = TRUE;
             break;
             break;
@@ -753,24 +764,13 @@ Curl_cookie_add(struct Curl_easy *data,
         /* this is an "illegal" <what>=<this> pair */
         /* this is an "illegal" <what>=<this> pair */
       }
       }
 
 
-      if(!semiptr || !*semiptr) {
-        /* we already know there are no more cookies */
-        semiptr = NULL;
-        continue;
-      }
-
-      ptr = semiptr + 1;
       while(*ptr && ISBLANK(*ptr))
       while(*ptr && ISBLANK(*ptr))
         ptr++;
         ptr++;
-      semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
-
-      if(!semiptr && *ptr)
-        /*
-         * There are no more semicolons, but there's a final name=value pair
-         * coming up
-         */
-        semiptr = strchr(ptr, '\0');
-    } while(semiptr);
+      if(*ptr == ';')
+        ptr++;
+      else
+        break;
+    } while(1);
 
 
     if(co->maxage) {
     if(co->maxage) {
       CURLofft offt;
       CURLofft offt;
@@ -1057,7 +1057,7 @@ Curl_cookie_add(struct Curl_easy *data,
       Curl_psl_release(data);
       Curl_psl_release(data);
     }
     }
     else
     else
-      acceptable = !bad_domain(domain);
+      acceptable = !bad_domain(domain, strlen(domain));
 
 
     if(!acceptable) {
     if(!acceptable) {
       infof(data, "cookie '%s' dropped, domain '%s' must not "
       infof(data, "cookie '%s' dropped, domain '%s' must not "
@@ -1447,7 +1447,8 @@ struct Cookie *Curl_cookie_getlist(struct Curl_easy *data,
 
 
       /* now check if the domain is correct */
       /* now check if the domain is correct */
       if(!co->domain ||
       if(!co->domain ||
-         (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
+         (co->tailmatch && !is_ip &&
+          tailmatch(co->domain, co->domain? strlen(co->domain):0, host)) ||
          ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
          ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
         /*
         /*
          * the right part of the host matches the domain stuff in the
          * the right part of the host matches the domain stuff in the
@@ -1798,11 +1799,6 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
   CURLcode res;
   CURLcode res;
 
 
   if(data->set.str[STRING_COOKIEJAR]) {
   if(data->set.str[STRING_COOKIEJAR]) {
-    /* If there is a list of cookie files to read, do it first so that
-       we have all the told files read before we write the new jar.
-       Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
-    Curl_cookie_loadfiles(data);
-
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
 
 
     /* if we have a destination file for all the cookies to get dumped to */
     /* if we have a destination file for all the cookies to get dumped to */

+ 8 - 2
Utilities/cmcurl/lib/curl_gssapi.c

@@ -34,10 +34,16 @@
 #include "curl_memory.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 #include "memdebug.h"
 
 
-gss_OID_desc Curl_spnego_mech_oid = {
+#if defined(__GNUC__)
+#define CURL_ALIGN8   __attribute__ ((aligned(8)))
+#else
+#define CURL_ALIGN8
+#endif
+
+gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = {
   6, (char *)"\x2b\x06\x01\x05\x05\x02"
   6, (char *)"\x2b\x06\x01\x05\x05\x02"
 };
 };
-gss_OID_desc Curl_krb5_mech_oid = {
+gss_OID_desc Curl_krb5_mech_oid CURL_ALIGN8 = {
   9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
   9, (char *)"\x2a\x86\x48\x86\xf7\x12\x01\x02\x02"
 };
 };
 
 

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

@@ -38,7 +38,7 @@
 #include "connect.h"
 #include "connect.h"
 #include "http2.h"
 #include "http2.h"
 #include "http_proxy.h"
 #include "http_proxy.h"
-#include "cf-http.h"
+#include "cf-https-connect.h"
 #include "socks.h"
 #include "socks.h"
 #include "strtok.h"
 #include "strtok.h"
 #include "vtls/vtls.h"
 #include "vtls/vtls.h"

+ 35 - 40
Utilities/cmcurl/lib/curl_path.c

@@ -32,70 +32,65 @@
 #include "escape.h"
 #include "escape.h"
 #include "memdebug.h"
 #include "memdebug.h"
 
 
+#define MAX_SSHPATH_LEN 100000 /* arbitrary */
+
 /* figure out the path to work with in this particular request */
 /* figure out the path to work with in this particular request */
 CURLcode Curl_getworkingpath(struct Curl_easy *data,
 CURLcode Curl_getworkingpath(struct Curl_easy *data,
                              char *homedir,  /* when SFTP is used */
                              char *homedir,  /* when SFTP is used */
                              char **path) /* returns the  allocated
                              char **path) /* returns the  allocated
                                              real path to work with */
                                              real path to work with */
 {
 {
-  char *real_path = NULL;
   char *working_path;
   char *working_path;
   size_t working_path_len;
   size_t working_path_len;
+  struct dynbuf npath;
   CURLcode result =
   CURLcode result =
     Curl_urldecode(data->state.up.path, 0, &working_path,
     Curl_urldecode(data->state.up.path, 0, &working_path,
                    &working_path_len, REJECT_ZERO);
                    &working_path_len, REJECT_ZERO);
   if(result)
   if(result)
     return result;
     return result;
 
 
+  /* new path to switch to in case we need to */
+  Curl_dyn_init(&npath, MAX_SSHPATH_LEN);
+
   /* Check for /~/, indicating relative to the user's home directory */
   /* Check for /~/, indicating relative to the user's home directory */
-  if(data->conn->handler->protocol & CURLPROTO_SCP) {
-    real_path = malloc(working_path_len + 1);
-    if(!real_path) {
+  if((data->conn->handler->protocol & CURLPROTO_SCP) &&
+     (working_path_len > 3) && (!memcmp(working_path, "/~/", 3))) {
+    /* It is referenced to the home directory, so strip the leading '/~/' */
+    if(Curl_dyn_addn(&npath, &working_path[3], working_path_len - 3)) {
       free(working_path);
       free(working_path);
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
-    if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
-      /* It is referenced to the home directory, so strip the leading '/~/' */
-      memcpy(real_path, working_path + 3, working_path_len - 2);
-    else
-      memcpy(real_path, working_path, 1 + working_path_len);
   }
   }
-  else if(data->conn->handler->protocol & CURLPROTO_SFTP) {
-    if((working_path_len > 1) && (working_path[1] == '~')) {
-      size_t homelen = strlen(homedir);
-      real_path = malloc(homelen + working_path_len + 1);
-      if(!real_path) {
-        free(working_path);
-        return CURLE_OUT_OF_MEMORY;
-      }
-      /* It is referenced to the home directory, so strip the
-         leading '/' */
-      memcpy(real_path, homedir, homelen);
-      /* Only add a trailing '/' if homedir does not end with one */
-      if(homelen == 0 || real_path[homelen - 1] != '/') {
-        real_path[homelen] = '/';
-        homelen++;
-        real_path[homelen] = '\0';
-      }
-      if(working_path_len > 3) {
-        memcpy(real_path + homelen, working_path + 3,
-               1 + working_path_len -3);
-      }
+  else if((data->conn->handler->protocol & CURLPROTO_SFTP) &&
+          (working_path_len > 2) && !memcmp(working_path, "/~/", 3)) {
+    size_t len;
+    const char *p;
+    int copyfrom = 3;
+    if(Curl_dyn_add(&npath, homedir)) {
+      free(working_path);
+      return CURLE_OUT_OF_MEMORY;
     }
     }
-    else {
-      real_path = malloc(working_path_len + 1);
-      if(!real_path) {
-        free(working_path);
-        return CURLE_OUT_OF_MEMORY;
-      }
-      memcpy(real_path, working_path, 1 + working_path_len);
+    /* Copy a separating '/' if homedir does not end with one */
+    len = Curl_dyn_len(&npath);
+    p = Curl_dyn_ptr(&npath);
+    if(len && (p[len-1] != '/'))
+      copyfrom = 2;
+
+    if(Curl_dyn_addn(&npath,
+                     &working_path[copyfrom], working_path_len - copyfrom)) {
+      free(working_path);
+      return CURLE_OUT_OF_MEMORY;
     }
     }
   }
   }
 
 
-  free(working_path);
+  if(Curl_dyn_len(&npath)) {
+    free(working_path);
 
 
-  /* store the pointer for the caller to receive */
-  *path = real_path;
+    /* store the pointer for the caller to receive */
+    *path = Curl_dyn_ptr(&npath);
+  }
+  else
+    *path = working_path;
 
 
   return CURLE_OK;
   return CURLE_OK;
 }
 }

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

@@ -456,8 +456,8 @@
 #  endif
 #  endif
 #endif
 #endif
 
 
-#if (SIZEOF_CURL_OFF_T == 4)
-#  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
+#if (SIZEOF_CURL_OFF_T < 8)
+#error "too small curl_off_t"
 #else
 #else
    /* assume SIZEOF_CURL_OFF_T == 8 */
    /* assume SIZEOF_CURL_OFF_T == 8 */
 #  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
 #  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)

+ 8 - 0
Utilities/cmcurl/lib/curl_setup_once.h

@@ -69,6 +69,14 @@
 #include <unistd.h>
 #include <unistd.h>
 #endif
 #endif
 
 
+#ifdef USE_WOLFSSL
+#  if defined(HAVE_STDINT_H)
+#    include <stdint.h>
+#  elif defined(HAVE_INTTYPES_H)
+#    include <inttypes.h>
+#  endif
+#endif
+
 #ifdef __hpux
 #ifdef __hpux
 #  if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
 #  if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
 #    ifdef _APP32_64BIT_OFF_T
 #    ifdef _APP32_64BIT_OFF_T

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

@@ -952,7 +952,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
 
       /* we got a response, store it in the cache */
       /* we got a response, store it in the cache */
-      dns = Curl_cache_addr(data, ai, dohp->host, dohp->port);
+      dns = Curl_cache_addr(data, ai, dohp->host, 0, dohp->port);
 
 
       if(data->share)
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

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

@@ -99,8 +99,7 @@ static CURLcode dyn_nappend(struct dynbuf *s,
        include that as well when it uses this code */
        include that as well when it uses this code */
     void *p = realloc(s->bufr, a);
     void *p = realloc(s->bufr, a);
     if(!p) {
     if(!p) {
-      Curl_safefree(s->bufr);
-      s->leng = s->allc = 0;
+      Curl_dyn_free(s);
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
     s->bufr = p;
     s->bufr = p;

+ 0 - 1
Utilities/cmcurl/lib/easy.c

@@ -1228,7 +1228,6 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
     return result;
     return result;
 
 
   *n = (size_t)n1;
   *n = (size_t)n1;
-  infof(data, "reached %s:%d", __FILE__, __LINE__);
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 

+ 109 - 45
Utilities/cmcurl/lib/ftp.c

@@ -436,6 +436,12 @@ static CURLcode InitiateTransfer(struct Curl_easy *data)
   bool connected;
   bool connected;
 
 
   DEBUGF(infof(data, "ftp InitiateTransfer()"));
   DEBUGF(infof(data, "ftp InitiateTransfer()"));
+  if(conn->bits.ftp_use_data_ssl && data->set.ftp_use_port &&
+     !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) {
+    result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET);
+    if(result)
+      return result;
+  }
   result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected);
   result = Curl_conn_connect(data, SECONDARYSOCKET, TRUE, &connected);
   if(result || !connected)
   if(result || !connected)
     return result;
     return result;
@@ -1795,6 +1801,29 @@ static char *control_address(struct connectdata *conn)
   return conn->primary_ip;
   return conn->primary_ip;
 }
 }
 
 
+static bool match_pasv_6nums(const char *p,
+                             unsigned int *array) /* 6 numbers */
+{
+  int i;
+  for(i = 0; i < 6; i++) {
+    unsigned long num;
+    char *endp;
+    if(i) {
+      if(*p != ',')
+        return FALSE;
+      p++;
+    }
+    if(!ISDIGIT(*p))
+      return FALSE;
+    num = strtoul(p, &endp, 10);
+    if(num > 255)
+      return FALSE;
+    array[i] = (unsigned int)num;
+    p = endp;
+  }
+  return TRUE;
+}
+
 static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
 static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
                                     int ftpcode)
                                     int ftpcode)
 {
 {
@@ -1814,27 +1843,18 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     /* positive EPSV response */
     /* positive EPSV response */
     char *ptr = strchr(str, '(');
     char *ptr = strchr(str, '(');
     if(ptr) {
     if(ptr) {
-      unsigned int num;
-      char separator[4];
+      char sep;
       ptr++;
       ptr++;
-      if(5 == sscanf(ptr, "%c%c%c%u%c",
-                     &separator[0],
-                     &separator[1],
-                     &separator[2],
-                     &num,
-                     &separator[3])) {
-        const char sep1 = separator[0];
-        int i;
-
-        /* The four separators should be identical, or else this is an oddly
-           formatted reply and we bail out immediately. */
-        for(i = 1; i<4; i++) {
-          if(separator[i] != sep1) {
-            ptr = NULL; /* set to NULL to signal error */
-            break;
-          }
-        }
-        if(num > 0xffff) {
+      /* |||12345| */
+      sep = ptr[0];
+      /* the ISDIGIT() check here is because strtoul() accepts leading minus
+         etc */
+      if((ptr[1] == sep) && (ptr[2] == sep) && ISDIGIT(ptr[3])) {
+        char *endp;
+        unsigned long num = strtoul(&ptr[3], &endp, 10);
+        if(*endp != sep)
+          ptr = NULL;
+        else if(num > 0xffff) {
           failf(data, "Illegal port number in EPSV reply");
           failf(data, "Illegal port number in EPSV reply");
           return CURLE_FTP_WEIRD_PASV_REPLY;
           return CURLE_FTP_WEIRD_PASV_REPLY;
         }
         }
@@ -1856,8 +1876,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
   else if((ftpc->count1 == 1) &&
   else if((ftpc->count1 == 1) &&
           (ftpcode == 227)) {
           (ftpcode == 227)) {
     /* positive PASV response */
     /* positive PASV response */
-    unsigned int ip[4] = {0, 0, 0, 0};
-    unsigned int port[2] = {0, 0};
+    unsigned int ip[6];
 
 
     /*
     /*
      * Scan for a sequence of six comma-separated numbers and use them as
      * Scan for a sequence of six comma-separated numbers and use them as
@@ -1869,15 +1888,12 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
      * "227 Entering passive mode. 127,0,0,1,4,51"
      * "227 Entering passive mode. 127,0,0,1,4,51"
      */
      */
     while(*str) {
     while(*str) {
-      if(6 == sscanf(str, "%u,%u,%u,%u,%u,%u",
-                     &ip[0], &ip[1], &ip[2], &ip[3],
-                     &port[0], &port[1]))
+      if(match_pasv_6nums(str, ip))
         break;
         break;
       str++;
       str++;
     }
     }
 
 
-    if(!*str || (ip[0] > 255) || (ip[1] > 255)  || (ip[2] > 255)  ||
-       (ip[3] > 255) || (port[0] > 255)  || (port[1] > 255) ) {
+    if(!*str) {
       failf(data, "Couldn't interpret the 227-response");
       failf(data, "Couldn't interpret the 227-response");
       return CURLE_FTP_WEIRD_227_FORMAT;
       return CURLE_FTP_WEIRD_227_FORMAT;
     }
     }
@@ -1897,7 +1913,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     if(!ftpc->newhost)
     if(!ftpc->newhost)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
 
 
-    ftpc->newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
+    ftpc->newport = (unsigned short)(((ip[4]<<8) + ip[5]) & 0xffff);
   }
   }
   else if(ftpc->count1 == 0) {
   else if(ftpc->count1 == 0) {
     /* EPSV failed, move on to PASV */
     /* EPSV failed, move on to PASV */
@@ -2032,6 +2048,30 @@ static CURLcode ftp_state_port_resp(struct Curl_easy *data,
   return result;
   return result;
 }
 }
 
 
+static int twodigit(const char *p)
+{
+  return (p[0]-'0') * 10 + (p[1]-'0');
+}
+
+static bool ftp_213_date(const char *p, int *year, int *month, int *day,
+                         int *hour, int *minute, int *second)
+{
+  size_t len = strlen(p);
+  if(len < 14)
+    return FALSE;
+  *year = twodigit(&p[0]) * 100 + twodigit(&p[2]);
+  *month = twodigit(&p[4]);
+  *day = twodigit(&p[6]);
+  *hour = twodigit(&p[8]);
+  *minute = twodigit(&p[10]);
+  *second = twodigit(&p[12]);
+
+  if((*month > 12) || (*day > 31) || (*hour > 23) || (*minute > 59) ||
+     (*second > 60))
+    return FALSE;
+  return TRUE;
+}
+
 static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
 static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
                                     int ftpcode)
                                     int ftpcode)
 {
 {
@@ -2046,8 +2086,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
       /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
          last .sss part is optional and means fractions of a second */
          last .sss part is optional and means fractions of a second */
       int year, month, day, hour, minute, second;
       int year, month, day, hour, minute, second;
-      if(6 == sscanf(&data->state.buffer[4], "%04d%02d%02d%02d%02d%02d",
-                     &year, &month, &day, &hour, &minute, &second)) {
+      if(ftp_213_date(&data->state.buffer[4],
+                      &year, &month, &day, &hour, &minute, &second)) {
         /* we have a time, reformat it */
         /* we have a time, reformat it */
         char timebuf[24];
         char timebuf[24];
         msnprintf(timebuf, sizeof(timebuf),
         msnprintf(timebuf, sizeof(timebuf),
@@ -2635,7 +2675,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
   int ftpcode;
   int ftpcode;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct pingpong *pp = &ftpc->pp;
   struct pingpong *pp = &ftpc->pp;
-  static const char ftpauth[][4]  = { "SSL", "TLS" };
+  static const char * const ftpauth[] = { "SSL", "TLS" };
   size_t nread = 0;
   size_t nread = 0;
 
 
   if(pp->sendleft)
   if(pp->sendleft)
@@ -3221,7 +3261,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
   if(data->state.wildcardmatch) {
   if(data->state.wildcardmatch) {
     if(data->set.chunk_end && ftpc->file) {
     if(data->set.chunk_end && ftpc->file) {
       Curl_set_in_callback(data, true);
       Curl_set_in_callback(data, true);
-      data->set.chunk_end(data->wildcard.customptr);
+      data->set.chunk_end(data->set.wildcardptr);
       Curl_set_in_callback(data, false);
       Curl_set_in_callback(data, false);
     }
     }
     ftpc->known_filesize = -1;
     ftpc->known_filesize = -1;
@@ -3728,7 +3768,7 @@ static CURLcode init_wc_data(struct Curl_easy *data)
   char *last_slash;
   char *last_slash;
   struct FTP *ftp = data->req.p.ftp;
   struct FTP *ftp = data->req.p.ftp;
   char *path = ftp->path;
   char *path = ftp->path;
-  struct WildcardData *wildcard = &(data->wildcard);
+  struct WildcardData *wildcard = data->wildcard;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   struct ftp_wc *ftpwc = NULL;
   struct ftp_wc *ftpwc = NULL;
 
 
@@ -3776,7 +3816,7 @@ static CURLcode init_wc_data(struct Curl_easy *data)
     goto fail;
     goto fail;
   }
   }
 
 
-  wildcard->protdata = ftpwc; /* put it to the WildcardData tmp pointer */
+  wildcard->ftpwc = ftpwc; /* put it to the WildcardData tmp pointer */
   wildcard->dtor = wc_data_dtor;
   wildcard->dtor = wc_data_dtor;
 
 
   /* wildcard does not support NOCWD option (assert it?) */
   /* wildcard does not support NOCWD option (assert it?) */
@@ -3814,13 +3854,13 @@ static CURLcode init_wc_data(struct Curl_easy *data)
   }
   }
   Curl_safefree(wildcard->pattern);
   Curl_safefree(wildcard->pattern);
   wildcard->dtor = ZERO_NULL;
   wildcard->dtor = ZERO_NULL;
-  wildcard->protdata = NULL;
+  wildcard->ftpwc = NULL;
   return result;
   return result;
 }
 }
 
 
 static CURLcode wc_statemach(struct Curl_easy *data)
 static CURLcode wc_statemach(struct Curl_easy *data)
 {
 {
-  struct WildcardData * const wildcard = &(data->wildcard);
+  struct WildcardData * const wildcard = data->wildcard;
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
 
 
@@ -3837,7 +3877,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
     case CURLWC_MATCHING: {
     case CURLWC_MATCHING: {
       /* In this state is LIST response successfully parsed, so lets restore
       /* In this state is LIST response successfully parsed, so lets restore
          previous WRITEFUNCTION callback and WRITEDATA pointer */
          previous WRITEFUNCTION callback and WRITEDATA pointer */
-      struct ftp_wc *ftpwc = wildcard->protdata;
+      struct ftp_wc *ftpwc = wildcard->ftpwc;
       data->set.fwrite_func = ftpwc->backup.write_function;
       data->set.fwrite_func = ftpwc->backup.write_function;
       data->set.out = ftpwc->backup.file_descriptor;
       data->set.out = ftpwc->backup.file_descriptor;
       ftpwc->backup.write_function = ZERO_NULL;
       ftpwc->backup.write_function = ZERO_NULL;
@@ -3876,7 +3916,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
         long userresponse;
         long userresponse;
         Curl_set_in_callback(data, true);
         Curl_set_in_callback(data, true);
         userresponse = data->set.chunk_bgn(
         userresponse = data->set.chunk_bgn(
-          finfo, wildcard->customptr, (int)wildcard->filelist.size);
+          finfo, data->set.wildcardptr, (int)wildcard->filelist.size);
         Curl_set_in_callback(data, false);
         Curl_set_in_callback(data, false);
         switch(userresponse) {
         switch(userresponse) {
         case CURL_CHUNK_BGN_FUNC_SKIP:
         case CURL_CHUNK_BGN_FUNC_SKIP:
@@ -3916,7 +3956,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
     case CURLWC_SKIP: {
     case CURLWC_SKIP: {
       if(data->set.chunk_end) {
       if(data->set.chunk_end) {
         Curl_set_in_callback(data, true);
         Curl_set_in_callback(data, true);
-        data->set.chunk_end(data->wildcard.customptr);
+        data->set.chunk_end(data->set.wildcardptr);
         Curl_set_in_callback(data, false);
         Curl_set_in_callback(data, false);
       }
       }
       Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
       Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
@@ -3926,7 +3966,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
     }
     }
 
 
     case CURLWC_CLEAN: {
     case CURLWC_CLEAN: {
-      struct ftp_wc *ftpwc = wildcard->protdata;
+      struct ftp_wc *ftpwc = wildcard->ftpwc;
       result = CURLE_OK;
       result = CURLE_OK;
       if(ftpwc)
       if(ftpwc)
         result = Curl_ftp_parselist_geterror(ftpwc->parser);
         result = Curl_ftp_parselist_geterror(ftpwc->parser);
@@ -3939,7 +3979,7 @@ static CURLcode wc_statemach(struct Curl_easy *data)
     case CURLWC_ERROR:
     case CURLWC_ERROR:
     case CURLWC_CLEAR:
     case CURLWC_CLEAR:
       if(wildcard->dtor)
       if(wildcard->dtor)
-        wildcard->dtor(wildcard->protdata);
+        wildcard->dtor(wildcard->ftpwc);
       return result;
       return result;
     }
     }
   }
   }
@@ -3966,8 +4006,8 @@ static CURLcode ftp_do(struct Curl_easy *data, bool *done)
 
 
   if(data->state.wildcardmatch) {
   if(data->state.wildcardmatch) {
     result = wc_statemach(data);
     result = wc_statemach(data);
-    if(data->wildcard.state == CURLWC_SKIP ||
-      data->wildcard.state == CURLWC_DONE) {
+    if(data->wildcard->state == CURLWC_SKIP ||
+       data->wildcard->state == CURLWC_DONE) {
       /* do not call ftp_regular_transfer */
       /* do not call ftp_regular_transfer */
       return CURLE_OK;
       return CURLE_OK;
     }
     }
@@ -4053,6 +4093,8 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
   }
   }
 
 
   freedirs(ftpc);
   freedirs(ftpc);
+  Curl_safefree(ftpc->account);
+  Curl_safefree(ftpc->alternative_to_user);
   Curl_safefree(ftpc->prevpath);
   Curl_safefree(ftpc->prevpath);
   Curl_safefree(ftpc->server_os);
   Curl_safefree(ftpc->server_os);
   Curl_pp_disconnect(pp);
   Curl_pp_disconnect(pp);
@@ -4322,11 +4364,31 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
   char *type;
   char *type;
   struct FTP *ftp;
   struct FTP *ftp;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
+  struct ftp_conn *ftpc = &conn->proto.ftpc;
 
 
-  data->req.p.ftp = ftp = calloc(sizeof(struct FTP), 1);
+  ftp = calloc(sizeof(struct FTP), 1);
   if(!ftp)
   if(!ftp)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
+  /* clone connection related data that is FTP specific */
+  if(data->set.str[STRING_FTP_ACCOUNT]) {
+    ftpc->account = strdup(data->set.str[STRING_FTP_ACCOUNT]);
+    if(!ftpc->account) {
+      free(ftp);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  if(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]) {
+    ftpc->alternative_to_user =
+      strdup(data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
+    if(!ftpc->alternative_to_user) {
+      Curl_safefree(ftpc->account);
+      free(ftp);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  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]; /* don't include the initial slash */
 
 
   /* FTP URLs support an extension like ";type=<typecode>" that
   /* FTP URLs support an extension like ";type=<typecode>" that
@@ -4361,7 +4423,9 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
   /* get some initial data into the ftp struct */
   /* get some initial data into the ftp struct */
   ftp->transfer = PPTRANSFER_BODY;
   ftp->transfer = PPTRANSFER_BODY;
   ftp->downloadsize = 0;
   ftp->downloadsize = 0;
-  conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
+  ftpc->known_filesize = -1; /* unknown size for now */
+  ftpc->use_ssl = data->set.use_ssl;
+  ftpc->ccc = data->set.ftp_ccc;
 
 
   return result;
   return result;
 }
 }

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

@@ -120,6 +120,8 @@ struct FTP {
    struct */
    struct */
 struct ftp_conn {
 struct ftp_conn {
   struct pingpong pp;
   struct pingpong pp;
+  char *account;
+  char *alternative_to_user;
   char *entrypath; /* the PWD reply when we logged on */
   char *entrypath; /* the PWD reply when we logged on */
   char *file;    /* url-decoded file name (or path) */
   char *file;    /* url-decoded file name (or path) */
   char **dirs;   /* realloc()ed array for path components */
   char **dirs;   /* realloc()ed array for path components */
@@ -143,6 +145,9 @@ struct ftp_conn {
   ftpstate state; /* always use ftp.c:state() to change state! */
   ftpstate state; /* always use ftp.c:state() to change state! */
   ftpstate state_saved; /* transfer type saved to be reloaded after data
   ftpstate state_saved; /* transfer type saved to be reloaded after data
                            connection is established */
                            connection is established */
+  unsigned char use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
+                              IMAP or POP3 or others! (type: curl_usessl)*/
+  unsigned char ccc;       /* ccc level for this connection */
   BIT(ftp_trying_alternative);
   BIT(ftp_trying_alternative);
   BIT(dont_check);  /* Set to TRUE to prevent the final (post-transfer)
   BIT(dont_check);  /* Set to TRUE to prevent the final (post-transfer)
                        file size and 226/250 status check. It should still
                        file size and 226/250 status check. It should still

+ 40 - 3
Utilities/cmcurl/lib/ftplistparser.c

@@ -181,6 +181,43 @@ struct ftp_parselist_data {
   } offsets;
   } offsets;
 };
 };
 
 
+static void fileinfo_dtor(void *user, void *element)
+{
+  (void)user;
+  Curl_fileinfo_cleanup(element);
+}
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc)
+{
+  Curl_llist_init(&wc->filelist, fileinfo_dtor);
+  wc->state = CURLWC_INIT;
+
+  return CURLE_OK;
+}
+
+void Curl_wildcard_dtor(struct WildcardData **wcp)
+{
+  struct WildcardData *wc = *wcp;
+  if(!wc)
+    return;
+
+  if(wc->dtor) {
+    wc->dtor(wc->ftpwc);
+    wc->dtor = ZERO_NULL;
+    wc->ftpwc = NULL;
+  }
+  DEBUGASSERT(wc->ftpwc == NULL);
+
+  Curl_llist_destroy(&wc->filelist, NULL);
+  free(wc->path);
+  wc->path = NULL;
+  free(wc->pattern);
+  wc->pattern = NULL;
+  wc->state = CURLWC_INIT;
+  free(wc);
+  *wcp = NULL;
+}
+
 struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
 struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
 {
 {
   return calloc(1, sizeof(struct ftp_parselist_data));
   return calloc(1, sizeof(struct ftp_parselist_data));
@@ -274,8 +311,8 @@ static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
                                     struct fileinfo *infop)
                                     struct fileinfo *infop)
 {
 {
   curl_fnmatch_callback compare;
   curl_fnmatch_callback compare;
-  struct WildcardData *wc = &data->wildcard;
-  struct ftp_wc *ftpwc = wc->protdata;
+  struct WildcardData *wc = data->wildcard;
+  struct ftp_wc *ftpwc = wc->ftpwc;
   struct Curl_llist *llist = &wc->filelist;
   struct Curl_llist *llist = &wc->filelist;
   struct ftp_parselist_data *parser = ftpwc->parser;
   struct ftp_parselist_data *parser = ftpwc->parser;
   bool add = TRUE;
   bool add = TRUE;
@@ -330,7 +367,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
 {
 {
   size_t bufflen = size*nmemb;
   size_t bufflen = size*nmemb;
   struct Curl_easy *data = (struct Curl_easy *)connptr;
   struct Curl_easy *data = (struct Curl_easy *)connptr;
-  struct ftp_wc *ftpwc = data->wildcard.protdata;
+  struct ftp_wc *ftpwc = data->wildcard->ftpwc;
   struct ftp_parselist_data *parser = ftpwc->parser;
   struct ftp_parselist_data *parser = ftpwc->parser;
   struct fileinfo *infop;
   struct fileinfo *infop;
   struct curl_fileinfo *finfo;
   struct curl_fileinfo *finfo;

+ 34 - 0
Utilities/cmcurl/lib/ftplistparser.h

@@ -39,5 +39,39 @@ struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void);
 
 
 void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data);
 void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data);
 
 
+/* list of wildcard process states */
+typedef enum {
+  CURLWC_CLEAR = 0,
+  CURLWC_INIT = 1,
+  CURLWC_MATCHING, /* library is trying to get list of addresses for
+                      downloading */
+  CURLWC_DOWNLOADING,
+  CURLWC_CLEAN, /* deallocate resources and reset settings */
+  CURLWC_SKIP,  /* skip over concrete file */
+  CURLWC_ERROR, /* error cases */
+  CURLWC_DONE   /* if is wildcard->state == CURLWC_DONE wildcard loop
+                   will end */
+} wildcard_states;
+
+typedef void (*wildcard_dtor)(void *ptr);
+
+/* struct keeping information about wildcard download process */
+struct WildcardData {
+  char *path; /* path to the directory, where we trying wildcard-match */
+  char *pattern; /* wildcard pattern */
+  struct Curl_llist filelist; /* llist with struct Curl_fileinfo */
+  struct ftp_wc *ftpwc; /* pointer to FTP wildcard data */
+  wildcard_dtor dtor;
+  unsigned char state; /* wildcard_states */
+};
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc);
+void Curl_wildcard_dtor(struct WildcardData **wcp);
+
+struct Curl_easy;
+
+#else
+/* FTP is disabled */
+#define Curl_wildcard_dtor(x)
 #endif /* CURL_DISABLE_FTP */
 #endif /* CURL_DISABLE_FTP */
 #endif /* HEADER_CURL_FTPLISTPARSER_H */
 #endif /* HEADER_CURL_FTPLISTPARSER_H */

+ 9 - 8
Utilities/cmcurl/lib/headers.c

@@ -38,14 +38,13 @@
 
 
 /* Generate the curl_header struct for the user. This function MUST assign all
 /* Generate the curl_header struct for the user. This function MUST assign all
    struct fields in the output struct. */
    struct fields in the output struct. */
-static void copy_header_external(struct Curl_easy *data,
-                                 struct Curl_header_store *hs,
+static void copy_header_external(struct Curl_header_store *hs,
                                  size_t index,
                                  size_t index,
                                  size_t amount,
                                  size_t amount,
                                  struct Curl_llist_element *e,
                                  struct Curl_llist_element *e,
-                                 struct curl_header **hout)
+                                 struct curl_header *hout)
 {
 {
-  struct curl_header *h = *hout = &data->state.headerout;
+  struct curl_header *h = hout;
   h->name = hs->name;
   h->name = hs->name;
   h->value = hs->value;
   h->value = hs->value;
   h->amount = amount;
   h->amount = amount;
@@ -118,7 +117,9 @@ CURLHcode curl_easy_header(CURL *easy,
       return CURLHE_MISSING;
       return CURLHE_MISSING;
   }
   }
   /* this is the name we want */
   /* this is the name we want */
-  copy_header_external(data, hs, nameindex, amount, e_pick, hout);
+  copy_header_external(hs, nameindex, amount, e_pick,
+                       &data->state.headerout[0]);
+  *hout = &data->state.headerout[0];
   return CURLHE_OK;
   return CURLHE_OK;
 }
 }
 
 
@@ -132,7 +133,6 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
   struct Curl_llist_element *pick;
   struct Curl_llist_element *pick;
   struct Curl_llist_element *e;
   struct Curl_llist_element *e;
   struct Curl_header_store *hs;
   struct Curl_header_store *hs;
-  struct curl_header *hout;
   size_t amount = 0;
   size_t amount = 0;
   size_t index = 0;
   size_t index = 0;
 
 
@@ -179,8 +179,9 @@ struct curl_header *curl_easy_nextheader(CURL *easy,
       index = amount - 1;
       index = amount - 1;
   }
   }
 
 
-  copy_header_external(data, hs, index, amount, pick, &hout);
-  return hout;
+  copy_header_external(hs, index, amount, pick,
+                       &data->state.headerout[1]);
+  return &data->state.headerout[1];
 }
 }
 
 
 static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
 static CURLcode namevalue(char *header, size_t hlen, unsigned int type,

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

@@ -78,7 +78,7 @@ CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
 
       dns = Curl_cache_addr(data, ai,
       dns = Curl_cache_addr(data, ai,
-                            data->state.async.hostname,
+                            data->state.async.hostname, 0,
                             data->state.async.port);
                             data->state.async.port);
       if(data->share)
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);

+ 50 - 41
Utilities/cmcurl/lib/hostip.c

@@ -167,18 +167,25 @@ void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
 
 
 /*
 /*
  * Create a hostcache id string for the provided host + port, to be used by
  * Create a hostcache id string for the provided host + port, to be used by
- * the DNS caching. Without alloc.
+ * the DNS caching. Without alloc. Return length of the id string.
  */
  */
-static void
-create_hostcache_id(const char *name, int port, char *ptr, size_t buflen)
+static size_t
+create_hostcache_id(const char *name,
+                    size_t nlen, /* 0 or actual name length */
+                    int port, char *ptr, size_t buflen)
 {
 {
-  size_t len = strlen(name);
+  size_t len = nlen ? nlen : strlen(name);
+  size_t olen = 0;
+  DEBUGASSERT(buflen >= MAX_HOSTCACHE_LEN);
   if(len > (buflen - 7))
   if(len > (buflen - 7))
     len = buflen - 7;
     len = buflen - 7;
   /* store and lower case the name */
   /* store and lower case the name */
-  while(len--)
+  while(len--) {
     *ptr++ = Curl_raw_tolower(*name++);
     *ptr++ = Curl_raw_tolower(*name++);
-  msnprintf(ptr, 7, ":%u", port);
+    olen++;
+  }
+  olen += msnprintf(ptr, 7, ":%u", port);
+  return olen;
 }
 }
 
 
 struct hostcache_prune_data {
 struct hostcache_prune_data {
@@ -260,20 +267,18 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
                                          int port)
                                          int port)
 {
 {
   struct Curl_dns_entry *dns = NULL;
   struct Curl_dns_entry *dns = NULL;
-  size_t entry_len;
   char entry_id[MAX_HOSTCACHE_LEN];
   char entry_id[MAX_HOSTCACHE_LEN];
 
 
   /* Create an entry id, based upon the hostname and port */
   /* Create an entry id, based upon the hostname and port */
-  create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
-  entry_len = strlen(entry_id);
+  size_t entry_len = create_hostcache_id(hostname, 0, port,
+                                         entry_id, sizeof(entry_id));
 
 
   /* See if its already in our dns cache */
   /* See if its already in our dns cache */
   dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
   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 */
   /* No entry found in cache, check if we might have a wildcard entry */
   if(!dns && data->state.wildcard_resolve) {
   if(!dns && data->state.wildcard_resolve) {
-    create_hostcache_id("*", port, entry_id, sizeof(entry_id));
-    entry_len = strlen(entry_id);
+    entry_len = create_hostcache_id("*", 1, port, entry_id, sizeof(entry_id));
 
 
     /* See if it's already in our dns cache */
     /* See if it's already in our dns cache */
     dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
     dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
@@ -438,6 +443,7 @@ struct Curl_dns_entry *
 Curl_cache_addr(struct Curl_easy *data,
 Curl_cache_addr(struct Curl_easy *data,
                 struct Curl_addrinfo *addr,
                 struct Curl_addrinfo *addr,
                 const char *hostname,
                 const char *hostname,
+                size_t hostlen, /* length or zero */
                 int port)
                 int port)
 {
 {
   char entry_id[MAX_HOSTCACHE_LEN];
   char entry_id[MAX_HOSTCACHE_LEN];
@@ -461,8 +467,8 @@ Curl_cache_addr(struct Curl_easy *data,
   }
   }
 
 
   /* Create an entry id, based upon the hostname and port */
   /* Create an entry id, based upon the hostname and port */
-  create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
-  entry_len = strlen(entry_id);
+  entry_len = create_hostcache_id(hostname, hostlen, port,
+                                  entry_id, sizeof(entry_id));
 
 
   dns->inuse = 1;   /* the cache has the first reference */
   dns->inuse = 1;   /* the cache has the first reference */
   dns->addr = addr; /* this is the address(es) */
   dns->addr = addr; /* this is the address(es) */
@@ -791,7 +797,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
 
       /* we got a response, store it in the cache */
       /* we got a response, store it in the cache */
-      dns = Curl_cache_addr(data, addr, hostname, port);
+      dns = Curl_cache_addr(data, addr, hostname, 0, port);
 
 
       if(data->share)
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -1059,8 +1065,7 @@ void Curl_hostcache_clean(struct Curl_easy *data,
 CURLcode Curl_loadhostpairs(struct Curl_easy *data)
 CURLcode Curl_loadhostpairs(struct Curl_easy *data)
 {
 {
   struct curl_slist *hostp;
   struct curl_slist *hostp;
-  char hostname[256];
-  int port = 0;
+  char *host_end;
 
 
   /* Default is no wildcard found */
   /* Default is no wildcard found */
   data->state.wildcard_resolve = false;
   data->state.wildcard_resolve = false;
@@ -1070,18 +1075,25 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
     if(!hostp->data)
     if(!hostp->data)
       continue;
       continue;
     if(hostp->data[0] == '-') {
     if(hostp->data[0] == '-') {
+      unsigned long num = 0;
       size_t entry_len;
       size_t entry_len;
-
-      if(2 != sscanf(hostp->data + 1, "%255[^:]:%d", hostname, &port)) {
-        infof(data, "Couldn't parse CURLOPT_RESOLVE removal entry '%s'",
+      size_t hlen = 0;
+      host_end = strchr(&hostp->data[1], ':');
+
+      if(host_end) {
+        hlen = host_end - &hostp->data[1];
+        num = strtoul(++host_end, NULL, 10);
+        if(!hlen || (num > 0xffff))
+          host_end = NULL;
+      }
+      if(!host_end) {
+        infof(data, "Bad syntax CURLOPT_RESOLVE removal entry '%s'",
               hostp->data);
               hostp->data);
         continue;
         continue;
       }
       }
-
       /* Create an entry id, based upon the hostname and port */
       /* Create an entry id, based upon the hostname and port */
-      create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
-      entry_len = strlen(entry_id);
-
+      entry_len = create_hostcache_id(&hostp->data[1], hlen, (int)num,
+                                      entry_id, sizeof(entry_id));
       if(data->share)
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
 
@@ -1102,25 +1114,22 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       char *addr_begin;
       char *addr_begin;
       char *addr_end;
       char *addr_end;
       char *port_ptr;
       char *port_ptr;
+      int port = 0;
       char *end_ptr;
       char *end_ptr;
       bool permanent = TRUE;
       bool permanent = TRUE;
-      char *host_begin;
-      char *host_end;
       unsigned long tmp_port;
       unsigned long tmp_port;
       bool error = true;
       bool error = true;
+      char *host_begin = hostp->data;
+      size_t hlen = 0;
 
 
-      host_begin = hostp->data;
       if(host_begin[0] == '+') {
       if(host_begin[0] == '+') {
         host_begin++;
         host_begin++;
         permanent = FALSE;
         permanent = FALSE;
       }
       }
       host_end = strchr(host_begin, ':');
       host_end = strchr(host_begin, ':');
-      if(!host_end ||
-         ((host_end - host_begin) >= (ptrdiff_t)sizeof(hostname)))
+      if(!host_end)
         goto err;
         goto err;
-
-      memcpy(hostname, host_begin, host_end - host_begin);
-      hostname[host_end - host_begin] = '\0';
+      hlen = host_end - host_begin;
 
 
       port_ptr = host_end + 1;
       port_ptr = host_end + 1;
       tmp_port = strtoul(port_ptr, &end_ptr, 10);
       tmp_port = strtoul(port_ptr, &end_ptr, 10);
@@ -1196,8 +1205,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       }
       }
 
 
       /* Create an entry id, based upon the hostname and port */
       /* Create an entry id, based upon the hostname and port */
-      create_hostcache_id(hostname, port, entry_id, sizeof(entry_id));
-      entry_len = strlen(entry_id);
+      entry_len = create_hostcache_id(host_begin, hlen, port,
+                                      entry_id, sizeof(entry_id));
 
 
       if(data->share)
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
@@ -1206,8 +1215,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
 
       if(dns) {
       if(dns) {
-        infof(data, "RESOLVE %s:%d is - old addresses discarded",
-              hostname, port);
+        infof(data, "RESOLVE %.*s:%d is - old addresses discarded",
+              (int)hlen, host_begin, port);
         /* delete old entry, there are two reasons for this
         /* delete old entry, there are two reasons for this
          1. old entry may have different addresses.
          1. old entry may have different addresses.
          2. even if entry with correct addresses is already in the cache,
          2. even if entry with correct addresses is already in the cache,
@@ -1223,7 +1232,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       }
       }
 
 
       /* put this new host in the cache */
       /* put this new host in the cache */
-      dns = Curl_cache_addr(data, head, hostname, port);
+      dns = Curl_cache_addr(data, head, host_begin, hlen, port);
       if(dns) {
       if(dns) {
         if(permanent)
         if(permanent)
           dns->timestamp = 0; /* mark as permanent */
           dns->timestamp = 0; /* mark as permanent */
@@ -1239,13 +1248,13 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         Curl_freeaddrinfo(head);
         Curl_freeaddrinfo(head);
         return CURLE_OUT_OF_MEMORY;
         return CURLE_OUT_OF_MEMORY;
       }
       }
-      infof(data, "Added %s:%d:%s to DNS cache%s",
-            hostname, port, addresses, permanent ? "" : " (non-permanent)");
+      infof(data, "Added %.*s:%d:%s to DNS cache%s",
+            (int)hlen, host_begin, port, addresses,
+            permanent ? "" : " (non-permanent)");
 
 
       /* Wildcard hostname */
       /* Wildcard hostname */
-      if(hostname[0] == '*' && hostname[1] == '\0') {
-        infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks",
-              hostname, port);
+      if((hlen == 1) && (host_begin[0] == '*')) {
+        infof(data, "RESOLVE *:%d using wildcard", port);
         data->state.wildcard_resolve = true;
         data->state.wildcard_resolve = true;
       }
       }
     }
     }

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

@@ -178,7 +178,7 @@ Curl_fetch_addr(struct Curl_easy *data,
  */
  */
 struct Curl_dns_entry *
 struct Curl_dns_entry *
 Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr,
 Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr,
-                const char *hostname, int port);
+                const char *hostname, size_t hostlen, int port);
 
 
 #ifndef INADDR_NONE
 #ifndef INADDR_NONE
 #define CURL_INADDR_NONE (in_addr_t) ~0
 #define CURL_INADDR_NONE (in_addr_t) ~0

+ 99 - 76
Utilities/cmcurl/lib/http.c

@@ -88,6 +88,7 @@
 #include "hsts.h"
 #include "hsts.h"
 #include "ws.h"
 #include "ws.h"
 #include "c-hyper.h"
 #include "c-hyper.h"
+#include "curl_ctype.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -233,15 +234,12 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
 
 
   Curl_mime_initpart(&http->form);
   Curl_mime_initpart(&http->form);
   data->req.p.http = http;
   data->req.p.http = http;
+  connkeep(conn, "HTTP default");
 
 
-  if((data->state.httpwant == CURL_HTTP_VERSION_3)
-     || (data->state.httpwant == CURL_HTTP_VERSION_3ONLY)) {
+  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
     CURLcode result = Curl_conn_may_http3(data, conn);
     CURLcode result = Curl_conn_may_http3(data, conn);
     if(result)
     if(result)
       return result;
       return result;
-
-     /* TODO: HTTP lower version eyeballing */
-    conn->transport = TRNSPRT_QUIC;
   }
   }
 
 
   return CURLE_OK;
   return CURLE_OK;
@@ -2342,7 +2340,16 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
         return result;
         return result;
     }
     }
 
 
-    if(http->postsize) {
+    /* For really small puts we don't 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. */
+    ptr = Curl_checkheaders(data, STRCONST("Expect"));
+    if(ptr) {
+      data->state.expect100header =
+        Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
+    }
+    else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
       result = expect100(data, conn, r);
       result = expect100(data, conn, r);
       if(result)
       if(result)
         return result;
         return result;
@@ -4155,11 +4162,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
     if(!k->headerline++) {
     if(!k->headerline++) {
       /* This is the first header, it MUST be the error code line
       /* This is the first header, it MUST be the error code line
          or else we consider this to be the body right away! */
          or else we consider this to be the body right away! */
-      int httpversion_major;
-      int rtspversion_major;
-      int nc = 0;
-#define HEADER1 headp /* no conversion needed, just use headp */
-
+      bool fine_statusline = FALSE;
       if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
       if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
         /*
         /*
          * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
          * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
@@ -4168,39 +4171,60 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
          * says. We allow any three-digit number here, but we cannot make
          * 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 isn't within the protocol.
          */
          */
-        char separator;
-        char twoorthree[2];
         int httpversion = 0;
         int httpversion = 0;
-        char digit4 = 0;
-        nc = sscanf(HEADER1,
-                    " HTTP/%1d.%1d%c%3d%c",
-                    &httpversion_major,
-                    &httpversion,
-                    &separator,
-                    &k->httpcode,
-                    &digit4);
-
-        if(nc == 1 && httpversion_major >= 2 &&
-           2 == sscanf(HEADER1, " HTTP/%1[23] %d", twoorthree, &k->httpcode)) {
-          conn->httpversion = 0;
-          nc = 4;
-          separator = ' ';
-        }
-
-        /* There can only be a 4th response code digit stored in 'digit4' if
-           all the other fields were parsed and stored first, so nc is 5 when
-           digit4 a digit.
-
-           The sscanf() line above will also allow zero-prefixed and negative
-           numbers, so we check for that too here.
-        */
-        else if(ISDIGIT(digit4) || (nc >= 4 && k->httpcode < 100)) {
-          failf(data, "Unsupported response code in HTTP response");
-          return CURLE_UNSUPPORTED_PROTOCOL;
+        char *p = headp;
+
+        while(*p && ISBLANK(*p))
+          p++;
+        if(!strncmp(p, "HTTP/", 5)) {
+          p += 5;
+          switch(*p) {
+          case '1':
+            p++;
+            if((p[0] == '.') && (p[1] == '0' || p[1] == '1')) {
+              if(ISBLANK(p[2])) {
+                httpversion = 10 + (p[1] - '0');
+                p += 3;
+                if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+                  k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+                    (p[2] - '0');
+                  p += 3;
+                  if(ISSPACE(*p))
+                    fine_statusline = TRUE;
+                }
+              }
+            }
+            if(!fine_statusline) {
+              failf(data, "Unsupported HTTP/1 subversion in response");
+              return CURLE_UNSUPPORTED_PROTOCOL;
+            }
+            break;
+          case '2':
+          case '3':
+            if(!ISBLANK(p[1]))
+              break;
+            httpversion = (*p - '0') * 10;
+            p += 2;
+            if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+              k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+                (p[2] - '0');
+              p += 3;
+              if(!ISSPACE(*p))
+                break;
+              fine_statusline = TRUE;
+            }
+            break;
+          default: /* unsupported */
+            failf(data, "Unsupported HTTP version in response");
+            return CURLE_UNSUPPORTED_PROTOCOL;
+          }
         }
         }
 
 
-        if((nc >= 4) && (' ' == separator)) {
-          httpversion += 10 * httpversion_major;
+        if(fine_statusline) {
+          if(k->httpcode < 100) {
+            failf(data, "Unsupported response code in HTTP response");
+            return CURLE_UNSUPPORTED_PROTOCOL;
+          }
           switch(httpversion) {
           switch(httpversion) {
           case 10:
           case 10:
           case 11:
           case 11:
@@ -4227,51 +4251,50 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
             conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
             conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
           }
           }
         }
         }
-        else if(!nc) {
-          /* this is the real world, not a Nirvana
-             NCSA 1.5.x returns this crap when asked for HTTP/1.1
-          */
-          nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode);
-          conn->httpversion = 10;
-
+        else {
           /* If user has set option HTTP200ALIASES,
           /* If user has set option HTTP200ALIASES,
              compare header line against list of aliases
              compare header line against list of aliases
           */
           */
-          if(!nc) {
-            statusline check =
-              checkhttpprefix(data,
-                              Curl_dyn_ptr(&data->state.headerb),
-                              Curl_dyn_len(&data->state.headerb));
-            if(check == STATUS_DONE) {
-              nc = 1;
-              k->httpcode = 200;
-              conn->httpversion = 10;
-            }
+          statusline check =
+            checkhttpprefix(data,
+                            Curl_dyn_ptr(&data->state.headerb),
+                            Curl_dyn_len(&data->state.headerb));
+          if(check == STATUS_DONE) {
+            fine_statusline = TRUE;
+            k->httpcode = 200;
+            conn->httpversion = 10;
           }
           }
         }
         }
-        else {
-          failf(data, "Unsupported HTTP version in response");
-          return CURLE_UNSUPPORTED_PROTOCOL;
-        }
       }
       }
       else if(conn->handler->protocol & CURLPROTO_RTSP) {
       else if(conn->handler->protocol & CURLPROTO_RTSP) {
-        char separator;
-        int rtspversion;
-        nc = sscanf(HEADER1,
-                    " RTSP/%1d.%1d%c%3d",
-                    &rtspversion_major,
-                    &rtspversion,
-                    &separator,
-                    &k->httpcode);
-        if((nc == 4) && (' ' == separator)) {
-          conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
-        }
-        else {
-          nc = 0;
+        char *p = headp;
+        while(*p && ISBLANK(*p))
+          p++;
+        if(!strncmp(p, "RTSP/", 5)) {
+          p += 5;
+          if(ISDIGIT(*p)) {
+            p++;
+            if((p[0] == '.') && ISDIGIT(p[1])) {
+              if(ISBLANK(p[2])) {
+                p += 3;
+                if(ISDIGIT(p[0]) && ISDIGIT(p[1]) && ISDIGIT(p[2])) {
+                  k->httpcode = (p[0] - '0') * 100 + (p[1] - '0') * 10 +
+                    (p[2] - '0');
+                  p += 3;
+                  if(ISSPACE(*p)) {
+                    fine_statusline = TRUE;
+                    conn->httpversion = 11; /* RTSP acts like HTTP 1.1 */
+                  }
+                }
+              }
+            }
+          }
+          if(!fine_statusline)
+            return CURLE_WEIRD_SERVER_REPLY;
         }
         }
       }
       }
 
 
-      if(nc) {
+      if(fine_statusline) {
         result = Curl_http_statusline(data, conn);
         result = Curl_http_statusline(data, conn);
         if(result)
         if(result)
           return result;
           return result;

+ 192 - 159
Utilities/cmcurl/lib/http2.c

@@ -98,7 +98,6 @@ static size_t populate_binsettings(uint8_t *binsettings,
 struct cf_h2_ctx {
 struct cf_h2_ctx {
   nghttp2_session *h2;
   nghttp2_session *h2;
   uint32_t max_concurrent_streams;
   uint32_t max_concurrent_streams;
-  bool enable_push;
   /* The easy handle used in the current filter call, cleared at return */
   /* The easy handle used in the current filter call, cleared at return */
   struct cf_call_data call_data;
   struct cf_call_data call_data;
 
 
@@ -116,6 +115,10 @@ struct cf_h2_ctx {
   int32_t pause_stream_id; /* stream ID which paused
   int32_t pause_stream_id; /* stream ID which paused
                               nghttp2_session_mem_recv */
                               nghttp2_session_mem_recv */
   size_t drain_total; /* sum of all stream's UrlState.drain */
   size_t drain_total; /* sum of all stream's UrlState.drain */
+  int32_t goaway_error;
+  int32_t last_stream_id;
+  BIT(goaway);
+  BIT(enable_push);
 };
 };
 
 
 /* How to access `call_data` from a cf_h2 filter */
 /* How to access `call_data` from a cf_h2 filter */
@@ -363,6 +366,15 @@ static void http2_stream_free(struct HTTP *stream)
   }
   }
 }
 }
 
 
+/*
+ * Returns nonzero if current HTTP/2 session should be closed.
+ */
+static int should_close_session(struct cf_h2_ctx *ctx)
+{
+  return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) &&
+    !nghttp2_session_want_write(ctx->h2);
+}
+
 /*
 /*
  * The server may send us data at any point (e.g. PING frames). Therefore,
  * The server may send us data at any point (e.g. PING frames). Therefore,
  * we cannot assume that an HTTP/2 socket is dead just because it is readable.
  * we cannot assume that an HTTP/2 socket is dead just because it is readable.
@@ -370,35 +382,27 @@ static void http2_stream_free(struct HTTP *stream)
  * Check the lower filters first and, if successful, peek at the socket
  * Check the lower filters first and, if successful, peek at the socket
  * and distinguish between closed and data.
  * and distinguish between closed and data.
  */
  */
-static bool http2_connisdead(struct Curl_cfilter *cf, struct Curl_easy *data)
+static bool http2_connisalive(struct Curl_cfilter *cf, struct Curl_easy *data,
+                              bool *input_pending)
 {
 {
   struct cf_h2_ctx *ctx = cf->ctx;
   struct cf_h2_ctx *ctx = cf->ctx;
-  int sval;
-  bool dead = TRUE;
+  bool alive = TRUE;
 
 
-  if(!cf->next || !cf->next->cft->is_alive(cf->next, data))
-    return TRUE;
+  *input_pending = FALSE;
+  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+    return FALSE;
 
 
-  sval = SOCKET_READABLE(Curl_conn_cf_get_socket(cf, data), 0);
-  if(sval == 0) {
-    /* timeout */
-    dead = FALSE;
-  }
-  else if(sval & CURL_CSELECT_ERR) {
-    /* socket is in an error state */
-    dead = TRUE;
-  }
-  else if(sval & CURL_CSELECT_IN) {
+  if(*input_pending) {
     /* This happens before we've sent off a request and the connection is
     /* 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,
        not in use by any other transfer, there shouldn't be any data here,
        only "protocol frames" */
        only "protocol frames" */
     CURLcode result;
     CURLcode result;
     ssize_t nread = -1;
     ssize_t nread = -1;
 
 
+    *input_pending = FALSE;
     Curl_attach_connection(data, cf->conn);
     Curl_attach_connection(data, cf->conn);
     nread = Curl_conn_cf_recv(cf->next, data,
     nread = Curl_conn_cf_recv(cf->next, data,
                               ctx->inbuf, H2_BUFSIZE, &result);
                               ctx->inbuf, H2_BUFSIZE, &result);
-    dead = FALSE;
     if(nread != -1) {
     if(nread != -1) {
       DEBUGF(LOG_CF(data, cf, "%d bytes stray data read before trying "
       DEBUGF(LOG_CF(data, cf, "%d bytes stray data read before trying "
                     "h2 connection", (int)nread));
                     "h2 connection", (int)nread));
@@ -406,15 +410,19 @@ static bool http2_connisdead(struct Curl_cfilter *cf, struct Curl_easy *data)
       ctx->inbuflen = nread;
       ctx->inbuflen = nread;
       if(h2_process_pending_input(cf, data, &result) < 0)
       if(h2_process_pending_input(cf, data, &result) < 0)
         /* immediate error, considered dead */
         /* immediate error, considered dead */
-        dead = TRUE;
+        alive = FALSE;
+      else {
+        alive = !should_close_session(ctx);
+      }
     }
     }
-    else
+    else {
       /* the read failed so let's say this is dead anyway */
       /* the read failed so let's say this is dead anyway */
-      dead = TRUE;
+      alive = FALSE;
+    }
     Curl_detach_connection(data);
     Curl_detach_connection(data);
   }
   }
 
 
-  return dead;
+  return alive;
 }
 }
 
 
 static CURLcode http2_send_ping(struct Curl_cfilter *cf,
 static CURLcode http2_send_ping(struct Curl_cfilter *cf,
@@ -815,7 +823,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
       ctx->max_concurrent_streams = nghttp2_session_get_remote_settings(
       ctx->max_concurrent_streams = nghttp2_session_get_remote_settings(
           session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
           session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
       ctx->enable_push = nghttp2_session_get_remote_settings(
       ctx->enable_push = nghttp2_session_get_remote_settings(
-          session, NGHTTP2_SETTINGS_ENABLE_PUSH);
+          session, NGHTTP2_SETTINGS_ENABLE_PUSH) != 0;
       DEBUGF(LOG_CF(data, cf, "MAX_CONCURRENT_STREAMS == %d",
       DEBUGF(LOG_CF(data, cf, "MAX_CONCURRENT_STREAMS == %d",
                     ctx->max_concurrent_streams));
                     ctx->max_concurrent_streams));
       DEBUGF(LOG_CF(data, cf, "ENABLE_PUSH == %s",
       DEBUGF(LOG_CF(data, cf, "ENABLE_PUSH == %s",
@@ -829,9 +837,12 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
       break;
       break;
     }
     }
     case NGHTTP2_GOAWAY:
     case NGHTTP2_GOAWAY:
+      ctx->goaway = TRUE;
+      ctx->goaway_error = frame->goaway.error_code;
+      ctx->last_stream_id = frame->goaway.last_stream_id;
       if(data) {
       if(data) {
         infof(data, "recveived GOAWAY, error=%d, last_stream=%u",
         infof(data, "recveived GOAWAY, error=%d, last_stream=%u",
-                    frame->goaway.error_code, frame->goaway.last_stream_id);
+                    ctx->goaway_error, ctx->last_stream_id);
         multi_connchanged(data->multi);
         multi_connchanged(data->multi);
       }
       }
       break;
       break;
@@ -858,7 +869,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
 
 
   switch(frame->hd.type) {
   switch(frame->hd.type) {
   case NGHTTP2_DATA:
   case NGHTTP2_DATA:
-    /* If body started on this stream, then receiving DATA is illegal. */
+    /* If !body started on this stream, then receiving DATA is illegal. */
     DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv frame DATA", stream_id));
     DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv frame DATA", stream_id));
     if(!stream->bodystarted) {
     if(!stream->bodystarted) {
       rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
       rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
@@ -940,7 +951,21 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
     break;
     break;
   case NGHTTP2_RST_STREAM:
   case NGHTTP2_RST_STREAM:
     DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv RST", stream_id));
     DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv RST", stream_id));
+    stream->closed = TRUE;
     stream->reset = TRUE;
     stream->reset = TRUE;
+    drain_this(cf, data);
+    Curl_expire(data, 0, EXPIRE_RUN_NOW);
+    break;
+  case NGHTTP2_WINDOW_UPDATE:
+    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv WINDOW_UPDATE", stream_id));
+    if((data_s->req.keepon & KEEP_SEND_HOLD) &&
+       (data_s->req.keepon & KEEP_SEND)) {
+      data_s->req.keepon &= ~KEEP_SEND_HOLD;
+      drain_this(cf, data_s);
+      Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
+      DEBUGF(LOG_CF(data, cf, "[h2sid=%u] un-holding after win update",
+                    stream_id));
+    }
     break;
     break;
   default:
   default:
     DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv frame %x",
     DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] recv frame %x",
@@ -1006,18 +1031,6 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
     return NGHTTP2_ERR_PAUSE;
     return NGHTTP2_ERR_PAUSE;
   }
   }
 
 
-#if 0
-  /* pause execution of nghttp2 if we received data for another handle
-     in order to process them first. */
-  if(CF_DATA_CURRENT(cf) != data_s) {
-    ctx->pause_stream_id = stream_id;
-    DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] not call_data -> NGHTTP2_ERR_PAUSE",
-                  stream_id));
-    drain_this(cf, data_s);
-    return NGHTTP2_ERR_PAUSE;
-  }
-#endif
-
   return 0;
   return 0;
 }
 }
 
 
@@ -1030,44 +1043,43 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
   struct HTTP *stream;
   struct HTTP *stream;
   int rv;
   int rv;
   (void)session;
   (void)session;
-  (void)stream_id;
 
 
-  if(stream_id) {
-    /* get the stream from the hash based on Stream ID, stream ID zero is for
-       connection-oriented stuff */
-    data_s = nghttp2_session_get_stream_user_data(session, stream_id);
-    if(!data_s) {
-      /* We could get stream ID not in the hash.  For example, if we
-         decided to reject stream (e.g., PUSH_PROMISE). */
-      return 0;
-    }
-    DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] on_stream_close(), %s (err %d)",
-                  stream_id, nghttp2_http2_strerror(error_code), error_code));
-    stream = data_s->req.p.http;
-    if(!stream)
-      return NGHTTP2_ERR_CALLBACK_FAILURE;
+  /* get the stream from the hash based on Stream ID, stream ID zero is for
+     connection-oriented stuff */
+  data_s = stream_id?
+             nghttp2_session_get_stream_user_data(session, stream_id) : NULL;
+  if(!data_s) {
+    return 0;
+  }
+  stream = data_s->req.p.http;
+  DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] on_stream_close(), %s (err %d)",
+                stream_id, nghttp2_http2_strerror(error_code), error_code));
+  if(!stream)
+    return NGHTTP2_ERR_CALLBACK_FAILURE;
 
 
-    stream->closed = TRUE;
-    if(CF_DATA_CURRENT(cf) != data_s) {
-      drain_this(cf, data_s);
-      Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
-    }
-    stream->error = error_code;
+  stream->closed = TRUE;
+  stream->error = error_code;
+  if(stream->error)
+    stream->reset = TRUE;
 
 
-    /* remove the entry from the hash as the stream is now gone */
-    rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
-    if(rv) {
-      infof(data_s, "http/2: failed to clear user_data for stream %u",
-            stream_id);
-      DEBUGASSERT(0);
-    }
-    if(stream_id == ctx->pause_stream_id) {
-      DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed the pause stream",
-                    stream_id));
-      ctx->pause_stream_id = 0;
-    }
-    DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed, cleared", stream_id));
+  if(CF_DATA_CURRENT(cf) != data_s) {
+    drain_this(cf, data_s);
+    Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
   }
   }
+
+  /* remove `data_s` from the nghttp2 stream */
+  rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
+  if(rv) {
+    infof(data_s, "http/2: failed to clear user_data for stream %u",
+          stream_id);
+    DEBUGASSERT(0);
+  }
+  if(stream_id == ctx->pause_stream_id) {
+    DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed the pause stream",
+                  stream_id));
+    ctx->pause_stream_id = 0;
+  }
+  DEBUGF(LOG_CF(data_s, cf, "[h2sid=%u] closed now", stream_id));
   return 0;
   return 0;
 }
 }
 
 
@@ -1383,7 +1395,8 @@ static void http2_data_done(struct Curl_cfilter *cf,
     ctx->pause_stream_id = 0;
     ctx->pause_stream_id = 0;
   }
   }
 
 
-  if(premature || (!stream->closed && stream->stream_id)) {
+  (void)premature;
+  if(!stream->closed && stream->stream_id) {
     /* RST_STREAM */
     /* RST_STREAM */
     DEBUGF(LOG_CF(data, cf, "[h2sid=%u] RST", stream->stream_id));
     DEBUGF(LOG_CF(data, cf, "[h2sid=%u] RST", stream->stream_id));
     if(!nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
     if(!nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
@@ -1445,15 +1458,6 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
   return result;
   return result;
 }
 }
 
 
-/*
- * Returns nonzero if current HTTP/2 session should be closed.
- */
-static int should_close_session(struct cf_h2_ctx *ctx)
-{
-  return ctx->drain_total == 0 && !nghttp2_session_want_read(ctx->h2) &&
-    !nghttp2_session_want_write(ctx->h2);
-}
-
 /*
 /*
  * h2_process_pending_input() processes pending input left in
  * h2_process_pending_input() processes pending input left in
  * httpc->inbuf.  Then, call h2_session_send() to send pending data.
  * httpc->inbuf.  Then, call h2_session_send() to send pending data.
@@ -1586,8 +1590,6 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
     }
     }
   }
   }
 
 
-  /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
-  stream->closed = FALSE;
   if(stream->error == NGHTTP2_REFUSED_STREAM) {
   if(stream->error == NGHTTP2_REFUSED_STREAM) {
     DEBUGF(LOG_CF(data, cf, "[h2sid=%u] REFUSED_STREAM, try again on a new "
     DEBUGF(LOG_CF(data, cf, "[h2sid=%u] REFUSED_STREAM, try again on a new "
                   "connection", stream->stream_id));
                   "connection", stream->stream_id));
@@ -1603,6 +1605,11 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
     *err = CURLE_HTTP2_STREAM;
     *err = CURLE_HTTP2_STREAM;
     return -1;
     return -1;
   }
   }
+  else if(stream->reset) {
+    failf(data, "HTTP/2 stream %u was reset", stream->stream_id);
+    *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
+    return -1;
+  }
 
 
   if(!stream->bodystarted) {
   if(!stream->bodystarted) {
     failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
     failf(data, "HTTP/2 stream %u was closed cleanly, but before getting "
@@ -1638,7 +1645,7 @@ static ssize_t http2_handle_stream_close(struct Curl_cfilter *cf,
 
 
   stream->close_handled = TRUE;
   stream->close_handled = TRUE;
 
 
-  DEBUGF(LOG_CF(data, cf, "http2_recv returns 0, http2_handle_stream_close"));
+  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] closed cleanly", stream->stream_id));
   return 0;
   return 0;
 }
 }
 
 
@@ -1720,9 +1727,29 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   struct HTTP *stream = data->req.p.http;
   struct HTTP *stream = data->req.p.http;
   ssize_t nread = -1;
   ssize_t nread = -1;
   struct cf_call_data save;
   struct cf_call_data save;
+  bool conn_is_closed = FALSE;
 
 
   CF_DATA_SAVE(save, cf, data);
   CF_DATA_SAVE(save, cf, data);
 
 
+  /* If the h2 session has told us to GOAWAY with an error AND
+   * indicated the highest stream id it has processes AND
+   * the stream we are trying to read has a higher id, this
+   * means we will most likely not receive any more for it.
+   * Treat this as if the server explicitly had RST the stream */
+  if((ctx->goaway && ctx->goaway_error &&
+      ctx->last_stream_id > 0 &&
+      ctx->last_stream_id < stream->stream_id)) {
+    stream->reset = TRUE;
+  }
+
+  /* If a stream is RST, it does not matter what state the h2 session
+   * is in, our answer to receiving data is always the same. */
+  if(stream->reset) {
+    *err = stream->bodystarted? CURLE_PARTIAL_FILE : CURLE_RECV_ERROR;
+    nread = -1;
+    goto out;
+  }
+
   if(should_close_session(ctx)) {
   if(should_close_session(ctx)) {
     DEBUGF(LOG_CF(data, cf, "http2_recv: nothing to do in this session"));
     DEBUGF(LOG_CF(data, cf, "http2_recv: nothing to do in this session"));
     if(cf->conn->bits.close) {
     if(cf->conn->bits.close) {
@@ -1763,7 +1790,7 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
     goto out;
     goto out;
   }
   }
 
 
-  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv: win %u/%u",
+  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv: win %u/%u",
                 stream->stream_id,
                 stream->stream_id,
                 nghttp2_session_get_local_window_size(ctx->h2),
                 nghttp2_session_get_local_window_size(ctx->h2),
                 nghttp2_session_get_stream_local_window_size(ctx->h2,
                 nghttp2_session_get_stream_local_window_size(ctx->h2,
@@ -1846,57 +1873,40 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
     stream->memlen = 0;
     stream->memlen = 0;
 
 
     if(ctx->inbuflen > 0) {
     if(ctx->inbuflen > 0) {
-      DEBUGF(LOG_CF(data, cf, "Use data left in connection buffer, nread=%zd",
-                    ctx->inbuflen - ctx->nread_inbuf));
+      DEBUGF(LOG_CF(data, cf, "[h2sid=%u] %zd bytes in inbuf",
+                    stream->stream_id, ctx->inbuflen - ctx->nread_inbuf));
       if(h2_process_pending_input(cf, data, err))
       if(h2_process_pending_input(cf, data, err))
         return -1;
         return -1;
     }
     }
 
 
-    while(stream->memlen == 0          /* have no data for this stream */
-          && !ctx->pause_stream_id     /* we are not paused either */
-          && ctx->inbuflen == 0) {     /* and out input buffer is empty */
+    while(stream->memlen == 0 &&       /* have no data for this stream */
+          !stream->closed &&           /* and it is not closed/reset */
+          !ctx->pause_stream_id &&     /* we are not paused either */
+          ctx->inbuflen == 0 &&       /* and out input buffer is empty */
+          !conn_is_closed) {          /* and connection is not closed */
       /* Receive data from the "lower" filters */
       /* Receive data from the "lower" filters */
       nread = Curl_conn_cf_recv(cf->next, data, ctx->inbuf, H2_BUFSIZE, err);
       nread = Curl_conn_cf_recv(cf->next, data, ctx->inbuf, H2_BUFSIZE, err);
       if(nread < 0) {
       if(nread < 0) {
-        if(*err != CURLE_AGAIN)
-          failf(data, "Failed receiving HTTP2 data");
-        else if(stream->closed) {
-          /* received when the stream was already closed! */
-          nread = http2_handle_stream_close(cf, data, stream, err);
-          goto out;
+        DEBUGASSERT(*err);
+        if(*err == CURLE_AGAIN) {
+          break;
         }
         }
-
-        /* nothing to read from the lower layers, clear drain */
-        drained_transfer(cf, data);
-        nread = -1;
-        goto out;
+        failf(data, "Failed receiving HTTP2 data");
+        conn_is_closed = TRUE;
       }
       }
       else if(nread == 0) {
       else if(nread == 0) {
-        if(!stream->closed) {
-          /* This will happen when the server or proxy server is SIGKILLed
-             during data transfer. We should emit an error since our data
-             received may be incomplete. */
-          failf(data, "HTTP/2 stream %u was not closed cleanly before"
-                " end of the underlying stream",
-                stream->stream_id);
-          drained_transfer(cf, data);
-          *err = CURLE_PARTIAL_FILE;
-          nread = -1;
-          goto out;
-        }
-
-        DEBUGF(LOG_CF(data, cf, "[h2sid=%u] end of stream",
+        DEBUGF(LOG_CF(data, cf, "[h2sid=%u] underlying connection is closed",
                       stream->stream_id));
                       stream->stream_id));
-        *err = CURLE_OK;
-        nread = 0;
-        goto out;
+        conn_is_closed = TRUE;
+      }
+      else {
+        DEBUGF(LOG_CF(data, cf, "[h2sid=%u] read %zd from connection",
+                      stream->stream_id, nread));
+        ctx->inbuflen = nread;
+        DEBUGASSERT(ctx->nread_inbuf == 0);
+        if(h2_process_pending_input(cf, data, err))
+          return -1;
       }
       }
-
-      DEBUGF(LOG_CF(data, cf, "read %zd from connection", nread));
-      ctx->inbuflen = nread;
-      DEBUGASSERT(ctx->nread_inbuf == 0);
-      if(h2_process_pending_input(cf, data, err))
-        return -1;
     }
     }
 
 
   }
   }
@@ -1933,11 +1943,18 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
 
 
     *err = CURLE_OK;
     *err = CURLE_OK;
     nread = retlen;
     nread = retlen;
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_h2_recv -> %zd",
-                  stream->stream_id, nread));
     goto out;
     goto out;
   }
   }
 
 
+  if(conn_is_closed && !stream->closed) {
+    /* underlying connection is closed and we have nothing for the stream.
+     * Treat this as a RST */
+    stream->closed = stream->reset = TRUE;
+      failf(data, "HTTP/2 stream %u was not closed cleanly before"
+            " end of the underlying connection",
+            stream->stream_id);
+  }
+
   if(stream->closed) {
   if(stream->closed) {
     nread = http2_handle_stream_close(cf, data, stream, err);
     nread = http2_handle_stream_close(cf, data, stream, err);
     goto out;
     goto out;
@@ -1950,9 +1967,9 @@ static ssize_t cf_h2_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   }
   }
   *err = CURLE_AGAIN;
   *err = CURLE_AGAIN;
   nread = -1;
   nread = -1;
-  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv -> AGAIN",
-                stream->stream_id));
 out:
 out:
+  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv -> %zd, %d",
+                stream->stream_id, nread, *err));
   CF_DATA_RESTORE(cf, save);
   CF_DATA_RESTORE(cf, save);
   return nread;
   return nread;
 }
 }
@@ -1976,19 +1993,20 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
   CURLcode result;
   CURLcode result;
   struct h2h3req *hreq;
   struct h2h3req *hreq;
   struct cf_call_data save;
   struct cf_call_data save;
+  ssize_t nwritten;
 
 
   CF_DATA_SAVE(save, cf, data);
   CF_DATA_SAVE(save, cf, data);
-  DEBUGF(LOG_CF(data, cf, "send len=%zu", len));
+  DEBUGF(LOG_CF(data, cf, "cf_send(len=%zu) start", len));
 
 
   if(stream->stream_id != -1) {
   if(stream->stream_id != -1) {
     if(stream->close_handled) {
     if(stream->close_handled) {
       infof(data, "stream %u closed", stream->stream_id);
       infof(data, "stream %u closed", stream->stream_id);
       *err = CURLE_HTTP2_STREAM;
       *err = CURLE_HTTP2_STREAM;
-      len = -1;
+      nwritten = -1;
       goto out;
       goto out;
     }
     }
     else if(stream->closed) {
     else if(stream->closed) {
-      len = http2_handle_stream_close(cf, data, stream, err);
+      nwritten = http2_handle_stream_close(cf, data, stream, err);
       goto out;
       goto out;
     }
     }
     /* If stream_id != -1, we have dispatched request HEADERS, and now
     /* If stream_id != -1, we have dispatched request HEADERS, and now
@@ -1998,26 +2016,24 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
     rv = nghttp2_session_resume_data(ctx->h2, stream->stream_id);
     rv = nghttp2_session_resume_data(ctx->h2, stream->stream_id);
     if(nghttp2_is_fatal(rv)) {
     if(nghttp2_is_fatal(rv)) {
       *err = CURLE_SEND_ERROR;
       *err = CURLE_SEND_ERROR;
-      len = -1;
+      nwritten = -1;
       goto out;
       goto out;
     }
     }
     result = h2_session_send(cf, data);
     result = h2_session_send(cf, data);
     if(result) {
     if(result) {
       *err = result;
       *err = result;
-      len = -1;
+      nwritten = -1;
       goto out;
       goto out;
     }
     }
-    len -= stream->upload_len;
 
 
-    /* Nullify here because we call nghttp2_session_send() and they
-       might refer to the old buffer. */
+    nwritten = (ssize_t)len - (ssize_t)stream->upload_len;
     stream->upload_mem = NULL;
     stream->upload_mem = NULL;
     stream->upload_len = 0;
     stream->upload_len = 0;
 
 
     if(should_close_session(ctx)) {
     if(should_close_session(ctx)) {
       DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
       DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
       *err = CURLE_HTTP2;
       *err = CURLE_HTTP2;
-      len = -1;
+      nwritten = -1;
       goto out;
       goto out;
     }
     }
 
 
@@ -2029,26 +2045,36 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
       nghttp2_session_resume_data(ctx->h2, stream->stream_id);
       nghttp2_session_resume_data(ctx->h2, stream->stream_id);
     }
     }
 
 
-#ifdef DEBUG_HTTP2
-    if(!len) {
-      infof(data, "http2_send: easy %p (stream %u) win %u/%u",
-            data, stream->stream_id,
-            nghttp2_session_get_remote_window_size(ctx->h2),
-            nghttp2_session_get_stream_remote_window_size(ctx->h2,
-                                                          stream->stream_id)
-        );
-
+    if(!nwritten) {
+      size_t rwin = nghttp2_session_get_stream_remote_window_size(ctx->h2,
+                                                          stream->stream_id);
+      DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_send: win %u/%zu",
+             stream->stream_id,
+             nghttp2_session_get_remote_window_size(ctx->h2), rwin));
+        if(rwin == 0) {
+          /* We cannot upload more as the stream's remote window size
+           * is 0. We need to receive WIN_UPDATEs before we can continue.
+           */
+          data->req.keepon |= KEEP_SEND_HOLD;
+          DEBUGF(LOG_CF(data, cf, "[h2sid=%u] holding send as remote flow "
+                 "window is exhausted", stream->stream_id));
+        }
     }
     }
-    infof(data, "http2_send returns %zu for stream %u", len,
-          stream->stream_id);
-#endif
+    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_send returns %zd ",
+           stream->stream_id, nwritten));
+
+    /* handled writing BODY for open stream. */
     goto out;
     goto out;
   }
   }
-
+  /* Stream has not been opened yet. `buf` is expected to contain
+   * request headers. */
+  /* TODO: this assumes that the `buf` and `len` we are called with
+   * is *all* HEADERs and no body. We have no way to determine here
+   * if that is indeed the case. */
   result = Curl_pseudo_headers(data, buf, len, NULL, &hreq);
   result = Curl_pseudo_headers(data, buf, len, NULL, &hreq);
   if(result) {
   if(result) {
     *err = result;
     *err = result;
-    len = -1;
+    nwritten = -1;
     goto out;
     goto out;
   }
   }
   nheader = hreq->entries;
   nheader = hreq->entries;
@@ -2057,7 +2083,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
   if(!nva) {
   if(!nva) {
     Curl_pseudo_free(hreq);
     Curl_pseudo_free(hreq);
     *err = CURLE_OUT_OF_MEMORY;
     *err = CURLE_OUT_OF_MEMORY;
-    len = -1;
+    nwritten = -1;
     goto out;
     goto out;
   }
   }
   else {
   else {
@@ -2104,25 +2130,28 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
     DEBUGF(LOG_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
     DEBUGF(LOG_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
                   nghttp2_strerror(stream_id), stream_id));
                   nghttp2_strerror(stream_id), stream_id));
     *err = CURLE_SEND_ERROR;
     *err = CURLE_SEND_ERROR;
-    len = -1;
+    nwritten = -1;
     goto out;
     goto out;
   }
   }
 
 
   infof(data, "Using Stream ID: %u (easy handle %p)",
   infof(data, "Using Stream ID: %u (easy handle %p)",
         stream_id, (void *)data);
         stream_id, (void *)data);
   stream->stream_id = stream_id;
   stream->stream_id = stream_id;
+  /* See TODO above. We assume that the whole buf was consumed by
+   * generating the request headers. */
+  nwritten = len;
 
 
   result = h2_session_send(cf, data);
   result = h2_session_send(cf, data);
   if(result) {
   if(result) {
     *err = result;
     *err = result;
-    len = -1;
+    nwritten = -1;
     goto out;
     goto out;
   }
   }
 
 
   if(should_close_session(ctx)) {
   if(should_close_session(ctx)) {
     DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
     DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
     *err = CURLE_HTTP2;
     *err = CURLE_HTTP2;
-    len = -1;
+    nwritten = -1;
     goto out;
     goto out;
   }
   }
 
 
@@ -2137,7 +2166,7 @@ static ssize_t cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data,
 
 
 out:
 out:
   CF_DATA_RESTORE(cf, save);
   CF_DATA_RESTORE(cf, save);
-  return len;
+  return nwritten;
 }
 }
 
 
 static int cf_h2_get_select_socks(struct Curl_cfilter *cf,
 static int cf_h2_get_select_socks(struct Curl_cfilter *cf,
@@ -2160,7 +2189,7 @@ static int cf_h2_get_select_socks(struct Curl_cfilter *cf,
 
 
   /* we're (still uploading OR the HTTP/2 layer wants to send data) AND
   /* we're (still uploading OR the HTTP/2 layer wants to send data) AND
      there's a window to send data in */
      there's a window to send data in */
-  if((((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
+  if((((k->keepon & KEEP_SENDBITS) == KEEP_SEND) ||
       nghttp2_session_want_write(ctx->h2)) &&
       nghttp2_session_want_write(ctx->h2)) &&
      (nghttp2_session_get_remote_window_size(ctx->h2) &&
      (nghttp2_session_get_remote_window_size(ctx->h2) &&
       nghttp2_session_get_stream_remote_window_size(ctx->h2,
       nghttp2_session_get_stream_remote_window_size(ctx->h2,
@@ -2329,14 +2358,17 @@ static bool cf_h2_data_pending(struct Curl_cfilter *cf,
 }
 }
 
 
 static bool cf_h2_is_alive(struct Curl_cfilter *cf,
 static bool cf_h2_is_alive(struct Curl_cfilter *cf,
-                           struct Curl_easy *data)
+                           struct Curl_easy *data,
+                           bool *input_pending)
 {
 {
   struct cf_h2_ctx *ctx = cf->ctx;
   struct cf_h2_ctx *ctx = cf->ctx;
   CURLcode result;
   CURLcode result;
   struct cf_call_data save;
   struct cf_call_data save;
 
 
   CF_DATA_SAVE(save, cf, data);
   CF_DATA_SAVE(save, cf, data);
-  result = (ctx && ctx->h2 && !http2_connisdead(cf, data));
+  result = (ctx && ctx->h2 && http2_connisalive(cf, data, input_pending));
+  DEBUGF(LOG_CF(data, cf, "conn alive -> %d, input_pending=%d",
+         result, *input_pending));
   CF_DATA_RESTORE(cf, save);
   CF_DATA_RESTORE(cf, save);
   return result;
   return result;
 }
 }
@@ -2479,7 +2511,8 @@ bool Curl_http2_may_switch(struct Curl_easy *data,
                            int sockindex)
                            int sockindex)
 {
 {
   (void)sockindex;
   (void)sockindex;
-  if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+  if(!Curl_conn_is_http2(data, conn, sockindex) &&
+     data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
     if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
     if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
       /* We don't support HTTP/2 proxies yet. Also it's debatable
       /* We don't support HTTP/2 proxies yet. Also it's debatable

+ 135 - 55
Utilities/cmcurl/lib/http_aws_sigv4.c

@@ -58,13 +58,15 @@
 
 
 #define TIMESTAMP_SIZE 17
 #define TIMESTAMP_SIZE 17
 
 
-static void sha256_to_hex(char *dst, unsigned char *sha, size_t dst_l)
+/* hex-encoded with trailing null */
+#define SHA256_HEX_LENGTH (2 * SHA256_DIGEST_LENGTH + 1)
+
+static void sha256_to_hex(char *dst, unsigned char *sha)
 {
 {
   int i;
   int i;
 
 
-  DEBUGASSERT(dst_l >= 65);
-  for(i = 0; i < 32; ++i) {
-    msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]);
+  for(i = 0; i < SHA256_DIGEST_LENGTH; ++i) {
+    msnprintf(dst + (i * 2), SHA256_HEX_LENGTH - (i * 2), "%02x", sha[i]);
   }
   }
 }
 }
 
 
@@ -135,6 +137,7 @@ static CURLcode make_headers(struct Curl_easy *data,
                              char *timestamp,
                              char *timestamp,
                              char *provider1,
                              char *provider1,
                              char **date_header,
                              char **date_header,
+                             char *content_sha256_header,
                              struct dynbuf *canonical_headers,
                              struct dynbuf *canonical_headers,
                              struct dynbuf *signed_headers)
                              struct dynbuf *signed_headers)
 {
 {
@@ -189,6 +192,13 @@ static CURLcode make_headers(struct Curl_easy *data,
   }
   }
 
 
 
 
+  if (*content_sha256_header) {
+    tmp_head = curl_slist_append(head, content_sha256_header);
+    if(!tmp_head)
+      goto fail;
+    head = tmp_head;
+  }
+
   for(l = data->set.headers; l; l = l->next) {
   for(l = data->set.headers; l; l = l->next) {
     tmp_head = curl_slist_append(head, l->data);
     tmp_head = curl_slist_append(head, l->data);
     if(!tmp_head)
     if(!tmp_head)
@@ -267,6 +277,9 @@ fail:
 }
 }
 
 
 #define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256"))
 #define CONTENT_SHA256_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Content-Sha256"))
+/* add 2 for ": " between header name and value */
+#define CONTENT_SHA256_HDR_LEN (CONTENT_SHA256_KEY_LEN + 2 + \
+                                SHA256_HEX_LENGTH)
 
 
 /* try to parse a payload hash from the content-sha256 header */
 /* try to parse a payload hash from the content-sha256 header */
 static char *parse_content_sha_hdr(struct Curl_easy *data,
 static char *parse_content_sha_hdr(struct Curl_easy *data,
@@ -300,6 +313,63 @@ static char *parse_content_sha_hdr(struct Curl_easy *data,
   return value;
   return value;
 }
 }
 
 
+static CURLcode calc_payload_hash(struct Curl_easy *data,
+                                  unsigned char *sha_hash, char *sha_hex)
+{
+  const char *post_data = data->set.postfields;
+  size_t post_data_len = 0;
+  CURLcode result;
+
+  if(post_data) {
+    if(data->set.postfieldsize < 0)
+      post_data_len = strlen(post_data);
+    else
+      post_data_len = (size_t)data->set.postfieldsize;
+  }
+  result = Curl_sha256it(sha_hash, (const unsigned char *) post_data,
+                         post_data_len);
+  if(!result)
+    sha256_to_hex(sha_hex, sha_hash);
+  return result;
+}
+
+#define S3_UNSIGNED_PAYLOAD "UNSIGNED-PAYLOAD"
+
+static CURLcode calc_s3_payload_hash(struct Curl_easy *data,
+                                     Curl_HttpReq httpreq, char *provider1,
+                                     unsigned char *sha_hash,
+                                     char *sha_hex, char *header)
+{
+  bool empty_method = (httpreq == HTTPREQ_GET || httpreq == HTTPREQ_HEAD);
+  /* The request method or filesize indicate no request payload */
+  bool empty_payload = (empty_method || data->set.filesize == 0);
+  /* The POST payload is in memory */
+  bool post_payload = (httpreq == HTTPREQ_POST && data->set.postfields);
+  CURLcode ret = CURLE_OUT_OF_MEMORY;
+
+  if(empty_payload || post_payload) {
+    /* Calculate a real hash when we know the request payload */
+    ret = calc_payload_hash(data, sha_hash, sha_hex);
+    if(ret)
+      goto fail;
+  }
+  else {
+    /* Fall back to s3's UNSIGNED-PAYLOAD */
+    size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1;
+    DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */
+    memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len);
+    sha_hex[len] = 0;
+  }
+
+  /* format the required content-sha256 header */
+  msnprintf(header, CONTENT_SHA256_HDR_LEN,
+            "x-%s-content-sha256: %s", provider1, sha_hex);
+
+  ret = CURLE_OK;
+fail:
+  return ret;
+}
+
 CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
 CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
 {
 {
   CURLcode ret = CURLE_OUT_OF_MEMORY;
   CURLcode ret = CURLE_OUT_OF_MEMORY;
@@ -310,6 +380,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   char provider1[MAX_SIGV4_LEN + 1]="";
   char provider1[MAX_SIGV4_LEN + 1]="";
   char region[MAX_SIGV4_LEN + 1]="";
   char region[MAX_SIGV4_LEN + 1]="";
   char service[MAX_SIGV4_LEN + 1]="";
   char service[MAX_SIGV4_LEN + 1]="";
+  bool sign_as_s3 = false;
   const char *hostname = conn->host.name;
   const char *hostname = conn->host.name;
   time_t clock;
   time_t clock;
   struct tm tm;
   struct tm tm;
@@ -318,20 +389,21 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   struct dynbuf canonical_headers;
   struct dynbuf canonical_headers;
   struct dynbuf signed_headers;
   struct dynbuf signed_headers;
   char *date_header = NULL;
   char *date_header = NULL;
+  Curl_HttpReq httpreq;
+  const char *method = NULL;
   char *payload_hash = NULL;
   char *payload_hash = NULL;
   size_t payload_hash_len = 0;
   size_t payload_hash_len = 0;
-  const char *post_data = data->set.postfields;
-  size_t post_data_len = 0;
-  unsigned char sha_hash[32];
-  char sha_hex[65];
+  unsigned char sha_hash[SHA256_DIGEST_LENGTH];
+  char sha_hex[SHA256_HEX_LENGTH];
+  char content_sha256_hdr[CONTENT_SHA256_HDR_LEN + 2] = ""; /* add \r\n */
   char *canonical_request = NULL;
   char *canonical_request = NULL;
   char *request_type = NULL;
   char *request_type = NULL;
   char *credential_scope = NULL;
   char *credential_scope = NULL;
   char *str_to_sign = NULL;
   char *str_to_sign = NULL;
   const char *user = data->state.aptr.user ? data->state.aptr.user : "";
   const char *user = data->state.aptr.user ? data->state.aptr.user : "";
   char *secret = NULL;
   char *secret = NULL;
-  unsigned char sign0[32] = {0};
-  unsigned char sign1[32] = {0};
+  unsigned char sign0[SHA256_DIGEST_LENGTH] = {0};
+  unsigned char sign1[SHA256_DIGEST_LENGTH] = {0};
   char *auth_headers = NULL;
   char *auth_headers = NULL;
 
 
   DEBUGASSERT(!proxy);
   DEBUGASSERT(!proxy);
@@ -408,6 +480,29 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
     }
     }
   }
   }
 
 
+  Curl_http_method(data, conn, &method, &httpreq);
+
+  /* AWS S3 requires a x-amz-content-sha256 header, and supports special
+   * values like UNSIGNED-PAYLOAD */
+  sign_as_s3 = (strcasecompare(provider0, "aws") &&
+                strcasecompare(service, "s3"));
+
+  payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len);
+
+  if(!payload_hash) {
+    if(sign_as_s3)
+      ret = calc_s3_payload_hash(data, httpreq, provider1, sha_hash,
+                                 sha_hex, content_sha256_hdr);
+    else
+      ret = calc_payload_hash(data, sha_hash, sha_hex);
+    if(ret)
+      goto fail;
+
+    payload_hash = sha_hex;
+    /* may be shorter than SHA256_HEX_LENGTH, like S3_UNSIGNED_PAYLOAD */
+    payload_hash_len = strlen(sha_hex);
+  }
+
 #ifdef DEBUGBUILD
 #ifdef DEBUGBUILD
   {
   {
     char *force_timestamp = getenv("CURL_FORCETIME");
     char *force_timestamp = getenv("CURL_FORCETIME");
@@ -429,54 +524,37 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   }
   }
 
 
   ret = make_headers(data, hostname, timestamp, provider1,
   ret = make_headers(data, hostname, timestamp, provider1,
-                     &date_header, &canonical_headers, &signed_headers);
+                     &date_header, content_sha256_hdr,
+                     &canonical_headers, &signed_headers);
   if(ret)
   if(ret)
     goto fail;
     goto fail;
   ret = CURLE_OUT_OF_MEMORY;
   ret = CURLE_OUT_OF_MEMORY;
 
 
+  if(*content_sha256_hdr) {
+    /* make_headers() needed this without the \r\n for canonicalization */
+    size_t hdrlen = strlen(content_sha256_hdr);
+    DEBUGASSERT(hdrlen + 3 < sizeof(content_sha256_hdr));
+    memcpy(content_sha256_hdr + hdrlen, "\r\n", 3);
+  }
+
   memcpy(date, timestamp, sizeof(date));
   memcpy(date, timestamp, sizeof(date));
   date[sizeof(date) - 1] = 0;
   date[sizeof(date) - 1] = 0;
 
 
-  payload_hash = parse_content_sha_hdr(data, provider1, &payload_hash_len);
-
-  if(!payload_hash) {
-    if(post_data) {
-      if(data->set.postfieldsize < 0)
-        post_data_len = strlen(post_data);
-      else
-        post_data_len = (size_t)data->set.postfieldsize;
-    }
-    if(Curl_sha256it(sha_hash, (const unsigned char *) post_data,
-                     post_data_len))
-      goto fail;
-
-    sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
-    payload_hash = sha_hex;
-    payload_hash_len = strlen(sha_hex);
-  }
-
-  {
-    Curl_HttpReq httpreq;
-    const char *method;
-
-    Curl_http_method(data, conn, &method, &httpreq);
-
-    canonical_request =
-      curl_maprintf("%s\n" /* HTTPRequestMethod */
-                    "%s\n" /* CanonicalURI */
-                    "%s\n" /* CanonicalQueryString */
-                    "%s\n" /* CanonicalHeaders */
-                    "%s\n" /* SignedHeaders */
-                    "%.*s",  /* HashedRequestPayload in hex */
-                    method,
-                    data->state.up.path,
-                    data->state.up.query ? data->state.up.query : "",
-                    Curl_dyn_ptr(&canonical_headers),
-                    Curl_dyn_ptr(&signed_headers),
-                    (int)payload_hash_len, payload_hash);
-    if(!canonical_request)
-      goto fail;
-  }
+  canonical_request =
+    curl_maprintf("%s\n" /* HTTPRequestMethod */
+                  "%s\n" /* CanonicalURI */
+                  "%s\n" /* CanonicalQueryString */
+                  "%s\n" /* CanonicalHeaders */
+                  "%s\n" /* SignedHeaders */
+                  "%.*s",  /* HashedRequestPayload in hex */
+                  method,
+                  data->state.up.path,
+                  data->state.up.query ? data->state.up.query : "",
+                  Curl_dyn_ptr(&canonical_headers),
+                  Curl_dyn_ptr(&signed_headers),
+                  (int)payload_hash_len, payload_hash);
+  if(!canonical_request)
+    goto fail;
 
 
   /* provider 0 lowercase */
   /* provider 0 lowercase */
   Curl_strntolower(provider0, provider0, strlen(provider0));
   Curl_strntolower(provider0, provider0, strlen(provider0));
@@ -493,7 +571,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
                    strlen(canonical_request)))
                    strlen(canonical_request)))
     goto fail;
     goto fail;
 
 
-  sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+  sha256_to_hex(sha_hex, sha_hash);
 
 
   /* provider 0 uppercase */
   /* provider 0 uppercase */
   Curl_strntoupper(provider0, provider0, strlen(provider0));
   Curl_strntoupper(provider0, provider0, strlen(provider0));
@@ -527,20 +605,22 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
   HMAC_SHA256(sign0, sizeof(sign0), request_type, strlen(request_type), sign1);
   HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
   HMAC_SHA256(sign1, sizeof(sign1), str_to_sign, strlen(str_to_sign), sign0);
 
 
-  sha256_to_hex(sha_hex, sign0, sizeof(sha_hex));
+  sha256_to_hex(sha_hex, sign0);
 
 
   /* provider 0 uppercase */
   /* provider 0 uppercase */
   auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
   auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
                                "Credential=%s/%s, "
                                "Credential=%s/%s, "
                                "SignedHeaders=%s, "
                                "SignedHeaders=%s, "
                                "Signature=%s\r\n"
                                "Signature=%s\r\n"
-                               "%s\r\n",
+                               "%s\r\n"
+                               "%s", /* optional sha256 header includes \r\n */
                                provider0,
                                provider0,
                                user,
                                user,
                                credential_scope,
                                credential_scope,
                                Curl_dyn_ptr(&signed_headers),
                                Curl_dyn_ptr(&signed_headers),
                                sha_hex,
                                sha_hex,
-                               date_header);
+                               date_header,
+                               content_sha256_hdr);
   if(!auth_headers) {
   if(!auth_headers) {
     goto fail;
     goto fail;
   }
   }

+ 7 - 5
Utilities/cmcurl/lib/http_proxy.c

@@ -403,7 +403,6 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   struct SingleRequest *k = &data->req;
   struct SingleRequest *k = &data->req;
-  int subversion = 0;
   (void)cf;
   (void)cf;
 
 
   if((checkprefix("WWW-Authenticate:", header) &&
   if((checkprefix("WWW-Authenticate:", header) &&
@@ -461,11 +460,14 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
                              STRCONST("Proxy-Connection:"),
                              STRCONST("Proxy-Connection:"),
                              STRCONST("close")))
                              STRCONST("close")))
     ts->close_connection = TRUE;
     ts->close_connection = TRUE;
-  else if(2 == sscanf(header, "HTTP/1.%d %d",
-                      &subversion,
-                      &k->httpcode)) {
+  else if(!strncmp(header, "HTTP/1.", 7) &&
+          ((header[7] == '0') || (header[7] == '1')) &&
+          (header[8] == ' ') &&
+          ISDIGIT(header[9]) && ISDIGIT(header[10]) && ISDIGIT(header[11]) &&
+          !ISDIGIT(header[12])) {
     /* store the HTTP code from the proxy */
     /* store the HTTP code from the proxy */
-    data->info.httpproxycode = k->httpcode;
+    data->info.httpproxycode =  k->httpcode = (header[9] - '0') * 100 +
+      (header[10] - '0') * 10 + (header[11] - '0');
   }
   }
   return result;
   return result;
 }
 }

+ 5 - 0
Utilities/cmcurl/lib/idn.c

@@ -184,6 +184,11 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host)
   if(!Curl_is_ASCII_name(host->name)) {
   if(!Curl_is_ASCII_name(host->name)) {
     char *decoded = idn_decode(host->name);
     char *decoded = idn_decode(host->name);
     if(decoded) {
     if(decoded) {
+      if(!*decoded) {
+        /* zero length is a bad host name */
+        Curl_idn_free(decoded);
+        return CURLE_URL_MALFORMAT;
+      }
       /* successful */
       /* successful */
       host->encalloc = decoded;
       host->encalloc = decoded;
       /* change the name pointer to point to the encoded hostname */
       /* change the name pointer to point to the encoded hostname */

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

@@ -41,6 +41,15 @@
 #define INADDRSZ         4
 #define INADDRSZ         4
 #define INT16SZ          2
 #define INT16SZ          2
 
 
+/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
 /*
 /*
  * Format an IPv4 address, more or less like inet_ntop().
  * Format an IPv4 address, more or less like inet_ntop().
  *
  *
@@ -72,7 +81,6 @@ static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
   return dst;
   return dst;
 }
 }
 
 
-#ifdef ENABLE_IPV6
 /*
 /*
  * Convert IPv6 binary address into presentation (printable) format.
  * Convert IPv6 binary address into presentation (printable) format.
  */
  */
@@ -168,7 +176,6 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
   strcpy(dst, tmp);
   strcpy(dst, tmp);
   return dst;
   return dst;
 }
 }
-#endif  /* ENABLE_IPV6 */
 
 
 /*
 /*
  * Convert a network format address to presentation format.
  * Convert a network format address to presentation format.
@@ -187,10 +194,8 @@ char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
   switch(af) {
   switch(af) {
   case AF_INET:
   case AF_INET:
     return inet_ntop4((const unsigned char *)src, buf, size);
     return inet_ntop4((const unsigned char *)src, buf, size);
-#ifdef ENABLE_IPV6
   case AF_INET6:
   case AF_INET6:
     return inet_ntop6((const unsigned char *)src, buf, size);
     return inet_ntop6((const unsigned char *)src, buf, size);
-#endif
   default:
   default:
     errno = EAFNOSUPPORT;
     errno = EAFNOSUPPORT;
     return NULL;
     return NULL;

+ 9 - 6
Utilities/cmcurl/lib/inet_pton.c

@@ -38,15 +38,22 @@
 #define INADDRSZ         4
 #define INADDRSZ         4
 #define INT16SZ          2
 #define INT16SZ          2
 
 
+/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
 /*
 /*
  * WARNING: Don't even consider trying to compile this on a system where
  * WARNING: Don't even consider trying to compile this on a system where
  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
  */
  */
 
 
 static int      inet_pton4(const char *src, unsigned char *dst);
 static int      inet_pton4(const char *src, unsigned char *dst);
-#ifdef ENABLE_IPV6
 static int      inet_pton6(const char *src, unsigned char *dst);
 static int      inet_pton6(const char *src, unsigned char *dst);
-#endif
 
 
 /* int
 /* int
  * inet_pton(af, src, dst)
  * inet_pton(af, src, dst)
@@ -70,10 +77,8 @@ Curl_inet_pton(int af, const char *src, void *dst)
   switch(af) {
   switch(af) {
   case AF_INET:
   case AF_INET:
     return (inet_pton4(src, (unsigned char *)dst));
     return (inet_pton4(src, (unsigned char *)dst));
-#ifdef ENABLE_IPV6
   case AF_INET6:
   case AF_INET6:
     return (inet_pton6(src, (unsigned char *)dst));
     return (inet_pton6(src, (unsigned char *)dst));
-#endif
   default:
   default:
     errno = EAFNOSUPPORT;
     errno = EAFNOSUPPORT;
     return (-1);
     return (-1);
@@ -135,7 +140,6 @@ inet_pton4(const char *src, unsigned char *dst)
   return (1);
   return (1);
 }
 }
 
 
-#ifdef ENABLE_IPV6
 /* int
 /* int
  * inet_pton6(src, dst)
  * inet_pton6(src, dst)
  *      convert presentation level address to network order binary form.
  *      convert presentation level address to network order binary form.
@@ -234,6 +238,5 @@ inet_pton6(const char *src, unsigned char *dst)
   memcpy(dst, tmp, IN6ADDRSZ);
   memcpy(dst, tmp, IN6ADDRSZ);
   return (1);
   return (1);
 }
 }
-#endif /* ENABLE_IPV6 */
 
 
 #endif /* HAVE_INET_PTON */
 #endif /* HAVE_INET_PTON */

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

@@ -721,8 +721,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
     return 0;
     return 0;
 
 
   if(buf[3] != '-')
   if(buf[3] != '-')
-    /* safe to ignore return code */
-    (void)sscanf(buf, "%d", &ret_code);
+    ret_code = atoi(buf);
 
 
   if(buf[decoded_len - 1] == '\n')
   if(buf[decoded_len - 1] == '\n')
     buf[decoded_len - 1] = '\0';
     buf[decoded_len - 1] = '\0';
@@ -765,8 +764,9 @@ static int sec_set_protection_level(struct Curl_easy *data)
 
 
     pbsz = strstr(data->state.buffer, "PBSZ=");
     pbsz = strstr(data->state.buffer, "PBSZ=");
     if(pbsz) {
     if(pbsz) {
-      /* ignore return code, use default value if it fails */
-      (void)sscanf(pbsz, "PBSZ=%u", &buffer_size);
+      /* stick to default value if the check fails */
+      if(!strncmp(pbsz, "PBSZ=", 5) && ISDIGIT(pbsz[5]))
+        buffer_size = atoi(&pbsz[5]);
       if(buffer_size < conn->buffer_size)
       if(buffer_size < conn->buffer_size)
         conn->buffer_size = buffer_size;
         conn->buffer_size = buffer_size;
     }
     }

+ 8 - 0
Utilities/cmcurl/lib/ldap.c

@@ -140,6 +140,14 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp);
 #define ldap_err2string ldap_err2stringA
 #define ldap_err2string ldap_err2stringA
 #endif
 #endif
 
 
+#if defined(USE_WIN32_LDAP) && defined(_MSC_VER) && (_MSC_VER <= 1600)
+/* Workaround for warning:
+   'type cast' : conversion from 'int' to 'void *' of greater size */
+#undef LDAP_OPT_ON
+#undef LDAP_OPT_OFF
+#define LDAP_OPT_ON   ((void *)(size_t)1)
+#define LDAP_OPT_OFF  ((void *)(size_t)0)
+#endif
 
 
 static CURLcode ldap_do(struct Curl_easy *data, bool *done);
 static CURLcode ldap_do(struct Curl_easy *data, bool *done);
 
 

+ 3 - 2
Utilities/cmcurl/lib/mqtt.c

@@ -122,8 +122,9 @@ static CURLcode mqtt_send(struct Curl_easy *data,
   struct MQTT *mq = data->req.p.mqtt;
   struct MQTT *mq = data->req.p.mqtt;
   ssize_t n;
   ssize_t n;
   result = Curl_write(data, sockfd, buf, len, &n);
   result = Curl_write(data, sockfd, buf, len, &n);
-  if(!result)
-    Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
+  if(result)
+    return result;
+  Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
   if(len != (size_t)n) {
   if(len != (size_t)n) {
     size_t nsend = len - n;
     size_t nsend = len - n;
     char *sendleftovers = Curl_memdup(&buf[n], nsend);
     char *sendleftovers = Curl_memdup(&buf[n], nsend);

+ 57 - 46
Utilities/cmcurl/lib/multi.c

@@ -445,9 +445,6 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
   sockhash_destroy(&multi->sockhash);
   sockhash_destroy(&multi->sockhash);
   Curl_hash_destroy(&multi->hostcache);
   Curl_hash_destroy(&multi->hostcache);
   Curl_conncache_destroy(&multi->conn_cache);
   Curl_conncache_destroy(&multi->conn_cache);
-  Curl_llist_destroy(&multi->msglist, NULL);
-  Curl_llist_destroy(&multi->pending, NULL);
-
   free(multi);
   free(multi);
   return NULL;
   return NULL;
 }
 }
@@ -459,6 +456,42 @@ struct Curl_multi *curl_multi_init(void)
                            CURL_DNS_HASH_SIZE);
                            CURL_DNS_HASH_SIZE);
 }
 }
 
 
+static void link_easy(struct Curl_multi *multi,
+                      struct Curl_easy *data)
+{
+  /* We add the new easy entry last in the list. */
+  data->next = NULL; /* end of the line */
+  if(multi->easyp) {
+    struct Curl_easy *last = multi->easylp;
+    last->next = data;
+    data->prev = last;
+    multi->easylp = data; /* the new last node */
+  }
+  else {
+    /* first node, make prev NULL! */
+    data->prev = NULL;
+    multi->easylp = multi->easyp = data; /* both first and last */
+  }
+}
+
+/* unlink the given easy handle from the linked list of easy handles */
+static void unlink_easy(struct Curl_multi *multi,
+                        struct Curl_easy *data)
+{
+  /* make the previous node point to our next */
+  if(data->prev)
+    data->prev->next = data->next;
+  else
+    multi->easyp = data->next; /* point to first node */
+
+  /* make our next point to our previous node */
+  if(data->next)
+    data->next->prev = data->prev;
+  else
+    multi->easylp = data->prev; /* point to last node */
+}
+
+
 CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
 CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
                                 struct Curl_easy *data)
                                 struct Curl_easy *data)
 {
 {
@@ -554,19 +587,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
     data->psl = &multi->psl;
     data->psl = &multi->psl;
 #endif
 #endif
 
 
-  /* We add the new entry last in the list. */
-  data->next = NULL; /* end of the line */
-  if(multi->easyp) {
-    struct Curl_easy *last = multi->easylp;
-    last->next = data;
-    data->prev = last;
-    multi->easylp = data; /* the new last node */
-  }
-  else {
-    /* first node, make prev NULL! */
-    data->prev = NULL;
-    multi->easylp = multi->easyp = data; /* both first and last */
-  }
+  link_easy(multi, data);
 
 
   /* increase the node-counter */
   /* increase the node-counter */
   multi->num_easy++;
   multi->num_easy++;
@@ -841,10 +862,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
 
 
   Curl_wildcard_dtor(&data->wildcard);
   Curl_wildcard_dtor(&data->wildcard);
 
 
-  /* destroy the timeout list that is held in the easy handle, do this *after*
-     multi_done() as that may actually call Curl_expire that uses this */
-  Curl_llist_destroy(&data->state.timeoutlist, NULL);
-
   /* change state without using multistate(), only to make singlesocket() do
   /* change state without using multistate(), only to make singlesocket() do
      what we want */
      what we want */
   data->mstate = MSTATE_COMPLETED;
   data->mstate = MSTATE_COMPLETED;
@@ -917,17 +934,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
     }
     }
   }
   }
 
 
-  /* make the previous node point to our next */
-  if(data->prev)
-    data->prev->next = data->next;
-  else
-    multi->easyp = data->next; /* point to first node */
-
-  /* make our next point to our previous node */
-  if(data->next)
-    data->next->prev = data->prev;
-  else
-    multi->easylp = data->prev; /* point to last node */
+  unlink_easy(multi, data);
 
 
   /* NOTE NOTE NOTE
   /* NOTE NOTE NOTE
      We do not touch the easy handle here! */
      We do not touch the easy handle here! */
@@ -976,7 +983,7 @@ void Curl_attach_connection(struct Curl_easy *data,
   data->conn = conn;
   data->conn = conn;
   Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
   Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
                          &data->conn_queue);
                          &data->conn_queue);
-  if(conn->handler->attach)
+  if(conn->handler && conn->handler->attach)
     conn->handler->attach(data, conn);
     conn->handler->attach(data, conn);
   Curl_conn_ev_data_attach(conn, data);
   Curl_conn_ev_data_attach(conn, data);
 }
 }
@@ -2192,7 +2199,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 #ifndef CURL_DISABLE_FTP
 #ifndef CURL_DISABLE_FTP
             /* some steps needed for wildcard matching */
             /* some steps needed for wildcard matching */
             if(data->state.wildcardmatch) {
             if(data->state.wildcardmatch) {
-              struct WildcardData *wc = &data->wildcard;
+              struct WildcardData *wc = data->wildcard;
               if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
               if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
                 /* skip some states if it is important */
                 /* skip some states if it is important */
                 multi_done(data, CURLE_OK, FALSE);
                 multi_done(data, CURLE_OK, FALSE);
@@ -2344,7 +2351,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 #ifndef CURL_DISABLE_FTP
 #ifndef CURL_DISABLE_FTP
         if(data->state.wildcardmatch &&
         if(data->state.wildcardmatch &&
            ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
            ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
-          data->wildcard.state = CURLWC_DONE;
+          data->wildcard->state = CURLWC_DONE;
         }
         }
 #endif
 #endif
         multistate(data, MSTATE_DONE);
         multistate(data, MSTATE_DONE);
@@ -2574,7 +2581,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 
 
 #ifndef CURL_DISABLE_FTP
 #ifndef CURL_DISABLE_FTP
       if(data->state.wildcardmatch) {
       if(data->state.wildcardmatch) {
-        if(data->wildcard.state != CURLWC_DONE) {
+        if(data->wildcard->state != CURLWC_DONE) {
           /* if a wildcard is set and we are not ending -> lets start again
           /* if a wildcard is set and we are not ending -> lets start again
              with MSTATE_INIT */
              with MSTATE_INIT */
           multistate(data, MSTATE_INIT);
           multistate(data, MSTATE_INIT);
@@ -2706,18 +2713,25 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
     return CURLM_RECURSIVE_API_CALL;
     return CURLM_RECURSIVE_API_CALL;
 
 
   data = multi->easyp;
   data = multi->easyp;
-  while(data) {
+  if(data) {
     CURLMcode result;
     CURLMcode result;
+    bool nosig = data->set.no_signal;
     SIGPIPE_VARIABLE(pipe_st);
     SIGPIPE_VARIABLE(pipe_st);
-
     sigpipe_ignore(data, &pipe_st);
     sigpipe_ignore(data, &pipe_st);
-    result = multi_runsingle(multi, &now, data);
+    /* Do the loop and only alter the signal ignore state if the next handle
+       has a different NO_SIGNAL state than the previous */
+    do {
+      if(data->set.no_signal != nosig) {
+        sigpipe_restore(&pipe_st);
+        sigpipe_ignore(data, &pipe_st);
+        nosig = data->set.no_signal;
+      }
+      result = multi_runsingle(multi, &now, data);
+      if(result)
+        returncode = result;
+      data = data->next; /* operate on next handle */
+    } while(data);
     sigpipe_restore(&pipe_st);
     sigpipe_restore(&pipe_st);
-
-    if(result)
-      returncode = result;
-
-    data = data->next; /* operate on next handle */
   }
   }
 
 
   /*
   /*
@@ -2788,9 +2802,6 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
 
 
     sockhash_destroy(&multi->sockhash);
     sockhash_destroy(&multi->sockhash);
     Curl_conncache_destroy(&multi->conn_cache);
     Curl_conncache_destroy(&multi->conn_cache);
-    Curl_llist_destroy(&multi->msglist, NULL);
-    Curl_llist_destroy(&multi->pending, NULL);
-
     Curl_hash_destroy(&multi->hostcache);
     Curl_hash_destroy(&multi->hostcache);
     Curl_psl_destroy(&multi->psl);
     Curl_psl_destroy(&multi->psl);
 
 

+ 100 - 59
Utilities/cmcurl/lib/parsedate.c

@@ -212,56 +212,55 @@ static int checkday(const char *check, size_t len)
 {
 {
   int i;
   int i;
   const char * const *what;
   const char * const *what;
-  bool found = FALSE;
   if(len > 3)
   if(len > 3)
     what = &weekday[0];
     what = &weekday[0];
-  else
+  else if(len == 3)
     what = &Curl_wkday[0];
     what = &Curl_wkday[0];
+  else
+    return -1; /* too short */
   for(i = 0; i<7; i++) {
   for(i = 0; i<7; i++) {
-    if(strcasecompare(check, what[0])) {
-      found = TRUE;
-      break;
-    }
+    size_t ilen = strlen(what[0]);
+    if((ilen == len) &&
+       strncasecompare(check, what[0], len))
+      return i;
     what++;
     what++;
   }
   }
-  return found?i:-1;
+  return -1;
 }
 }
 
 
-static int checkmonth(const char *check)
+static int checkmonth(const char *check, size_t len)
 {
 {
   int i;
   int i;
-  const char * const *what;
-  bool found = FALSE;
+  const char * const *what = &Curl_month[0];
+  if(len != 3)
+    return -1; /* not a month */
 
 
-  what = &Curl_month[0];
   for(i = 0; i<12; i++) {
   for(i = 0; i<12; i++) {
-    if(strcasecompare(check, what[0])) {
-      found = TRUE;
-      break;
-    }
+    if(strncasecompare(check, what[0], 3))
+      return i;
     what++;
     what++;
   }
   }
-  return found?i:-1; /* return the offset or -1, no real offset is -1 */
+  return -1; /* return the offset or -1, no real offset is -1 */
 }
 }
 
 
 /* return the time zone offset between GMT and the input one, in number
 /* return the time zone offset between GMT and the input one, in number
    of seconds or -1 if the timezone wasn't found/legal */
    of seconds or -1 if the timezone wasn't found/legal */
 
 
-static int checktz(const char *check)
+static int checktz(const char *check, size_t len)
 {
 {
   unsigned int i;
   unsigned int i;
-  const struct tzinfo *what;
-  bool found = FALSE;
+  const struct tzinfo *what = tz;
+  if(len > 4) /* longer than any valid timezone */
+    return -1;
 
 
-  what = tz;
   for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
   for(i = 0; i< sizeof(tz)/sizeof(tz[0]); i++) {
-    if(strcasecompare(check, what->name)) {
-      found = TRUE;
-      break;
-    }
+    size_t ilen = strlen(what->name);
+    if((ilen == len) &&
+       strncasecompare(check, what->name, len))
+      return what->offset*60;
     what++;
     what++;
   }
   }
-  return found?what->offset*60:-1;
+  return -1;
 }
 }
 
 
 static void skip(const char **date)
 static void skip(const char **date)
@@ -294,6 +293,53 @@ static time_t time2epoch(int sec, int min, int hour,
            + hour) * 60 + min) * 60 + sec;
            + hour) * 60 + min) * 60 + sec;
 }
 }
 
 
+/* Returns the value of a single-digit or two-digit decimal number, return
+   then pointer to after the number. The 'date' pointer is known to point to a
+   digit. */
+static int oneortwodigit(const char *date, const char **endp)
+{
+  int num = date[0] - '0';
+  if(ISDIGIT(date[1])) {
+    *endp = &date[2];
+    return num*10 + (date[1] - '0');
+  }
+  *endp = &date[1];
+  return num;
+}
+
+
+/* HH:MM:SS or HH:MM and accept single-digits too */
+static bool match_time(const char *date,
+                       int *h, int *m, int *s, char **endp)
+{
+  const char *p;
+  int hh, mm, ss = 0;
+  hh = oneortwodigit(date, &p);
+  if((hh < 24) && (*p == ':') && ISDIGIT(p[1])) {
+    mm = oneortwodigit(&p[1], &p);
+    if(mm < 60) {
+      if((*p == ':') && ISDIGIT(p[1])) {
+        ss = oneortwodigit(&p[1], &p);
+        if(ss <= 60) {
+          /* valid HH:MM:SS */
+          goto match;
+        }
+      }
+      else {
+        /* valid HH:MM */
+        goto match;
+      }
+    }
+  }
+  return FALSE; /* not a time string */
+  match:
+  *h = hh;
+  *m = mm;
+  *s = ss;
+  *endp = (char *)p;
+  return TRUE;
+}
+
 /*
 /*
  * parsedate()
  * parsedate()
  *
  *
@@ -305,6 +351,9 @@ static time_t time2epoch(int sec, int min, int hour,
  * PARSEDATE_SOONER - time underflow at the low end of time_t
  * PARSEDATE_SOONER - time underflow at the low end of time_t
  */
  */
 
 
+/* Wednesday is the longest name this parser knows about */
+#define NAME_LEN 12
+
 static int parsedate(const char *date, time_t *output)
 static int parsedate(const char *date, time_t *output)
 {
 {
   time_t t = 0;
   time_t t = 0;
@@ -327,32 +376,32 @@ static int parsedate(const char *date, time_t *output)
 
 
     if(ISALPHA(*date)) {
     if(ISALPHA(*date)) {
       /* a name coming up */
       /* a name coming up */
-      char buf[32]="";
-      size_t len;
-      if(sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZ"
-                          "abcdefghijklmnopqrstuvwxyz]", buf))
-        len = strlen(buf);
-      else
-        len = 0;
-
-      if(wdaynum == -1) {
-        wdaynum = checkday(buf, len);
-        if(wdaynum != -1)
-          found = TRUE;
-      }
-      if(!found && (monnum == -1)) {
-        monnum = checkmonth(buf);
-        if(monnum != -1)
-          found = TRUE;
+      size_t len = 0;
+      const char *p = date;
+      while(ISALPHA(*p) && (len < NAME_LEN)) {
+        p++;
+        len++;
       }
       }
 
 
-      if(!found && (tzoff == -1)) {
-        /* this just must be a time zone string */
-        tzoff = checktz(buf);
-        if(tzoff != -1)
-          found = TRUE;
-      }
+      if(len != NAME_LEN) {
+        if(wdaynum == -1) {
+          wdaynum = checkday(date, len);
+          if(wdaynum != -1)
+            found = TRUE;
+        }
+        if(!found && (monnum == -1)) {
+          monnum = checkmonth(date, len);
+          if(monnum != -1)
+            found = TRUE;
+        }
 
 
+        if(!found && (tzoff == -1)) {
+          /* this just must be a time zone string */
+          tzoff = checktz(date, len);
+          if(tzoff != -1)
+            found = TRUE;
+        }
+      }
       if(!found)
       if(!found)
         return PARSEDATE_FAIL; /* bad string */
         return PARSEDATE_FAIL; /* bad string */
 
 
@@ -362,18 +411,10 @@ static int parsedate(const char *date, time_t *output)
       /* a digit */
       /* a digit */
       int val;
       int val;
       char *end;
       char *end;
-      int len = 0;
       if((secnum == -1) &&
       if((secnum == -1) &&
-         (3 == sscanf(date, "%02d:%02d:%02d%n",
-                      &hournum, &minnum, &secnum, &len))) {
-        /* time stamp! */
-        date += len;
-      }
-      else if((secnum == -1) &&
-              (2 == sscanf(date, "%02d:%02d%n", &hournum, &minnum, &len))) {
-        /* time stamp without seconds */
-        date += len;
-        secnum = 0;
+         match_time(date, &hournum, &minnum, &secnum, &end)) {
+        /* time stamp */
+        date = end;
       }
       }
       else {
       else {
         long lval;
         long lval;

+ 2 - 11
Utilities/cmcurl/lib/progress.c

@@ -87,8 +87,6 @@ static char *max5data(curl_off_t bytes, char *max5)
               CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
               CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
               (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
               (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
 
 
-#if (SIZEOF_CURL_OFF_T > 4)
-
   else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
   else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
     /* 'XXXXM' is good until we're at 10000MB or above */
     /* 'XXXXM' is good until we're at 10000MB or above */
     msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
     msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
@@ -111,15 +109,8 @@ static char *max5data(curl_off_t bytes, char *max5)
     /* up to 10000PB, display without decimal: XXXXP */
     /* up to 10000PB, display without decimal: XXXXP */
     msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
     msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "P", bytes/ONE_PETABYTE);
 
 
-    /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number
-       can hold, but our data type is signed so 8192PB will be the maximum. */
-
-#else
-
-  else
-    msnprintf(max5, 6, "%4" CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE);
-
-#endif
+  /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number can
+     hold, but our data type is signed so 8192PB will be the maximum. */
 
 
   return max5;
   return max5;
 }
 }

+ 9 - 0
Utilities/cmcurl/lib/rand.c

@@ -30,6 +30,10 @@
 #ifdef HAVE_ARPA_INET_H
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 #endif
 #endif
+#ifdef HAVE_ARC4RANDOM
+/* Some platforms might have the prototype missing (ubuntu + libressl) */
+uint32_t arc4random(void);
+#endif
 
 
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include "vtls/vtls.h"
 #include "vtls/vtls.h"
@@ -143,6 +147,11 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
   }
   }
 #endif
 #endif
 
 
+#ifdef HAVE_ARC4RANDOM
+  *rnd = (unsigned int)arc4random();
+  return CURLE_OK;
+#endif
+
 #if defined(RANDOM_FILE) && !defined(WIN32)
 #if defined(RANDOM_FILE) && !defined(WIN32)
   if(!seeded) {
   if(!seeded) {
     /* if there's a random file to read a seed from, use it */
     /* if there's a random file to read a seed from, use it */

+ 9 - 6
Utilities/cmcurl/lib/rtsp.c

@@ -145,7 +145,8 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data,
   (void)data;
   (void)data;
 
 
   if(checks_to_perform & CONNCHECK_ISDEAD) {
   if(checks_to_perform & CONNCHECK_ISDEAD) {
-    if(!Curl_conn_is_alive(data, conn))
+    bool input_pending;
+    if(!Curl_conn_is_alive(data, conn, &input_pending))
       ret_val |= CONNRESULT_DEAD;
       ret_val |= CONNRESULT_DEAD;
   }
   }
 
 
@@ -755,12 +756,14 @@ CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len)
 
 
 CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
 CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
 {
 {
-  long CSeq = 0;
-
   if(checkprefix("CSeq:", header)) {
   if(checkprefix("CSeq:", header)) {
-    /* Store the received CSeq. Match is verified in rtsp_done */
-    int nc = sscanf(&header[4], ": %ld", &CSeq);
-    if(nc == 1) {
+    long CSeq = 0;
+    char *endp;
+    char *p = &header[5];
+    while(ISBLANK(*p))
+      p++;
+    CSeq = strtol(p, &endp, 10);
+    if(p != endp) {
       struct RTSP *rtsp = data->req.p.rtsp;
       struct RTSP *rtsp = data->req.p.rtsp;
       rtsp->CSeq_recv = CSeq; /* mark the request */
       rtsp->CSeq_recv = CSeq; /* mark the request */
       data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
       data->state.rtsp_CSeq_recv = CSeq; /* update the handle */

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

@@ -230,14 +230,14 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
   if(readfd0 != CURL_SOCKET_BAD) {
   if(readfd0 != CURL_SOCKET_BAD) {
     if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
     if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
       r |= CURL_CSELECT_IN;
       r |= CURL_CSELECT_IN;
-    if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+    if(pfd[num].revents & (POLLPRI|POLLNVAL))
       r |= CURL_CSELECT_ERR;
       r |= CURL_CSELECT_ERR;
     num++;
     num++;
   }
   }
   if(readfd1 != CURL_SOCKET_BAD) {
   if(readfd1 != CURL_SOCKET_BAD) {
     if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
     if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
       r |= CURL_CSELECT_IN2;
       r |= CURL_CSELECT_IN2;
-    if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+    if(pfd[num].revents & (POLLPRI|POLLNVAL))
       r |= CURL_CSELECT_ERR;
       r |= CURL_CSELECT_ERR;
     num++;
     num++;
   }
   }

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

@@ -899,7 +899,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     case CURL_HTTP_VERSION_NONE:
     case CURL_HTTP_VERSION_NONE:
 #ifdef USE_HTTP2
 #ifdef USE_HTTP2
       /* TODO: this seems an undesirable quirk to force a behaviour on
       /* TODO: this seems an undesirable quirk to force a behaviour on
-       * lower implementations that they should recognize independantly? */
+       * lower implementations that they should recognize independently? */
       arg = CURL_HTTP_VERSION_2TLS;
       arg = CURL_HTTP_VERSION_2TLS;
 #endif
 #endif
       /* accepted */
       /* accepted */
@@ -2369,7 +2369,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     arg = va_arg(param, long);
     arg = va_arg(param, long);
     if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST))
     if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST))
       return CURLE_BAD_FUNCTION_ARGUMENT;
       return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.use_ssl = (curl_usessl)arg;
+    data->set.use_ssl = (unsigned char)arg;
     break;
     break;
 
 
   case CURLOPT_SSL_OPTIONS:
   case CURLOPT_SSL_OPTIONS:
@@ -2849,7 +2849,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
     data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
     break;
     break;
   case CURLOPT_CHUNK_DATA:
   case CURLOPT_CHUNK_DATA:
-    data->wildcard.customptr = va_arg(param, void *);
+    data->set.wildcardptr = va_arg(param, void *);
     break;
     break;
   case CURLOPT_FNMATCH_DATA:
   case CURLOPT_FNMATCH_DATA:
     data->set.fnmatch_data = va_arg(param, void *);
     data->set.fnmatch_data = va_arg(param, void *);

+ 0 - 1
Utilities/cmcurl/lib/sigpipe.h

@@ -50,7 +50,6 @@ static void sigpipe_ignore(struct Curl_easy *data,
   if(!data->set.no_signal) {
   if(!data->set.no_signal) {
     struct sigaction action;
     struct sigaction action;
     /* first, extract the existing situation */
     /* first, extract the existing situation */
-    memset(&ig->old_pipe_act, 0, sizeof(struct sigaction));
     sigaction(SIGPIPE, NULL, &ig->old_pipe_act);
     sigaction(SIGPIPE, NULL, &ig->old_pipe_act);
     action = ig->old_pipe_act;
     action = ig->old_pipe_act;
     /* ignore this signal */
     /* ignore this signal */

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

@@ -25,8 +25,7 @@
 
 
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
-#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) &&  \
-  (SIZEOF_CURL_OFF_T > 4)
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
 
 
 #define BUILDING_CURL_SMB_C
 #define BUILDING_CURL_SMB_C
 
 

+ 109 - 70
Utilities/cmcurl/lib/telnet.c

@@ -770,22 +770,32 @@ static void printsub(struct Curl_easy *data,
   }
   }
 }
 }
 
 
+static bool str_is_nonascii(const char *str)
+{
+  size_t len = strlen(str);
+  while(len--) {
+    if(*str & 0x80)
+      return TRUE;
+    str++;
+  }
+  return FALSE;
+}
+
 static CURLcode check_telnet_options(struct Curl_easy *data)
 static CURLcode check_telnet_options(struct Curl_easy *data)
 {
 {
   struct curl_slist *head;
   struct curl_slist *head;
   struct curl_slist *beg;
   struct curl_slist *beg;
-  char option_keyword[128] = "";
-  char option_arg[256] = "";
   struct TELNET *tn = data->req.p.telnet;
   struct TELNET *tn = data->req.p.telnet;
-  struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
-  int binary_option;
 
 
   /* Add the user name as an environment variable if it
   /* Add the user name as an environment variable if it
      was given on the command line */
      was given on the command line */
   if(data->state.aptr.user) {
   if(data->state.aptr.user) {
-    msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
-    beg = curl_slist_append(tn->telnet_vars, option_arg);
+    char buffer[256];
+    if(str_is_nonascii(data->conn->user))
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    msnprintf(buffer, sizeof(buffer), "USER,%s", data->conn->user);
+    beg = curl_slist_append(tn->telnet_vars, buffer);
     if(!beg) {
     if(!beg) {
       curl_slist_free_all(tn->telnet_vars);
       curl_slist_free_all(tn->telnet_vars);
       tn->telnet_vars = NULL;
       tn->telnet_vars = NULL;
@@ -795,68 +805,100 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
     tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
   }
   }
 
 
-  for(head = data->set.telnet_options; head; head = head->next) {
-    if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
-              option_keyword, option_arg) == 2) {
-
-      /* Terminal type */
-      if(strcasecompare(option_keyword, "TTYPE")) {
-        strncpy(tn->subopt_ttype, option_arg, 31);
-        tn->subopt_ttype[31] = 0; /* String termination */
-        tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+  for(head = data->set.telnet_options; head && !result; head = head->next) {
+    size_t olen;
+    char *option = head->data;
+    char *arg;
+    char *sep = strchr(option, '=');
+    if(sep) {
+      olen = sep - option;
+      arg = ++sep;
+      if(str_is_nonascii(arg))
         continue;
         continue;
-      }
+      switch(olen) {
+      case 5:
+        /* Terminal type */
+        if(strncasecompare(option, "TTYPE", 5)) {
+          strncpy(tn->subopt_ttype, arg, 31);
+          tn->subopt_ttype[31] = 0; /* String termination */
+          tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+        }
+        else
+          result = CURLE_UNKNOWN_OPTION;
+        break;
 
 
-      /* Display variable */
-      if(strcasecompare(option_keyword, "XDISPLOC")) {
-        strncpy(tn->subopt_xdisploc, option_arg, 127);
-        tn->subopt_xdisploc[127] = 0; /* String termination */
-        tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
-        continue;
-      }
+      case 8:
+        /* Display variable */
+        if(strncasecompare(option, "XDISPLOC", 8)) {
+          strncpy(tn->subopt_xdisploc, arg, 127);
+          tn->subopt_xdisploc[127] = 0; /* String termination */
+          tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
+        }
+        else
+          result = CURLE_UNKNOWN_OPTION;
+        break;
 
 
-      /* Environment variable */
-      if(strcasecompare(option_keyword, "NEW_ENV")) {
-        beg = curl_slist_append(tn->telnet_vars, option_arg);
-        if(!beg) {
-          result = CURLE_OUT_OF_MEMORY;
-          break;
+      case 7:
+        /* Environment variable */
+        if(strncasecompare(option, "NEW_ENV", 7)) {
+          beg = curl_slist_append(tn->telnet_vars, arg);
+          if(!beg) {
+            result = CURLE_OUT_OF_MEMORY;
+            break;
+          }
+          tn->telnet_vars = beg;
+          tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
         }
         }
-        tn->telnet_vars = beg;
-        tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
-        continue;
-      }
+        else
+          result = CURLE_UNKNOWN_OPTION;
+        break;
 
 
-      /* Window Size */
-      if(strcasecompare(option_keyword, "WS")) {
-        if(sscanf(option_arg, "%hu%*[xX]%hu",
-                  &tn->subopt_wsx, &tn->subopt_wsy) == 2)
-          tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
-        else {
-          failf(data, "Syntax error in telnet option: %s", head->data);
-          result = CURLE_SETOPT_OPTION_SYNTAX;
-          break;
+      case 2:
+        /* Window Size */
+        if(strncasecompare(option, "WS", 2)) {
+          char *p;
+          unsigned long x = strtoul(arg, &p, 10);
+          unsigned long y = 0;
+          if(x && (x <= 0xffff) && Curl_raw_tolower(*p) == 'x') {
+            p++;
+            y = strtoul(p, NULL, 10);
+            if(y && (y <= 0xffff)) {
+              tn->subopt_wsx = (unsigned short)x;
+              tn->subopt_wsy = (unsigned short)y;
+              tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
+            }
+          }
+          if(!y) {
+            failf(data, "Syntax error in telnet option: %s", head->data);
+            result = CURLE_SETOPT_OPTION_SYNTAX;
+          }
         }
         }
-        continue;
-      }
+        else
+          result = CURLE_UNKNOWN_OPTION;
+        break;
 
 
-      /* To take care or not of the 8th bit in data exchange */
-      if(strcasecompare(option_keyword, "BINARY")) {
-        binary_option = atoi(option_arg);
-        if(binary_option != 1) {
-          tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
-          tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+      case 6:
+        /* To take care or not of the 8th bit in data exchange */
+        if(strncasecompare(option, "BINARY", 6)) {
+          int binary_option = atoi(arg);
+          if(binary_option != 1) {
+            tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+            tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+          }
         }
         }
-        continue;
+        else
+          result = CURLE_UNKNOWN_OPTION;
+        break;
+      default:
+        failf(data, "Unknown telnet option %s", head->data);
+        result = CURLE_UNKNOWN_OPTION;
+        break;
       }
       }
-
-      failf(data, "Unknown telnet option %s", head->data);
-      result = CURLE_UNKNOWN_OPTION;
-      break;
     }
     }
-    failf(data, "Syntax error in telnet option: %s", head->data);
-    result = CURLE_SETOPT_OPTION_SYNTAX;
-    break;
+    else {
+      failf(data, "Syntax error in telnet option: %s", head->data);
+      result = CURLE_SETOPT_OPTION_SYNTAX;
+    }
   }
   }
 
 
   if(result) {
   if(result) {
@@ -881,8 +923,6 @@ static void suboption(struct Curl_easy *data)
   ssize_t bytes_written;
   ssize_t bytes_written;
   size_t len;
   size_t len;
   int err;
   int err;
-  char varname[128] = "";
-  char varval[128] = "";
   struct TELNET *tn = data->req.p.telnet;
   struct TELNET *tn = data->req.p.telnet;
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
 
 
@@ -920,19 +960,18 @@ static void suboption(struct Curl_easy *data)
 
 
       for(v = tn->telnet_vars; v; v = v->next) {
       for(v = tn->telnet_vars; v; v = v->next) {
         size_t tmplen = (strlen(v->data) + 1);
         size_t tmplen = (strlen(v->data) + 1);
-        /* Add the variable only if it fits */
+        /* Add the variable if it fits */
         if(len + tmplen < (int)sizeof(temp)-6) {
         if(len + tmplen < (int)sizeof(temp)-6) {
-          int rv;
-          char sep[2] = "";
-          varval[0] = 0;
-          rv = sscanf(v->data, "%127[^,]%1[,]%127s", varname, sep, varval);
-          if(rv == 1)
+          char *s = strchr(v->data, ',');
+          if(!s)
             len += msnprintf((char *)&temp[len], sizeof(temp) - len,
             len += msnprintf((char *)&temp[len], sizeof(temp) - len,
-                             "%c%s", CURL_NEW_ENV_VAR, varname);
-          else if(rv >= 2)
+                             "%c%s", CURL_NEW_ENV_VAR, v->data);
+          else {
+            size_t vlen = s - v->data;
             len += msnprintf((char *)&temp[len], sizeof(temp) - len,
             len += msnprintf((char *)&temp[len], sizeof(temp) - len,
-                             "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
-                             CURL_NEW_ENV_VALUE, varval);
+                             "%c%.*s%c%s", CURL_NEW_ENV_VAR,
+                             (int)vlen, v->data, CURL_NEW_ENV_VALUE, ++s);
+          }
         }
         }
       }
       }
       msnprintf((char *)&temp[len], sizeof(temp) - len,
       msnprintf((char *)&temp[len], sizeof(temp) - len,

+ 17 - 4
Utilities/cmcurl/lib/transfer.c

@@ -980,7 +980,15 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
     if(result)
     if(result)
       return result;
       return result;
 
 
-    win_update_buffer_size(conn->writesockfd);
+#if defined(WIN32) && defined(USE_WINSOCK)
+    {
+      struct curltime n = Curl_now();
+      if(Curl_timediff(n, k->last_sndbuf_update) > 1000) {
+        win_update_buffer_size(conn->writesockfd);
+        k->last_sndbuf_update = n;
+      }
+    }
+#endif
 
 
     if(k->pendingheader) {
     if(k->pendingheader) {
       /* parts of what was sent was header */
       /* parts of what was sent was header */
@@ -1226,8 +1234,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
   }
   }
 
 
   /* Now update the "done" boolean we return */
   /* Now update the "done" boolean we return */
-  *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND|
-                            KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE;
+  *done = (0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) ? TRUE : FALSE;
   result = CURLE_OK;
   result = CURLE_OK;
 out:
 out:
   if(result)
   if(result)
@@ -1394,7 +1401,13 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
 #ifndef CURL_DISABLE_FTP
 #ifndef CURL_DISABLE_FTP
     data->state.wildcardmatch = data->set.wildcard_enabled;
     data->state.wildcardmatch = data->set.wildcard_enabled;
     if(data->state.wildcardmatch) {
     if(data->state.wildcardmatch) {
-      struct WildcardData *wc = &data->wildcard;
+      struct WildcardData *wc;
+      if(!data->wildcard) {
+        data->wildcard = calloc(1, sizeof(struct WildcardData));
+        if(!data->wildcard)
+          return CURLE_OUT_OF_MEMORY;
+      }
+      wc = data->wildcard;
       if(wc->state < CURLWC_INIT) {
       if(wc->state < CURLWC_INIT) {
         result = Curl_wildcard_init(wc); /* init wildcard structures */
         result = Curl_wildcard_init(wc); /* init wildcard structures */
         if(result)
         if(result)

+ 48 - 48
Utilities/cmcurl/lib/url.c

@@ -288,33 +288,6 @@ static const struct Curl_handler * const protocols[] = {
   (struct Curl_handler *) NULL
   (struct Curl_handler *) NULL
 };
 };
 
 
-/*
- * Dummy handler for undefined protocol schemes.
- */
-
-static const struct Curl_handler Curl_handler_dummy = {
-  "<no protocol>",                      /* scheme */
-  ZERO_NULL,                            /* setup_connection */
-  ZERO_NULL,                            /* do_it */
-  ZERO_NULL,                            /* done */
-  ZERO_NULL,                            /* do_more */
-  ZERO_NULL,                            /* connect_it */
-  ZERO_NULL,                            /* connecting */
-  ZERO_NULL,                            /* doing */
-  ZERO_NULL,                            /* proto_getsock */
-  ZERO_NULL,                            /* doing_getsock */
-  ZERO_NULL,                            /* domore_getsock */
-  ZERO_NULL,                            /* perform_getsock */
-  ZERO_NULL,                            /* disconnect */
-  ZERO_NULL,                            /* readwrite */
-  ZERO_NULL,                            /* connection_check */
-  ZERO_NULL,                            /* attach connection */
-  0,                                    /* defport */
-  0,                                    /* protocol */
-  0,                                    /* family */
-  PROTOPT_NONE                          /* flags */
-};
-
 void Curl_freeset(struct Curl_easy *data)
 void Curl_freeset(struct Curl_easy *data)
 {
 {
   /* Free all dynamic strings stored in the data->set substructure. */
   /* Free all dynamic strings stored in the data->set substructure. */
@@ -341,6 +314,11 @@ void Curl_freeset(struct Curl_easy *data)
   data->state.url = NULL;
   data->state.url = NULL;
 
 
   Curl_mime_cleanpart(&data->set.mimepost);
   Curl_mime_cleanpart(&data->set.mimepost);
+
+#ifndef CURL_DISABLE_COOKIES
+  curl_slist_free_all(data->set.cookielist);
+  data->set.cookielist = NULL;
+#endif
 }
 }
 
 
 /* free the URL pieces */
 /* free the URL pieces */
@@ -431,9 +409,6 @@ CURLcode Curl_close(struct Curl_easy **datap)
   Curl_dyn_free(&data->state.headerb);
   Curl_dyn_free(&data->state.headerb);
   Curl_safefree(data->state.ulbuf);
   Curl_safefree(data->state.ulbuf);
   Curl_flush_cookies(data, TRUE);
   Curl_flush_cookies(data, TRUE);
-#ifndef CURL_DISABLE_COOKIES
-  curl_slist_free_all(data->set.cookielist); /* clean up list */
-#endif
   Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
   Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
   Curl_altsvc_cleanup(&data->asi);
   Curl_altsvc_cleanup(&data->asi);
   Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
   Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
@@ -752,8 +727,6 @@ static void conn_free(struct Curl_easy *data, struct connectdata *conn)
   Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
   Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
   Curl_safefree(conn->hostname_resolve);
   Curl_safefree(conn->hostname_resolve);
   Curl_safefree(conn->secondaryhostname);
   Curl_safefree(conn->secondaryhostname);
-
-  Curl_llist_destroy(&conn->easyq, NULL);
   Curl_safefree(conn->localdev);
   Curl_safefree(conn->localdev);
   Curl_free_primary_ssl_config(&conn->ssl_config);
   Curl_free_primary_ssl_config(&conn->ssl_config);
 
 
@@ -823,7 +796,7 @@ void Curl_disconnect(struct Curl_easy *data,
      disconnect and shutdown */
      disconnect and shutdown */
   Curl_attach_connection(data, conn);
   Curl_attach_connection(data, conn);
 
 
-  if(conn->handler->disconnect)
+  if(conn->handler && conn->handler->disconnect)
     /* This is set if protocol-specific cleanups should be made */
     /* This is set if protocol-specific cleanups should be made */
     conn->handler->disconnect(data, conn, dead_connection);
     conn->handler->disconnect(data, conn, dead_connection);
 
 
@@ -965,7 +938,20 @@ static bool extract_if_dead(struct connectdata *conn,
 
 
     }
     }
     else {
     else {
-      dead = !Curl_conn_is_alive(data, conn);
+      bool input_pending;
+
+      dead = !Curl_conn_is_alive(data, conn, &input_pending);
+      if(input_pending) {
+        /* For reuse, we want a "clean" connection state. The includes
+         * that we expect - in general - no waiting input data. Input
+         * waiting might be a TLS Notify Close, for example. We reject
+         * that.
+         * For protocols where data from other other end may arrive at
+         * any time (HTTP/2 PING for example), the protocol handler needs
+         * to install its own `connection_check` callback.
+         */
+        dead = TRUE;
+      }
     }
     }
 
 
     if(dead) {
     if(dead) {
@@ -1170,14 +1156,14 @@ ConnectionExists(struct Curl_easy *data,
             continue;
             continue;
           }
           }
         }
         }
+      }
 
 
-        if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
-          foundPendingCandidate = TRUE;
-          /* Don't pick a connection that hasn't connected yet */
-          infof(data, "Connection #%ld isn't open enough, can't reuse",
-                check->connection_id);
-          continue;
-        }
+      if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
+        foundPendingCandidate = TRUE;
+        /* Don't pick a connection that hasn't connected yet */
+        infof(data, "Connection #%ld isn't open enough, can't reuse",
+              check->connection_id);
+        continue;
       }
       }
 
 
 #ifdef USE_UNIX_SOCKETS
 #ifdef USE_UNIX_SOCKETS
@@ -1291,6 +1277,11 @@ ConnectionExists(struct Curl_easy *data,
         }
         }
       }
       }
 
 
+      /* GSS delegation differences do not actually affect every connection
+         and auth method, but this check takes precaution before efficiency */
+      if(needle->gssapi_delegation != check->gssapi_delegation)
+        continue;
+
       /* If multiplexing isn't enabled on the h2 connection and h1 is
       /* If multiplexing isn't enabled on the h2 connection and h1 is
          explicitly requested, handle it: */
          explicitly requested, handle it: */
       if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
       if((needle->handler->protocol & PROTO_FAMILY_HTTP) &&
@@ -1299,11 +1290,24 @@ ConnectionExists(struct Curl_easy *data,
           || ((check->httpversion >= 30) &&
           || ((check->httpversion >= 30) &&
            (data->state.httpwant < CURL_HTTP_VERSION_3))))
            (data->state.httpwant < CURL_HTTP_VERSION_3))))
         continue;
         continue;
-
-      if(get_protocol_family(needle->handler) == PROTO_FAMILY_SSH) {
+#ifdef USE_SSH
+      else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
         if(!ssh_config_matches(needle, check))
         if(!ssh_config_matches(needle, check))
           continue;
           continue;
       }
       }
+#endif
+#ifndef CURL_DISABLE_FTP
+      else if(get_protocol_family(needle->handler) & PROTO_FAMILY_FTP) {
+        /* Also match ACCOUNT, ALTERNATIVE-TO-USER, USE_SSL and CCC options */
+        if(Curl_timestrcmp(needle->proto.ftpc.account,
+                           check->proto.ftpc.account) ||
+           Curl_timestrcmp(needle->proto.ftpc.alternative_to_user,
+                           check->proto.ftpc.alternative_to_user) ||
+           (needle->proto.ftpc.use_ssl != check->proto.ftpc.use_ssl) ||
+           (needle->proto.ftpc.ccc != check->proto.ftpc.ccc))
+          continue;
+      }
+#endif
 
 
       if((needle->handler->flags&PROTOPT_SSL)
       if((needle->handler->flags&PROTOPT_SSL)
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -1494,10 +1498,6 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
   if(!conn)
   if(!conn)
     return NULL;
     return NULL;
 
 
-  conn->handler = &Curl_handler_dummy;  /* Be sure we have a handler defined
-                                           already from start to avoid NULL
-                                           situations and checks */
-
   /* and we setup a few fields in case we end up actually using this struct */
   /* and we setup a few fields in case we end up actually using this struct */
 
 
   conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
   conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD;     /* no file descriptor */
@@ -1589,11 +1589,11 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
   conn->fclosesocket = data->set.fclosesocket;
   conn->fclosesocket = data->set.fclosesocket;
   conn->closesocket_client = data->set.closesocket_client;
   conn->closesocket_client = data->set.closesocket_client;
   conn->lastused = Curl_now(); /* used now */
   conn->lastused = Curl_now(); /* used now */
+  conn->gssapi_delegation = data->set.gssapi_delegation;
 
 
   return conn;
   return conn;
   error:
   error:
 
 
-  Curl_llist_destroy(&conn->easyq, NULL);
   free(conn->localdev);
   free(conn->localdev);
   free(conn);
   free(conn);
   return NULL;
   return NULL;

+ 18 - 13
Utilities/cmcurl/lib/urlapi.c

@@ -57,6 +57,15 @@
 /* scheme is not URL encoded, the longest libcurl supported ones are... */
 /* scheme is not URL encoded, the longest libcurl supported ones are... */
 #define MAX_SCHEME_LEN 40
 #define MAX_SCHEME_LEN 40
 
 
+/*
+ * If ENABLE_IPV6 is disabled, we still want to parse IPv6 addresses, so make
+ * sure we have _some_ value for AF_INET6 without polluting our fake value
+ * everywhere.
+ */
+#if !defined(ENABLE_IPV6) && !defined(AF_INET6)
+#define AF_INET6 (AF_INET + 1)
+#endif
+
 /* Internal representation of CURLU. Point to URL-encoded strings. */
 /* Internal representation of CURLU. Point to URL-encoded strings. */
 struct Curl_URL {
 struct Curl_URL {
   char *scheme;
   char *scheme;
@@ -599,7 +608,8 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
         return CURLUE_BAD_IPV6;
         return CURLUE_BAD_IPV6;
       /* hostname is fine */
       /* hostname is fine */
     }
     }
-#ifdef ENABLE_IPV6
+
+    /* Check the IPv6 address. */
     {
     {
       char dest[16]; /* fits a binary IPv6 address */
       char dest[16]; /* fits a binary IPv6 address */
       char norm[MAX_IPADR_LEN];
       char norm[MAX_IPADR_LEN];
@@ -616,11 +626,10 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname,
       }
       }
       hostname[hlen] = ']'; /* restore ending bracket */
       hostname[hlen] = ']'; /* restore ending bracket */
     }
     }
-#endif
   }
   }
   else {
   else {
     /* letters from the second string are not ok */
     /* letters from the second string are not ok */
-    len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()");
+    len = strcspn(hostname, " \r\n\t/:#?!@{}[]\\$\'\"^`*<>=;,+&()%");
     if(hlen != len)
     if(hlen != len)
       /* hostname with bad content */
       /* hostname with bad content */
       return CURLUE_BAD_HOSTNAME;
       return CURLUE_BAD_HOSTNAME;
@@ -1341,7 +1350,7 @@ void curl_url_cleanup(CURLU *u)
     }                                           \
     }                                           \
   } while(0)
   } while(0)
 
 
-CURLU *curl_url_dup(CURLU *in)
+CURLU *curl_url_dup(const CURLU *in)
 {
 {
   struct Curl_URL *u = calloc(sizeof(struct Curl_URL), 1);
   struct Curl_URL *u = calloc(sizeof(struct Curl_URL), 1);
   if(u) {
   if(u) {
@@ -1362,10 +1371,10 @@ CURLU *curl_url_dup(CURLU *in)
   return NULL;
   return NULL;
 }
 }
 
 
-CURLUcode curl_url_get(CURLU *u, CURLUPart what,
+CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
                        char **part, unsigned int flags)
                        char **part, unsigned int flags)
 {
 {
-  char *ptr;
+  const char *ptr;
   CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
   CURLUcode ifmissing = CURLUE_UNKNOWN_PART;
   char portbuf[7];
   char portbuf[7];
   bool urldecode = (flags & CURLU_URLDECODE)?1:0;
   bool urldecode = (flags & CURLU_URLDECODE)?1:0;
@@ -1432,11 +1441,8 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
     break;
     break;
   case CURLUPART_PATH:
   case CURLUPART_PATH:
     ptr = u->path;
     ptr = u->path;
-    if(!ptr) {
-      ptr = u->path = strdup("/");
-      if(!u->path)
-        return CURLUE_OUT_OF_MEMORY;
-    }
+    if(!ptr)
+      ptr = "/";
     break;
     break;
   case CURLUPART_QUERY:
   case CURLUPART_QUERY:
     ptr = u->query;
     ptr = u->query;
@@ -1546,8 +1552,7 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
               return CURLUE_OUT_OF_MEMORY;
               return CURLUE_OUT_OF_MEMORY;
             host++;
             host++;
           }
           }
-          free(u->host);
-          u->host = Curl_dyn_ptr(&enc);
+          allochost = Curl_dyn_ptr(&enc);
         }
         }
       }
       }
 
 

+ 11 - 5
Utilities/cmcurl/lib/urldata.h

@@ -168,7 +168,7 @@ typedef CURLcode (*Curl_datastream)(struct Curl_easy *data,
 #include "rtsp.h"
 #include "rtsp.h"
 #include "smb.h"
 #include "smb.h"
 #include "mqtt.h"
 #include "mqtt.h"
-#include "wildcard.h"
+#include "ftplistparser.h"
 #include "multihandle.h"
 #include "multihandle.h"
 #include "c-hyper.h"
 #include "c-hyper.h"
 #include "cf-socket.h"
 #include "cf-socket.h"
@@ -686,6 +686,10 @@ struct SingleRequest {
   } p;
   } p;
 #ifndef CURL_DISABLE_DOH
 #ifndef CURL_DISABLE_DOH
   struct dohdata *doh; /* DoH specific data for this request */
   struct dohdata *doh; /* DoH specific data for this request */
+#endif
+#if defined(WIN32) && defined(USE_WINSOCK)
+  struct curltime last_sndbuf_update;  /* last time readwrite_upload called
+                                          win_update_buffer_size */
 #endif
 #endif
   unsigned char setcookies;
   unsigned char setcookies;
   unsigned char writer_stack_depth; /* Unencoding stack depth. */
   unsigned char writer_stack_depth; /* Unencoding stack depth. */
@@ -1057,6 +1061,7 @@ struct connectdata {
   unsigned char ip_version; /* copied from the Curl_easy at creation time */
   unsigned char ip_version; /* copied from the Curl_easy at creation time */
   unsigned char httpversion; /* the HTTP version*10 reported by the server */
   unsigned char httpversion; /* the HTTP version*10 reported by the server */
   unsigned char connect_only;
   unsigned char connect_only;
+  unsigned char gssapi_delegation; /* inherited from set.gssapi_delegation */
 };
 };
 
 
 /* The end of connectdata. */
 /* The end of connectdata. */
@@ -1374,7 +1379,7 @@ struct UrlState {
   struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
   struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
                                  headers */
                                  headers */
   struct Curl_llist httphdrs; /* received headers */
   struct Curl_llist httphdrs; /* received headers */
-  struct curl_header headerout; /* for external purposes */
+  struct curl_header headerout[2]; /* for external purposes */
   struct Curl_header_store *prevhead; /* the latest added header */
   struct Curl_header_store *prevhead; /* the latest added header */
   trailers_state trailers_state; /* whether we are sending trailers
   trailers_state trailers_state; /* whether we are sending trailers
                                     and what stage are we at */
                                     and what stage are we at */
@@ -1713,8 +1718,6 @@ struct UserDefined {
 #ifndef CURL_DISABLE_NETRC
 #ifndef CURL_DISABLE_NETRC
   unsigned char use_netrc;        /* enum CURL_NETRC_OPTION values  */
   unsigned char use_netrc;        /* enum CURL_NETRC_OPTION values  */
 #endif
 #endif
-  curl_usessl use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
-                            IMAP or POP3 or others! */
   unsigned int new_file_perms;      /* when creating remote files */
   unsigned int new_file_perms;      /* when creating remote files */
   char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
   char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
   struct curl_blob *blobs[BLOB_LAST];
   struct curl_blob *blobs[BLOB_LAST];
@@ -1739,6 +1742,7 @@ struct UserDefined {
   curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds
   curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds
                                     to pattern (e.g. if WILDCARDMATCH is on) */
                                     to pattern (e.g. if WILDCARDMATCH is on) */
   void *fnmatch_data;
   void *fnmatch_data;
+  void *wildcardptr;
 #endif
 #endif
  /* GSS-API credential delegation, see the documentation of
  /* GSS-API credential delegation, see the documentation of
     CURLOPT_GSSAPI_DELEGATION */
     CURLOPT_GSSAPI_DELEGATION */
@@ -1773,6 +1777,8 @@ struct UserDefined {
   BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
   BIT(mail_rcpt_allowfails); /* allow RCPT TO command to fail for some
                                 recipients */
                                 recipients */
 #endif
 #endif
+  unsigned char use_ssl;   /* if AUTH TLS is to be attempted etc, for FTP or
+                              IMAP or POP3 or others! (type: curl_usessl)*/
   unsigned char connect_only; /* make connection/request, then let
   unsigned char connect_only; /* make connection/request, then let
                                  application use the socket */
                                  application use the socket */
   BIT(is_fread_set); /* has read callback been set to non-NULL? */
   BIT(is_fread_set); /* has read callback been set to non-NULL? */
@@ -1934,7 +1940,7 @@ struct Curl_easy {
   struct UrlState state;       /* struct for fields used for state info and
   struct UrlState state;       /* struct for fields used for state info and
                                   other dynamic purposes */
                                   other dynamic purposes */
 #ifndef CURL_DISABLE_FTP
 #ifndef CURL_DISABLE_FTP
-  struct WildcardData wildcard; /* wildcard download state info */
+  struct WildcardData *wildcard; /* wildcard download state info */
 #endif
 #endif
   struct PureInfo info;        /* stats, reports and info data */
   struct PureInfo info;        /* stats, reports and info data */
   struct curl_tlssessioninfo tsi; /* Information about the TLS session, only
   struct curl_tlssessioninfo tsi; /* Information about the TLS session, only

+ 9 - 2
Utilities/cmcurl/lib/version.c

@@ -62,7 +62,15 @@
 #endif
 #endif
 
 
 #ifdef HAVE_BROTLI
 #ifdef HAVE_BROTLI
+#if defined(__GNUC__)
+/* Ignore -Wvla warnings in brotli headers */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wvla"
+#endif
 #include <brotli/decode.h>
 #include <brotli/decode.h>
+#if defined(__GNUC__)
+#pragma GCC diagnostic pop
+#endif
 #endif
 #endif
 
 
 #ifdef HAVE_ZSTD
 #ifdef HAVE_ZSTD
@@ -357,8 +365,7 @@ static const char * const protocols[] = {
 #ifdef USE_SSH
 #ifdef USE_SSH
   "sftp",
   "sftp",
 #endif
 #endif
-#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
-   (SIZEOF_CURL_OFF_T > 4)
+#if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE)
   "smb",
   "smb",
 #  ifdef USE_SSL
 #  ifdef USE_SSL
   "smbs",
   "smbs",

+ 16 - 7
Utilities/cmcurl/lib/vquic/curl_msh3.c

@@ -548,7 +548,6 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
                                    struct Curl_easy *data,
                                    struct Curl_easy *data,
                                    int event, int arg1, void *arg2)
                                    int event, int arg1, void *arg2)
 {
 {
-  struct cf_msh3_ctx *ctx = cf->ctx;
   struct HTTP *stream = data->req.p.http;
   struct HTTP *stream = data->req.p.http;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
 
 
@@ -579,11 +578,6 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
     DEBUGF(LOG_CF(data, cf, "req: update info"));
     DEBUGF(LOG_CF(data, cf, "req: update info"));
     cf_msh3_active(cf, data);
     cf_msh3_active(cf, data);
     break;
     break;
-  case CF_CTRL_CONN_REPORT_STATS:
-    if(cf->sockindex == FIRSTSOCKET)
-      Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
-    break;
-
   default:
   default:
     break;
     break;
   }
   }
@@ -753,6 +747,19 @@ static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
     *pres1 = 100;
     *pres1 = 100;
     return CURLE_OK;
     return CURLE_OK;
   }
   }
+  case CF_QUERY_TIMER_CONNECT: {
+    struct curltime *when = pres2;
+    /* we do not know when the first byte arrived */
+    if(cf->connected)
+      *when = ctx->handshake_at;
+    return CURLE_OK;
+  }
+  case CF_QUERY_TIMER_APPCONNECT: {
+    struct curltime *when = pres2;
+    if(cf->connected)
+      *when = ctx->handshake_at;
+    return CURLE_OK;
+  }
   default:
   default:
     break;
     break;
   }
   }
@@ -762,11 +769,13 @@ static CURLcode cf_msh3_query(struct Curl_cfilter *cf,
 }
 }
 
 
 static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf,
 static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data)
+                                  struct Curl_easy *data,
+                                  bool *input_pending)
 {
 {
   struct cf_msh3_ctx *ctx = cf->ctx;
   struct cf_msh3_ctx *ctx = cf->ctx;
 
 
   (void)data;
   (void)data;
+  *input_pending = FALSE;
   return ctx && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD && ctx->qconn &&
   return ctx && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD && ctx->qconn &&
          ctx->connected;
          ctx->connected;
 }
 }

+ 48 - 13
Utilities/cmcurl/lib/vquic/curl_ngtcp2.c

@@ -64,6 +64,8 @@
 #include "vtls/vtls.h"
 #include "vtls/vtls.h"
 #include "curl_ngtcp2.h"
 #include "curl_ngtcp2.h"
 
 
+#include "warnless.h"
+
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "curl_memory.h"
@@ -901,7 +903,7 @@ static int cf_ngtcp2_get_select_socks(struct Curl_cfilter *cf,
   rv |= GETSOCK_READSOCK(0);
   rv |= GETSOCK_READSOCK(0);
 
 
   /* we're still uploading or the HTTP/2 layer wants to send data */
   /* we're still uploading or the HTTP/2 layer wants to send data */
-  if((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND &&
+  if((k->keepon & KEEP_SENDBITS) == KEEP_SEND &&
      (!stream->h3out || stream->h3out->used < H3_SEND_SIZE) &&
      (!stream->h3out || stream->h3out->used < H3_SEND_SIZE) &&
      ngtcp2_conn_get_cwnd_left(ctx->qconn) &&
      ngtcp2_conn_get_cwnd_left(ctx->qconn) &&
      ngtcp2_conn_get_max_data_left(ctx->qconn) &&
      ngtcp2_conn_get_max_data_left(ctx->qconn) &&
@@ -951,7 +953,7 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
 }
 }
 
 
 /*
 /*
- * write_resp_raw() copies resonse data in raw format to the `data`'s
+ * write_resp_raw() copies response data in raw format to the `data`'s
   * receive buffer. If not enough space is available, it appends to the
   * receive buffer. If not enough space is available, it appends to the
  * `data`'s overflow buffer.
  * `data`'s overflow buffer.
  */
  */
@@ -1762,7 +1764,7 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
   ssize_t recvd;
   ssize_t recvd;
   int rv;
   int rv;
   uint8_t buf[65536];
   uint8_t buf[65536];
-  size_t bufsize = sizeof(buf);
+  int bufsize = (int)sizeof(buf);
   size_t pktcount = 0, total_recvd = 0;
   size_t pktcount = 0, total_recvd = 0;
   struct sockaddr_storage remote_addr;
   struct sockaddr_storage remote_addr;
   socklen_t remote_addrlen;
   socklen_t remote_addrlen;
@@ -2107,13 +2109,6 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf,
       }
       }
     }
     }
     break;
     break;
-  case CF_CTRL_CONN_REPORT_STATS:
-    if(cf->sockindex == FIRSTSOCKET) {
-      if(ctx->got_first_byte)
-        Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at);
-      Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
-    }
-    break;
   default:
   default:
     break;
     break;
   }
   }
@@ -2127,7 +2122,6 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
 
 
   if(ctx->qlogfd != -1) {
   if(ctx->qlogfd != -1) {
     close(ctx->qlogfd);
     close(ctx->qlogfd);
-    ctx->qlogfd = -1;
   }
   }
 #ifdef USE_OPENSSL
 #ifdef USE_OPENSSL
   if(ctx->ssl)
   if(ctx->ssl)
@@ -2155,6 +2149,7 @@ static void cf_ngtcp2_ctx_clear(struct cf_ngtcp2_ctx *ctx)
     ngtcp2_conn_del(ctx->qconn);
     ngtcp2_conn_del(ctx->qconn);
 
 
   memset(ctx, 0, sizeof(*ctx));
   memset(ctx, 0, sizeof(*ctx));
+  ctx->qlogfd = -1;
   ctx->call_data = save;
   ctx->call_data = save;
 }
 }
 
 
@@ -2176,7 +2171,7 @@ static void cf_ngtcp2_close(struct Curl_cfilter *cf, struct Curl_easy *data)
                                             (uint8_t *)buffer, sizeof(buffer),
                                             (uint8_t *)buffer, sizeof(buffer),
                                             &ctx->last_error, ts);
                                             &ctx->last_error, ts);
     if(rc > 0) {
     if(rc > 0) {
-      while((send(ctx->q.sockfd, buffer, rc, 0) == -1) &&
+      while((send(ctx->q.sockfd, buffer, (SEND_TYPE_ARG3)rc, 0) == -1) &&
             SOCKERRNO == EINTR);
             SOCKERRNO == EINTR);
     }
     }
 
 
@@ -2200,6 +2195,7 @@ static void cf_ngtcp2_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
   }
   }
   cf->ctx = NULL;
   cf->ctx = NULL;
   /* No CF_DATA_RESTORE(cf, save) possible */
   /* No CF_DATA_RESTORE(cf, save) possible */
+  (void)save;
 }
 }
 
 
 /*
 /*
@@ -2428,6 +2424,18 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
     else
     else
       *pres1 = -1;
       *pres1 = -1;
     return CURLE_OK;
     return CURLE_OK;
+  case CF_QUERY_TIMER_CONNECT: {
+    struct curltime *when = pres2;
+    if(ctx->got_first_byte)
+      *when = ctx->first_byte_at;
+    return CURLE_OK;
+  }
+  case CF_QUERY_TIMER_APPCONNECT: {
+    struct curltime *when = pres2;
+    if(cf->connected)
+      *when = ctx->handshake_at;
+    return CURLE_OK;
+  }
   default:
   default:
     break;
     break;
   }
   }
@@ -2436,6 +2444,32 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf,
     CURLE_UNKNOWN_OPTION;
     CURLE_UNKNOWN_OPTION;
 }
 }
 
 
+static bool cf_ngtcp2_conn_is_alive(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    bool *input_pending)
+{
+  bool alive = TRUE;
+
+  *input_pending = FALSE;
+  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+    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,
+       only "protocol frames" */
+    *input_pending = FALSE;
+    Curl_attach_connection(data, cf->conn);
+    if(cf_process_ingress(cf, data))
+      alive = FALSE;
+    else {
+      alive = TRUE;
+    }
+    Curl_detach_connection(data);
+  }
+
+  return alive;
+}
 
 
 struct Curl_cftype Curl_cft_http3 = {
 struct Curl_cftype Curl_cft_http3 = {
   "HTTP/3",
   "HTTP/3",
@@ -2450,7 +2484,7 @@ struct Curl_cftype Curl_cft_http3 = {
   cf_ngtcp2_send,
   cf_ngtcp2_send,
   cf_ngtcp2_recv,
   cf_ngtcp2_recv,
   cf_ngtcp2_data_event,
   cf_ngtcp2_data_event,
-  Curl_cf_def_conn_is_alive,
+  cf_ngtcp2_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
   Curl_cf_def_conn_keep_alive,
   cf_ngtcp2_query,
   cf_ngtcp2_query,
 };
 };
@@ -2470,6 +2504,7 @@ CURLcode Curl_cf_ngtcp2_create(struct Curl_cfilter **pcf,
     result = CURLE_OUT_OF_MEMORY;
     result = CURLE_OUT_OF_MEMORY;
     goto out;
     goto out;
   }
   }
+  ctx->qlogfd = -1;
   cf_ngtcp2_ctx_clear(ctx);
   cf_ngtcp2_ctx_clear(ctx);
 
 
   result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);
   result = Curl_cf_create(&cf, &Curl_cft_http3, ctx);

+ 41 - 10
Utilities/cmcurl/lib/vquic/curl_quiche.c

@@ -444,7 +444,7 @@ static CURLcode cf_process_ingress(struct Curl_cfilter *cf,
   struct cf_quiche_ctx *ctx = cf->ctx;
   struct cf_quiche_ctx *ctx = cf->ctx;
   int64_t stream3_id = data->req.p.http? data->req.p.http->stream3_id : -1;
   int64_t stream3_id = data->req.p.http? data->req.p.http->stream3_id : -1;
   uint8_t buf[65536];
   uint8_t buf[65536];
-  size_t bufsize = sizeof(buf);
+  int bufsize = (int)sizeof(buf);
   struct sockaddr_storage remote_addr;
   struct sockaddr_storage remote_addr;
   socklen_t remote_addrlen;
   socklen_t remote_addrlen;
   quiche_recv_info recv_info;
   quiche_recv_info recv_info;
@@ -950,7 +950,7 @@ static int cf_quiche_get_select_socks(struct Curl_cfilter *cf,
   rv |= GETSOCK_READSOCK(0);
   rv |= GETSOCK_READSOCK(0);
 
 
   /* we're still uploading or the HTTP/3 layer wants to send data */
   /* we're still uploading or the HTTP/3 layer wants to send data */
-  if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND)
+  if(((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
      && stream_is_writeable(cf, data))
      && stream_is_writeable(cf, data))
     rv |= GETSOCK_WRITESOCK(0);
     rv |= GETSOCK_WRITESOCK(0);
 
 
@@ -1016,13 +1016,6 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf,
   case CF_CTRL_DATA_IDLE:
   case CF_CTRL_DATA_IDLE:
     /* anything to do? */
     /* anything to do? */
     break;
     break;
-  case CF_CTRL_CONN_REPORT_STATS:
-    if(cf->sockindex == FIRSTSOCKET) {
-      if(ctx->got_first_byte)
-        Curl_pgrsTimeWas(data, TIMER_CONNECT, ctx->first_byte_at);
-      Curl_pgrsTimeWas(data, TIMER_APPCONNECT, ctx->handshake_at);
-    }
-    break;
   default:
   default:
     break;
     break;
   }
   }
@@ -1346,6 +1339,18 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
     else
     else
       *pres1 = -1;
       *pres1 = -1;
     return CURLE_OK;
     return CURLE_OK;
+  case CF_QUERY_TIMER_CONNECT: {
+    struct curltime *when = pres2;
+    if(ctx->got_first_byte)
+      *when = ctx->first_byte_at;
+    return CURLE_OK;
+  }
+  case CF_QUERY_TIMER_APPCONNECT: {
+    struct curltime *when = pres2;
+    if(cf->connected)
+      *when = ctx->handshake_at;
+    return CURLE_OK;
+  }
   default:
   default:
     break;
     break;
   }
   }
@@ -1354,6 +1359,32 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf,
     CURLE_UNKNOWN_OPTION;
     CURLE_UNKNOWN_OPTION;
 }
 }
 
 
+static bool cf_quiche_conn_is_alive(struct Curl_cfilter *cf,
+                                    struct Curl_easy *data,
+                                    bool *input_pending)
+{
+  bool alive = TRUE;
+
+  *input_pending = FALSE;
+  if(!cf->next || !cf->next->cft->is_alive(cf->next, data, input_pending))
+    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,
+       only "protocol frames" */
+    *input_pending = FALSE;
+    Curl_attach_connection(data, cf->conn);
+    if(cf_process_ingress(cf, data))
+      alive = FALSE;
+    else {
+      alive = TRUE;
+    }
+    Curl_detach_connection(data);
+  }
+
+  return alive;
+}
 
 
 struct Curl_cftype Curl_cft_http3 = {
 struct Curl_cftype Curl_cft_http3 = {
   "HTTP/3",
   "HTTP/3",
@@ -1368,7 +1399,7 @@ struct Curl_cftype Curl_cft_http3 = {
   cf_quiche_send,
   cf_quiche_send,
   cf_quiche_recv,
   cf_quiche_recv,
   cf_quiche_data_event,
   cf_quiche_data_event,
-  Curl_cf_def_conn_is_alive,
+  cf_quiche_conn_is_alive,
   Curl_cf_def_conn_keep_alive,
   Curl_cf_def_conn_keep_alive,
   cf_quiche_query,
   cf_quiche_query,
 };
 };

+ 6 - 1
Utilities/cmcurl/lib/vquic/vquic.c

@@ -167,7 +167,8 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf,
 
 
   *psent = 0;
   *psent = 0;
 
 
-  while((sent = send(qctx->sockfd, (const char *)pkt, pktlen, 0)) == -1 &&
+  while((sent = send(qctx->sockfd,
+                     (const char *)pkt, (SEND_TYPE_ARG3)pktlen, 0)) == -1 &&
         SOCKERRNO == EINTR)
         SOCKERRNO == EINTR)
     ;
     ;
 
 
@@ -363,6 +364,10 @@ bool Curl_conn_is_http3(const struct Curl_easy *data,
 CURLcode Curl_conn_may_http3(struct Curl_easy *data,
 CURLcode Curl_conn_may_http3(struct Curl_easy *data,
                              const struct connectdata *conn)
                              const struct connectdata *conn)
 {
 {
+  if(conn->transport == TRNSPRT_UNIX) {
+    /* cannot do QUIC over a unix domain socket */
+    return CURLE_QUIC_CONNECT_ERROR;
+  }
   if(!(conn->handler->flags & PROTOPT_SSL)) {
   if(!(conn->handler->flags & PROTOPT_SSL)) {
     failf(data, "HTTP/3 requested for non-HTTPS URL");
     failf(data, "HTTP/3 requested for non-HTTPS URL");
     return CURLE_URL_MALFORMAT;
     return CURLE_URL_MALFORMAT;

+ 17 - 37
Utilities/cmcurl/lib/vssh/libssh.c

@@ -685,7 +685,6 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
   struct ssh_conn *sshc = &conn->proto.sshc;
   struct ssh_conn *sshc = &conn->proto.sshc;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   int rc = SSH_NO_ERROR, err;
   int rc = SSH_NO_ERROR, err;
-  char *new_readdir_line;
   int seekerr = CURL_SEEKFUNC_OK;
   int seekerr = CURL_SEEKFUNC_OK;
   const char *err_msg;
   const char *err_msg;
   *block = 0;                   /* we're not blocking by default */
   *block = 0;                   /* we're not blocking by default */
@@ -1432,7 +1431,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       break;
       break;
 
 
     case SSH_SFTP_READDIR:
     case SSH_SFTP_READDIR:
-
+      Curl_dyn_reset(&sshc->readdir_buf);
       if(sshc->readdir_attrs)
       if(sshc->readdir_attrs)
         sftp_attributes_free(sshc->readdir_attrs);
         sftp_attributes_free(sshc->readdir_attrs);
 
 
@@ -1468,17 +1467,12 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
                      sshc->readdir_len);
                      sshc->readdir_len);
         }
         }
         else {
         else {
-          sshc->readdir_currLen = strlen(sshc->readdir_longentry);
-          sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
-          sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
-          if(!sshc->readdir_line) {
-            state(data, SSH_SFTP_CLOSE);
+          if(Curl_dyn_add(&sshc->readdir_buf, sshc->readdir_longentry)) {
             sshc->actualcode = CURLE_OUT_OF_MEMORY;
             sshc->actualcode = CURLE_OUT_OF_MEMORY;
+            state(data, SSH_STOP);
             break;
             break;
           }
           }
 
 
-          memcpy(sshc->readdir_line, sshc->readdir_longentry,
-                 sshc->readdir_currLen);
           if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
           if((sshc->readdir_attrs->flags & SSH_FILEXFER_ATTR_PERMISSIONS) &&
              ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
              ((sshc->readdir_attrs->permissions & SSH_S_IFMT) ==
               SSH_S_IFLNK)) {
               SSH_S_IFLNK)) {
@@ -1541,24 +1535,11 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
 
 
       Curl_safefree(sshc->readdir_linkPath);
       Curl_safefree(sshc->readdir_linkPath);
 
 
-      /* get room for the filename and extra output */
-      sshc->readdir_totalLen += 4 + sshc->readdir_len;
-      new_readdir_line = Curl_saferealloc(sshc->readdir_line,
-                                          sshc->readdir_totalLen);
-      if(!new_readdir_line) {
-        sshc->readdir_line = NULL;
-        state(data, SSH_SFTP_CLOSE);
+      if(Curl_dyn_addf(&sshc->readdir_buf, " -> %s",
+                       sshc->readdir_filename)) {
         sshc->actualcode = CURLE_OUT_OF_MEMORY;
         sshc->actualcode = CURLE_OUT_OF_MEMORY;
         break;
         break;
       }
       }
-      sshc->readdir_line = new_readdir_line;
-
-      sshc->readdir_currLen += msnprintf(sshc->readdir_line +
-                                         sshc->readdir_currLen,
-                                         sshc->readdir_totalLen -
-                                         sshc->readdir_currLen,
-                                         " -> %s",
-                                         sshc->readdir_filename);
 
 
       sftp_attributes_free(sshc->readdir_link_attrs);
       sftp_attributes_free(sshc->readdir_link_attrs);
       sshc->readdir_link_attrs = NULL;
       sshc->readdir_link_attrs = NULL;
@@ -1568,21 +1549,19 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       state(data, SSH_SFTP_READDIR_BOTTOM);
       state(data, SSH_SFTP_READDIR_BOTTOM);
       /* FALLTHROUGH */
       /* FALLTHROUGH */
     case SSH_SFTP_READDIR_BOTTOM:
     case SSH_SFTP_READDIR_BOTTOM:
-      sshc->readdir_currLen += msnprintf(sshc->readdir_line +
-                                         sshc->readdir_currLen,
-                                         sshc->readdir_totalLen -
-                                         sshc->readdir_currLen, "\n");
-      result = Curl_client_write(data, CLIENTWRITE_BODY,
-                                 sshc->readdir_line,
-                                 sshc->readdir_currLen);
+      if(Curl_dyn_addn(&sshc->readdir_buf, "\n", 1))
+        result = CURLE_OUT_OF_MEMORY;
+      else
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
+                                   Curl_dyn_ptr(&sshc->readdir_buf),
+                                   Curl_dyn_len(&sshc->readdir_buf));
 
 
       if(!result) {
       if(!result) {
         /* output debug output if that is requested */
         /* output debug output if that is requested */
-        Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
-                   sshc->readdir_currLen);
-        data->req.bytecount += sshc->readdir_currLen;
+        Curl_debug(data, CURLINFO_DATA_OUT, Curl_dyn_ptr(&sshc->readdir_buf),
+                   Curl_dyn_len(&sshc->readdir_buf));
+        data->req.bytecount += Curl_dyn_len(&sshc->readdir_buf);
       }
       }
-      Curl_safefree(sshc->readdir_line);
       ssh_string_free_char(sshc->readdir_tmp);
       ssh_string_free_char(sshc->readdir_tmp);
       sshc->readdir_tmp = NULL;
       sshc->readdir_tmp = NULL;
 
 
@@ -2021,7 +2000,7 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, bool *block)
       Curl_safefree(sshc->rsa);
       Curl_safefree(sshc->rsa);
       Curl_safefree(sshc->quote_path1);
       Curl_safefree(sshc->quote_path1);
       Curl_safefree(sshc->quote_path2);
       Curl_safefree(sshc->quote_path2);
-      Curl_safefree(sshc->readdir_line);
+      Curl_dyn_free(&sshc->readdir_buf);
       Curl_safefree(sshc->readdir_linkPath);
       Curl_safefree(sshc->readdir_linkPath);
       SSH_STRING_FREE_CHAR(sshc->homedir);
       SSH_STRING_FREE_CHAR(sshc->homedir);
 
 
@@ -2166,11 +2145,12 @@ static CURLcode myssh_setup_connection(struct Curl_easy *data,
                                        struct connectdata *conn)
                                        struct connectdata *conn)
 {
 {
   struct SSHPROTO *ssh;
   struct SSHPROTO *ssh;
-  (void)conn;
+  struct ssh_conn *sshc = &conn->proto.sshc;
 
 
   data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
   data->req.p.ssh = ssh = calloc(1, sizeof(struct SSHPROTO));
   if(!ssh)
   if(!ssh)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
+  Curl_dyn_init(&sshc->readdir_buf, PATH_MAX * 2);
 
 
   return CURLE_OK;
   return CURLE_OK;
 }
 }

+ 10 - 5
Utilities/cmcurl/lib/vssh/libssh2.c

@@ -100,10 +100,11 @@
 
 
 /* Local functions: */
 /* Local functions: */
 static const char *sftp_libssh2_strerror(unsigned long err);
 static const char *sftp_libssh2_strerror(unsigned long err);
+#ifdef CURL_LIBSSH2_DEBUG
 static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
 static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
 static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
 static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
 static LIBSSH2_FREE_FUNC(my_libssh2_free);
 static LIBSSH2_FREE_FUNC(my_libssh2_free);
-
+#endif
 static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data);
 static CURLcode ssh_force_knownhost_key_type(struct Curl_easy *data);
 static CURLcode ssh_connect(struct Curl_easy *data, bool *done);
 static CURLcode ssh_connect(struct Curl_easy *data, bool *done);
 static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done);
 static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done);
@@ -283,6 +284,8 @@ static CURLcode libssh2_session_error_to_CURLE(int err)
   return CURLE_SSH;
   return CURLE_SSH;
 }
 }
 
 
+#ifdef CURL_LIBSSH2_DEBUG
+
 static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
 static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
 {
 {
   (void)abstract; /* arg not used */
   (void)abstract; /* arg not used */
@@ -302,6 +305,8 @@ static LIBSSH2_FREE_FUNC(my_libssh2_free)
     free(ptr);
     free(ptr);
 }
 }
 
 
+#endif
+
 /*
 /*
  * SSH State machine related code
  * SSH State machine related code
  */
  */
@@ -2400,7 +2405,6 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
       result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename);
       result = Curl_dyn_addf(&sshp->readdir, " -> %s", sshp->readdir_filename);
 
 
       if(result) {
       if(result) {
-        sshc->readdir_line = NULL;
         Curl_safefree(sshp->readdir_filename);
         Curl_safefree(sshp->readdir_filename);
         Curl_safefree(sshp->readdir_longentry);
         Curl_safefree(sshp->readdir_longentry);
         state(data, SSH_SFTP_CLOSE);
         state(data, SSH_SFTP_CLOSE);
@@ -3004,12 +3008,9 @@ static CURLcode ssh_statemach_act(struct Curl_easy *data, bool *block)
 
 
       Curl_safefree(sshc->rsa_pub);
       Curl_safefree(sshc->rsa_pub);
       Curl_safefree(sshc->rsa);
       Curl_safefree(sshc->rsa);
-
       Curl_safefree(sshc->quote_path1);
       Curl_safefree(sshc->quote_path1);
       Curl_safefree(sshc->quote_path2);
       Curl_safefree(sshc->quote_path2);
-
       Curl_safefree(sshc->homedir);
       Curl_safefree(sshc->homedir);
-      Curl_safefree(sshc->readdir_line);
 
 
       /* the code we are about to return */
       /* the code we are about to return */
       result = sshc->actualcode;
       result = sshc->actualcode;
@@ -3268,9 +3269,13 @@ static CURLcode ssh_connect(struct Curl_easy *data, bool *done)
   sock = conn->sock[FIRSTSOCKET];
   sock = conn->sock[FIRSTSOCKET];
 #endif /* CURL_LIBSSH2_DEBUG */
 #endif /* CURL_LIBSSH2_DEBUG */
 
 
+#ifdef CURL_LIBSSH2_DEBUG
   sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
   sshc->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
                                               my_libssh2_free,
                                               my_libssh2_free,
                                               my_libssh2_realloc, data);
                                               my_libssh2_realloc, data);
+#else
+  sshc->ssh_session = libssh2_session_init();
+#endif
   if(!sshc->ssh_session) {
   if(!sshc->ssh_session) {
     failf(data, "Failure initialising ssh session");
     failf(data, "Failure initialising ssh session");
     return CURLE_FAILED_INIT;
     return CURLE_FAILED_INIT;

+ 2 - 2
Utilities/cmcurl/lib/vssh/ssh.h

@@ -147,7 +147,6 @@ struct ssh_conn {
 
 
   char *homedir;              /* when doing SFTP we figure out home dir in the
   char *homedir;              /* when doing SFTP we figure out home dir in the
                                  connect phase */
                                  connect phase */
-  char *readdir_line;
   /* end of READDIR stuff */
   /* end of READDIR stuff */
 
 
   int secondCreateDirs;         /* counter use by the code to see if the
   int secondCreateDirs;         /* counter use by the code to see if the
@@ -158,7 +157,8 @@ struct ssh_conn {
 
 
 #if defined(USE_LIBSSH)
 #if defined(USE_LIBSSH)
   char *readdir_linkPath;
   char *readdir_linkPath;
-  size_t readdir_len, readdir_totalLen, readdir_currLen;
+  size_t readdir_len;
+  struct dynbuf readdir_buf;
 /* our variables */
 /* our variables */
   unsigned kbd_state; /* 0 or 1 */
   unsigned kbd_state; /* 0 or 1 */
   ssh_key privkey;
   ssh_key privkey;

+ 1 - 31
Utilities/cmcurl/lib/vtls/nss.c

@@ -1536,36 +1536,6 @@ static void nss_cleanup(void)
   initialized = 0;
   initialized = 0;
 }
 }
 
 
-/*
- * This function uses SSL_peek to determine connection status.
- *
- * Return codes:
- *     1 means the connection is still in place
- *     0 means the connection has been closed
- *    -1 means the connection status is unknown
- */
-static int nss_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct ssl_backend_data *backend = connssl->backend;
-  int rc;
-  char buf;
-
-  (void)data;
-  DEBUGASSERT(backend);
-
-  rc =
-    PR_Recv(backend->handle, (void *)&buf, 1, PR_MSG_PEEK,
-            PR_SecondsToInterval(1));
-  if(rc > 0)
-    return 1; /* connection still in place */
-
-  if(rc == 0)
-    return 0; /* connection has been closed */
-
-  return -1;  /* connection status unknown */
-}
-
 static void close_one(struct ssl_connect_data *connssl)
 static void close_one(struct ssl_connect_data *connssl)
 {
 {
   /* before the cleanup, check whether we are using a client certificate */
   /* before the cleanup, check whether we are using a client certificate */
@@ -2524,7 +2494,7 @@ const struct Curl_ssl Curl_ssl_nss = {
   nss_init,                     /* init */
   nss_init,                     /* init */
   nss_cleanup,                  /* cleanup */
   nss_cleanup,                  /* cleanup */
   nss_version,                  /* version */
   nss_version,                  /* version */
-  nss_check_cxn,                /* check_cxn */
+  Curl_none_check_cxn,          /* check_cxn */
   /* NSS has no shutdown function provided and thus always fail */
   /* NSS has no shutdown function provided and thus always fail */
   Curl_none_shutdown,           /* shutdown */
   Curl_none_shutdown,           /* shutdown */
   nss_data_pending,             /* data_pending */
   nss_data_pending,             /* data_pending */

+ 1 - 58
Utilities/cmcurl/lib/vtls/openssl.c

@@ -1788,63 +1788,6 @@ static void ossl_cleanup(void)
   Curl_tls_keylog_close();
   Curl_tls_keylog_close();
 }
 }
 
 
-/*
- * This function is used to determine connection status.
- *
- * Return codes:
- *     1 means the connection is still in place
- *     0 means the connection has been closed
- *    -1 means the connection status is unknown
- */
-static int ossl_check_cxn(struct Curl_cfilter *cf, struct Curl_easy *data)
-{
-  /* SSL_peek takes data out of the raw recv buffer without peeking so we use
-     recv MSG_PEEK instead. Bug #795 */
-#ifdef MSG_PEEK
-  char buf;
-  ssize_t nread;
-  curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
-  if(sock == CURL_SOCKET_BAD)
-    return 0; /* no socket, consider closed */
-  nread = recv((RECV_TYPE_ARG1)sock,
-               (RECV_TYPE_ARG2)&buf, (RECV_TYPE_ARG3)1,
-               (RECV_TYPE_ARG4)MSG_PEEK);
-  if(nread == 0)
-    return 0; /* connection has been closed */
-  if(nread == 1)
-    return 1; /* connection still in place */
-  else if(nread == -1) {
-      int err = SOCKERRNO;
-      if(err == EINPROGRESS ||
-#if defined(EAGAIN) && (EAGAIN != EWOULDBLOCK)
-         err == EAGAIN ||
-#endif
-         err == EWOULDBLOCK)
-        return 1; /* connection still in place */
-      if(err == ECONNRESET ||
-#ifdef ECONNABORTED
-         err == ECONNABORTED ||
-#endif
-#ifdef ENETDOWN
-         err == ENETDOWN ||
-#endif
-#ifdef ENETRESET
-         err == ENETRESET ||
-#endif
-#ifdef ESHUTDOWN
-         err == ESHUTDOWN ||
-#endif
-#ifdef ETIMEDOUT
-         err == ETIMEDOUT ||
-#endif
-         err == ENOTCONN)
-        return 0; /* connection has been closed */
-  }
-#endif
-  (void)data;
-  return -1; /* connection status unknown */
-}
-
 /* Selects an OpenSSL crypto engine
 /* Selects an OpenSSL crypto engine
  */
  */
 static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine)
 static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine)
@@ -4836,7 +4779,7 @@ const struct Curl_ssl Curl_ssl_openssl = {
   ossl_init,                /* init */
   ossl_init,                /* init */
   ossl_cleanup,             /* cleanup */
   ossl_cleanup,             /* cleanup */
   ossl_version,             /* version */
   ossl_version,             /* version */
-  ossl_check_cxn,           /* check_cxn */
+  Curl_none_check_cxn,      /* check_cxn */
   ossl_shutdown,            /* shutdown */
   ossl_shutdown,            /* shutdown */
   ossl_data_pending,        /* data_pending */
   ossl_data_pending,        /* data_pending */
   ossl_random,              /* random */
   ossl_random,              /* random */

+ 74 - 67
Utilities/cmcurl/lib/vtls/schannel.c

@@ -264,128 +264,133 @@ set_ssl_version_min_max(DWORD *enabled_protocols,
 
 
 /* longest is 26, buffer is slightly bigger */
 /* longest is 26, buffer is slightly bigger */
 #define LONGEST_ALG_ID 32
 #define LONGEST_ALG_ID 32
-#define CIPHEROPTION(X)                         \
-  if(strcmp(#X, tmp) == 0)                      \
-    return X
+#define CIPHEROPTION(x) {#x, x}
 
 
-static int
-get_alg_id_by_name(char *name)
-{
-  char tmp[LONGEST_ALG_ID] = { 0 };
-  char *nameEnd = strchr(name, ':');
-  size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
+struct algo {
+  const char *name;
+  int id;
+};
 
 
-  /* reject too-long alg names */
-  if(n > (LONGEST_ALG_ID - 1))
-    return 0;
-
-  strncpy(tmp, name, n);
-  tmp[n] = 0;
-  CIPHEROPTION(CALG_MD2);
-  CIPHEROPTION(CALG_MD4);
-  CIPHEROPTION(CALG_MD5);
-  CIPHEROPTION(CALG_SHA);
-  CIPHEROPTION(CALG_SHA1);
-  CIPHEROPTION(CALG_MAC);
-  CIPHEROPTION(CALG_RSA_SIGN);
-  CIPHEROPTION(CALG_DSS_SIGN);
+static const struct algo algs[]= {
+  CIPHEROPTION(CALG_MD2),
+  CIPHEROPTION(CALG_MD4),
+  CIPHEROPTION(CALG_MD5),
+  CIPHEROPTION(CALG_SHA),
+  CIPHEROPTION(CALG_SHA1),
+  CIPHEROPTION(CALG_MAC),
+  CIPHEROPTION(CALG_RSA_SIGN),
+  CIPHEROPTION(CALG_DSS_SIGN),
 /* ifdefs for the options that are defined conditionally in wincrypt.h */
 /* ifdefs for the options that are defined conditionally in wincrypt.h */
 #ifdef CALG_NO_SIGN
 #ifdef CALG_NO_SIGN
-  CIPHEROPTION(CALG_NO_SIGN);
+  CIPHEROPTION(CALG_NO_SIGN),
 #endif
 #endif
-  CIPHEROPTION(CALG_RSA_KEYX);
-  CIPHEROPTION(CALG_DES);
+  CIPHEROPTION(CALG_RSA_KEYX),
+  CIPHEROPTION(CALG_DES),
 #ifdef CALG_3DES_112
 #ifdef CALG_3DES_112
-  CIPHEROPTION(CALG_3DES_112);
+  CIPHEROPTION(CALG_3DES_112),
 #endif
 #endif
-  CIPHEROPTION(CALG_3DES);
-  CIPHEROPTION(CALG_DESX);
-  CIPHEROPTION(CALG_RC2);
-  CIPHEROPTION(CALG_RC4);
-  CIPHEROPTION(CALG_SEAL);
+  CIPHEROPTION(CALG_3DES),
+  CIPHEROPTION(CALG_DESX),
+  CIPHEROPTION(CALG_RC2),
+  CIPHEROPTION(CALG_RC4),
+  CIPHEROPTION(CALG_SEAL),
 #ifdef CALG_DH_SF
 #ifdef CALG_DH_SF
-  CIPHEROPTION(CALG_DH_SF);
+  CIPHEROPTION(CALG_DH_SF),
 #endif
 #endif
-  CIPHEROPTION(CALG_DH_EPHEM);
+  CIPHEROPTION(CALG_DH_EPHEM),
 #ifdef CALG_AGREEDKEY_ANY
 #ifdef CALG_AGREEDKEY_ANY
-  CIPHEROPTION(CALG_AGREEDKEY_ANY);
+  CIPHEROPTION(CALG_AGREEDKEY_ANY),
 #endif
 #endif
 #ifdef CALG_HUGHES_MD5
 #ifdef CALG_HUGHES_MD5
-  CIPHEROPTION(CALG_HUGHES_MD5);
+  CIPHEROPTION(CALG_HUGHES_MD5),
 #endif
 #endif
-  CIPHEROPTION(CALG_SKIPJACK);
+  CIPHEROPTION(CALG_SKIPJACK),
 #ifdef CALG_TEK
 #ifdef CALG_TEK
-  CIPHEROPTION(CALG_TEK);
+  CIPHEROPTION(CALG_TEK),
 #endif
 #endif
-  CIPHEROPTION(CALG_CYLINK_MEK);
-  CIPHEROPTION(CALG_SSL3_SHAMD5);
+  CIPHEROPTION(CALG_CYLINK_MEK),
+  CIPHEROPTION(CALG_SSL3_SHAMD5),
 #ifdef CALG_SSL3_MASTER
 #ifdef CALG_SSL3_MASTER
-  CIPHEROPTION(CALG_SSL3_MASTER);
+  CIPHEROPTION(CALG_SSL3_MASTER),
 #endif
 #endif
 #ifdef CALG_SCHANNEL_MASTER_HASH
 #ifdef CALG_SCHANNEL_MASTER_HASH
-  CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH);
+  CIPHEROPTION(CALG_SCHANNEL_MASTER_HASH),
 #endif
 #endif
 #ifdef CALG_SCHANNEL_MAC_KEY
 #ifdef CALG_SCHANNEL_MAC_KEY
-  CIPHEROPTION(CALG_SCHANNEL_MAC_KEY);
+  CIPHEROPTION(CALG_SCHANNEL_MAC_KEY),
 #endif
 #endif
 #ifdef CALG_SCHANNEL_ENC_KEY
 #ifdef CALG_SCHANNEL_ENC_KEY
-  CIPHEROPTION(CALG_SCHANNEL_ENC_KEY);
+  CIPHEROPTION(CALG_SCHANNEL_ENC_KEY),
 #endif
 #endif
 #ifdef CALG_PCT1_MASTER
 #ifdef CALG_PCT1_MASTER
-  CIPHEROPTION(CALG_PCT1_MASTER);
+  CIPHEROPTION(CALG_PCT1_MASTER),
 #endif
 #endif
 #ifdef CALG_SSL2_MASTER
 #ifdef CALG_SSL2_MASTER
-  CIPHEROPTION(CALG_SSL2_MASTER);
+  CIPHEROPTION(CALG_SSL2_MASTER),
 #endif
 #endif
 #ifdef CALG_TLS1_MASTER
 #ifdef CALG_TLS1_MASTER
-  CIPHEROPTION(CALG_TLS1_MASTER);
+  CIPHEROPTION(CALG_TLS1_MASTER),
 #endif
 #endif
 #ifdef CALG_RC5
 #ifdef CALG_RC5
-  CIPHEROPTION(CALG_RC5);
+  CIPHEROPTION(CALG_RC5),
 #endif
 #endif
 #ifdef CALG_HMAC
 #ifdef CALG_HMAC
-  CIPHEROPTION(CALG_HMAC);
+  CIPHEROPTION(CALG_HMAC),
 #endif
 #endif
 #ifdef CALG_TLS1PRF
 #ifdef CALG_TLS1PRF
-  CIPHEROPTION(CALG_TLS1PRF);
+  CIPHEROPTION(CALG_TLS1PRF),
 #endif
 #endif
 #ifdef CALG_HASH_REPLACE_OWF
 #ifdef CALG_HASH_REPLACE_OWF
-  CIPHEROPTION(CALG_HASH_REPLACE_OWF);
+  CIPHEROPTION(CALG_HASH_REPLACE_OWF),
 #endif
 #endif
 #ifdef CALG_AES_128
 #ifdef CALG_AES_128
-  CIPHEROPTION(CALG_AES_128);
+  CIPHEROPTION(CALG_AES_128),
 #endif
 #endif
 #ifdef CALG_AES_192
 #ifdef CALG_AES_192
-  CIPHEROPTION(CALG_AES_192);
+  CIPHEROPTION(CALG_AES_192),
 #endif
 #endif
 #ifdef CALG_AES_256
 #ifdef CALG_AES_256
-  CIPHEROPTION(CALG_AES_256);
+  CIPHEROPTION(CALG_AES_256),
 #endif
 #endif
 #ifdef CALG_AES
 #ifdef CALG_AES
-  CIPHEROPTION(CALG_AES);
+  CIPHEROPTION(CALG_AES),
 #endif
 #endif
 #ifdef CALG_SHA_256
 #ifdef CALG_SHA_256
-  CIPHEROPTION(CALG_SHA_256);
+  CIPHEROPTION(CALG_SHA_256),
 #endif
 #endif
 #ifdef CALG_SHA_384
 #ifdef CALG_SHA_384
-  CIPHEROPTION(CALG_SHA_384);
+  CIPHEROPTION(CALG_SHA_384),
 #endif
 #endif
 #ifdef CALG_SHA_512
 #ifdef CALG_SHA_512
-  CIPHEROPTION(CALG_SHA_512);
+  CIPHEROPTION(CALG_SHA_512),
 #endif
 #endif
 #ifdef CALG_ECDH
 #ifdef CALG_ECDH
-  CIPHEROPTION(CALG_ECDH);
+  CIPHEROPTION(CALG_ECDH),
 #endif
 #endif
 #ifdef CALG_ECMQV
 #ifdef CALG_ECMQV
-  CIPHEROPTION(CALG_ECMQV);
+  CIPHEROPTION(CALG_ECMQV),
 #endif
 #endif
 #ifdef CALG_ECDSA
 #ifdef CALG_ECDSA
-  CIPHEROPTION(CALG_ECDSA);
+  CIPHEROPTION(CALG_ECDSA),
 #endif
 #endif
 #ifdef CALG_ECDH_EPHEM
 #ifdef CALG_ECDH_EPHEM
-  CIPHEROPTION(CALG_ECDH_EPHEM);
+  CIPHEROPTION(CALG_ECDH_EPHEM),
 #endif
 #endif
-  return 0;
+  {NULL, 0},
+};
+
+static int
+get_alg_id_by_name(char *name)
+{
+  char *nameEnd = strchr(name, ':');
+  size_t n = nameEnd ? (size_t)(nameEnd - name) : strlen(name);
+  int i;
+
+  for(i = 0; algs[i].name; i++) {
+    if((n == strlen(algs[i].name) && !strncmp(algs[i].name, name, n)))
+      return algs[i].id;
+  }
+  return 0; /* not found */
 }
 }
 
 
 #define NUM_CIPHERS 47 /* There are 47 options listed above */
 #define NUM_CIPHERS 47 /* There are 47 options listed above */
@@ -1201,18 +1206,18 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
     /* The first four bytes will be an unsigned int indicating number
     /* The first four bytes will be an unsigned int indicating number
        of bytes of data in the rest of the buffer. */
        of bytes of data in the rest of the buffer. */
     extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
     extension_len = (unsigned int *)(void *)(&alpn_buffer[cur]);
-    cur += sizeof(unsigned int);
+    cur += (int)sizeof(unsigned int);
 
 
     /* The next four bytes are an indicator that this buffer will contain
     /* The next four bytes are an indicator that this buffer will contain
        ALPN data, as opposed to NPN, for example. */
        ALPN data, as opposed to NPN, for example. */
     *(unsigned int *)(void *)&alpn_buffer[cur] =
     *(unsigned int *)(void *)&alpn_buffer[cur] =
       SecApplicationProtocolNegotiationExt_ALPN;
       SecApplicationProtocolNegotiationExt_ALPN;
-    cur += sizeof(unsigned int);
+    cur += (int)sizeof(unsigned int);
 
 
     /* The next two bytes will be an unsigned short indicating the number
     /* The next two bytes will be an unsigned short indicating the number
        of bytes used to list the preferred protocols. */
        of bytes used to list the preferred protocols. */
     list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
     list_len = (unsigned short*)(void *)(&alpn_buffer[cur]);
-    cur += sizeof(unsigned short);
+    cur += (int)sizeof(unsigned short);
 
 
     list_start_index = cur;
     list_start_index = cur;
 
 
@@ -1225,7 +1230,9 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data)
     cur += proto.len;
     cur += proto.len;
 
 
     *list_len = curlx_uitous(cur - list_start_index);
     *list_len = curlx_uitous(cur - list_start_index);
-    *extension_len = *list_len + sizeof(unsigned int) + sizeof(unsigned short);
+    *extension_len = *list_len +
+      (unsigned short)sizeof(unsigned int) +
+      (unsigned short)sizeof(unsigned short);
 
 
     InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
     InitSecBuffer(&inbuf, SECBUFFER_APPLICATION_PROTOCOLS, alpn_buffer, cur);
     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);
     InitSecBufferDesc(&inbuf_desc, &inbuf, 1);

+ 39 - 68
Utilities/cmcurl/lib/vtls/sectransp.c

@@ -2150,50 +2150,39 @@ static long pem_to_der(const char *in, unsigned char **out, size_t *outlen)
   return sep_end - in;
   return sep_end - in;
 }
 }
 
 
+#define MAX_CERTS_SIZE (50*1024*1024) /* arbitrary - to catch mistakes */
+
 static int read_cert(const char *file, unsigned char **out, size_t *outlen)
 static int read_cert(const char *file, unsigned char **out, size_t *outlen)
 {
 {
   int fd;
   int fd;
-  ssize_t n, len = 0, cap = 512;
-  unsigned char buf[512], *data;
+  ssize_t n;
+  unsigned char buf[512];
+  struct dynbuf certs;
+
+  Curl_dyn_init(&certs, MAX_CERTS_SIZE);
 
 
   fd = open(file, 0);
   fd = open(file, 0);
   if(fd < 0)
   if(fd < 0)
     return -1;
     return -1;
 
 
-  data = malloc(cap);
-  if(!data) {
-    close(fd);
-    return -1;
-  }
-
   for(;;) {
   for(;;) {
     n = read(fd, buf, sizeof(buf));
     n = read(fd, buf, sizeof(buf));
+    if(!n)
+      break;
     if(n < 0) {
     if(n < 0) {
       close(fd);
       close(fd);
-      free(data);
+      Curl_dyn_free(&certs);
       return -1;
       return -1;
     }
     }
-    else if(n == 0) {
+    if(Curl_dyn_addn(&certs, buf, n)) {
       close(fd);
       close(fd);
-      break;
-    }
-
-    if(len + n >= cap) {
-      cap *= 2;
-      data = Curl_saferealloc(data, cap);
-      if(!data) {
-        close(fd);
-        return -1;
-      }
+      return -1;
     }
     }
-
-    memcpy(data + len, buf, n);
-    len += n;
   }
   }
-  data[len] = '\0';
+  close(fd);
 
 
-  *out = data;
-  *outlen = len;
+  *out = Curl_dyn_uptr(&certs);
+  *outlen = Curl_dyn_len(&certs);
 
 
   return 0;
   return 0;
 }
 }
@@ -2202,16 +2191,18 @@ static int append_cert_to_array(struct Curl_easy *data,
                                 const unsigned char *buf, size_t buflen,
                                 const unsigned char *buf, size_t buflen,
                                 CFMutableArrayRef array)
                                 CFMutableArrayRef array)
 {
 {
-    CFDataRef certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
     char *certp;
     char *certp;
     CURLcode result;
     CURLcode result;
+    SecCertificateRef cacert;
+    CFDataRef certdata;
+
+    certdata = CFDataCreate(kCFAllocatorDefault, buf, buflen);
     if(!certdata) {
     if(!certdata) {
       failf(data, "SSL: failed to allocate array for CA certificate");
       failf(data, "SSL: failed to allocate array for CA certificate");
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
 
 
-    SecCertificateRef cacert =
-      SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
+    cacert = SecCertificateCreateWithData(kCFAllocatorDefault, certdata);
     CFRelease(certdata);
     CFRelease(certdata);
     if(!cacert) {
     if(!cacert) {
       failf(data, "SSL: failed to create SecCertificate from CA certificate");
       failf(data, "SSL: failed to create SecCertificate from CA certificate");
@@ -2425,11 +2416,15 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
 
 
   do {
   do {
     SecTrustRef trust;
     SecTrustRef trust;
-    OSStatus ret = SSLCopyPeerTrust(ctx, &trust);
+    OSStatus ret;
+    SecKeyRef keyRef;
+    OSStatus success;
+
+    ret = SSLCopyPeerTrust(ctx, &trust);
     if(ret != noErr || !trust)
     if(ret != noErr || !trust)
       break;
       break;
 
 
-    SecKeyRef keyRef = SecTrustCopyPublicKey(trust);
+    keyRef = SecTrustCopyPublicKey(trust);
     CFRelease(trust);
     CFRelease(trust);
     if(!keyRef)
     if(!keyRef)
       break;
       break;
@@ -2443,8 +2438,8 @@ static CURLcode pkp_pin_peer_pubkey(struct Curl_easy *data,
 
 
 #elif SECTRANSP_PINNEDPUBKEY_V2
 #elif SECTRANSP_PINNEDPUBKEY_V2
 
 
-    OSStatus success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
-                                     &publicKeyBits);
+    success = SecItemExport(keyRef, kSecFormatOpenSSL, 0, NULL,
+                            &publicKeyBits);
     CFRelease(keyRef);
     CFRelease(keyRef);
     if(success != errSecSuccess || !publicKeyBits)
     if(success != errSecSuccess || !publicKeyBits)
       break;
       break;
@@ -2987,12 +2982,13 @@ static CURLcode sectransp_connect_step3(struct Curl_cfilter *cf,
                                         struct Curl_easy *data)
                                         struct Curl_easy *data)
 {
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct ssl_connect_data *connssl = cf->ctx;
+  CURLcode result;
 
 
   DEBUGF(LOG_CF(data, cf, "connect_step3"));
   DEBUGF(LOG_CF(data, cf, "connect_step3"));
   /* There is no step 3!
   /* There is no step 3!
    * Well, okay, let's collect server certificates, and if verbose mode is on,
    * Well, okay, let's collect server certificates, and if verbose mode is on,
    * let's print the details of the server certificates. */
    * let's print the details of the server certificates. */
-  const CURLcode result = collect_server_cert(cf, data);
+  result = collect_server_cert(cf, data);
   if(result)
   if(result)
     return result;
     return result;
 
 
@@ -3237,35 +3233,6 @@ static size_t sectransp_version(char *buffer, size_t size)
   return msnprintf(buffer, size, "SecureTransport");
   return msnprintf(buffer, size, "SecureTransport");
 }
 }
 
 
-/*
- * This function uses SSLGetSessionState to determine connection status.
- *
- * Return codes:
- *     1 means the connection is still in place
- *     0 means the connection has been closed
- *    -1 means the connection status is unknown
- */
-static int sectransp_check_cxn(struct Curl_cfilter *cf,
-                               struct Curl_easy *data)
-{
-  struct ssl_connect_data *connssl = cf->ctx;
-  struct ssl_backend_data *backend = connssl->backend;
-  OSStatus err;
-  SSLSessionState state;
-
-  (void)data;
-  DEBUGASSERT(backend);
-
-  if(backend->ssl_ctx) {
-    DEBUGF(LOG_CF(data, cf, "check connection"));
-    err = SSLGetSessionState(backend->ssl_ctx, &state);
-    if(err == noErr)
-      return state == kSSLConnected || state == kSSLHandshake;
-    return -1;
-  }
-  return 0;
-}
-
 static bool sectransp_data_pending(struct Curl_cfilter *cf,
 static bool sectransp_data_pending(struct Curl_cfilter *cf,
                                    const struct Curl_easy *data)
                                    const struct Curl_easy *data)
 {
 {
@@ -3410,13 +3377,15 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf,
   DEBUGASSERT(backend);
   DEBUGASSERT(backend);
 
 
   again:
   again:
+  *curlcode = CURLE_OK;
   err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed);
   err = SSLRead(backend->ssl_ctx, buf, buffersize, &processed);
 
 
   if(err != noErr) {
   if(err != noErr) {
     switch(err) {
     switch(err) {
       case errSSLWouldBlock:  /* return how much we read (if anything) */
       case errSSLWouldBlock:  /* return how much we read (if anything) */
-        if(processed)
+        if(processed) {
           return (ssize_t)processed;
           return (ssize_t)processed;
+        }
         *curlcode = CURLE_AGAIN;
         *curlcode = CURLE_AGAIN;
         return -1L;
         return -1L;
         break;
         break;
@@ -3428,7 +3397,7 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf,
       case errSSLClosedGraceful:
       case errSSLClosedGraceful:
       case errSSLClosedNoNotify:
       case errSSLClosedNoNotify:
         *curlcode = CURLE_OK;
         *curlcode = CURLE_OK;
-        return -1L;
+        return 0;
         break;
         break;
 
 
         /* The below is errSSLPeerAuthCompleted; it's not defined in
         /* The below is errSSLPeerAuthCompleted; it's not defined in
@@ -3439,8 +3408,10 @@ static ssize_t sectransp_recv(struct Curl_cfilter *cf,
           CURLcode result = verify_cert(cf, data, conn_config->CAfile,
           CURLcode result = verify_cert(cf, data, conn_config->CAfile,
                                         conn_config->ca_info_blob,
                                         conn_config->ca_info_blob,
                                         backend->ssl_ctx);
                                         backend->ssl_ctx);
-          if(result)
-            return result;
+          if(result) {
+            *curlcode = result;
+            return -1;
+          }
         }
         }
         goto again;
         goto again;
       default:
       default:
@@ -3477,7 +3448,7 @@ const struct Curl_ssl Curl_ssl_sectransp = {
   Curl_none_init,                     /* init */
   Curl_none_init,                     /* init */
   Curl_none_cleanup,                  /* cleanup */
   Curl_none_cleanup,                  /* cleanup */
   sectransp_version,                  /* version */
   sectransp_version,                  /* version */
-  sectransp_check_cxn,                /* check_cxn */
+  Curl_none_check_cxn,                /* check_cxn */
   sectransp_shutdown,                 /* shutdown */
   sectransp_shutdown,                 /* shutdown */
   sectransp_data_pending,             /* data_pending */
   sectransp_data_pending,             /* data_pending */
   sectransp_random,                   /* random */
   sectransp_random,                   /* random */

+ 38 - 10
Utilities/cmcurl/lib/vtls/vtls.c

@@ -1604,16 +1604,11 @@ static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
                              struct Curl_easy *data,
                              struct Curl_easy *data,
                              int event, int arg1, void *arg2)
                              int event, int arg1, void *arg2)
 {
 {
-  struct ssl_connect_data *connssl = cf->ctx;
   struct cf_call_data save;
   struct cf_call_data save;
 
 
   (void)arg1;
   (void)arg1;
   (void)arg2;
   (void)arg2;
   switch(event) {
   switch(event) {
-  case CF_CTRL_CONN_REPORT_STATS:
-    if(cf->sockindex == FIRSTSOCKET && !Curl_ssl_cf_is_proxy(cf))
-      Curl_pgrsTimeWas(data, TIMER_APPCONNECT, connssl->handshake_done);
-    break;
   case CF_CTRL_DATA_ATTACH:
   case CF_CTRL_DATA_ATTACH:
     if(Curl_ssl->attach_data) {
     if(Curl_ssl->attach_data) {
       CF_DATA_SAVE(save, cf, data);
       CF_DATA_SAVE(save, cf, data);
@@ -1634,10 +1629,32 @@ static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf,
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data)
+static CURLcode ssl_cf_query(struct Curl_cfilter *cf,
+                             struct Curl_easy *data,
+                             int query, int *pres1, void *pres2)
+{
+  struct ssl_connect_data *connssl = cf->ctx;
+
+  switch(query) {
+  case CF_QUERY_TIMER_APPCONNECT: {
+    struct curltime *when = pres2;
+    if(cf->connected && !Curl_ssl_cf_is_proxy(cf))
+      *when = connssl->handshake_done;
+    return CURLE_OK;
+  }
+  default:
+    break;
+  }
+  return cf->next?
+    cf->next->cft->query(cf->next, data, query, pres1, pres2) :
+    CURLE_UNKNOWN_OPTION;
+}
+
+static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data,
+                            bool *input_pending)
 {
 {
   struct cf_call_data save;
   struct cf_call_data save;
-  bool result;
+  int result;
   /*
   /*
    * This function tries to determine connection status.
    * This function tries to determine connection status.
    *
    *
@@ -1647,9 +1664,20 @@ static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data)
    *    -1 means the connection status is unknown
    *    -1 means the connection status is unknown
    */
    */
   CF_DATA_SAVE(save, cf, data);
   CF_DATA_SAVE(save, cf, data);
-  result = Curl_ssl->check_cxn(cf, data) != 0;
+  result = Curl_ssl->check_cxn(cf, data);
   CF_DATA_RESTORE(cf, save);
   CF_DATA_RESTORE(cf, save);
-  return result;
+  if(result > 0) {
+    *input_pending = TRUE;
+    return TRUE;
+  }
+  if(result == 0) {
+    *input_pending = FALSE;
+    return FALSE;
+  }
+  /* ssl backend does not know */
+  return cf->next?
+    cf->next->cft->is_alive(cf->next, data, input_pending) :
+    FALSE; /* pessimistic in absence of data */
 }
 }
 
 
 struct Curl_cftype Curl_cft_ssl = {
 struct Curl_cftype Curl_cft_ssl = {
@@ -1667,7 +1695,7 @@ struct Curl_cftype Curl_cft_ssl = {
   ssl_cf_cntrl,
   ssl_cf_cntrl,
   cf_ssl_is_alive,
   cf_ssl_is_alive,
   Curl_cf_def_conn_keep_alive,
   Curl_cf_def_conn_keep_alive,
-  Curl_cf_def_query,
+  ssl_cf_query,
 };
 };
 
 
 struct Curl_cftype Curl_cft_ssl_proxy = {
 struct Curl_cftype Curl_cft_ssl_proxy = {

+ 34 - 5
Utilities/cmcurl/lib/vtls/wolfssl.c

@@ -94,6 +94,7 @@
 struct ssl_backend_data {
 struct ssl_backend_data {
   SSL_CTX* ctx;
   SSL_CTX* ctx;
   SSL*     handle;
   SSL*     handle;
+  CURLcode io_result;       /* result of last BIO cfilter operation */
 };
 };
 
 
 #ifdef OPENSSL_EXTRA
 #ifdef OPENSSL_EXTRA
@@ -279,12 +280,16 @@ static long bio_cf_ctrl(WOLFSSL_BIO *bio, int cmd, long num, void *ptr)
 static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
 static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
 {
 {
   struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
   struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
+  struct ssl_connect_data *connssl = cf->ctx;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   ssize_t nwritten;
   ssize_t nwritten;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
 
 
   DEBUGASSERT(data);
   DEBUGASSERT(data);
   nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
   nwritten = Curl_conn_cf_send(cf->next, data, buf, blen, &result);
+  connssl->backend->io_result = result;
+  DEBUGF(LOG_CF(data, cf, "bio_write(len=%d) -> %zd, %d",
+                blen, nwritten, result));
   wolfSSL_BIO_clear_retry_flags(bio);
   wolfSSL_BIO_clear_retry_flags(bio);
   if(nwritten < 0 && CURLE_AGAIN == result)
   if(nwritten < 0 && CURLE_AGAIN == result)
     BIO_set_retry_read(bio);
     BIO_set_retry_read(bio);
@@ -294,6 +299,7 @@ static int bio_cf_out_write(WOLFSSL_BIO *bio, const char *buf, int blen)
 static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
 static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
 {
 {
   struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
   struct Curl_cfilter *cf = wolfSSL_BIO_get_data(bio);
+  struct ssl_connect_data *connssl = cf->ctx;
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   ssize_t nread;
   ssize_t nread;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
@@ -304,6 +310,9 @@ static int bio_cf_in_read(WOLFSSL_BIO *bio, char *buf, int blen)
     return 0;
     return 0;
 
 
   nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
   nread = Curl_conn_cf_recv(cf->next, data, buf, blen, &result);
+  connssl->backend->io_result = result;
+  DEBUGF(LOG_CF(data, cf, "bio_read(len=%d) -> %zd, %d",
+                blen, nread, result));
   wolfSSL_BIO_clear_retry_flags(bio);
   wolfSSL_BIO_clear_retry_flags(bio);
   if(nread < 0 && CURLE_AGAIN == result)
   if(nread < 0 && CURLE_AGAIN == result)
     BIO_set_retry_read(bio);
     BIO_set_retry_read(bio);
@@ -789,6 +798,9 @@ wolfssl_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data)
       }
       }
     }
     }
 #endif
 #endif
+    else if(backend->io_result == CURLE_AGAIN) {
+      return CURLE_OK;
+    }
     else {
     else {
       failf(data, "SSL_connect failed with error %d: %s", detail,
       failf(data, "SSL_connect failed with error %d: %s", detail,
           ERR_error_string(detail, error_buffer));
           ERR_error_string(detail, error_buffer));
@@ -948,7 +960,6 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
   ERR_clear_error();
   ERR_clear_error();
 
 
   rc = SSL_write(backend->handle, mem, memlen);
   rc = SSL_write(backend->handle, mem, memlen);
-
   if(rc <= 0) {
   if(rc <= 0) {
     int err = SSL_get_error(backend->handle, rc);
     int err = SSL_get_error(backend->handle, rc);
 
 
@@ -956,9 +967,17 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
     case SSL_ERROR_WANT_READ:
     case SSL_ERROR_WANT_READ:
     case SSL_ERROR_WANT_WRITE:
     case SSL_ERROR_WANT_WRITE:
       /* there's data pending, re-invoke SSL_write() */
       /* there's data pending, re-invoke SSL_write() */
+      DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len));
       *curlcode = CURLE_AGAIN;
       *curlcode = CURLE_AGAIN;
       return -1;
       return -1;
     default:
     default:
+      if(backend->io_result == CURLE_AGAIN) {
+        DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> AGAIN", len));
+        *curlcode = CURLE_AGAIN;
+        return -1;
+      }
+      DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> %d, %d",
+                    len, rc, err));
       failf(data, "SSL write: %s, errno %d",
       failf(data, "SSL write: %s, errno %d",
             ERR_error_string(err, error_buffer),
             ERR_error_string(err, error_buffer),
             SOCKERRNO);
             SOCKERRNO);
@@ -966,6 +985,7 @@ static ssize_t wolfssl_send(struct Curl_cfilter *cf,
       return -1;
       return -1;
     }
     }
   }
   }
+  DEBUGF(LOG_CF(data, cf, "wolfssl_send(len=%zu) -> %d", len, rc));
   return rc;
   return rc;
 }
 }
 
 
@@ -995,19 +1015,19 @@ static void wolfssl_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 
 
 static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
 static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
                             struct Curl_easy *data,
                             struct Curl_easy *data,
-                            char *buf,
-                            size_t buffersize,
+                            char *buf, size_t blen,
                             CURLcode *curlcode)
                             CURLcode *curlcode)
 {
 {
   struct ssl_connect_data *connssl = cf->ctx;
   struct ssl_connect_data *connssl = cf->ctx;
   struct ssl_backend_data *backend = connssl->backend;
   struct ssl_backend_data *backend = connssl->backend;
   char error_buffer[WOLFSSL_MAX_ERROR_SZ];
   char error_buffer[WOLFSSL_MAX_ERROR_SZ];
-  int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+  int buffsize = (blen > (size_t)INT_MAX) ? INT_MAX : (int)blen;
   int nread;
   int nread;
 
 
   DEBUGASSERT(backend);
   DEBUGASSERT(backend);
 
 
   ERR_clear_error();
   ERR_clear_error();
+  *curlcode = CURLE_OK;
 
 
   nread = SSL_read(backend->handle, buf, buffsize);
   nread = SSL_read(backend->handle, buf, buffsize);
 
 
@@ -1016,22 +1036,31 @@ static ssize_t wolfssl_recv(struct Curl_cfilter *cf,
 
 
     switch(err) {
     switch(err) {
     case SSL_ERROR_ZERO_RETURN: /* no more data */
     case SSL_ERROR_ZERO_RETURN: /* no more data */
-      break;
+      DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> CLOSED", blen));
+      *curlcode = CURLE_OK;
+      return 0;
     case SSL_ERROR_NONE:
     case SSL_ERROR_NONE:
       /* FALLTHROUGH */
       /* FALLTHROUGH */
     case SSL_ERROR_WANT_READ:
     case SSL_ERROR_WANT_READ:
       /* FALLTHROUGH */
       /* FALLTHROUGH */
     case SSL_ERROR_WANT_WRITE:
     case SSL_ERROR_WANT_WRITE:
       /* there's data pending, re-invoke SSL_read() */
       /* there's data pending, re-invoke SSL_read() */
+      DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen));
       *curlcode = CURLE_AGAIN;
       *curlcode = CURLE_AGAIN;
       return -1;
       return -1;
     default:
     default:
+      if(backend->io_result == CURLE_AGAIN) {
+        DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> AGAIN", blen));
+        *curlcode = CURLE_AGAIN;
+        return -1;
+      }
       failf(data, "SSL read: %s, errno %d",
       failf(data, "SSL read: %s, errno %d",
             ERR_error_string(err, error_buffer), SOCKERRNO);
             ERR_error_string(err, error_buffer), SOCKERRNO);
       *curlcode = CURLE_RECV_ERROR;
       *curlcode = CURLE_RECV_ERROR;
       return -1;
       return -1;
     }
     }
   }
   }
+  DEBUGF(LOG_CF(data, cf, "wolfssl_recv(len=%zu) -> %d", blen, nread));
   return nread;
   return nread;
 }
 }
 
 

+ 2 - 2
Utilities/cmcurl/lib/vtls/x509asn1.c

@@ -1118,7 +1118,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
   for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
   for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
     version = (version << 8) | *(const unsigned char *) ccp;
     version = (version << 8) | *(const unsigned char *) ccp;
   if(data->set.ssl.certinfo) {
   if(data->set.ssl.certinfo) {
-    ccp = curl_maprintf("%lx", version);
+    ccp = curl_maprintf("%x", version);
     if(!ccp)
     if(!ccp)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     result = Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
     result = Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
@@ -1127,7 +1127,7 @@ CURLcode Curl_extract_certinfo(struct Curl_easy *data,
       return result;
       return result;
   }
   }
   if(!certnum)
   if(!certnum)
-    infof(data, "   Version: %lu (0x%lx)", version + 1, version);
+    infof(data, "   Version: %u (0x%x)", version + 1, version);
 
 
   /* Serial number. */
   /* Serial number. */
   ccp = ASN1tostr(&cert.serialNumber, 0);
   ccp = ASN1tostr(&cert.serialNumber, 0);

+ 0 - 75
Utilities/cmcurl/lib/wildcard.c

@@ -1,75 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#ifndef CURL_DISABLE_FTP
-
-#include "wildcard.h"
-#include "llist.h"
-#include "fileinfo.h"
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-static void fileinfo_dtor(void *user, void *element)
-{
-  (void)user;
-  Curl_fileinfo_cleanup(element);
-}
-
-CURLcode Curl_wildcard_init(struct WildcardData *wc)
-{
-  Curl_llist_init(&wc->filelist, fileinfo_dtor);
-  wc->state = CURLWC_INIT;
-
-  return CURLE_OK;
-}
-
-void Curl_wildcard_dtor(struct WildcardData *wc)
-{
-  if(!wc)
-    return;
-
-  if(wc->dtor) {
-    wc->dtor(wc->protdata);
-    wc->dtor = ZERO_NULL;
-    wc->protdata = NULL;
-  }
-  DEBUGASSERT(wc->protdata == NULL);
-
-  Curl_llist_destroy(&wc->filelist, NULL);
-
-
-  free(wc->path);
-  wc->path = NULL;
-  free(wc->pattern);
-  wc->pattern = NULL;
-
-  wc->customptr = NULL;
-  wc->state = CURLWC_INIT;
-}
-
-#endif /* if disabled */

+ 0 - 70
Utilities/cmcurl/lib/wildcard.h

@@ -1,70 +0,0 @@
-#ifndef HEADER_CURL_WILDCARD_H
-#define HEADER_CURL_WILDCARD_H
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#ifndef CURL_DISABLE_FTP
-#include <curl/curl.h>
-#include "llist.h"
-
-/* list of wildcard process states */
-typedef enum {
-  CURLWC_CLEAR = 0,
-  CURLWC_INIT = 1,
-  CURLWC_MATCHING, /* library is trying to get list of addresses for
-                      downloading */
-  CURLWC_DOWNLOADING,
-  CURLWC_CLEAN, /* deallocate resources and reset settings */
-  CURLWC_SKIP,  /* skip over concrete file */
-  CURLWC_ERROR, /* error cases */
-  CURLWC_DONE   /* if is wildcard->state == CURLWC_DONE wildcard loop
-                   will end */
-} wildcard_states;
-
-typedef void (*wildcard_dtor)(void *ptr);
-
-/* struct keeping information about wildcard download process */
-struct WildcardData {
-  wildcard_states state;
-  char *path; /* path to the directory, where we trying wildcard-match */
-  char *pattern; /* wildcard pattern */
-  struct Curl_llist filelist; /* llist with struct Curl_fileinfo */
-  void *protdata; /* pointer to protocol specific temporary data */
-  wildcard_dtor dtor;
-  void *customptr;  /* for CURLOPT_CHUNK_DATA pointer */
-};
-
-CURLcode Curl_wildcard_init(struct WildcardData *wc);
-void Curl_wildcard_dtor(struct WildcardData *wc);
-
-struct Curl_easy;
-
-#else
-/* FTP is disabled */
-#define Curl_wildcard_dtor(x)
-#endif
-
-#endif /* HEADER_CURL_WILDCARD_H */

+ 0 - 7
Utilities/cmcurl/lib/ws.c

@@ -166,10 +166,6 @@ CURLcode Curl_ws_accept(struct Curl_easy *data,
   }
   }
   k->upgr101 = UPGR101_RECEIVED;
   k->upgr101 = UPGR101_RECEIVED;
 
 
-  if(data->set.connect_only)
-    /* switch off non-blocking sockets */
-    (void)curlx_nonblock(conn->sock[FIRSTSOCKET], FALSE);
-
   return result;
   return result;
 }
 }
 
 
@@ -750,9 +746,6 @@ CURLcode Curl_ws_disconnect(struct Curl_easy *data,
   (void)data;
   (void)data;
   (void)dead_connection;
   (void)dead_connection;
   Curl_dyn_free(&wsc->early);
   Curl_dyn_free(&wsc->early);
-
-  /* make sure this is non-blocking to avoid getting stuck in shutdown */
-  (void)curlx_nonblock(conn->sock[FIRSTSOCKET], TRUE);
   return CURLE_OK;
   return CURLE_OK;
 }
 }