1
0
Эх сурвалжийг харах

curl 2020-08-19 (9d954e49)

Code extracted from:

    https://github.com/curl/curl.git

at commit 9d954e49bce3706a9a2efb119ecd05767f0f2a9e (curl-7_72_0).
Curl Upstream 5 жил өмнө
parent
commit
7ceb56989f

+ 69 - 0
CMake/FindZstd.cmake

@@ -0,0 +1,69 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1998 - 2020, 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.haxx.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.
+#
+###########################################################################
+
+#[=======================================================================[.rst:
+FindZstd
+----------
+
+Find the zstd library
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+``Zstd_FOUND``
+  System has zstd
+``Zstd_INCLUDE_DIRS``
+  The zstd include directories.
+``Zstd_LIBRARIES``
+  The libraries needed to use zstd
+#]=======================================================================]
+
+if(UNIX)
+  find_package(PkgConfig QUIET)
+  pkg_search_module(PC_Zstd libzstd)
+endif()
+
+find_path(Zstd_INCLUDE_DIR zstd.h
+  HINTS
+    ${PC_Zstd_INCLUDEDIR}
+    ${PC_Zstd_INCLUDE_DIRS}
+)
+
+find_library(Zstd_LIBRARY NAMES zstd
+  HINTS
+    ${PC_Zstd_LIBDIR}
+    ${PC_Zstd_LIBRARY_DIRS}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(Zstd
+  REQUIRED_VARS
+    Zstd_LIBRARY
+    Zstd_INCLUDE_DIR
+)
+
+if(Zstd_FOUND)
+  set(Zstd_LIBRARIES    ${Zstd_LIBRARY})
+  set(Zstd_INCLUDE_DIRS ${Zstd_INCLUDE_DIR})
+endif()
+
+mark_as_advanced(Zstd_INCLUDE_DIRS Zstd_LIBRARIES)

+ 46 - 10
CMakeLists.txt

@@ -82,12 +82,15 @@ if(WIN32)
   set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string")
   set(CURL_TARGET_WINDOWS_VERSION "" CACHE STRING "Minimum target Windows version as hex string")
   if(CURL_TARGET_WINDOWS_VERSION)
   if(CURL_TARGET_WINDOWS_VERSION)
     add_definitions(-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION})
     add_definitions(-D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION})
+    set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WIN32_WINNT=${CURL_TARGET_WINDOWS_VERSION}")
   elseif(ENABLE_INET_PTON)
   elseif(ENABLE_INET_PTON)
     # _WIN32_WINNT_VISTA (0x0600)
     # _WIN32_WINNT_VISTA (0x0600)
     add_definitions(-D_WIN32_WINNT=0x0600)
     add_definitions(-D_WIN32_WINNT=0x0600)
+    set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WIN32_WINNT=0x0600")
   else()
   else()
     # _WIN32_WINNT_WINXP (0x0501)
     # _WIN32_WINNT_WINXP (0x0501)
     add_definitions(-D_WIN32_WINNT=0x0501)
     add_definitions(-D_WIN32_WINNT=0x0501)
+    set(CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS} -D_WIN32_WINNT=0x0501")
   endif()
   endif()
 endif()
 endif()
 option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF)
 option(CURL_LTO "Turn on compiler Link Time Optimizations" OFF)
@@ -101,7 +104,7 @@ option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OF
 
 
 if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
 if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
   if(PICKY_COMPILER)
   if(PICKY_COMPILER)
-    foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wno-long-long -Wfloat-equal -Wno-multichar -Wsign-compare -Wundef -Wno-format-nonliteral -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wno-sign-conversion -Wvla -Wdouble-promotion -Wno-system-headers -Wno-pedantic-ms-format)
+    foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wfloat-equal -Wsign-compare -Wundef -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wvla -Wdouble-promotion)
       # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
       # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
       # test result in.
       # test result in.
       string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname)
       string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname)
@@ -110,6 +113,15 @@ if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
         set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT}")
         set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${_CCOPT}")
       endif()
       endif()
     endforeach()
     endforeach()
+    foreach(_CCOPT long-long multichar format-nonliteral sign-conversion system-headers pedantic-ms-format)
+      # GCC only warns about unknown -Wno- options if there are also other diagnostic messages,
+      # so test for the positive form instead
+      string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname)
+      check_c_compiler_flag("-W${_CCOPT}" ${_optvarname})
+      if(${_optvarname})
+        set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-${_CCOPT}")
+      endif()
+    endforeach()
   endif()
   endif()
 endif()
 endif()
 
 
@@ -213,7 +225,10 @@ if(ENABLE_IPV6 AND NOT WIN32)
   endif()
   endif()
 endif()
 endif()
 
 
-curl_nroff_check()
+if(USE_MANUAL)
+    #nroff is currently only used when USE_MANUAL is set, so we can prevent the warning of no *NROFF if USE_MANUAL is OFF (or not defined), by not even looking for NROFF..
+    curl_nroff_check()
+endif()
 find_package(Perl)
 find_package(Perl)
 
 
 cmake_dependent_option(ENABLE_MANUAL "to provide the built-in manual"
 cmake_dependent_option(ENABLE_MANUAL "to provide the built-in manual"
@@ -297,14 +312,17 @@ endif()
 
 
 # check SSL libraries
 # check SSL libraries
 # TODO support GnuTLS
 # TODO support GnuTLS
+if(CMAKE_USE_WINSSL)
+  message(FATAL_ERROR "The cmake option CMAKE_USE_WINSSL was renamed to CMAKE_USE_SCHANNEL.")
+endif()
 
 
 if(APPLE)
 if(APPLE)
   option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF)
   option(CMAKE_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF)
 endif()
 endif()
 if(WIN32)
 if(WIN32)
-  option(CMAKE_USE_WINSSL "enable Windows native SSL/TLS" OFF)
+  option(CMAKE_USE_SCHANNEL "enable Windows native SSL/TLS" 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
-    CMAKE_USE_WINSSL OFF)
+    CMAKE_USE_SCHANNEL OFF)
 endif()
 endif()
 option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF)
 option(CMAKE_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF)
 option(CMAKE_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF)
 option(CMAKE_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF)
@@ -312,13 +330,13 @@ option(CMAKE_USE_NSS "Enable NSS for SSL/TLS" OFF)
 option(CMAKE_USE_WOLFSSL "enable wolfSSL for SSL/TLS" OFF)
 option(CMAKE_USE_WOLFSSL "enable wolfSSL for SSL/TLS" OFF)
 
 
 set(openssl_default ON)
 set(openssl_default ON)
-if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_WINSSL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS OR CMAKE_USE_WOLFSSL)
+if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_SCHANNEL OR CMAKE_USE_MBEDTLS OR CMAKE_USE_NSS OR CMAKE_USE_WOLFSSL)
   set(openssl_default OFF)
   set(openssl_default OFF)
 endif()
 endif()
 option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ${openssl_default})
 option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ${openssl_default})
 
 
 count_true(enabled_ssl_options_count
 count_true(enabled_ssl_options_count
-  CMAKE_USE_WINSSL
+  CMAKE_USE_SCHANNEL
   CMAKE_USE_SECTRANSP
   CMAKE_USE_SECTRANSP
   CMAKE_USE_OPENSSL
   CMAKE_USE_OPENSSL
   CMAKE_USE_MBEDTLS
   CMAKE_USE_MBEDTLS
@@ -330,10 +348,10 @@ if(enabled_ssl_options_count GREATER "1")
   set(CURL_WITH_MULTI_SSL ON)
   set(CURL_WITH_MULTI_SSL ON)
 endif()
 endif()
 
 
-if(CMAKE_USE_WINSSL)
+if(CMAKE_USE_SCHANNEL)
   set(SSL_ENABLED ON)
   set(SSL_ENABLED ON)
   set(USE_SCHANNEL ON) # Windows native SSL/TLS support
   set(USE_SCHANNEL ON) # Windows native SSL/TLS support
-  set(USE_WINDOWS_SSPI ON) # CMAKE_USE_WINSSL implies CURL_WINDOWS_SSPI
+  set(USE_WINDOWS_SSPI ON) # CMAKE_USE_SCHANNEL implies CURL_WINDOWS_SSPI
   list(APPEND CURL_LIBS "crypt32")
   list(APPEND CURL_LIBS "crypt32")
 endif()
 endif()
 if(CURL_WINDOWS_SSPI)
 if(CURL_WINDOWS_SSPI)
@@ -638,6 +656,22 @@ if(CURL_BROTLI)
   endif()
   endif()
 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)
+  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()
+  if(Zstd_FOUND AND HAVE_ZSTD_CREATEDSTREAM)
+    set(HAVE_ZSTD ON)
+    list(APPEND CURL_LIBS ${Zstd_LIBRARIES})
+    include_directories(${Zstd_INCLUDE_DIRS})
+  endif()
+endif()
+
 #libSSH2
 #libSSH2
 option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON)
 option(CMAKE_USE_LIBSSH2 "Use libSSH2" ON)
 mark_as_advanced(CMAKE_USE_LIBSSH2)
 mark_as_advanced(CMAKE_USE_LIBSSH2)
@@ -1319,11 +1353,13 @@ _add_if("SSL"           SSL_ENABLED)
 _add_if("IPv6"          ENABLE_IPV6)
 _add_if("IPv6"          ENABLE_IPV6)
 _add_if("unix-sockets"  USE_UNIX_SOCKETS)
 _add_if("unix-sockets"  USE_UNIX_SOCKETS)
 _add_if("libz"          HAVE_LIBZ)
 _add_if("libz"          HAVE_LIBZ)
+_add_if("brotli"        HAVE_BROTLI)
+_add_if("zstd"          HAVE_ZSTD)
 _add_if("AsynchDNS"     USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
 _add_if("AsynchDNS"     USE_ARES OR USE_THREADS_POSIX OR USE_THREADS_WIN32)
 _add_if("IDN"           HAVE_LIBIDN2)
 _add_if("IDN"           HAVE_LIBIDN2)
 _add_if("Largefile"     (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND
 _add_if("Largefile"     (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND
                         ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
                         ((SIZEOF_OFF_T GREATER 4) OR USE_WIN32_LARGE_FILES))
-# TODO SSP1 (WinSSL) check is missing
+# TODO SSP1 (Schannel) check is missing
 _add_if("SSPI"          USE_WINDOWS_SSPI)
 _add_if("SSPI"          USE_WINDOWS_SSPI)
 _add_if("GSS-API"       HAVE_GSSAPI)
 _add_if("GSS-API"       HAVE_GSSAPI)
 _add_if("alt-svc"       ENABLE_ALT_SVC)
 _add_if("alt-svc"       ENABLE_ALT_SVC)
@@ -1385,7 +1421,7 @@ message(STATUS "Enabled protocols: ${SUPPORT_PROTOCOLS}")
 
 
 # Clear list and collect SSL backends
 # Clear list and collect SSL backends
 set(_items)
 set(_items)
-_add_if("WinSSL"           SSL_ENABLED AND USE_WINDOWS_SSPI)
+_add_if("Schannel"         SSL_ENABLED AND USE_WINDOWS_SSPI)
 _add_if("OpenSSL"          SSL_ENABLED AND USE_OPENSSL)
 _add_if("OpenSSL"          SSL_ENABLED AND USE_OPENSSL)
 _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP)
 _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP)
 _add_if("mbedTLS"          SSL_ENABLED AND USE_MBEDTLS)
 _add_if("mbedTLS"          SSL_ENABLED AND USE_MBEDTLS)

+ 11 - 6
include/curl/curl.h

@@ -2634,10 +2634,6 @@ typedef enum {
   CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47,
   CURLINFO_PROXY_SSL_VERIFYRESULT = CURLINFO_LONG + 47,
   CURLINFO_PROTOCOL         = CURLINFO_LONG   + 48,
   CURLINFO_PROTOCOL         = CURLINFO_LONG   + 48,
   CURLINFO_SCHEME           = CURLINFO_STRING + 49,
   CURLINFO_SCHEME           = CURLINFO_STRING + 49,
-  /* Fill in new entries below here! */
-
-  /* Preferably these would be defined conditionally based on the
-     sizeof curl_off_t being 64-bits */
   CURLINFO_TOTAL_TIME_T     = CURLINFO_OFF_T + 50,
   CURLINFO_TOTAL_TIME_T     = CURLINFO_OFF_T + 50,
   CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51,
   CURLINFO_NAMELOOKUP_TIME_T = CURLINFO_OFF_T + 51,
   CURLINFO_CONNECT_TIME_T   = CURLINFO_OFF_T + 52,
   CURLINFO_CONNECT_TIME_T   = CURLINFO_OFF_T + 52,
@@ -2646,8 +2642,9 @@ typedef enum {
   CURLINFO_REDIRECT_TIME_T  = CURLINFO_OFF_T + 55,
   CURLINFO_REDIRECT_TIME_T  = CURLINFO_OFF_T + 55,
   CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56,
   CURLINFO_APPCONNECT_TIME_T = CURLINFO_OFF_T + 56,
   CURLINFO_RETRY_AFTER      = CURLINFO_OFF_T + 57,
   CURLINFO_RETRY_AFTER      = CURLINFO_OFF_T + 57,
+  CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58,
 
 
-  CURLINFO_LASTONE          = 57
+  CURLINFO_LASTONE          = 58
 } CURLINFO;
 } CURLINFO;
 
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -2748,6 +2745,7 @@ typedef enum {
   CURLVERSION_FIFTH,
   CURLVERSION_FIFTH,
   CURLVERSION_SIXTH,
   CURLVERSION_SIXTH,
   CURLVERSION_SEVENTH,
   CURLVERSION_SEVENTH,
+  CURLVERSION_EIGHTH,
   CURLVERSION_LAST /* never actually use this */
   CURLVERSION_LAST /* never actually use this */
 } CURLversion;
 } CURLversion;
 
 
@@ -2756,7 +2754,7 @@ typedef enum {
    meant to be a built-in version number for what kind of struct the caller
    meant to be a built-in version number for what kind of struct the caller
    expects. If the struct ever changes, we redefine the NOW to another enum
    expects. If the struct ever changes, we redefine the NOW to another enum
    from above. */
    from above. */
-#define CURLVERSION_NOW CURLVERSION_SEVENTH
+#define CURLVERSION_NOW CURLVERSION_EIGHTH
 
 
 struct curl_version_info_data {
 struct curl_version_info_data {
   CURLversion age;          /* age of the returned struct */
   CURLversion age;          /* age of the returned struct */
@@ -2802,6 +2800,11 @@ struct curl_version_info_data {
   const char *capath;          /* the built-in default CURLOPT_CAPATH, might
   const char *capath;          /* the built-in default CURLOPT_CAPATH, might
                                   be NULL */
                                   be NULL */
 
 
+  /* These fields were added in CURLVERSION_EIGHTH */
+  unsigned int zstd_ver_num; /* Numeric Zstd version
+                                  (MAJOR << 24) | (MINOR << 12) | PATCH */
+  const char *zstd_version; /* human readable string. */
+
 };
 };
 typedef struct curl_version_info_data curl_version_info_data;
 typedef struct curl_version_info_data curl_version_info_data;
 
 
@@ -2836,6 +2839,8 @@ typedef struct curl_version_info_data curl_version_info_data;
 #define CURL_VERSION_BROTLI       (1<<23) /* Brotli features are present. */
 #define CURL_VERSION_BROTLI       (1<<23) /* Brotli features are present. */
 #define CURL_VERSION_ALTSVC       (1<<24) /* Alt-Svc handling built-in */
 #define CURL_VERSION_ALTSVC       (1<<24) /* Alt-Svc handling built-in */
 #define CURL_VERSION_HTTP3        (1<<25) /* HTTP3 support built-in */
 #define CURL_VERSION_HTTP3        (1<<25) /* HTTP3 support built-in */
+#define CURL_VERSION_ZSTD         (1<<26) /* zstd features are present */
+#define CURL_VERSION_UNICODE      (1<<27) /* Unicode support on Windows */
 
 
  /*
  /*
  * NAME curl_version_info()
  * NAME curl_version_info()

+ 4 - 4
include/curl/curlver.h

@@ -30,13 +30,13 @@
 
 
 /* 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.71.1-DEV"
+#define LIBCURL_VERSION "7.72.0-DEV"
 
 
 /* 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_MAJOR 7
-#define LIBCURL_VERSION_MINOR 71
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 72
+#define LIBCURL_VERSION_PATCH 0
 
 
 /* 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
    parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
    parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -57,7 +57,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 0x074701
+#define LIBCURL_VERSION_NUM 0x074800
 
 
 /*
 /*
  * 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

+ 6 - 4
include/curl/multi.h

@@ -427,12 +427,14 @@ CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
  * Name: curl_push_callback
  * Name: curl_push_callback
  *
  *
  * Desc: This callback gets called when a new stream is being pushed by the
  * Desc: This callback gets called when a new stream is being pushed by the
- *       server. It approves or denies the new stream.
+ *       server. It approves or denies the new stream. It can also decide
+ *       to completely fail the connection.
  *
  *
- * Returns: CURL_PUSH_OK or CURL_PUSH_DENY.
+ * Returns: CURL_PUSH_OK, CURL_PUSH_DENY or CURL_PUSH_ERROROUT
  */
  */
-#define CURL_PUSH_OK   0
-#define CURL_PUSH_DENY 1
+#define CURL_PUSH_OK       0
+#define CURL_PUSH_DENY     1
+#define CURL_PUSH_ERROROUT 2 /* added in 7.72.0 */
 
 
 struct curl_pushheaders;  /* forward declaration only */
 struct curl_pushheaders;  /* forward declaration only */
 
 

+ 3 - 2
lib/Makefile.inc

@@ -60,7 +60,8 @@ LIB_CFILES = altsvc.c amigaos.c asyn-ares.c asyn-thread.c base64.c            \
   sendf.c setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \
   sendf.c setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \
   socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c         \
   socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c         \
   strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c    \
   strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c    \
-  transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c dynbuf.c
+  transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c dynbuf.c     \
+  version_win32.c
 
 
 LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h    \
 LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h    \
   content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h      \
   content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h      \
@@ -79,7 +80,7 @@ LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h    \
   smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \
   smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \
   strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h     \
   strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h     \
   timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h           \
   timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h           \
-  x509asn1.h dynbuf.h
+  x509asn1.h dynbuf.h version_win32.h
 
 
 LIB_RCFILES = libcurl.rc
 LIB_RCFILES = libcurl.rc
 
 

+ 4 - 4
lib/asyn-ares.c

@@ -633,7 +633,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 
 
   *waitp = 0; /* default to synchronous response */
   *waitp = 0; /* default to synchronous response */
 
 
-#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+#ifdef ENABLE_IPV6
   switch(conn->ip_version) {
   switch(conn->ip_version) {
   default:
   default:
 #if ARES_VERSION >= 0x010601
 #if ARES_VERSION >= 0x010601
@@ -649,7 +649,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
     family = PF_INET6;
     family = PF_INET6;
     break;
     break;
   }
   }
-#endif /* CURLRES_IPV6 */
+#endif /* ENABLE_IPV6 */
 
 
   bufp = strdup(hostname);
   bufp = strdup(hostname);
   if(bufp) {
   if(bufp) {
@@ -670,7 +670,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 
 
     /* initial status - failed */
     /* initial status - failed */
     res->last_status = ARES_ENOTFOUND;
     res->last_status = ARES_ENOTFOUND;
-#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+#ifdef ENABLE_IPV6
     if(family == PF_UNSPEC) {
     if(family == PF_UNSPEC) {
       if(Curl_ipv6works(conn)) {
       if(Curl_ipv6works(conn)) {
         res->num_pending = 2;
         res->num_pending = 2;
@@ -690,7 +690,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
       }
       }
     }
     }
     else
     else
-#endif /* CURLRES_IPV6 */
+#endif /* ENABLE_IPV6 */
     {
     {
       res->num_pending = 1;
       res->num_pending = 1;
 
 

+ 0 - 1
lib/asyn.h

@@ -164,7 +164,6 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 #define Curl_resolver_kill(x) Curl_nop_stmt
 #define Curl_resolver_kill(x) Curl_nop_stmt
 #define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
 #define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
 #define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
 #define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
-#define Curl_resolver_getsock(x,y,z) 0
 #define Curl_resolver_duphandle(x,y,z) CURLE_OK
 #define Curl_resolver_duphandle(x,y,z) CURLE_OK
 #define Curl_resolver_init(x,y) CURLE_OK
 #define Curl_resolver_init(x,y) CURLE_OK
 #define Curl_resolver_global_init() CURLE_OK
 #define Curl_resolver_global_init() CURLE_OK

+ 15 - 14
lib/connect.c

@@ -74,7 +74,7 @@
 #include "warnless.h"
 #include "warnless.h"
 #include "conncache.h"
 #include "conncache.h"
 #include "multihandle.h"
 #include "multihandle.h"
-#include "system_win32.h"
+#include "version_win32.h"
 #include "quic.h"
 #include "quic.h"
 #include "socks.h"
 #include "socks.h"
 
 
@@ -934,10 +934,10 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
 
         return CURLE_OK;
         return CURLE_OK;
       }
       }
-      infof(data, "Connection failed\n");
     }
     }
-    else if(rc & CURL_CSELECT_ERR)
+    else if(rc & CURL_CSELECT_ERR) {
       (void)verifyconnect(conn->tempsock[i], &error);
       (void)verifyconnect(conn->tempsock[i], &error);
+    }
 
 
     /*
     /*
      * The connection failed here, we should attempt to connect to the "next
      * The connection failed here, we should attempt to connect to the "next
@@ -1085,8 +1085,8 @@ void Curl_sndbufset(curl_socket_t sockfd)
   static int detectOsState = DETECT_OS_NONE;
   static int detectOsState = DETECT_OS_NONE;
 
 
   if(detectOsState == DETECT_OS_NONE) {
   if(detectOsState == DETECT_OS_NONE) {
-    if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
-                                   VERSION_GREATER_THAN_EQUAL))
+    if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT,
+                                    VERSION_GREATER_THAN_EQUAL))
       detectOsState = DETECT_OS_VISTA_OR_LATER;
       detectOsState = DETECT_OS_VISTA_OR_LATER;
     else
     else
       detectOsState = DETECT_OS_PREVISTA;
       detectOsState = DETECT_OS_PREVISTA;
@@ -1363,15 +1363,15 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
 }
 }
 
 
 struct connfind {
 struct connfind {
-  struct connectdata *tofind;
-  bool found;
+  long id_tofind;
+  struct connectdata *found;
 };
 };
 
 
 static int conn_is_conn(struct connectdata *conn, void *param)
 static int conn_is_conn(struct connectdata *conn, void *param)
 {
 {
   struct connfind *f = (struct connfind *)param;
   struct connfind *f = (struct connfind *)param;
-  if(conn == f->tofind) {
-    f->found = TRUE;
+  if(conn->connection_id == f->id_tofind) {
+    f->found = conn;
     return 1;
     return 1;
   }
   }
   return 0;
   return 0;
@@ -1393,21 +1393,22 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
    * - that is associated with a multi handle, and whose connection
    * - that is associated with a multi handle, and whose connection
    *   was detached with CURLOPT_CONNECT_ONLY
    *   was detached with CURLOPT_CONNECT_ONLY
    */
    */
-  if(data->state.lastconnect && (data->multi_easy || data->multi)) {
-    struct connectdata *c = data->state.lastconnect;
+  if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) {
+    struct connectdata *c;
     struct connfind find;
     struct connfind find;
-    find.tofind = data->state.lastconnect;
-    find.found = FALSE;
+    find.id_tofind = data->state.lastconnect_id;
+    find.found = NULL;
 
 
     Curl_conncache_foreach(data, data->multi_easy?
     Curl_conncache_foreach(data, data->multi_easy?
                            &data->multi_easy->conn_cache:
                            &data->multi_easy->conn_cache:
                            &data->multi->conn_cache, &find, conn_is_conn);
                            &data->multi->conn_cache, &find, conn_is_conn);
 
 
     if(!find.found) {
     if(!find.found) {
-      data->state.lastconnect = NULL;
+      data->state.lastconnect_id = -1;
       return CURL_SOCKET_BAD;
       return CURL_SOCKET_BAD;
     }
     }
 
 
+    c = find.found;
     if(connp) {
     if(connp) {
       /* only store this if the caller cares for it */
       /* only store this if the caller cares for it */
       *connp = c;
       *connp = c;

+ 96 - 0
lib/content_encoding.c

@@ -38,6 +38,10 @@
 #include <brotli/decode.h>
 #include <brotli/decode.h>
 #endif
 #endif
 
 
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
+
 #include "sendf.h"
 #include "sendf.h"
 #include "http.h"
 #include "http.h"
 #include "content_encoding.h"
 #include "content_encoding.h"
@@ -710,6 +714,95 @@ static const struct content_encoding brotli_encoding = {
 #endif
 #endif
 
 
 
 
+#ifdef HAVE_ZSTD
+/* Writer parameters. */
+struct zstd_params {
+  ZSTD_DStream *zds;    /* State structure for zstd. */
+  void *decomp;
+};
+
+static CURLcode zstd_init_writer(struct connectdata *conn,
+                                 struct contenc_writer *writer)
+{
+  struct zstd_params *zp = (struct zstd_params *)&writer->params;
+  (void)conn;
+
+  if(!writer->downstream)
+    return CURLE_WRITE_ERROR;
+
+  zp->zds = ZSTD_createDStream();
+  zp->decomp = NULL;
+  return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
+}
+
+static CURLcode zstd_unencode_write(struct connectdata *conn,
+    struct contenc_writer *writer,
+    const char *buf, size_t nbytes)
+{
+  CURLcode result = CURLE_OK;
+  struct zstd_params *zp = (struct zstd_params *)&writer->params;
+  ZSTD_inBuffer in;
+  ZSTD_outBuffer out;
+  size_t errorCode;
+
+  if(!zp->decomp) {
+    zp->decomp = malloc(DSIZ);
+    if(!zp->decomp)
+      return CURLE_OUT_OF_MEMORY;
+  }
+  in.pos = 0;
+  in.src = buf;
+  in.size = nbytes;
+
+  for(;;) {
+    out.pos = 0;
+    out.dst = zp->decomp;
+    out.size = DSIZ;
+
+    errorCode = ZSTD_decompressStream(zp->zds, &out, &in);
+    if(ZSTD_isError(errorCode)) {
+      return CURLE_BAD_CONTENT_ENCODING;
+    }
+    if(out.pos > 0) {
+      result = Curl_unencode_write(conn, writer->downstream,
+                                   zp->decomp, out.pos);
+      if(result)
+        break;
+    }
+    if((in.pos == nbytes) && (out.pos < out.size))
+      break;
+  }
+
+  return result;
+}
+
+static void zstd_close_writer(struct connectdata *conn,
+    struct contenc_writer *writer)
+{
+  struct zstd_params *zp = (struct zstd_params *)&writer->params;
+  (void)conn;
+
+  if(zp->decomp) {
+    free(zp->decomp);
+    zp->decomp = NULL;
+  }
+  if(zp->zds) {
+    ZSTD_freeDStream(zp->zds);
+    zp->zds = NULL;
+  }
+}
+
+static const struct content_encoding zstd_encoding = {
+  "zstd",
+  NULL,
+  zstd_init_writer,
+  zstd_unencode_write,
+  zstd_close_writer,
+  sizeof(struct zstd_params)
+};
+#endif
+
+
 /* Identity handler. */
 /* Identity handler. */
 static CURLcode identity_init_writer(struct connectdata *conn,
 static CURLcode identity_init_writer(struct connectdata *conn,
                                      struct contenc_writer *writer)
                                      struct contenc_writer *writer)
@@ -751,6 +844,9 @@ static const struct content_encoding * const encodings[] = {
 #endif
 #endif
 #ifdef HAVE_BROTLI
 #ifdef HAVE_BROTLI
   &brotli_encoding,
   &brotli_encoding,
+#endif
+#ifdef HAVE_ZSTD
+  &zstd_encoding,
 #endif
 #endif
   NULL
   NULL
 };
 };

+ 3 - 0
lib/curl_config.h.cmake

@@ -437,6 +437,9 @@
 /* if brotli is available */
 /* if brotli is available */
 #cmakedefine HAVE_BROTLI 1
 #cmakedefine HAVE_BROTLI 1
 
 
+/* if zstd is available */
+#cmakedefine HAVE_ZSTD 1
+
 /* if your compiler supports LL */
 /* if your compiler supports LL */
 #cmakedefine HAVE_LL 1
 #cmakedefine HAVE_LL 1
 
 

+ 1 - 1
lib/curl_setup.h

@@ -641,7 +641,7 @@ int netware_init(void);
   defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) ||  \
   defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) ||  \
   defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
   defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
   defined(USE_MBEDTLS) ||                                               \
   defined(USE_MBEDTLS) ||                                               \
-  (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_SET_ODD_PARITY))
+  (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
 
 
 #define USE_NTLM
 #define USE_NTLM
 
 

+ 2 - 1
lib/curl_sspi.c

@@ -28,6 +28,7 @@
 #include "curl_sspi.h"
 #include "curl_sspi.h"
 #include "curl_multibyte.h"
 #include "curl_multibyte.h"
 #include "system_win32.h"
 #include "system_win32.h"
+#include "version_win32.h"
 #include "warnless.h"
 #include "warnless.h"
 
 
 /* The last #include files should be: */
 /* The last #include files should be: */
@@ -82,7 +83,7 @@ CURLcode Curl_sspi_global_init(void)
      * have both these DLLs (security.dll forwards calls to secur32.dll) */
      * have both these DLLs (security.dll forwards calls to secur32.dll) */
 
 
     /* Load SSPI dll into the address space of the calling process */
     /* Load SSPI dll into the address space of the calling process */
-    if(Curl_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL))
+    if(curlx_verify_windows_version(4, 0, PLATFORM_WINNT, VERSION_EQUAL))
       s_hSecDll = Curl_load_library(TEXT("security.dll"));
       s_hSecDll = Curl_load_library(TEXT("security.dll"));
     else
     else
       s_hSecDll = Curl_load_library(TEXT("secur32.dll"));
       s_hSecDll = Curl_load_library(TEXT("secur32.dll"));

+ 3 - 0
lib/curlx.h

@@ -63,6 +63,9 @@
   curlx_unicodefree()
   curlx_unicodefree()
 */
 */
 
 
+#include "version_win32.h"
+/* "version_win32.h" provides curlx_verify_windows_version() */
+
 /* Now setup curlx_ * names for the functions that are to become curlx_ and
 /* Now setup curlx_ * names for the functions that are to become curlx_ and
    be removed from a future libcurl official API:
    be removed from a future libcurl official API:
    curlx_getenv
    curlx_getenv

+ 2 - 2
lib/doh.c

@@ -858,7 +858,7 @@ doh2ai(const struct dohentry *de, const char *hostname, int port)
       addr = (void *)ai->ai_addr; /* storage area for this info */
       addr = (void *)ai->ai_addr; /* storage area for this info */
       DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
       DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
       memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
       memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
-      addr->sin_family = (CURL_SA_FAMILY_T)addrtype;
+      addr->sin_family = addrtype;
       addr->sin_port = htons((unsigned short)port);
       addr->sin_port = htons((unsigned short)port);
       break;
       break;
 
 
@@ -867,7 +867,7 @@ doh2ai(const struct dohentry *de, const char *hostname, int port)
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
       DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
       DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
       memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
       memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
-      addr6->sin6_family = (CURL_SA_FAMILY_T)addrtype;
+      addr6->sin6_family = addrtype;
       addr6->sin6_port = htons((unsigned short)port);
       addr6->sin6_port = htons((unsigned short)port);
       break;
       break;
 #endif
 #endif

+ 2 - 2
lib/dynbuf.h

@@ -53,11 +53,11 @@ size_t Curl_dyn_len(const struct dynbuf *s);
 #define DYN_HAXPROXY        2048
 #define DYN_HAXPROXY        2048
 #define DYN_HTTP_REQUEST    (128*1024)
 #define DYN_HTTP_REQUEST    (128*1024)
 #define DYN_H2_HEADERS      (128*1024)
 #define DYN_H2_HEADERS      (128*1024)
-#define DYN_H2_TRAILER      4096
+#define DYN_H2_TRAILERS     (128*1024)
 #define DYN_APRINTF         8000000
 #define DYN_APRINTF         8000000
 #define DYN_RTSP_REQ_HEADER (64*1024)
 #define DYN_RTSP_REQ_HEADER (64*1024)
 #define DYN_TRAILERS        (64*1024)
 #define DYN_TRAILERS        (64*1024)
 #define DYN_PROXY_CONNECT_HEADERS 16384
 #define DYN_PROXY_CONNECT_HEADERS 16384
 #define DYN_QLOG_NAME       1024
 #define DYN_QLOG_NAME       1024
-#define DYN_H1_TRAILER      DYN_H2_TRAILER
+#define DYN_H1_TRAILER      4096
 #endif
 #endif

+ 1 - 2
lib/easy.c

@@ -838,8 +838,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
 
 
   /* the connection cache is setup on demand */
   /* the connection cache is setup on demand */
   outcurl->state.conn_cache = NULL;
   outcurl->state.conn_cache = NULL;
-
-  outcurl->state.lastconnect = NULL;
+  outcurl->state.lastconnect_id = -1;
 
 
   outcurl->progress.flags    = data->progress.flags;
   outcurl->progress.flags    = data->progress.flags;
   outcurl->progress.callback = data->progress.callback;
   outcurl->progress.callback = data->progress.callback;

+ 3 - 3
lib/ftp.c

@@ -3251,9 +3251,9 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
     }
     }
 
 
     if(conn->ssl[SECONDARYSOCKET].use) {
     if(conn->ssl[SECONDARYSOCKET].use) {
-      /* The secondary socket used SSL so we must close down that part first
-         before we close the socket for real */
-      result = Curl_ssl_shutdown(conn, SECONDARYSOCKET);
+      /* The secondary socket is using SSL so we must close down that part
+         first before we close the socket for real */
+      Curl_ssl_close(conn, SECONDARYSOCKET);
 
 
       /* Note that we keep "use" set to TRUE since that (next) connection is
       /* Note that we keep "use" set to TRUE since that (next) connection is
          still requested to use SSL */
          still requested to use SSL */

+ 29 - 0
lib/getinfo.c

@@ -78,6 +78,7 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
   info->conn_local_ip[0] = '\0';
   info->conn_local_ip[0] = '\0';
   info->conn_primary_port = 0;
   info->conn_primary_port = 0;
   info->conn_local_port = 0;
   info->conn_local_port = 0;
+  info->retry_after = 0;
 
 
   info->conn_scheme = 0;
   info->conn_scheme = 0;
   info->conn_protocol = 0;
   info->conn_protocol = 0;
@@ -95,6 +96,34 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
   case CURLINFO_EFFECTIVE_URL:
   case CURLINFO_EFFECTIVE_URL:
     *param_charp = data->change.url?data->change.url:(char *)"";
     *param_charp = data->change.url?data->change.url:(char *)"";
     break;
     break;
+  case CURLINFO_EFFECTIVE_METHOD: {
+    const char *m = data->set.str[STRING_CUSTOMREQUEST];
+    if(!m) {
+      if(data->set.opt_no_body)
+        m = "HEAD";
+      else {
+        switch(data->state.httpreq) {
+        case HTTPREQ_POST:
+        case HTTPREQ_POST_FORM:
+        case HTTPREQ_POST_MIME:
+          m = "POST";
+          break;
+        case HTTPREQ_PUT:
+          m = "PUT";
+          break;
+        default: /* this should never happen */
+        case HTTPREQ_GET:
+          m = "GET";
+          break;
+        case HTTPREQ_HEAD:
+          m = "HEAD";
+          break;
+        }
+      }
+    }
+    *param_charp = m;
+  }
+    break;
   case CURLINFO_CONTENT_TYPE:
   case CURLINFO_CONTENT_TYPE:
     *param_charp = data->info.contenttype;
     *param_charp = data->info.contenttype;
     break;
     break;

+ 0 - 3
lib/http.c

@@ -2014,9 +2014,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
       case HTTPREQ_PUT:
       case HTTPREQ_PUT:
         request = "PUT";
         request = "PUT";
         break;
         break;
-      case HTTPREQ_OPTIONS:
-        request = "OPTIONS";
-        break;
       default: /* this should never happen */
       default: /* this should never happen */
       case HTTPREQ_GET:
       case HTTPREQ_GET:
         request = "GET";
         request = "GET";

+ 1 - 0
lib/http.h

@@ -148,6 +148,7 @@ struct HTTP {
   struct dynbuf header_recvbuf;
   struct dynbuf header_recvbuf;
   size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into
   size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into
                                   upper layer */
                                   upper layer */
+  struct dynbuf trailer_recvbuf;
   int status_code; /* HTTP status code */
   int status_code; /* HTTP status code */
   const uint8_t *pausedata; /* pointer to data received in on_data_chunk */
   const uint8_t *pausedata; /* pointer to data received in on_data_chunk */
   size_t pauselen; /* the number of bytes left in data */
   size_t pauselen; /* the number of bytes left in data */

+ 60 - 20
lib/http2.c

@@ -514,7 +514,7 @@ static int push_promise(struct Curl_easy *data,
                         struct connectdata *conn,
                         struct connectdata *conn,
                         const nghttp2_push_promise *frame)
                         const nghttp2_push_promise *frame)
 {
 {
-  int rv;
+  int rv; /* one of the CURL_PUSH_* defines */
   H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
   H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!\n",
                frame->promised_stream_id));
                frame->promised_stream_id));
   if(data->multi->push_cb) {
   if(data->multi->push_cb) {
@@ -528,7 +528,7 @@ static int push_promise(struct Curl_easy *data,
     struct Curl_easy *newhandle = duphandle(data);
     struct Curl_easy *newhandle = duphandle(data);
     if(!newhandle) {
     if(!newhandle) {
       infof(data, "failed to duplicate handle\n");
       infof(data, "failed to duplicate handle\n");
-      rv = 1; /* FAIL HARD */
+      rv = CURL_PUSH_DENY; /* FAIL HARD */
       goto fail;
       goto fail;
     }
     }
 
 
@@ -541,13 +541,15 @@ static int push_promise(struct Curl_easy *data,
     if(!stream) {
     if(!stream) {
       failf(data, "Internal NULL stream!\n");
       failf(data, "Internal NULL stream!\n");
       (void)Curl_close(&newhandle);
       (void)Curl_close(&newhandle);
-      rv = 1;
+      rv = CURL_PUSH_DENY;
       goto fail;
       goto fail;
     }
     }
 
 
     rv = set_transfer_url(newhandle, &heads);
     rv = set_transfer_url(newhandle, &heads);
-    if(rv)
+    if(rv) {
+      rv = CURL_PUSH_DENY;
       goto fail;
       goto fail;
+    }
 
 
     Curl_set_in_callback(data, true);
     Curl_set_in_callback(data, true);
     rv = data->multi->push_cb(data, newhandle,
     rv = data->multi->push_cb(data, newhandle,
@@ -563,6 +565,7 @@ static int push_promise(struct Curl_easy *data,
     stream->push_headers_used = 0;
     stream->push_headers_used = 0;
 
 
     if(rv) {
     if(rv) {
+      DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
       /* denied, kill off the new handle again */
       /* denied, kill off the new handle again */
       http2_stream_free(newhandle->req.protop);
       http2_stream_free(newhandle->req.protop);
       newhandle->req.protop = NULL;
       newhandle->req.protop = NULL;
@@ -583,7 +586,7 @@ static int push_promise(struct Curl_easy *data,
       http2_stream_free(newhandle->req.protop);
       http2_stream_free(newhandle->req.protop);
       newhandle->req.protop = NULL;
       newhandle->req.protop = NULL;
       Curl_close(&newhandle);
       Curl_close(&newhandle);
-      rv = 1;
+      rv = CURL_PUSH_DENY;
       goto fail;
       goto fail;
     }
     }
 
 
@@ -595,12 +598,13 @@ static int push_promise(struct Curl_easy *data,
       infof(data, "failed to set user_data for stream %d\n",
       infof(data, "failed to set user_data for stream %d\n",
             frame->promised_stream_id);
             frame->promised_stream_id);
       DEBUGASSERT(0);
       DEBUGASSERT(0);
+      rv = CURL_PUSH_DENY;
       goto fail;
       goto fail;
     }
     }
   }
   }
   else {
   else {
     H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
     H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!\n"));
-    rv = 1;
+    rv = CURL_PUSH_DENY;
   }
   }
   fail:
   fail:
   return rv;
   return rv;
@@ -737,11 +741,16 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
   case NGHTTP2_PUSH_PROMISE:
   case NGHTTP2_PUSH_PROMISE:
     rv = push_promise(data_s, conn, &frame->push_promise);
     rv = push_promise(data_s, conn, &frame->push_promise);
     if(rv) { /* deny! */
     if(rv) { /* deny! */
-      rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
+      int h2;
+      DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
+      h2 = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
                                      frame->push_promise.promised_stream_id,
                                      frame->push_promise.promised_stream_id,
                                      NGHTTP2_CANCEL);
                                      NGHTTP2_CANCEL);
-      if(nghttp2_is_fatal(rv)) {
-        return rv;
+      if(nghttp2_is_fatal(h2))
+        return NGHTTP2_ERR_CALLBACK_FAILURE;
+      else if(rv == CURL_PUSH_ERROROUT) {
+        DEBUGF(infof(data_s, "Fail the parent stream (too)\n"));
+        return NGHTTP2_ERR_CALLBACK_FAILURE;
       }
       }
     }
     }
     break;
     break;
@@ -839,7 +848,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
       return 0;
       return 0;
     }
     }
     H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
     H2BUGF(infof(data_s, "on_stream_close(), %s (err %d), stream %u\n",
-                 nghttp2_strerror(error_code), error_code, stream_id));
+                 nghttp2_http2_strerror(error_code), error_code, stream_id));
     stream = data_s->req.protop;
     stream = data_s->req.protop;
     if(!stream)
     if(!stream)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
       return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1006,18 +1015,11 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
 
 
   if(stream->bodystarted) {
   if(stream->bodystarted) {
     /* This is a trailer */
     /* This is a trailer */
-    struct dynbuf trail;
     H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
     H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
                  value));
                  value));
-    Curl_dyn_init(&trail, DYN_H2_TRAILER);
-    result = Curl_dyn_addf(&trail,
+    result = Curl_dyn_addf(&stream->trailer_recvbuf,
                            "%.*s: %.*s\r\n", namelen, name,
                            "%.*s: %.*s\r\n", namelen, name,
                            valuelen, value);
                            valuelen, value);
-    if(!result)
-      result = Curl_client_write(conn, CLIENTWRITE_HEADER,
-                                 Curl_dyn_ptr(&trail),
-                                 Curl_dyn_len(&trail));
-    Curl_dyn_free(&trail);
     if(result)
     if(result)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
       return NGHTTP2_ERR_CALLBACK_FAILURE;
 
 
@@ -1165,6 +1167,7 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
   /* there might be allocated resources done before this got the 'h2' pointer
   /* there might be allocated resources done before this got the 'h2' pointer
      setup */
      setup */
   Curl_dyn_free(&http->header_recvbuf);
   Curl_dyn_free(&http->header_recvbuf);
+  Curl_dyn_free(&http->trailer_recvbuf);
   if(http->push_headers) {
   if(http->push_headers) {
     /* if they weren't used and then freed before */
     /* if they weren't used and then freed before */
     for(; http->push_headers_used > 0; --http->push_headers_used) {
     for(; http->push_headers_used > 0; --http->push_headers_used) {
@@ -1174,7 +1177,8 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
     http->push_headers = NULL;
     http->push_headers = NULL;
   }
   }
 
 
-  if(!httpc->h2) /* not HTTP/2 ? */
+  if(!(data->conn->handler->protocol&PROTO_FAMILY_HTTP) ||
+     !httpc->h2) /* not HTTP/2 ? */
     return;
     return;
 
 
   if(premature) {
   if(premature) {
@@ -1203,6 +1207,13 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
     }
     }
     http->stream_id = 0;
     http->stream_id = 0;
   }
   }
+
+  if(0 == nghttp2_session_check_request_allowed(httpc->h2)) {
+    /* No more requests are allowed in the current session, so the connection
+       may not be reused. This is set when a GOAWAY frame has been received or
+       when the limit of stream identifiers has been reached. */
+    connclose(data->conn, "http/2: No new requests allowed");
+  }
 }
 }
 
 
 /*
 /*
@@ -1456,7 +1467,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
   }
   }
   else if(httpc->error_code != NGHTTP2_NO_ERROR) {
   else if(httpc->error_code != NGHTTP2_NO_ERROR) {
     failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)",
     failf(data, "HTTP/2 stream %d was not closed cleanly: %s (err %u)",
-          stream->stream_id, nghttp2_strerror(httpc->error_code),
+          stream->stream_id, nghttp2_http2_strerror(httpc->error_code),
           httpc->error_code);
           httpc->error_code);
     *err = CURLE_HTTP2_STREAM;
     *err = CURLE_HTTP2_STREAM;
     return -1;
     return -1;
@@ -1470,6 +1481,31 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
     return -1;
     return -1;
   }
   }
 
 
+  if(Curl_dyn_len(&stream->trailer_recvbuf)) {
+    char *trailp = Curl_dyn_ptr(&stream->trailer_recvbuf);
+    char *lf;
+
+    do {
+      size_t len = 0;
+      CURLcode result;
+      /* each trailer line ends with a newline */
+      lf = strchr(trailp, '\n');
+      if(!lf)
+        break;
+      len = lf + 1 - trailp;
+
+      if(data->set.verbose)
+        Curl_debug(data, CURLINFO_HEADER_IN, trailp, len);
+      /* pass the trailers one by one to the callback */
+      result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailp, len);
+      if(result) {
+        *err = result;
+        return -1;
+      }
+      trailp = ++lf;
+    } while(lf);
+  }
+
   stream->close_handled = TRUE;
   stream->close_handled = TRUE;
 
 
   H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
   H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
@@ -2075,6 +2111,9 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
 
 
   h2_pri_spec(conn->data, &pri_spec);
   h2_pri_spec(conn->data, &pri_spec);
 
 
+  H2BUGF(infof(conn->data, "http2_send request allowed %d (easy handle %p)\n",
+               nghttp2_session_check_request_allowed(h2), (void *)conn->data));
+
   switch(conn->data->state.httpreq) {
   switch(conn->data->state.httpreq) {
   case HTTPREQ_POST:
   case HTTPREQ_POST:
   case HTTPREQ_POST_FORM:
   case HTTPREQ_POST_FORM:
@@ -2151,6 +2190,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
   stream->stream_id = -1;
   stream->stream_id = -1;
 
 
   Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS);
   Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS);
+  Curl_dyn_init(&stream->trailer_recvbuf, DYN_H2_TRAILERS);
 
 
   if((conn->handler == &Curl_handler_http2_ssl) ||
   if((conn->handler == &Curl_handler_http2_ssl) ||
      (conn->handler == &Curl_handler_http2))
      (conn->handler == &Curl_handler_http2))

+ 3 - 1
lib/md4.c

@@ -102,7 +102,9 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
 #include <openssl/md4.h>
 #include <openssl/md4.h>
 
 
 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
-              (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
+              (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
+       defined(__MAC_OS_X_VERSION_MIN_ALLOWED) && \
+              (__MAC_OS_X_VERSION_MIN_ALLOWED < 101500)) || \
       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
 
 

+ 3 - 1
lib/md5.c

@@ -139,7 +139,9 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
 }
 }
 
 
 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
 #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
-              (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
+              (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040) && \
+       defined(__MAC_OS_X_VERSION_MIN_ALLOWED) && \
+              (__MAC_OS_X_VERSION_MIN_ALLOWED < 101500)) || \
       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
 
 

+ 10 - 0
lib/memdebug.c

@@ -456,6 +456,16 @@ FILE *curl_dbg_fopen(const char *file, const char *mode,
   return res;
   return res;
 }
 }
 
 
+FILE *curl_dbg_fdopen(int filedes, const char *mode,
+                      int line, const char *source)
+{
+  FILE *res = fdopen(filedes, mode);
+  if(source)
+    curl_dbg_log("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
+                 source, line, filedes, mode, (void *)res);
+  return res;
+}
+
 int curl_dbg_fclose(FILE *file, int line, const char *source)
 int curl_dbg_fclose(FILE *file, int line, const char *source)
 {
 {
   int res;
   int res;

+ 4 - 1
lib/memdebug.h

@@ -8,7 +8,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -79,6 +79,9 @@ CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd,
 /* FILE functions */
 /* FILE functions */
 CURL_EXTERN FILE *curl_dbg_fopen(const char *file, const char *mode, int line,
 CURL_EXTERN FILE *curl_dbg_fopen(const char *file, const char *mode, int line,
                                  const char *source);
                                  const char *source);
+CURL_EXTERN FILE *curl_dbg_fdopen(int filedes, const char *mode,
+                                  int line, const char *source);
+
 CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
 CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source);
 
 
 #ifndef MEMDEBUG_NODEFINES
 #ifndef MEMDEBUG_NODEFINES

+ 20 - 6
lib/mprintf.c

@@ -178,12 +178,14 @@ static long dprintf_DollarString(char *input, char **end)
 {
 {
   int number = 0;
   int number = 0;
   while(ISDIGIT(*input)) {
   while(ISDIGIT(*input)) {
-    number *= 10;
-    number += *input-'0';
+    if(number < MAX_PARAMETERS) {
+      number *= 10;
+      number += *input - '0';
+    }
     input++;
     input++;
   }
   }
-  if(number && ('$'==*input++)) {
-    *end = input;
+  if(number <= MAX_PARAMETERS && ('$' == *input)) {
+    *end = ++input;
     return number;
     return number;
   }
   }
   return 0;
   return 0;
@@ -377,6 +379,8 @@ static int dprintf_Pass1(const char *format, struct va_stack *vto,
           if(width > max_param)
           if(width > max_param)
             max_param = width;
             max_param = width;
           break;
           break;
+        case '\0':
+          fmt--;
         default:
         default:
           break;
           break;
         }
         }
@@ -458,6 +462,9 @@ static int dprintf_Pass1(const char *format, struct va_stack *vto,
         /* we have the width specified from a parameter, so we make that
         /* we have the width specified from a parameter, so we make that
            parameter's info setup properly */
            parameter's info setup properly */
         long k = width - 1;
         long k = width - 1;
+        if((k < 0) || (k >= MAX_PARAMETERS))
+          /* out of allowed range */
+          return 1;
         vto[i].width = k;
         vto[i].width = k;
         vto[k].type = FORMAT_WIDTH;
         vto[k].type = FORMAT_WIDTH;
         vto[k].flags = FLAGS_NEW;
         vto[k].flags = FLAGS_NEW;
@@ -469,6 +476,9 @@ static int dprintf_Pass1(const char *format, struct va_stack *vto,
         /* we have the precision specified from a parameter, so we make that
         /* we have the precision specified from a parameter, so we make that
            parameter's info setup properly */
            parameter's info setup properly */
         long k = precision - 1;
         long k = precision - 1;
+        if((k < 0) || (k >= MAX_PARAMETERS))
+          /* out of allowed range */
+          return 1;
         vto[i].precision = k;
         vto[i].precision = k;
         vto[k].type = FORMAT_WIDTH;
         vto[k].type = FORMAT_WIDTH;
         vto[k].flags = FLAGS_NEW;
         vto[k].flags = FLAGS_NEW;
@@ -476,7 +486,7 @@ static int dprintf_Pass1(const char *format, struct va_stack *vto,
         vto[k].width = 0;
         vto[k].width = 0;
         vto[k].precision = 0;
         vto[k].precision = 0;
       }
       }
-      *endpos++ = fmt + 1; /* end of this sequence */
+      *endpos++ = fmt + ((*fmt == '\0') ? 0 : 1); /* end of this sequence */
     }
     }
   }
   }
 
 
@@ -754,7 +764,7 @@ static int dprintf_formatf(
 
 
       if(prec > 0) {
       if(prec > 0) {
         width -= prec;
         width -= prec;
-        while(prec-- > 0)
+        while(prec-- > 0 && w >= work)
           *w-- = '0';
           *w-- = '0';
       }
       }
 
 
@@ -918,6 +928,8 @@ static int dprintf_formatf(
              precision */
              precision */
           size_t maxprec = sizeof(work) - 2;
           size_t maxprec = sizeof(work) - 2;
           double val = p->data.dnum;
           double val = p->data.dnum;
+          if(width > 0 && prec <= width)
+            maxprec -= width;
           while(val >= 10.0) {
           while(val >= 10.0) {
             val /= 10;
             val /= 10;
             maxprec--;
             maxprec--;
@@ -925,6 +937,8 @@ static int dprintf_formatf(
 
 
           if(prec > (long)maxprec)
           if(prec > (long)maxprec)
             prec = (long)maxprec-1;
             prec = (long)maxprec-1;
+          if(prec < 0)
+            prec = 0;
           /* RECURSIVE USAGE */
           /* RECURSIVE USAGE */
           len = curl_msnprintf(fptr, left, ".%ld", prec);
           len = curl_msnprintf(fptr, left, ".%ld", prec);
           fptr += len;
           fptr += len;

+ 37 - 25
lib/multi.c

@@ -455,6 +455,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
     data->state.conn_cache = &data->share->conn_cache;
     data->state.conn_cache = &data->share->conn_cache;
   else
   else
     data->state.conn_cache = &multi->conn_cache;
     data->state.conn_cache = &multi->conn_cache;
+  data->state.lastconnect_id = -1;
 
 
 #ifdef USE_LIBPSL
 #ifdef USE_LIBPSL
   /* Do the same for PSL. */
   /* Do the same for PSL. */
@@ -677,11 +678,11 @@ static CURLcode multi_done(struct Curl_easy *data,
     CONNCACHE_UNLOCK(data);
     CONNCACHE_UNLOCK(data);
     if(Curl_conncache_return_conn(data, conn)) {
     if(Curl_conncache_return_conn(data, conn)) {
       /* remember the most recently used connection */
       /* remember the most recently used connection */
-      data->state.lastconnect = conn;
+      data->state.lastconnect_id = conn->connection_id;
       infof(data, "%s\n", buffer);
       infof(data, "%s\n", buffer);
     }
     }
     else
     else
-      data->state.lastconnect = NULL;
+      data->state.lastconnect_id = -1;
   }
   }
 
 
   Curl_safefree(data->state.buffer);
   Curl_safefree(data->state.buffer);
@@ -689,6 +690,26 @@ static CURLcode multi_done(struct Curl_easy *data,
   return result;
   return result;
 }
 }
 
 
+static int close_connect_only(struct connectdata *conn, void *param)
+{
+  struct Curl_easy *data = param;
+
+  if(data->state.lastconnect_id != conn->connection_id)
+    return 0;
+
+  if(conn->data != data)
+    return 1;
+  conn->data = NULL;
+
+  if(!conn->bits.connect_only)
+    return 1;
+
+  connclose(conn, "Removing connect-only easy handle");
+  conn->bits.connect_only = FALSE;
+
+  return 1;
+}
+
 CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
 CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
                                    struct Curl_easy *data)
                                    struct Curl_easy *data)
 {
 {
@@ -776,10 +797,6 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
      multi_done() as that may actually call Curl_expire that uses this */
      multi_done() as that may actually call Curl_expire that uses this */
   Curl_llist_destroy(&data->state.timeoutlist, NULL);
   Curl_llist_destroy(&data->state.timeoutlist, NULL);
 
 
-  /* as this was using a shared connection cache we clear the pointer to that
-     since we're not part of that multi handle anymore */
-  data->state.conn_cache = 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 = CURLM_STATE_COMPLETED;
   data->mstate = CURLM_STATE_COMPLETED;
@@ -789,12 +806,22 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
   /* Remove the association between the connection and the handle */
   /* Remove the association between the connection and the handle */
   Curl_detach_connnection(data);
   Curl_detach_connnection(data);
 
 
+  if(data->state.lastconnect_id != -1) {
+    /* Mark any connect-only connection for closure */
+    Curl_conncache_foreach(data, data->state.conn_cache,
+                           data, &close_connect_only);
+  }
+
 #ifdef USE_LIBPSL
 #ifdef USE_LIBPSL
   /* Remove the PSL association. */
   /* Remove the PSL association. */
   if(data->psl == &multi->psl)
   if(data->psl == &multi->psl)
     data->psl = NULL;
     data->psl = NULL;
 #endif
 #endif
 
 
+  /* as this was using a shared connection cache we clear the pointer to that
+     since we're not part of that multi handle anymore */
+  data->state.conn_cache = NULL;
+
   data->multi = NULL; /* clear the association to this multi handle */
   data->multi = NULL; /* clear the association to this multi handle */
 
 
   /* make sure there's no pending message in the queue sent from this easy
   /* make sure there's no pending message in the queue sent from this easy
@@ -958,19 +985,6 @@ static int multi_getsock(struct Curl_easy *data,
 
 
   switch(data->mstate) {
   switch(data->mstate) {
   default:
   default:
-#if 0 /* switch back on these cases to get the compiler to check for all enums
-         to be present */
-  case CURLM_STATE_TOOFAST:  /* returns 0, so will not select. */
-  case CURLM_STATE_COMPLETED:
-  case CURLM_STATE_MSGSENT:
-  case CURLM_STATE_INIT:
-  case CURLM_STATE_CONNECT:
-  case CURLM_STATE_WAITDO:
-  case CURLM_STATE_DONE:
-  case CURLM_STATE_LAST:
-    /* this will get called with CURLM_STATE_COMPLETED when a handle is
-       removed */
-#endif
     return 0;
     return 0;
 
 
   case CURLM_STATE_WAITRESOLVE:
   case CURLM_STATE_WAITRESOLVE:
@@ -1255,7 +1269,7 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
         sleep_ms = timeout_ms;
         sleep_ms = timeout_ms;
       /* when there are no easy handles in the multi, this holds a -1
       /* when there are no easy handles in the multi, this holds a -1
          timeout */
          timeout */
-      else if((sleep_ms < 0) && extrawait)
+      else if(sleep_ms < 0)
         sleep_ms = timeout_ms;
         sleep_ms = timeout_ms;
       Curl_wait_ms(sleep_ms);
       Curl_wait_ms(sleep_ms);
     }
     }
@@ -1808,7 +1822,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
             multistate(data, CURLM_STATE_SENDPROTOCONNECT);
             multistate(data, CURLM_STATE_SENDPROTOCONNECT);
           }
           }
         }
         }
-      else if(result)
+      else
         stream_error = TRUE;
         stream_error = TRUE;
       break;
       break;
 #endif
 #endif
@@ -1858,7 +1872,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         multistate(data, CURLM_STATE_DO);
         multistate(data, CURLM_STATE_DO);
         rc = CURLM_CALL_MULTI_PERFORM;
         rc = CURLM_CALL_MULTI_PERFORM;
       }
       }
-      else if(result) {
+      else {
         /* failure detected */
         /* failure detected */
         Curl_posttransfer(data);
         Curl_posttransfer(data);
         multi_done(data, result, TRUE);
         multi_done(data, result, TRUE);
@@ -2962,9 +2976,7 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
       long streams = va_arg(param, long);
       long streams = va_arg(param, long);
       if(streams < 1)
       if(streams < 1)
         streams = 100;
         streams = 100;
-      multi->max_concurrent_streams =
-        (streams > (long)INITIAL_MAX_CONCURRENT_STREAMS)?
-        INITIAL_MAX_CONCURRENT_STREAMS : (unsigned int)streams;
+      multi->max_concurrent_streams = curlx_sltoui(streams);
     }
     }
     break;
     break;
   default:
   default:

+ 1 - 1
lib/multihandle.h

@@ -81,7 +81,7 @@ struct Curl_multi {
      this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
      this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
   long type;
   long type;
 
 
-  /* We have a doubly-linked circular list with easy handles */
+  /* We have a doubly-linked list with easy handles */
   struct Curl_easy *easyp;
   struct Curl_easy *easyp;
   struct Curl_easy *easylp; /* last node */
   struct Curl_easy *easylp; /* last node */
 
 

+ 2 - 1
lib/parsedate.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -624,6 +624,7 @@ CURLcode Curl_gmtime(time_t intime, struct tm *store)
   /* thread-safe version */
   /* thread-safe version */
   tm = (struct tm *)gmtime_r(&intime, store);
   tm = (struct tm *)gmtime_r(&intime, store);
 #else
 #else
+  /* !checksrc! disable BANNEDFUNC 1 */
   tm = gmtime(&intime);
   tm = gmtime(&intime);
   if(tm)
   if(tm)
     *store = *tm; /* copy the pointed struct to the local copy */
     *store = *tm; /* copy the pointed struct to the local copy */

+ 12 - 3
lib/rename.c

@@ -27,6 +27,7 @@
 #if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) ||  \
 #if (!defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)) ||  \
   defined(USE_ALTSVC)
   defined(USE_ALTSVC)
 
 
+#include "curl_multibyte.h"
 #include "timeval.h"
 #include "timeval.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
@@ -39,17 +40,25 @@ int Curl_rename(const char *oldpath, const char *newpath)
 {
 {
 #ifdef WIN32
 #ifdef WIN32
   /* rename() on Windows doesn't overwrite, so we can't use it here.
   /* rename() on Windows doesn't overwrite, so we can't use it here.
-     MoveFileExA() will overwrite and is usually atomic, however it fails
+     MoveFileEx() will overwrite and is usually atomic, however it fails
      when there are open handles to the file. */
      when there are open handles to the file. */
   const int max_wait_ms = 1000;
   const int max_wait_ms = 1000;
   struct curltime start = Curl_now();
   struct curltime start = Curl_now();
+  TCHAR *tchar_oldpath = curlx_convert_UTF8_to_tchar((char *)oldpath);
+  TCHAR *tchar_newpath = curlx_convert_UTF8_to_tchar((char *)newpath);
   for(;;) {
   for(;;) {
     timediff_t diff;
     timediff_t diff;
-    if(MoveFileExA(oldpath, newpath, MOVEFILE_REPLACE_EXISTING))
+    if(MoveFileEx(tchar_oldpath, tchar_newpath, MOVEFILE_REPLACE_EXISTING)) {
+      curlx_unicodefree(tchar_oldpath);
+      curlx_unicodefree(tchar_newpath);
       break;
       break;
+    }
     diff = Curl_timediff(Curl_now(), start);
     diff = Curl_timediff(Curl_now(), start);
-    if(diff < 0 || diff > max_wait_ms)
+    if(diff < 0 || diff > max_wait_ms) {
+      curlx_unicodefree(tchar_oldpath);
+      curlx_unicodefree(tchar_newpath);
       return 1;
       return 1;
+    }
     Sleep(1);
     Sleep(1);
   }
   }
 #else
 #else

+ 2 - 0
lib/setopt.c

@@ -274,6 +274,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     if(data->set.opt_no_body)
     if(data->set.opt_no_body)
       /* in HTTP lingo, no body means using the HEAD request... */
       /* in HTTP lingo, no body means using the HEAD request... */
       data->set.method = HTTPREQ_HEAD;
       data->set.method = HTTPREQ_HEAD;
+    else if(data->set.method == HTTPREQ_HEAD)
+      data->set.method = HTTPREQ_GET;
     break;
     break;
   case CURLOPT_FAILONERROR:
   case CURLOPT_FAILONERROR:
     /*
     /*

+ 4 - 2
lib/smtp.c

@@ -1760,8 +1760,10 @@ static CURLcode smtp_parse_address(struct connectdata *conn, const char *fqma,
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
   length = strlen(dup);
   length = strlen(dup);
-  if(dup[length - 1] == '>')
-    dup[length - 1] = '\0';
+  if(length) {
+    if(dup[length - 1] == '>')
+      dup[length - 1] = '\0';
+  }
 
 
   /* Extract the host name from the address (if we can) */
   /* Extract the host name from the address (if we can) */
   host->name = strpbrk(dup, "@");
   host->name = strpbrk(dup, "@");

+ 3 - 3
lib/socks.c

@@ -327,18 +327,18 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
      * Make connection
      * Make connection
      */
      */
     {
     {
-      ssize_t packetsize = 9 +
+      size_t packetsize = 9 +
         strlen((char *)socksreq + 8); /* size including NUL */
         strlen((char *)socksreq + 8); /* size including NUL */
 
 
       /* If SOCKS4a, set special invalid IP address 0.0.0.x */
       /* If SOCKS4a, set special invalid IP address 0.0.0.x */
       if(protocol4a) {
       if(protocol4a) {
-        ssize_t hostnamelen = 0;
+        size_t hostnamelen = 0;
         socksreq[4] = 0;
         socksreq[4] = 0;
         socksreq[5] = 0;
         socksreq[5] = 0;
         socksreq[6] = 0;
         socksreq[6] = 0;
         socksreq[7] = 1;
         socksreq[7] = 1;
         /* append hostname */
         /* append hostname */
-        hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */
+        hostnamelen = strlen(hostname) + 1; /* length including NUL */
         if(hostnamelen <= 255)
         if(hostnamelen <= 255)
           strcpy((char *)socksreq + packetsize, hostname);
           strcpy((char *)socksreq + packetsize, hostname);
         else {
         else {

+ 4 - 9
lib/strdup.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -39,19 +39,14 @@ char *curlx_strdup(const char *str)
   if(!str)
   if(!str)
     return (char *)NULL;
     return (char *)NULL;
 
 
-  len = strlen(str);
+  len = strlen(str) + 1;
 
 
-  if(len >= ((size_t)-1) / sizeof(char))
-    return (char *)NULL;
-
-  newstr = malloc((len + 1)*sizeof(char));
+  newstr = malloc(len);
   if(!newstr)
   if(!newstr)
     return (char *)NULL;
     return (char *)NULL;
 
 
-  memcpy(newstr, str, (len + 1)*sizeof(char));
-
+  memcpy(newstr, str, len);
   return newstr;
   return newstr;
-
 }
 }
 #endif
 #endif
 
 

+ 3 - 194
lib/system_win32.c

@@ -26,6 +26,7 @@
 
 
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include "system_win32.h"
 #include "system_win32.h"
+#include "version_win32.h"
 #include "curl_sspi.h"
 #include "curl_sspi.h"
 #include "warnless.h"
 #include "warnless.h"
 
 
@@ -106,8 +107,8 @@ CURLcode Curl_win32_init(long flags)
       Curl_if_nametoindex = pIfNameToIndex;
       Curl_if_nametoindex = pIfNameToIndex;
   }
   }
 
 
-  if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
-                                 VERSION_GREATER_THAN_EQUAL)) {
+  if(curlx_verify_windows_version(6, 0, PLATFORM_WINNT,
+                                  VERSION_GREATER_THAN_EQUAL)) {
     Curl_isVistaOrGreater = TRUE;
     Curl_isVistaOrGreater = TRUE;
   }
   }
   else
   else
@@ -159,198 +160,6 @@ typedef HMODULE (APIENTRY *LOADLIBRARYEX_FN)(LPCTSTR, HANDLE, DWORD);
 #  define LOADLIBARYEX    "LoadLibraryExA"
 #  define LOADLIBARYEX    "LoadLibraryExA"
 #endif
 #endif
 
 
-/*
- * Curl_verify_windows_version()
- *
- * This is used to verify if we are running on a specific windows version.
- *
- * Parameters:
- *
- * majorVersion [in] - The major version number.
- * minorVersion [in] - The minor version number.
- * platform     [in] - The optional platform identifier.
- * condition    [in] - The test condition used to specifier whether we are
- *                     checking a version less then, equal to or greater than
- *                     what is specified in the major and minor version
- *                     numbers.
- *
- * Returns TRUE if matched; otherwise FALSE.
- */
-bool Curl_verify_windows_version(const unsigned int majorVersion,
-                                 const unsigned int minorVersion,
-                                 const PlatformIdentifier platform,
-                                 const VersionCondition condition)
-{
-  bool matched = FALSE;
-
-#if defined(CURL_WINDOWS_APP)
-  /* We have no way to determine the Windows version from Windows apps,
-     so let's assume we're running on the target Windows version. */
-  const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
-  const WORD targetVersion = (WORD)_WIN32_WINNT;
-
-  switch(condition) {
-  case VERSION_LESS_THAN:
-    matched = targetVersion < fullVersion;
-    break;
-
-  case VERSION_LESS_THAN_EQUAL:
-    matched = targetVersion <= fullVersion;
-    break;
-
-  case VERSION_EQUAL:
-    matched = targetVersion == fullVersion;
-    break;
-
-  case VERSION_GREATER_THAN_EQUAL:
-    matched = targetVersion >= fullVersion;
-    break;
-
-  case VERSION_GREATER_THAN:
-    matched = targetVersion > fullVersion;
-    break;
-  }
-
-  if(matched && (platform == PLATFORM_WINDOWS)) {
-    /* we're always running on PLATFORM_WINNT */
-    matched = FALSE;
-  }
-#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
-    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
-  OSVERSIONINFO osver;
-
-  memset(&osver, 0, sizeof(osver));
-  osver.dwOSVersionInfoSize = sizeof(osver);
-
-  /* Find out Windows version */
-  if(GetVersionEx(&osver)) {
-    /* Verify the Operating System version number */
-    switch(condition) {
-    case VERSION_LESS_THAN:
-      if(osver.dwMajorVersion < majorVersion ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion < minorVersion))
-        matched = TRUE;
-      break;
-
-    case VERSION_LESS_THAN_EQUAL:
-      if(osver.dwMajorVersion < majorVersion ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion <= minorVersion))
-        matched = TRUE;
-      break;
-
-    case VERSION_EQUAL:
-      if(osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion == minorVersion)
-        matched = TRUE;
-      break;
-
-    case VERSION_GREATER_THAN_EQUAL:
-      if(osver.dwMajorVersion > majorVersion ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion >= minorVersion))
-        matched = TRUE;
-      break;
-
-    case VERSION_GREATER_THAN:
-      if(osver.dwMajorVersion > majorVersion ||
-        (osver.dwMajorVersion == majorVersion &&
-         osver.dwMinorVersion > minorVersion))
-        matched = TRUE;
-      break;
-    }
-
-    /* Verify the platform identifier (if necessary) */
-    if(matched) {
-      switch(platform) {
-      case PLATFORM_WINDOWS:
-        if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
-          matched = FALSE;
-        break;
-
-      case PLATFORM_WINNT:
-        if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
-          matched = FALSE;
-
-      default: /* like platform == PLATFORM_DONT_CARE */
-        break;
-      }
-    }
-  }
-#else
-  ULONGLONG cm = 0;
-  OSVERSIONINFOEX osver;
-  BYTE majorCondition;
-  BYTE minorCondition;
-  BYTE spMajorCondition;
-  BYTE spMinorCondition;
-
-  switch(condition) {
-  case VERSION_LESS_THAN:
-    majorCondition = VER_LESS;
-    minorCondition = VER_LESS;
-    spMajorCondition = VER_LESS_EQUAL;
-    spMinorCondition = VER_LESS_EQUAL;
-    break;
-
-  case VERSION_LESS_THAN_EQUAL:
-    majorCondition = VER_LESS_EQUAL;
-    minorCondition = VER_LESS_EQUAL;
-    spMajorCondition = VER_LESS_EQUAL;
-    spMinorCondition = VER_LESS_EQUAL;
-    break;
-
-  case VERSION_EQUAL:
-    majorCondition = VER_EQUAL;
-    minorCondition = VER_EQUAL;
-    spMajorCondition = VER_GREATER_EQUAL;
-    spMinorCondition = VER_GREATER_EQUAL;
-    break;
-
-  case VERSION_GREATER_THAN_EQUAL:
-    majorCondition = VER_GREATER_EQUAL;
-    minorCondition = VER_GREATER_EQUAL;
-    spMajorCondition = VER_GREATER_EQUAL;
-    spMinorCondition = VER_GREATER_EQUAL;
-    break;
-
-  case VERSION_GREATER_THAN:
-    majorCondition = VER_GREATER;
-    minorCondition = VER_GREATER;
-    spMajorCondition = VER_GREATER_EQUAL;
-    spMinorCondition = VER_GREATER_EQUAL;
-    break;
-
-  default:
-    return FALSE;
-  }
-
-  memset(&osver, 0, sizeof(osver));
-  osver.dwOSVersionInfoSize = sizeof(osver);
-  osver.dwMajorVersion = majorVersion;
-  osver.dwMinorVersion = minorVersion;
-  if(platform == PLATFORM_WINDOWS)
-    osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
-  else if(platform == PLATFORM_WINNT)
-    osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
-
-  cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
-  cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
-  cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
-  cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
-  if(platform != PLATFORM_DONT_CARE)
-    cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
-
-  if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
-                                VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
-                       cm))
-    matched = TRUE;
-#endif
-
-  return matched;
-}
-
 /*
 /*
  * Curl_load_library()
  * Curl_load_library()
  *
  *

+ 1 - 23
lib/system_win32.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2016 - 2019, Steve Holme, <[email protected]>.
+ * Copyright (C) 2016 - 2020, Steve Holme, <[email protected]>.
  *
  *
  * This software is licensed as described in the file COPYING, which
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
  * you should have received as part of this distribution. The terms
@@ -32,34 +32,12 @@ extern bool Curl_isVistaOrGreater;
 CURLcode Curl_win32_init(long flags);
 CURLcode Curl_win32_init(long flags);
 void Curl_win32_cleanup(long init_flags);
 void Curl_win32_cleanup(long init_flags);
 
 
-/* Version condition */
-typedef enum {
-  VERSION_LESS_THAN,
-  VERSION_LESS_THAN_EQUAL,
-  VERSION_EQUAL,
-  VERSION_GREATER_THAN_EQUAL,
-  VERSION_GREATER_THAN
-} VersionCondition;
-
-/* Platform identifier */
-typedef enum {
-  PLATFORM_DONT_CARE,
-  PLATFORM_WINDOWS,
-  PLATFORM_WINNT
-} PlatformIdentifier;
-
 /* We use our own typedef here since some headers might lack this */
 /* We use our own typedef here since some headers might lack this */
 typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *);
 typedef unsigned int(WINAPI *IF_NAMETOINDEX_FN)(const char *);
 
 
 /* This is used instead of if_nametoindex if available on Windows */
 /* This is used instead of if_nametoindex if available on Windows */
 extern IF_NAMETOINDEX_FN Curl_if_nametoindex;
 extern IF_NAMETOINDEX_FN Curl_if_nametoindex;
 
 
-/* This is used to verify if we are running on a specific windows version */
-bool Curl_verify_windows_version(const unsigned int majorVersion,
-                                 const unsigned int minorVersion,
-                                 const PlatformIdentifier platform,
-                                 const VersionCondition condition);
-
 /* This is used to dynamically load DLLs */
 /* This is used to dynamically load DLLs */
 HMODULE Curl_load_library(LPCTSTR filename);
 HMODULE Curl_load_library(LPCTSTR filename);
 
 

+ 12 - 5
lib/transfer.c

@@ -487,6 +487,12 @@ CURLcode Curl_readrewind(struct connectdata *conn)
 static int data_pending(const struct Curl_easy *data)
 static int data_pending(const struct Curl_easy *data)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
+
+#ifdef ENABLE_QUIC
+  if(conn->transport == TRNSPRT_QUIC)
+    return Curl_quic_data_pending(data);
+#endif
+
   /* in the case of libssh2, we can never be really sure that we have emptied
   /* in the case of libssh2, we can never be really sure that we have emptied
      its internal buffers so we MUST always try until we get EAGAIN back */
      its internal buffers so we MUST always try until we get EAGAIN back */
   return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
   return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
@@ -500,8 +506,6 @@ static int data_pending(const struct Curl_easy *data)
        be called and we cannot signal the HTTP/2 stream has closed. As
        be called and we cannot signal the HTTP/2 stream has closed. As
        a workaround, we return nonzero here to call http2_recv. */
        a workaround, we return nonzero here to call http2_recv. */
     ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion >= 20);
     ((conn->handler->protocol&PROTO_FAMILY_HTTP) && conn->httpversion >= 20);
-#elif defined(ENABLE_QUIC)
-    Curl_ssl_data_pending(conn, FIRSTSOCKET) || Curl_quic_data_pending(data);
 #else
 #else
     Curl_ssl_data_pending(conn, FIRSTSOCKET);
     Curl_ssl_data_pending(conn, FIRSTSOCKET);
 #endif
 #endif
@@ -1441,8 +1445,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
 
 
   if(!data->change.url && data->set.uh) {
   if(!data->change.url && data->set.uh) {
     CURLUcode uc;
     CURLUcode uc;
+    free(data->set.str[STRING_SET_URL]);
     uc = curl_url_get(data->set.uh,
     uc = curl_url_get(data->set.uh,
-                        CURLUPART_URL, &data->set.str[STRING_SET_URL], 0);
+                      CURLUPART_URL, &data->set.str[STRING_SET_URL], 0);
     if(uc) {
     if(uc) {
       failf(data, "No URL set!");
       failf(data, "No URL set!");
       return CURLE_URL_MALFORMAT;
       return CURLE_URL_MALFORMAT;
@@ -1799,12 +1804,14 @@ CURLcode Curl_retry_request(struct connectdata *conn,
   }
   }
   if(retry) {
   if(retry) {
 #define CONN_MAX_RETRIES 5
 #define CONN_MAX_RETRIES 5
-    if(conn->retrycount++ >= CONN_MAX_RETRIES) {
+    if(data->state.retrycount++ >= CONN_MAX_RETRIES) {
       failf(data, "Connection died, tried %d times before giving up",
       failf(data, "Connection died, tried %d times before giving up",
             CONN_MAX_RETRIES);
             CONN_MAX_RETRIES);
+      data->state.retrycount = 0;
       return CURLE_SEND_ERROR;
       return CURLE_SEND_ERROR;
     }
     }
-    infof(conn->data, "Connection died, retrying a fresh connect\n");
+    infof(conn->data, "Connection died, retrying a fresh connect\
+(retry count: %d)\n", data->state.retrycount);
     *url = strdup(conn->data->change.url);
     *url = strdup(conn->data->change.url);
     if(!*url)
     if(!*url)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;

+ 5 - 4
lib/url.c

@@ -630,7 +630,7 @@ CURLcode Curl_open(struct Curl_easy **curl)
     Curl_initinfo(data);
     Curl_initinfo(data);
 
 
     /* most recent connection is not yet defined */
     /* most recent connection is not yet defined */
-    data->state.lastconnect = NULL;
+    data->state.lastconnect_id = -1;
 
 
     data->progress.flags |= PGRS_HIDE;
     data->progress.flags |= PGRS_HIDE;
     data->state.current_speed = -1; /* init to negative == impossible */
     data->state.current_speed = -1; /* init to negative == impossible */
@@ -1836,11 +1836,12 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
   CURLU *uh;
   CURLU *uh;
   CURLUcode uc;
   CURLUcode uc;
   char *hostname;
   char *hostname;
+  bool use_set_uh = (data->set.uh && !data->state.this_is_a_follow);
 
 
   up_free(data); /* cleanup previous leftovers first */
   up_free(data); /* cleanup previous leftovers first */
 
 
   /* parse the URL */
   /* parse the URL */
-  if(data->set.uh) {
+  if(use_set_uh) {
     uh = data->state.uh = curl_url_dup(data->set.uh);
     uh = data->state.uh = curl_url_dup(data->set.uh);
   }
   }
   else {
   else {
@@ -1863,7 +1864,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
     data->change.url_alloc = TRUE;
     data->change.url_alloc = TRUE;
   }
   }
 
 
-  if(!data->set.uh) {
+  if(!use_set_uh) {
     char *newurl;
     char *newurl;
     uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
     uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
                     CURLU_GUESS_SCHEME |
                     CURLU_GUESS_SCHEME |
@@ -3170,7 +3171,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
   else {
   else {
     /* this is a fresh connect */
     /* this is a fresh connect */
     int rc;
     int rc;
-    struct Curl_dns_entry *hostaddr;
+    struct Curl_dns_entry *hostaddr = NULL;
 
 
 #ifdef USE_UNIX_SOCKETS
 #ifdef USE_UNIX_SOCKETS
     if(conn->unix_domain_socket) {
     if(conn->unix_domain_socket) {

+ 3 - 3
lib/urldata.h

@@ -1090,7 +1090,6 @@ struct connectdata {
   struct http_connect_state *connect_state; /* for HTTP CONNECT */
   struct http_connect_state *connect_state; /* for HTTP CONNECT */
   struct connectbundle *bundle; /* The bundle we are member of */
   struct connectbundle *bundle; /* The bundle we are member of */
   int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */
   int negnpn; /* APLN or NPN TLS negotiated protocol, CURL_HTTP_VERSION* */
-  int retrycount; /* number of retries on a new connection */
 #ifdef USE_UNIX_SOCKETS
 #ifdef USE_UNIX_SOCKETS
   char *unix_domain_socket;
   char *unix_domain_socket;
 #endif
 #endif
@@ -1195,7 +1194,6 @@ typedef enum {
   HTTPREQ_POST_MIME, /* we make a difference internally */
   HTTPREQ_POST_MIME, /* we make a difference internally */
   HTTPREQ_PUT,
   HTTPREQ_PUT,
   HTTPREQ_HEAD,
   HTTPREQ_HEAD,
-  HTTPREQ_OPTIONS,
   HTTPREQ_LAST /* last in list */
   HTTPREQ_LAST /* last in list */
 } Curl_HttpReq;
 } Curl_HttpReq;
 
 
@@ -1297,10 +1295,12 @@ struct UrlState {
   /* Points to the connection cache */
   /* Points to the connection cache */
   struct conncache *conn_cache;
   struct conncache *conn_cache;
 
 
+  int retrycount; /* number of retries on a new connection */
+
   /* buffers to store authentication data in, as parsed from input options */
   /* buffers to store authentication data in, as parsed from input options */
   struct curltime keeps_speed; /* for the progress meter really */
   struct curltime keeps_speed; /* for the progress meter really */
 
 
-  struct connectdata *lastconnect; /* The last connection, NULL if undefined */
+  long lastconnect_id; /* The last connection, -1 if undefined */
   struct dynbuf headerb; /* buffer to store headers in */
   struct dynbuf headerb; /* buffer to store headers in */
 
 
   char *buffer; /* download buffer */
   char *buffer; /* download buffer */

+ 1 - 0
lib/vauth/ntlm.c

@@ -191,6 +191,7 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
         return CURLE_BAD_CONTENT_ENCODING;
         return CURLE_BAD_CONTENT_ENCODING;
       }
       }
 
 
+      free(ntlm->target_info); /* replace any previous data */
       ntlm->target_info = malloc(target_info_len);
       ntlm->target_info = malloc(target_info_len);
       if(!ntlm->target_info)
       if(!ntlm->target_info)
         return CURLE_OUT_OF_MEMORY;
         return CURLE_OUT_OF_MEMORY;

+ 45 - 2
lib/version.c

@@ -66,6 +66,10 @@
 #include <brotli/decode.h>
 #include <brotli/decode.h>
 #endif
 #endif
 
 
+#ifdef HAVE_ZSTD
+#include <zstd.h>
+#endif
+
 #ifdef HAVE_BROTLI
 #ifdef HAVE_BROTLI
 static size_t brotli_version(char *buf, size_t bufsz)
 static size_t brotli_version(char *buf, size_t bufsz)
 {
 {
@@ -78,6 +82,20 @@ static size_t brotli_version(char *buf, size_t bufsz)
 }
 }
 #endif
 #endif
 
 
+#ifdef HAVE_ZSTD
+static size_t zstd_version(char *buf, size_t bufsz)
+{
+  unsigned long zstd_version = (unsigned long)ZSTD_versionNumber();
+  unsigned int major = (unsigned int)(zstd_version / (100 * 100));
+  unsigned int minor = (unsigned int)((zstd_version -
+                         (major * 100 * 100)) / 100);
+  unsigned int patch = (unsigned int)(zstd_version -
+                         (major * 100 * 100) - (minor * 100));
+
+  return msnprintf(buf, bufsz, "%u.%u.%u", major, minor, patch);
+}
+#endif
+
 /*
 /*
  * curl_version() returns a pointer to a static buffer.
  * curl_version() returns a pointer to a static buffer.
  *
  *
@@ -103,6 +121,9 @@ char *curl_version(void)
 #ifdef HAVE_BROTLI
 #ifdef HAVE_BROTLI
   char br_version[40] = "brotli/";
   char br_version[40] = "brotli/";
 #endif
 #endif
+#ifdef HAVE_ZSTD
+  char zst_version[40] = "zstd/";
+#endif
 #ifdef USE_ARES
 #ifdef USE_ARES
   char cares_version[40];
   char cares_version[40];
 #endif
 #endif
@@ -153,6 +174,10 @@ char *curl_version(void)
   brotli_version(&br_version[7], sizeof(br_version) - 7);
   brotli_version(&br_version[7], sizeof(br_version) - 7);
   src[i++] = br_version;
   src[i++] = br_version;
 #endif
 #endif
+#ifdef HAVE_ZSTD
+  zstd_version(&zst_version[5], sizeof(zst_version) - 5);
+  src[i++] = zst_version;
+#endif
 #ifdef USE_ARES
 #ifdef USE_ARES
   msnprintf(cares_version, sizeof(cares_version),
   msnprintf(cares_version, sizeof(cares_version),
             "c-ares/%s", ares_version(NULL));
             "c-ares/%s", ares_version(NULL));
@@ -365,6 +390,9 @@ static curl_version_info_data version_info = {
     ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
     ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
   | CURL_VERSION_LARGEFILE
   | CURL_VERSION_LARGEFILE
 #endif
 #endif
+#if defined(WIN32) && defined(UNICODE) && defined(_UNICODE)
+  | CURL_VERSION_UNICODE
+#endif
 #if defined(CURL_DOES_CONVERSIONS)
 #if defined(CURL_DOES_CONVERSIONS)
   | CURL_VERSION_CONV
   | CURL_VERSION_CONV
 #endif
 #endif
@@ -389,6 +417,9 @@ static curl_version_info_data version_info = {
 #if defined(HAVE_BROTLI)
 #if defined(HAVE_BROTLI)
   | CURL_VERSION_BROTLI
   | CURL_VERSION_BROTLI
 #endif
 #endif
+#if defined(HAVE_ZSTD)
+  | CURL_VERSION_ZSTD
+#endif
 #if defined(USE_ALTSVC)
 #if defined(USE_ALTSVC)
   | CURL_VERSION_ALTSVC
   | CURL_VERSION_ALTSVC
 #endif
 #endif
@@ -413,10 +444,12 @@ static curl_version_info_data version_info = {
   NULL,
   NULL,
 #endif
 #endif
 #ifdef CURL_CA_PATH
 #ifdef CURL_CA_PATH
-  CURL_CA_PATH  /* capath */
+  CURL_CA_PATH,  /* capath */
 #else
 #else
-  NULL
+  NULL,
 #endif
 #endif
+  0,    /* zstd_ver_num */
+  NULL  /* zstd version */
 };
 };
 
 
 curl_version_info_data *curl_version_info(CURLversion stamp)
 curl_version_info_data *curl_version_info(CURLversion stamp)
@@ -434,6 +467,10 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
 #ifdef HAVE_BROTLI
 #ifdef HAVE_BROTLI
   static char brotli_buffer[80];
   static char brotli_buffer[80];
 #endif
 #endif
+#ifdef HAVE_ZSTD
+  static char zstd_buffer[80];
+#endif
+
 
 
 #ifdef USE_SSL
 #ifdef USE_SSL
   Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
   Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
@@ -485,6 +522,12 @@ curl_version_info_data *curl_version_info(CURLversion stamp)
   version_info.brotli_version = brotli_buffer;
   version_info.brotli_version = brotli_buffer;
 #endif
 #endif
 
 
+#ifdef HAVE_ZSTD
+  version_info.zstd_ver_num = (unsigned int)ZSTD_versionNumber();
+  zstd_version(zstd_buffer, sizeof(zstd_buffer));
+  version_info.zstd_version = zstd_buffer;
+#endif
+
 #ifdef USE_NGHTTP2
 #ifdef USE_NGHTTP2
   {
   {
     nghttp2_info *h2 = nghttp2_version(0);
     nghttp2_info *h2 = nghttp2_version(0);

+ 226 - 0
lib/version_win32.c

@@ -0,0 +1,226 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2016 - 2020, Steve Holme, <[email protected]>.
+ *
+ * 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.haxx.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.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(WIN32)
+
+#include <curl/curl.h>
+#include "version_win32.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * curlx_verify_windows_version()
+ *
+ * This is used to verify if we are running on a specific windows version.
+ *
+ * Parameters:
+ *
+ * majorVersion [in] - The major version number.
+ * minorVersion [in] - The minor version number.
+ * platform     [in] - The optional platform identifier.
+ * condition    [in] - The test condition used to specifier whether we are
+ *                     checking a version less then, equal to or greater than
+ *                     what is specified in the major and minor version
+ *                     numbers.
+ *
+ * Returns TRUE if matched; otherwise FALSE.
+ */
+bool curlx_verify_windows_version(const unsigned int majorVersion,
+                                  const unsigned int minorVersion,
+                                  const PlatformIdentifier platform,
+                                  const VersionCondition condition)
+{
+  bool matched = FALSE;
+
+#if defined(CURL_WINDOWS_APP)
+  /* We have no way to determine the Windows version from Windows apps,
+     so let's assume we're running on the target Windows version. */
+  const WORD fullVersion = MAKEWORD(minorVersion, majorVersion);
+  const WORD targetVersion = (WORD)_WIN32_WINNT;
+
+  switch(condition) {
+  case VERSION_LESS_THAN:
+    matched = targetVersion < fullVersion;
+    break;
+
+  case VERSION_LESS_THAN_EQUAL:
+    matched = targetVersion <= fullVersion;
+    break;
+
+  case VERSION_EQUAL:
+    matched = targetVersion == fullVersion;
+    break;
+
+  case VERSION_GREATER_THAN_EQUAL:
+    matched = targetVersion >= fullVersion;
+    break;
+
+  case VERSION_GREATER_THAN:
+    matched = targetVersion > fullVersion;
+    break;
+  }
+
+  if(matched && (platform == PLATFORM_WINDOWS)) {
+    /* we're always running on PLATFORM_WINNT */
+    matched = FALSE;
+  }
+#elif !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_WIN2K) || \
+    (_WIN32_WINNT < _WIN32_WINNT_WIN2K)
+  OSVERSIONINFO osver;
+
+  memset(&osver, 0, sizeof(osver));
+  osver.dwOSVersionInfoSize = sizeof(osver);
+
+  /* Find out Windows version */
+  if(GetVersionEx(&osver)) {
+    /* Verify the Operating System version number */
+    switch(condition) {
+    case VERSION_LESS_THAN:
+      if(osver.dwMajorVersion < majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion < minorVersion))
+        matched = TRUE;
+      break;
+
+    case VERSION_LESS_THAN_EQUAL:
+      if(osver.dwMajorVersion < majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion <= minorVersion))
+        matched = TRUE;
+      break;
+
+    case VERSION_EQUAL:
+      if(osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion == minorVersion)
+        matched = TRUE;
+      break;
+
+    case VERSION_GREATER_THAN_EQUAL:
+      if(osver.dwMajorVersion > majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion >= minorVersion))
+        matched = TRUE;
+      break;
+
+    case VERSION_GREATER_THAN:
+      if(osver.dwMajorVersion > majorVersion ||
+        (osver.dwMajorVersion == majorVersion &&
+         osver.dwMinorVersion > minorVersion))
+        matched = TRUE;
+      break;
+    }
+
+    /* Verify the platform identifier (if necessary) */
+    if(matched) {
+      switch(platform) {
+      case PLATFORM_WINDOWS:
+        if(osver.dwPlatformId != VER_PLATFORM_WIN32_WINDOWS)
+          matched = FALSE;
+        break;
+
+      case PLATFORM_WINNT:
+        if(osver.dwPlatformId != VER_PLATFORM_WIN32_NT)
+          matched = FALSE;
+
+      default: /* like platform == PLATFORM_DONT_CARE */
+        break;
+      }
+    }
+  }
+#else
+  ULONGLONG cm = 0;
+  OSVERSIONINFOEX osver;
+  BYTE majorCondition;
+  BYTE minorCondition;
+  BYTE spMajorCondition;
+  BYTE spMinorCondition;
+
+  switch(condition) {
+  case VERSION_LESS_THAN:
+    majorCondition = VER_LESS;
+    minorCondition = VER_LESS;
+    spMajorCondition = VER_LESS_EQUAL;
+    spMinorCondition = VER_LESS_EQUAL;
+    break;
+
+  case VERSION_LESS_THAN_EQUAL:
+    majorCondition = VER_LESS_EQUAL;
+    minorCondition = VER_LESS_EQUAL;
+    spMajorCondition = VER_LESS_EQUAL;
+    spMinorCondition = VER_LESS_EQUAL;
+    break;
+
+  case VERSION_EQUAL:
+    majorCondition = VER_EQUAL;
+    minorCondition = VER_EQUAL;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  case VERSION_GREATER_THAN_EQUAL:
+    majorCondition = VER_GREATER_EQUAL;
+    minorCondition = VER_GREATER_EQUAL;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  case VERSION_GREATER_THAN:
+    majorCondition = VER_GREATER;
+    minorCondition = VER_GREATER;
+    spMajorCondition = VER_GREATER_EQUAL;
+    spMinorCondition = VER_GREATER_EQUAL;
+    break;
+
+  default:
+    return FALSE;
+  }
+
+  memset(&osver, 0, sizeof(osver));
+  osver.dwOSVersionInfoSize = sizeof(osver);
+  osver.dwMajorVersion = majorVersion;
+  osver.dwMinorVersion = minorVersion;
+  if(platform == PLATFORM_WINDOWS)
+    osver.dwPlatformId = VER_PLATFORM_WIN32_WINDOWS;
+  else if(platform == PLATFORM_WINNT)
+    osver.dwPlatformId = VER_PLATFORM_WIN32_NT;
+
+  cm = VerSetConditionMask(cm, VER_MAJORVERSION, majorCondition);
+  cm = VerSetConditionMask(cm, VER_MINORVERSION, minorCondition);
+  cm = VerSetConditionMask(cm, VER_SERVICEPACKMAJOR, spMajorCondition);
+  cm = VerSetConditionMask(cm, VER_SERVICEPACKMINOR, spMinorCondition);
+  if(platform != PLATFORM_DONT_CARE)
+    cm = VerSetConditionMask(cm, VER_PLATFORMID, VER_EQUAL);
+
+  if(VerifyVersionInfo(&osver, (VER_MAJORVERSION | VER_MINORVERSION |
+                                VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR),
+                       cm))
+    matched = TRUE;
+#endif
+
+  return matched;
+}
+
+#endif /* WIN32 */

+ 53 - 0
lib/version_win32.h

@@ -0,0 +1,53 @@
+#ifndef HEADER_CURL_VERSION_WIN32_H
+#define HEADER_CURL_VERSION_WIN32_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2016 - 2020, Steve Holme, <[email protected]>.
+ *
+ * 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.haxx.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.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if defined(WIN32)
+
+/* Version condition */
+typedef enum {
+  VERSION_LESS_THAN,
+  VERSION_LESS_THAN_EQUAL,
+  VERSION_EQUAL,
+  VERSION_GREATER_THAN_EQUAL,
+  VERSION_GREATER_THAN
+} VersionCondition;
+
+/* Platform identifier */
+typedef enum {
+  PLATFORM_DONT_CARE,
+  PLATFORM_WINDOWS,
+  PLATFORM_WINNT
+} PlatformIdentifier;
+
+/* This is used to verify if we are running on a specific windows version */
+bool curlx_verify_windows_version(const unsigned int majorVersion,
+                                  const unsigned int minorVersion,
+                                  const PlatformIdentifier platform,
+                                  const VersionCondition condition);
+
+#endif /* WIN32 */
+
+#endif /* HEADER_CURL_VERSION_WIN32_H */

+ 10 - 9
lib/vquic/ngtcp2.c

@@ -150,9 +150,11 @@ quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level)
 }
 }
 #endif
 #endif
 
 
-static void qlog_callback(void *user_data, const void *data, size_t datalen)
+static void qlog_callback(void *user_data, uint32_t flags,
+                          const void *data, size_t datalen)
 {
 {
   struct quicsocket *qs = (struct quicsocket *)user_data;
   struct quicsocket *qs = (struct quicsocket *)user_data;
+  (void)flags;
   if(qs->qlogfd != -1) {
   if(qs->qlogfd != -1) {
     ssize_t rc = write(qs->qlogfd, data, datalen);
     ssize_t rc = write(qs->qlogfd, data, datalen);
     if(rc == -1) {
     if(rc == -1) {
@@ -826,9 +828,8 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
   if(rv == -1)
   if(rv == -1)
     return CURLE_QUIC_CONNECT_ERROR;
     return CURLE_QUIC_CONNECT_ERROR;
 
 
-  ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr, qs->local_addrlen,
-                   NULL);
-  ngtcp2_addr_init(&path.remote, (uint8_t*)addr, addrlen, NULL);
+  ngtcp2_addr_init(&path.local, &qs->local_addr, qs->local_addrlen, NULL);
+  ngtcp2_addr_init(&path.remote, addr, addrlen, NULL);
 
 
 #ifdef NGTCP2_PROTO_VER
 #ifdef NGTCP2_PROTO_VER
 #define QUICVER NGTCP2_PROTO_VER
 #define QUICVER NGTCP2_PROTO_VER
@@ -1744,10 +1745,10 @@ static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd,
       return CURLE_RECV_ERROR;
       return CURLE_RECV_ERROR;
     }
     }
 
 
-    ngtcp2_addr_init(&path.local, (uint8_t *)&qs->local_addr,
+    ngtcp2_addr_init(&path.local, &qs->local_addr,
                      qs->local_addrlen, NULL);
                      qs->local_addrlen, NULL);
-    ngtcp2_addr_init(&path.remote, (uint8_t *)&remote_addr, remote_addrlen,
-                     NULL);
+    ngtcp2_addr_init(&path.remote, (struct sockaddr *)&remote_addr,
+                     remote_addrlen, NULL);
 
 
     rv = ngtcp2_conn_read_pkt(qs->qconn, &path, buf, recvd, ts);
     rv = ngtcp2_conn_read_pkt(qs->qconn, &path, buf, recvd, ts);
     if(rv != 0) {
     if(rv != 0) {
@@ -1778,7 +1779,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
   nghttp3_vec vec[16];
   nghttp3_vec vec[16];
   ssize_t ndatalen;
   ssize_t ndatalen;
 
 
-  switch(qs->local_addr.ss_family) {
+  switch(qs->local_addr.sa_family) {
   case AF_INET:
   case AF_INET:
     pktlen = NGTCP2_MAX_PKTLEN_IPV4;
     pktlen = NGTCP2_MAX_PKTLEN_IPV4;
     break;
     break;
@@ -1834,7 +1835,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
             }
             }
             continue;
             continue;
           }
           }
-          else if(outlen == NGTCP2_ERR_WRITE_STREAM_MORE) {
+          else if(outlen == NGTCP2_ERR_WRITE_MORE) {
             assert(ndatalen > 0);
             assert(ndatalen > 0);
             rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id,
             rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id,
                                                ndatalen);
                                                ndatalen);

+ 1 - 1
lib/vquic/ngtcp2.h

@@ -58,7 +58,7 @@ struct quicsocket {
   struct quic_handshake crypto_data[3];
   struct quic_handshake crypto_data[3];
   /* the last TLS alert description generated by the local endpoint */
   /* the last TLS alert description generated by the local endpoint */
   uint8_t tls_alert;
   uint8_t tls_alert;
-  struct sockaddr_storage local_addr;
+  struct sockaddr local_addr;
   socklen_t local_addrlen;
   socklen_t local_addrlen;
 
 
   nghttp3_conn *h3conn;
   nghttp3_conn *h3conn;

+ 8 - 2
lib/vquic/quiche.c

@@ -95,8 +95,14 @@ static CURLcode qs_disconnect(struct quicsocket *qs)
     quiche_h3_config_free(qs->h3config);
     quiche_h3_config_free(qs->h3config);
   if(qs->h3c)
   if(qs->h3c)
     quiche_h3_conn_free(qs->h3c);
     quiche_h3_conn_free(qs->h3c);
-  quiche_config_free(qs->cfg);
-  quiche_conn_free(qs->conn);
+  if(qs->cfg) {
+    quiche_config_free(qs->cfg);
+    qs->cfg = NULL;
+  }
+  if(qs->conn) {
+    quiche_conn_free(qs->conn);
+    qs->conn = NULL;
+  }
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 

+ 1 - 1
lib/vssh/libssh2.c

@@ -1256,7 +1256,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
           result = CURLE_SSH;
           result = CURLE_SSH;
         sshc->actualcode = result;
         sshc->actualcode = result;
         DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
         DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
-                     ssherr, (int)result));
+                     sftperr, (int)result));
         state(conn, SSH_STOP);
         state(conn, SSH_STOP);
         break;
         break;
       }
       }

+ 9 - 2
lib/vtls/bearssl.c

@@ -300,8 +300,12 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_backend_data *backend = connssl->backend;
   struct ssl_backend_data *backend = connssl->backend;
   const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
   const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+#ifndef CURL_DISABLE_PROXY
   const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
   const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
     conn->host.name;
     conn->host.name;
+#else
+  const char *hostname = conn->host.name;
+#endif
   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
   const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
   const bool verifyhost = SSL_CONN_CONFIG(verifyhost);
   const bool verifyhost = SSL_CONN_CONFIG(verifyhost);
   CURLcode ret;
   CURLcode ret;
@@ -386,8 +390,11 @@ static CURLcode bearssl_connect_step1(struct connectdata *conn, int sockindex)
      */
      */
 
 
 #ifdef USE_NGHTTP2
 #ifdef USE_NGHTTP2
-    if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
-       (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifndef CURL_DISABLE_PROXY
+      && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+#endif
+      ) {
       backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
       backend->protocols[cur++] = NGHTTP2_PROTO_VERSION_ID;
       infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
       infof(data, "ALPN, offering %s\n", NGHTTP2_PROTO_VERSION_ID);
     }
     }

+ 41 - 13
lib/vtls/gtls.c

@@ -399,10 +399,15 @@ gtls_connect_step1(struct connectdata *conn,
 #endif
 #endif
   const char *prioritylist;
   const char *prioritylist;
   const char *err = NULL;
   const char *err = NULL;
+#ifndef CURL_DISABLE_PROXY
   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
     conn->host.name;
     conn->host.name;
   long * const certverifyresult = SSL_IS_PROXY() ?
   long * const certverifyresult = SSL_IS_PROXY() ?
     &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
     &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+#else
+  const char * const hostname = conn->host.name;
+  long * const certverifyresult = &data->set.ssl.certverifyresult;
+#endif
 
 
   if(connssl->state == ssl_connection_complete)
   if(connssl->state == ssl_connection_complete)
     /* to make us tolerant against being called more than once for the
     /* to make us tolerant against being called more than once for the
@@ -620,8 +625,11 @@ gtls_connect_step1(struct connectdata *conn,
     gnutls_datum_t protocols[2];
     gnutls_datum_t protocols[2];
 
 
 #ifdef USE_NGHTTP2
 #ifdef USE_NGHTTP2
-    if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
-       (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifndef CURL_DISABLE_PROXY
+       && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+#endif
+       ) {
       protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
       protocols[cur].data = (unsigned char *)NGHTTP2_PROTO_VERSION_ID;
       protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
       protocols[cur].size = NGHTTP2_PROTO_VERSION_ID_LEN;
       cur++;
       cur++;
@@ -694,12 +702,15 @@ gtls_connect_step1(struct connectdata *conn,
     }
     }
   }
   }
 
 
+#ifndef CURL_DISABLE_PROXY
   if(conn->proxy_ssl[sockindex].use) {
   if(conn->proxy_ssl[sockindex].use) {
     transport_ptr = conn->proxy_ssl[sockindex].backend->session;
     transport_ptr = conn->proxy_ssl[sockindex].backend->session;
     gnutls_transport_push = Curl_gtls_push_ssl;
     gnutls_transport_push = Curl_gtls_push_ssl;
     gnutls_transport_pull = Curl_gtls_pull_ssl;
     gnutls_transport_pull = Curl_gtls_pull_ssl;
   }
   }
-  else {
+  else
+#endif
+  {
     /* file descriptor for the socket */
     /* file descriptor for the socket */
     transport_ptr = &conn->sock[sockindex];
     transport_ptr = &conn->sock[sockindex];
     gnutls_transport_push = Curl_gtls_push;
     gnutls_transport_push = Curl_gtls_push;
@@ -828,10 +839,15 @@ gtls_connect_step3(struct connectdata *conn,
   unsigned int bits;
   unsigned int bits;
   gnutls_protocol_t version = gnutls_protocol_get_version(session);
   gnutls_protocol_t version = gnutls_protocol_get_version(session);
 #endif
 #endif
+#ifndef CURL_DISABLE_PROXY
   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
   const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
     conn->host.name;
     conn->host.name;
   long * const certverifyresult = SSL_IS_PROXY() ?
   long * const certverifyresult = SSL_IS_PROXY() ?
     &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
     &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+#else
+  const char * const hostname = conn->host.name;
+  long * const certverifyresult = &data->set.ssl.certverifyresult;
+#endif
 
 
   /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
   /* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
   ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
   ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
@@ -1112,8 +1128,12 @@ gtls_connect_step3(struct connectdata *conn,
   }
   }
 #endif
 #endif
   if(!rc) {
   if(!rc) {
+#ifndef CURL_DISABLE_PROXY
     const char * const dispname = SSL_IS_PROXY() ?
     const char * const dispname = SSL_IS_PROXY() ?
       conn->http_proxy.host.dispname : conn->host.dispname;
       conn->http_proxy.host.dispname : conn->host.dispname;
+#else
+    const char * const dispname = conn->host.dispname;
+#endif
 
 
     if(SSL_CONN_CONFIG(verifyhost)) {
     if(SSL_CONN_CONFIG(verifyhost)) {
       failf(data, "SSL: certificate subject name (%s) does not match "
       failf(data, "SSL: certificate subject name (%s) does not match "
@@ -1216,20 +1236,23 @@ gtls_connect_step3(struct connectdata *conn,
 
 
 
 
   rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields);
   rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields);
-  if(rc != 0)
-    return CURLE_OUT_OF_MEMORY;
-  infof(data, "\t subject: %s\n", certfields.data);
+  if(rc)
+    infof(data, "Failed to get certificate name\n");
+  else {
+    infof(data, "\t subject: %s\n", certfields.data);
 
 
-  certclock = gnutls_x509_crt_get_activation_time(x509_cert);
-  showtime(data, "start date", certclock);
+    certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+    showtime(data, "start date", certclock);
 
 
-  certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
-  showtime(data, "expire date", certclock);
+    certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+    showtime(data, "expire date", certclock);
+  }
 
 
   rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields);
   rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields);
-  if(rc != 0)
-    return CURLE_OUT_OF_MEMORY;
-  infof(data, "\t issuer: %s\n", certfields.data);
+  if(rc)
+    infof(data, "Failed to get certificate issuer\n");
+  else
+    infof(data, "\t issuer: %s\n", certfields.data);
 #endif
 #endif
 
 
   gnutls_x509_crt_deinit(x509_cert);
   gnutls_x509_crt_deinit(x509_cert);
@@ -1381,10 +1404,13 @@ static bool Curl_gtls_data_pending(const struct connectdata *conn,
      0 != gnutls_record_check_pending(backend->session))
      0 != gnutls_record_check_pending(backend->session))
     res = TRUE;
     res = TRUE;
 
 
+#ifndef CURL_DISABLE_PROXY
   connssl = &conn->proxy_ssl[connindex];
   connssl = &conn->proxy_ssl[connindex];
+  backend = connssl->backend;
   if(backend->session &&
   if(backend->session &&
      0 != gnutls_record_check_pending(backend->session))
      0 != gnutls_record_check_pending(backend->session))
     res = TRUE;
     res = TRUE;
+#endif
 
 
   return res;
   return res;
 }
 }
@@ -1433,7 +1459,9 @@ static void close_one(struct ssl_connect_data *connssl)
 static void Curl_gtls_close(struct connectdata *conn, int sockindex)
 static void Curl_gtls_close(struct connectdata *conn, int sockindex)
 {
 {
   close_one(&conn->ssl[sockindex]);
   close_one(&conn->ssl[sockindex]);
+#ifndef CURL_DISABLE_PROXY
   close_one(&conn->proxy_ssl[sockindex]);
   close_one(&conn->proxy_ssl[sockindex]);
+#endif
 }
 }
 
 
 /*
 /*

+ 35 - 9
lib/vtls/nss.c

@@ -1027,9 +1027,11 @@ static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
   CERTCertificate *cert;
   CERTCertificate *cert;
 
 
   /* remember the cert verification result */
   /* remember the cert verification result */
+#ifndef CURL_DISABLE_PROXY
   if(SSL_IS_PROXY())
   if(SSL_IS_PROXY())
     data->set.proxy_ssl.certverifyresult = err;
     data->set.proxy_ssl.certverifyresult = err;
   else
   else
+#endif
     data->set.ssl.certverifyresult = err;
     data->set.ssl.certverifyresult = err;
 
 
   if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
   if(err == SSL_ERROR_BAD_CERT_DOMAIN && !SSL_CONN_CONFIG(verifyhost))
@@ -1553,24 +1555,32 @@ static void nss_close(struct ssl_connect_data *connssl)
 static void Curl_nss_close(struct connectdata *conn, int sockindex)
 static void Curl_nss_close(struct connectdata *conn, int sockindex)
 {
 {
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
   struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+#ifndef CURL_DISABLE_PROXY
   struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
   struct ssl_connect_data *connssl_proxy = &conn->proxy_ssl[sockindex];
+#endif
   struct ssl_backend_data *backend = connssl->backend;
   struct ssl_backend_data *backend = connssl->backend;
 
 
-  if(backend->handle || connssl_proxy->backend->handle) {
+  if(backend->handle
+#ifndef CURL_DISABLE_PROXY
+    || connssl_proxy->backend->handle
+#endif
+    ) {
     /* NSS closes the socket we previously handed to it, so we must mark it
     /* NSS closes the socket we previously handed to it, so we must mark it
        as closed to avoid double close */
        as closed to avoid double close */
     fake_sclose(conn->sock[sockindex]);
     fake_sclose(conn->sock[sockindex]);
     conn->sock[sockindex] = CURL_SOCKET_BAD;
     conn->sock[sockindex] = CURL_SOCKET_BAD;
   }
   }
 
 
+#ifndef CURL_DISABLE_PROXY
   if(backend->handle)
   if(backend->handle)
     /* nss_close(connssl) will transitively close also
     /* nss_close(connssl) will transitively close also
        connssl_proxy->backend->handle if both are used. Clear it to avoid
        connssl_proxy->backend->handle if both are used. Clear it to avoid
        a double close leading to crash. */
        a double close leading to crash. */
     connssl_proxy->backend->handle = NULL;
     connssl_proxy->backend->handle = NULL;
 
 
-  nss_close(connssl);
   nss_close(connssl_proxy);
   nss_close(connssl_proxy);
+#endif
+  nss_close(connssl);
 }
 }
 
 
 /* return true if NSS can provide error code (and possibly msg) for the
 /* return true if NSS can provide error code (and possibly msg) for the
@@ -1828,6 +1838,12 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
   CURLcode result;
   CURLcode result;
   bool second_layer = FALSE;
   bool second_layer = FALSE;
   SSLVersionRange sslver_supported;
   SSLVersionRange sslver_supported;
+#ifndef CURL_DISABLE_PROXY
+  const char *hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
+    conn->host.name;
+#else
+  const char *hostname = conn->host.name;
+#endif
 
 
   SSLVersionRange sslver = {
   SSLVersionRange sslver = {
     SSL_LIBRARY_VERSION_TLS_1_0,  /* min */
     SSL_LIBRARY_VERSION_TLS_1_0,  /* min */
@@ -1932,9 +1948,11 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
     goto error;
     goto error;
 
 
   /* not checked yet */
   /* not checked yet */
+#ifndef CURL_DISABLE_PROXY
   if(SSL_IS_PROXY())
   if(SSL_IS_PROXY())
     data->set.proxy_ssl.certverifyresult = 0;
     data->set.proxy_ssl.certverifyresult = 0;
   else
   else
+#endif
     data->set.ssl.certverifyresult = 0;
     data->set.ssl.certverifyresult = 0;
 
 
   if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
   if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
@@ -1991,12 +2009,14 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
     goto error;
     goto error;
   }
   }
 
 
+#ifndef CURL_DISABLE_PROXY
   if(conn->proxy_ssl[sockindex].use) {
   if(conn->proxy_ssl[sockindex].use) {
     DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
     DEBUGASSERT(ssl_connection_complete == conn->proxy_ssl[sockindex].state);
     DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL);
     DEBUGASSERT(conn->proxy_ssl[sockindex].backend->handle != NULL);
     nspr_io = conn->proxy_ssl[sockindex].backend->handle;
     nspr_io = conn->proxy_ssl[sockindex].backend->handle;
     second_layer = TRUE;
     second_layer = TRUE;
   }
   }
+#endif
   else {
   else {
     /* wrap OS file descriptor by NSPR's file descriptor abstraction */
     /* wrap OS file descriptor by NSPR's file descriptor abstraction */
     nspr_io = PR_ImportTCPSocket(sockfd);
     nspr_io = PR_ImportTCPSocket(sockfd);
@@ -2077,8 +2097,11 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
     unsigned char protocols[128];
     unsigned char protocols[128];
 
 
 #ifdef USE_NGHTTP2
 #ifdef USE_NGHTTP2
-    if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
-       (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
+    if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifndef CURL_DISABLE_PROXY
+      && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+#endif
+      ) {
       protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
       protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
       memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
       memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
           NGHTTP2_PROTO_VERSION_ID_LEN);
           NGHTTP2_PROTO_VERSION_ID_LEN);
@@ -2101,14 +2124,11 @@ static CURLcode nss_setup_connect(struct connectdata *conn, int sockindex)
     goto error;
     goto error;
 
 
   /* propagate hostname to the TLS layer */
   /* propagate hostname to the TLS layer */
-  if(SSL_SetURL(backend->handle, SSL_IS_PROXY() ? conn->http_proxy.host.name :
-                conn->host.name) != SECSuccess)
+  if(SSL_SetURL(backend->handle, hostname) != SECSuccess)
     goto error;
     goto error;
 
 
   /* prevent NSS from re-using the session for a different hostname */
   /* prevent NSS from re-using the session for a different hostname */
-  if(SSL_SetSockPeerID(backend->handle, SSL_IS_PROXY() ?
-                       conn->http_proxy.host.name : conn->host.name)
-     != SECSuccess)
+  if(SSL_SetSockPeerID(backend->handle, hostname) != SECSuccess)
     goto error;
     goto error;
 
 
   return CURLE_OK;
   return CURLE_OK;
@@ -2127,11 +2147,17 @@ static CURLcode nss_do_connect(struct connectdata *conn, int sockindex)
   struct Curl_easy *data = conn->data;
   struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_SSL_CONNECT_ERROR;
   CURLcode result = CURLE_SSL_CONNECT_ERROR;
   PRUint32 timeout;
   PRUint32 timeout;
+#ifndef CURL_DISABLE_PROXY
   long * const certverifyresult = SSL_IS_PROXY() ?
   long * const certverifyresult = SSL_IS_PROXY() ?
     &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
     &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
   const char * const pinnedpubkey = SSL_IS_PROXY() ?
   const char * const pinnedpubkey = SSL_IS_PROXY() ?
               data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
               data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
               data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
               data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+#else
+  long * const certverifyresult = &data->set.ssl.certverifyresult;
+  const char * const pinnedpubkey =
+              data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+#endif
 
 
 
 
   /* check timeout situation */
   /* check timeout situation */

+ 5 - 2
lib/vtls/openssl.c

@@ -619,7 +619,9 @@ SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in,
                                   const char *key_passwd)
                                   const char *key_passwd)
 {
 {
 /* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
 /* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
-#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) /* 1.0.2 or later */
+#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) && /* OpenSSL 1.0.2 or later */ \
+    !(defined(LIBRESSL_VERSION_NUMBER) && \
+      (LIBRESSL_VERSION_NUMBER < 0x2090100fL)) /* LibreSSL 2.9.1 or later */
   int ret = 0;
   int ret = 0;
   X509 *x = NULL;
   X509 *x = NULL;
   void *passwd_callback_userdata = (void *)key_passwd;
   void *passwd_callback_userdata = (void *)key_passwd;
@@ -2825,7 +2827,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
   if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) &&
   if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) &&
      (SSL_SET_OPTION(native_ca_store))) {
      (SSL_SET_OPTION(native_ca_store))) {
     X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
     X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
-    HCERTSTORE hStore = CertOpenSystemStoreA((HCRYPTPROV_LEGACY)NULL, "ROOT");
+    HCERTSTORE hStore = CertOpenSystemStore((HCRYPTPROV_LEGACY)NULL,
+                                            TEXT("ROOT"));
 
 
     if(hStore) {
     if(hStore) {
       PCCERT_CONTEXT pContext = NULL;
       PCCERT_CONTEXT pContext = NULL;

+ 10 - 10
lib/vtls/schannel.c

@@ -50,7 +50,7 @@
 #include "x509asn1.h"
 #include "x509asn1.h"
 #include "curl_printf.h"
 #include "curl_printf.h"
 #include "multiif.h"
 #include "multiif.h"
-#include "system_win32.h"
+#include "version_win32.h"
 
 
 /* The last #include file should be: */
 /* The last #include file should be: */
 #include "curl_memory.h"
 #include "curl_memory.h"
@@ -436,8 +436,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
                "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
                "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
                hostname, conn->remote_port));
                hostname, conn->remote_port));
 
 
-  if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
-                                 VERSION_LESS_THAN_EQUAL)) {
+  if(curlx_verify_windows_version(5, 1, PLATFORM_WINNT,
+                                  VERSION_LESS_THAN_EQUAL)) {
     /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
     /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
        algorithms that may not be supported by all servers. */
        algorithms that may not be supported by all servers. */
     infof(data, "schannel: Windows version is old and may not be able to "
     infof(data, "schannel: Windows version is old and may not be able to "
@@ -448,10 +448,10 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
   /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
   /* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
      Also it doesn't seem to be supported for Wine, see curl bug #983. */
      Also it doesn't seem to be supported for Wine, see curl bug #983. */
   BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
   BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
-    !GetProcAddress(GetModuleHandleA("ntdll"),
+    !GetProcAddress(GetModuleHandle(TEXT("ntdll")),
                     "wine_get_version") &&
                     "wine_get_version") &&
-    Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
-                                VERSION_GREATER_THAN_EQUAL);
+    curlx_verify_windows_version(6, 3, PLATFORM_WINNT,
+                                 VERSION_GREATER_THAN_EQUAL);
 #else
 #else
   BACKEND->use_alpn = false;
   BACKEND->use_alpn = false;
 #endif
 #endif
@@ -467,8 +467,8 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
 #else
 #else
 #ifdef HAS_MANUAL_VERIFY_API
 #ifdef HAS_MANUAL_VERIFY_API
   if(SSL_CONN_CONFIG(CAfile)) {
   if(SSL_CONN_CONFIG(CAfile)) {
-    if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT,
-                                   VERSION_GREATER_THAN_EQUAL)) {
+    if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT,
+                                    VERSION_GREATER_THAN_EQUAL)) {
       BACKEND->use_manual_cred_validation = true;
       BACKEND->use_manual_cred_validation = true;
     }
     }
     else {
     else {
@@ -2015,8 +2015,8 @@ schannel_recv(struct connectdata *conn, int sockindex,
   */
   */
   if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
   if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
      !BACKEND->recv_sspi_close_notify) {
      !BACKEND->recv_sspi_close_notify) {
-    bool isWin2k = Curl_verify_windows_version(5, 0, PLATFORM_WINNT,
-                                               VERSION_EQUAL);
+    bool isWin2k = curlx_verify_windows_version(5, 0, PLATFORM_WINNT,
+                                                VERSION_EQUAL);
 
 
     if(isWin2k && sspi_status == SEC_E_OK)
     if(isWin2k && sspi_status == SEC_E_OK)
       BACKEND->recv_sspi_close_notify = true;
       BACKEND->recv_sspi_close_notify = true;

+ 4 - 4
lib/vtls/schannel_verify.c

@@ -45,7 +45,7 @@
 #include "curl_multibyte.h"
 #include "curl_multibyte.h"
 #include "curl_printf.h"
 #include "curl_printf.h"
 #include "hostcheck.h"
 #include "hostcheck.h"
-#include "system_win32.h"
+#include "version_win32.h"
 
 
 /* The last #include file should be: */
 /* The last #include file should be: */
 #include "curl_memory.h"
 #include "curl_memory.h"
@@ -317,8 +317,8 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
   DWORD i;
   DWORD i;
 
 
   /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
   /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */
-  if(Curl_verify_windows_version(6, 2, PLATFORM_WINNT,
-                                 VERSION_GREATER_THAN_EQUAL)) {
+  if(curlx_verify_windows_version(6, 2, PLATFORM_WINNT,
+                                  VERSION_GREATER_THAN_EQUAL)) {
 #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
 #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG
     /* CertGetNameString will provide the 8-bit character string without
     /* CertGetNameString will provide the 8-bit character string without
      * any decoding */
      * any decoding */
@@ -564,7 +564,7 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex)
      * trusted certificates. This is only supported on Windows 7+.
      * trusted certificates. This is only supported on Windows 7+.
      */
      */
 
 
-    if(Curl_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) {
+    if(curlx_verify_windows_version(6, 1, PLATFORM_WINNT, VERSION_LESS_THAN)) {
       failf(data, "schannel: this version of Windows is too old to support "
       failf(data, "schannel: this version of Windows is too old to support "
             "certificate verification via CA bundle file.");
             "certificate verification via CA bundle file.");
       result = CURLE_SSL_CACERT_BADFILE;
       result = CURLE_SSL_CACERT_BADFILE;

+ 1 - 0
lib/vtls/vtls.c

@@ -621,6 +621,7 @@ void Curl_ssl_close(struct connectdata *conn, int sockindex)
 {
 {
   DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
   DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
   Curl_ssl->close_one(conn, sockindex);
   Curl_ssl->close_one(conn, sockindex);
+  conn->ssl[sockindex].state = ssl_connection_none;
 }
 }
 
 
 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
 CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)