Browse Source

curl 2021-05-26 (6b951a69)

Code extracted from:

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

at commit 6b951a6928811507d493303b2878e848c077b471 (curl-7_77_0).
Curl Upstream 4 years ago
parent
commit
18b2a8d760
100 changed files with 2678 additions and 1861 deletions
  1. 1 19
      CMake/CurlTests.c
  2. 1 4
      CMake/Platforms/WindowsCache.cmake
  3. 84 43
      CMakeLists.txt
  4. 37 8
      include/curl/curl.h
  5. 5 5
      include/curl/curlver.h
  6. 6 6
      include/curl/typecheck-gcc.h
  7. 12 5
      lib/CMakeLists.txt
  8. 5 0
      lib/Makefile.inc
  9. 28 1
      lib/amigaos.c
  10. 16 46
      lib/asyn-ares.c
  11. 16 60
      lib/asyn-thread.c
  12. 127 0
      lib/bufref.c
  13. 46 0
      lib/bufref.h
  14. 31 16
      lib/c-hyper.c
  15. 0 2
      lib/conncache.c
  16. 72 57
      lib/connect.c
  17. 3 3
      lib/connect.h
  18. 5 4
      lib/content_encoding.c
  19. 253 182
      lib/cookie.c
  20. 7 6
      lib/cookie.h
  21. 7 1
      lib/curl_addrinfo.c
  22. 19 46
      lib/curl_config.h.cmake
  23. 3 3
      lib/curl_endian.c
  24. 2 2
      lib/curl_endian.h
  25. 2 2
      lib/curl_get_line.c
  26. 1 1
      lib/curl_gssapi.c
  27. 0 1
      lib/curl_krb5.h
  28. 51 33
      lib/curl_multibyte.c
  29. 21 22
      lib/curl_multibyte.h
  30. 69 76
      lib/curl_ntlm_core.c
  31. 10 8
      lib/curl_ntlm_core.h
  32. 5 5
      lib/curl_path.c
  33. 7 1
      lib/curl_rtmp.c
  34. 191 111
      lib/curl_sasl.c
  35. 11 6
      lib/curl_sasl.h
  36. 46 25
      lib/curl_setup.h
  37. 2 17
      lib/curl_setup_once.h
  38. 6 5
      lib/dict.c
  39. 67 58
      lib/doh.c
  40. 2 2
      lib/dynbuf.h
  41. 24 34
      lib/easy.c
  42. 6 1
      lib/easyoptions.c
  43. 24 16
      lib/file.c
  44. 70 51
      lib/ftp.c
  45. 1 2
      lib/ftplistparser.c
  46. 7 3
      lib/getinfo.c
  47. 2 0
      lib/gopher.c
  48. 2 2
      lib/hash.c
  49. 4 4
      lib/hostcheck.c
  50. 65 19
      lib/hostip.c
  51. 1 9
      lib/hostip.h
  52. 3 16
      lib/hostip6.c
  53. 13 8
      lib/hsts.c
  54. 4 4
      lib/hsts.h
  55. 150 71
      lib/http.c
  56. 11 5
      lib/http.h
  57. 138 81
      lib/http2.c
  58. 3 3
      lib/http2.h
  59. 2 2
      lib/http_aws_sigv4.c
  60. 5 6
      lib/http_digest.c
  61. 0 1
      lib/http_digest.h
  62. 1 1
      lib/http_negotiate.c
  63. 59 43
      lib/http_ntlm.c
  64. 84 30
      lib/http_proxy.c
  65. 24 0
      lib/http_proxy.h
  66. 6 4
      lib/imap.c
  67. 2 2
      lib/inet_ntop.c
  68. 5 17
      lib/krb5.c
  69. 26 14
      lib/ldap.c
  70. 3 3
      lib/llist.c
  71. 3 30
      lib/md4.c
  72. 2 29
      lib/md5.c
  73. 25 10
      lib/memdebug.c
  74. 2 2
      lib/mime.c
  75. 2 2
      lib/mprintf.c
  76. 1 0
      lib/mqtt.c
  77. 258 151
      lib/multi.c
  78. 26 24
      lib/multihandle.h
  79. 4 4
      lib/non-ascii.c
  80. 2 8
      lib/nonblock.c
  81. 78 60
      lib/openldap.c
  82. 3 4
      lib/pingpong.h
  83. 19 8
      lib/pop3.c
  84. 41 51
      lib/progress.c
  85. 5 4
      lib/rtsp.c
  86. 1 1
      lib/select.c
  87. 16 7
      lib/sendf.c
  88. 123 47
      lib/setopt.c
  89. 4 4
      lib/setup-vms.h
  90. 6 36
      lib/sha256.c
  91. 2 2
      lib/share.c
  92. 2 2
      lib/sigpipe.h
  93. 6 5
      lib/smb.c
  94. 3 3
      lib/smb.h
  95. 7 5
      lib/smtp.c
  96. 1 4
      lib/socketpair.h
  97. 3 3
      lib/socks.c
  98. 1 1
      lib/socks_gssapi.c
  99. 1 1
      lib/socks_sspi.c
  100. 9 9
      lib/splay.c

+ 1 - 19
CMake/CurlTests.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -214,24 +214,6 @@ if (sizeof (bool *) )
 #include <float.h>
 #include <float.h>
 int main() { return 0; }
 int main() { return 0; }
 #endif
 #endif
-#ifdef RETSIGTYPE_TEST
-#include <sys/types.h>
-#include <signal.h>
-#ifdef signal
-# undef signal
-#endif
-#ifdef __cplusplus
-extern "C" void (*signal (int, void (*)(int)))(int);
-#else
-void (*signal ()) ();
-#endif
-
-int
-main ()
-{
-  return 0;
-}
-#endif
 #ifdef HAVE_INET_NTOA_R_DECL
 #ifdef HAVE_INET_NTOA_R_DECL
 #include <arpa/inet.h>
 #include <arpa/inet.h>
 
 

+ 1 - 4
CMake/Platforms/WindowsCache.cmake

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #                             \___|\___/|_| \_\_____|
 #
 #
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2021, 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
@@ -89,8 +89,6 @@ if(NOT UNIX)
     set(HAVE_INET_ADDR 1)
     set(HAVE_INET_ADDR 1)
     set(HAVE_INET_NTOA 1)
     set(HAVE_INET_NTOA 1)
     set(HAVE_INET_NTOA_R 0)
     set(HAVE_INET_NTOA_R 0)
-    set(HAVE_TCGETATTR 0)
-    set(HAVE_TCSETATTR 0)
     set(HAVE_PERROR 1)
     set(HAVE_PERROR 1)
     set(HAVE_CLOSESOCKET 1)
     set(HAVE_CLOSESOCKET 1)
     set(HAVE_SETVBUF 0)
     set(HAVE_SETVBUF 0)
@@ -134,7 +132,6 @@ if(NOT UNIX)
       set(HAVE_GETADDRINFO 0)
       set(HAVE_GETADDRINFO 0)
     endif()
     endif()
     set(STDC_HEADERS 1)
     set(STDC_HEADERS 1)
-    set(RETSIGTYPE_TEST 1)
 
 
     set(HAVE_SIGACTION 0)
     set(HAVE_SIGACTION 0)
     set(HAVE_MACRO_SIGSETJMP 0)
     set(HAVE_MACRO_SIGSETJMP 0)

+ 84 - 43
CMakeLists.txt

@@ -191,6 +191,9 @@ mark_as_advanced(CURL_DISABLE_GOPHER)
 option(CURL_DISABLE_MQTT "to disable MQTT" OFF)
 option(CURL_DISABLE_MQTT "to disable MQTT" OFF)
 mark_as_advanced(CURL_DISABLE_MQTT)
 mark_as_advanced(CURL_DISABLE_MQTT)
 
 
+option(CURL_ENABLE_EXPORT_TARGET "to enable cmake export target" ON)
+mark_as_advanced(CURL_ENABLE_EXPORT_TARGET)
+
 if(HTTP_ONLY)
 if(HTTP_ONLY)
   set(CURL_DISABLE_DICT ON)
   set(CURL_DISABLE_DICT ON)
   set(CURL_DISABLE_FILE ON)
   set(CURL_DISABLE_FILE ON)
@@ -210,6 +213,8 @@ endif()
 
 
 option(CURL_DISABLE_ALTSVC "to disable alt-svc support" OFF)
 option(CURL_DISABLE_ALTSVC "to disable alt-svc support" OFF)
 mark_as_advanced(CURL_DISABLE_ALTSVC)
 mark_as_advanced(CURL_DISABLE_ALTSVC)
+option(CURL_DISABLE_HSTS "to disable HSTS support" OFF)
+mark_as_advanced(CURL_DISABLE_HSTS)
 option(CURL_DISABLE_COOKIES "to disable cookies support" OFF)
 option(CURL_DISABLE_COOKIES "to disable cookies support" OFF)
 mark_as_advanced(CURL_DISABLE_COOKIES)
 mark_as_advanced(CURL_DISABLE_COOKIES)
 option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF)
 option(CURL_DISABLE_CRYPTO_AUTH "to disable cryptographic authentication" OFF)
@@ -310,7 +315,6 @@ check_function_exists(gethostname HAVE_GETHOSTNAME)
 if(WIN32)
 if(WIN32)
   check_library_exists_concat("ws2_32" getch        HAVE_LIBWS2_32)
   check_library_exists_concat("ws2_32" getch        HAVE_LIBWS2_32)
   check_library_exists_concat("winmm"  getch        HAVE_LIBWINMM)
   check_library_exists_concat("winmm"  getch        HAVE_LIBWINMM)
-  list(APPEND CURL_LIBS "advapi32")
 endif()
 endif()
 
 
 # check SSL libraries
 # check SSL libraries
@@ -356,7 +360,6 @@ 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_SCHANNEL implies CURL_WINDOWS_SSPI
   set(USE_WINDOWS_SSPI ON) # CMAKE_USE_SCHANNEL implies CURL_WINDOWS_SSPI
-  list(APPEND CURL_LIBS "crypt32")
 endif()
 endif()
 if(CURL_WINDOWS_SSPI)
 if(CURL_WINDOWS_SSPI)
   set(USE_WINDOWS_SSPI ON)
   set(USE_WINDOWS_SSPI ON)
@@ -383,6 +386,14 @@ if(CMAKE_USE_SECTRANSP)
   list(APPEND CURL_LIBS "${COREFOUNDATION_FRAMEWORK}" "${SECURITY_FRAMEWORK}")
   list(APPEND CURL_LIBS "${COREFOUNDATION_FRAMEWORK}" "${SECURITY_FRAMEWORK}")
 endif()
 endif()
 
 
+if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+  find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
+  if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
+     message(FATAL_ERROR "SystemConfiguration framework not found")
+  endif()
+  list(APPEND CURL_LIBS "${SYSTEMCONFIGURATION_FRAMEWORK}")
+endif()
+
 if(CMAKE_USE_OPENSSL)
 if(CMAKE_USE_OPENSSL)
   find_package(OpenSSL REQUIRED)
   find_package(OpenSSL REQUIRED)
   set(SSL_ENABLED ON)
   set(SSL_ENABLED ON)
@@ -505,10 +516,6 @@ if(USE_QUICHE)
   cmake_pop_check_state()
   cmake_pop_check_state()
 endif()
 endif()
 
 
-if(WIN32)
-  set(USE_WIN32_CRYPTO ON)
-endif()
-
 if(NOT CURL_DISABLE_LDAP)
 if(NOT CURL_DISABLE_LDAP)
   if(WIN32)
   if(WIN32)
     option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
     option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
@@ -625,6 +632,14 @@ if(USE_LIBIDN2)
   check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2)
   check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2)
 endif()
 endif()
 
 
+if(WIN32)
+  option(USE_WIN32_IDN "Use WinIDN for IDN support" OFF)
+  if(USE_WIN32_IDN)
+    list(APPEND CURL_LIBS "Normaliz")
+    set(WANT_IDN_PROTOTYPES ON)
+  endif()
+endif()
+
 # Check for symbol dlopen (same as HAVE_LIBDL)
 # Check for symbol dlopen (same as HAVE_LIBDL)
 check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
 check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
 
 
@@ -847,7 +862,8 @@ elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT)
     foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS})
     foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS})
       if(EXISTS "${SEARCH_CA_BUNDLE_PATH}")
       if(EXISTS "${SEARCH_CA_BUNDLE_PATH}")
         message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}")
         message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}")
-        set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}")
+        set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}" CACHE STRING
+            "Path to the CA bundle. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
         set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
         set(CURL_CA_BUNDLE_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
         break()
         break()
       endif()
       endif()
@@ -856,7 +872,8 @@ elseif(CURL_CA_PATH_AUTODETECT OR CURL_CA_BUNDLE_AUTODETECT)
 
 
   if(CURL_CA_PATH_AUTODETECT AND (NOT CURL_CA_PATH_SET))
   if(CURL_CA_PATH_AUTODETECT AND (NOT CURL_CA_PATH_SET))
     if(EXISTS "/etc/ssl/certs")
     if(EXISTS "/etc/ssl/certs")
-      set(CURL_CA_PATH "/etc/ssl/certs")
+      set(CURL_CA_PATH "/etc/ssl/certs" CACHE STRING
+          "Location of default CA path. Set 'none' to disable or 'auto' for auto-detection. Defaults to 'auto'.")
       set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
       set(CURL_CA_PATH_SET TRUE CACHE BOOL "Path to the CA bundle has been set")
     endif()
     endif()
   endif()
   endif()
@@ -874,9 +891,7 @@ if(NOT UNIX)
   check_include_file_concat("winsock.h"      HAVE_WINSOCK_H)
   check_include_file_concat("winsock.h"      HAVE_WINSOCK_H)
   check_include_file_concat("ws2tcpip.h"     HAVE_WS2TCPIP_H)
   check_include_file_concat("ws2tcpip.h"     HAVE_WS2TCPIP_H)
   check_include_file_concat("winsock2.h"     HAVE_WINSOCK2_H)
   check_include_file_concat("winsock2.h"     HAVE_WINSOCK2_H)
-  if(NOT CURL_WINDOWS_SSPI AND USE_OPENSSL)
-    set(CURL_LIBS ${CURL_LIBS} "crypt32")
-  endif()
+  check_include_file_concat("wincrypt.h"     HAVE_WINCRYPT_H)
 endif()
 endif()
 
 
 check_include_file_concat("stdio.h"          HAVE_STDIO_H)
 check_include_file_concat("stdio.h"          HAVE_STDIO_H)
@@ -999,20 +1014,18 @@ check_symbol_exists(alarm         "${CURL_INCLUDES}" HAVE_ALARM)
 if(NOT HAVE_STRNCMPI)
 if(NOT HAVE_STRNCMPI)
   set(HAVE_STRCMPI)
   set(HAVE_STRCMPI)
 endif()
 endif()
+check_symbol_exists(getppid       "${CURL_INCLUDES}" HAVE_GETPPID)
+check_symbol_exists(utimes        "${CURL_INCLUDES}" HAVE_UTIMES)
+
 check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR)
 check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR)
 check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R)
 check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R)
 check_symbol_exists(gettimeofday  "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
 check_symbol_exists(gettimeofday  "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY)
 check_symbol_exists(inet_addr     "${CURL_INCLUDES}" HAVE_INET_ADDR)
 check_symbol_exists(inet_addr     "${CURL_INCLUDES}" HAVE_INET_ADDR)
 check_symbol_exists(inet_ntoa     "${CURL_INCLUDES}" HAVE_INET_NTOA)
 check_symbol_exists(inet_ntoa     "${CURL_INCLUDES}" HAVE_INET_NTOA)
 check_symbol_exists(inet_ntoa_r   "${CURL_INCLUDES}" HAVE_INET_NTOA_R)
 check_symbol_exists(inet_ntoa_r   "${CURL_INCLUDES}" HAVE_INET_NTOA_R)
-check_symbol_exists(tcsetattr     "${CURL_INCLUDES}" HAVE_TCSETATTR)
-check_symbol_exists(tcgetattr     "${CURL_INCLUDES}" HAVE_TCGETATTR)
-check_symbol_exists(perror        "${CURL_INCLUDES}" HAVE_PERROR)
 check_symbol_exists(closesocket   "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
 check_symbol_exists(closesocket   "${CURL_INCLUDES}" HAVE_CLOSESOCKET)
-check_symbol_exists(setvbuf       "${CURL_INCLUDES}" HAVE_SETVBUF)
 check_symbol_exists(sigsetjmp     "${CURL_INCLUDES}" HAVE_SIGSETJMP)
 check_symbol_exists(sigsetjmp     "${CURL_INCLUDES}" HAVE_SIGSETJMP)
 check_symbol_exists(getpass_r     "${CURL_INCLUDES}" HAVE_GETPASS_R)
 check_symbol_exists(getpass_r     "${CURL_INCLUDES}" HAVE_GETPASS_R)
-check_symbol_exists(strlcat       "${CURL_INCLUDES}" HAVE_STRLCAT)
 check_symbol_exists(getpwuid      "${CURL_INCLUDES}" HAVE_GETPWUID)
 check_symbol_exists(getpwuid      "${CURL_INCLUDES}" HAVE_GETPWUID)
 check_symbol_exists(getpwuid_r    "${CURL_INCLUDES}" HAVE_GETPWUID_R)
 check_symbol_exists(getpwuid_r    "${CURL_INCLUDES}" HAVE_GETPWUID_R)
 check_symbol_exists(geteuid       "${CURL_INCLUDES}" HAVE_GETEUID)
 check_symbol_exists(geteuid       "${CURL_INCLUDES}" HAVE_GETEUID)
@@ -1062,6 +1075,16 @@ if(HAVE_FSETXATTR)
   endforeach()
   endforeach()
 endif()
 endif()
 
 
+set(CMAKE_EXTRA_INCLUDE_FILES   "sys/socket.h")
+check_type_size("sa_family_t"   SIZEOF_SA_FAMILY_T)
+set(HAVE_SA_FAMILY_T            ${HAVE_SIZEOF_SA_FAMILY_T})
+set(CMAKE_EXTRA_INCLUDE_FILES   "")
+
+set(CMAKE_EXTRA_INCLUDE_FILES   "ws2def.h")
+check_type_size("ADDRESS_FAMILY"    SIZEOF_ADDRESS_FAMILY)
+set(HAVE_ADDRESS_FAMILY         ${HAVE_SIZEOF_ADDRESS_FAMILY})
+set(CMAKE_EXTRA_INCLUDE_FILES   "")
+
 # sigaction and sigsetjmp are special. Use special mechanism for
 # sigaction and sigsetjmp are special. Use special mechanism for
 # detecting those, but only if previous attempt failed.
 # detecting those, but only if previous attempt failed.
 if(HAVE_SIGNAL_H)
 if(HAVE_SIGNAL_H)
@@ -1110,7 +1133,6 @@ foreach(CURL_TEST
     HAVE_IN_ADDR_T
     HAVE_IN_ADDR_T
     HAVE_BOOL_T
     HAVE_BOOL_T
     STDC_HEADERS
     STDC_HEADERS
-    RETSIGTYPE_TEST
     HAVE_INET_NTOA_R_DECL
     HAVE_INET_NTOA_R_DECL
     HAVE_INET_NTOA_R_DECL_REENTRANT
     HAVE_INET_NTOA_R_DECL_REENTRANT
     HAVE_GETADDRINFO
     HAVE_GETADDRINFO
@@ -1211,12 +1233,6 @@ if(HAVE_FIONBIO OR
   set(HAVE_DISABLED_NONBLOCKING)
   set(HAVE_DISABLED_NONBLOCKING)
 endif()
 endif()
 
 
-if(RETSIGTYPE_TEST)
-  set(RETSIGTYPE void)
-else()
-  set(RETSIGTYPE int)
-endif()
-
 if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
 if(CMAKE_COMPILER_IS_GNUCC AND APPLE)
   include(CheckCCompilerFlag)
   include(CheckCCompilerFlag)
   check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double)
   check_c_compiler_flag(-Wno-long-double HAVE_C_FLAG_Wno_long_double)
@@ -1254,6 +1270,19 @@ if(WIN32)
 
 
   # Use the manifest embedded in the Windows Resource
   # Use the manifest embedded in the Windows Resource
   set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DCURL_EMBED_MANIFEST")
   set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DCURL_EMBED_MANIFEST")
+
+  # Check if crypto functions in wincrypt.h are actually available
+  if(HAVE_WINCRYPT_H)
+    check_symbol_exists(CryptAcquireContext "${CURL_INCLUDES}" USE_WINCRYPT)
+  endif()
+  if(USE_WINCRYPT)
+    set(USE_WIN32_CRYPTO ON)
+  endif()
+
+  # Link required libraries for USE_WIN32_CRYPTO or USE_SCHANNEL
+  if(USE_WIN32_CRYPTO OR USE_SCHANNEL)
+    list(APPEND CURL_LIBS "advapi32" "crypt32")
+  endif()
 endif()
 endif()
 
 
 if(MSVC)
 if(MSVC)
@@ -1266,6 +1295,11 @@ if(MSVC)
   else()
   else()
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
     set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /W4")
   endif()
   endif()
+
+  # Use multithreaded compilation on VS 2008+
+  if(MSVC_VERSION GREATER_EQUAL 1500)
+    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /MP")
+  endif()
 endif()
 endif()
 
 
 if(CURL_WERROR)
 if(CURL_WERROR)
@@ -1335,14 +1369,6 @@ if(BUILD_TESTING)
   add_subdirectory(tests)
   add_subdirectory(tests)
 endif()
 endif()
 
 
-# NTLM support requires crypto function adaptions from various SSL libs
-# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
-if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_DARWINSSL OR USE_MBEDTLS OR USE_WIN32_CRYPTO))
-  set(use_ntlm ON)
-else()
-  set(use_ntlm OFF)
-endif()
-
 # Helper to populate a list (_items) with a label when conditions (the remaining
 # Helper to populate a list (_items) with a label when conditions (the remaining
 # args) are satisfied
 # args) are satisfied
 macro(_add_if label)
 macro(_add_if label)
@@ -1352,6 +1378,13 @@ macro(_add_if label)
   endif()
   endif()
 endmacro()
 endmacro()
 
 
+# NTLM support requires crypto function adaptions from various SSL libs
+# TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
+if(NOT CURL_DISABLE_CRYPTO_AUTH AND (USE_OPENSSL OR USE_MBEDTLS OR
+                                     USE_DARWINSSL OR USE_WIN32_CRYPTO))
+  set(use_curl_ntlm_core ON)
+endif()
+
 # Clear list and try to detect available features
 # Clear list and try to detect available features
 set(_items)
 set(_items)
 _add_if("SSL"           SSL_ENABLED)
 _add_if("SSL"           SSL_ENABLED)
@@ -1361,13 +1394,14 @@ _add_if("libz"          HAVE_LIBZ)
 _add_if("brotli"        HAVE_BROTLI)
 _add_if("brotli"        HAVE_BROTLI)
 _add_if("zstd"          HAVE_ZSTD)
 _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("Largefile"     (CURL_SIZEOF_CURL_OFF_T GREATER 4) AND
+_add_if("IDN"           HAVE_LIBIDN2 OR USE_WIN32_IDN)
+_add_if("Largefile"     (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 (Schannel) 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"       NOT CURL_DISABLE_ALTSVC)
 _add_if("alt-svc"       NOT CURL_DISABLE_ALTSVC)
+_add_if("HSTS"          NOT CURL_DISABLE_HSTS)
 # TODO SSP1 missing for SPNEGO
 # TODO SSP1 missing for SPNEGO
 _add_if("SPNEGO"        NOT CURL_DISABLE_CRYPTO_AUTH AND
 _add_if("SPNEGO"        NOT CURL_DISABLE_CRYPTO_AUTH AND
                         (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
                         (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
@@ -1375,9 +1409,12 @@ _add_if("Kerberos"      NOT CURL_DISABLE_CRYPTO_AUTH AND
                         (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
                         (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
 # NTLM support requires crypto function adaptions from various SSL libs
 # NTLM support requires crypto function adaptions from various SSL libs
 # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
 # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
-_add_if("NTLM"        use_ntlm OR USE_WINDOWS_SSPI)
+_add_if("NTLM"          NOT CURL_DISABLE_CRYPTO_AUTH AND
+                        (use_curl_ntlm_core OR USE_WINDOWS_SSPI))
 # TODO missing option (autoconf: --enable-ntlm-wb)
 # TODO missing option (autoconf: --enable-ntlm-wb)
-_add_if("NTLM_WB"     use_ntlm AND NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
+_add_if("NTLM_WB"       NOT CURL_DISABLE_CRYPTO_AUTH AND
+                        (use_curl_ntlm_core OR USE_WINDOWS_SSPI) AND
+                        NOT CURL_DISABLE_HTTP AND NTLM_WB_ENABLED)
 # TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP
 # TODO missing option (--enable-tls-srp), depends on GNUTLS_SRP/OPENSSL_SRP
 _add_if("TLS-SRP"       USE_TLS_SRP)
 _add_if("TLS-SRP"       USE_TLS_SRP)
 # TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header
 # TODO option --with-nghttp2 tests for nghttp2 lib and nghttp2/nghttp2.h header
@@ -1411,8 +1448,10 @@ _add_if("POP3"          NOT CURL_DISABLE_POP3)
 _add_if("POP3S"         NOT CURL_DISABLE_POP3 AND SSL_ENABLED)
 _add_if("POP3S"         NOT CURL_DISABLE_POP3 AND SSL_ENABLED)
 _add_if("IMAP"          NOT CURL_DISABLE_IMAP)
 _add_if("IMAP"          NOT CURL_DISABLE_IMAP)
 _add_if("IMAPS"         NOT CURL_DISABLE_IMAP AND SSL_ENABLED)
 _add_if("IMAPS"         NOT CURL_DISABLE_IMAP AND SSL_ENABLED)
-_add_if("SMB"           NOT CURL_DISABLE_SMB AND use_ntlm)
-_add_if("SMBS"          NOT CURL_DISABLE_SMB AND SSL_ENABLED AND use_ntlm)
+_add_if("SMB"           NOT CURL_DISABLE_SMB AND
+                        use_curl_ntlm_core AND (SIZEOF_CURL_OFF_T GREATER 4))
+_add_if("SMBS"          NOT CURL_DISABLE_SMB AND SSL_ENABLED AND
+                        use_curl_ntlm_core AND (SIZEOF_CURL_OFF_T GREATER 4))
 _add_if("SMTP"          NOT CURL_DISABLE_SMTP)
 _add_if("SMTP"          NOT CURL_DISABLE_SMTP)
 _add_if("SMTPS"         NOT CURL_DISABLE_SMTP AND SSL_ENABLED)
 _add_if("SMTPS"         NOT CURL_DISABLE_SMTP AND SSL_ENABLED)
 _add_if("SCP"           USE_LIBSSH2 OR USE_LIBSSH)
 _add_if("SCP"           USE_LIBSSH2 OR USE_LIBSSH)
@@ -1428,7 +1467,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("Schannel"         SSL_ENABLED AND USE_WINDOWS_SSPI)
+_add_if("Schannel"         SSL_ENABLED AND USE_SCHANNEL)
 _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)
@@ -1533,11 +1572,13 @@ configure_package_config_file(CMake/curl-config.cmake.in
         INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR}
         INSTALL_DESTINATION ${CURL_INSTALL_CMAKE_DIR}
 )
 )
 
 
-install(
-        EXPORT "${TARGETS_EXPORT_NAME}"
-        NAMESPACE "${PROJECT_NAME}::"
-        DESTINATION ${CURL_INSTALL_CMAKE_DIR}
-)
+if(CURL_ENABLE_EXPORT_TARGET)
+  install(
+          EXPORT "${TARGETS_EXPORT_NAME}"
+          NAMESPACE "${PROJECT_NAME}::"
+          DESTINATION ${CURL_INSTALL_CMAKE_DIR}
+  )
+endif()
 
 
 install(
 install(
         FILES ${version_config} ${project_config}
         FILES ${version_config} ${project_config}

+ 37 - 8
include/curl/curl.h

@@ -155,7 +155,8 @@ typedef enum {
   CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */
   CURLSSLBACKEND_AXTLS = 10, /* never used since 7.63.0 */
   CURLSSLBACKEND_MBEDTLS = 11,
   CURLSSLBACKEND_MBEDTLS = 11,
   CURLSSLBACKEND_MESALINK = 12,
   CURLSSLBACKEND_MESALINK = 12,
-  CURLSSLBACKEND_BEARSSL = 13
+  CURLSSLBACKEND_BEARSSL = 13,
+  CURLSSLBACKEND_RUSTLS = 14
 } curl_sslbackend;
 } curl_sslbackend;
 
 
 /* aliases for library clones and renames */
 /* aliases for library clones and renames */
@@ -611,6 +612,7 @@ typedef enum {
   CURLE_HTTP3,                   /* 95 - An HTTP/3 layer problem */
   CURLE_HTTP3,                   /* 95 - An HTTP/3 layer problem */
   CURLE_QUIC_CONNECT_ERROR,      /* 96 - QUIC connection error */
   CURLE_QUIC_CONNECT_ERROR,      /* 96 - QUIC connection error */
   CURLE_PROXY,                   /* 97 - proxy handshake error */
   CURLE_PROXY,                   /* 97 - proxy handshake error */
+  CURLE_SSL_CLIENTCERT,          /* 98 - client-side certificate required */
   CURL_LAST /* never use! */
   CURL_LAST /* never use! */
 } CURLcode;
 } CURLcode;
 
 
@@ -887,6 +889,10 @@ typedef enum {
    operating system. Currently implemented under MS-Windows. */
    operating system. Currently implemented under MS-Windows. */
 #define CURLSSLOPT_NATIVE_CA (1<<4)
 #define CURLSSLOPT_NATIVE_CA (1<<4)
 
 
+/* - CURLSSLOPT_AUTO_CLIENT_CERT tells libcurl to automatically locate and use
+   a client certificate for authentication. (Schannel) */
+#define CURLSSLOPT_AUTO_CLIENT_CERT (1<<5)
+
 /* The default connection attempt delay in milliseconds for happy eyeballs.
 /* The default connection attempt delay in milliseconds for happy eyeballs.
    CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
    CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS.3 and happy-eyeballs-timeout-ms.d document
    this value, keep them in sync. */
    this value, keep them in sync. */
@@ -1460,8 +1466,8 @@ typedef enum {
 #define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
 #define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
 
 
   /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
   /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
-     tell libcurl to resolve names to those IP versions only. This only has
-     affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
+     tell libcurl to use those IP versions only. This only has effect on
+     systems with support for more than one, i.e IPv4 _and_ IPv6. */
   CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),
   CURLOPT(CURLOPT_IPRESOLVE, CURLOPTTYPE_VALUES, 113),
 
 
   /* Set this option to limit the size of a file that will be downloaded from
   /* Set this option to limit the size of a file that will be downloaded from
@@ -2078,6 +2084,23 @@ typedef enum {
   /* Parameters for V4 signature */
   /* Parameters for V4 signature */
   CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305),
   CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305),
 
 
+  /* Same as CURLOPT_SSL_VERIFYPEER but for DOH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYPEER, CURLOPTTYPE_LONG, 306),
+
+  /* Same as CURLOPT_SSL_VERIFYHOST but for DOH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYHOST, CURLOPTTYPE_LONG, 307),
+
+  /* Same as CURLOPT_SSL_VERIFYSTATUS but for DOH (DNS-over-HTTPS) servers. */
+  CURLOPT(CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOPTTYPE_LONG, 308),
+
+  /* The CA certificates as "blob" used to validate the peer certificate
+     this option is used only if SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_CAINFO_BLOB, CURLOPTTYPE_BLOB, 309),
+
+  /* The CA certificates as "blob" used to validate the proxy certificate
+     this option is used only if PROXY_SSL_VERIFYPEER is true */
+  CURLOPT(CURLOPT_PROXY_CAINFO_BLOB, CURLOPTTYPE_BLOB, 310),
+
   CURLOPT_LASTENTRY /* the last unused */
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 } CURLoption;
 
 
@@ -2112,10 +2135,10 @@ typedef enum {
   /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
   /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
      name resolves addresses using more than one IP protocol version, this
      name resolves addresses using more than one IP protocol version, this
      option might be handy to force libcurl to use a specific IP version. */
      option might be handy to force libcurl to use a specific IP version. */
-#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
+#define CURL_IPRESOLVE_WHATEVER 0 /* default, uses addresses to all IP
                                      versions that your system allows */
                                      versions that your system allows */
-#define CURL_IPRESOLVE_V4       1 /* resolve to IPv4 addresses */
-#define CURL_IPRESOLVE_V6       2 /* resolve to IPv6 addresses */
+#define CURL_IPRESOLVE_V4       1 /* uses only IPv4 addresses/connections */
+#define CURL_IPRESOLVE_V6       2 /* uses only IPv6 addresses/connections */
 
 
   /* three convenient "aliases" that follow the name scheme better */
   /* three convenient "aliases" that follow the name scheme better */
 #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
 #define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
@@ -2751,8 +2774,9 @@ typedef enum {
   CURLINFO_RETRY_AFTER      = CURLINFO_OFF_T + 57,
   CURLINFO_RETRY_AFTER      = CURLINFO_OFF_T + 57,
   CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58,
   CURLINFO_EFFECTIVE_METHOD = CURLINFO_STRING + 58,
   CURLINFO_PROXY_ERROR      = CURLINFO_LONG + 59,
   CURLINFO_PROXY_ERROR      = CURLINFO_LONG + 59,
+  CURLINFO_REFERER          = CURLINFO_STRING + 60,
 
 
-  CURLINFO_LASTONE          = 59
+  CURLINFO_LASTONE          = 60
 } 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
@@ -2855,6 +2879,7 @@ typedef enum {
   CURLVERSION_SEVENTH,
   CURLVERSION_SEVENTH,
   CURLVERSION_EIGHTH,
   CURLVERSION_EIGHTH,
   CURLVERSION_NINTH,
   CURLVERSION_NINTH,
+  CURLVERSION_TENTH,
   CURLVERSION_LAST /* never actually use this */
   CURLVERSION_LAST /* never actually use this */
 } CURLversion;
 } CURLversion;
 
 
@@ -2863,7 +2888,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_NINTH
+#define CURLVERSION_NOW CURLVERSION_TENTH
 
 
 struct curl_version_info_data {
 struct curl_version_info_data {
   CURLversion age;          /* age of the returned struct */
   CURLversion age;          /* age of the returned struct */
@@ -2916,6 +2941,9 @@ struct curl_version_info_data {
 
 
   /* These fields were added in CURLVERSION_NINTH */
   /* These fields were added in CURLVERSION_NINTH */
   const char *hyper_version; /* human readable string. */
   const char *hyper_version; /* human readable string. */
+
+  /* These fields were added in CURLVERSION_TENTH */
+  const char *gsasl_version; /* human readable string. */
 };
 };
 typedef struct curl_version_info_data curl_version_info_data;
 typedef struct curl_version_info_data curl_version_info_data;
 
 
@@ -2953,6 +2981,7 @@ typedef struct curl_version_info_data curl_version_info_data;
 #define CURL_VERSION_ZSTD         (1<<26) /* zstd features are present */
 #define CURL_VERSION_ZSTD         (1<<26) /* zstd features are present */
 #define CURL_VERSION_UNICODE      (1<<27) /* Unicode support on Windows */
 #define CURL_VERSION_UNICODE      (1<<27) /* Unicode support on Windows */
 #define CURL_VERSION_HSTS         (1<<28) /* HSTS is supported */
 #define CURL_VERSION_HSTS         (1<<28) /* HSTS is supported */
+#define CURL_VERSION_GSASL        (1<<29) /* libgsasl is supported */
 
 
  /*
  /*
  * NAME curl_version_info()
  * NAME curl_version_info()

+ 5 - 5
include/curl/curlver.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -26,16 +26,16 @@
    a script at release-time. This was made its own header file in 7.11.2 */
    a script at release-time. This was made its own header file in 7.11.2 */
 
 
 /* This is the global package copyright */
 /* This is the global package copyright */
-#define LIBCURL_COPYRIGHT "1996 - 2020 Daniel Stenberg, <[email protected]>."
+#define LIBCURL_COPYRIGHT "1996 - 2021 Daniel Stenberg, <[email protected]>."
 
 
 /* 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.75.0-DEV"
+#define LIBCURL_VERSION "7.77.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 75
+#define LIBCURL_VERSION_MINOR 77
 #define LIBCURL_VERSION_PATCH 0
 #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
@@ -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 0x074b00
+#define LIBCURL_VERSION_NUM 0x074d00
 
 
 /*
 /*
  * 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 - 6
include/curl/typecheck-gcc.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -667,11 +667,11 @@ typedef CURLcode (*_curl_ssl_ctx_callback4)(CURL *, const void *,
 /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
 /* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
  * this will of course break if we're included before OpenSSL headers...
  * this will of course break if we're included before OpenSSL headers...
  */
  */
-typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *);
-typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *);
-typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *);
-typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX,
-                                           const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback5)(CURL *, SSL_CTX *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback6)(CURL *, SSL_CTX *, const void *);
+typedef CURLcode (*_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX *, void *);
+typedef CURLcode (*_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX *,
+                                            const void *);
 #else
 #else
 typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
 typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
 typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;
 typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;

+ 12 - 5
lib/CMakeLists.txt

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #                             \___|\___/|_| \_\_____|
 #
 #
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2021, 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
@@ -20,6 +20,7 @@
 #
 #
 ###########################################################################
 ###########################################################################
 set(LIB_NAME libcurl)
 set(LIB_NAME libcurl)
+set(LIBCURL_OUTPUT_NAME libcurl CACHE STRING "Basename of the curl library")
 
 
 if(BUILD_SHARED_LIBS)
 if(BUILD_SHARED_LIBS)
   set(CURL_STATICLIB NO)
   set(CURL_STATICLIB NO)
@@ -98,7 +99,10 @@ if(WIN32)
   add_definitions(-D_USRDLL)
   add_definitions(-D_USRDLL)
 endif()
 endif()
 
 
-set_target_properties(${LIB_NAME} PROPERTIES COMPILE_DEFINITIONS BUILDING_LIBCURL)
+set_target_properties(${LIB_NAME} PROPERTIES
+  COMPILE_DEFINITIONS BUILDING_LIBCURL
+  OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
+  )
 
 
 if(HIDES_CURL_PRIVATE_SYMBOLS)
 if(HIDES_CURL_PRIVATE_SYMBOLS)
   set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   set_property(TARGET ${LIB_NAME} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
@@ -117,13 +121,16 @@ endif()
 
 
 if(WIN32)
 if(WIN32)
   if(BUILD_SHARED_LIBS)
   if(BUILD_SHARED_LIBS)
-    # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib"
-    set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib")
+    if(MSVC)
+      # Add "_imp" as a suffix before the extension to avoid conflicting with
+      # the statically linked "libcurl.lib"
+      set_target_properties(${LIB_NAME} PROPERTIES IMPORT_SUFFIX "_imp.lib")
+    endif()
   endif()
   endif()
 endif()
 endif()
 
 
 target_include_directories(${LIB_NAME} INTERFACE
 target_include_directories(${LIB_NAME} INTERFACE
-  $<INSTALL_INTERFACE:include>
+  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
   $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
   $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
 
 
 install(TARGETS ${LIB_NAME}
 install(TARGETS ${LIB_NAME}

+ 5 - 0
lib/Makefile.inc

@@ -25,6 +25,7 @@ LIB_VAUTH_CFILES =      \
   vauth/cram.c          \
   vauth/cram.c          \
   vauth/digest.c        \
   vauth/digest.c        \
   vauth/digest_sspi.c   \
   vauth/digest_sspi.c   \
+  vauth/gsasl.c         \
   vauth/krb5_gssapi.c   \
   vauth/krb5_gssapi.c   \
   vauth/krb5_sspi.c     \
   vauth/krb5_sspi.c     \
   vauth/ntlm.c          \
   vauth/ntlm.c          \
@@ -49,6 +50,7 @@ LIB_VTLS_CFILES =           \
   vtls/mesalink.c           \
   vtls/mesalink.c           \
   vtls/nss.c                \
   vtls/nss.c                \
   vtls/openssl.c            \
   vtls/openssl.c            \
+  vtls/rustls.c             \
   vtls/schannel.c           \
   vtls/schannel.c           \
   vtls/schannel_verify.c    \
   vtls/schannel_verify.c    \
   vtls/sectransp.c          \
   vtls/sectransp.c          \
@@ -65,6 +67,7 @@ LIB_VTLS_HFILES =           \
   vtls/mesalink.h           \
   vtls/mesalink.h           \
   vtls/nssg.h               \
   vtls/nssg.h               \
   vtls/openssl.h            \
   vtls/openssl.h            \
+  vtls/rustls.h             \
   vtls/schannel.h           \
   vtls/schannel.h           \
   vtls/sectransp.h          \
   vtls/sectransp.h          \
   vtls/vtls.h               \
   vtls/vtls.h               \
@@ -94,6 +97,7 @@ LIB_CFILES =         \
   asyn-ares.c        \
   asyn-ares.c        \
   asyn-thread.c      \
   asyn-thread.c      \
   base64.c           \
   base64.c           \
+  bufref.c           \
   c-hyper.c          \
   c-hyper.c          \
   conncache.c        \
   conncache.c        \
   connect.c          \
   connect.c          \
@@ -214,6 +218,7 @@ LIB_HFILES =         \
   amigaos.h          \
   amigaos.h          \
   arpa_telnet.h      \
   arpa_telnet.h      \
   asyn.h             \
   asyn.h             \
+  bufref.h           \
   c-hyper.h          \
   c-hyper.h          \
   conncache.h        \
   conncache.h        \
   connect.h          \
   connect.h          \

+ 28 - 1
lib/amigaos.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -90,6 +90,33 @@ void Curl_amiga_X509_free(X509 *a)
 {
 {
   X509_free(a);
   X509_free(a);
 }
 }
+
+/* AmiSSL replaces many functions with macros. Curl requires pointer
+ * to some of these functions. Thus, we have to encapsulate these macros.
+ */
+
+#include "warnless.h"
+
+int (SHA256_Init)(SHA256_CTX *c)
+{
+  return SHA256_Init(c);
+};
+
+int (SHA256_Update)(SHA256_CTX *c, const void *data, size_t len)
+{
+  return SHA256_Update(c, data, curlx_uztoui(len));
+};
+
+int (SHA256_Final)(unsigned char *md, SHA256_CTX *c)
+{
+  return SHA256_Final(md, c);
+};
+
+void (X509_INFO_free)(X509_INFO *a)
+{
+  X509_INFO_free(a);
+};
+
 #endif /* USE_AMISSL */
 #endif /* USE_AMISSL */
 #endif /* __AMIGA__ */
 #endif /* __AMIGA__ */
 
 

+ 16 - 46
lib/asyn-ares.c

@@ -309,7 +309,7 @@ static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
       pfd[i].fd = socks[i];
       pfd[i].fd = socks[i];
       pfd[i].events |= POLLWRNORM|POLLOUT;
       pfd[i].events |= POLLWRNORM|POLLOUT;
     }
     }
-    if(pfd[i].events != 0)
+    if(pfd[i].events)
       num++;
       num++;
     else
     else
       break;
       break;
@@ -384,13 +384,8 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
        them */
        them */
     res->temp_ai = NULL;
     res->temp_ai = NULL;
 
 
-    if(!data->state.async.dns) {
-      failf(data, "Could not resolve: %s (%s)",
-            data->state.async.hostname,
-            ares_strerror(data->state.async.status));
-      result = data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
-        CURLE_COULDNT_RESOLVE_HOST;
-    }
+    if(!data->state.async.dns)
+      result = Curl_resolver_error(data);
     else
     else
       *dns = data->state.async.dns;
       *dns = data->state.async.dns;
 
 
@@ -625,28 +620,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 int *waitp)
                                                 int *waitp)
 {
 {
   char *bufp;
   char *bufp;
-  int family = PF_INET;
 
 
   *waitp = 0; /* default to synchronous response */
   *waitp = 0; /* default to synchronous response */
 
 
-#ifdef ENABLE_IPV6
-  switch(data->set.ipver) {
-  default:
-#if ARES_VERSION >= 0x010601
-    family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
-                           c-ares versions this just falls through and defaults
-                           to PF_INET */
-    break;
-#endif
-  case CURL_IPRESOLVE_V4:
-    family = PF_INET;
-    break;
-  case CURL_IPRESOLVE_V6:
-    family = PF_INET6;
-    break;
-  }
-#endif /* ENABLE_IPV6 */
-
   bufp = strdup(hostname);
   bufp = strdup(hostname);
   if(bufp) {
   if(bufp) {
     struct thread_data *res = NULL;
     struct thread_data *res = NULL;
@@ -666,33 +642,27 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
 
 
     /* initial status - failed */
     /* initial status - failed */
     res->last_status = ARES_ENOTFOUND;
     res->last_status = ARES_ENOTFOUND;
-#ifdef ENABLE_IPV6
-    if(family == PF_UNSPEC) {
-      if(Curl_ipv6works(data)) {
-        res->num_pending = 2;
-
-        /* areschannel is already setup in the Curl_open() function */
-        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
-                            PF_INET, query_completed_cb, data);
-        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
-                            PF_INET6, query_completed_cb, data);
-      }
-      else {
-        res->num_pending = 1;
 
 
-        /* areschannel is already setup in the Curl_open() function */
-        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
-                            PF_INET, query_completed_cb, data);
-      }
+#if ARES_VERSION >= 0x010601
+    /* IPv6 supported by c-ares since 1.6.1 */
+    if(Curl_ipv6works(data)) {
+      /* The stack seems to be IPv6-enabled */
+      res->num_pending = 2;
+
+      /* areschannel is already setup in the Curl_open() function */
+      ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                          PF_INET, query_completed_cb, data);
+      ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                          PF_INET6, query_completed_cb, data);
     }
     }
     else
     else
-#endif /* ENABLE_IPV6 */
+#endif /* ARES_VERSION >= 0x010601 */
     {
     {
       res->num_pending = 1;
       res->num_pending = 1;
 
 
       /* areschannel is already setup in the Curl_open() function */
       /* areschannel is already setup in the Curl_open() function */
       ares_gethostbyname((ares_channel)data->state.async.resolver,
       ares_gethostbyname((ares_channel)data->state.async.resolver,
-                         hostname, family,
+                         hostname, PF_INET,
                          query_completed_cb, data);
                          query_completed_cb, data);
     }
     }
 
 

+ 16 - 60
lib/asyn-thread.c

@@ -163,7 +163,7 @@ struct thread_sync_data {
   int port;
   int port;
   char *hostname;        /* hostname to resolve, Curl_async.hostname
   char *hostname;        /* hostname to resolve, Curl_async.hostname
                             duplicate */
                             duplicate */
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
   struct Curl_easy *data;
   struct Curl_easy *data;
   curl_socket_t sock_pair[2]; /* socket pair */
   curl_socket_t sock_pair[2]; /* socket pair */
 #endif
 #endif
@@ -201,7 +201,7 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd)
   if(tsd->res)
   if(tsd->res)
     Curl_freeaddrinfo(tsd->res);
     Curl_freeaddrinfo(tsd->res);
 
 
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
   /*
   /*
    * close one end of the socket pair (may be done in resolver thread);
    * close one end of the socket pair (may be done in resolver thread);
    * the other end (for reading) is always closed in the parent thread.
    * the other end (for reading) is always closed in the parent thread.
@@ -238,12 +238,12 @@ int init_thread_sync_data(struct thread_data *td,
 #endif
 #endif
 
 
   tsd->mtx = malloc(sizeof(curl_mutex_t));
   tsd->mtx = malloc(sizeof(curl_mutex_t));
-  if(tsd->mtx == NULL)
+  if(!tsd->mtx)
     goto err_exit;
     goto err_exit;
 
 
   Curl_mutex_init(tsd->mtx);
   Curl_mutex_init(tsd->mtx);
 
 
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
   /* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */
   /* create socket pair, avoid AF_LOCAL since it doesn't build on Solaris */
   if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) {
   if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &tsd->sock_pair[0]) < 0) {
     tsd->sock_pair[0] = CURL_SOCKET_BAD;
     tsd->sock_pair[0] = CURL_SOCKET_BAD;
@@ -297,7 +297,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
   struct thread_data *td = tsd->td;
   struct thread_data *td = tsd->td;
   char service[12];
   char service[12];
   int rc;
   int rc;
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
   char buf[1];
   char buf[1];
 #endif
 #endif
 
 
@@ -305,7 +305,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
 
 
   rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
   rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
 
 
-  if(rc != 0) {
+  if(rc) {
     tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
     tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
     if(tsd->sock_error == 0)
     if(tsd->sock_error == 0)
       tsd->sock_error = RESOLVER_ENOMEM;
       tsd->sock_error = RESOLVER_ENOMEM;
@@ -322,7 +322,7 @@ static unsigned int CURL_STDCALL getaddrinfo_thread(void *arg)
     free(td);
     free(td);
   }
   }
   else {
   else {
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
     if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
     if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
       /* DNS has been resolved, signal client task */
       /* DNS has been resolved, signal client task */
       buf[0] = 1;
       buf[0] = 1;
@@ -382,7 +382,7 @@ static void destroy_async_data(struct Curl_async *async)
   if(async->tdata) {
   if(async->tdata) {
     struct thread_data *td = async->tdata;
     struct thread_data *td = async->tdata;
     int done;
     int done;
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
     curl_socket_t sock_rd = td->tsd.sock_pair[0];
     curl_socket_t sock_rd = td->tsd.sock_pair[0];
     struct Curl_easy *data = td->tsd.data;
     struct Curl_easy *data = td->tsd.data;
 #endif
 #endif
@@ -407,7 +407,7 @@ static void destroy_async_data(struct Curl_async *async)
 
 
       free(async->tdata);
       free(async->tdata);
     }
     }
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
     /*
     /*
      * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
      * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
      * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
      * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
@@ -483,35 +483,6 @@ static bool init_resolve_thread(struct Curl_easy *data,
   return FALSE;
   return FALSE;
 }
 }
 
 
-/*
- * resolver_error() calls failf() with the appropriate message after a resolve
- * error
- */
-
-static CURLcode resolver_error(struct Curl_easy *data)
-{
-  const char *host_or_proxy;
-  CURLcode result;
-
-#ifndef CURL_DISABLE_PROXY
-  struct connectdata *conn = data->conn;
-  if(conn->bits.httpproxy) {
-    host_or_proxy = "proxy";
-    result = CURLE_COULDNT_RESOLVE_PROXY;
-  }
-  else
-#endif
-  {
-    host_or_proxy = "host";
-    result = CURLE_COULDNT_RESOLVE_HOST;
-  }
-
-  failf(data, "Could not resolve %s: %s", host_or_proxy,
-        data->state.async.hostname);
-
-  return result;
-}
-
 /*
 /*
  * 'entry' may be NULL and then no data is returned
  * 'entry' may be NULL and then no data is returned
  */
  */
@@ -542,7 +513,7 @@ static CURLcode thread_wait_resolv(struct Curl_easy *data,
 
 
   if(!data->state.async.dns && report)
   if(!data->state.async.dns && report)
     /* a name was not resolved, report error */
     /* a name was not resolved, report error */
-    result = resolver_error(data);
+    result = Curl_resolver_error(data);
 
 
   destroy_async_data(&data->state.async);
   destroy_async_data(&data->state.async);
 
 
@@ -616,7 +587,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
     getaddrinfo_complete(data);
     getaddrinfo_complete(data);
 
 
     if(!data->state.async.dns) {
     if(!data->state.async.dns) {
-      CURLcode result = resolver_error(data);
+      CURLcode result = Curl_resolver_error(data);
       destroy_async_data(&data->state.async);
       destroy_async_data(&data->state.async);
       return result;
       return result;
     }
     }
@@ -654,13 +625,13 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
   timediff_t milli;
   timediff_t milli;
   timediff_t ms;
   timediff_t ms;
   struct resdata *reslv = (struct resdata *)data->state.async.resolver;
   struct resdata *reslv = (struct resdata *)data->state.async.resolver;
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
   struct thread_data *td = data->state.async.tdata;
   struct thread_data *td = data->state.async.tdata;
 #else
 #else
   (void)socks;
   (void)socks;
 #endif
 #endif
 
 
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
   if(td) {
   if(td) {
     /* return read fd to client for polling the DNS resolution status */
     /* return read fd to client for polling the DNS resolution status */
     socks[0] = td->tsd.sock_pair[0];
     socks[0] = td->tsd.sock_pair[0];
@@ -679,7 +650,7 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
     else
     else
       milli = 200;
       milli = 200;
     Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
     Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
-#ifdef USE_SOCKETPAIR
+#ifndef CURL_DISABLE_SOCKETPAIR
   }
   }
 #endif
 #endif
 
 
@@ -730,24 +701,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
   *waitp = 0; /* default to synchronous response */
   *waitp = 0; /* default to synchronous response */
 
 
 #ifdef CURLRES_IPV6
 #ifdef CURLRES_IPV6
-  /*
-   * Check if a limited name resolve has been requested.
-   */
-  switch(data->set.ipver) {
-  case CURL_IPRESOLVE_V4:
-    pf = PF_INET;
-    break;
-  case CURL_IPRESOLVE_V6:
-    pf = PF_INET6;
-    break;
-  default:
+  if(Curl_ipv6works(data))
+    /* The stack seems to be IPv6-enabled */
     pf = PF_UNSPEC;
     pf = PF_UNSPEC;
-    break;
-  }
-
-  if((pf != PF_INET) && !Curl_ipv6works(data))
-    /* The stack seems to be a non-IPv6 one */
-    pf = PF_INET;
 #endif /* CURLRES_IPV6 */
 #endif /* CURLRES_IPV6 */
 
 
   memset(&hints, 0, sizeof(hints));
   memset(&hints, 0, sizeof(hints));

+ 127 - 0
lib/bufref.c

@@ -0,0 +1,127 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2021, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "urldata.h"
+#include "bufref.h"
+
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define SIGNATURE 0x5c48e9b2    /* Random pattern. */
+
+/*
+ * Init a bufref struct.
+ */
+void Curl_bufref_init(struct bufref *br)
+{
+  DEBUGASSERT(br);
+  br->dtor = NULL;
+  br->ptr = NULL;
+  br->len = 0;
+
+#ifdef DEBUGBUILD
+  br->signature = SIGNATURE;
+#endif
+}
+
+/*
+ * Free the buffer and re-init the necessary fields. It doesn't touch the
+ * 'signature' field and thus this buffer reference can be reused.
+ */
+
+void Curl_bufref_free(struct bufref *br)
+{
+  DEBUGASSERT(br);
+  DEBUGASSERT(br->signature == SIGNATURE);
+  DEBUGASSERT(br->ptr || !br->len);
+
+  if(br->ptr && br->dtor)
+    br->dtor((void *) br->ptr);
+
+  br->dtor = NULL;
+  br->ptr = NULL;
+  br->len = 0;
+}
+
+/*
+ * Set the buffer reference to new values. The previously referenced buffer
+ * is released before assignment.
+ */
+void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
+                     void (*dtor)(void *))
+{
+  DEBUGASSERT(ptr || !len);
+  DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
+
+  Curl_bufref_free(br);
+  br->ptr = (const unsigned char *) ptr;
+  br->len = len;
+  br->dtor = dtor;
+}
+
+/*
+ * Get a pointer to the referenced buffer.
+ */
+const unsigned char *Curl_bufref_ptr(const struct bufref *br)
+{
+  DEBUGASSERT(br);
+  DEBUGASSERT(br->signature == SIGNATURE);
+  DEBUGASSERT(br->ptr || !br->len);
+
+  return br->ptr;
+}
+
+/*
+ * Get the length of the referenced buffer data.
+ */
+size_t Curl_bufref_len(const struct bufref *br)
+{
+  DEBUGASSERT(br);
+  DEBUGASSERT(br->signature == SIGNATURE);
+  DEBUGASSERT(br->ptr || !br->len);
+
+  return br->len;
+}
+
+CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len)
+{
+  unsigned char *cpy = NULL;
+
+  DEBUGASSERT(br);
+  DEBUGASSERT(br->signature == SIGNATURE);
+  DEBUGASSERT(br->ptr || !br->len);
+  DEBUGASSERT(ptr || !len);
+  DEBUGASSERT(len <= CURL_MAX_INPUT_LENGTH);
+
+  if(ptr) {
+    cpy = malloc(len + 1);
+    if(!cpy)
+      return CURLE_OUT_OF_MEMORY;
+    if(len)
+      memcpy(cpy, ptr, len);
+    cpy[len] = '\0';
+  }
+
+  Curl_bufref_set(br, cpy, len, curl_free);
+  return CURLE_OK;
+}

+ 46 - 0
lib/bufref.h

@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_BUFREF_H
+#define HEADER_CURL_BUFREF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2021, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * Generic buffer reference.
+ */
+struct bufref {
+  void (*dtor)(void *);         /* Associated destructor. */
+  const unsigned char *ptr;     /* Referenced data buffer. */
+  size_t len;                   /* The data size in bytes. */
+#ifdef DEBUGBUILD
+  int signature;                /* Detect API use mistakes. */
+#endif
+};
+
+
+void Curl_bufref_init(struct bufref *br);
+void Curl_bufref_set(struct bufref *br, const void *ptr, size_t len,
+                     void (*dtor)(void *));
+const unsigned char *Curl_bufref_ptr(const struct bufref *br);
+size_t Curl_bufref_len(const struct bufref *br);
+CURLcode Curl_bufref_memdup(struct bufref *br, const void *ptr, size_t len);
+void Curl_bufref_free(struct bufref *br);
+
+#endif

+ 31 - 16
lib/c-hyper.c

@@ -51,6 +51,7 @@
 #include "transfer.h"
 #include "transfer.h"
 #include "multiif.h"
 #include "multiif.h"
 #include "progress.h"
 #include "progress.h"
+#include "content_encoding.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -174,8 +175,14 @@ static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
   }
   }
   if(k->ignorebody)
   if(k->ignorebody)
     return HYPER_ITER_CONTINUE;
     return HYPER_ITER_CONTINUE;
+  if(0 == len)
+    return HYPER_ITER_CONTINUE;
   Curl_debug(data, CURLINFO_DATA_IN, buf, len);
   Curl_debug(data, CURLINFO_DATA_IN, buf, len);
-  result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
+  if(!data->set.http_ce_skip && k->writer_stack)
+    /* content-encoded data */
+    result = Curl_unencode_write(data, k->writer_stack, buf, len);
+  else
+    result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
 
 
   if(result) {
   if(result) {
     data->state.hresult = result;
     data->state.hresult = result;
@@ -198,11 +205,8 @@ static CURLcode status_line(struct Curl_easy *data,
                             const uint8_t *reason, size_t rlen)
                             const uint8_t *reason, size_t rlen)
 {
 {
   CURLcode result;
   CURLcode result;
-  size_t wrote;
   size_t len;
   size_t len;
   const char *vstr;
   const char *vstr;
-  curl_write_callback writeheader =
-    data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
   vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
   vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
     (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
     (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
   conn->httpversion =
   conn->httpversion =
@@ -225,12 +229,12 @@ static CURLcode status_line(struct Curl_easy *data,
   len = Curl_dyn_len(&data->state.headerb);
   len = Curl_dyn_len(&data->state.headerb);
   Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
   Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
              len);
              len);
-  Curl_set_in_callback(data, true);
-  wrote = writeheader(Curl_dyn_ptr(&data->state.headerb), 1, len,
-                      data->set.writeheader);
-  Curl_set_in_callback(data, false);
-  if(wrote != len)
-    return CURLE_WRITE_ERROR;
+  result = Curl_client_write(data, CLIENTWRITE_HEADER,
+                             Curl_dyn_ptr(&data->state.headerb), len);
+  if(result) {
+    data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+    return HYPER_ITER_BREAK;
+  }
 
 
   data->info.header_size += (long)len;
   data->info.header_size += (long)len;
   data->req.headerbytecount += (long)len;
   data->req.headerbytecount += (long)len;
@@ -327,7 +331,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
       infof(data, "hyperstream is done!\n");
       infof(data, "hyperstream is done!\n");
       break;
       break;
     }
     }
-    else if(t != HYPER_TASK_RESPONSE) {
+    else if(t != HYPER_TASK_RESPONSE && t != HYPER_TASK_EMPTY) {
       *didwhat = KEEP_RECV;
       *didwhat = KEEP_RECV;
       break;
       break;
     }
     }
@@ -464,8 +468,6 @@ CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
     else
     else
       linelen = 2; /* CRLF ending */
       linelen = 2; /* CRLF ending */
     linelen += (p - n);
     linelen += (p - n);
-    if(!n)
-      return CURLE_BAD_FUNCTION_ARGUMENT;
     vlen = p - v;
     vlen = p - v;
 
 
     if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
     if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
@@ -741,7 +743,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     goto error;
     goto error;
   }
   }
 
 
-  if(data->set.httpversion == CURL_HTTP_VERSION_1_0) {
+  if(data->state.httpwant == CURL_HTTP_VERSION_1_0) {
     if(HYPERE_OK != hyper_request_set_version(req,
     if(HYPERE_OK != hyper_request_set_version(req,
                                               HYPER_HTTP_VERSION_1_0)) {
                                               HYPER_HTTP_VERSION_1_0)) {
       failf(data, "error setting HTTP version");
       failf(data, "error setting HTTP version");
@@ -807,14 +809,27 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 #endif
 #endif
 
 
   Curl_safefree(data->state.aptr.ref);
   Curl_safefree(data->state.aptr.ref);
-  if(data->change.referer && !Curl_checkheaders(data, "Referer")) {
-    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+  if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
     if(!data->state.aptr.ref)
     if(!data->state.aptr.ref)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     if(Curl_hyper_header(data, headers, data->state.aptr.ref))
     if(Curl_hyper_header(data, headers, data->state.aptr.ref))
       goto error;
       goto error;
   }
   }
 
 
+  if(!Curl_checkheaders(data, "Accept-Encoding") &&
+     data->set.str[STRING_ENCODING]) {
+    Curl_safefree(data->state.aptr.accept_encoding);
+    data->state.aptr.accept_encoding =
+      aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+    if(!data->state.aptr.accept_encoding)
+      return CURLE_OUT_OF_MEMORY;
+    if(Curl_hyper_header(data, headers, data->state.aptr.accept_encoding))
+      goto error;
+  }
+  else
+    Curl_safefree(data->state.aptr.accept_encoding);
+
   result = cookies(data, conn, headers);
   result = cookies(data, conn, headers);
   if(result)
   if(result)
     return result;
     return result;

+ 0 - 2
lib/conncache.c

@@ -466,7 +466,6 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
     data->state.conn_cache->num_conn--;
     data->state.conn_cache->num_conn--;
     DEBUGF(infof(data, "The cache now contains %zu members\n",
     DEBUGF(infof(data, "The cache now contains %zu members\n",
                  data->state.conn_cache->num_conn));
                  data->state.conn_cache->num_conn));
-    conn_candidate->data = data; /* associate! */
   }
   }
 
 
   return conn_candidate;
   return conn_candidate;
@@ -529,7 +528,6 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
     connc->num_conn--;
     connc->num_conn--;
     DEBUGF(infof(data, "The cache now contains %zu members\n",
     DEBUGF(infof(data, "The cache now contains %zu members\n",
                  connc->num_conn));
                  connc->num_conn));
-    conn_candidate->data = data; /* associate! */
   }
   }
   CONNCACHE_UNLOCK(data);
   CONNCACHE_UNLOCK(data);
 
 

+ 72 - 57
lib/connect.c

@@ -171,65 +171,63 @@ singleipconnect(struct Curl_easy *data,
  * infinite time left). If the value is negative, the timeout time has already
  * infinite time left). If the value is negative, the timeout time has already
  * elapsed.
  * elapsed.
  *
  *
- * The start time is stored in progress.t_startsingle - as set with
- * Curl_pgrsTime(..., TIMER_STARTSINGLE);
- *
  * If 'nowp' is non-NULL, it points to the current time.
  * If 'nowp' is non-NULL, it points to the current time.
  * 'duringconnect' is FALSE if not during a connect, as then of course the
  * 'duringconnect' is FALSE if not during a connect, as then of course the
  * connect timeout is not taken into account!
  * connect timeout is not taken into account!
  *
  *
  * @unittest: 1303
  * @unittest: 1303
  */
  */
+
+#define TIMEOUT_CONNECT 1
+#define TIMEOUT_MAXTIME 2
+
 timediff_t Curl_timeleft(struct Curl_easy *data,
 timediff_t Curl_timeleft(struct Curl_easy *data,
                          struct curltime *nowp,
                          struct curltime *nowp,
                          bool duringconnect)
                          bool duringconnect)
 {
 {
-  int timeout_set = 0;
-  timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+  unsigned int timeout_set = 0;
+  timediff_t connect_timeout_ms = 0;
+  timediff_t maxtime_timeout_ms = 0;
+  timediff_t timeout_ms = 0;
   struct curltime now;
   struct curltime now;
 
 
-  /* if a timeout is set, use the most restrictive one */
-
-  if(data->set.timeout > 0)
-    timeout_set |= 1;
-  if(duringconnect && (data->set.connecttimeout > 0))
-    timeout_set |= 2;
-
-  switch(timeout_set) {
-  case 1:
-    timeout_ms = data->set.timeout;
-    break;
-  case 2:
-    timeout_ms = data->set.connecttimeout;
-    break;
-  case 3:
-    if(data->set.timeout < data->set.connecttimeout)
-      timeout_ms = data->set.timeout;
-    else
-      timeout_ms = data->set.connecttimeout;
-    break;
-  default:
-    /* use the default */
-    if(!duringconnect)
-      /* if we're not during connect, there's no default timeout so if we're
-         at zero we better just return zero and not make it a negative number
-         by the math below */
-      return 0;
-    break;
+  /* The duration of a connect and the total transfer are calculated from two
+     different time-stamps. It can end up with the total timeout being reached
+     before the connect timeout expires and we must acknowledge whichever
+     timeout that is reached first. The total timeout is set per entire
+     operation, while the connect timeout is set per connect. */
+
+  if(data->set.timeout > 0) {
+    timeout_set = TIMEOUT_MAXTIME;
+    maxtime_timeout_ms = data->set.timeout;
+  }
+  if(duringconnect) {
+    timeout_set |= TIMEOUT_CONNECT;
+    connect_timeout_ms = (data->set.connecttimeout > 0) ?
+      data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
   }
   }
+  if(!timeout_set)
+    /* no timeout  */
+    return 0;
 
 
   if(!nowp) {
   if(!nowp) {
     now = Curl_now();
     now = Curl_now();
     nowp = &now;
     nowp = &now;
   }
   }
 
 
-  /* subtract elapsed time */
-  if(duringconnect)
-    /* since this most recent connect started */
-    timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
-  else
-    /* since the entire operation started */
-    timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+  if(timeout_set & TIMEOUT_MAXTIME) {
+    maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
+    timeout_ms = maxtime_timeout_ms;
+  }
+
+  if(timeout_set & TIMEOUT_CONNECT) {
+    connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
+
+    if(!(timeout_set & TIMEOUT_MAXTIME) ||
+       (connect_timeout_ms < maxtime_timeout_ms))
+      timeout_ms = connect_timeout_ms;
+  }
+
   if(!timeout_ms)
   if(!timeout_ms)
     /* avoid returning 0 as that means no timeout! */
     /* avoid returning 0 as that means no timeout! */
     return -1;
     return -1;
@@ -611,7 +609,7 @@ static CURLcode trynextip(struct Curl_easy *data,
 /* Copies connection info into the transfer handle to make it available when
 /* Copies connection info into the transfer handle to make it available when
    the transfer handle is no longer associated with the connection. */
    the transfer handle is no longer associated with the connection. */
 void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
 void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
-                          char *local_ip, long local_port)
+                          char *local_ip, int local_port)
 {
 {
   memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
   memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
   if(local_ip && local_ip[0])
   if(local_ip && local_ip[0])
@@ -627,7 +625,7 @@ void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
 /* retrieves ip address and port from a sockaddr structure.
 /* retrieves ip address and port from a sockaddr structure.
    note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
    note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
 bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
 bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
-                      char *addr, long *port)
+                      char *addr, int *port)
 {
 {
   struct sockaddr_in *si = NULL;
   struct sockaddr_in *si = NULL;
 #ifdef ENABLE_IPV6
 #ifdef ENABLE_IPV6
@@ -662,7 +660,7 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
 #endif
 #endif
 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
     case AF_UNIX:
     case AF_UNIX:
-      if(salen > (curl_socklen_t)sizeof(sa_family_t)) {
+      if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
         su = (struct sockaddr_un*)sa;
         su = (struct sockaddr_un*)sa;
         msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
         msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
       }
       }
@@ -690,7 +688,7 @@ void Curl_conninfo_remote(struct Curl_easy *data,
   char buffer[STRERROR_LEN];
   char buffer[STRERROR_LEN];
   struct Curl_sockaddr_storage ssrem;
   struct Curl_sockaddr_storage ssrem;
   curl_socklen_t plen;
   curl_socklen_t plen;
-  long port;
+  int port;
   plen = sizeof(struct Curl_sockaddr_storage);
   plen = sizeof(struct Curl_sockaddr_storage);
   memset(&ssrem, 0, sizeof(ssrem));
   memset(&ssrem, 0, sizeof(ssrem));
   if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
   if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
@@ -715,7 +713,7 @@ void Curl_conninfo_remote(struct Curl_easy *data,
 /* retrieves the start/end point information of a socket of an established
 /* retrieves the start/end point information of a socket of an established
    connection */
    connection */
 void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
 void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
-                         char *local_ip, long *local_port)
+                         char *local_ip, int *local_port)
 {
 {
 #ifdef HAVE_GETSOCKNAME
 #ifdef HAVE_GETSOCKNAME
   char buffer[STRERROR_LEN];
   char buffer[STRERROR_LEN];
@@ -752,7 +750,7 @@ void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
      ip address and port number whenever an outgoing connection is
      ip address and port number whenever an outgoing connection is
      **established** from the primary socket to a remote address. */
      **established** from the primary socket to a remote address. */
   char local_ip[MAX_IPADR_LEN] = "";
   char local_ip[MAX_IPADR_LEN] = "";
-  long local_port = -1;
+  int local_port = -1;
 
 
   if(conn->transport == TRNSPRT_TCP) {
   if(conn->transport == TRNSPRT_TCP) {
     if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
     if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
@@ -908,8 +906,10 @@ CURLcode Curl_is_connected(struct Curl_easy *data,
         connkeep(conn, "HTTP/3 default");
         connkeep(conn, "HTTP/3 default");
         return CURLE_OK;
         return CURLE_OK;
       }
       }
-      if(result)
+      if(result) {
+        conn->tempsock[i] = CURL_SOCKET_BAD;
         error = SOCKERRNO;
         error = SOCKERRNO;
+      }
     }
     }
     else
     else
 #endif
 #endif
@@ -1158,7 +1158,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
   curl_socket_t sockfd;
   curl_socket_t sockfd;
   CURLcode result;
   CURLcode result;
   char ipaddress[MAX_IPADR_LEN];
   char ipaddress[MAX_IPADR_LEN];
-  long port;
+  int port;
   bool is_tcp;
   bool is_tcp;
 #ifdef TCP_FASTOPEN_CONNECT
 #ifdef TCP_FASTOPEN_CONNECT
   int optval = 1;
   int optval = 1;
@@ -1180,7 +1180,7 @@ static CURLcode singleipconnect(struct Curl_easy *data,
     Curl_closesocket(data, conn, sockfd);
     Curl_closesocket(data, conn, sockfd);
     return CURLE_OK;
     return CURLE_OK;
   }
   }
-  infof(data, "  Trying %s:%ld...\n", ipaddress, port);
+  infof(data, "  Trying %s:%d...\n", ipaddress, port);
 
 
 #ifdef ENABLE_IPV6
 #ifdef ENABLE_IPV6
   is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
   is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
@@ -1367,14 +1367,31 @@ CURLcode Curl_connecthost(struct Curl_easy *data,
   conn->timeoutms_per_addr[1] =
   conn->timeoutms_per_addr[1] =
     conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
     conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
 
 
-  conn->tempfamily[0] = conn->tempaddr[0]?
-    conn->tempaddr[0]->ai_family:0;
+  if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
+    /* any IP version is allowed */
+    conn->tempfamily[0] = conn->tempaddr[0]?
+      conn->tempaddr[0]->ai_family:0;
+#ifdef ENABLE_IPV6
+    conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
+      AF_INET : AF_INET6;
+#else
+    conn->tempfamily[1] = AF_UNSPEC;
+#endif
+  }
+  else {
+    /* only one IP version is allowed */
+    conn->tempfamily[0] = (conn->ip_version == CURL_IPRESOLVE_V4) ?
+      AF_INET :
 #ifdef ENABLE_IPV6
 #ifdef ENABLE_IPV6
-  conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
-    AF_INET : AF_INET6;
+      AF_INET6;
 #else
 #else
-  conn->tempfamily[1] = AF_UNSPEC;
+      AF_UNSPEC;
 #endif
 #endif
+    conn->tempfamily[1] = AF_UNSPEC;
+
+    ainext(conn, 0, FALSE); /* find first address of the right type */
+  }
+
   ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
   ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
 
 
   DEBUGF(infof(data, "family0 == %s, family1 == %s\n",
   DEBUGF(infof(data, "family0 == %s, family1 == %s\n",
@@ -1448,11 +1465,9 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
     }
     }
 
 
     c = find.found;
     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;
-      c->data = data;
-    }
     return c->sock[FIRSTSOCKET];
     return c->sock[FIRSTSOCKET];
   }
   }
   return CURL_SOCKET_BAD;
   return CURL_SOCKET_BAD;

+ 3 - 3
lib/connect.h

@@ -54,7 +54,7 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
                                   struct connectdata **connp);
                                   struct connectdata **connp);
 
 
 bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
 bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
-                      char *addr, long *port);
+                      char *addr, int *port);
 
 
 /*
 /*
  * Check if a connection seems to be alive.
  * Check if a connection seems to be alive.
@@ -81,9 +81,9 @@ void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
 void Curl_conninfo_remote(struct Curl_easy *data, struct connectdata *conn,
 void Curl_conninfo_remote(struct Curl_easy *data, struct connectdata *conn,
                           curl_socket_t sockfd);
                           curl_socket_t sockfd);
 void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
 void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
-                         char *local_ip, long *local_port);
+                         char *local_ip, int *local_port);
 void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
 void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
-                          char *local_ip, long local_port);
+                          char *local_ip, int local_port);
 int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
 int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
                      curl_socket_t sock);
                      curl_socket_t sock);
 
 

+ 5 - 4
lib/content_encoding.c

@@ -178,7 +178,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
   /* Dynamically allocate a buffer for decompression because it's uncommonly
   /* Dynamically allocate a buffer for decompression because it's uncommonly
      large to hold on the stack */
      large to hold on the stack */
   decomp = malloc(DSIZ);
   decomp = malloc(DSIZ);
-  if(decomp == NULL)
+  if(!decomp)
     return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
     return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
 
 
   /* because the buffer size is fixed, iteratively decompress and transfer to
   /* because the buffer size is fixed, iteratively decompress and transfer to
@@ -487,7 +487,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
        */
        */
       z->avail_in = (uInt) nbytes;
       z->avail_in = (uInt) nbytes;
       z->next_in = malloc(z->avail_in);
       z->next_in = malloc(z->avail_in);
-      if(z->next_in == NULL) {
+      if(!z->next_in) {
         return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
         return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
       }
       }
       memcpy(z->next_in, buf, z->avail_in);
       memcpy(z->next_in, buf, z->avail_in);
@@ -509,7 +509,7 @@ static CURLcode gzip_unencode_write(struct Curl_easy *data,
     ssize_t hlen;
     ssize_t hlen;
     z->avail_in += (uInt) nbytes;
     z->avail_in += (uInt) nbytes;
     z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
     z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
-    if(z->next_in == NULL) {
+    if(!z->next_in) {
       return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
       return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
     }
     }
     /* Append the new block of data to the previous one */
     /* Append the new block of data to the previous one */
@@ -985,7 +985,8 @@ new_unencoding_writer(struct Curl_easy *data,
   return writer;
   return writer;
 }
 }
 
 
-/* Write data using an unencoding writer stack. */
+/* Write data using an unencoding writer stack. "nbytes" is not
+   allowed to be 0. */
 CURLcode Curl_unencode_write(struct Curl_easy *data,
 CURLcode Curl_unencode_write(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes)
                              const char *buf, size_t nbytes)

+ 253 - 182
lib/cookie.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -105,6 +105,8 @@ Example set of cookies:
 #include "curl_memory.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 #include "memdebug.h"
 
 
+static void strstore(char **str, const char *newstr);
+
 static void freecookie(struct Cookie *co)
 static void freecookie(struct Cookie *co)
 {
 {
   free(co->expirestr);
   free(co->expirestr);
@@ -129,12 +131,13 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
   if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
   if(!strcasecompare(cooke_domain, hostname + hostname_len-cookie_domain_len))
     return FALSE;
     return FALSE;
 
 
-  /* A lead char of cookie_domain is not '.'.
-     RFC6265 4.1.2.3. The Domain Attribute says:
-       For example, if the value of the Domain attribute is
-       "example.com", the user agent will include the cookie in the Cookie
-       header when making HTTP requests to example.com, www.example.com, and
-       www.corp.example.com.
+  /*
+   * A lead char of cookie_domain is not '.'.
+   * RFC6265 4.1.2.3. The Domain Attribute says:
+   * For example, if the value of the Domain attribute is
+   * "example.com", the user agent will include the cookie in the Cookie
+   * header when making HTTP requests to example.com, www.example.com, and
+   * www.corp.example.com.
    */
    */
   if(hostname_len == cookie_domain_len)
   if(hostname_len == cookie_domain_len)
     return TRUE;
     return TRUE;
@@ -144,7 +147,10 @@ static bool tailmatch(const char *cooke_domain, const char *hostname)
 }
 }
 
 
 /*
 /*
- * Return true if the given string is an IP(v4|v6) address.
+ * isip
+ *
+ * Returns true if the given string is an IPv4 or IPv6 address (if IPv6 has
+ * been enabled while building libcurl, and false otherwise.
  */
  */
 static bool isip(const char *domain)
 static bool isip(const char *domain)
 {
 {
@@ -193,19 +199,19 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
 
 
   /* #-fragments are already cut off! */
   /* #-fragments are already cut off! */
   if(0 == strlen(uri_path) || uri_path[0] != '/') {
   if(0 == strlen(uri_path) || uri_path[0] != '/') {
-    free(uri_path);
-    uri_path = strdup("/");
+    strstore(&uri_path, "/");
     if(!uri_path)
     if(!uri_path)
       return FALSE;
       return FALSE;
   }
   }
 
 
-  /* here, RFC6265 5.1.4 says
-     4. Output the characters of the uri-path from the first character up
-        to, but not including, the right-most %x2F ("/").
-     but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
-     without redirect.
-     Ignore this algorithm because /hoge is uri path for this case
-     (uri path is not /).
+  /*
+   * here, RFC6265 5.1.4 says
+   *  4. Output the characters of the uri-path from the first character up
+   *     to, but not including, the right-most %x2F ("/").
+   *  but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site
+   *  without redirect.
+   *  Ignore this algorithm because /hoge is uri path for this case
+   *  (uri path is not /).
    */
    */
 
 
   uri_path_len = strlen(uri_path);
   uri_path_len = strlen(uri_path);
@@ -328,8 +334,7 @@ static char *sanitize_cookie_path(const char *cookie_path)
   /* RFC6265 5.2.4 The Path Attribute */
   /* RFC6265 5.2.4 The Path Attribute */
   if(new_path[0] != '/') {
   if(new_path[0] != '/') {
     /* Let cookie-path be the default-path. */
     /* Let cookie-path be the default-path. */
-    free(new_path);
-    new_path = strdup("/");
+    strstore(&new_path, "/");
     return new_path;
     return new_path;
   }
   }
 
 
@@ -348,7 +353,7 @@ static char *sanitize_cookie_path(const char *cookie_path)
  */
  */
 void Curl_cookie_loadfiles(struct Curl_easy *data)
 void Curl_cookie_loadfiles(struct Curl_easy *data)
 {
 {
-  struct curl_slist *list = data->change.cookielist;
+  struct curl_slist *list = data->state.cookielist;
   if(list) {
   if(list) {
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
     while(list) {
     while(list) {
@@ -357,7 +362,8 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
                                         data->cookies,
                                         data->cookies,
                                         data->set.cookiesession);
                                         data->set.cookiesession);
       if(!newcookies)
       if(!newcookies)
-        /* Failure may be due to OOM or a bad cookie; both are ignored
+        /*
+         * Failure may be due to OOM or a bad cookie; both are ignored
          * but only the first should be
          * but only the first should be
          */
          */
         infof(data, "ignoring failed cookie_init for %s\n", list->data);
         infof(data, "ignoring failed cookie_init for %s\n", list->data);
@@ -365,17 +371,20 @@ void Curl_cookie_loadfiles(struct Curl_easy *data)
         data->cookies = newcookies;
         data->cookies = newcookies;
       list = list->next;
       list = list->next;
     }
     }
-    curl_slist_free_all(data->change.cookielist); /* clean up list */
-    data->change.cookielist = NULL; /* don't do this again! */
+    curl_slist_free_all(data->state.cookielist); /* clean up list */
+    data->state.cookielist = NULL; /* don't do this again! */
     Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
     Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
   }
   }
 }
 }
 
 
 /*
 /*
- * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
- * that will be freed before the allocated string is stored there.
+ * strstore
  *
  *
- * It is meant to easily replace strdup()
+ * A thin wrapper around strdup which ensures that any memory allocated at
+ * *str will be freed before the string allocated by strdup is stored there.
+ * The intended usecase is repeated assignments to the same variable during
+ * parsing in a last-wins scenario. The caller is responsible for checking
+ * for OOM errors.
  */
  */
 static void strstore(char **str, const char *newstr)
 static void strstore(char **str, const char *newstr)
 {
 {
@@ -384,7 +393,11 @@ static void strstore(char **str, const char *newstr)
 }
 }
 
 
 /*
 /*
- * remove_expired() removes expired cookies.
+ * remove_expired
+ *
+ * Remove expired cookies from the hash by inspecting the expires timestamp on
+ * each cookie in the hash, freeing and deleting any where the timestamp is in
+ * the past.
  */
  */
 static void remove_expired(struct CookieInfo *cookies)
 static void remove_expired(struct CookieInfo *cookies)
 {
 {
@@ -421,25 +434,23 @@ static bool bad_domain(const char *domain)
   return !strchr(domain, '.') && !strcasecompare(domain, "localhost");
   return !strchr(domain, '.') && !strcasecompare(domain, "localhost");
 }
 }
 
 
-/****************************************************************************
- *
- * Curl_cookie_add()
- *
- * Add a single cookie line to the cookie keeping object.
+/*
+ * Curl_cookie_add
  *
  *
- * Be aware that sometimes we get an IP-only host name, and that might also be
- * a numerical IPv6 address.
+ * Add a single cookie line to the cookie keeping object. Be aware that
+ * sometimes we get an IP-only host name, and that might also be a numerical
+ * IPv6 address.
  *
  *
  * Returns NULL on out of memory or invalid cookie. This is suboptimal,
  * Returns NULL on out of memory or invalid cookie. This is suboptimal,
  * as they should be treated separately.
  * as they should be treated separately.
- ***************************************************************************/
-
+ */
 struct Cookie *
 struct Cookie *
 Curl_cookie_add(struct Curl_easy *data,
 Curl_cookie_add(struct Curl_easy *data,
-                /* The 'data' pointer here may be NULL at times, and thus
-                   must only be used very carefully for things that can deal
-                   with data being NULL. Such as infof() and similar */
-
+                /*
+                 * The 'data' pointer here may be NULL at times, and thus
+                 * must only be used very carefully for things that can deal
+                 * with data being NULL. Such as infof() and similar
+                 */
                 struct CookieInfo *c,
                 struct CookieInfo *c,
                 bool httpheader, /* TRUE if HTTP header-style line */
                 bool httpheader, /* TRUE if HTTP header-style line */
                 bool noexpire, /* if TRUE, skip remove_expired() */
                 bool noexpire, /* if TRUE, skip remove_expired() */
@@ -493,9 +504,11 @@ Curl_cookie_add(struct Curl_easy *data,
       if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
       if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n=] =%"
                      MAX_NAME_TXT "[^;\r\n]",
                      MAX_NAME_TXT "[^;\r\n]",
                      name, what)) {
                      name, what)) {
-        /* Use strstore() below to properly deal with received cookie
-           headers that have the same string property set more than once,
-           and then we use the last one. */
+        /*
+         * Use strstore() below to properly deal with received cookie
+         * headers that have the same string property set more than once,
+         * and then we use the last one.
+         */
         const char *whatptr;
         const char *whatptr;
         bool done = FALSE;
         bool done = FALSE;
         bool sep;
         bool sep;
@@ -503,11 +516,13 @@ Curl_cookie_add(struct Curl_easy *data,
         size_t nlen = strlen(name);
         size_t nlen = strlen(name);
         const char *endofn = &ptr[ nlen ];
         const char *endofn = &ptr[ nlen ];
 
 
+        /*
+         * Check for too long individual name or contents, or too long
+         * combination of name + contents. Chrome and Firefox support 4095 or
+         * 4096 bytes combo
+         */
         if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
         if(nlen >= (MAX_NAME-1) || len >= (MAX_NAME-1) ||
            ((nlen + len) > MAX_NAME)) {
            ((nlen + len) > MAX_NAME)) {
-          /* too long individual name or contents, or too long combination of
-             name + contents. Chrome and Firefox support 4095 or 4096 bytes
-             combo. */
           freecookie(co);
           freecookie(co);
           infof(data, "oversized cookie dropped, name/val %zu + %zu bytes\n",
           infof(data, "oversized cookie dropped, name/val %zu + %zu bytes\n",
                 nlen, len);
                 nlen, len);
@@ -569,8 +584,10 @@ Curl_cookie_add(struct Curl_easy *data,
           }
           }
         }
         }
         else if(!len) {
         else if(!len) {
-          /* this was a "<name>=" with no content, and we must allow
-             'secure' and 'httponly' specified this weirdly */
+          /*
+           * this was a "<name>=" with no content, and we must allow
+           * 'secure' and 'httponly' specified this weirdly
+           */
           done = TRUE;
           done = TRUE;
           /*
           /*
            * secure cookies are only allowed to be set when the connection is
            * secure cookies are only allowed to be set when the connection is
@@ -610,8 +627,10 @@ Curl_cookie_add(struct Curl_easy *data,
         else if(strcasecompare("domain", name)) {
         else if(strcasecompare("domain", name)) {
           bool is_ip;
           bool is_ip;
 
 
-          /* Now, we make sure that our host is within the given domain,
-             or the given domain is not valid and thus cannot be set. */
+          /*
+           * Now, we make sure that our host is within the given domain, or
+           * the given domain is not valid and thus cannot be set.
+           */
 
 
           if('.' == whatptr[0])
           if('.' == whatptr[0])
             whatptr++; /* ignore preceding dot */
             whatptr++; /* ignore preceding dot */
@@ -641,9 +660,10 @@ Curl_cookie_add(struct Curl_easy *data,
                                        given */
                                        given */
           }
           }
           else {
           else {
-            /* we did not get a tailmatch and then the attempted set domain
-               is not a domain to which the current host belongs. Mark as
-               bad. */
+            /*
+             * We did not get a tailmatch and then the attempted set domain is
+             * not a domain to which the current host belongs. Mark as bad.
+             */
             badcookie = TRUE;
             badcookie = TRUE;
             infof(data, "skipped cookie with bad tailmatch domain: %s\n",
             infof(data, "skipped cookie with bad tailmatch domain: %s\n",
                   whatptr);
                   whatptr);
@@ -657,15 +677,15 @@ Curl_cookie_add(struct Curl_easy *data,
           }
           }
         }
         }
         else if(strcasecompare("max-age", name)) {
         else if(strcasecompare("max-age", name)) {
-          /* Defined in RFC2109:
-
-             Optional.  The Max-Age attribute defines the lifetime of the
-             cookie, in seconds.  The delta-seconds value is a decimal non-
-             negative integer.  After delta-seconds seconds elapse, the
-             client should discard the cookie.  A value of zero means the
-             cookie should be discarded immediately.
-
-          */
+          /*
+           * Defined in RFC2109:
+           *
+           * Optional.  The Max-Age attribute defines the lifetime of the
+           * cookie, in seconds.  The delta-seconds value is a decimal non-
+           * negative integer.  After delta-seconds seconds elapse, the
+           * client should discard the cookie.  A value of zero means the
+           * cookie should be discarded immediately.
+           */
           strstore(&co->maxage, whatptr);
           strstore(&co->maxage, whatptr);
           if(!co->maxage) {
           if(!co->maxage) {
             badcookie = TRUE;
             badcookie = TRUE;
@@ -679,9 +699,10 @@ Curl_cookie_add(struct Curl_easy *data,
             break;
             break;
           }
           }
         }
         }
+
         /*
         /*
-          else this is the second (or more) name we don't know
-          about! */
+         * Else, this is the second (or more) name we don't know about!
+         */
       }
       }
       else {
       else {
         /* this is an "illegal" <what>=<this> pair */
         /* this is an "illegal" <what>=<this> pair */
@@ -699,8 +720,10 @@ Curl_cookie_add(struct Curl_easy *data,
       semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
       semiptr = strchr(ptr, ';'); /* now, find the next semicolon */
 
 
       if(!semiptr && *ptr)
       if(!semiptr && *ptr)
-        /* There are no more semicolons, but there's a final name=value pair
-           coming up */
+        /*
+         * There are no more semicolons, but there's a final name=value pair
+         * coming up
+         */
         semiptr = strchr(ptr, '\0');
         semiptr = strchr(ptr, '\0');
     } while(semiptr);
     } while(semiptr);
 
 
@@ -724,13 +747,16 @@ Curl_cookie_add(struct Curl_easy *data,
       }
       }
     }
     }
     else if(co->expirestr) {
     else if(co->expirestr) {
-      /* Note that if the date couldn't get parsed for whatever reason,
-         the cookie will be treated as a session cookie */
+      /*
+       * Note that if the date couldn't get parsed for whatever reason, the
+       * cookie will be treated as a session cookie
+       */
       co->expires = Curl_getdate_capped(co->expirestr);
       co->expires = Curl_getdate_capped(co->expirestr);
 
 
-      /* Session cookies have expires set to 0 so if we get that back
-         from the date parser let's add a second to make it a
-         non-session cookie */
+      /*
+       * Session cookies have expires set to 0 so if we get that back from the
+       * date parser let's add a second to make it a non-session cookie
+       */
       if(co->expires == 0)
       if(co->expires == 0)
         co->expires = 1;
         co->expires = 1;
       else if(co->expires < 0)
       else if(co->expires < 0)
@@ -747,13 +773,17 @@ Curl_cookie_add(struct Curl_easy *data,
     }
     }
 
 
     if(!badcookie && !co->path && path) {
     if(!badcookie && !co->path && path) {
-      /* No path was given in the header line, set the default.
-         Note that the passed-in path to this function MAY have a '?' and
-         following part that MUST not be stored as part of the path. */
+      /*
+       * No path was given in the header line, set the default.  Note that the
+       * passed-in path to this function MAY have a '?' and following part that
+       * MUST NOT be stored as part of the path.
+       */
       char *queryp = strchr(path, '?');
       char *queryp = strchr(path, '?');
 
 
-      /* queryp is where the interesting part of the path ends, so now we
-         want to the find the last */
+      /*
+       * queryp is where the interesting part of the path ends, so now we
+       * want to the find the last
+       */
       char *endslash;
       char *endslash;
       if(!queryp)
       if(!queryp)
         endslash = strrchr(path, '/');
         endslash = strrchr(path, '/');
@@ -774,29 +804,34 @@ Curl_cookie_add(struct Curl_easy *data,
       }
       }
     }
     }
 
 
+    /*
+     * If we didn't get a cookie name, or a bad one, the this is an illegal
+     * line so bail out.
+     */
     if(badcookie || !co->name) {
     if(badcookie || !co->name) {
-      /* we didn't get a cookie name or a bad one,
-         this is an illegal line, bail out */
       freecookie(co);
       freecookie(co);
       return NULL;
       return NULL;
     }
     }
 
 
   }
   }
   else {
   else {
-    /* This line is NOT a HTTP header style line, we do offer support for
-       reading the odd netscape cookies-file format here */
+    /*
+     * This line is NOT a HTTP header style line, we do offer support for
+     * reading the odd netscape cookies-file format here
+     */
     char *ptr;
     char *ptr;
     char *firstptr;
     char *firstptr;
     char *tok_buf = NULL;
     char *tok_buf = NULL;
     int fields;
     int fields;
 
 
-    /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
-       marked with httpOnly after the domain name are not accessible
-       from javascripts, but since curl does not operate at javascript
-       level, we include them anyway. In Firefox's cookie files, these
-       lines are preceded with #HttpOnly_ and then everything is
-       as usual, so we skip 10 characters of the line..
-    */
+    /*
+     * IE introduced HTTP-only cookies to prevent XSS attacks. Cookies marked
+     * with httpOnly after the domain name are not accessible from javascripts,
+     * but since curl does not operate at javascript level, we include them
+     * anyway. In Firefox's cookie files, these lines are preceded with
+     * #HttpOnly_ and then everything is as usual, so we skip 10 characters of
+     * the line..
+     */
     if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
     if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
       lineptr += 10;
       lineptr += 10;
       co->httponly = TRUE;
       co->httponly = TRUE;
@@ -817,8 +852,10 @@ Curl_cookie_add(struct Curl_easy *data,
 
 
     firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
     firstptr = strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
 
 
-    /* Now loop through the fields and init the struct we already have
-       allocated */
+    /*
+     * Now loop through the fields and init the struct we already have
+     * allocated
+     */
     for(ptr = firstptr, fields = 0; ptr && !badcookie;
     for(ptr = firstptr, fields = 0; ptr && !badcookie;
         ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
         ptr = strtok_r(NULL, "\t", &tok_buf), fields++) {
       switch(fields) {
       switch(fields) {
@@ -830,10 +867,11 @@ Curl_cookie_add(struct Curl_easy *data,
           badcookie = TRUE;
           badcookie = TRUE;
         break;
         break;
       case 1:
       case 1:
-        /* flag: A TRUE/FALSE value indicating if all machines within a given
-           domain can access the variable. Set TRUE when the cookie says
-           .domain.com and to false when the domain is complete www.domain.com
-        */
+        /*
+         * flag: A TRUE/FALSE value indicating if all machines within a given
+         * domain can access the variable. Set TRUE when the cookie says
+         * .domain.com and to false when the domain is complete www.domain.com
+         */
         co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
         co->tailmatch = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
         break;
         break;
       case 2:
       case 2:
@@ -942,17 +980,23 @@ Curl_cookie_add(struct Curl_easy *data,
   co->livecookie = c->running;
   co->livecookie = c->running;
   co->creationtime = ++c->lastct;
   co->creationtime = ++c->lastct;
 
 
-  /* now, we have parsed the incoming line, we must now check if this
-     supersedes an already existing cookie, which it may if the previous have
-     the same domain and path as this */
+  /*
+   * Now we have parsed the incoming line, we must now check if this supersedes
+   * an already existing cookie, which it may if the previous have the same
+   * domain and path as this.
+   */
 
 
   /* at first, remove expired cookies */
   /* at first, remove expired cookies */
   if(!noexpire)
   if(!noexpire)
     remove_expired(c);
     remove_expired(c);
 
 
 #ifdef USE_LIBPSL
 #ifdef USE_LIBPSL
-  /* Check if the domain is a Public Suffix and if yes, ignore the cookie. */
-  if(domain && co->domain && !isip(co->domain)) {
+  /*
+   * Check if the domain is a Public Suffix and if yes, ignore the cookie. We
+   * must also check that the data handle isn't NULL since the psl code will
+   * dereference it.
+   */
+  if(data && (domain && co->domain && !isip(co->domain))) {
     const psl_ctx_t *psl = Curl_psl_use(data);
     const psl_ctx_t *psl = Curl_psl_use(data);
     int acceptable;
     int acceptable;
 
 
@@ -1028,12 +1072,12 @@ Curl_cookie_add(struct Curl_easy *data,
       }
       }
 
 
       if(replace_old && !co->livecookie && clist->livecookie) {
       if(replace_old && !co->livecookie && clist->livecookie) {
-        /* Both cookies matched fine, except that the already present
-           cookie is "live", which means it was set from a header, while
-           the new one isn't "live" and thus only read from a file. We let
-           live cookies stay alive */
-
-        /* Free the newcomer and get out of here! */
+        /*
+         * Both cookies matched fine, except that the already present cookie is
+         * "live", which means it was set from a header, while the new one was
+         * read from a file and thus isn't "live". "live" cookies are preferred
+         * so the new cookie is freed.
+         */
         freecookie(co);
         freecookie(co);
         return NULL;
         return NULL;
       }
       }
@@ -1059,8 +1103,10 @@ Curl_cookie_add(struct Curl_easy *data,
         free(co);   /* free the newly allocated memory */
         free(co);   /* free the newly allocated memory */
         co = clist; /* point to the previous struct instead */
         co = clist; /* point to the previous struct instead */
 
 
-        /* We have replaced a cookie, now skip the rest of the list but
-           make sure the 'lastc' pointer is properly set */
+        /*
+         * We have replaced a cookie, now skip the rest of the list but make
+         * sure the 'lastc' pointer is properly set
+         */
         do {
         do {
           lastc = clist;
           lastc = clist;
           clist = clist->next;
           clist = clist->next;
@@ -1092,19 +1138,19 @@ Curl_cookie_add(struct Curl_easy *data,
 }
 }
 
 
 
 
-/*****************************************************************************
- *
+/*
  * Curl_cookie_init()
  * Curl_cookie_init()
  *
  *
  * Inits a cookie struct to read data from a local file. This is always
  * Inits a cookie struct to read data from a local file. This is always
- * called before any cookies are set. File may be NULL.
+ * called before any cookies are set. File may be NULL in which case only the
+ * struct is initialized. Is file is "-" then STDIN is read.
  *
  *
  * If 'newsession' is TRUE, discard all "session cookies" on read from file.
  * If 'newsession' is TRUE, discard all "session cookies" on read from file.
  *
  *
  * Note that 'data' might be called as NULL pointer.
  * Note that 'data' might be called as NULL pointer.
  *
  *
  * Returns NULL on out of memory. Invalid cookies are ignored.
  * Returns NULL on out of memory. Invalid cookies are ignored.
- ****************************************************************************/
+ */
 struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
 struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
                                     const char *file,
                                     const char *file,
                                     struct CookieInfo *inc,
                                     struct CookieInfo *inc,
@@ -1166,7 +1212,12 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
       Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
       Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
     }
     }
     free(line); /* free the line buffer */
     free(line); /* free the line buffer */
-    remove_expired(c); /* run this once, not on every cookie */
+
+    /*
+     * Remove expired cookies from the hash. We must make sure to run this
+     * after reading the file, and not not on every cookie.
+     */
+    remove_expired(c);
 
 
     if(fromfile)
     if(fromfile)
       fclose(fp);
       fclose(fp);
@@ -1180,16 +1231,24 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
 
 
 fail:
 fail:
   free(line);
   free(line);
+  /*
+   * Only clean up if we allocated it here, as the original could still be in
+   * use by a share handle.
+   */
   if(!inc)
   if(!inc)
-    /* Only clean up if we allocated it here, as the original could still be in
-     * use by a share handle */
     Curl_cookie_cleanup(c);
     Curl_cookie_cleanup(c);
   if(fromfile && fp)
   if(fromfile && fp)
     fclose(fp);
     fclose(fp);
   return NULL; /* out of memory */
   return NULL; /* out of memory */
 }
 }
 
 
-/* sort this so that the longest path gets before the shorter path */
+/*
+ * cookie_sort
+ *
+ * Helper function to sort cookies such that the longest path gets before the
+ * shorter path. Path, domain and name lengths are considered in that order,
+ * with tge creationtime as the tiebreaker.
+ */
 static int cookie_sort(const void *p1, const void *p2)
 static int cookie_sort(const void *p1, const void *p2)
 {
 {
   struct Cookie *c1 = *(struct Cookie **)p1;
   struct Cookie *c1 = *(struct Cookie **)p1;
@@ -1221,7 +1280,11 @@ static int cookie_sort(const void *p1, const void *p2)
   return (c2->creationtime > c1->creationtime) ? 1 : -1;
   return (c2->creationtime > c1->creationtime) ? 1 : -1;
 }
 }
 
 
-/* sort cookies only according to creation time */
+/*
+ * cookie_sort_ct
+ *
+ * Helper function to sort cookies according to creation time.
+ */
 static int cookie_sort_ct(const void *p1, const void *p2)
 static int cookie_sort_ct(const void *p1, const void *p2)
 {
 {
   struct Cookie *c1 = *(struct Cookie **)p1;
   struct Cookie *c1 = *(struct Cookie **)p1;
@@ -1265,18 +1328,15 @@ static struct Cookie *dup_cookie(struct Cookie *src)
   return NULL;
   return NULL;
 }
 }
 
 
-/*****************************************************************************
- *
- * Curl_cookie_getlist()
+/*
+ * Curl_cookie_getlist
  *
  *
- * For a given host and path, return a linked list of cookies that the
- * client should send to the server if used now. The secure boolean informs
- * the cookie if a secure connection is achieved or not.
+ * For a given host and path, return a linked list of cookies that the client
+ * should send to the server if used now. The secure boolean informs the cookie
+ * if a secure connection is achieved or not.
  *
  *
  * It shall only return cookies that haven't expired.
  * It shall only return cookies that haven't expired.
- *
- ****************************************************************************/
-
+ */
 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
 struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
                                    const char *host, const char *path,
                                    const char *host, const char *path,
                                    bool secure)
                                    bool secure)
@@ -1307,15 +1367,21 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
       if(!co->domain ||
       if(!co->domain ||
          (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
          (co->tailmatch && !is_ip && tailmatch(co->domain, host)) ||
          ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
          ((!co->tailmatch || is_ip) && strcasecompare(host, co->domain)) ) {
-        /* the right part of the host matches the domain stuff in the
-           cookie data */
+        /*
+         * the right part of the host matches the domain stuff in the
+         * cookie data
+         */
 
 
-        /* now check the left part of the path with the cookies path
-           requirement */
+        /*
+         * now check the left part of the path with the cookies path
+         * requirement
+         */
         if(!co->spath || pathmatch(co->spath, path) ) {
         if(!co->spath || pathmatch(co->spath, path) ) {
 
 
-          /* and now, we know this is a match and we should create an
-             entry for the return-linked-list */
+          /*
+           * and now, we know this is a match and we should create an
+           * entry for the return-linked-list
+           */
 
 
           newco = dup_cookie(co);
           newco = dup_cookie(co);
           if(newco) {
           if(newco) {
@@ -1336,9 +1402,11 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
   }
   }
 
 
   if(matches) {
   if(matches) {
-    /* Now we need to make sure that if there is a name appearing more than
-       once, the longest specified path version comes first. To make this
-       the swiftest way, we just sort them all based on path length. */
+    /*
+     * Now we need to make sure that if there is a name appearing more than
+     * once, the longest specified path version comes first. To make this
+     * the swiftest way, we just sort them all based on path length.
+     */
     struct Cookie **array;
     struct Cookie **array;
     size_t i;
     size_t i;
 
 
@@ -1373,13 +1441,11 @@ fail:
   return NULL;
   return NULL;
 }
 }
 
 
-/*****************************************************************************
- *
- * Curl_cookie_clearall()
+/*
+ * Curl_cookie_clearall
  *
  *
  * Clear all existing cookies and reset the counter.
  * Clear all existing cookies and reset the counter.
- *
- ****************************************************************************/
+ */
 void Curl_cookie_clearall(struct CookieInfo *cookies)
 void Curl_cookie_clearall(struct CookieInfo *cookies)
 {
 {
   if(cookies) {
   if(cookies) {
@@ -1392,14 +1458,11 @@ void Curl_cookie_clearall(struct CookieInfo *cookies)
   }
   }
 }
 }
 
 
-/*****************************************************************************
- *
- * Curl_cookie_freelist()
+/*
+ * Curl_cookie_freelist
  *
  *
  * Free a list of cookies previously returned by Curl_cookie_getlist();
  * Free a list of cookies previously returned by Curl_cookie_getlist();
- *
- ****************************************************************************/
-
+ */
 void Curl_cookie_freelist(struct Cookie *co)
 void Curl_cookie_freelist(struct Cookie *co)
 {
 {
   struct Cookie *next;
   struct Cookie *next;
@@ -1410,14 +1473,11 @@ void Curl_cookie_freelist(struct Cookie *co)
   }
   }
 }
 }
 
 
-
-/*****************************************************************************
- *
- * Curl_cookie_clearsess()
+/*
+ * Curl_cookie_clearsess
  *
  *
  * Free all session cookies in the cookies list.
  * Free all session cookies in the cookies list.
- *
- ****************************************************************************/
+ */
 void Curl_cookie_clearsess(struct CookieInfo *cookies)
 void Curl_cookie_clearsess(struct CookieInfo *cookies)
 {
 {
   struct Cookie *first, *curr, *next, *prev = NULL;
   struct Cookie *first, *curr, *next, *prev = NULL;
@@ -1454,14 +1514,11 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies)
   }
   }
 }
 }
 
 
-
-/*****************************************************************************
- *
+/*
  * Curl_cookie_cleanup()
  * Curl_cookie_cleanup()
  *
  *
  * Free a "cookie object" previous created with Curl_cookie_init().
  * Free a "cookie object" previous created with Curl_cookie_init().
- *
- ****************************************************************************/
+ */
 void Curl_cookie_cleanup(struct CookieInfo *c)
 void Curl_cookie_cleanup(struct CookieInfo *c)
 {
 {
   if(c) {
   if(c) {
@@ -1473,12 +1530,13 @@ void Curl_cookie_cleanup(struct CookieInfo *c)
   }
   }
 }
 }
 
 
-/* get_netscape_format()
+/*
+ * get_netscape_format()
  *
  *
  * Formats a string for Netscape output file, w/o a newline at the end.
  * Formats a string for Netscape output file, w/o a newline at the end.
- *
- * Function returns a char * to a formatted line. Has to be free()d
-*/
+ * Function returns a char * to a formatted line. The caller is responsible
+ * for freeing the returned pointer.
+ */
 static char *get_netscape_format(const struct Cookie *co)
 static char *get_netscape_format(const struct Cookie *co)
 {
 {
   return aprintf(
   return aprintf(
@@ -1491,8 +1549,10 @@ static char *get_netscape_format(const struct Cookie *co)
     "%s\t"   /* name */
     "%s\t"   /* name */
     "%s",    /* value */
     "%s",    /* value */
     co->httponly?"#HttpOnly_":"",
     co->httponly?"#HttpOnly_":"",
-    /* Make sure all domains are prefixed with a dot if they allow
-       tailmatching. This is Mozilla-style. */
+    /*
+     * Make sure all domains are prefixed with a dot if they allow
+     * tailmatching. This is Mozilla-style.
+     */
     (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
     (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
     co->domain?co->domain:"unknown",
     co->domain?co->domain:"unknown",
     co->tailmatch?"TRUE":"FALSE",
     co->tailmatch?"TRUE":"FALSE",
@@ -1511,18 +1571,18 @@ static char *get_netscape_format(const struct Cookie *co)
  *
  *
  * The function returns non-zero on write failure.
  * The function returns non-zero on write failure.
  */
  */
-static int cookie_output(struct Curl_easy *data,
-                         struct CookieInfo *c, const char *filename)
+static CURLcode cookie_output(struct Curl_easy *data,
+                              struct CookieInfo *c, const char *filename)
 {
 {
   struct Cookie *co;
   struct Cookie *co;
   FILE *out = NULL;
   FILE *out = NULL;
   bool use_stdout = FALSE;
   bool use_stdout = FALSE;
   char *tempstore = NULL;
   char *tempstore = NULL;
-  bool error = false;
+  CURLcode error = CURLE_OK;
 
 
   if(!c)
   if(!c)
     /* no cookie engine alive */
     /* no cookie engine alive */
-    return 0;
+    return CURLE_OK;
 
 
   /* at first, remove expired cookies */
   /* at first, remove expired cookies */
   remove_expired(c);
   remove_expired(c);
@@ -1540,11 +1600,13 @@ static int cookie_output(struct Curl_easy *data,
 
 
     tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
     tempstore = aprintf("%s.%s.tmp", filename, randsuffix);
     if(!tempstore)
     if(!tempstore)
-      return 1;
+      return CURLE_OUT_OF_MEMORY;
 
 
     out = fopen(tempstore, FOPEN_WRITETEXT);
     out = fopen(tempstore, FOPEN_WRITETEXT);
-    if(!out)
+    if(!out) {
+      error = CURLE_WRITE_ERROR;
       goto error;
       goto error;
+    }
   }
   }
 
 
   fputs("# Netscape HTTP Cookie File\n"
   fputs("# Netscape HTTP Cookie File\n"
@@ -1559,6 +1621,7 @@ static int cookie_output(struct Curl_easy *data,
 
 
     array = calloc(1, sizeof(struct Cookie *) * c->numcookies);
     array = calloc(1, sizeof(struct Cookie *) * c->numcookies);
     if(!array) {
     if(!array) {
+      error = CURLE_OUT_OF_MEMORY;
       goto error;
       goto error;
     }
     }
 
 
@@ -1575,9 +1638,9 @@ static int cookie_output(struct Curl_easy *data,
 
 
     for(i = 0; i < nvalid; i++) {
     for(i = 0; i < nvalid; i++) {
       char *format_ptr = get_netscape_format(array[i]);
       char *format_ptr = get_netscape_format(array[i]);
-      if(format_ptr == NULL) {
-        fprintf(out, "#\n# Fatal libcurl error\n");
+      if(!format_ptr) {
         free(array);
         free(array);
+        error = CURLE_OUT_OF_MEMORY;
         goto error;
         goto error;
       }
       }
       fprintf(out, "%s\n", format_ptr);
       fprintf(out, "%s\n", format_ptr);
@@ -1592,18 +1655,24 @@ static int cookie_output(struct Curl_easy *data,
     out = NULL;
     out = NULL;
     if(Curl_rename(tempstore, filename)) {
     if(Curl_rename(tempstore, filename)) {
       unlink(tempstore);
       unlink(tempstore);
+      error = CURLE_WRITE_ERROR;
       goto error;
       goto error;
     }
     }
   }
   }
 
 
-  goto cleanup;
+  /*
+   * If we reach here we have successfully written a cookie file so theree is
+   * no need to inspect the error, any error case should have jumped into the
+   * error block below.
+   */
+  free(tempstore);
+  return CURLE_OK;
+
 error:
 error:
-  error = true;
-cleanup:
   if(out && !use_stdout)
   if(out && !use_stdout)
     fclose(out);
     fclose(out);
   free(tempstore);
   free(tempstore);
-  return error ? 1 : 0;
+  return error;
 }
 }
 
 
 static struct curl_slist *cookie_list(struct Curl_easy *data)
 static struct curl_slist *cookie_list(struct Curl_easy *data)
@@ -1614,8 +1683,7 @@ static struct curl_slist *cookie_list(struct Curl_easy *data)
   char *line;
   char *line;
   unsigned int i;
   unsigned int i;
 
 
-  if((data->cookies == NULL) ||
-      (data->cookies->numcookies == 0))
+  if(!data->cookies || (data->cookies->numcookies == 0))
     return NULL;
     return NULL;
 
 
   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
   for(i = 0; i < COOKIE_HASH_SIZE; i++) {
@@ -1651,8 +1719,10 @@ struct curl_slist *Curl_cookie_list(struct Curl_easy *data)
 
 
 void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
 void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
 {
 {
+  CURLcode res;
+
   if(data->set.str[STRING_COOKIEJAR]) {
   if(data->set.str[STRING_COOKIEJAR]) {
-    if(data->change.cookielist) {
+    if(data->state.cookielist) {
       /* If there is a list of cookie files to read, do it first so that
       /* If there is a list of cookie files to read, do it first so that
          we have all the told files read before we write the new jar.
          we have all the told files read before we write the new jar.
          Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
          Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
@@ -1662,16 +1732,17 @@ void Curl_flush_cookies(struct Curl_easy *data, bool cleanup)
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
 
 
     /* if we have a destination file for all the cookies to get dumped to */
     /* if we have a destination file for all the cookies to get dumped to */
-    if(cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]))
-      infof(data, "WARNING: failed to save cookies in %s\n",
-            data->set.str[STRING_COOKIEJAR]);
+    res = cookie_output(data, data->cookies, data->set.str[STRING_COOKIEJAR]);
+    if(res)
+      infof(data, "WARNING: failed to save cookies in %s: %s\n",
+            data->set.str[STRING_COOKIEJAR], curl_easy_strerror(res));
   }
   }
   else {
   else {
-    if(cleanup && data->change.cookielist) {
+    if(cleanup && data->state.cookielist) {
       /* since nothing is written, we can just free the list of cookie file
       /* since nothing is written, we can just free the list of cookie file
          names */
          names */
-      curl_slist_free_all(data->change.cookielist); /* clean up list */
-      data->change.cookielist = NULL;
+      curl_slist_free_all(data->state.cookielist); /* clean up list */
+      data->state.cookielist = NULL;
     }
     }
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
   }
   }

+ 7 - 6
lib/cookie.h

@@ -91,13 +91,13 @@ struct Curl_easy;
  */
  */
 
 
 struct Cookie *Curl_cookie_add(struct Curl_easy *data,
 struct Cookie *Curl_cookie_add(struct Curl_easy *data,
-                               struct CookieInfo *, bool header, bool noexpiry,
-                               char *lineptr,
+                               struct CookieInfo *c, bool header,
+                               bool noexpiry, char *lineptr,
                                const char *domain, const char *path,
                                const char *domain, const char *path,
                                bool secure);
                                bool secure);
 
 
-struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
-                                   const char *, bool);
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, const char *host,
+                                   const char *path, bool secure);
 void Curl_cookie_freelist(struct Cookie *cookies);
 void Curl_cookie_freelist(struct Cookie *cookies);
 void Curl_cookie_clearall(struct CookieInfo *cookies);
 void Curl_cookie_clearall(struct CookieInfo *cookies);
 void Curl_cookie_clearsess(struct CookieInfo *cookies);
 void Curl_cookie_clearsess(struct CookieInfo *cookies);
@@ -110,9 +110,10 @@ void Curl_cookie_clearsess(struct CookieInfo *cookies);
 #define Curl_flush_cookies(x,y) Curl_nop_stmt
 #define Curl_flush_cookies(x,y) Curl_nop_stmt
 #else
 #else
 void Curl_flush_cookies(struct Curl_easy *data, bool cleanup);
 void Curl_flush_cookies(struct Curl_easy *data, bool cleanup);
-void Curl_cookie_cleanup(struct CookieInfo *);
+void Curl_cookie_cleanup(struct CookieInfo *c);
 struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
 struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
-                                    const char *, struct CookieInfo *, bool);
+                                    const char *file, struct CookieInfo *inc,
+                                    bool newsession);
 struct curl_slist *Curl_cookie_list(struct Curl_easy *data);
 struct curl_slist *Curl_cookie_list(struct Curl_easy *data);
 void Curl_cookie_loadfiles(struct Curl_easy *data);
 void Curl_cookie_loadfiles(struct Curl_easy *data);
 #endif
 #endif

+ 7 - 1
lib/curl_addrinfo.c

@@ -50,6 +50,12 @@
 #  define in_addr_t unsigned long
 #  define in_addr_t unsigned long
 #endif
 #endif
 
 
+#if defined(USE_UNIX_SOCKETS) && defined(WINAPI_FAMILY) && \
+    (WINAPI_FAMILY == WINAPI_FAMILY_APP)
+   /* Required for sockaddr_un type */
+#  include <afunix.h>
+#endif
+
 #include <stddef.h>
 #include <stddef.h>
 
 
 #include "curl_addrinfo.h"
 #include "curl_addrinfo.h"
@@ -141,7 +147,7 @@ Curl_getaddrinfo_ex(const char *nodename,
       continue;
       continue;
 
 
     /* ignore elements without required address info */
     /* ignore elements without required address info */
-    if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0))
+    if(!ai->ai_addr || !(ai->ai_addrlen > 0))
       continue;
       continue;
 
 
     /* ignore elements with bogus address size */
     /* ignore elements with bogus address size */

+ 19 - 46
lib/curl_config.h.cmake

@@ -98,7 +98,7 @@
 #endif
 #endif
 
 
 /* Allow SMB to work on Windows */
 /* Allow SMB to work on Windows */
-#cmakedefine USE_WIN32_CRYPTO
+#cmakedefine USE_WIN32_CRYPTO 1
 
 
 /* Use Windows LDAP implementation */
 /* Use Windows LDAP implementation */
 #cmakedefine USE_WIN32_LDAP 1
 #cmakedefine USE_WIN32_LDAP 1
@@ -112,21 +112,6 @@
 /* Define if you want to enable IPv6 support */
 /* Define if you want to enable IPv6 support */
 #cmakedefine ENABLE_IPV6 1
 #cmakedefine ENABLE_IPV6 1
 
 
-/* Define to the type qualifier of arg 1 for getnameinfo. */
-#cmakedefine GETNAMEINFO_QUAL_ARG1 ${GETNAMEINFO_QUAL_ARG1}
-
-/* Define to the type of arg 1 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG1 ${GETNAMEINFO_TYPE_ARG1}
-
-/* Define to the type of arg 2 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG2 ${GETNAMEINFO_TYPE_ARG2}
-
-/* Define to the type of args 4 and 6 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG46 ${GETNAMEINFO_TYPE_ARG46}
-
-/* Define to the type of arg 7 for getnameinfo. */
-#cmakedefine GETNAMEINFO_TYPE_ARG7 ${GETNAMEINFO_TYPE_ARG7}
-
 /* Specifies the number of arguments to getservbyport_r */
 /* Specifies the number of arguments to getservbyport_r */
 #cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS}
 #cmakedefine GETSERVBYPORT_R_ARGS ${GETSERVBYPORT_R_ARGS}
 
 
@@ -208,6 +193,9 @@
 /* Define to 1 if you have the `geteuid' function. */
 /* Define to 1 if you have the `geteuid' function. */
 #cmakedefine HAVE_GETEUID 1
 #cmakedefine HAVE_GETEUID 1
 
 
+/* Define to 1 if you have the `getppid' function. */
+#cmakedefine HAVE_GETPPID 1
+
 /* Define to 1 if you have the gethostbyaddr function. */
 /* Define to 1 if you have the gethostbyaddr function. */
 #cmakedefine HAVE_GETHOSTBYADDR 1
 #cmakedefine HAVE_GETHOSTBYADDR 1
 
 
@@ -244,9 +232,6 @@
 /* Define to 1 if you have a working getifaddrs function. */
 /* Define to 1 if you have a working getifaddrs function. */
 #cmakedefine HAVE_GETIFADDRS 1
 #cmakedefine HAVE_GETIFADDRS 1
 
 
-/* Define to 1 if you have the getnameinfo function. */
-#cmakedefine HAVE_GETNAMEINFO 1
-
 /* Define to 1 if you have the `getpass_r' function. */
 /* Define to 1 if you have the `getpass_r' function. */
 #cmakedefine HAVE_GETPASS_R 1
 #cmakedefine HAVE_GETPASS_R 1
 
 
@@ -322,21 +307,18 @@
 /* Define to 1 if you have the `inet_addr' function. */
 /* Define to 1 if you have the `inet_addr' function. */
 #cmakedefine HAVE_INET_ADDR 1
 #cmakedefine HAVE_INET_ADDR 1
 
 
-/* Define to 1 if you have the inet_ntoa_r function. */
-#cmakedefine HAVE_INET_NTOA_R 1
-
-/* inet_ntoa_r() takes 2 args */
-#cmakedefine HAVE_INET_NTOA_R_2 1
-
-/* inet_ntoa_r() takes 3 args */
-#cmakedefine HAVE_INET_NTOA_R_3 1
-
 /* Define to 1 if you have a IPv6 capable working inet_ntop function. */
 /* Define to 1 if you have a IPv6 capable working inet_ntop function. */
 #cmakedefine HAVE_INET_NTOP 1
 #cmakedefine HAVE_INET_NTOP 1
 
 
 /* Define to 1 if you have a IPv6 capable working inet_pton function. */
 /* Define to 1 if you have a IPv6 capable working inet_pton function. */
 #cmakedefine HAVE_INET_PTON 1
 #cmakedefine HAVE_INET_PTON 1
 
 
+/* Define to 1 if symbol `sa_family_t' exists */
+#cmakedefine HAVE_SA_FAMILY_T 1
+
+/* Define to 1 if symbol `ADDRESS_FAMILY' exists */
+#cmakedefine HAVE_ADDRESS_FAMILY 1
+
 /* Define to 1 if you have the <inttypes.h> header file. */
 /* Define to 1 if you have the <inttypes.h> header file. */
 #cmakedefine HAVE_INTTYPES_H 1
 #cmakedefine HAVE_INTTYPES_H 1
 
 
@@ -509,9 +491,6 @@
 /* Define to 1 if you have the <pem.h> header file. */
 /* Define to 1 if you have the <pem.h> header file. */
 #cmakedefine HAVE_PEM_H 1
 #cmakedefine HAVE_PEM_H 1
 
 
-/* Define to 1 if you have the `perror' function. */
-#cmakedefine HAVE_PERROR 1
-
 /* Define to 1 if you have the `pipe' function. */
 /* Define to 1 if you have the `pipe' function. */
 #cmakedefine HAVE_PIPE 1
 #cmakedefine HAVE_PIPE 1
 
 
@@ -653,15 +632,6 @@
 /* Define to 1 if you have the <string.h> header file. */
 /* Define to 1 if you have the <string.h> header file. */
 #cmakedefine HAVE_STRING_H 1
 #cmakedefine HAVE_STRING_H 1
 
 
-/* Define to 1 if you have the strlcat function. */
-#cmakedefine HAVE_STRLCAT 1
-
-/* Define to 1 if you have the `strlcpy' function. */
-#cmakedefine HAVE_STRLCPY 1
-
-/* Define to 1 if you have the strncasecmp function. */
-#cmakedefine HAVE_STRNCASECMP 1
-
 /* Define to 1 if you have the strncmpi function. */
 /* Define to 1 if you have the strncmpi function. */
 #cmakedefine HAVE_STRNCMPI 1
 #cmakedefine HAVE_STRNCMPI 1
 
 
@@ -752,6 +722,9 @@
 /* Define to 1 if you have the `utime' function. */
 /* Define to 1 if you have the `utime' function. */
 #cmakedefine HAVE_UTIME 1
 #cmakedefine HAVE_UTIME 1
 
 
+/* Define to 1 if you have the `utimes' function. */
+#cmakedefine HAVE_UTIMES 1
+
 /* Define to 1 if you have the <utime.h> header file. */
 /* Define to 1 if you have the <utime.h> header file. */
 #cmakedefine HAVE_UTIME_H 1
 #cmakedefine HAVE_UTIME_H 1
 
 
@@ -879,9 +852,6 @@
 /* Define to the function return type for recv. */
 /* Define to the function return type for recv. */
 #cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV}
 #cmakedefine RECV_TYPE_RETV ${RECV_TYPE_RETV}
 
 
-/* Define as the return type of signal handlers (`int' or `void'). */
-#cmakedefine RETSIGTYPE ${RETSIGTYPE}
-
 /* Define to the type qualifier of arg 5 for select. */
 /* Define to the type qualifier of arg 5 for select. */
 #cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5}
 #cmakedefine SELECT_QUAL_ARG5 ${SELECT_QUAL_ARG5}
 
 
@@ -963,9 +933,6 @@ ${SIZEOF_TIME_T_CODE}
 /* Define if you want to enable WIN32 threaded DNS lookup */
 /* Define if you want to enable WIN32 threaded DNS lookup */
 #cmakedefine USE_THREADS_WIN32 1
 #cmakedefine USE_THREADS_WIN32 1
 
 
-/* Define to disable non-blocking sockets. */
-#cmakedefine USE_BLOCKING_SOCKETS 1
-
 /* if GnuTLS is enabled */
 /* if GnuTLS is enabled */
 #cmakedefine USE_GNUTLS 1
 #cmakedefine USE_GNUTLS 1
 
 
@@ -1079,3 +1046,9 @@ ${SIZEOF_TIME_T_CODE}
 
 
 /* Define to 1 if you have the mach_absolute_time function. */
 /* Define to 1 if you have the mach_absolute_time function. */
 #cmakedefine HAVE_MACH_ABSOLUTE_TIME 1
 #cmakedefine HAVE_MACH_ABSOLUTE_TIME 1
+
+/* to enable Windows IDN */
+#cmakedefine USE_WIN32_IDN 1
+
+/* to make the compiler know the prototypes of Windows IDN APIs */
+#cmakedefine WANT_IDN_PROTOTYPES 1

+ 3 - 3
lib/curl_endian.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -81,7 +81,7 @@ unsigned short Curl_read16_be(const unsigned char *buf)
                           ((unsigned short)buf[1]));
                           ((unsigned short)buf[1]));
 }
 }
 
 
-#if (CURL_SIZEOF_CURL_OFF_T > 4)
+#if (SIZEOF_CURL_OFF_T > 4)
 /*
 /*
  * write32_le()
  * write32_le()
  *
  *
@@ -121,4 +121,4 @@ void Curl_write64_le(const __int64 value, unsigned char *buffer)
   write32_le((int)value, buffer);
   write32_le((int)value, buffer);
   write32_le((int)(value >> 32), buffer + 4);
   write32_le((int)(value >> 32), buffer + 4);
 }
 }
-#endif /* CURL_SIZEOF_CURL_OFF_T > 4 */
+#endif /* SIZEOF_CURL_OFF_T > 4 */

+ 2 - 2
lib/curl_endian.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -31,7 +31,7 @@ unsigned int Curl_read32_le(const unsigned char *buf);
 /* Converts a 16-bit integer from big endian */
 /* Converts a 16-bit integer from big endian */
 unsigned short Curl_read16_be(const unsigned char *buf);
 unsigned short Curl_read16_be(const unsigned char *buf);
 
 
-#if (CURL_SIZEOF_CURL_OFF_T > 4)
+#if (SIZEOF_CURL_OFF_T > 4)
 /* Converts a 64-bit integer to little endian */
 /* Converts a 64-bit integer to little endian */
 #if defined(HAVE_LONGLONG)
 #if defined(HAVE_LONGLONG)
 void Curl_write64_le(const long long value, unsigned char *buffer);
 void Curl_write64_le(const long long value, unsigned char *buffer);

+ 2 - 2
lib/curl_get_line.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -23,7 +23,7 @@
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
 #if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) ||  \
 #if !defined(CURL_DISABLE_COOKIES) || !defined(CURL_DISABLE_ALTSVC) ||  \
-  defined(USE_HSTS)
+  !defined(CURL_DISABLE_HSTS)
 
 
 #include "curl_get_line.h"
 #include "curl_get_line.h"
 #include "curl_memory.h"
 #include "curl_memory.h"

+ 1 - 1
lib/curl_gssapi.c

@@ -102,7 +102,7 @@ static size_t display_gss_error(OM_uint32 status, int type,
                        (char *)status_string.value);
                        (char *)status_string.value);
     }
     }
     gss_release_buffer(&min_stat, &status_string);
     gss_release_buffer(&min_stat, &status_string);
-  } while(!GSS_ERROR(maj_stat) && msg_ctx != 0);
+  } while(!GSS_ERROR(maj_stat) && msg_ctx);
 
 
   return len;
   return len;
 }
 }

+ 0 - 1
lib/curl_krb5.h

@@ -29,7 +29,6 @@ struct Curl_sec_client_mech {
   int (*auth)(void *, struct Curl_easy *data, struct connectdata *);
   int (*auth)(void *, struct Curl_easy *data, struct connectdata *);
   void (*end)(void *);
   void (*end)(void *);
   int (*check_prot)(void *, int);
   int (*check_prot)(void *, int);
-  int (*overhead)(void *, int, int);
   int (*encode)(void *, const void *, int, int, void **);
   int (*encode)(void *, const void *, int, int, void **);
   int (*decode)(void *, void *, int, int, struct connectdata *);
   int (*decode)(void *, void *, int, int, struct connectdata *);
 };
 };

+ 51 - 33
lib/curl_multibyte.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -21,7 +21,11 @@
  ***************************************************************************/
  ***************************************************************************/
 
 
 /*
 /*
- * This file is 'mem-include-scan' clean. See test 1132.
+ * This file is 'mem-include-scan' clean, which means memdebug.h and
+ * curl_memory.h are purposely not included in this file. See test 1132.
+ *
+ * The functions in this file are curlx functions which are not tracked by the
+ * curl memory tracker memdebug.
  */
  */
 
 
 #include "curl_setup.h"
 #include "curl_setup.h"
@@ -82,6 +86,32 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
 
 
 #if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES)
 #if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES)
 
 
+int curlx_win32_open(const char *filename, int oflag, ...)
+{
+  int pmode = 0;
+
+#ifdef _UNICODE
+  int result = -1;
+  wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
+#endif
+
+  va_list param;
+  va_start(param, oflag);
+  if(oflag & O_CREAT)
+    pmode = va_arg(param, int);
+  va_end(param);
+
+#ifdef _UNICODE
+  if(filename_w)
+    result = _wopen(filename_w, oflag, pmode);
+  free(filename_w);
+  if(result != -1)
+    return result;
+#endif
+
+  return (_open)(filename, oflag, pmode);
+}
+
 FILE *curlx_win32_fopen(const char *filename, const char *mode)
 FILE *curlx_win32_fopen(const char *filename, const char *mode)
 {
 {
 #ifdef _UNICODE
 #ifdef _UNICODE
@@ -104,50 +134,38 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
   int result = -1;
   int result = -1;
 #ifdef _UNICODE
 #ifdef _UNICODE
   wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
   wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
-#endif /* _UNICODE */
-
+  if(path_w) {
 #if defined(USE_WIN32_SMALL_FILES)
 #if defined(USE_WIN32_SMALL_FILES)
-#if defined(_UNICODE)
-  if(path_w)
     result = _wstat(path_w, buffer);
     result = _wstat(path_w, buffer);
-  else
-#endif /* _UNICODE */
-    result = _stat(path, buffer);
-#else /* USE_WIN32_SMALL_FILES */
-#if defined(_UNICODE)
-  if(path_w)
+#else
     result = _wstati64(path_w, buffer);
     result = _wstati64(path_w, buffer);
-  else
+#endif
+    free(path_w);
+    if(result != -1)
+      return result;
+  }
 #endif /* _UNICODE */
 #endif /* _UNICODE */
-    result = _stati64(path, buffer);
-#endif /* USE_WIN32_SMALL_FILES */
 
 
-#ifdef _UNICODE
-  free(path_w);
+#if defined(USE_WIN32_SMALL_FILES)
+  result = _stat(path, buffer);
+#else
+  result = _stati64(path, buffer);
 #endif
 #endif
-
   return result;
   return result;
 }
 }
 
 
 int curlx_win32_access(const char *path, int mode)
 int curlx_win32_access(const char *path, int mode)
 {
 {
-    int result = -1;
-#ifdef _UNICODE
-    wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
-#endif /* _UNICODE */
-
 #if defined(_UNICODE)
 #if defined(_UNICODE)
-    if(path_w)
-        result = _waccess(path_w, mode);
-    else
-#endif /* _UNICODE */
-        result = _access(path, mode);
-
-#ifdef _UNICODE
+  wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
+  if(path_w) {
+    int result = _waccess(path_w, mode);
     free(path_w);
     free(path_w);
-#endif
-
-    return result;
+    if(result != -1)
+      return result;
+  }
+#endif /* _UNICODE */
+  return _access(path, mode);
 }
 }
 
 
 #endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
 #endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */

+ 21 - 22
lib/curl_multibyte.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -31,7 +31,6 @@
 
 
 wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8);
 wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8);
 char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
 char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
-
 #endif /* WIN32 */
 #endif /* WIN32 */
 
 
 /*
 /*
@@ -40,29 +39,23 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
  * preprocessor conditional directives needed by code using these
  * preprocessor conditional directives needed by code using these
  * to differentiate UNICODE from non-UNICODE builds.
  * to differentiate UNICODE from non-UNICODE builds.
  *
  *
- * When building with UNICODE defined, these two macros
- * curlx_convert_UTF8_to_tchar() and curlx_convert_tchar_to_UTF8()
- * return a pointer to a newly allocated memory area holding result.
- * When the result is no longer needed, allocated memory is intended
- * to be free'ed with curlx_unicodefree().
+ * In the case of a non-UNICODE build the tchar strings are char strings that
+ * are duplicated via strdup and remain in whatever the passed in encoding is,
+ * which is assumed to be UTF-8 but may be other encoding. Therefore the
+ * significance of the conversion functions is primarily for UNICODE builds.
+ *
+ * Allocated memory should be free'd with curlx_unicodefree().
  *
  *
- * When building without UNICODE defined, this macros
- * curlx_convert_UTF8_to_tchar() and curlx_convert_tchar_to_UTF8()
- * return the pointer received as argument. curlx_unicodefree() does
- * no actual free'ing of this pointer it is simply set to NULL.
+ * Note: Because these are curlx functions their memory usage is not tracked
+ * by the curl memory tracker memdebug. You'll notice that curlx function-like
+ * macros call free and strdup in parentheses, eg (strdup)(ptr), and that's to
+ * ensure that the curl memdebug override macros do not replace them.
  */
  */
 
 
 #if defined(UNICODE) && defined(WIN32)
 #if defined(UNICODE) && defined(WIN32)
 
 
 #define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
 #define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
 #define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))
 #define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))
-#define curlx_unicodefree(ptr)                          \
-  do {                                                  \
-    if(ptr) {                                           \
-      (free)(ptr);                                        \
-      (ptr) = NULL;                                     \
-    }                                                   \
-  } while(0)
 
 
 typedef union {
 typedef union {
   unsigned short       *tchar_ptr;
   unsigned short       *tchar_ptr;
@@ -73,10 +66,8 @@ typedef union {
 
 
 #else
 #else
 
 
-#define curlx_convert_UTF8_to_tchar(ptr) (ptr)
-#define curlx_convert_tchar_to_UTF8(ptr) (ptr)
-#define curlx_unicodefree(ptr) \
-  do {(ptr) = NULL;} while(0)
+#define curlx_convert_UTF8_to_tchar(ptr) (strdup)(ptr)
+#define curlx_convert_tchar_to_UTF8(ptr) (strdup)(ptr)
 
 
 typedef union {
 typedef union {
   char                *tchar_ptr;
   char                *tchar_ptr;
@@ -87,4 +78,12 @@ typedef union {
 
 
 #endif /* UNICODE && WIN32 */
 #endif /* UNICODE && WIN32 */
 
 
+#define curlx_unicodefree(ptr)                          \
+  do {                                                  \
+    if(ptr) {                                           \
+      (free)(ptr);                                      \
+      (ptr) = NULL;                                     \
+    }                                                   \
+  } while(0)
+
 #endif /* HEADER_CURL_MULTIBYTE_H */
 #endif /* HEADER_CURL_MULTIBYTE_H */

+ 69 - 76
lib/curl_ntlm_core.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -34,13 +34,12 @@
 /* Please keep the SSL backend-specific #if branches in this order:
 /* Please keep the SSL backend-specific #if branches in this order:
 
 
    1. USE_OPENSSL
    1. USE_OPENSSL
-   2. USE_GNUTLS_NETTLE
-   3. USE_GNUTLS
-   4. USE_NSS
-   5. USE_MBEDTLS
-   6. USE_SECTRANSP
-   7. USE_OS400CRYPTO
-   8. USE_WIN32_CRYPTO
+   2. USE_GNUTLS
+   3. USE_NSS
+   4. USE_MBEDTLS
+   5. USE_SECTRANSP
+   6. USE_OS400CRYPTO
+   7. USE_WIN32_CRYPTO
 
 
    This ensures that:
    This ensures that:
    - the same SSL branch gets activated throughout this source
    - the same SSL branch gets activated throughout this source
@@ -74,13 +73,9 @@
 #    define DESKEY(x) &x
 #    define DESKEY(x) &x
 #  endif
 #  endif
 
 
-#elif defined(USE_GNUTLS_NETTLE)
-
-#  include <nettle/des.h>
-
 #elif defined(USE_GNUTLS)
 #elif defined(USE_GNUTLS)
 
 
-#  include <gcrypt.h>
+#  include <nettle/des.h>
 
 
 #elif defined(USE_NSS)
 #elif defined(USE_NSS)
 
 
@@ -159,7 +154,7 @@ static void setup_des_key(const unsigned char *key_56,
   DES_set_key(&key, ks);
   DES_set_key(&key, ks);
 }
 }
 
 
-#elif defined(USE_GNUTLS_NETTLE)
+#elif defined(USE_GNUTLS)
 
 
 static void setup_des_key(const unsigned char *key_56,
 static void setup_des_key(const unsigned char *key_56,
                           struct des_ctx *des)
                           struct des_ctx *des)
@@ -176,26 +171,6 @@ static void setup_des_key(const unsigned char *key_56,
   des_set_key(des, (const uint8_t *) key);
   des_set_key(des, (const uint8_t *) key);
 }
 }
 
 
-#elif defined(USE_GNUTLS)
-
-/*
- * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
- */
-static void setup_des_key(const unsigned char *key_56,
-                          gcry_cipher_hd_t *des)
-{
-  char key[8];
-
-  /* Expand the 56-bit key to 64-bits */
-  extend_key_56_to_64(key_56, key);
-
-  /* Set the key parity to odd */
-  Curl_des_set_odd_parity((unsigned char *) key, sizeof(key));
-
-  /* Set the key */
-  gcry_cipher_setkey(*des, key, sizeof(key));
-}
-
 #elif defined(USE_NSS)
 #elif defined(USE_NSS)
 
 
 /*
 /*
@@ -402,7 +377,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
   setup_des_key(keys + 14, DESKEY(ks));
   setup_des_key(keys + 14, DESKEY(ks));
   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
   DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
                   DESKEY(ks), DES_ENCRYPT);
                   DESKEY(ks), DES_ENCRYPT);
-#elif defined(USE_GNUTLS_NETTLE)
+#elif defined(USE_GNUTLS)
   struct des_ctx des;
   struct des_ctx des;
   setup_des_key(keys, &des);
   setup_des_key(keys, &des);
   des_encrypt(&des, 8, results, plaintext);
   des_encrypt(&des, 8, results, plaintext);
@@ -410,23 +385,6 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
   des_encrypt(&des, 8, results + 8, plaintext);
   des_encrypt(&des, 8, results + 8, plaintext);
   setup_des_key(keys + 14, &des);
   setup_des_key(keys + 14, &des);
   des_encrypt(&des, 8, results + 16, plaintext);
   des_encrypt(&des, 8, results + 16, plaintext);
-#elif defined(USE_GNUTLS)
-  gcry_cipher_hd_t des;
-
-  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-  setup_des_key(keys, &des);
-  gcry_cipher_encrypt(des, results, 8, plaintext, 8);
-  gcry_cipher_close(des);
-
-  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-  setup_des_key(keys + 7, &des);
-  gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8);
-  gcry_cipher_close(des);
-
-  gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-  setup_des_key(keys + 14, &des);
-  gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
-  gcry_cipher_close(des);
 #elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
 #elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
   encrypt_des(plaintext, results, keys);
   encrypt_des(plaintext, results, keys);
@@ -473,24 +431,12 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
     setup_des_key(pw + 7, DESKEY(ks));
     setup_des_key(pw + 7, DESKEY(ks));
     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
     DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
                     DESKEY(ks), DES_ENCRYPT);
                     DESKEY(ks), DES_ENCRYPT);
-#elif defined(USE_GNUTLS_NETTLE)
+#elif defined(USE_GNUTLS)
     struct des_ctx des;
     struct des_ctx des;
     setup_des_key(pw, &des);
     setup_des_key(pw, &des);
     des_encrypt(&des, 8, lmbuffer, magic);
     des_encrypt(&des, 8, lmbuffer, magic);
     setup_des_key(pw + 7, &des);
     setup_des_key(pw + 7, &des);
     des_encrypt(&des, 8, lmbuffer + 8, magic);
     des_encrypt(&des, 8, lmbuffer + 8, magic);
-#elif defined(USE_GNUTLS)
-    gcry_cipher_hd_t des;
-
-    gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-    setup_des_key(pw, &des);
-    gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
-    gcry_cipher_close(des);
-
-    gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
-    setup_des_key(pw + 7, &des);
-    gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
-    gcry_cipher_close(des);
 #elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
 #elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
     encrypt_des(magic, lmbuffer, pw);
     encrypt_des(magic, lmbuffer, pw);
@@ -567,6 +513,56 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
 
 
 #if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
 #if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
 
 
+/* Timestamp in tenths of a microsecond since January 1, 1601 00:00:00 UTC. */
+struct ms_filetime {
+  unsigned int dwLowDateTime;
+  unsigned int dwHighDateTime;
+};
+
+/* Convert a time_t to an MS FILETIME (MS-DTYP section 2.3.3). */
+static void time2filetime(struct ms_filetime *ft, time_t t)
+{
+#if SIZEOF_TIME_T > 4
+  t = (t + CURL_OFF_T_C(11644473600)) * 10000000;
+  ft->dwLowDateTime = (unsigned int) (t & 0xFFFFFFFF);
+  ft->dwHighDateTime = (unsigned int) (t >> 32);
+#else
+  unsigned int r, s;
+  unsigned int i;
+
+  ft->dwLowDateTime = t & 0xFFFFFFFF;
+  ft->dwHighDateTime = 0;
+
+# ifndef HAVE_TIME_T_UNSIGNED
+  /* Extend sign if needed. */
+  if(ft->dwLowDateTime & 0x80000000)
+    ft->dwHighDateTime = ~0;
+# endif
+
+  /* Bias seconds to Jan 1, 1601.
+     134774 days = 11644473600 seconds = 0x2B6109100 */
+  r = ft->dwLowDateTime;
+  ft->dwLowDateTime = (ft->dwLowDateTime + 0xB6109100U) & 0xFFFFFFFF;
+  ft->dwHighDateTime += ft->dwLowDateTime < r? 0x03: 0x02;
+
+  /* Convert to tenths of microseconds. */
+  ft->dwHighDateTime *= 10000000;
+  i = 32;
+  do {
+    i -= 8;
+    s = ((ft->dwLowDateTime >> i) & 0xFF) * (10000000 - 1);
+    r = (s << i) & 0xFFFFFFFF;
+    s >>= 1;   /* Split shift to avoid width overflow. */
+    s >>= 31 - i;
+    ft->dwLowDateTime = (ft->dwLowDateTime + r) & 0xFFFFFFFF;
+    if(ft->dwLowDateTime < r)
+      s++;
+    ft->dwHighDateTime += s;
+  } while(i);
+  ft->dwHighDateTime &= 0xFFFFFFFF;
+#endif
+}
+
 /* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
 /* This creates the NTLMv2 hash by using NTLM hash as the key and Unicode
  * (uppercase UserName + Domain) as the data
  * (uppercase UserName + Domain) as the data
  */
  */
@@ -640,22 +636,18 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
   unsigned int len = 0;
   unsigned int len = 0;
   unsigned char *ptr = NULL;
   unsigned char *ptr = NULL;
   unsigned char hmac_output[HMAC_MD5_LENGTH];
   unsigned char hmac_output[HMAC_MD5_LENGTH];
-  curl_off_t tw;
+  struct ms_filetime tw;
 
 
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
 
 
-#if CURL_SIZEOF_CURL_OFF_T < 8
-#error "this section needs 64bit support to work"
-#endif
-
   /* Calculate the timestamp */
   /* Calculate the timestamp */
 #ifdef DEBUGBUILD
 #ifdef DEBUGBUILD
   char *force_timestamp = getenv("CURL_FORCETIME");
   char *force_timestamp = getenv("CURL_FORCETIME");
   if(force_timestamp)
   if(force_timestamp)
-    tw = CURL_OFF_T_C(11644473600) * 10000000;
+    time2filetime(&tw, (time_t) 0);
   else
   else
 #endif
 #endif
-    tw = ((curl_off_t)time(NULL) + CURL_OFF_T_C(11644473600)) * 10000000;
+    time2filetime(&tw, time(NULL));
 
 
   /* Calculate the response len */
   /* Calculate the response len */
   len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN;
   len = HMAC_MD5_LENGTH + NTLMv2_BLOB_LEN;
@@ -667,13 +659,14 @@ CURLcode Curl_ntlm_core_mk_ntlmv2_resp(unsigned char *ntlmv2hash,
 
 
   /* Create the BLOB structure */
   /* Create the BLOB structure */
   msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN,
   msnprintf((char *)ptr + HMAC_MD5_LENGTH, NTLMv2_BLOB_LEN,
-            "%c%c%c%c"   /* NTLMv2_BLOB_SIGNATURE */
-            "%c%c%c%c",  /* Reserved = 0 */
+            "%c%c%c%c"           /* NTLMv2_BLOB_SIGNATURE */
+            "%c%c%c%c"           /* Reserved = 0 */
+            "%c%c%c%c%c%c%c%c",  /* Timestamp */
             NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
             NTLMv2_BLOB_SIGNATURE[0], NTLMv2_BLOB_SIGNATURE[1],
             NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3],
             NTLMv2_BLOB_SIGNATURE[2], NTLMv2_BLOB_SIGNATURE[3],
-            0, 0, 0, 0);
+            0, 0, 0, 0,
+            LONGQUARTET(tw.dwLowDateTime), LONGQUARTET(tw.dwHighDateTime));
 
 
-  Curl_write64_le(tw, ptr + 24);
   memcpy(ptr + 32, challenge_client, 8);
   memcpy(ptr + 32, challenge_client, 8);
   memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len);
   memcpy(ptr + 44, ntlm->target_info, ntlm->target_info_len);
 
 

+ 10 - 8
lib/curl_ntlm_core.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -30,7 +30,6 @@
    then it must be initialized to be used by NTLM. */
    then it must be initialized to be used by NTLM. */
 #if !defined(USE_OPENSSL) && \
 #if !defined(USE_OPENSSL) && \
     !defined(USE_WOLFSSL) && \
     !defined(USE_WOLFSSL) && \
-    !defined(USE_GNUTLS_NETTLE) && \
     !defined(USE_GNUTLS) && \
     !defined(USE_GNUTLS) && \
     defined(USE_NSS)
     defined(USE_NSS)
 #define NTLM_NEEDS_NSS_INIT
 #define NTLM_NEEDS_NSS_INIT
@@ -48,19 +47,22 @@
 #define USE_NTRESPONSES
 #define USE_NTRESPONSES
 
 
 /* Define USE_NTLM2SESSION in order to make the type-3 message include the
 /* Define USE_NTLM2SESSION in order to make the type-3 message include the
-   NTLM2Session response message, requires USE_NTRESPONSES defined to 1 and
-   MD5 support */
-#if defined(USE_NTRESPONSES) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+   NTLM2Session response message, requires USE_NTRESPONSES defined to 1 */
+#if defined(USE_NTRESPONSES)
 #define USE_NTLM2SESSION
 #define USE_NTLM2SESSION
 #endif
 #endif
 
 
 /* Define USE_NTLM_V2 in order to allow the type-3 message to include the
 /* Define USE_NTLM_V2 in order to allow the type-3 message to include the
-   LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1
-   and support for 64-bit integers. */
-#if defined(USE_NTRESPONSES) && (CURL_SIZEOF_CURL_OFF_T > 4)
+   LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1 */
+#if defined(USE_NTRESPONSES)
 #define USE_NTLM_V2
 #define USE_NTLM_V2
 #endif
 #endif
 
 
+/* Helpers to generate function byte arguments in little endian order */
+#define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
+#define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
+  ((int)(((x) >> 16) & 0xff)), ((int)(((x) >> 24) & 0xff))
+
 void Curl_ntlm_core_lm_resp(const unsigned char *keys,
 void Curl_ntlm_core_lm_resp(const unsigned char *keys,
                             const unsigned char *plaintext,
                             const unsigned char *plaintext,
                             unsigned char *results);
                             unsigned char *results);

+ 5 - 5
lib/curl_path.c

@@ -48,7 +48,7 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
   /* Check for /~/, indicating relative to the user's home directory */
   /* Check for /~/, indicating relative to the user's home directory */
   if(data->conn->handler->protocol & CURLPROTO_SCP) {
   if(data->conn->handler->protocol & CURLPROTO_SCP) {
     real_path = malloc(working_path_len + 1);
     real_path = malloc(working_path_len + 1);
-    if(real_path == NULL) {
+    if(!real_path) {
       free(working_path);
       free(working_path);
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
@@ -62,7 +62,7 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
     if((working_path_len > 1) && (working_path[1] == '~')) {
     if((working_path_len > 1) && (working_path[1] == '~')) {
       size_t homelen = strlen(homedir);
       size_t homelen = strlen(homedir);
       real_path = malloc(homelen + working_path_len + 1);
       real_path = malloc(homelen + working_path_len + 1);
-      if(real_path == NULL) {
+      if(!real_path) {
         free(working_path);
         free(working_path);
         return CURLE_OUT_OF_MEMORY;
         return CURLE_OUT_OF_MEMORY;
       }
       }
@@ -78,7 +78,7 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
     }
     }
     else {
     else {
       real_path = malloc(working_path_len + 1);
       real_path = malloc(working_path_len + 1);
-      if(real_path == NULL) {
+      if(!real_path) {
         free(working_path);
         free(working_path);
         return CURLE_OUT_OF_MEMORY;
         return CURLE_OUT_OF_MEMORY;
       }
       }
@@ -130,7 +130,7 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
   /* Allocate enough space for home directory and filename + separator */
   /* Allocate enough space for home directory and filename + separator */
   fullPathLength = strlen(cp) + strlen(homedir) + 2;
   fullPathLength = strlen(cp) + strlen(homedir) + 2;
   *path = malloc(fullPathLength);
   *path = malloc(fullPathLength);
-  if(*path == NULL)
+  if(!*path)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 
 
   /* Check for quoted filenames */
   /* Check for quoted filenames */
@@ -169,7 +169,7 @@ CURLcode Curl_get_pathname(const char **cpp, char **path, char *homedir)
   else {
   else {
     /* Read to end of filename - either to whitespace or terminator */
     /* Read to end of filename - either to whitespace or terminator */
     end = strpbrk(cp, WHITESPACE);
     end = strpbrk(cp, WHITESPACE);
-    if(end == NULL)
+    if(!end)
       end = strchr(cp, '\0');
       end = strchr(cp, '\0');
     /* return pointer to second parameter if it exists */
     /* return pointer to second parameter if it exists */
     *cpp = end + strspn(end, WHITESPACE);
     *cpp = end + strspn(end, WHITESPACE);

+ 7 - 1
lib/curl_rtmp.c

@@ -79,6 +79,7 @@ const struct Curl_handler Curl_handler_rtmp = {
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_RTMP,                            /* defport */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMP,                       /* protocol */
   CURLPROTO_RTMP,                       /* protocol */
   CURLPROTO_RTMP,                       /* family */
   CURLPROTO_RTMP,                       /* family */
@@ -101,6 +102,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_RTMPT,                           /* defport */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPT,                      /* protocol */
   CURLPROTO_RTMPT,                      /* protocol */
   CURLPROTO_RTMPT,                      /* family */
   CURLPROTO_RTMPT,                      /* family */
@@ -123,6 +125,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_RTMP,                            /* defport */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMPE,                      /* protocol */
   CURLPROTO_RTMPE,                      /* protocol */
   CURLPROTO_RTMPE,                      /* family */
   CURLPROTO_RTMPE,                      /* family */
@@ -145,6 +148,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_RTMPT,                           /* defport */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPTE,                     /* protocol */
   CURLPROTO_RTMPTE,                     /* protocol */
   CURLPROTO_RTMPTE,                     /* family */
   CURLPROTO_RTMPTE,                     /* family */
@@ -167,6 +171,7 @@ const struct Curl_handler Curl_handler_rtmps = {
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_RTMPS,                           /* defport */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPS,                      /* protocol */
   CURLPROTO_RTMPS,                      /* protocol */
   CURLPROTO_RTMP,                       /* family */
   CURLPROTO_RTMP,                       /* family */
@@ -189,6 +194,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
   rtmp_disconnect,                      /* disconnect */
   rtmp_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_RTMPS,                           /* defport */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPTS,                     /* protocol */
   CURLPROTO_RTMPTS,                     /* protocol */
   CURLPROTO_RTMPT,                      /* family */
   CURLPROTO_RTMPT,                      /* family */
@@ -204,7 +210,7 @@ static CURLcode rtmp_setup_connection(struct Curl_easy *data,
 
 
   RTMP_Init(r);
   RTMP_Init(r);
   RTMP_SetBufferMS(r, DEF_BUFTIME);
   RTMP_SetBufferMS(r, DEF_BUFTIME);
-  if(!RTMP_SetupURL(r, data->change.url)) {
+  if(!RTMP_SetupURL(r, data->state.url)) {
     RTMP_Free(r);
     RTMP_Free(r);
     return CURLE_URL_MALFORMAT;
     return CURLE_URL_MALFORMAT;
   }
   }

+ 191 - 111
lib/curl_sasl.c

@@ -23,6 +23,8 @@
  * RFC2831 DIGEST-MD5 authentication
  * RFC2831 DIGEST-MD5 authentication
  * RFC4422 Simple Authentication and Security Layer (SASL)
  * RFC4422 Simple Authentication and Security Layer (SASL)
  * RFC4616 PLAIN authentication
  * RFC4616 PLAIN authentication
+ * RFC5802 SCRAM-SHA-1 authentication
+ * RFC7677 SCRAM-SHA-256 authentication
  * RFC6749 OAuth 2.0 Authorization Framework
  * RFC6749 OAuth 2.0 Authorization Framework
  * RFC7628 A Set of SASL Mechanisms for OAuth
  * RFC7628 A Set of SASL Mechanisms for OAuth
  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
  * Draft   LOGIN SASL Mechanism <draft-murchison-sasl-login-00.txt>
@@ -56,7 +58,7 @@
 static const struct {
 static const struct {
   const char   *name;  /* Name */
   const char   *name;  /* Name */
   size_t        len;   /* Name length */
   size_t        len;   /* Name length */
-  unsigned int  bit;   /* Flag bit */
+  unsigned short bit;   /* Flag bit */
 } mechtable[] = {
 } mechtable[] = {
   { "LOGIN",        5,  SASL_MECH_LOGIN },
   { "LOGIN",        5,  SASL_MECH_LOGIN },
   { "PLAIN",        5,  SASL_MECH_PLAIN },
   { "PLAIN",        5,  SASL_MECH_PLAIN },
@@ -67,6 +69,8 @@ static const struct {
   { "NTLM",         4,  SASL_MECH_NTLM },
   { "NTLM",         4,  SASL_MECH_NTLM },
   { "XOAUTH2",      7,  SASL_MECH_XOAUTH2 },
   { "XOAUTH2",      7,  SASL_MECH_XOAUTH2 },
   { "OAUTHBEARER",  11, SASL_MECH_OAUTHBEARER },
   { "OAUTHBEARER",  11, SASL_MECH_OAUTHBEARER },
+  { "SCRAM-SHA-1",  11, SASL_MECH_SCRAM_SHA_1 },
+  { "SCRAM-SHA-256",13, SASL_MECH_SCRAM_SHA_256 },
   { ZERO_NULL,      0,  0 }
   { ZERO_NULL,      0,  0 }
 };
 };
 
 
@@ -90,6 +94,13 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
   }
   }
 #endif
 #endif
 
 
+#if defined(USE_GSASL)
+  /* Cleanup the GSASL structure */
+  if(authused & (SASL_MECH_SCRAM_SHA_1 | SASL_MECH_SCRAM_SHA_256)) {
+    Curl_auth_gsasl_cleanup(&conn->gsasl);
+  }
+#endif
+
 #if defined(USE_NTLM)
 #if defined(USE_NTLM)
   /* Cleanup the NTLM structure */
   /* Cleanup the NTLM structure */
   if(authused == SASL_MECH_NTLM) {
   if(authused == SASL_MECH_NTLM) {
@@ -117,7 +128,8 @@ void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
  *
  *
  * Returns the SASL mechanism token or 0 if no match.
  * Returns the SASL mechanism token or 0 if no match.
  */
  */
-unsigned int Curl_sasl_decode_mech(const char *ptr, size_t maxlen, size_t *len)
+unsigned short Curl_sasl_decode_mech(const char *ptr, size_t maxlen,
+                                     size_t *len)
 {
 {
   unsigned int i;
   unsigned int i;
   char c;
   char c;
@@ -162,7 +174,7 @@ CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
   if(!strncmp(value, "*", len))
   if(!strncmp(value, "*", len))
     sasl->prefmech = SASL_AUTH_DEFAULT;
     sasl->prefmech = SASL_AUTH_DEFAULT;
   else {
   else {
-    unsigned int mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
+    unsigned short mechbit = Curl_sasl_decode_mech(value, len, &mechlen);
     if(mechbit && mechlen == len)
     if(mechbit && mechlen == len)
       sasl->prefmech |= mechbit;
       sasl->prefmech |= mechbit;
     else
     else
@@ -215,6 +227,7 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
     "GSSAPI_NO_DATA",
     "GSSAPI_NO_DATA",
     "OAUTH2",
     "OAUTH2",
     "OAUTH2_RESP",
     "OAUTH2_RESP",
+    "GSASL",
     "CANCEL",
     "CANCEL",
     "FINAL",
     "FINAL",
     /* LAST */
     /* LAST */
@@ -230,6 +243,49 @@ static void state(struct SASL *sasl, struct Curl_easy *data,
   sasl->state = newstate;
   sasl->state = newstate;
 }
 }
 
 
+/* Get the SASL server message and convert it to binary. */
+static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
+                                   struct bufref *out)
+{
+  unsigned char *msg;
+  size_t msglen;
+  char *serverdata = NULL;
+  CURLcode result = CURLE_OK;
+
+  sasl->params->getmessage(data->state.buffer, &serverdata);
+  if(!serverdata)
+    result = CURLE_BAD_CONTENT_ENCODING;
+  else if(!*serverdata || *serverdata == '=')
+    Curl_bufref_set(out, NULL, 0, NULL);
+  else {
+    result = Curl_base64_decode(serverdata, &msg, &msglen);
+    if(!result)
+      Curl_bufref_set(out, msg, msglen, curl_free);
+  }
+  return result;
+}
+
+/* Encode the outgoing SASL message. */
+static CURLcode build_message(struct Curl_easy *data, struct bufref *msg)
+{
+  CURLcode result = CURLE_OK;
+  char *base64;
+  size_t base64len;
+
+  if(!Curl_bufref_ptr(msg))             /* Empty mesage. */
+    Curl_bufref_set(msg, "", 0, NULL);
+  else if(!Curl_bufref_len(msg))        /* Explicit empty response. */
+    Curl_bufref_set(msg, "=", 1, NULL);
+  else {
+    result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg),
+                                Curl_bufref_len(msg), &base64, &base64len);
+    if(!result)
+      Curl_bufref_set(msg, base64, base64len, curl_free);
+  }
+
+  return result;
+}
+
 /*
 /*
  * Curl_sasl_can_authenticate()
  * Curl_sasl_can_authenticate()
  *
  *
@@ -260,25 +316,21 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   unsigned int enabledmechs;
   unsigned int enabledmechs;
   const char *mech = NULL;
   const char *mech = NULL;
-  char *resp = NULL;
-  size_t len = 0;
+  struct bufref resp;
   saslstate state1 = SASL_STOP;
   saslstate state1 = SASL_STOP;
   saslstate state2 = SASL_FINAL;
   saslstate state2 = SASL_FINAL;
-#ifndef CURL_DISABLE_PROXY
-  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
-    conn->host.name;
-  const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
-#else
-  const char * const hostname = conn->host.name;
-  const long int port = conn->remote_port;
-#endif
+  const char * const hostname = SSL_HOST_NAME();
+  const long int port = SSL_HOST_PORT();
 #if defined(USE_KERBEROS5) || defined(USE_NTLM)
 #if defined(USE_KERBEROS5) || defined(USE_NTLM)
   const char *service = data->set.str[STRING_SERVICE_NAME] ?
   const char *service = data->set.str[STRING_SERVICE_NAME] ?
     data->set.str[STRING_SERVICE_NAME] :
     data->set.str[STRING_SERVICE_NAME] :
     sasl->params->service;
     sasl->params->service;
 #endif
 #endif
   const char *oauth_bearer = data->set.str[STRING_BEARER];
   const char *oauth_bearer = data->set.str[STRING_BEARER];
+  struct bufref nullmsg;
 
 
+  Curl_bufref_init(&nullmsg);
+  Curl_bufref_init(&resp);
   sasl->force_ir = force_ir;    /* Latch for future use */
   sasl->force_ir = force_ir;    /* Latch for future use */
   sasl->authused = 0;           /* No mechanism used yet */
   sasl->authused = 0;           /* No mechanism used yet */
   enabledmechs = sasl->authmechs & sasl->prefmech;
   enabledmechs = sasl->authmechs & sasl->prefmech;
@@ -292,8 +344,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
     sasl->authused = SASL_MECH_EXTERNAL;
     sasl->authused = SASL_MECH_EXTERNAL;
 
 
     if(force_ir || data->set.sasl_ir)
     if(force_ir || data->set.sasl_ir)
-      result = Curl_auth_create_external_message(data, conn->user, &resp,
-                                                 &len);
+      result = Curl_auth_create_external_message(conn->user, &resp);
   }
   }
   else if(conn->bits.user_passwd) {
   else if(conn->bits.user_passwd) {
 #if defined(USE_KERBEROS5)
 #if defined(USE_KERBEROS5)
@@ -309,10 +360,39 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
         result = Curl_auth_create_gssapi_user_message(data, conn->user,
         result = Curl_auth_create_gssapi_user_message(data, conn->user,
                                                       conn->passwd,
                                                       conn->passwd,
                                                       service,
                                                       service,
-                                                      data->conn->host.name,
+                                                      conn->host.name,
                                                       sasl->mutual_auth,
                                                       sasl->mutual_auth,
                                                       NULL, &conn->krb5,
                                                       NULL, &conn->krb5,
-                                                      &resp, &len);
+                                                      &resp);
+    }
+    else
+#endif
+#ifdef USE_GSASL
+    if((enabledmechs & SASL_MECH_SCRAM_SHA_256) &&
+       Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_256,
+                                    &conn->gsasl)) {
+      mech = SASL_MECH_STRING_SCRAM_SHA_256;
+      sasl->authused = SASL_MECH_SCRAM_SHA_256;
+      state1 = SASL_GSASL;
+      state2 = SASL_GSASL;
+
+      result = Curl_auth_gsasl_start(data, conn->user,
+                                     conn->passwd, &conn->gsasl);
+      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
+        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
+    }
+    else if((enabledmechs & SASL_MECH_SCRAM_SHA_1) &&
+            Curl_auth_gsasl_is_supported(data, SASL_MECH_STRING_SCRAM_SHA_1,
+                                         &conn->gsasl)) {
+      mech = SASL_MECH_STRING_SCRAM_SHA_1;
+      sasl->authused = SASL_MECH_SCRAM_SHA_1;
+      state1 = SASL_GSASL;
+      state2 = SASL_GSASL;
+
+      result = Curl_auth_gsasl_start(data, conn->user,
+                                     conn->passwd, &conn->gsasl);
+      if(result == CURLE_OK && (force_ir || data->set.sasl_ir))
+        result = Curl_auth_gsasl_token(data, &nullmsg, &conn->gsasl, &resp);
     }
     }
     else
     else
 #endif
 #endif
@@ -342,8 +422,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
                                                      conn->user, conn->passwd,
                                                      conn->user, conn->passwd,
                                                      service,
                                                      service,
                                                      hostname,
                                                      hostname,
-                                                     &conn->ntlm, &resp,
-                                                     &len);
+                                                     &conn->ntlm, &resp);
       }
       }
     else
     else
 #endif
 #endif
@@ -354,11 +433,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
       sasl->authused = SASL_MECH_OAUTHBEARER;
       sasl->authused = SASL_MECH_OAUTHBEARER;
 
 
       if(force_ir || data->set.sasl_ir)
       if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+        result = Curl_auth_create_oauth_bearer_message(conn->user,
                                                        hostname,
                                                        hostname,
                                                        port,
                                                        port,
                                                        oauth_bearer,
                                                        oauth_bearer,
-                                                       &resp, &len);
+                                                       &resp);
     }
     }
     else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
     else if((enabledmechs & SASL_MECH_XOAUTH2) && oauth_bearer) {
       mech = SASL_MECH_STRING_XOAUTH2;
       mech = SASL_MECH_STRING_XOAUTH2;
@@ -366,9 +445,9 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
       sasl->authused = SASL_MECH_XOAUTH2;
       sasl->authused = SASL_MECH_XOAUTH2;
 
 
       if(force_ir || data->set.sasl_ir)
       if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
+        result = Curl_auth_create_xoauth_bearer_message(conn->user,
                                                         oauth_bearer,
                                                         oauth_bearer,
-                                                        &resp, &len);
+                                                        &resp);
     }
     }
     else if(enabledmechs & SASL_MECH_PLAIN) {
     else if(enabledmechs & SASL_MECH_PLAIN) {
       mech = SASL_MECH_STRING_PLAIN;
       mech = SASL_MECH_STRING_PLAIN;
@@ -376,9 +455,9 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
       sasl->authused = SASL_MECH_PLAIN;
       sasl->authused = SASL_MECH_PLAIN;
 
 
       if(force_ir || data->set.sasl_ir)
       if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_plain_message(data, conn->sasl_authzid,
+        result = Curl_auth_create_plain_message(conn->sasl_authzid,
                                                 conn->user, conn->passwd,
                                                 conn->user, conn->passwd,
-                                                &resp, &len);
+                                                &resp);
     }
     }
     else if(enabledmechs & SASL_MECH_LOGIN) {
     else if(enabledmechs & SASL_MECH_LOGIN) {
       mech = SASL_MECH_STRING_LOGIN;
       mech = SASL_MECH_STRING_LOGIN;
@@ -387,26 +466,29 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
       sasl->authused = SASL_MECH_LOGIN;
       sasl->authused = SASL_MECH_LOGIN;
 
 
       if(force_ir || data->set.sasl_ir)
       if(force_ir || data->set.sasl_ir)
-        result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
+        result = Curl_auth_create_login_message(conn->user, &resp);
     }
     }
   }
   }
 
 
   if(!result && mech) {
   if(!result && mech) {
-    if(resp && sasl->params->maxirlen &&
-       strlen(mech) + len > sasl->params->maxirlen) {
-      free(resp);
-      resp = NULL;
-    }
+    if(Curl_bufref_ptr(&resp))
+      result = build_message(data, &resp);
+
+    if(sasl->params->maxirlen &&
+       strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
+      Curl_bufref_free(&resp);
+
+    if(!result)
+      result = sasl->params->sendauth(data, conn, mech,
+                                      (const char *) Curl_bufref_ptr(&resp));
 
 
-    result = sasl->params->sendauth(data, conn, mech, resp);
     if(!result) {
     if(!result) {
       *progress = SASL_INPROGRESS;
       *progress = SASL_INPROGRESS;
-      state(sasl, data, resp ? state2 : state1);
+      state(sasl, data, Curl_bufref_ptr(&resp) ? state2 : state1);
     }
     }
   }
   }
 
 
-  free(resp);
-
+  Curl_bufref_free(&resp);
   return result;
   return result;
 }
 }
 
 
@@ -421,29 +503,20 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
 {
 {
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   saslstate newstate = SASL_FINAL;
   saslstate newstate = SASL_FINAL;
-  char *resp = NULL;
-#ifndef CURL_DISABLE_PROXY
-  const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
-    conn->host.name;
-  const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
-#else
-  const char * const hostname = conn->host.name;
-  const long int port = conn->remote_port;
-#endif
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
-  char *chlg = NULL;
-  size_t chlglen = 0;
-#endif
+  struct bufref resp;
+  const char * const hostname = SSL_HOST_NAME();
+  const long int port = SSL_HOST_PORT();
 #if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) ||     \
 #if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) ||     \
   defined(USE_NTLM)
   defined(USE_NTLM)
   const char *service = data->set.str[STRING_SERVICE_NAME] ?
   const char *service = data->set.str[STRING_SERVICE_NAME] ?
     data->set.str[STRING_SERVICE_NAME] :
     data->set.str[STRING_SERVICE_NAME] :
     sasl->params->service;
     sasl->params->service;
-  char *serverdata;
 #endif
 #endif
-  size_t len = 0;
   const char *oauth_bearer = data->set.str[STRING_BEARER];
   const char *oauth_bearer = data->set.str[STRING_BEARER];
+  struct bufref serverdata;
 
 
+  Curl_bufref_init(&serverdata);
+  Curl_bufref_init(&resp);
   *progress = SASL_INPROGRESS;
   *progress = SASL_INPROGRESS;
 
 
   if(sasl->state == SASL_FINAL) {
   if(sasl->state == SASL_FINAL) {
@@ -466,42 +539,45 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
     *progress = SASL_DONE;
     *progress = SASL_DONE;
     return result;
     return result;
   case SASL_PLAIN:
   case SASL_PLAIN:
-    result = Curl_auth_create_plain_message(data, conn->sasl_authzid,
-                                            conn->user, conn->passwd,
-                                            &resp, &len);
+    result = Curl_auth_create_plain_message(conn->sasl_authzid,
+                                            conn->user, conn->passwd, &resp);
     break;
     break;
   case SASL_LOGIN:
   case SASL_LOGIN:
-    result = Curl_auth_create_login_message(data, conn->user, &resp, &len);
+    result = Curl_auth_create_login_message(conn->user, &resp);
     newstate = SASL_LOGIN_PASSWD;
     newstate = SASL_LOGIN_PASSWD;
     break;
     break;
   case SASL_LOGIN_PASSWD:
   case SASL_LOGIN_PASSWD:
-    result = Curl_auth_create_login_message(data, conn->passwd, &resp, &len);
+    result = Curl_auth_create_login_message(conn->passwd, &resp);
     break;
     break;
   case SASL_EXTERNAL:
   case SASL_EXTERNAL:
-    result = Curl_auth_create_external_message(data, conn->user, &resp, &len);
+    result = Curl_auth_create_external_message(conn->user, &resp);
     break;
     break;
-
 #ifndef CURL_DISABLE_CRYPTO_AUTH
 #ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifdef USE_GSASL
+  case SASL_GSASL:
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_gsasl_token(data, &serverdata, &conn->gsasl, &resp);
+    if(!result && Curl_bufref_len(&resp) > 0)
+      newstate = SASL_GSASL;
+    break;
+#endif
   case SASL_CRAMMD5:
   case SASL_CRAMMD5:
-    sasl->params->getmessage(data->state.buffer, &serverdata);
-    result = Curl_auth_decode_cram_md5_message(serverdata, &chlg, &chlglen);
+    result = get_server_message(sasl, data, &serverdata);
     if(!result)
     if(!result)
-      result = Curl_auth_create_cram_md5_message(data, chlg, conn->user,
-                                                 conn->passwd, &resp, &len);
-    free(chlg);
+      result = Curl_auth_create_cram_md5_message(&serverdata, conn->user,
+                                                 conn->passwd, &resp);
     break;
     break;
   case SASL_DIGESTMD5:
   case SASL_DIGESTMD5:
-    sasl->params->getmessage(data->state.buffer, &serverdata);
-    result = Curl_auth_create_digest_md5_message(data, serverdata,
-                                                 conn->user, conn->passwd,
-                                                 service,
-                                                 &resp, &len);
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_create_digest_md5_message(data, &serverdata,
+                                                   conn->user, conn->passwd,
+                                                   service, &resp);
     newstate = SASL_DIGESTMD5_RESP;
     newstate = SASL_DIGESTMD5_RESP;
     break;
     break;
   case SASL_DIGESTMD5_RESP:
   case SASL_DIGESTMD5_RESP:
-    resp = strdup("");
-    if(!resp)
-      result = CURLE_OUT_OF_MEMORY;
+    /* Keep response NULL to output an empty line. */
     break;
     break;
 #endif
 #endif
 
 
@@ -511,18 +587,19 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
     result = Curl_auth_create_ntlm_type1_message(data,
     result = Curl_auth_create_ntlm_type1_message(data,
                                                  conn->user, conn->passwd,
                                                  conn->user, conn->passwd,
                                                  service, hostname,
                                                  service, hostname,
-                                                 &conn->ntlm, &resp, &len);
+                                                 &conn->ntlm, &resp);
     newstate = SASL_NTLM_TYPE2MSG;
     newstate = SASL_NTLM_TYPE2MSG;
     break;
     break;
   case SASL_NTLM_TYPE2MSG:
   case SASL_NTLM_TYPE2MSG:
     /* Decode the type-2 message */
     /* Decode the type-2 message */
-    sasl->params->getmessage(data->state.buffer, &serverdata);
-    result = Curl_auth_decode_ntlm_type2_message(data, serverdata,
-                                                 &conn->ntlm);
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_decode_ntlm_type2_message(data, &serverdata,
+                                                   &conn->ntlm);
     if(!result)
     if(!result)
       result = Curl_auth_create_ntlm_type3_message(data, conn->user,
       result = Curl_auth_create_ntlm_type3_message(data, conn->user,
                                                    conn->passwd, &conn->ntlm,
                                                    conn->passwd, &conn->ntlm,
-                                                   &resp, &len);
+                                                   &resp);
     break;
     break;
 #endif
 #endif
 
 
@@ -531,55 +608,59 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
     result = Curl_auth_create_gssapi_user_message(data, conn->user,
     result = Curl_auth_create_gssapi_user_message(data, conn->user,
                                                   conn->passwd,
                                                   conn->passwd,
                                                   service,
                                                   service,
-                                                  data->conn->host.name,
+                                                  conn->host.name,
                                                   sasl->mutual_auth, NULL,
                                                   sasl->mutual_auth, NULL,
                                                   &conn->krb5,
                                                   &conn->krb5,
-                                                  &resp, &len);
+                                                  &resp);
     newstate = SASL_GSSAPI_TOKEN;
     newstate = SASL_GSSAPI_TOKEN;
     break;
     break;
   case SASL_GSSAPI_TOKEN:
   case SASL_GSSAPI_TOKEN:
-    sasl->params->getmessage(data->state.buffer, &serverdata);
-    if(sasl->mutual_auth) {
-      /* Decode the user token challenge and create the optional response
-         message */
-      result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
-                                                    NULL, NULL,
-                                                    sasl->mutual_auth,
-                                                    serverdata, &conn->krb5,
-                                                    &resp, &len);
-      newstate = SASL_GSSAPI_NO_DATA;
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result) {
+      if(sasl->mutual_auth) {
+        /* Decode the user token challenge and create the optional response
+           message */
+        result = Curl_auth_create_gssapi_user_message(data, NULL, NULL,
+                                                      NULL, NULL,
+                                                      sasl->mutual_auth,
+                                                      &serverdata,
+                                                      &conn->krb5,
+                                                      &resp);
+        newstate = SASL_GSSAPI_NO_DATA;
+      }
+      else
+        /* Decode the security challenge and create the response message */
+        result = Curl_auth_create_gssapi_security_message(data, &serverdata,
+                                                          &conn->krb5,
+                                                          &resp);
     }
     }
-    else
-      /* Decode the security challenge and create the response message */
-      result = Curl_auth_create_gssapi_security_message(data, serverdata,
-                                                        &conn->krb5,
-                                                        &resp, &len);
     break;
     break;
   case SASL_GSSAPI_NO_DATA:
   case SASL_GSSAPI_NO_DATA:
-    sasl->params->getmessage(data->state.buffer, &serverdata);
     /* Decode the security challenge and create the response message */
     /* Decode the security challenge and create the response message */
-    result = Curl_auth_create_gssapi_security_message(data, serverdata,
-                                                      &conn->krb5,
-                                                      &resp, &len);
+    result = get_server_message(sasl, data, &serverdata);
+    if(!result)
+      result = Curl_auth_create_gssapi_security_message(data, &serverdata,
+                                                        &conn->krb5,
+                                                        &resp);
     break;
     break;
 #endif
 #endif
 
 
   case SASL_OAUTH2:
   case SASL_OAUTH2:
     /* Create the authorisation message */
     /* Create the authorisation message */
     if(sasl->authused == SASL_MECH_OAUTHBEARER) {
     if(sasl->authused == SASL_MECH_OAUTHBEARER) {
-      result = Curl_auth_create_oauth_bearer_message(data, conn->user,
+      result = Curl_auth_create_oauth_bearer_message(conn->user,
                                                      hostname,
                                                      hostname,
                                                      port,
                                                      port,
                                                      oauth_bearer,
                                                      oauth_bearer,
-                                                     &resp, &len);
+                                                     &resp);
 
 
       /* Failures maybe sent by the server as continuations for OAUTHBEARER */
       /* Failures maybe sent by the server as continuations for OAUTHBEARER */
       newstate = SASL_OAUTH2_RESP;
       newstate = SASL_OAUTH2_RESP;
     }
     }
     else
     else
-      result = Curl_auth_create_xoauth_bearer_message(data, conn->user,
+      result = Curl_auth_create_xoauth_bearer_message(conn->user,
                                                       oauth_bearer,
                                                       oauth_bearer,
-                                                      &resp, &len);
+                                                      &resp);
     break;
     break;
 
 
   case SASL_OAUTH2_RESP:
   case SASL_OAUTH2_RESP:
@@ -591,11 +672,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
       return result;
       return result;
     }
     }
     else if(code == sasl->params->contcode) {
     else if(code == sasl->params->contcode) {
-      /* Acknowledge the continuation by sending a 0x01 response base64
-         encoded */
-      resp = strdup("AQ==");
-      if(!resp)
-        result = CURLE_OUT_OF_MEMORY;
+      /* Acknowledge the continuation by sending a 0x01 response. */
+      Curl_bufref_set(&resp, "\x01", 1, NULL);
       break;
       break;
     }
     }
     else {
     else {
@@ -609,15 +687,15 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
     sasl->authmechs ^= sasl->authused;
     sasl->authmechs ^= sasl->authused;
 
 
     /* Start an alternative SASL authentication */
     /* Start an alternative SASL authentication */
-    result = Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
-    newstate = sasl->state;   /* Use state from Curl_sasl_start() */
-    break;
+    return Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
   default:
   default:
     failf(data, "Unsupported SASL authentication mechanism");
     failf(data, "Unsupported SASL authentication mechanism");
     result = CURLE_UNSUPPORTED_PROTOCOL;  /* Should not happen */
     result = CURLE_UNSUPPORTED_PROTOCOL;  /* Should not happen */
     break;
     break;
   }
   }
 
 
+  Curl_bufref_free(&serverdata);
+
   switch(result) {
   switch(result) {
   case CURLE_BAD_CONTENT_ENCODING:
   case CURLE_BAD_CONTENT_ENCODING:
     /* Cancel dialog */
     /* Cancel dialog */
@@ -625,8 +703,10 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
     newstate = SASL_CANCEL;
     newstate = SASL_CANCEL;
     break;
     break;
   case CURLE_OK:
   case CURLE_OK:
-    if(resp)
-      result = sasl->params->sendcont(data, conn, resp);
+    result = build_message(data, &resp);
+    if(!result)
+      result = sasl->params->sendcont(data, conn,
+                                      (const char *) Curl_bufref_ptr(&resp));
     break;
     break;
   default:
   default:
     newstate = SASL_STOP;    /* Stop on error */
     newstate = SASL_STOP;    /* Stop on error */
@@ -634,7 +714,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
     break;
     break;
   }
   }
 
 
-  free(resp);
+  Curl_bufref_free(&resp);
 
 
   state(sasl, data, newstate);
   state(sasl, data, newstate);
 
 

+ 11 - 6
lib/curl_sasl.h

@@ -37,10 +37,12 @@ struct connectdata;
 #define SASL_MECH_NTLM              (1 << 6)
 #define SASL_MECH_NTLM              (1 << 6)
 #define SASL_MECH_XOAUTH2           (1 << 7)
 #define SASL_MECH_XOAUTH2           (1 << 7)
 #define SASL_MECH_OAUTHBEARER       (1 << 8)
 #define SASL_MECH_OAUTHBEARER       (1 << 8)
+#define SASL_MECH_SCRAM_SHA_1       (1 << 9)
+#define SASL_MECH_SCRAM_SHA_256     (1 << 10)
 
 
 /* Authentication mechanism values */
 /* Authentication mechanism values */
 #define SASL_AUTH_NONE          0
 #define SASL_AUTH_NONE          0
-#define SASL_AUTH_ANY           ~0U
+#define SASL_AUTH_ANY           0xffff
 #define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
 #define SASL_AUTH_DEFAULT       (SASL_AUTH_ANY & ~SASL_MECH_EXTERNAL)
 
 
 /* Authentication mechanism strings */
 /* Authentication mechanism strings */
@@ -53,6 +55,8 @@ struct connectdata;
 #define SASL_MECH_STRING_NTLM         "NTLM"
 #define SASL_MECH_STRING_NTLM         "NTLM"
 #define SASL_MECH_STRING_XOAUTH2      "XOAUTH2"
 #define SASL_MECH_STRING_XOAUTH2      "XOAUTH2"
 #define SASL_MECH_STRING_OAUTHBEARER  "OAUTHBEARER"
 #define SASL_MECH_STRING_OAUTHBEARER  "OAUTHBEARER"
+#define SASL_MECH_STRING_SCRAM_SHA_1  "SCRAM-SHA-1"
+#define SASL_MECH_STRING_SCRAM_SHA_256 "SCRAM-SHA-256"
 
 
 /* SASL machine states */
 /* SASL machine states */
 typedef enum {
 typedef enum {
@@ -71,6 +75,7 @@ typedef enum {
   SASL_GSSAPI_NO_DATA,
   SASL_GSSAPI_NO_DATA,
   SASL_OAUTH2,
   SASL_OAUTH2,
   SASL_OAUTH2_RESP,
   SASL_OAUTH2_RESP,
+  SASL_GSASL,
   SASL_CANCEL,
   SASL_CANCEL,
   SASL_FINAL
   SASL_FINAL
 } saslstate;
 } saslstate;
@@ -103,9 +108,9 @@ struct SASLproto {
 struct SASL {
 struct SASL {
   const struct SASLproto *params; /* Protocol dependent parameters */
   const struct SASLproto *params; /* Protocol dependent parameters */
   saslstate state;         /* Current machine state */
   saslstate state;         /* Current machine state */
-  unsigned int authmechs;  /* Accepted authentication mechanisms */
-  unsigned int prefmech;   /* Preferred authentication mechanism */
-  unsigned int authused;   /* Auth mechanism used for the connection */
+  unsigned short authmechs;  /* Accepted authentication mechanisms */
+  unsigned short prefmech;   /* Preferred authentication mechanism */
+  unsigned short authused;   /* Auth mechanism used for the connection */
   bool resetprefs;         /* For URL auth option parsing. */
   bool resetprefs;         /* For URL auth option parsing. */
   bool mutual_auth;        /* Mutual authentication enabled (GSSAPI only) */
   bool mutual_auth;        /* Mutual authentication enabled (GSSAPI only) */
   bool force_ir;           /* Protocol always supports initial response */
   bool force_ir;           /* Protocol always supports initial response */
@@ -121,8 +126,8 @@ struct SASL {
 void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
 void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused);
 
 
 /* Convert a mechanism name to a token */
 /* Convert a mechanism name to a token */
-unsigned int Curl_sasl_decode_mech(const char *ptr,
-                                   size_t maxlen, size_t *len);
+unsigned short Curl_sasl_decode_mech(const char *ptr,
+                                     size_t maxlen, size_t *len);
 
 
 /* Parse the URL login options */
 /* Parse the URL login options */
 CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,
 CURLcode Curl_sasl_parse_url_auth_option(struct SASL *sasl,

+ 46 - 25
lib/curl_setup.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -54,6 +54,16 @@
 #  ifndef NOGDI
 #  ifndef NOGDI
 #    define NOGDI
 #    define NOGDI
 #  endif
 #  endif
+/* Detect Windows App environment which has a restricted access
+ * to the Win32 APIs. */
+# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
+  defined(WINAPI_FAMILY)
+#  include <winapifamily.h>
+#  if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) &&  \
+     !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#    define CURL_WINDOWS_APP
+#  endif
+# endif
 #endif
 #endif
 
 
 /*
 /*
@@ -151,8 +161,6 @@
 
 
 #include <curl/curl.h>
 #include <curl/curl.h>
 
 
-#define CURL_SIZEOF_CURL_OFF_T SIZEOF_CURL_OFF_T
-
 /*
 /*
  * Disable other protocols when http is the only one desired.
  * Disable other protocols when http is the only one desired.
  */
  */
@@ -239,7 +247,11 @@
  * performing this task will result in a synthesized IPv6 address.
  * performing this task will result in a synthesized IPv6 address.
  */
  */
 #if defined(__APPLE__) && !defined(USE_ARES)
 #if defined(__APPLE__) && !defined(USE_ARES)
+#include <TargetConditionals.h>
 #define USE_RESOLVE_ON_IPS 1
 #define USE_RESOLVE_ON_IPS 1
+#  if defined(TARGET_OS_OSX) && TARGET_OS_OSX
+#    define CURL_OSX_CALL_COPYPROXIES 1
+#  endif
 #endif
 #endif
 
 
 #ifdef USE_LWIPSOCK
 #ifdef USE_LWIPSOCK
@@ -335,8 +347,10 @@
 #  define stat(fname,stp)            curlx_win32_stat(fname, stp)
 #  define stat(fname,stp)            curlx_win32_stat(fname, stp)
 #  define struct_stat                struct _stati64
 #  define struct_stat                struct _stati64
 #  define LSEEK_ERROR                (__int64)-1
 #  define LSEEK_ERROR                (__int64)-1
+#  define open                       curlx_win32_open
 #  define fopen(fname,mode)          curlx_win32_fopen(fname, mode)
 #  define fopen(fname,mode)          curlx_win32_fopen(fname, mode)
 #  define access(fname,mode)         curlx_win32_access(fname, mode)
 #  define access(fname,mode)         curlx_win32_access(fname, mode)
+   int curlx_win32_open(const char *filename, int oflag, ...);
    int curlx_win32_stat(const char *path, struct_stat *buffer);
    int curlx_win32_stat(const char *path, struct_stat *buffer);
    FILE *curlx_win32_fopen(const char *filename, const char *mode);
    FILE *curlx_win32_fopen(const char *filename, const char *mode);
    int curlx_win32_access(const char *path, int mode);
    int curlx_win32_access(const char *path, int mode);
@@ -356,9 +370,11 @@
 #    define fstat(fdes,stp)            _fstat(fdes, stp)
 #    define fstat(fdes,stp)            _fstat(fdes, stp)
 #    define stat(fname,stp)            curlx_win32_stat(fname, stp)
 #    define stat(fname,stp)            curlx_win32_stat(fname, stp)
 #    define struct_stat                struct _stat
 #    define struct_stat                struct _stat
+#    define open                       curlx_win32_open
 #    define fopen(fname,mode)          curlx_win32_fopen(fname, mode)
 #    define fopen(fname,mode)          curlx_win32_fopen(fname, mode)
 #    define access(fname,mode)         curlx_win32_access(fname, mode)
 #    define access(fname,mode)         curlx_win32_access(fname, mode)
      int curlx_win32_stat(const char *path, struct_stat *buffer);
      int curlx_win32_stat(const char *path, struct_stat *buffer);
+     int curlx_win32_open(const char *filename, int oflag, ...);
      FILE *curlx_win32_fopen(const char *filename, const char *mode);
      FILE *curlx_win32_fopen(const char *filename, const char *mode);
      int curlx_win32_access(const char *path, int mode);
      int curlx_win32_access(const char *path, int mode);
 #  endif
 #  endif
@@ -408,7 +424,7 @@
 #if (SIZEOF_CURL_OFF_T == 4)
 #if (SIZEOF_CURL_OFF_T == 4)
 #  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
 #  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
 #else
 #else
-   /* assume CURL_SIZEOF_CURL_OFF_T == 8 */
+   /* assume SIZEOF_CURL_OFF_T == 8 */
 #  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
 #  define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
 #endif
 #endif
 #define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
 #define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
@@ -505,7 +521,6 @@
 #    undef HAVE_GETADDRINFO_THREADSAFE
 #    undef HAVE_GETADDRINFO_THREADSAFE
 #    undef HAVE_FREEADDRINFO
 #    undef HAVE_FREEADDRINFO
 #    undef HAVE_GETADDRINFO
 #    undef HAVE_GETADDRINFO
-#    undef HAVE_GETNAMEINFO
 #    undef ENABLE_IPV6
 #    undef ENABLE_IPV6
 #  endif
 #  endif
 #endif
 #endif
@@ -612,7 +627,7 @@ int netware_init(void);
     defined(USE_MBEDTLS) || \
     defined(USE_MBEDTLS) || \
     defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
     defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
     defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) || \
     defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) || \
-    defined(USE_BEARSSL)
+    defined(USE_BEARSSL) || defined(USE_RUSTLS)
 #define USE_SSL    /* SSL support has been enabled */
 #define USE_SSL    /* SSL support has been enabled */
 #endif
 #endif
 
 
@@ -629,7 +644,7 @@ int netware_init(void);
 #endif
 #endif
 
 
 /* Single point where USE_NTLM definition might be defined */
 /* Single point where USE_NTLM definition might be defined */
-#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#ifndef CURL_DISABLE_CRYPTO_AUTH
 #if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                     \
 #if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                     \
   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) ||              \
@@ -703,13 +718,19 @@ int netware_init(void);
 #endif
 #endif
 
 
 /*
 /*
- * Portable symbolic names for Winsock shutdown() mode flags.
+ * shutdown() flags for systems that don't define them
  */
  */
 
 
-#ifdef USE_WINSOCK
-#  define SHUT_RD   0x00
-#  define SHUT_WR   0x01
-#  define SHUT_RDWR 0x02
+#ifndef SHUT_RD
+#define SHUT_RD 0x00
+#endif
+
+#ifndef SHUT_WR
+#define SHUT_WR 0x01
+#endif
+
+#ifndef SHUT_RDWR
+#define SHUT_RDWR 0x02
 #endif
 #endif
 
 
 /* Define S_ISREG if not defined by system headers, f.e. MSVC */
 /* Define S_ISREG if not defined by system headers, f.e. MSVC */
@@ -760,20 +781,16 @@ endings either CRLF or LF so 't' is appropriate.
 #  endif
 #  endif
 #endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUND */
 #endif /* DONT_USE_RECV_BEFORE_SEND_WORKAROUND */
 
 
-/* Detect Windows App environment which has a restricted access
- * to the Win32 APIs. */
-# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
-  defined(WINAPI_FAMILY)
-#  include <winapifamily.h>
-#  if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) &&  \
-     !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-#    define CURL_WINDOWS_APP
-#  endif
-# endif
-
-/* for systems that don't detect this in configure, use a sensible default */
+/* for systems that don't detect this in configure */
 #ifndef CURL_SA_FAMILY_T
 #ifndef CURL_SA_FAMILY_T
-#define CURL_SA_FAMILY_T unsigned short
+#  if defined(HAVE_SA_FAMILY_T)
+#    define CURL_SA_FAMILY_T sa_family_t
+#  elif defined(HAVE_ADDRESS_FAMILY)
+#    define CURL_SA_FAMILY_T ADDRESS_FAMILY
+#  else
+/* use a sensible default */
+#    define CURL_SA_FAMILY_T unsigned short
+#  endif
 #endif
 #endif
 
 
 /* Some convenience macros to get the larger/smaller value out of two given.
 /* Some convenience macros to get the larger/smaller value out of two given.
@@ -794,6 +811,10 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #define UNITTEST static
 #define UNITTEST static
 #endif
 #endif
 
 
+#if defined(USE_NGHTTP2) || defined(USE_HYPER)
+#define USE_HTTP2
+#endif
+
 #if defined(USE_NGTCP2) || defined(USE_QUICHE)
 #if defined(USE_NGTCP2) || defined(USE_QUICHE)
 #define ENABLE_QUIC
 #define ENABLE_QUIC
 #endif
 #endif

+ 2 - 17
lib/curl_setup_once.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -32,6 +32,7 @@
 #include <string.h>
 #include <string.h>
 #include <stdarg.h>
 #include <stdarg.h>
 #include <ctype.h>
 #include <ctype.h>
+#include <time.h>
 
 
 #ifdef HAVE_ERRNO_H
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #include <errno.h>
@@ -55,13 +56,6 @@
 
 
 #ifdef HAVE_SYS_TIME_H
 #ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
 #include <sys/time.h>
-#ifdef TIME_WITH_SYS_TIME
-#include <time.h>
-#endif
-#else
-#ifdef HAVE_TIME_H
-#include <time.h>
-#endif
 #endif
 #endif
 
 
 #ifdef WIN32
 #ifdef WIN32
@@ -350,15 +344,6 @@ typedef int sig_atomic_t;
 #endif
 #endif
 
 
 
 
-/*
- * Default return type for signal handlers.
- */
-
-#ifndef RETSIGTYPE
-#define RETSIGTYPE void
-#endif
-
-
 /*
 /*
  * Macro used to include code only in debug builds.
  * Macro used to include code only in debug builds.
  */
  */

+ 6 - 5
lib/dict.c

@@ -89,6 +89,7 @@ const struct Curl_handler Curl_handler_dict = {
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_DICT,                            /* defport */
   PORT_DICT,                            /* defport */
   CURLPROTO_DICT,                       /* protocol */
   CURLPROTO_DICT,                       /* protocol */
   CURLPROTO_DICT,                       /* family */
   CURLPROTO_DICT,                       /* family */
@@ -214,14 +215,14 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
       }
       }
     }
     }
 
 
-    if((word == NULL) || (*word == (char)0)) {
+    if(!word || (*word == (char)0)) {
       infof(data, "lookup word is missing\n");
       infof(data, "lookup word is missing\n");
       word = (char *)"default";
       word = (char *)"default";
     }
     }
-    if((database == NULL) || (*database == (char)0)) {
+    if(!database || (*database == (char)0)) {
       database = (char *)"!";
       database = (char *)"!";
     }
     }
-    if((strategy == NULL) || (*strategy == (char)0)) {
+    if(!strategy || (*strategy == (char)0)) {
       strategy = (char *)".";
       strategy = (char *)".";
     }
     }
 
 
@@ -265,11 +266,11 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
       }
       }
     }
     }
 
 
-    if((word == NULL) || (*word == (char)0)) {
+    if(!word || (*word == (char)0)) {
       infof(data, "lookup word is missing\n");
       infof(data, "lookup word is missing\n");
       word = (char *)"default";
       word = (char *)"default";
     }
     }
-    if((database == NULL) || (*database == (char)0)) {
+    if(!database || (*database == (char)0)) {
       database = (char *)"!";
       database = (char *)"!";
     }
     }
 
 

+ 67 - 58
lib/doh.c

@@ -207,10 +207,12 @@ static int doh_done(struct Curl_easy *doh, CURLcode result)
 }
 }
 
 
 #define ERROR_CHECK_SETOPT(x,y) \
 #define ERROR_CHECK_SETOPT(x,y) \
-do {                                      \
-  result = curl_easy_setopt(doh, x, y);   \
-  if(result)                              \
-    goto error;                           \
+do {                                          \
+  result = curl_easy_setopt(doh, x, y);       \
+  if(result &&                                \
+     result != CURLE_NOT_BUILT_IN &&          \
+     result != CURLE_UNKNOWN_OPTION)          \
+    goto error;                               \
 } while(0)
 } while(0)
 
 
 static CURLcode dohprobe(struct Curl_easy *data,
 static CURLcode dohprobe(struct Curl_easy *data,
@@ -282,84 +284,93 @@ static CURLcode dohprobe(struct Curl_easy *data,
     ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
     ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS);
 #endif
 #endif
     ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
     ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms);
+    ERROR_CHECK_SETOPT(CURLOPT_SHARE, data->share);
+    if(data->set.err && data->set.err != stderr)
+      ERROR_CHECK_SETOPT(CURLOPT_STDERR, data->set.err);
     if(data->set.verbose)
     if(data->set.verbose)
       ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
       ERROR_CHECK_SETOPT(CURLOPT_VERBOSE, 1L);
     if(data->set.no_signal)
     if(data->set.no_signal)
       ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
       ERROR_CHECK_SETOPT(CURLOPT_NOSIGNAL, 1L);
 
 
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST,
+      data->set.doh_verifyhost ? 2L : 0L);
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER,
+      data->set.doh_verifypeer ? 1L : 0L);
+    ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS,
+      data->set.doh_verifystatus ? 1L : 0L);
+
     /* Inherit *some* SSL options from the user's transfer. This is a
     /* Inherit *some* SSL options from the user's transfer. This is a
-       best-guess as to which options are needed for compatibility. #3661 */
+       best-guess as to which options are needed for compatibility. #3661
+
+       Note DOH does not inherit the user's proxy server so proxy SSL settings
+       have no effect and are not inherited. If that changes then two new
+       options should be added to check doh proxy insecure separately,
+       CURLOPT_DOH_PROXY_SSL_VERIFYHOST and CURLOPT_DOH_PROXY_SSL_VERIFYPEER.
+       */
     if(data->set.ssl.falsestart)
     if(data->set.ssl.falsestart)
       ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
       ERROR_CHECK_SETOPT(CURLOPT_SSL_FALSESTART, 1L);
-    if(data->set.ssl.primary.verifyhost)
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYHOST, 2L);
-#ifndef CURL_DISABLE_PROXY
-    if(data->set.proxy_ssl.primary.verifyhost)
-      ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYHOST, 2L);
-    if(data->set.proxy_ssl.primary.verifypeer)
-      ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_VERIFYPEER, 1L);
-    if(data->set.str[STRING_SSL_CAFILE_PROXY]) {
-      ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAINFO,
-        data->set.str[STRING_SSL_CAFILE_PROXY]);
-    }
-    if(data->set.str[STRING_SSL_CRLFILE_PROXY]) {
-      ERROR_CHECK_SETOPT(CURLOPT_PROXY_CRLFILE,
-        data->set.str[STRING_SSL_CRLFILE_PROXY]);
-    }
-    if(data->set.proxy_ssl.no_revoke)
-      ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
-    else if(data->set.proxy_ssl.revoke_best_effort)
-      ERROR_CHECK_SETOPT(CURLOPT_PROXY_SSL_OPTIONS,
-                         CURLSSLOPT_REVOKE_BEST_EFFORT);
-    if(data->set.str[STRING_SSL_CAPATH_PROXY]) {
-      ERROR_CHECK_SETOPT(CURLOPT_PROXY_CAPATH,
-        data->set.str[STRING_SSL_CAPATH_PROXY]);
-    }
-#endif
-    if(data->set.ssl.primary.verifypeer)
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYPEER, 1L);
-    if(data->set.ssl.primary.verifystatus)
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_VERIFYSTATUS, 1L);
-    if(data->set.str[STRING_SSL_CAFILE_ORIG]) {
+    if(data->set.str[STRING_SSL_CAFILE]) {
       ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
       ERROR_CHECK_SETOPT(CURLOPT_CAINFO,
-        data->set.str[STRING_SSL_CAFILE_ORIG]);
+                         data->set.str[STRING_SSL_CAFILE]);
+    }
+    if(data->set.blobs[BLOB_CAINFO]) {
+      ERROR_CHECK_SETOPT(CURLOPT_CAINFO_BLOB,
+                         data->set.blobs[BLOB_CAINFO]);
     }
     }
-    if(data->set.str[STRING_SSL_CAPATH_ORIG]) {
+    if(data->set.str[STRING_SSL_CAPATH]) {
       ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
       ERROR_CHECK_SETOPT(CURLOPT_CAPATH,
-        data->set.str[STRING_SSL_CAPATH_ORIG]);
+                         data->set.str[STRING_SSL_CAPATH]);
     }
     }
-    if(data->set.str[STRING_SSL_CRLFILE_ORIG]) {
+    if(data->set.str[STRING_SSL_CRLFILE]) {
       ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
       ERROR_CHECK_SETOPT(CURLOPT_CRLFILE,
-        data->set.str[STRING_SSL_CRLFILE_ORIG]);
+                         data->set.str[STRING_SSL_CRLFILE]);
     }
     }
     if(data->set.ssl.certinfo)
     if(data->set.ssl.certinfo)
       ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
       ERROR_CHECK_SETOPT(CURLOPT_CERTINFO, 1L);
     if(data->set.str[STRING_SSL_RANDOM_FILE]) {
     if(data->set.str[STRING_SSL_RANDOM_FILE]) {
       ERROR_CHECK_SETOPT(CURLOPT_RANDOM_FILE,
       ERROR_CHECK_SETOPT(CURLOPT_RANDOM_FILE,
-        data->set.str[STRING_SSL_RANDOM_FILE]);
+                         data->set.str[STRING_SSL_RANDOM_FILE]);
     }
     }
     if(data->set.str[STRING_SSL_EGDSOCKET]) {
     if(data->set.str[STRING_SSL_EGDSOCKET]) {
       ERROR_CHECK_SETOPT(CURLOPT_EGDSOCKET,
       ERROR_CHECK_SETOPT(CURLOPT_EGDSOCKET,
-        data->set.str[STRING_SSL_EGDSOCKET]);
+                         data->set.str[STRING_SSL_EGDSOCKET]);
     }
     }
-    if(data->set.ssl.no_revoke)
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_NO_REVOKE);
-    else if(data->set.ssl.revoke_best_effort)
-      ERROR_CHECK_SETOPT(CURLOPT_SSL_OPTIONS, CURLSSLOPT_REVOKE_BEST_EFFORT);
     if(data->set.ssl.fsslctx)
     if(data->set.ssl.fsslctx)
       ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
       ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_FUNCTION, data->set.ssl.fsslctx);
     if(data->set.ssl.fsslctxp)
     if(data->set.ssl.fsslctxp)
       ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
       ERROR_CHECK_SETOPT(CURLOPT_SSL_CTX_DATA, data->set.ssl.fsslctxp);
     if(data->set.str[STRING_SSL_EC_CURVES]) {
     if(data->set.str[STRING_SSL_EC_CURVES]) {
       ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
       ERROR_CHECK_SETOPT(CURLOPT_SSL_EC_CURVES,
-        data->set.str[STRING_SSL_EC_CURVES]);
+                         data->set.str[STRING_SSL_EC_CURVES]);
+    }
+
+    {
+      long mask =
+        (data->set.ssl.enable_beast ?
+         CURLSSLOPT_ALLOW_BEAST : 0) |
+        (data->set.ssl.no_revoke ?
+         CURLSSLOPT_NO_REVOKE : 0) |
+        (data->set.ssl.no_partialchain ?
+         CURLSSLOPT_NO_PARTIALCHAIN : 0) |
+        (data->set.ssl.revoke_best_effort ?
+         CURLSSLOPT_REVOKE_BEST_EFFORT : 0) |
+        (data->set.ssl.native_ca_store ?
+         CURLSSLOPT_NATIVE_CA : 0) |
+        (data->set.ssl.auto_client_cert ?
+         CURLSSLOPT_AUTO_CLIENT_CERT : 0);
+
+      curl_easy_setopt(doh, CURLOPT_SSL_OPTIONS, mask);
     }
     }
 
 
     doh->set.fmultidone = doh_done;
     doh->set.fmultidone = doh_done;
     doh->set.dohfor = data; /* identify for which transfer this is done */
     doh->set.dohfor = data; /* identify for which transfer this is done */
     p->easy = doh;
     p->easy = doh;
 
 
-    /* add this transfer to the multi handle */
+    /* DOH private_data must be null because the user must have a way to
+       distinguish their transfer's handle from DOH handles in user
+       callbacks (ie SSL CTX callback). */
+    DEBUGASSERT(!data->set.private_data);
+
     if(curl_multi_add_handle(multi, doh))
     if(curl_multi_add_handle(multi, doh))
       goto error;
       goto error;
   }
   }
@@ -409,17 +420,15 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
   if(!dohp->headers)
   if(!dohp->headers)
     goto error;
     goto error;
 
 
-  if(conn->ip_version != CURL_IPRESOLVE_V6) {
-    /* create IPv4 DOH request */
-    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
-                      DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
-                      data->multi, dohp->headers);
-    if(result)
-      goto error;
-    dohp->pending++;
-  }
+  /* create IPv4 DOH request */
+  result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
+                    DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
+                    data->multi, dohp->headers);
+  if(result)
+    goto error;
+  dohp->pending++;
 
 
-  if(conn->ip_version != CURL_IPRESOLVE_V4) {
+  if(Curl_ipv6works(data)) {
     /* create IPv6 DOH request */
     /* create IPv6 DOH request */
     result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
     result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
                       DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
                       DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],

+ 2 - 2
lib/dynbuf.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2020, 2021, 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
@@ -74,7 +74,7 @@ int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
 #define DYN_DOH_CNAME       256
 #define DYN_DOH_CNAME       256
 #define DYN_PAUSE_BUFFER    (64 * 1024 * 1024)
 #define DYN_PAUSE_BUFFER    (64 * 1024 * 1024)
 #define DYN_HAXPROXY        2048
 #define DYN_HAXPROXY        2048
-#define DYN_HTTP_REQUEST    (128*1024)
+#define DYN_HTTP_REQUEST    (1024*1024)
 #define DYN_H2_HEADERS      (128*1024)
 #define DYN_H2_HEADERS      (128*1024)
 #define DYN_H2_TRAILERS     (128*1024)
 #define DYN_H2_TRAILERS     (128*1024)
 #define DYN_APRINTF         8000000
 #define DYN_APRINTF         8000000

+ 24 - 34
lib/easy.c

@@ -789,7 +789,6 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
   /* duplicate all blobs */
   /* duplicate all blobs */
   for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
   for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
     result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
     result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
-    /* Curl_setstropt return CURLE_BAD_FUNCTION_ARGUMENT with blob */
     if(result)
     if(result)
       return result;
       return result;
   }
   }
@@ -810,7 +809,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
   result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost);
   result = Curl_mime_duppart(&dst->set.mimepost, &src->set.mimepost);
 
 
   if(src->set.resolve)
   if(src->set.resolve)
-    dst->change.resolve = dst->set.resolve;
+    dst->state.resolve = dst->set.resolve;
 
 
   return result;
   return result;
 }
 }
@@ -858,25 +857,25 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
   }
   }
 
 
   /* duplicate all values in 'change' */
   /* duplicate all values in 'change' */
-  if(data->change.cookielist) {
-    outcurl->change.cookielist =
-      Curl_slist_duplicate(data->change.cookielist);
-    if(!outcurl->change.cookielist)
+  if(data->state.cookielist) {
+    outcurl->state.cookielist =
+      Curl_slist_duplicate(data->state.cookielist);
+    if(!outcurl->state.cookielist)
       goto fail;
       goto fail;
   }
   }
 
 
-  if(data->change.url) {
-    outcurl->change.url = strdup(data->change.url);
-    if(!outcurl->change.url)
+  if(data->state.url) {
+    outcurl->state.url = strdup(data->state.url);
+    if(!outcurl->state.url)
       goto fail;
       goto fail;
-    outcurl->change.url_alloc = TRUE;
+    outcurl->state.url_alloc = TRUE;
   }
   }
 
 
-  if(data->change.referer) {
-    outcurl->change.referer = strdup(data->change.referer);
-    if(!outcurl->change.referer)
+  if(data->state.referer) {
+    outcurl->state.referer = strdup(data->state.referer);
+    if(!outcurl->state.referer)
       goto fail;
       goto fail;
-    outcurl->change.referer_alloc = TRUE;
+    outcurl->state.referer_alloc = TRUE;
   }
   }
 
 
   /* Reinitialize an SSL engine for the new handle
   /* Reinitialize an SSL engine for the new handle
@@ -895,7 +894,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
       (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
       (void)Curl_altsvc_load(outcurl->asi, outcurl->set.str[STRING_ALTSVC]);
   }
   }
 #endif
 #endif
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
   if(data->hsts) {
   if(data->hsts) {
     outcurl->hsts = Curl_hsts_init();
     outcurl->hsts = Curl_hsts_init();
     if(!outcurl->hsts)
     if(!outcurl->hsts)
@@ -947,12 +946,12 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
   fail:
   fail:
 
 
   if(outcurl) {
   if(outcurl) {
-    curl_slist_free_all(outcurl->change.cookielist);
-    outcurl->change.cookielist = NULL;
+    curl_slist_free_all(outcurl->state.cookielist);
+    outcurl->state.cookielist = NULL;
     Curl_safefree(outcurl->state.buffer);
     Curl_safefree(outcurl->state.buffer);
     Curl_dyn_free(&outcurl->state.headerb);
     Curl_dyn_free(&outcurl->state.headerb);
-    Curl_safefree(outcurl->change.url);
-    Curl_safefree(outcurl->change.referer);
+    Curl_safefree(outcurl->state.url);
+    Curl_safefree(outcurl->state.referer);
     Curl_altsvc_cleanup(&outcurl->asi);
     Curl_altsvc_cleanup(&outcurl->asi);
     Curl_hsts_cleanup(&outcurl->hsts);
     Curl_hsts_cleanup(&outcurl->hsts);
     Curl_freeset(outcurl);
     Curl_freeset(outcurl);
@@ -1034,8 +1033,8 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
 
 
   /* Unpause parts in active mime tree. */
   /* Unpause parts in active mime tree. */
   if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
   if((k->keepon & ~newstate & KEEP_SEND_PAUSE) &&
-     (data->mstate == CURLM_STATE_PERFORM ||
-      data->mstate == CURLM_STATE_TOOFAST) &&
+     (data->mstate == MSTATE_PERFORMING ||
+      data->mstate == MSTATE_RATELIMITING) &&
      data->state.fread_func == (curl_read_callback) Curl_mime_read) {
      data->state.fread_func == (curl_read_callback) Curl_mime_read) {
     Curl_mime_unpause(data->state.in);
     Curl_mime_unpause(data->state.in);
   }
   }
@@ -1052,8 +1051,6 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
       unsigned int i;
       unsigned int i;
       unsigned int count = data->state.tempcount;
       unsigned int count = data->state.tempcount;
       struct tempbuf writebuf[3]; /* there can only be three */
       struct tempbuf writebuf[3]; /* there can only be three */
-      struct connectdata *conn = data->conn;
-      struct Curl_easy *saved_data = NULL;
 
 
       /* copy the structs to allow for immediate re-pausing */
       /* copy the structs to allow for immediate re-pausing */
       for(i = 0; i < data->state.tempcount; i++) {
       for(i = 0; i < data->state.tempcount; i++) {
@@ -1062,12 +1059,6 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
       }
       }
       data->state.tempcount = 0;
       data->state.tempcount = 0;
 
 
-      /* set the connection's current owner */
-      if(conn->data != data) {
-        saved_data = conn->data;
-        conn->data = data;
-      }
-
       for(i = 0; i < count; i++) {
       for(i = 0; i < count; i++) {
         /* even if one function returns error, this loops through and frees
         /* even if one function returns error, this loops through and frees
            all buffers */
            all buffers */
@@ -1078,10 +1069,6 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
         Curl_dyn_free(&writebuf[i].b);
         Curl_dyn_free(&writebuf[i].b);
       }
       }
 
 
-      /* recover previous owner of the connection */
-      if(saved_data)
-        conn->data = saved_data;
-
       if(result)
       if(result)
         return result;
         return result;
     }
     }
@@ -1117,7 +1104,7 @@ static CURLcode easy_connection(struct Curl_easy *data,
                                 curl_socket_t *sfd,
                                 curl_socket_t *sfd,
                                 struct connectdata **connp)
                                 struct connectdata **connp)
 {
 {
-  if(data == NULL)
+  if(!data)
     return CURLE_BAD_FUNCTION_ARGUMENT;
     return CURLE_BAD_FUNCTION_ARGUMENT;
 
 
   /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
   /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
@@ -1183,6 +1170,7 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
   CURLcode result;
   CURLcode result;
   ssize_t n1;
   ssize_t n1;
   struct connectdata *c = NULL;
   struct connectdata *c = NULL;
+  SIGPIPE_VARIABLE(pipe_st);
 
 
   if(Curl_is_in_callback(data))
   if(Curl_is_in_callback(data))
     return CURLE_RECURSIVE_API_CALL;
     return CURLE_RECURSIVE_API_CALL;
@@ -1197,7 +1185,9 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
     Curl_attach_connnection(data, c);
     Curl_attach_connnection(data, c);
 
 
   *n = 0;
   *n = 0;
+  sigpipe_ignore(data, &pipe_st);
   result = Curl_write(data, sfd, buffer, buflen, &n1);
   result = Curl_write(data, sfd, buffer, buflen, &n1);
+  sigpipe_restore(&pipe_st);
 
 
   if(n1 == -1)
   if(n1 == -1)
     return CURLE_SEND_ERROR;
     return CURLE_SEND_ERROR;

+ 6 - 1
lib/easyoptions.c

@@ -38,6 +38,7 @@ struct curl_easyoption Curl_easyopts[] = {
   {"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0},
   {"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0},
   {"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0},
   {"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0},
   {"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
   {"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
+  {"CAINFO_BLOB", CURLOPT_CAINFO_BLOB, CURLOT_BLOB, 0},
   {"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
   {"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
   {"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0},
   {"CERTINFO", CURLOPT_CERTINFO, CURLOT_LONG, 0},
   {"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0},
   {"CHUNK_BGN_FUNCTION", CURLOPT_CHUNK_BGN_FUNCTION, CURLOT_FUNCTION, 0},
@@ -78,6 +79,9 @@ struct curl_easyoption Curl_easyopts[] = {
   {"DNS_SERVERS", CURLOPT_DNS_SERVERS, CURLOT_STRING, 0},
   {"DNS_SERVERS", CURLOPT_DNS_SERVERS, CURLOT_STRING, 0},
   {"DNS_SHUFFLE_ADDRESSES", CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOT_LONG, 0},
   {"DNS_SHUFFLE_ADDRESSES", CURLOPT_DNS_SHUFFLE_ADDRESSES, CURLOT_LONG, 0},
   {"DNS_USE_GLOBAL_CACHE", CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOT_LONG, 0},
   {"DNS_USE_GLOBAL_CACHE", CURLOPT_DNS_USE_GLOBAL_CACHE, CURLOT_LONG, 0},
+  {"DOH_SSL_VERIFYHOST", CURLOPT_DOH_SSL_VERIFYHOST, CURLOT_LONG, 0},
+  {"DOH_SSL_VERIFYPEER", CURLOPT_DOH_SSL_VERIFYPEER, CURLOT_LONG, 0},
+  {"DOH_SSL_VERIFYSTATUS", CURLOPT_DOH_SSL_VERIFYSTATUS, CURLOT_LONG, 0},
   {"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0},
   {"DOH_URL", CURLOPT_DOH_URL, CURLOT_STRING, 0},
   {"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0},
   {"EGDSOCKET", CURLOPT_EGDSOCKET, CURLOT_STRING, 0},
   {"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS},
   {"ENCODING", CURLOPT_ACCEPT_ENCODING, CURLOT_STRING, CURLOT_FLAG_ALIAS},
@@ -202,6 +206,7 @@ struct curl_easyoption Curl_easyopts[] = {
   {"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0},
   {"PROXYUSERNAME", CURLOPT_PROXYUSERNAME, CURLOT_STRING, 0},
   {"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0},
   {"PROXYUSERPWD", CURLOPT_PROXYUSERPWD, CURLOT_STRING, 0},
   {"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0},
   {"PROXY_CAINFO", CURLOPT_PROXY_CAINFO, CURLOT_STRING, 0},
+  {"PROXY_CAINFO_BLOB", CURLOPT_PROXY_CAINFO_BLOB, CURLOT_BLOB, 0},
   {"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0},
   {"PROXY_CAPATH", CURLOPT_PROXY_CAPATH, CURLOT_STRING, 0},
   {"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0},
   {"PROXY_CRLFILE", CURLOPT_PROXY_CRLFILE, CURLOT_STRING, 0},
   {"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0},
   {"PROXY_ISSUERCERT", CURLOPT_PROXY_ISSUERCERT, CURLOT_STRING, 0},
@@ -349,6 +354,6 @@ struct curl_easyoption Curl_easyopts[] = {
  */
  */
 int Curl_easyopts_check(void)
 int Curl_easyopts_check(void)
 {
 {
-  return ((CURLOPT_LASTENTRY%10000) != (305 + 1));
+  return ((CURLOPT_LASTENTRY%10000) != (310 + 1));
 }
 }
 #endif
 #endif

+ 24 - 16
lib/file.c

@@ -111,6 +111,7 @@ const struct Curl_handler Curl_handler_file = {
   file_disconnect,                      /* disconnect */
   file_disconnect,                      /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   0,                                    /* defport */
   0,                                    /* defport */
   CURLPROTO_FILE,                       /* protocol */
   CURLPROTO_FILE,                       /* protocol */
   CURLPROTO_FILE,                       /* family */
   CURLPROTO_FILE,                       /* family */
@@ -410,19 +411,21 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
     struct tm buffer;
     struct tm buffer;
     const struct tm *tm = &buffer;
     const struct tm *tm = &buffer;
     char header[80];
     char header[80];
+    int headerlen;
+    char accept_ranges[24]= { "Accept-ranges: bytes\r\n" };
     if(expected_size >= 0) {
     if(expected_size >= 0) {
-      msnprintf(header, sizeof(header),
+      headerlen = msnprintf(header, sizeof(header),
                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
                 expected_size);
                 expected_size);
-      result = Curl_client_write(data, CLIENTWRITE_HEADER, header, 0);
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
       if(result)
       if(result)
         return result;
         return result;
-    }
 
 
-    result = Curl_client_write(data, CLIENTWRITE_HEADER,
-                               (char *)"Accept-ranges: bytes\r\n", 0);
-    if(result)
-      return result;
+      result = Curl_client_write(data, CLIENTWRITE_HEADER,
+                                 accept_ranges, strlen(accept_ranges));
+      if(result != CURLE_OK)
+        return result;
+    }
 
 
     filetime = (time_t)statbuf.st_mtime;
     filetime = (time_t)statbuf.st_mtime;
     result = Curl_gmtime(filetime, &buffer);
     result = Curl_gmtime(filetime, &buffer);
@@ -430,7 +433,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
       return result;
       return result;
 
 
     /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
     /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
-    msnprintf(header, sizeof(header),
+    headerlen = msnprintf(header, sizeof(header),
               "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
               "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n%s",
               Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
               Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
               tm->tm_mday,
               tm->tm_mday,
@@ -440,7 +443,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
               tm->tm_min,
               tm->tm_min,
               tm->tm_sec,
               tm->tm_sec,
               data->set.opt_no_body ? "": "\r\n");
               data->set.opt_no_body ? "": "\r\n");
-    result = Curl_client_write(data, CLIENTWRITE_HEADER, header, 0);
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, header, headerlen);
     if(result)
     if(result)
       return result;
       return result;
     /* set the file size to make it available post transfer */
     /* set the file size to make it available post transfer */
@@ -464,18 +467,23 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
     data->state.resume_from += (curl_off_t)statbuf.st_size;
     data->state.resume_from += (curl_off_t)statbuf.st_size;
   }
   }
 
 
-  if(data->state.resume_from <= expected_size)
-    expected_size -= data->state.resume_from;
-  else {
-    failf(data, "failed to resume file:// transfer");
-    return CURLE_BAD_DOWNLOAD_RESUME;
+  if(data->state.resume_from > 0) {
+    /* We check explicitly if we have a start offset, because
+     * expected_size may be -1 if we don't know how large the file is,
+     * in which case we should not adjust it. */
+    if(data->state.resume_from <= expected_size)
+      expected_size -= data->state.resume_from;
+    else {
+      failf(data, "failed to resume file:// transfer");
+      return CURLE_BAD_DOWNLOAD_RESUME;
+    }
   }
   }
 
 
   /* A high water mark has been specified so we obey... */
   /* A high water mark has been specified so we obey... */
   if(data->req.maxdownload > 0)
   if(data->req.maxdownload > 0)
     expected_size = data->req.maxdownload;
     expected_size = data->req.maxdownload;
 
 
-  if(!fstated || (expected_size == 0))
+  if(!fstated || (expected_size <= 0))
     size_known = FALSE;
     size_known = FALSE;
   else
   else
     size_known = TRUE;
     size_known = TRUE;
@@ -484,7 +492,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
      this is both more efficient than the former call to download() and
      this is both more efficient than the former call to download() and
      it avoids problems with select() and recv() on file descriptors
      it avoids problems with select() and recv() on file descriptors
      in Winsock */
      in Winsock */
-  if(fstated)
+  if(size_known)
     Curl_pgrsSetDownloadSize(data, expected_size);
     Curl_pgrsSetDownloadSize(data, expected_size);
 
 
   if(data->state.resume_from) {
   if(data->state.resume_from) {

+ 70 - 51
lib/ftp.c

@@ -175,6 +175,7 @@ const struct Curl_handler Curl_handler_ftp = {
   ftp_disconnect,                  /* disconnect */
   ftp_disconnect,                  /* disconnect */
   ZERO_NULL,                       /* readwrite */
   ZERO_NULL,                       /* readwrite */
   ZERO_NULL,                       /* connection_check */
   ZERO_NULL,                       /* connection_check */
+  ZERO_NULL,                       /* attach connection */
   PORT_FTP,                        /* defport */
   PORT_FTP,                        /* defport */
   CURLPROTO_FTP,                   /* protocol */
   CURLPROTO_FTP,                   /* protocol */
   CURLPROTO_FTP,                   /* family */
   CURLPROTO_FTP,                   /* family */
@@ -205,6 +206,7 @@ const struct Curl_handler Curl_handler_ftps = {
   ftp_disconnect,                  /* disconnect */
   ftp_disconnect,                  /* disconnect */
   ZERO_NULL,                       /* readwrite */
   ZERO_NULL,                       /* readwrite */
   ZERO_NULL,                       /* connection_check */
   ZERO_NULL,                       /* connection_check */
+  ZERO_NULL,                       /* attach connection */
   PORT_FTPS,                       /* defport */
   PORT_FTPS,                       /* defport */
   CURLPROTO_FTPS,                  /* protocol */
   CURLPROTO_FTPS,                  /* protocol */
   CURLPROTO_FTP,                   /* family */
   CURLPROTO_FTP,                   /* family */
@@ -1090,7 +1092,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
   else
   else
     res = NULL; /* failure! */
     res = NULL; /* failure! */
 
 
-  if(res == NULL) {
+  if(!res) {
     failf(data, "failed to resolve the address provided to PORT: %s", host);
     failf(data, "failed to resolve the address provided to PORT: %s", host);
     free(addr);
     free(addr);
     return CURLE_FTP_PORT_FAILED;
     return CURLE_FTP_PORT_FAILED;
@@ -1357,7 +1359,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
   struct FTP *ftp = data->req.p.ftp;
   struct FTP *ftp = data->req.p.ftp;
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
 
 
-  if(ftp->transfer != FTPTRANSFER_BODY) {
+  if(ftp->transfer != PPTRANSFER_BODY) {
     /* doesn't transfer any data */
     /* doesn't transfer any data */
 
 
     /* still possibly do PRE QUOTE jobs */
     /* still possibly do PRE QUOTE jobs */
@@ -1378,7 +1380,7 @@ static CURLcode ftp_state_prepare_transfer(struct Curl_easy *data)
         result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
         result = Curl_pp_sendf(data, &ftpc->pp, "PRET %s",
                                data->set.str[STRING_CUSTOMREQUEST]?
                                data->set.str[STRING_CUSTOMREQUEST]?
                                data->set.str[STRING_CUSTOMREQUEST]:
                                data->set.str[STRING_CUSTOMREQUEST]:
-                               (data->set.ftp_list_only?"NLST":"LIST"));
+                               (data->state.list_only?"NLST":"LIST"));
       else if(data->set.upload)
       else if(data->set.upload)
         result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
         result = Curl_pp_sendf(data, &ftpc->pp, "PRET STOR %s",
                                conn->proto.ftpc.file);
                                conn->proto.ftpc.file);
@@ -1401,7 +1403,7 @@ static CURLcode ftp_state_rest(struct Curl_easy *data,
   struct FTP *ftp = data->req.p.ftp;
   struct FTP *ftp = data->req.p.ftp;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
 
-  if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
+  if((ftp->transfer != PPTRANSFER_BODY) && ftpc->file) {
     /* if a "head"-like request is being made (on a file) */
     /* if a "head"-like request is being made (on a file) */
 
 
     /* Determine if server can respond to REST command and therefore
     /* Determine if server can respond to REST command and therefore
@@ -1423,7 +1425,7 @@ static CURLcode ftp_state_size(struct Curl_easy *data,
   struct FTP *ftp = data->req.p.ftp;
   struct FTP *ftp = data->req.p.ftp;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
 
 
-  if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
+  if((ftp->transfer == PPTRANSFER_INFO) && ftpc->file) {
     /* if a "head"-like request is being made (on a file) */
     /* if a "head"-like request is being made (on a file) */
 
 
     /* we know ftpc->file is a valid pointer to a file name */
     /* we know ftpc->file is a valid pointer to a file name */
@@ -1485,7 +1487,7 @@ static CURLcode ftp_state_list(struct Curl_easy *data)
   cmd = aprintf("%s%s%s",
   cmd = aprintf("%s%s%s",
                 data->set.str[STRING_CUSTOMREQUEST]?
                 data->set.str[STRING_CUSTOMREQUEST]?
                 data->set.str[STRING_CUSTOMREQUEST]:
                 data->set.str[STRING_CUSTOMREQUEST]:
-                (data->set.ftp_list_only?"NLST":"LIST"),
+                (data->state.list_only?"NLST":"LIST"),
                 lstArg? " ": "",
                 lstArg? " ": "",
                 lstArg? lstArg: "");
                 lstArg? lstArg: "");
   free(lstArg);
   free(lstArg);
@@ -1525,17 +1527,17 @@ static CURLcode ftp_state_type(struct Curl_easy *data)
      information. Which in FTP can't be much more than the file size and
      information. Which in FTP can't be much more than the file size and
      date. */
      date. */
   if(data->set.opt_no_body && ftpc->file &&
   if(data->set.opt_no_body && ftpc->file &&
-     ftp_need_type(conn, data->set.prefer_ascii)) {
+     ftp_need_type(conn, data->state.prefer_ascii)) {
     /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
     /* The SIZE command is _not_ RFC 959 specified, and therefore many servers
        may not support it! It is however the only way we have to get a file's
        may not support it! It is however the only way we have to get a file's
        size! */
        size! */
 
 
-    ftp->transfer = FTPTRANSFER_INFO;
+    ftp->transfer = PPTRANSFER_INFO;
     /* this means no actual transfer will be made */
     /* this means no actual transfer will be made */
 
 
     /* Some servers return different sizes for different modes, and thus we
     /* Some servers return different sizes for different modes, and thus we
        must set the proper type before we check the size */
        must set the proper type before we check the size */
-    result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_TYPE);
+    result = ftp_nb_type(data, conn, data->state.prefer_ascii, FTP_TYPE);
     if(result)
     if(result)
       return result;
       return result;
   }
   }
@@ -1578,6 +1580,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   struct FTP *ftp = data->req.p.ftp;
   struct FTP *ftp = data->req.p.ftp;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
   struct ftp_conn *ftpc = &conn->proto.ftpc;
+  bool append = data->set.remote_append;
 
 
   if((data->state.resume_from && !sizechecked) ||
   if((data->state.resume_from && !sizechecked) ||
      ((data->state.resume_from > 0) && sizechecked)) {
      ((data->state.resume_from > 0) && sizechecked)) {
@@ -1604,7 +1607,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
     }
     }
 
 
     /* enable append */
     /* enable append */
-    data->set.ftp_append = TRUE;
+    append = TRUE;
 
 
     /* Let's read off the proper amount of bytes from the input. */
     /* Let's read off the proper amount of bytes from the input. */
     if(conn->seek_func) {
     if(conn->seek_func) {
@@ -1652,7 +1655,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
 
 
         /* Set ->transfer so that we won't get any error in
         /* Set ->transfer so that we won't get any error in
          * ftp_done() because we didn't transfer anything! */
          * ftp_done() because we didn't transfer anything! */
-        ftp->transfer = FTPTRANSFER_NONE;
+        ftp->transfer = PPTRANSFER_NONE;
 
 
         state(data, FTP_STOP);
         state(data, FTP_STOP);
         return CURLE_OK;
         return CURLE_OK;
@@ -1661,8 +1664,7 @@ static CURLcode ftp_state_ul_setup(struct Curl_easy *data,
     /* we've passed, proceed as normal */
     /* we've passed, proceed as normal */
   } /* resume_from */
   } /* resume_from */
 
 
-  result = Curl_pp_sendf(data, &ftpc->pp,
-                         data->set.ftp_append?"APPE %s":"STOR %s",
+  result = Curl_pp_sendf(data, &ftpc->pp, append?"APPE %s":"STOR %s",
                          ftpc->file);
                          ftpc->file);
   if(!result)
   if(!result)
     state(data, FTP_STOR);
     state(data, FTP_STOR);
@@ -1739,7 +1741,7 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
       result = ftp_state_cwd(data, conn);
       result = ftp_state_cwd(data, conn);
       break;
       break;
     case FTP_RETR_PREQUOTE:
     case FTP_RETR_PREQUOTE:
-      if(ftp->transfer != FTPTRANSFER_BODY)
+      if(ftp->transfer != PPTRANSFER_BODY)
         state(data, FTP_STOP);
         state(data, FTP_STOP);
       else {
       else {
         if(ftpc->known_filesize != -1) {
         if(ftpc->known_filesize != -1) {
@@ -1747,13 +1749,19 @@ static CURLcode ftp_state_quote(struct Curl_easy *data,
           result = ftp_state_retr(data, ftpc->known_filesize);
           result = ftp_state_retr(data, ftpc->known_filesize);
         }
         }
         else {
         else {
-          if(data->set.ignorecl) {
-            /* This code is to support download of growing files.  It prevents
-               the state machine from requesting the file size from the
-               server.  With an unknown file size the download continues until
-               the server terminates it, otherwise the client stops if the
-               received byte count exceeds the reported file size.  Set option
-               CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this behavior.*/
+          if(data->set.ignorecl || data->state.prefer_ascii) {
+            /* 'ignorecl' is used to support download of growing files.  It
+               prevents the state machine from requesting the file size from
+               the server.  With an unknown file size the download continues
+               until the server terminates it, otherwise the client stops if
+               the received byte count exceeds the reported file size.  Set
+               option CURLOPT_IGNORE_CONTENT_LENGTH to 1 to enable this
+               behavior.
+
+               In addition: asking for the size for 'TYPE A' transfers is not
+               constructive since servers don't report the converted size. So
+               skip it.
+            */
             result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
             result = Curl_pp_sendf(data, &ftpc->pp, "RETR %s", ftpc->file);
             if(!result)
             if(!result)
               state(data, FTP_RETR);
               state(data, FTP_RETR);
@@ -2092,6 +2100,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
          data->set.get_filetime &&
          data->set.get_filetime &&
          (data->info.filetime >= 0) ) {
          (data->info.filetime >= 0) ) {
         char headerbuf[128];
         char headerbuf[128];
+        int headerbuflen;
         time_t filetime = data->info.filetime;
         time_t filetime = data->info.filetime;
         struct tm buffer;
         struct tm buffer;
         const struct tm *tm = &buffer;
         const struct tm *tm = &buffer;
@@ -2101,7 +2110,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
           return result;
           return result;
 
 
         /* format: "Tue, 15 Nov 1994 12:45:26" */
         /* format: "Tue, 15 Nov 1994 12:45:26" */
-        msnprintf(headerbuf, sizeof(headerbuf),
+        headerbuflen = msnprintf(headerbuf, sizeof(headerbuf),
                   "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
                   "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
                   Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
                   Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
                   tm->tm_mday,
                   tm->tm_mday,
@@ -2110,7 +2119,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
                   tm->tm_hour,
                   tm->tm_hour,
                   tm->tm_min,
                   tm->tm_min,
                   tm->tm_sec);
                   tm->tm_sec);
-        result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf, 0);
+        result = Curl_client_write(data, CLIENTWRITE_BOTH, headerbuf,
+                                   headerbuflen);
         if(result)
         if(result)
           return result;
           return result;
       } /* end of a ridiculous amount of conditionals */
       } /* end of a ridiculous amount of conditionals */
@@ -2133,7 +2143,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
       default:
       default:
         if(data->info.filetime <= data->set.timevalue) {
         if(data->info.filetime <= data->set.timevalue) {
           infof(data, "The requested document is not new enough\n");
           infof(data, "The requested document is not new enough\n");
-          ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+          ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
           data->info.timecond = TRUE;
           data->info.timecond = TRUE;
           state(data, FTP_STOP);
           state(data, FTP_STOP);
           return CURLE_OK;
           return CURLE_OK;
@@ -2142,7 +2152,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
       case CURL_TIMECOND_IFUNMODSINCE:
       case CURL_TIMECOND_IFUNMODSINCE:
         if(data->info.filetime > data->set.timevalue) {
         if(data->info.filetime > data->set.timevalue) {
           infof(data, "The requested document is not old enough\n");
           infof(data, "The requested document is not old enough\n");
-          ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+          ftp->transfer = PPTRANSFER_NONE; /* mark to not transfer data */
           data->info.timecond = TRUE;
           data->info.timecond = TRUE;
           state(data, FTP_STOP);
           state(data, FTP_STOP);
           return CURLE_OK;
           return CURLE_OK;
@@ -2250,7 +2260,7 @@ static CURLcode ftp_state_retr(struct Curl_easy *data,
 
 
       /* Set ->transfer so that we won't get any error in ftp_done()
       /* Set ->transfer so that we won't get any error in ftp_done()
        * because we didn't transfer the any file */
        * because we didn't transfer the any file */
-      ftp->transfer = FTPTRANSFER_NONE;
+      ftp->transfer = PPTRANSFER_NONE;
       state(data, FTP_STOP);
       state(data, FTP_STOP);
       return CURLE_OK;
       return CURLE_OK;
     }
     }
@@ -2303,17 +2313,21 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data,
 
 
   }
   }
   else if(ftpcode == 550) { /* "No such file or directory" */
   else if(ftpcode == 550) { /* "No such file or directory" */
-    failf(data, "The file does not exist");
-    return CURLE_REMOTE_FILE_NOT_FOUND;
+    /* allow a SIZE failure for (resumed) uploads, when probing what command
+       to use */
+    if(instate != FTP_STOR_SIZE) {
+      failf(data, "The file does not exist");
+      return CURLE_REMOTE_FILE_NOT_FOUND;
+    }
   }
   }
 
 
   if(instate == FTP_SIZE) {
   if(instate == FTP_SIZE) {
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
     if(-1 != filesize) {
     if(-1 != filesize) {
       char clbuf[128];
       char clbuf[128];
-      msnprintf(clbuf, sizeof(clbuf),
+      int clbuflen = msnprintf(clbuf, sizeof(clbuf),
                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
                 "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", filesize);
-      result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, 0);
+      result = Curl_client_write(data, CLIENTWRITE_BOTH, clbuf, clbuflen);
       if(result)
       if(result)
         return result;
         return result;
     }
     }
@@ -2347,7 +2361,8 @@ static CURLcode ftp_state_rest_resp(struct Curl_easy *data,
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
 #ifdef CURL_FTP_HTTPSTYLE_HEAD
     if(ftpcode == 350) {
     if(ftpcode == 350) {
       char buffer[24]= { "Accept-ranges: bytes\r\n" };
       char buffer[24]= { "Accept-ranges: bytes\r\n" };
-      result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer, 0);
+      result = Curl_client_write(data, CLIENTWRITE_BOTH, buffer,
+                                 strlen(buffer));
       if(result)
       if(result)
         return result;
         return result;
     }
     }
@@ -2448,7 +2463,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
      */
      */
 
 
     if((instate != FTP_LIST) &&
     if((instate != FTP_LIST) &&
-       !data->set.prefer_ascii &&
+       !data->state.prefer_ascii &&
        (ftp->downloadsize < 1)) {
        (ftp->downloadsize < 1)) {
       /*
       /*
        * It seems directory listings either don't show the size or very
        * It seems directory listings either don't show the size or very
@@ -2476,7 +2491,8 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
           bytes--;
           bytes--;
         }
         }
         /* if we have nothing but digits: */
         /* if we have nothing but digits: */
-        if(bytes++) {
+        if(bytes) {
+          ++bytes;
           /* get the number! */
           /* get the number! */
           (void)curlx_strtoofft(bytes, NULL, 0, &size);
           (void)curlx_strtoofft(bytes, NULL, 0, &size);
         }
         }
@@ -2487,7 +2503,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
 
 
     if(size > data->req.maxdownload && data->req.maxdownload > 0)
     if(size > data->req.maxdownload && data->req.maxdownload > 0)
       size = data->req.size = data->req.maxdownload;
       size = data->req.size = data->req.maxdownload;
-    else if((instate != FTP_LIST) && (data->set.prefer_ascii))
+    else if((instate != FTP_LIST) && (data->state.prefer_ascii))
       size = -1; /* kludge for servers that understate ASCII mode file size */
       size = -1; /* kludge for servers that understate ASCII mode file size */
 
 
     infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
     infof(data, "Maxdownload = %" CURL_FORMAT_CURL_OFF_T "\n",
@@ -2521,7 +2537,7 @@ static CURLcode ftp_state_get_resp(struct Curl_easy *data,
   else {
   else {
     if((instate == FTP_LIST) && (ftpcode == 450)) {
     if((instate == FTP_LIST) && (ftpcode == 450)) {
       /* simply no matching files in the dir listing */
       /* simply no matching files in the dir listing */
-      ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
+      ftp->transfer = PPTRANSFER_NONE; /* don't download anything */
       state(data, FTP_STOP); /* this phase is over */
       state(data, FTP_STOP); /* this phase is over */
     }
     }
     else {
     else {
@@ -3291,7 +3307,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
     close_secondarysocket(data, conn);
     close_secondarysocket(data, conn);
   }
   }
 
 
-  if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
+  if(!result && (ftp->transfer == PPTRANSFER_BODY) && ftpc->ctl_valid &&
      pp->pending_resp && !premature) {
      pp->pending_resp && !premature) {
     /*
     /*
      * Let's see what the server says about the transfer we just performed,
      * Let's see what the server says about the transfer we just performed,
@@ -3314,8 +3330,10 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
       connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
       connclose(conn, "Timeout or similar in FTP DONE operation"); /* close */
     }
     }
 
 
-    if(result)
+    if(result) {
+      Curl_safefree(ftp->pathalloc);
       return result;
       return result;
+    }
 
 
     if(ftpc->dont_check && data->req.maxdownload > 0) {
     if(ftpc->dont_check && data->req.maxdownload > 0) {
       /* we have just sent ABOR and there is no reliable way to check if it was
       /* we have just sent ABOR and there is no reliable way to check if it was
@@ -3351,7 +3369,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
     if((-1 != data->state.infilesize) &&
     if((-1 != data->state.infilesize) &&
        (data->state.infilesize != data->req.writebytecount) &&
        (data->state.infilesize != data->req.writebytecount) &&
        !data->set.crlf &&
        !data->set.crlf &&
-       (ftp->transfer == FTPTRANSFER_BODY)) {
+       (ftp->transfer == PPTRANSFER_BODY)) {
       failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
       failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
             " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
             " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
             data->req.bytecount, data->state.infilesize);
             data->req.bytecount, data->state.infilesize);
@@ -3383,7 +3401,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
   }
   }
 
 
   /* clear these for next connection */
   /* clear these for next connection */
-  ftp->transfer = FTPTRANSFER_BODY;
+  ftp->transfer = PPTRANSFER_BODY;
   ftpc->dont_check = FALSE;
   ftpc->dont_check = FALSE;
 
 
   /* Send any post-transfer QUOTE strings? */
   /* Send any post-transfer QUOTE strings? */
@@ -3594,7 +3612,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
     *completep = 0;
     *completep = 0;
   }
   }
 
 
-  if(ftp->transfer <= FTPTRANSFER_INFO) {
+  if(ftp->transfer <= PPTRANSFER_INFO) {
     /* a transfer is about to take place, or if not a file name was given
     /* a transfer is about to take place, or if not a file name was given
        so we'll do a SIZE on it later and then we need the right TYPE first */
        so we'll do a SIZE on it later and then we need the right TYPE first */
 
 
@@ -3620,7 +3638,8 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
       }
       }
     }
     }
     else if(data->set.upload) {
     else if(data->set.upload) {
-      result = ftp_nb_type(data, conn, data->set.prefer_ascii, FTP_STOR_TYPE);
+      result = ftp_nb_type(data, conn, data->state.prefer_ascii,
+                           FTP_STOR_TYPE);
       if(result)
       if(result)
         return result;
         return result;
 
 
@@ -3641,13 +3660,13 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
 
 
       if(result)
       if(result)
         ;
         ;
-      else if(data->set.ftp_list_only || !ftpc->file) {
+      else if(data->state.list_only || !ftpc->file) {
         /* The specified path ends with a slash, and therefore we think this
         /* The specified path ends with a slash, and therefore we think this
            is a directory that is requested, use LIST. But before that we
            is a directory that is requested, use LIST. But before that we
            need to set ASCII transfer mode. */
            need to set ASCII transfer mode. */
 
 
         /* But only if a body transfer was requested. */
         /* But only if a body transfer was requested. */
-        if(ftp->transfer == FTPTRANSFER_BODY) {
+        if(ftp->transfer == PPTRANSFER_BODY) {
           result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE);
           result = ftp_nb_type(data, conn, TRUE, FTP_LIST_TYPE);
           if(result)
           if(result)
             return result;
             return result;
@@ -3655,7 +3674,7 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep)
         /* otherwise just fall through */
         /* otherwise just fall through */
       }
       }
       else {
       else {
-        result = ftp_nb_type(data, conn, data->set.prefer_ascii,
+        result = ftp_nb_type(data, conn, data->state.prefer_ascii,
                              FTP_RETR_TYPE);
                              FTP_RETR_TYPE);
         if(result)
         if(result)
           return result;
           return result;
@@ -3703,7 +3722,7 @@ CURLcode ftp_perform(struct Curl_easy *data,
   if(data->set.opt_no_body) {
   if(data->set.opt_no_body) {
     /* requested no body means no transfer... */
     /* requested no body means no transfer... */
     struct FTP *ftp = data->req.p.ftp;
     struct FTP *ftp = data->req.p.ftp;
-    ftp->transfer = FTPTRANSFER_INFO;
+    ftp->transfer = PPTRANSFER_INFO;
   }
   }
 
 
   *dophase_done = FALSE; /* not done yet */
   *dophase_done = FALSE; /* not done yet */
@@ -4193,7 +4212,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
     ftpc->file = NULL; /* instead of point to a zero byte,
     ftpc->file = NULL; /* instead of point to a zero byte,
                             we make it a NULL pointer */
                             we make it a NULL pointer */
 
 
-  if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
+  if(data->set.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
     /* We need a file name when uploading. Return error! */
     /* We need a file name when uploading. Return error! */
     failf(data, "Uploading to a URL without a file name!");
     failf(data, "Uploading to a URL without a file name!");
     free(rawPath);
     free(rawPath);
@@ -4241,7 +4260,7 @@ static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
     }
     }
   }
   }
 
 
-  if(ftp->transfer != FTPTRANSFER_BODY)
+  if(ftp->transfer != PPTRANSFER_BODY)
     /* no data to transfer */
     /* no data to transfer */
     Curl_setup_transfer(data, -1, -1, FALSE, -1);
     Curl_setup_transfer(data, -1, -1, FALSE, -1);
   else if(!connected)
   else if(!connected)
@@ -4345,23 +4364,23 @@ static CURLcode ftp_setup_connection(struct Curl_easy *data,
 
 
     switch(command) {
     switch(command) {
     case 'A': /* ASCII mode */
     case 'A': /* ASCII mode */
-      data->set.prefer_ascii = TRUE;
+      data->state.prefer_ascii = TRUE;
       break;
       break;
 
 
     case 'D': /* directory mode */
     case 'D': /* directory mode */
-      data->set.ftp_list_only = TRUE;
+      data->state.list_only = TRUE;
       break;
       break;
 
 
     case 'I': /* binary mode */
     case 'I': /* binary mode */
     default:
     default:
       /* switch off ASCII */
       /* switch off ASCII */
-      data->set.prefer_ascii = FALSE;
+      data->state.prefer_ascii = FALSE;
       break;
       break;
     }
     }
   }
   }
 
 
   /* get some initial data into the ftp struct */
   /* get some initial data into the ftp struct */
-  ftp->transfer = FTPTRANSFER_BODY;
+  ftp->transfer = PPTRANSFER_BODY;
   ftp->downloadsize = 0;
   ftp->downloadsize = 0;
   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
   conn->proto.ftpc.known_filesize = -1; /* unknown size for now */
 
 

+ 1 - 2
lib/ftplistparser.c

@@ -424,7 +424,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
                 endptr++;
                 endptr++;
               while(ISDIGIT(*endptr))
               while(ISDIGIT(*endptr))
                 endptr++;
                 endptr++;
-              if(*endptr != 0) {
+              if(*endptr) {
                 parser->error = CURLE_FTP_BAD_FILE_LIST;
                 parser->error = CURLE_FTP_BAD_FILE_LIST;
                 goto fail;
                 goto fail;
               }
               }
@@ -966,7 +966,6 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           else if(c == '\n') {
           else if(c == '\n') {
             parser->offsets.filename = parser->item_offset;
             parser->offsets.filename = parser->item_offset;
             finfo->b_data[finfo->b_used - 1] = 0;
             finfo->b_data[finfo->b_used - 1] = 0;
-            parser->offsets.filename = parser->item_offset;
             result = ftp_pl_insert_finfo(data, infop);
             result = ftp_pl_insert_finfo(data, infop);
             if(result) {
             if(result) {
               parser->error = result;
               parser->error = result;

+ 7 - 3
lib/getinfo.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -94,7 +94,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
 {
 {
   switch(info) {
   switch(info) {
   case CURLINFO_EFFECTIVE_URL:
   case CURLINFO_EFFECTIVE_URL:
-    *param_charp = data->change.url?data->change.url:(char *)"";
+    *param_charp = data->state.url?data->state.url:(char *)"";
     break;
     break;
   case CURLINFO_EFFECTIVE_METHOD: {
   case CURLINFO_EFFECTIVE_METHOD: {
     const char *m = data->set.str[STRING_CUSTOMREQUEST];
     const char *m = data->set.str[STRING_CUSTOMREQUEST];
@@ -145,6 +145,10 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
        option had been enabled! */
        option had been enabled! */
     *param_charp = data->info.wouldredirect;
     *param_charp = data->info.wouldredirect;
     break;
     break;
+  case CURLINFO_REFERER:
+    /* Return the referrer header for this request, or NULL if unset */
+    *param_charp = data->state.referer;
+    break;
   case CURLINFO_PRIMARY_IP:
   case CURLINFO_PRIMARY_IP:
     /* Return the ip address of the most recent (primary) connection */
     /* Return the ip address of the most recent (primary) connection */
     *param_charp = data->info.conn_primary_ip;
     *param_charp = data->info.conn_primary_ip;
@@ -235,7 +239,7 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
     break;
     break;
 #endif
 #endif
   case CURLINFO_REDIRECT_COUNT:
   case CURLINFO_REDIRECT_COUNT:
-    *param_longp = data->set.followlocation;
+    *param_longp = data->state.followlocation;
     break;
     break;
   case CURLINFO_HTTPAUTH_AVAIL:
   case CURLINFO_HTTPAUTH_AVAIL:
     lptr.to_long = param_longp;
     lptr.to_long = param_longp;

+ 2 - 0
lib/gopher.c

@@ -74,6 +74,7 @@ const struct Curl_handler Curl_handler_gopher = {
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_GOPHER,                          /* defport */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHER,                     /* protocol */
   CURLPROTO_GOPHER,                     /* protocol */
   CURLPROTO_GOPHER,                     /* family */
   CURLPROTO_GOPHER,                     /* family */
@@ -97,6 +98,7 @@ const struct Curl_handler Curl_handler_gophers = {
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_GOPHER,                          /* defport */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHERS,                    /* protocol */
   CURLPROTO_GOPHERS,                    /* protocol */
   CURLPROTO_GOPHER,                     /* family */
   CURLPROTO_GOPHER,                     /* family */

+ 2 - 2
lib/hash.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -245,7 +245,7 @@ Curl_hash_clean_with_criterium(struct Curl_hash *h, void *user,
       struct Curl_hash_element *he = le->ptr;
       struct Curl_hash_element *he = le->ptr;
       lnext = le->next;
       lnext = le->next;
       /* ask the callback function if we shall remove this entry or not */
       /* ask the callback function if we shall remove this entry or not */
-      if(comp == NULL || comp(user, he->ptr)) {
+      if(!comp || comp(user, he->ptr)) {
         Curl_llist_remove(list, le, (void *) h);
         Curl_llist_remove(list, le, (void *) h);
         --h->size; /* one less entry in the hash now */
         --h->size; /* one less entry in the hash now */
       }
       }

+ 4 - 4
lib/hostcheck.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -81,7 +81,7 @@ static int hostmatch(char *hostname, char *pattern)
     pattern[len-1] = 0;
     pattern[len-1] = 0;
 
 
   pattern_wildcard = strchr(pattern, '*');
   pattern_wildcard = strchr(pattern, '*');
-  if(pattern_wildcard == NULL)
+  if(!pattern_wildcard)
     return strcasecompare(pattern, hostname) ?
     return strcasecompare(pattern, hostname) ?
       CURL_HOST_MATCH : CURL_HOST_NOMATCH;
       CURL_HOST_MATCH : CURL_HOST_NOMATCH;
 
 
@@ -97,7 +97,7 @@ static int hostmatch(char *hostname, char *pattern)
      match. */
      match. */
   wildcard_enabled = 1;
   wildcard_enabled = 1;
   pattern_label_end = strchr(pattern, '.');
   pattern_label_end = strchr(pattern, '.');
-  if(pattern_label_end == NULL || strchr(pattern_label_end + 1, '.') == NULL ||
+  if(!pattern_label_end || strchr(pattern_label_end + 1, '.') == NULL ||
      pattern_wildcard > pattern_label_end ||
      pattern_wildcard > pattern_label_end ||
      strncasecompare(pattern, "xn--", 4)) {
      strncasecompare(pattern, "xn--", 4)) {
     wildcard_enabled = 0;
     wildcard_enabled = 0;
@@ -107,7 +107,7 @@ static int hostmatch(char *hostname, char *pattern)
       CURL_HOST_MATCH : CURL_HOST_NOMATCH;
       CURL_HOST_MATCH : CURL_HOST_NOMATCH;
 
 
   hostname_label_end = strchr(hostname, '.');
   hostname_label_end = strchr(hostname, '.');
-  if(hostname_label_end == NULL ||
+  if(!hostname_label_end ||
      !strcasecompare(pattern_label_end, hostname_label_end))
      !strcasecompare(pattern_label_end, hostname_label_end))
     return CURL_HOST_NOMATCH;
     return CURL_HOST_NOMATCH;
 
 

+ 65 - 19
lib/hostip.c

@@ -68,6 +68,10 @@
 #include "curl_memory.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 #include "memdebug.h"
 
 
+#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
+#include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
+#endif
+
 #if defined(CURLRES_SYNCH) && \
 #if defined(CURLRES_SYNCH) && \
     defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
     defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
 /* alarm-based timeouts can only be used with all the dependencies satisfied */
 /* alarm-based timeouts can only be used with all the dependencies satisfied */
@@ -269,7 +273,7 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
   dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
   dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
 
   /* No entry found in cache, check if we might have a wildcard entry */
   /* No entry found in cache, check if we might have a wildcard entry */
-  if(!dns && data->change.wildcard_resolve) {
+  if(!dns && data->state.wildcard_resolve) {
     create_hostcache_id("*", port, entry_id, sizeof(entry_id));
     create_hostcache_id("*", port, entry_id, sizeof(entry_id));
     entry_len = strlen(entry_id);
     entry_len = strlen(entry_id);
 
 
@@ -466,10 +470,6 @@ Curl_cache_addr(struct Curl_easy *data,
  * function is used. You MUST call Curl_resolv_unlock() later (when you're
  * function is used. You MUST call Curl_resolv_unlock() later (when you're
  * done using this struct) to decrease the counter again.
  * done using this struct) to decrease the counter again.
  *
  *
- * In debug mode, we specifically test for an interface name "LocalHost"
- * and resolve "localhost" instead as a means to permit test cases
- * to connect to a local test server with any host name.
- *
  * Return codes:
  * Return codes:
  *
  *
  * CURLRESOLV_ERROR   (-1) = error, no pointer
  * CURLRESOLV_ERROR   (-1) = error, no pointer
@@ -520,13 +520,32 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
     if(data->set.resolver_start) {
     if(data->set.resolver_start) {
       int st;
       int st;
       Curl_set_in_callback(data, true);
       Curl_set_in_callback(data, true);
-      st = data->set.resolver_start(data->state.async.resolver, NULL,
-                                    data->set.resolver_start_client);
+      st = data->set.resolver_start(
+#ifdef USE_CURL_ASYNC
+        data->state.async.resolver,
+#else
+        NULL,
+#endif
+        NULL,
+        data->set.resolver_start_client);
       Curl_set_in_callback(data, false);
       Curl_set_in_callback(data, false);
       if(st)
       if(st)
         return CURLRESOLV_ERROR;
         return CURLRESOLV_ERROR;
     }
     }
 
 
+#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
+    /*
+     * The automagic conversion from IPv4 literals to IPv6 literals only works
+     * if the SCDynamicStoreCopyProxies system function gets called first. As
+     * Curl currently doesn't support system-wide HTTP proxies, we therefore
+     * don't use any value this function might return.
+     *
+     * This function is only available on a macOS and is not needed for
+     * IPv4-only builds, hence the conditions above.
+     */
+    SCDynamicStoreCopyProxies(NULL);
+#endif
+
 #ifndef USE_RESOLVE_ON_IPS
 #ifndef USE_RESOLVE_ON_IPS
     /* First check if this is an IPv4 address string */
     /* First check if this is an IPv4 address string */
     if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
     if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
@@ -572,13 +591,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
         /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
         /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
            non-zero value indicating that we need to wait for the response to
            non-zero value indicating that we need to wait for the response to
            the resolve call */
            the resolve call */
-        addr = Curl_getaddrinfo(data,
-#ifdef DEBUGBUILD
-                                (data->set.str[STRING_DEVICE]
-                                 && !strcmp(data->set.str[STRING_DEVICE],
-                                            "LocalHost"))?"localhost":
-#endif
-                                hostname, port, &respwait);
+        addr = Curl_getaddrinfo(data, hostname, port, &respwait);
       }
       }
     }
     }
     if(!addr) {
     if(!addr) {
@@ -625,7 +638,7 @@ enum resolve_t Curl_resolv(struct Curl_easy *data,
  * within a signal handler which is nonportable and could lead to problems.
  * within a signal handler which is nonportable and could lead to problems.
  */
  */
 static
 static
-RETSIGTYPE alarmfunc(int sig)
+void alarmfunc(int sig)
 {
 {
   /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */
   /* this is for "-ansi -Wall -pedantic" to stop complaining!   (rabe) */
   (void)sig;
   (void)sig;
@@ -872,9 +885,9 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
   int port = 0;
   int port = 0;
 
 
   /* Default is no wildcard found */
   /* Default is no wildcard found */
-  data->change.wildcard_resolve = false;
+  data->state.wildcard_resolve = false;
 
 
-  for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
+  for(hostp = data->state.resolve; hostp; hostp = hostp->next) {
     char entry_id[MAX_HOSTCACHE_LEN];
     char entry_id[MAX_HOSTCACHE_LEN];
     if(!hostp->data)
     if(!hostp->data)
       continue;
       continue;
@@ -1055,11 +1068,11 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       if(hostname[0] == '*' && hostname[1] == '\0') {
       if(hostname[0] == '*' && hostname[1] == '\0') {
         infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks\n",
         infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks\n",
               hostname, port);
               hostname, port);
-        data->change.wildcard_resolve = true;
+        data->state.wildcard_resolve = true;
       }
       }
     }
     }
   }
   }
-  data->change.resolve = NULL; /* dealt with now */
+  data->state.resolve = NULL; /* dealt with now */
 
 
   return CURLE_OK;
   return CURLE_OK;
 }
 }
@@ -1102,10 +1115,12 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
   CURLcode result;
   CURLcode result;
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
 
 
+#ifdef USE_CURL_ASYNC
   if(data->state.async.dns) {
   if(data->state.async.dns) {
     conn->dns_entry = data->state.async.dns;
     conn->dns_entry = data->state.async.dns;
     data->state.async.dns = NULL;
     data->state.async.dns = NULL;
   }
   }
+#endif
 
 
   result = Curl_setup_conn(data, protocol_done);
   result = Curl_setup_conn(data, protocol_done);
 
 
@@ -1116,3 +1131,34 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
   }
   }
   return result;
   return result;
 }
 }
+
+/*
+ * Curl_resolver_error() calls failf() with the appropriate message after a
+ * resolve error
+ */
+
+#ifdef USE_CURL_ASYNC
+CURLcode Curl_resolver_error(struct Curl_easy *data)
+{
+  const char *host_or_proxy;
+  CURLcode result;
+
+#ifndef CURL_DISABLE_PROXY
+  struct connectdata *conn = data->conn;
+  if(conn->bits.httpproxy) {
+    host_or_proxy = "proxy";
+    result = CURLE_COULDNT_RESOLVE_PROXY;
+  }
+  else
+#endif
+  {
+    host_or_proxy = "host";
+    result = CURLE_COULDNT_RESOLVE_HOST;
+  }
+
+  failf(data, "Could not resolve %s: %s", host_or_proxy,
+        data->state.async.hostname);
+
+  return result;
+}
+#endif /* USE_CURL_ASYNC */

+ 1 - 9
lib/hostip.h

@@ -136,15 +136,6 @@ void Curl_hostcache_prune(struct Curl_easy *data);
 /* Return # of addresses in a Curl_addrinfo struct */
 /* Return # of addresses in a Curl_addrinfo struct */
 int Curl_num_addresses(const struct Curl_addrinfo *addr);
 int Curl_num_addresses(const struct Curl_addrinfo *addr);
 
 
-#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
-int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
-                       GETNAMEINFO_TYPE_ARG2 salen,
-                       char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
-                       char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
-                       GETNAMEINFO_TYPE_ARG7 flags,
-                       int line, const char *source);
-#endif
-
 /* IPv4 threadsafe resolve function used for synch and asynch builds */
 /* IPv4 threadsafe resolve function used for synch and asynch builds */
 struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
 struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
 
 
@@ -245,4 +236,5 @@ CURLcode Curl_resolv_check(struct Curl_easy *data,
 int Curl_resolv_getsock(struct Curl_easy *data,
 int Curl_resolv_getsock(struct Curl_easy *data,
                         curl_socket_t *socks);
                         curl_socket_t *socks);
 
 
+CURLcode Curl_resolver_error(struct Curl_easy *data);
 #endif /* HEADER_CURL_HOSTIP_H */
 #endif /* HEADER_CURL_HOSTIP_H */

+ 3 - 16
lib/hostip6.c

@@ -140,26 +140,13 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
 #ifndef USE_RESOLVE_ON_IPS
 #ifndef USE_RESOLVE_ON_IPS
   char addrbuf[128];
   char addrbuf[128];
 #endif
 #endif
-  int pf;
+  int pf = PF_INET;
 
 
   *waitp = 0; /* synchronous response only */
   *waitp = 0; /* synchronous response only */
 
 
-  /* Check if a limited name resolve has been requested */
-  switch(data->set.ipver) {
-  case CURL_IPRESOLVE_V4:
-    pf = PF_INET;
-    break;
-  case CURL_IPRESOLVE_V6:
-    pf = PF_INET6;
-    break;
-  default:
+  if(Curl_ipv6works(data))
+    /* The stack seems to be IPv6-enabled */
     pf = PF_UNSPEC;
     pf = PF_UNSPEC;
-    break;
-  }
-
-  if((pf != PF_INET) && !Curl_ipv6works(data))
-    /* The stack seems to be a non-IPv6 one */
-    pf = PF_INET;
 
 
   memset(&hints, 0, sizeof(hints));
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
   hints.ai_family = pf;

+ 13 - 8
lib/hsts.c

@@ -25,7 +25,7 @@
  */
  */
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_HSTS)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include "urldata.h"
 #include "urldata.h"
 #include "llist.h"
 #include "llist.h"
@@ -37,6 +37,7 @@
 #include "parsedate.h"
 #include "parsedate.h"
 #include "rand.h"
 #include "rand.h"
 #include "rename.h"
 #include "rename.h"
+#include "strtoofft.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -46,8 +47,6 @@
 #define MAX_HSTS_LINE 4095
 #define MAX_HSTS_LINE 4095
 #define MAX_HSTS_HOSTLEN 256
 #define MAX_HSTS_HOSTLEN 256
 #define MAX_HSTS_HOSTLENSTR "256"
 #define MAX_HSTS_HOSTLENSTR "256"
-#define MAX_HSTS_SUBLEN 4
-#define MAX_HSTS_SUBLENSTR "4"
 #define MAX_HSTS_DATELEN 64
 #define MAX_HSTS_DATELEN 64
 #define MAX_HSTS_DATELENSTR "64"
 #define MAX_HSTS_DATELENSTR "64"
 
 
@@ -60,7 +59,10 @@ static time_t debugtime(void *unused)
   char *timestr = getenv("CURL_TIME");
   char *timestr = getenv("CURL_TIME");
   (void)unused;
   (void)unused;
   if(timestr) {
   if(timestr) {
-    unsigned long val = strtol(timestr, NULL, 10) + deltatime;
+    curl_off_t val;
+    (void)curlx_strtoofft(timestr, NULL, 10, &val);
+
+    val += (curl_off_t)deltatime;
     return (time_t)val;
     return (time_t)val;
   }
   }
   return time(NULL);
   return time(NULL);
@@ -276,7 +278,7 @@ static CURLcode hsts_push(struct Curl_easy *data,
   e.namelen = strlen(sts->host);
   e.namelen = strlen(sts->host);
   e.includeSubDomains = sts->includeSubDomains;
   e.includeSubDomains = sts->includeSubDomains;
 
 
-  result = Curl_gmtime(sts->expires, &stamp);
+  result = Curl_gmtime((time_t)sts->expires, &stamp);
   if(result)
   if(result)
     return result;
     return result;
 
 
@@ -296,7 +298,7 @@ static CURLcode hsts_push(struct Curl_easy *data,
 static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
 static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
 {
 {
   struct tm stamp;
   struct tm stamp;
-  CURLcode result = Curl_gmtime(sts->expires, &stamp);
+  CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp);
   if(result)
   if(result)
     return result;
     return result;
 
 
@@ -441,7 +443,10 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
           expires = Curl_getdate_capped(e.expire);
           expires = Curl_getdate_capped(e.expire);
         else
         else
           expires = TIME_T_MAX; /* the end of time */
           expires = TIME_T_MAX; /* the end of time */
-        result = hsts_create(h, e.name, e.includeSubDomains, expires);
+        result = hsts_create(h, e.name,
+                             /* bitfield to bool conversion: */
+                             e.includeSubDomains ? TRUE : FALSE,
+                             expires);
         if(result)
         if(result)
           return result;
           return result;
       }
       }
@@ -519,4 +524,4 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
   return hsts_pull(data, h);
   return hsts_pull(data, h);
 }
 }
 
 
-#endif /* CURL_DISABLE_HTTP || USE_HSTS */
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */

+ 4 - 4
lib/hsts.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2020 - 2021, 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
@@ -23,7 +23,7 @@
  ***************************************************************************/
  ***************************************************************************/
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_HSTS)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_HSTS)
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include "llist.h"
 #include "llist.h"
 
 
@@ -35,7 +35,7 @@ struct stsentry {
   struct Curl_llist_element node;
   struct Curl_llist_element node;
   const char *host;
   const char *host;
   bool includeSubDomains;
   bool includeSubDomains;
-  time_t expires; /* the timestamp of this entry's expiry */
+  curl_off_t expires; /* the timestamp of this entry's expiry */
 };
 };
 
 
 /* The HSTS cache. Needs to be able to tailmatch host names. */
 /* The HSTS cache. Needs to be able to tailmatch host names. */
@@ -61,5 +61,5 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
 #define Curl_hsts_cleanup(x)
 #define Curl_hsts_cleanup(x)
 #define Curl_hsts_loadcb(x,y)
 #define Curl_hsts_loadcb(x,y)
 #define Curl_hsts_save(x,y,z)
 #define Curl_hsts_save(x,y,z)
-#endif /* CURL_DISABLE_HTTP || USE_HSTS */
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
 #endif /* HEADER_CURL_HSTS_H */
 #endif /* HEADER_CURL_HSTS_H */

+ 150 - 71
lib/http.c

@@ -133,6 +133,7 @@ const struct Curl_handler Curl_handler_http = {
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_HTTP,                            /* defport */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTP,                       /* protocol */
   CURLPROTO_HTTP,                       /* protocol */
   CURLPROTO_HTTP,                       /* family */
   CURLPROTO_HTTP,                       /* family */
@@ -160,6 +161,7 @@ const struct Curl_handler Curl_handler_https = {
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_HTTPS,                           /* defport */
   PORT_HTTPS,                           /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
   CURLPROTO_HTTPS,                      /* protocol */
   CURLPROTO_HTTP,                       /* family */
   CURLPROTO_HTTP,                       /* family */
@@ -183,7 +185,7 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
   Curl_mime_initpart(&http->form, data);
   Curl_mime_initpart(&http->form, data);
   data->req.p.http = http;
   data->req.p.http = http;
 
 
-  if(data->set.httpversion == CURL_HTTP_VERSION_3) {
+  if(data->state.httpwant == CURL_HTTP_VERSION_3) {
     if(conn->handler->flags & PROTOPT_SSL)
     if(conn->handler->flags & PROTOPT_SSL)
       /* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does
       /* Only go HTTP/3 directly on HTTPS URLs. It needs a UDP socket and does
          the QUIC dance. */
          the QUIC dance. */
@@ -298,26 +300,27 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
 {
 {
   size_t size = 0;
   size_t size = 0;
   char *authorization = NULL;
   char *authorization = NULL;
-  struct connectdata *conn = data->conn;
   char **userp;
   char **userp;
   const char *user;
   const char *user;
   const char *pwd;
   const char *pwd;
   CURLcode result;
   CURLcode result;
   char *out;
   char *out;
 
 
+  /* credentials are unique per transfer for HTTP, do not use the ones for the
+     connection */
   if(proxy) {
   if(proxy) {
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
     userp = &data->state.aptr.proxyuserpwd;
     userp = &data->state.aptr.proxyuserpwd;
-    user = conn->http_proxy.user;
-    pwd = conn->http_proxy.passwd;
+    user = data->state.aptr.proxyuser;
+    pwd = data->state.aptr.proxypasswd;
 #else
 #else
     return CURLE_NOT_BUILT_IN;
     return CURLE_NOT_BUILT_IN;
 #endif
 #endif
   }
   }
   else {
   else {
     userp = &data->state.aptr.userpwd;
     userp = &data->state.aptr.userpwd;
-    user = conn->user;
-    pwd = conn->passwd;
+    user = data->state.aptr.user;
+    pwd = data->state.aptr.passwd;
   }
   }
 
 
   out = aprintf("%s:%s", user, pwd ? pwd : "");
   out = aprintf("%s:%s", user, pwd ? pwd : "");
@@ -595,7 +598,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
        conn->httpversion > 11) {
        conn->httpversion > 11) {
       infof(data, "Forcing HTTP/1.1 for NTLM");
       infof(data, "Forcing HTTP/1.1 for NTLM");
       connclose(conn, "Force HTTP/1.1 connection");
       connclose(conn, "Force HTTP/1.1 connection");
-      data->set.httpversion = CURL_HTTP_VERSION_1_1;
+      data->state.httpwant = CURL_HTTP_VERSION_1_1;
     }
     }
   }
   }
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -621,7 +624,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
        we must make sure to free it before allocating a new one. As figured
        we must make sure to free it before allocating a new one. As figured
        out in bug #2284386 */
        out in bug #2284386 */
     Curl_safefree(data->req.newurl);
     Curl_safefree(data->req.newurl);
-    data->req.newurl = strdup(data->change.url); /* clone URL */
+    data->req.newurl = strdup(data->state.url); /* clone URL */
     if(!data->req.newurl)
     if(!data->req.newurl)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
   }
   }
@@ -634,7 +637,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
        we didn't try HEAD or GET */
        we didn't try HEAD or GET */
     if((data->state.httpreq != HTTPREQ_GET) &&
     if((data->state.httpreq != HTTPREQ_GET) &&
        (data->state.httpreq != HTTPREQ_HEAD)) {
        (data->state.httpreq != HTTPREQ_HEAD)) {
-      data->req.newurl = strdup(data->change.url); /* clone URL */
+      data->req.newurl = strdup(data->state.url); /* clone URL */
       if(!data->req.newurl)
       if(!data->req.newurl)
         return CURLE_OUT_OF_MEMORY;
         return CURLE_OUT_OF_MEMORY;
       data->state.authhost.done = TRUE;
       data->state.authhost.done = TRUE;
@@ -709,7 +712,6 @@ output_auth_headers(struct Curl_easy *data,
   if(authstatus->picked == CURLAUTH_DIGEST) {
   if(authstatus->picked == CURLAUTH_DIGEST) {
     auth = "Digest";
     auth = "Digest";
     result = Curl_output_digest(data,
     result = Curl_output_digest(data,
-                                conn,
                                 proxy,
                                 proxy,
                                 (const unsigned char *)request,
                                 (const unsigned char *)request,
                                 (const unsigned char *)path);
                                 (const unsigned char *)path);
@@ -740,7 +742,7 @@ output_auth_headers(struct Curl_easy *data,
   if(authstatus->picked == CURLAUTH_BEARER) {
   if(authstatus->picked == CURLAUTH_BEARER) {
     /* Bearer */
     /* Bearer */
     if((!proxy && data->set.str[STRING_BEARER] &&
     if((!proxy && data->set.str[STRING_BEARER] &&
-        !Curl_checkheaders(data, "Authorization:"))) {
+        !Curl_checkheaders(data, "Authorization"))) {
       auth = "Bearer";
       auth = "Bearer";
       result = http_output_bearer(data);
       result = http_output_bearer(data);
       if(result)
       if(result)
@@ -756,11 +758,14 @@ output_auth_headers(struct Curl_easy *data,
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
     infof(data, "%s auth using %s with user '%s'\n",
     infof(data, "%s auth using %s with user '%s'\n",
           proxy ? "Proxy" : "Server", auth,
           proxy ? "Proxy" : "Server", auth,
-          proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") :
-          (conn->user ? conn->user : ""));
+          proxy ? (data->state.aptr.proxyuser ?
+                   data->state.aptr.proxyuser : "") :
+          (data->state.aptr.user ?
+           data->state.aptr.user : ""));
 #else
 #else
     infof(data, "Server auth using %s with user '%s'\n",
     infof(data, "Server auth using %s with user '%s'\n",
-          auth, conn->user ? conn->user : "");
+          auth, data->state.aptr.user ?
+          data->state.aptr.user : "");
 #endif
 #endif
     authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
     authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
   }
   }
@@ -871,13 +876,17 @@ Curl_http_output_auth(struct Curl_easy *data,
 #else
 #else
 /* when disabled */
 /* when disabled */
 CURLcode
 CURLcode
-Curl_http_output_auth(struct connectdata *conn,
+Curl_http_output_auth(struct Curl_easy *data,
+                      struct connectdata *conn,
                       const char *request,
                       const char *request,
+                      Curl_HttpReq httpreq,
                       const char *path,
                       const char *path,
                       bool proxytunnel)
                       bool proxytunnel)
 {
 {
+  (void)data;
   (void)conn;
   (void)conn;
   (void)request;
   (void)request;
+  (void)httpreq;
   (void)path;
   (void)path;
   (void)proxytunnel;
   (void)proxytunnel;
   return CURLE_OK;
   return CURLE_OK;
@@ -890,6 +899,11 @@ Curl_http_output_auth(struct connectdata *conn,
  * proxy CONNECT loop.
  * proxy CONNECT loop.
  */
  */
 
 
+static int is_valid_auth_separator(char ch)
+{
+  return ch == '\0' || ch == ',' || ISSPACE(ch);
+}
+
 CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
 CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
                               const char *auth) /* the first non-space */
                               const char *auth) /* the first non-space */
 {
 {
@@ -933,7 +947,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
 
 
   while(*auth) {
   while(*auth) {
 #ifdef USE_SPNEGO
 #ifdef USE_SPNEGO
-    if(checkprefix("Negotiate", auth)) {
+    if(checkprefix("Negotiate", auth) && is_valid_auth_separator(auth[9])) {
       if((authp->avail & CURLAUTH_NEGOTIATE) ||
       if((authp->avail & CURLAUTH_NEGOTIATE) ||
          Curl_auth_is_spnego_supported()) {
          Curl_auth_is_spnego_supported()) {
         *availp |= CURLAUTH_NEGOTIATE;
         *availp |= CURLAUTH_NEGOTIATE;
@@ -943,7 +957,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
           CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
           CURLcode result = Curl_input_negotiate(data, conn, proxy, auth);
           if(!result) {
           if(!result) {
             DEBUGASSERT(!data->req.newurl);
             DEBUGASSERT(!data->req.newurl);
-            data->req.newurl = strdup(data->change.url);
+            data->req.newurl = strdup(data->state.url);
             if(!data->req.newurl)
             if(!data->req.newurl)
               return CURLE_OUT_OF_MEMORY;
               return CURLE_OUT_OF_MEMORY;
             data->state.authproblem = FALSE;
             data->state.authproblem = FALSE;
@@ -959,7 +973,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
 #endif
 #endif
 #ifdef USE_NTLM
 #ifdef USE_NTLM
       /* NTLM support requires the SSL crypto libs */
       /* NTLM support requires the SSL crypto libs */
-      if(checkprefix("NTLM", auth)) {
+      if(checkprefix("NTLM", auth) && is_valid_auth_separator(auth[4])) {
         if((authp->avail & CURLAUTH_NTLM) ||
         if((authp->avail & CURLAUTH_NTLM) ||
            (authp->avail & CURLAUTH_NTLM_WB) ||
            (authp->avail & CURLAUTH_NTLM_WB) ||
            Curl_auth_is_ntlm_supported()) {
            Curl_auth_is_ntlm_supported()) {
@@ -997,7 +1011,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
       else
       else
 #endif
 #endif
 #ifndef CURL_DISABLE_CRYPTO_AUTH
 #ifndef CURL_DISABLE_CRYPTO_AUTH
-        if(checkprefix("Digest", auth)) {
+        if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) {
           if((authp->avail & CURLAUTH_DIGEST) != 0)
           if((authp->avail & CURLAUTH_DIGEST) != 0)
             infof(data, "Ignoring duplicate digest auth header.\n");
             infof(data, "Ignoring duplicate digest auth header.\n");
           else if(Curl_auth_is_digest_supported()) {
           else if(Curl_auth_is_digest_supported()) {
@@ -1019,7 +1033,8 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
         }
         }
         else
         else
 #endif
 #endif
-          if(checkprefix("Basic", auth)) {
+          if(checkprefix("Basic", auth) &&
+             is_valid_auth_separator(auth[5])) {
             *availp |= CURLAUTH_BASIC;
             *availp |= CURLAUTH_BASIC;
             authp->avail |= CURLAUTH_BASIC;
             authp->avail |= CURLAUTH_BASIC;
             if(authp->picked == CURLAUTH_BASIC) {
             if(authp->picked == CURLAUTH_BASIC) {
@@ -1032,7 +1047,8 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
             }
             }
           }
           }
           else
           else
-            if(checkprefix("Bearer", auth)) {
+            if(checkprefix("Bearer", auth) &&
+               is_valid_auth_separator(auth[6])) {
               *availp |= CURLAUTH_BEARER;
               *availp |= CURLAUTH_BEARER;
               authp->avail |= CURLAUTH_BEARER;
               authp->avail |= CURLAUTH_BEARER;
               if(authp->picked == CURLAUTH_BEARER) {
               if(authp->picked == CURLAUTH_BEARER) {
@@ -1087,6 +1103,14 @@ static bool http_should_fail(struct Curl_easy *data)
   if(httpcode < 400)
   if(httpcode < 400)
     return FALSE;
     return FALSE;
 
 
+  /*
+  ** A 416 response to a resume request is presumably because the file is
+  ** already completely downloaded and thus not actually a fail.
+  */
+  if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
+     httpcode == 416)
+    return FALSE;
+
   /*
   /*
   ** Any code >= 400 that's not 401 or 407 is always
   ** Any code >= 400 that's not 401 or 407 is always
   ** a terminal error
   ** a terminal error
@@ -1152,7 +1176,12 @@ static size_t readmoredata(char *buffer,
   /* make sure that a HTTP request is never sent away chunked! */
   /* make sure that a HTTP request is never sent away chunked! */
   data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
   data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
 
 
-  if(http->postsize <= (curl_off_t)fullsize) {
+  if(data->set.max_send_speed &&
+     (data->set.max_send_speed < http->postsize))
+    /* speed limit */
+    fullsize = (size_t)data->set.max_send_speed;
+
+  else if(http->postsize <= (curl_off_t)fullsize) {
     memcpy(buffer, http->postdata, (size_t)http->postsize);
     memcpy(buffer, http->postdata, (size_t)http->postsize);
     fullsize = (size_t)http->postsize;
     fullsize = (size_t)http->postsize;
 
 
@@ -1192,7 +1221,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
                              counter */
                              counter */
                           curl_off_t *bytes_written,
                           curl_off_t *bytes_written,
                           /* how much of the buffer contains body data */
                           /* how much of the buffer contains body data */
-                          size_t included_body_bytes,
+                          curl_off_t included_body_bytes,
                           int socketindex)
                           int socketindex)
 {
 {
   ssize_t amount;
   ssize_t amount;
@@ -1215,10 +1244,10 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
   ptr = Curl_dyn_ptr(in);
   ptr = Curl_dyn_ptr(in);
   size = Curl_dyn_len(in);
   size = Curl_dyn_len(in);
 
 
-  headersize = size - included_body_bytes; /* the initial part that isn't body
-                                              is header */
+  headersize = size - (size_t)included_body_bytes; /* the initial part that
+                                                      isn't body is header */
 
 
-  DEBUGASSERT(size > included_body_bytes);
+  DEBUGASSERT(size > (size_t)included_body_bytes);
 
 
   result = Curl_convert_to_network(data, ptr, headersize);
   result = Curl_convert_to_network(data, ptr, headersize);
   /* Curl_convert_to_network calls failf if unsuccessful */
   /* Curl_convert_to_network calls failf if unsuccessful */
@@ -1234,13 +1263,17 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
 #endif
 #endif
        )
        )
      && conn->httpversion != 20) {
      && conn->httpversion != 20) {
-    /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
-       when we speak HTTPS, as if only a fraction of it is sent now, this data
-       needs to fit into the normal read-callback buffer later on and that
-       buffer is using this size.
+    /* Make sure this doesn't send more body bytes than what the max send
+       speed says. The request bytes do not count to the max speed.
     */
     */
-
-    sendsize = CURLMIN(size, CURL_MAX_WRITE_SIZE);
+    if(data->set.max_send_speed &&
+       (included_body_bytes > data->set.max_send_speed)) {
+      curl_off_t overflow = included_body_bytes - data->set.max_send_speed;
+      DEBUGASSERT((size_t)overflow < size);
+      sendsize = size - (size_t)overflow;
+    }
+    else
+      sendsize = size;
 
 
     /* OpenSSL is very picky and we must send the SAME buffer pointer to the
     /* OpenSSL is very picky and we must send the SAME buffer pointer to the
        library when we attempt to re-send this buffer. Sending the same data
        library when we attempt to re-send this buffer. Sending the same data
@@ -1254,6 +1287,14 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
       Curl_dyn_free(in);
       Curl_dyn_free(in);
       return result;
       return result;
     }
     }
+    /* We never send more than upload_buffer_size bytes in one single chunk
+       when we speak HTTPS, as if only a fraction of it is sent now, this data
+       needs to fit into the normal read-callback buffer later on and that
+       buffer is using this size.
+    */
+    if(sendsize > (size_t)data->set.upload_buffer_size)
+      sendsize = (size_t)data->set.upload_buffer_size;
+
     memcpy(data->state.ulbuf, ptr, sendsize);
     memcpy(data->state.ulbuf, ptr, sendsize);
     ptr = data->state.ulbuf;
     ptr = data->state.ulbuf;
   }
   }
@@ -1272,7 +1313,19 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
     }
     }
     else
     else
 #endif
 #endif
-    sendsize = size;
+    {
+      /* Make sure this doesn't send more body bytes than what the max send
+         speed says. The request bytes do not count to the max speed.
+      */
+      if(data->set.max_send_speed &&
+         (included_body_bytes > data->set.max_send_speed)) {
+        curl_off_t overflow = included_body_bytes - data->set.max_send_speed;
+        DEBUGASSERT((size_t)overflow < size);
+        sendsize = size - (size_t)overflow;
+      }
+      else
+        sendsize = size;
+    }
   }
   }
 
 
   result = Curl_write(data, sockfd, ptr, sendsize, &amount);
   result = Curl_write(data, sockfd, ptr, sendsize, &amount);
@@ -1500,7 +1553,7 @@ static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
 
 
   msnprintf(proxy_header,
   msnprintf(proxy_header,
             sizeof(proxy_header),
             sizeof(proxy_header),
-            "PROXY %s %s %s %li %li\r\n",
+            "PROXY %s %s %s %i %i\r\n",
             tcp_version,
             tcp_version,
             data->info.conn_local_ip,
             data->info.conn_local_ip,
             data->info.conn_primary_ip,
             data->info.conn_primary_ip,
@@ -1548,7 +1601,7 @@ static int https_getsock(struct Curl_easy *data,
 {
 {
   (void)data;
   (void)data;
   if(conn->handler->flags & PROTOPT_SSL)
   if(conn->handler->flags & PROTOPT_SSL)
-    return Curl_ssl_getsock(conn, socks);
+    return Curl_ssl->getsock(conn, socks);
   return GETSOCK_BLANK;
   return GETSOCK_BLANK;
 }
 }
 #endif /* USE_SSL */
 #endif /* USE_SSL */
@@ -1621,11 +1674,11 @@ static bool use_http_1_1plus(const struct Curl_easy *data,
 {
 {
   if((data->state.httpversion == 10) || (conn->httpversion == 10))
   if((data->state.httpversion == 10) || (conn->httpversion == 10))
     return FALSE;
     return FALSE;
-  if((data->set.httpversion == CURL_HTTP_VERSION_1_0) &&
+  if((data->state.httpwant == CURL_HTTP_VERSION_1_0) &&
      (conn->httpversion <= 10))
      (conn->httpversion <= 10))
     return FALSE;
     return FALSE;
-  return ((data->set.httpversion == CURL_HTTP_VERSION_NONE) ||
-          (data->set.httpversion >= CURL_HTTP_VERSION_1_1));
+  return ((data->state.httpwant == CURL_HTTP_VERSION_NONE) ||
+          (data->state.httpwant >= CURL_HTTP_VERSION_1_1));
 }
 }
 
 
 #ifndef USE_HYPER
 #ifndef USE_HYPER
@@ -1633,7 +1686,7 @@ static const char *get_http_string(const struct Curl_easy *data,
                                    const struct connectdata *conn)
                                    const struct connectdata *conn)
 {
 {
 #ifdef ENABLE_QUIC
 #ifdef ENABLE_QUIC
-  if((data->set.httpversion == CURL_HTTP_VERSION_3) ||
+  if((data->state.httpwant == CURL_HTTP_VERSION_3) ||
      (conn->httpversion == 30))
      (conn->httpversion == 30))
     return "3";
     return "3";
 #endif
 #endif
@@ -1698,7 +1751,7 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
 
 
   if(
   if(
 #ifdef CURL_DO_LINEEND_CONV
 #ifdef CURL_DO_LINEEND_CONV
-     (handle->set.prefer_ascii) ||
+     (handle->state.prefer_ascii) ||
 #endif
 #endif
      (handle->set.crlf)) {
      (handle->set.crlf)) {
     /* \n will become \r\n later on */
     /* \n will become \r\n later on */
@@ -1960,10 +2013,10 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
 }
 }
 #else
 #else
 /* disabled */
 /* disabled */
-CURLcode Curl_add_timecondition(const struct connectdata *conn,
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
                                 struct dynbuf *req)
                                 struct dynbuf *req)
 {
 {
-  (void)conn;
+  (void)data;
   (void)req;
   (void)req;
   return CURLE_OK;
   return CURLE_OK;
 }
 }
@@ -2174,7 +2227,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
     /* Extract the URL to use in the request. Store in STRING_TEMP_URL for
     /* Extract the URL to use in the request. Store in STRING_TEMP_URL for
        clean-up reasons if the function returns before the free() further
        clean-up reasons if the function returns before the free() further
        down. */
        down. */
-    uc = curl_url_get(h, CURLUPART_URL, &url, 0);
+    uc = curl_url_get(h, CURLUPART_URL, &url, CURLU_NO_DEFAULT_PORT);
     if(uc) {
     if(uc) {
       curl_url_cleanup(h);
       curl_url_cleanup(h);
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
@@ -2205,7 +2258,7 @@ CURLcode Curl_http_target(struct Curl_easy *data,
         }
         }
         if(!type) {
         if(!type) {
           result = Curl_dyn_addf(r, ";type=%c",
           result = Curl_dyn_addf(r, ";type=%c",
-                                 data->set.prefer_ascii ? 'a' : 'i');
+                                 data->state.prefer_ascii ? 'a' : 'i');
           if(result)
           if(result)
             return result;
             return result;
         }
         }
@@ -2614,8 +2667,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
       }
       }
     }
     }
     /* issue the request */
     /* issue the request */
-    result = Curl_buffer_send(r, data, &data->info.request_size,
-                              (size_t)included_body, FIRSTSOCKET);
+    result = Curl_buffer_send(r, data, &data->info.request_size, included_body,
+                              FIRSTSOCKET);
 
 
     if(result)
     if(result)
       failf(data, "Failed sending HTTP POST request");
       failf(data, "Failed sending HTTP POST request");
@@ -2946,7 +2999,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
       default:
       default:
         /* Check if user wants to use HTTP/2 with clear TCP*/
         /* Check if user wants to use HTTP/2 with clear TCP*/
 #ifdef USE_NGHTTP2
 #ifdef USE_NGHTTP2
-        if(data->set.httpversion == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+        if(data->state.httpwant == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
           if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
           if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
             /* We don't support HTTP/2 proxies yet. Also it's debatable
             /* We don't support HTTP/2 proxies yet. Also it's debatable
@@ -3002,8 +3055,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   }
   }
 
 
   Curl_safefree(data->state.aptr.ref);
   Curl_safefree(data->state.aptr.ref);
-  if(data->change.referer && !Curl_checkheaders(data, "Referer")) {
-    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+  if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
     if(!data->state.aptr.ref)
     if(!data->state.aptr.ref)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
   }
   }
@@ -3016,10 +3069,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     if(!data->state.aptr.accept_encoding)
     if(!data->state.aptr.accept_encoding)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
   }
   }
-  else {
+  else
     Curl_safefree(data->state.aptr.accept_encoding);
     Curl_safefree(data->state.aptr.accept_encoding);
-    data->state.aptr.accept_encoding = NULL;
-  }
 
 
 #ifdef HAVE_LIBZ
 #ifdef HAVE_LIBZ
   /* we only consider transfer-encoding magic if libz support is built-in */
   /* we only consider transfer-encoding magic if libz support is built-in */
@@ -3071,6 +3122,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   /* initialize a dynamic send-buffer */
   /* initialize a dynamic send-buffer */
   Curl_dyn_init(&req, DYN_HTTP_REQUEST);
   Curl_dyn_init(&req, DYN_HTTP_REQUEST);
 
 
+  /* make sure the header buffer is reset - if there are leftovers from a
+     previous transfer */
+  Curl_dyn_reset(&data->state.headerb);
+
   /* add the main request stuff */
   /* add the main request stuff */
   /* GET/HEAD/POST/PUT */
   /* GET/HEAD/POST/PUT */
   result = Curl_dyn_addf(&req, "%s ", request);
   result = Curl_dyn_addf(&req, "%s ", request);
@@ -3124,7 +3179,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
                    *data->set.str[STRING_ENCODING] &&
                    *data->set.str[STRING_ENCODING] &&
                    data->state.aptr.accept_encoding)?
                    data->state.aptr.accept_encoding)?
                   data->state.aptr.accept_encoding:"",
                   data->state.aptr.accept_encoding:"",
-                  (data->change.referer && data->state.aptr.ref)?
+                  (data->state.referer && data->state.aptr.ref)?
                   data->state.aptr.ref:"" /* Referer: <data> */,
                   data->state.aptr.ref:"" /* Referer: <data> */,
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
                   (conn->bits.httpproxy &&
                   (conn->bits.httpproxy &&
@@ -3152,10 +3207,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 
 
   if(!(conn->handler->flags&PROTOPT_SSL) &&
   if(!(conn->handler->flags&PROTOPT_SSL) &&
      conn->httpversion != 20 &&
      conn->httpversion != 20 &&
-     (data->set.httpversion == CURL_HTTP_VERSION_2)) {
+     (data->state.httpwant == CURL_HTTP_VERSION_2)) {
     /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
     /* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
        over SSL */
        over SSL */
-    result = Curl_http2_request_upgrade(&req, conn);
+    result = Curl_http2_request_upgrade(&req, data);
     if(result) {
     if(result) {
       Curl_dyn_free(&req);
       Curl_dyn_free(&req);
       return result;
       return result;
@@ -3333,7 +3388,8 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
   if(!k->http_bodyless &&
   if(!k->http_bodyless &&
      !data->set.ignorecl && checkprefix("Content-Length:", headp)) {
      !data->set.ignorecl && checkprefix("Content-Length:", headp)) {
     curl_off_t contentlength;
     curl_off_t contentlength;
-    CURLofft offt = curlx_strtoofft(headp + 15, NULL, 10, &contentlength);
+    CURLofft offt = curlx_strtoofft(headp + strlen("Content-Length:"),
+                                    NULL, 10, &contentlength);
 
 
     if(offt == CURL_OFFT_OK) {
     if(offt == CURL_OFFT_OK) {
       if(data->set.max_filesize &&
       if(data->set.max_filesize &&
@@ -3432,7 +3488,9 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
      * of chunks, and a chunk-data set to zero signals the
      * of chunks, and a chunk-data set to zero signals the
      * end-of-chunks. */
      * end-of-chunks. */
 
 
-    result = Curl_build_unencoding_stack(data, headp + 18, TRUE);
+    result = Curl_build_unencoding_stack(data,
+                                         headp + strlen("Transfer-Encoding:"),
+                                         TRUE);
     if(result)
     if(result)
       return result;
       return result;
   }
   }
@@ -3445,17 +3503,20 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
      * 2616). zlib cannot handle compress.  However, errors are
      * 2616). zlib cannot handle compress.  However, errors are
      * handled further down when the response body is processed
      * handled further down when the response body is processed
      */
      */
-    result = Curl_build_unencoding_stack(data, headp + 17, FALSE);
+    result = Curl_build_unencoding_stack(data,
+                                         headp + strlen("Content-Encoding:"),
+                                         FALSE);
     if(result)
     if(result)
       return result;
       return result;
   }
   }
   else if(checkprefix("Retry-After:", headp)) {
   else if(checkprefix("Retry-After:", headp)) {
     /* Retry-After = HTTP-date / delay-seconds */
     /* Retry-After = HTTP-date / delay-seconds */
     curl_off_t retry_after = 0; /* zero for unknown or "now" */
     curl_off_t retry_after = 0; /* zero for unknown or "now" */
-    time_t date = Curl_getdate_capped(&headp[12]);
+    time_t date = Curl_getdate_capped(headp + strlen("Retry-After:"));
     if(-1 == date) {
     if(-1 == date) {
       /* not a date, try it as a decimal number */
       /* not a date, try it as a decimal number */
-      (void)curlx_strtoofft(&headp[12], NULL, 10, &retry_after);
+      (void)curlx_strtoofft(headp + strlen("Retry-After:"),
+                            NULL, 10, &retry_after);
     }
     }
     else
     else
       /* convert date to number of seconds into the future */
       /* convert date to number of seconds into the future */
@@ -3474,7 +3535,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
        The forth means the requested range was unsatisfied.
        The forth means the requested range was unsatisfied.
     */
     */
 
 
-    char *ptr = headp + 14;
+    char *ptr = headp + strlen("Content-Range:");
 
 
     /* Move forward until first digit or asterisk */
     /* Move forward until first digit or asterisk */
     while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
     while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
@@ -3497,7 +3558,8 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
     Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
                     CURL_LOCK_ACCESS_SINGLE);
                     CURL_LOCK_ACCESS_SINGLE);
     Curl_cookie_add(data,
     Curl_cookie_add(data,
-                    data->cookies, TRUE, FALSE, headp + 11,
+                    data->cookies, TRUE, FALSE,
+                    headp + strlen("Set-Cookie:"),
                     /* If there is a custom-set Host: name, use it
                     /* If there is a custom-set Host: name, use it
                        here, or else use real peer host name. */
                        here, or else use real peer host name. */
                     data->state.aptr.cookiehost?
                     data->state.aptr.cookiehost?
@@ -3532,7 +3594,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
       return result;
       return result;
   }
   }
 #ifdef USE_SPNEGO
 #ifdef USE_SPNEGO
-  else if(checkprefix("Persistent-Auth", headp)) {
+  else if(checkprefix("Persistent-Auth:", headp)) {
     struct negotiatedata *negdata = &conn->negotiate;
     struct negotiatedata *negdata = &conn->negotiate;
     struct auth *authp = &data->state.authhost;
     struct auth *authp = &data->state.authhost;
     if(authp->picked == CURLAUTH_NEGOTIATE) {
     if(authp->picked == CURLAUTH_NEGOTIATE) {
@@ -3576,13 +3638,13 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
     }
     }
   }
   }
 
 
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
   /* If enabled, the header is incoming and this is over HTTPS */
   /* If enabled, the header is incoming and this is over HTTPS */
   else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) &&
   else if(data->hsts && checkprefix("Strict-Transport-Security:", headp) &&
           (conn->handler->flags & PROTOPT_SSL)) {
           (conn->handler->flags & PROTOPT_SSL)) {
     CURLcode check =
     CURLcode check =
       Curl_hsts_parse(data->hsts, data->state.up.hostname,
       Curl_hsts_parse(data->hsts, data->state.up.hostname,
-                      &headp[ sizeof("Strict-Transport-Security:") -1 ]);
+                      headp + strlen("Strict-Transport-Security:"));
     if(check)
     if(check)
       infof(data, "Illegal STS header skipped\n");
       infof(data, "Illegal STS header skipped\n");
 #ifdef DEBUGBUILD
 #ifdef DEBUGBUILD
@@ -3606,7 +3668,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
     /* the ALPN of the current request */
     /* the ALPN of the current request */
     enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
     enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
     result = Curl_altsvc_parse(data, data->asi,
     result = Curl_altsvc_parse(data, data->asi,
-                               &headp[ strlen("Alt-Svc:") ],
+                               headp + strlen("Alt-Svc:"),
                                id, conn->host.name,
                                id, conn->host.name,
                                curlx_uitous(conn->remote_port));
                                curlx_uitous(conn->remote_port));
     if(result)
     if(result)
@@ -3995,7 +4057,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
                 infof(data, "Got 417 while waiting for a 100\n");
                 infof(data, "Got 417 while waiting for a 100\n");
                 data->state.disableexpect = TRUE;
                 data->state.disableexpect = TRUE;
                 DEBUGASSERT(!data->req.newurl);
                 DEBUGASSERT(!data->req.newurl);
-                data->req.newurl = strdup(data->change.url);
+                data->req.newurl = strdup(data->state.url);
                 Curl_done_sending(data, k);
                 Curl_done_sending(data, k);
               }
               }
               else if(data->set.http_keep_sending_on_error) {
               else if(data->set.http_keep_sending_on_error) {
@@ -4144,10 +4206,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
          */
          */
         char separator;
         char separator;
         char twoorthree[2];
         char twoorthree[2];
+        int httpversion = 0;
         nc = sscanf(HEADER1,
         nc = sscanf(HEADER1,
                     " HTTP/%1d.%1d%c%3d",
                     " HTTP/%1d.%1d%c%3d",
                     &httpversion_major,
                     &httpversion_major,
-                    &conn->httpversion,
+                    &httpversion,
                     &separator,
                     &separator,
                     &k->httpcode);
                     &k->httpcode);
 
 
@@ -4159,7 +4222,23 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
         }
         }
 
 
         if((nc == 4) && (' ' == separator)) {
         if((nc == 4) && (' ' == separator)) {
-          conn->httpversion += 10 * httpversion_major;
+          httpversion += 10 * httpversion_major;
+          switch(httpversion) {
+          case 10:
+          case 11:
+#if defined(USE_NGHTTP2) || defined(USE_HYPER)
+          case 20:
+#endif
+#if defined(ENABLE_QUIC)
+          case 30:
+#endif
+            conn->httpversion = (unsigned char)httpversion;
+            break;
+          default:
+            failf(data, "Unsupported HTTP version (%u.%d) in response",
+                  httpversion/10, httpversion%10);
+            return CURLE_UNSUPPORTED_PROTOCOL;
+          }
 
 
           if(k->upgr101 == UPGR101_RECEIVED) {
           if(k->upgr101 == UPGR101_RECEIVED) {
             /* supposedly upgraded to http2 now */
             /* supposedly upgraded to http2 now */
@@ -4200,14 +4279,14 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
       }
       }
       else if(conn->handler->protocol & CURLPROTO_RTSP) {
       else if(conn->handler->protocol & CURLPROTO_RTSP) {
         char separator;
         char separator;
+        int rtspversion;
         nc = sscanf(HEADER1,
         nc = sscanf(HEADER1,
                     " RTSP/%1d.%1d%c%3d",
                     " RTSP/%1d.%1d%c%3d",
                     &rtspversion_major,
                     &rtspversion_major,
-                    &conn->rtspversion,
+                    &rtspversion,
                     &separator,
                     &separator,
                     &k->httpcode);
                     &k->httpcode);
         if((nc == 4) && (' ' == separator)) {
         if((nc == 4) && (' ' == separator)) {
-          conn->rtspversion += 10 * rtspversion_major;
           conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
           conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
         }
         }
         else {
         else {

+ 11 - 5
lib/http.h

@@ -58,7 +58,7 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
 CURLcode Curl_buffer_send(struct dynbuf *in,
 CURLcode Curl_buffer_send(struct dynbuf *in,
                           struct Curl_easy *data,
                           struct Curl_easy *data,
                           curl_off_t *bytes_written,
                           curl_off_t *bytes_written,
-                          size_t included_body_bytes,
+                          curl_off_t included_body_bytes,
                           int socketindex);
                           int socketindex);
 #else
 #else
 #define Curl_buffer_send(a,b,c,d,e) CURLE_OK
 #define Curl_buffer_send(a,b,c,d,e) CURLE_OK
@@ -184,8 +184,7 @@ struct HTTP {
   enum {
   enum {
     HTTPSEND_NADA,    /* init */
     HTTPSEND_NADA,    /* init */
     HTTPSEND_REQUEST, /* sending a request */
     HTTPSEND_REQUEST, /* sending a request */
-    HTTPSEND_BODY,    /* sending body */
-    HTTPSEND_LAST     /* never use this */
+    HTTPSEND_BODY     /* sending body */
   } sending;
   } sending;
 
 
 #ifndef CURL_DISABLE_HTTP
 #ifndef CURL_DISABLE_HTTP
@@ -211,6 +210,7 @@ struct HTTP {
   char **push_headers;       /* allocated array */
   char **push_headers;       /* allocated array */
   size_t push_headers_used;  /* number of entries filled in */
   size_t push_headers_used;  /* number of entries filled in */
   size_t push_headers_alloc; /* number of entries allocated */
   size_t push_headers_alloc; /* number of entries allocated */
+  uint32_t error; /* HTTP/2 stream error code */
 #endif
 #endif
 #if defined(USE_NGHTTP2) || defined(USE_NGHTTP3)
 #if defined(USE_NGHTTP2) || defined(USE_NGHTTP3)
   bool closed; /* TRUE on HTTP2 stream close */
   bool closed; /* TRUE on HTTP2 stream close */
@@ -251,9 +251,16 @@ struct h2settings {
 struct http_conn {
 struct http_conn {
 #ifdef USE_NGHTTP2
 #ifdef USE_NGHTTP2
 #define H2_BINSETTINGS_LEN 80
 #define H2_BINSETTINGS_LEN 80
-  nghttp2_session *h2;
   uint8_t binsettings[H2_BINSETTINGS_LEN];
   uint8_t binsettings[H2_BINSETTINGS_LEN];
   size_t  binlen; /* length of the binsettings data */
   size_t  binlen; /* length of the binsettings data */
+
+  /* We associate the connnectdata struct with the connection, but we need to
+     make sure we can identify the current "driving" transfer. This is a
+     work-around for the lack of nghttp2_session_set_user_data() in older
+     nghttp2 versions that we want to support. (Added in 1.31.0) */
+  struct Curl_easy *trnsfr;
+
+  nghttp2_session *h2;
   Curl_send *send_underlying; /* underlying send Curl_send callback */
   Curl_send *send_underlying; /* underlying send Curl_send callback */
   Curl_recv *recv_underlying; /* underlying recv Curl_recv callback */
   Curl_recv *recv_underlying; /* underlying recv Curl_recv callback */
   char *inbuf; /* buffer to receive data from underlying socket */
   char *inbuf; /* buffer to receive data from underlying socket */
@@ -274,7 +281,6 @@ struct http_conn {
   /* list of settings that will be sent */
   /* list of settings that will be sent */
   nghttp2_settings_entry local_settings[3];
   nghttp2_settings_entry local_settings[3];
   size_t local_settings_num;
   size_t local_settings_num;
-  uint32_t error_code; /* HTTP/2 error code */
 #else
 #else
   int unused; /* prevent a compiler warning */
   int unused; /* prevent a compiler warning */
 #endif
 #endif

+ 138 - 81
lib/http2.c

@@ -211,6 +211,24 @@ static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
   return dead;
   return dead;
 }
 }
 
 
+/*
+ * Set the transfer that is currently using this HTTP/2 connection.
+ */
+static void set_transfer(struct http_conn *c,
+                         struct Curl_easy *data)
+{
+  c->trnsfr = data;
+}
+
+/*
+ * Get the transfer that is currently using this HTTP/2 connection.
+ */
+static struct Curl_easy *get_transfer(struct http_conn *c)
+{
+  DEBUGASSERT(c && c->trnsfr);
+  return c->trnsfr;
+}
+
 static unsigned int http2_conncheck(struct Curl_easy *data,
 static unsigned int http2_conncheck(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     struct connectdata *conn,
                                     unsigned int checks_to_perform)
                                     unsigned int checks_to_perform)
@@ -247,6 +265,7 @@ static unsigned int http2_conncheck(struct Curl_easy *data,
   }
   }
 
 
   if(send_frames) {
   if(send_frames) {
+    set_transfer(c, data); /* set the transfer */
     rc = nghttp2_session_send(c->h2);
     rc = nghttp2_session_send(c->h2);
     if(rc)
     if(rc)
       failf(data, "nghttp2_session_send() failed: %s(%d)",
       failf(data, "nghttp2_session_send() failed: %s(%d)",
@@ -269,6 +288,7 @@ void Curl_http2_setup_req(struct Curl_easy *data)
   http->mem = NULL;
   http->mem = NULL;
   http->len = 0;
   http->len = 0;
   http->memlen = 0;
   http->memlen = 0;
+  http->error = NGHTTP2_NO_ERROR;
 }
 }
 
 
 /* called from http_setup_conn */
 /* called from http_setup_conn */
@@ -276,7 +296,6 @@ void Curl_http2_setup_conn(struct connectdata *conn)
 {
 {
   conn->proto.httpc.settings.max_concurrent_streams =
   conn->proto.httpc.settings.max_concurrent_streams =
     DEFAULT_MAX_CONCURRENT_STREAMS;
     DEFAULT_MAX_CONCURRENT_STREAMS;
-  conn->proto.httpc.error_code = NGHTTP2_NO_ERROR;
 }
 }
 
 
 /*
 /*
@@ -300,6 +319,7 @@ static const struct Curl_handler Curl_handler_http2 = {
   http2_disconnect,                     /* disconnect */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   http2_conncheck,                      /* connection_check */
   http2_conncheck,                      /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_HTTP,                            /* defport */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTP,                       /* protocol */
   CURLPROTO_HTTP,                       /* protocol */
   CURLPROTO_HTTP,                       /* family */
   CURLPROTO_HTTP,                       /* family */
@@ -322,6 +342,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
   http2_disconnect,                     /* disconnect */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   http2_conncheck,                      /* connection_check */
   http2_conncheck,                      /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_HTTP,                            /* defport */
   PORT_HTTP,                            /* defport */
   CURLPROTO_HTTPS,                      /* protocol */
   CURLPROTO_HTTPS,                      /* protocol */
   CURLPROTO_HTTP,                       /* family */
   CURLPROTO_HTTP,                       /* family */
@@ -349,6 +370,7 @@ static ssize_t send_callback(nghttp2_session *h2,
 {
 {
   struct connectdata *conn = (struct connectdata *)userp;
   struct connectdata *conn = (struct connectdata *)userp;
   struct http_conn *c = &conn->proto.httpc;
   struct http_conn *c = &conn->proto.httpc;
+  struct Curl_easy *data = get_transfer(c);
   ssize_t written;
   ssize_t written;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
 
 
@@ -359,7 +381,7 @@ static ssize_t send_callback(nghttp2_session *h2,
     /* called before setup properly! */
     /* called before setup properly! */
     return NGHTTP2_ERR_CALLBACK_FAILURE;
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
 
-  written = ((Curl_send*)c->send_underlying)(conn->data, FIRSTSOCKET,
+  written = ((Curl_send*)c->send_underlying)(data, FIRSTSOCKET,
                                              mem, length, &result);
                                              mem, length, &result);
 
 
   if(result == CURLE_AGAIN) {
   if(result == CURLE_AGAIN) {
@@ -367,7 +389,7 @@ static ssize_t send_callback(nghttp2_session *h2,
   }
   }
 
 
   if(written == -1) {
   if(written == -1) {
-    failf(conn->data, "Failed sending HTTP2 data");
+    failf(data, "Failed sending HTTP2 data");
     return NGHTTP2_ERR_CALLBACK_FAILURE;
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
   }
 
 
@@ -479,38 +501,48 @@ static int set_transfer_url(struct Curl_easy *data,
   const char *v;
   const char *v;
   CURLU *u = curl_url();
   CURLU *u = curl_url();
   CURLUcode uc;
   CURLUcode uc;
-  char *url;
+  char *url = NULL;
+  int rc = 0;
 
 
   v = curl_pushheader_byname(hp, ":scheme");
   v = curl_pushheader_byname(hp, ":scheme");
   if(v) {
   if(v) {
     uc = curl_url_set(u, CURLUPART_SCHEME, v, 0);
     uc = curl_url_set(u, CURLUPART_SCHEME, v, 0);
-    if(uc)
-      return 1;
+    if(uc) {
+      rc = 1;
+      goto fail;
+    }
   }
   }
 
 
   v = curl_pushheader_byname(hp, ":authority");
   v = curl_pushheader_byname(hp, ":authority");
   if(v) {
   if(v) {
     uc = curl_url_set(u, CURLUPART_HOST, v, 0);
     uc = curl_url_set(u, CURLUPART_HOST, v, 0);
-    if(uc)
-      return 2;
+    if(uc) {
+      rc = 2;
+      goto fail;
+    }
   }
   }
 
 
   v = curl_pushheader_byname(hp, ":path");
   v = curl_pushheader_byname(hp, ":path");
   if(v) {
   if(v) {
     uc = curl_url_set(u, CURLUPART_PATH, v, 0);
     uc = curl_url_set(u, CURLUPART_PATH, v, 0);
-    if(uc)
-      return 3;
+    if(uc) {
+      rc = 3;
+      goto fail;
+    }
   }
   }
 
 
   uc = curl_url_get(u, CURLUPART_URL, &url, 0);
   uc = curl_url_get(u, CURLUPART_URL, &url, 0);
   if(uc)
   if(uc)
-    return 4;
+    rc = 4;
+  fail:
   curl_url_cleanup(u);
   curl_url_cleanup(u);
+  if(rc)
+    return rc;
 
 
-  if(data->change.url_alloc)
-    free(data->change.url);
-  data->change.url_alloc = TRUE;
-  data->change.url = url;
+  if(data->state.url_alloc)
+    free(data->state.url);
+  data->state.url_alloc = TRUE;
+  data->state.url = url;
   return 0;
   return 0;
 }
 }
 
 
@@ -551,6 +583,7 @@ static int push_promise(struct Curl_easy *data,
 
 
     rv = set_transfer_url(newhandle, &heads);
     rv = set_transfer_url(newhandle, &heads);
     if(rv) {
     if(rv) {
+      (void)Curl_close(&newhandle);
       rv = CURL_PUSH_DENY;
       rv = CURL_PUSH_DENY;
       goto fail;
       goto fail;
     }
     }
@@ -633,6 +666,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
   struct http_conn *httpc = &conn->proto.httpc;
   struct http_conn *httpc = &conn->proto.httpc;
   struct Curl_easy *data_s = NULL;
   struct Curl_easy *data_s = NULL;
   struct HTTP *stream = NULL;
   struct HTTP *stream = NULL;
+  struct Curl_easy *data = get_transfer(httpc);
   int rv;
   int rv;
   size_t left, ncopy;
   size_t left, ncopy;
   int32_t stream_id = frame->hd.stream_id;
   int32_t stream_id = frame->hd.stream_id;
@@ -642,30 +676,30 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
     /* stream ID zero is for connection-oriented stuff */
     /* stream ID zero is for connection-oriented stuff */
     if(frame->hd.type == NGHTTP2_SETTINGS) {
     if(frame->hd.type == NGHTTP2_SETTINGS) {
       uint32_t max_conn = httpc->settings.max_concurrent_streams;
       uint32_t max_conn = httpc->settings.max_concurrent_streams;
-      H2BUGF(infof(conn->data, "Got SETTINGS\n"));
+      H2BUGF(infof(data, "Got SETTINGS\n"));
       httpc->settings.max_concurrent_streams =
       httpc->settings.max_concurrent_streams =
         nghttp2_session_get_remote_settings(
         nghttp2_session_get_remote_settings(
           session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
           session, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
       httpc->settings.enable_push =
       httpc->settings.enable_push =
         nghttp2_session_get_remote_settings(
         nghttp2_session_get_remote_settings(
           session, NGHTTP2_SETTINGS_ENABLE_PUSH);
           session, NGHTTP2_SETTINGS_ENABLE_PUSH);
-      H2BUGF(infof(conn->data, "MAX_CONCURRENT_STREAMS == %d\n",
+      H2BUGF(infof(data, "MAX_CONCURRENT_STREAMS == %d\n",
                    httpc->settings.max_concurrent_streams));
                    httpc->settings.max_concurrent_streams));
-      H2BUGF(infof(conn->data, "ENABLE_PUSH == %s\n",
+      H2BUGF(infof(data, "ENABLE_PUSH == %s\n",
                    httpc->settings.enable_push?"TRUE":"false"));
                    httpc->settings.enable_push?"TRUE":"false"));
       if(max_conn != httpc->settings.max_concurrent_streams) {
       if(max_conn != httpc->settings.max_concurrent_streams) {
         /* only signal change if the value actually changed */
         /* only signal change if the value actually changed */
-        infof(conn->data,
+        infof(data,
               "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!\n",
               "Connection state changed (MAX_CONCURRENT_STREAMS == %u)!\n",
               httpc->settings.max_concurrent_streams);
               httpc->settings.max_concurrent_streams);
-        multi_connchanged(conn->data->multi);
+        multi_connchanged(data->multi);
       }
       }
     }
     }
     return 0;
     return 0;
   }
   }
   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
   if(!data_s) {
   if(!data_s) {
-    H2BUGF(infof(conn->data,
+    H2BUGF(infof(data,
                  "No Curl_easy associated with stream: %x\n",
                  "No Curl_easy associated with stream: %x\n",
                  stream_id));
                  stream_id));
     return 0;
     return 0;
@@ -733,14 +767,9 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
     stream->memlen += ncopy;
     stream->memlen += ncopy;
 
 
     drain_this(data_s, httpc);
     drain_this(data_s, httpc);
-    {
-      /* get the pointer from userp again since it was re-assigned above */
-      struct connectdata *conn_s = (struct connectdata *)userp;
-
-      /* if we receive data for another handle, wake that up */
-      if(conn_s->data != data_s)
-        Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
-    }
+    /* if we receive data for another handle, wake that up */
+    if(get_transfer(httpc) != data_s)
+      Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
     break;
     break;
   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);
@@ -768,15 +797,15 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
 
 
 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
 static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
                               int32_t stream_id,
                               int32_t stream_id,
-                              const uint8_t *data, size_t len, void *userp)
+                              const uint8_t *mem, size_t len, void *userp)
 {
 {
   struct HTTP *stream;
   struct HTTP *stream;
   struct Curl_easy *data_s;
   struct Curl_easy *data_s;
   size_t nread;
   size_t nread;
   struct connectdata *conn = (struct connectdata *)userp;
   struct connectdata *conn = (struct connectdata *)userp;
+  struct http_conn *httpc = &conn->proto.httpc;
   (void)session;
   (void)session;
   (void)flags;
   (void)flags;
-  (void)data;
 
 
   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
 
 
@@ -792,7 +821,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
     return NGHTTP2_ERR_CALLBACK_FAILURE;
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
 
   nread = CURLMIN(stream->len, len);
   nread = CURLMIN(stream->len, len);
-  memcpy(&stream->mem[stream->memlen], data, nread);
+  memcpy(&stream->mem[stream->memlen], mem, nread);
 
 
   stream->len -= nread;
   stream->len -= nread;
   stream->memlen += nread;
   stream->memlen += nread;
@@ -800,7 +829,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
   drain_this(data_s, &conn->proto.httpc);
   drain_this(data_s, &conn->proto.httpc);
 
 
   /* if we receive data for another handle, wake that up */
   /* if we receive data for another handle, wake that up */
-  if(conn->data != data_s)
+  if(get_transfer(httpc) != data_s)
     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
 
 
   H2BUGF(infof(data_s, "%zu data received for stream %u "
   H2BUGF(infof(data_s, "%zu data received for stream %u "
@@ -810,7 +839,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
                stream->memlen));
                stream->memlen));
 
 
   if(nread < len) {
   if(nread < len) {
-    stream->pausedata = data + nread;
+    stream->pausedata = mem + nread;
     stream->pauselen = len - nread;
     stream->pauselen = len - nread;
     H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
     H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
                  ", stream %u\n",
                  ", stream %u\n",
@@ -822,7 +851,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
 
 
   /* pause execution of nghttp2 if we received data for another handle
   /* pause execution of nghttp2 if we received data for another handle
      in order to process them first. */
      in order to process them first. */
-  if(conn->data != data_s) {
+  if(get_transfer(httpc) != data_s) {
     data_s->conn->proto.httpc.pause_stream_id = stream_id;
     data_s->conn->proto.httpc.pause_stream_id = stream_id;
 
 
     return NGHTTP2_ERR_PAUSE;
     return NGHTTP2_ERR_PAUSE;
@@ -861,7 +890,7 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
     httpc = &conn->proto.httpc;
     httpc = &conn->proto.httpc;
     drain_this(data_s, httpc);
     drain_this(data_s, httpc);
     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
-    httpc->error_code = error_code;
+    stream->error = error_code;
 
 
     /* remove the entry from the hash as the stream is now gone */
     /* remove the entry from the hash as the stream is now gone */
     rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
     rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
@@ -944,6 +973,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
   struct Curl_easy *data_s;
   struct Curl_easy *data_s;
   int32_t stream_id = frame->hd.stream_id;
   int32_t stream_id = frame->hd.stream_id;
   struct connectdata *conn = (struct connectdata *)userp;
   struct connectdata *conn = (struct connectdata *)userp;
+  struct http_conn *httpc = &conn->proto.httpc;
   CURLcode result;
   CURLcode result;
   (void)flags;
   (void)flags;
 
 
@@ -1049,7 +1079,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
     if(result)
     if(result)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     /* if we receive data for another handle, wake that up */
     /* if we receive data for another handle, wake that up */
-    if(conn->data != data_s)
+    if(get_transfer(httpc) != data_s)
       Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
       Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
 
 
     H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
     H2BUGF(infof(data_s, "h2 status: HTTP/2 %03d (easy %p)\n",
@@ -1073,7 +1103,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
   if(result)
   if(result)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   /* if we receive data for another handle, wake that up */
   /* if we receive data for another handle, wake that up */
-  if(conn->data != data_s)
+  if(get_transfer(httpc) != data_s)
     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
     Curl_expire(data_s, 0, EXPIRE_RUN_NOW);
 
 
   H2BUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
   H2BUGF(infof(data_s, "h2 header: %.*s: %.*s\n", namelen, name, valuelen,
@@ -1138,27 +1168,27 @@ static int error_callback(nghttp2_session *session,
                           size_t len,
                           size_t len,
                           void *userp)
                           void *userp)
 {
 {
-  struct connectdata *conn = (struct connectdata *)userp;
   (void)session;
   (void)session;
-  infof(conn->data, "http2 error: %.*s\n", len, msg);
+  (void)msg;
+  (void)len;
+  (void)userp;
   return 0;
   return 0;
 }
 }
 #endif
 #endif
 
 
-static void populate_settings(struct connectdata *conn,
+static void populate_settings(struct Curl_easy *data,
                               struct http_conn *httpc)
                               struct http_conn *httpc)
 {
 {
   nghttp2_settings_entry *iv = httpc->local_settings;
   nghttp2_settings_entry *iv = httpc->local_settings;
-  DEBUGASSERT(conn->data);
 
 
   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
   iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
-  iv[0].value = Curl_multi_max_concurrent_streams(conn->data->multi);
+  iv[0].value = Curl_multi_max_concurrent_streams(data->multi);
 
 
   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
   iv[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
   iv[1].value = HTTP2_HUGE_WINDOW_SIZE;
   iv[1].value = HTTP2_HUGE_WINDOW_SIZE;
 
 
   iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
   iv[2].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
-  iv[2].value = conn->data->multi->push_cb != NULL;
+  iv[2].value = data->multi->push_cb != NULL;
 
 
   httpc->local_settings_num = 3;
   httpc->local_settings_num = 3;
 }
 }
@@ -1187,6 +1217,7 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
 
 
   if(premature) {
   if(premature) {
     /* RST_STREAM */
     /* RST_STREAM */
+    set_transfer(httpc, data); /* set the transfer */
     if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
     if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
                                   http->stream_id, NGHTTP2_STREAM_CLOSED))
                                   http->stream_id, NGHTTP2_STREAM_CLOSED))
       (void)nghttp2_session_send(httpc->h2);
       (void)nghttp2_session_send(httpc->h2);
@@ -1209,6 +1240,7 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
             http->stream_id);
             http->stream_id);
       DEBUGASSERT(0);
       DEBUGASSERT(0);
     }
     }
+    set_transfer(httpc, NULL);
     http->stream_id = 0;
     http->stream_id = 0;
   }
   }
 }
 }
@@ -1223,7 +1255,7 @@ static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
     nghttp2_session_callbacks *callbacks;
     nghttp2_session_callbacks *callbacks;
 
 
     conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
     conn->proto.httpc.inbuf = malloc(H2_BUFSIZE);
-    if(conn->proto.httpc.inbuf == NULL)
+    if(!conn->proto.httpc.inbuf)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
 
 
     rc = nghttp2_session_callbacks_new(&callbacks);
     rc = nghttp2_session_callbacks_new(&callbacks);
@@ -1269,18 +1301,18 @@ static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
  * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
  * Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
  */
  */
 CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
 CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
-                                    struct connectdata *conn)
+                                    struct Curl_easy *data)
 {
 {
   CURLcode result;
   CURLcode result;
   ssize_t binlen;
   ssize_t binlen;
   char *base64;
   char *base64;
   size_t blen;
   size_t blen;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct SingleRequest *k = &data->req;
   struct SingleRequest *k = &data->req;
   uint8_t *binsettings = conn->proto.httpc.binsettings;
   uint8_t *binsettings = conn->proto.httpc.binsettings;
   struct http_conn *httpc = &conn->proto.httpc;
   struct http_conn *httpc = &conn->proto.httpc;
 
 
-  populate_settings(conn, httpc);
+  populate_settings(data, httpc);
 
 
   /* this returns number of bytes it wrote */
   /* this returns number of bytes it wrote */
   binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
   binlen = nghttp2_pack_settings_payload(binsettings, H2_BINSETTINGS_LEN,
@@ -1338,6 +1370,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
   nread = httpc->inbuflen - httpc->nread_inbuf;
   nread = httpc->inbuflen - httpc->nread_inbuf;
   inbuf = httpc->inbuf + httpc->nread_inbuf;
   inbuf = httpc->inbuf + httpc->nread_inbuf;
 
 
+  set_transfer(httpc, data); /* set the transfer */
   rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
   rv = nghttp2_session_mem_recv(httpc->h2, (const uint8_t *)inbuf, nread);
   if(rv < 0) {
   if(rv < 0) {
     failf(data,
     failf(data,
@@ -1363,7 +1396,7 @@ static int h2_process_pending_input(struct Curl_easy *data,
   }
   }
 
 
   rv = h2_session_send(data, httpc->h2);
   rv = h2_session_send(data, httpc->h2);
-  if(rv != 0) {
+  if(rv) {
     *err = CURLE_SEND_ERROR;
     *err = CURLE_SEND_ERROR;
     return -1;
     return -1;
   }
   }
@@ -1377,9 +1410,10 @@ static int h2_process_pending_input(struct Curl_easy *data,
   }
   }
 
 
   if(should_close_session(httpc)) {
   if(should_close_session(httpc)) {
+    struct HTTP *stream = data->req.p.http;
     H2BUGF(infof(data,
     H2BUGF(infof(data,
                  "h2_process_pending_input: nothing to do in this session\n"));
                  "h2_process_pending_input: nothing to do in this session\n"));
-    if(httpc->error_code)
+    if(stream->error)
       *err = CURLE_HTTP2;
       *err = CURLE_HTTP2;
     else {
     else {
       /* not an error per se, but should still close the connection */
       /* not an error per se, but should still close the connection */
@@ -1402,9 +1436,7 @@ CURLcode Curl_http2_done_sending(struct Curl_easy *data,
   if((conn->handler == &Curl_handler_http2_ssl) ||
   if((conn->handler == &Curl_handler_http2_ssl) ||
      (conn->handler == &Curl_handler_http2)) {
      (conn->handler == &Curl_handler_http2)) {
     /* make sure this is only attempted for HTTP/2 transfers */
     /* make sure this is only attempted for HTTP/2 transfers */
-
     struct HTTP *stream = data->req.p.http;
     struct HTTP *stream = data->req.p.http;
-
     struct http_conn *httpc = &conn->proto.httpc;
     struct http_conn *httpc = &conn->proto.httpc;
     nghttp2_session *h2 = httpc->h2;
     nghttp2_session *h2 = httpc->h2;
 
 
@@ -1426,13 +1458,15 @@ CURLcode Curl_http2_done_sending(struct Curl_easy *data,
 
 
       H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)\n", data));
       H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)\n", data));
 
 
-      /* re-set KEEP_SEND to make sure we are called again */
-      k->keepon |= KEEP_SEND;
-
       /* and attempt to send the pending frames */
       /* and attempt to send the pending frames */
       rv = h2_session_send(data, h2);
       rv = h2_session_send(data, h2);
-      if(rv != 0)
+      if(rv)
         result = CURLE_SEND_ERROR;
         result = CURLE_SEND_ERROR;
+
+      if(nghttp2_session_want_write(h2)) {
+         /* re-set KEEP_SEND to make sure we are called again */
+         k->keepon |= KEEP_SEND;
+      }
     }
     }
   }
   }
   return result;
   return result;
@@ -1460,7 +1494,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
 
 
   /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
   /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
   stream->closed = FALSE;
   stream->closed = FALSE;
-  if(httpc->error_code == NGHTTP2_REFUSED_STREAM) {
+  if(stream->error == NGHTTP2_REFUSED_STREAM) {
     H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!\n",
     H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!\n",
                  stream->stream_id));
                  stream->stream_id));
     connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
     connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
@@ -1468,10 +1502,10 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
     *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
     *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
     return -1;
     return -1;
   }
   }
-  else if(httpc->error_code != NGHTTP2_NO_ERROR) {
+  else if(stream->error != 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_http2_strerror(httpc->error_code),
-          httpc->error_code);
+          stream->stream_id, nghttp2_http2_strerror(stream->error),
+          stream->error);
     *err = CURLE_HTTP2_STREAM;
     *err = CURLE_HTTP2_STREAM;
     return -1;
     return -1;
   }
   }
@@ -1542,6 +1576,8 @@ static int h2_session_send(struct Curl_easy *data,
                            nghttp2_session *h2)
                            nghttp2_session *h2)
 {
 {
   struct HTTP *stream = data->req.p.http;
   struct HTTP *stream = data->req.p.http;
+  struct http_conn *httpc = &data->conn->proto.httpc;
+  set_transfer(httpc, data);
   if((data->set.stream_weight != data->state.stream_weight) ||
   if((data->set.stream_weight != data->state.stream_weight) ||
      (data->set.stream_depends_e != data->state.stream_depends_e) ||
      (data->set.stream_depends_e != data->state.stream_depends_e) ||
      (data->set.stream_depends_on != data->state.stream_depends_on) ) {
      (data->set.stream_depends_on != data->state.stream_depends_on) ) {
@@ -1585,6 +1621,10 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
     return -1;
     return -1;
   }
   }
 
 
+  if(stream->closed)
+    /* closed overrides paused */
+    return http2_handle_stream_close(conn, data, stream, err);
+
   /* Nullify here because we call nghttp2_session_send() and they
   /* Nullify here because we call nghttp2_session_send() and they
      might refer to the old buffer. */
      might refer to the old buffer. */
   stream->upload_mem = NULL;
   stream->upload_mem = NULL;
@@ -1707,6 +1747,17 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
       }
       }
 
 
       if(nread == 0) {
       if(nread == 0) {
+        if(!stream->closed) {
+          /* This will happen when the server or proxy server is SIGKILLed
+             during data transfer. We should emit an error since our data
+             received may be incomplete. */
+          failf(data, "HTTP/2 stream %d was not closed cleanly before"
+                " end of the underlying stream",
+                stream->stream_id);
+          *err = CURLE_HTTP2_STREAM;
+          return -1;
+        }
+
         H2BUGF(infof(data, "end of stream\n"));
         H2BUGF(infof(data, "end of stream\n"));
         *err = CURLE_OK;
         *err = CURLE_OK;
         return 0;
         return 0;
@@ -1725,7 +1776,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
                    nread));
                    nread));
     }
     }
 
 
-    if(h2_process_pending_input(data, httpc, err) != 0)
+    if(h2_process_pending_input(data, httpc, err))
       return -1;
       return -1;
   }
   }
   if(stream->memlen) {
   if(stream->memlen) {
@@ -1750,7 +1801,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
     return retlen;
     return retlen;
   }
   }
   if(stream->closed)
   if(stream->closed)
-    return 0;
+    return http2_handle_stream_close(conn, data, stream, err);
   *err = CURLE_AGAIN;
   *err = CURLE_AGAIN;
   H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
   H2BUGF(infof(data, "http2_recv returns AGAIN for stream %u\n",
                stream->stream_id));
                stream->stream_id));
@@ -1925,7 +1976,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
      more space. */
      more space. */
   nheader += 1;
   nheader += 1;
   nva = malloc(sizeof(nghttp2_nv) * nheader);
   nva = malloc(sizeof(nghttp2_nv) * nheader);
-  if(nva == NULL) {
+  if(!nva) {
     *err = CURLE_OUT_OF_MEMORY;
     *err = CURLE_OUT_OF_MEMORY;
     return -1;
     return -1;
   }
   }
@@ -2048,7 +2099,7 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
   }
   }
 
 
   /* :authority must come before non-pseudo header fields */
   /* :authority must come before non-pseudo header fields */
-  if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
+  if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
     nghttp2_nv authority = nva[authority_idx];
     nghttp2_nv authority = nva[authority_idx];
     for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
     for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
       nva[i] = nva[i - 1];
       nva[i] = nva[i - 1];
@@ -2117,10 +2168,8 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
         stream_id, (void *)data);
         stream_id, (void *)data);
   stream->stream_id = stream_id;
   stream->stream_id = stream_id;
 
 
-  /* this does not call h2_session_send() since there can not have been any
-   * priority update since the nghttp2_submit_request() call above */
-  rv = nghttp2_session_send(h2);
-  if(rv != 0) {
+  rv = h2_session_send(data, h2);
+  if(rv) {
     H2BUGF(infof(data,
     H2BUGF(infof(data,
                  "http2_send() nghttp2_session_send error (%s)%d\n",
                  "http2_send() nghttp2_session_send error (%s)%d\n",
                  nghttp2_strerror(rv), rv));
                  nghttp2_strerror(rv), rv));
@@ -2226,10 +2275,10 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
     /* stream 1 is opened implicitly on upgrade */
     /* stream 1 is opened implicitly on upgrade */
     stream->stream_id = 1;
     stream->stream_id = 1;
     /* queue SETTINGS frame (again) */
     /* queue SETTINGS frame (again) */
-    rv = nghttp2_session_upgrade(httpc->h2, httpc->binsettings,
-                                 httpc->binlen, NULL);
-    if(rv != 0) {
-      failf(data, "nghttp2_session_upgrade() failed: %s(%d)",
+    rv = nghttp2_session_upgrade2(httpc->h2, httpc->binsettings, httpc->binlen,
+                                  data->state.httpreq == HTTPREQ_HEAD, NULL);
+    if(rv) {
+      failf(data, "nghttp2_session_upgrade2() failed: %s(%d)",
             nghttp2_strerror(rv), rv);
             nghttp2_strerror(rv), rv);
       return CURLE_HTTP2;
       return CURLE_HTTP2;
     }
     }
@@ -2244,14 +2293,14 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
     }
     }
   }
   }
   else {
   else {
-    populate_settings(conn, httpc);
+    populate_settings(data, httpc);
 
 
     /* stream ID is unknown at this point */
     /* stream ID is unknown at this point */
     stream->stream_id = -1;
     stream->stream_id = -1;
     rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE,
     rv = nghttp2_submit_settings(httpc->h2, NGHTTP2_FLAG_NONE,
                                  httpc->local_settings,
                                  httpc->local_settings,
                                  httpc->local_settings_num);
                                  httpc->local_settings_num);
-    if(rv != 0) {
+    if(rv) {
       failf(data, "nghttp2_submit_settings() failed: %s(%d)",
       failf(data, "nghttp2_submit_settings() failed: %s(%d)",
             nghttp2_strerror(rv), rv);
             nghttp2_strerror(rv), rv);
       return CURLE_HTTP2;
       return CURLE_HTTP2;
@@ -2260,7 +2309,7 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
 
 
   rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
   rv = nghttp2_session_set_local_window_size(httpc->h2, NGHTTP2_FLAG_NONE, 0,
                                              HTTP2_HUGE_WINDOW_SIZE);
                                              HTTP2_HUGE_WINDOW_SIZE);
-  if(rv != 0) {
+  if(rv) {
     failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
     failf(data, "nghttp2_session_set_local_window_size() failed: %s(%d)",
           nghttp2_strerror(rv), rv);
           nghttp2_strerror(rv), rv);
     return CURLE_HTTP2;
     return CURLE_HTTP2;
@@ -2288,8 +2337,15 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
 
 
   DEBUGASSERT(httpc->nread_inbuf == 0);
   DEBUGASSERT(httpc->nread_inbuf == 0);
 
 
-  if(-1 == h2_process_pending_input(data, httpc, &result))
-    return CURLE_HTTP2;
+  /* Good enough to call it an end once the remaining payload is copied to the
+   * connection buffer.
+   * Some servers (e.g. nghttpx v1.43.0) may fulfill stream 1 immediately
+   * following the protocol switch other than waiting for the client-side
+   * connection preface. If h2_process_pending_input is invoked here to parse
+   * the remaining payload, stream 1 would be marked as closed too early and
+   * thus ignored in http2_recv (following 252790c53).
+   * The logic in lib/http.c and lib/transfer.c guarantees a following
+   * http2_recv would be invoked very soon. */
 
 
   return CURLE_OK;
   return CURLE_OK;
 }
 }
@@ -2299,7 +2355,8 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause)
   DEBUGASSERT(data);
   DEBUGASSERT(data);
   DEBUGASSERT(data->conn);
   DEBUGASSERT(data->conn);
   /* if it isn't HTTP/2, we're done */
   /* if it isn't HTTP/2, we're done */
-  if(!data->conn->proto.httpc.h2)
+  if(!(data->conn->handler->protocol & PROTO_FAMILY_HTTP) ||
+     !data->conn->proto.httpc.h2)
     return CURLE_OK;
     return CURLE_OK;
 #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
 #ifdef NGHTTP2_HAS_SET_LOCAL_WINDOW_SIZE
   else {
   else {
@@ -2423,10 +2480,10 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data)
 
 
 /* Only call this function for a transfer that already got a HTTP/2
 /* Only call this function for a transfer that already got a HTTP/2
    CURLE_HTTP2_STREAM error! */
    CURLE_HTTP2_STREAM error! */
-bool Curl_h2_http_1_1_error(struct connectdata *conn)
+bool Curl_h2_http_1_1_error(struct Curl_easy *data)
 {
 {
-  struct http_conn *httpc = &conn->proto.httpc;
-  return (httpc->error_code == NGHTTP2_HTTP_1_1_REQUIRED);
+  struct HTTP *stream = data->req.p.http;
+  return (stream->error == NGHTTP2_HTTP_1_1_REQUIRED);
 }
 }
 
 
 #else /* !USE_NGHTTP2 */
 #else /* !USE_NGHTTP2 */

+ 3 - 3
lib/http2.h

@@ -29,7 +29,7 @@
 
 
 /* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting
 /* value for MAX_CONCURRENT_STREAMS we use until we get an updated setting
    from the peer */
    from the peer */
-#define DEFAULT_MAX_CONCURRENT_STREAMS 13
+#define DEFAULT_MAX_CONCURRENT_STREAMS 100
 
 
 /*
 /*
  * Store nghttp2 version info in this buffer, Prefix with a space.  Return
  * Store nghttp2 version info in this buffer, Prefix with a space.  Return
@@ -43,7 +43,7 @@ CURLcode Curl_http2_init(struct connectdata *conn);
 void Curl_http2_init_state(struct UrlState *state);
 void Curl_http2_init_state(struct UrlState *state);
 void Curl_http2_init_userset(struct UserDefined *set);
 void Curl_http2_init_userset(struct UserDefined *set);
 CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
 CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
-                                    struct connectdata *conn);
+                                    struct Curl_easy *data);
 CURLcode Curl_http2_setup(struct Curl_easy *data, struct connectdata *conn);
 CURLcode Curl_http2_setup(struct Curl_easy *data, struct connectdata *conn);
 CURLcode Curl_http2_switched(struct Curl_easy *data,
 CURLcode Curl_http2_switched(struct Curl_easy *data,
                              const char *ptr, size_t nread);
                              const char *ptr, size_t nread);
@@ -62,7 +62,7 @@ void Curl_http2_cleanup_dependencies(struct Curl_easy *data);
 CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause);
 CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause);
 
 
 /* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */
 /* returns true if the HTTP/2 stream error was HTTP_1_1_REQUIRED */
-bool Curl_h2_http_1_1_error(struct connectdata *conn);
+bool Curl_h2_http_1_1_error(struct Curl_easy *data);
 #else /* USE_NGHTTP2 */
 #else /* USE_NGHTTP2 */
 #define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_setup(x,y) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_setup(x,y) CURLE_UNSUPPORTED_PROTOCOL

+ 2 - 2
lib/http_aws_sigv4.c

@@ -99,8 +99,8 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   char *request_type = NULL;
   char *request_type = NULL;
   char *credential_scope = NULL;
   char *credential_scope = NULL;
   char *str_to_sign = NULL;
   char *str_to_sign = NULL;
-  const char *user = conn->user ? conn->user : "";
-  const char *passwd = conn->passwd ? conn->passwd : "";
+  const char *user = data->state.aptr.user ? data->state.aptr.user : "";
+  const char *passwd = data->state.aptr.passwd ? data->state.aptr.passwd : "";
   char *secret = NULL;
   char *secret = NULL;
   unsigned char tmp_sign0[32] = {0};
   unsigned char tmp_sign0[32] = {0};
   unsigned char tmp_sign1[32] = {0};
   unsigned char tmp_sign1[32] = {0};

+ 5 - 6
lib/http_digest.c

@@ -56,7 +56,7 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
     digest = &data->state.digest;
     digest = &data->state.digest;
   }
   }
 
 
-  if(!checkprefix("Digest", header))
+  if(!checkprefix("Digest", header) || !ISSPACE(header[6]))
     return CURLE_BAD_CONTENT_ENCODING;
     return CURLE_BAD_CONTENT_ENCODING;
 
 
   header += strlen("Digest");
   header += strlen("Digest");
@@ -67,7 +67,6 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
 }
 }
 
 
 CURLcode Curl_output_digest(struct Curl_easy *data,
 CURLcode Curl_output_digest(struct Curl_easy *data,
-                            struct connectdata *conn,
                             bool proxy,
                             bool proxy,
                             const unsigned char *request,
                             const unsigned char *request,
                             const unsigned char *uripath)
                             const unsigned char *uripath)
@@ -97,16 +96,16 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
 #else
 #else
     digest = &data->state.proxydigest;
     digest = &data->state.proxydigest;
     allocuserpwd = &data->state.aptr.proxyuserpwd;
     allocuserpwd = &data->state.aptr.proxyuserpwd;
-    userp = conn->http_proxy.user;
-    passwdp = conn->http_proxy.passwd;
+    userp = data->state.aptr.proxyuser;
+    passwdp = data->state.aptr.proxypasswd;
     authp = &data->state.authproxy;
     authp = &data->state.authproxy;
 #endif
 #endif
   }
   }
   else {
   else {
     digest = &data->state.digest;
     digest = &data->state.digest;
     allocuserpwd = &data->state.aptr.userpwd;
     allocuserpwd = &data->state.aptr.userpwd;
-    userp = conn->user;
-    passwdp = conn->passwd;
+    userp = data->state.aptr.user;
+    passwdp = data->state.aptr.passwd;
     authp = &data->state.authhost;
     authp = &data->state.authhost;
   }
   }
 
 

+ 0 - 1
lib/http_digest.h

@@ -31,7 +31,6 @@ CURLcode Curl_input_digest(struct Curl_easy *data,
 
 
 /* this is for creating digest header output */
 /* this is for creating digest header output */
 CURLcode Curl_output_digest(struct Curl_easy *data,
 CURLcode Curl_output_digest(struct Curl_easy *data,
-                            struct connectdata *conn,
                             bool proxy,
                             bool proxy,
                             const unsigned char *request,
                             const unsigned char *request,
                             const unsigned char *uripath);
                             const unsigned char *uripath);

+ 1 - 1
lib/http_negotiate.c

@@ -179,7 +179,7 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
 
 
     free(base64);
     free(base64);
 
 
-    if(userp == NULL) {
+    if(!userp) {
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
 
 

+ 59 - 43
lib/http_ntlm.c

@@ -39,6 +39,7 @@
 #include "http_ntlm.h"
 #include "http_ntlm.h"
 #include "curl_ntlm_core.h"
 #include "curl_ntlm_core.h"
 #include "curl_ntlm_wb.h"
 #include "curl_ntlm_wb.h"
+#include "curl_base64.h"
 #include "vauth/vauth.h"
 #include "vauth/vauth.h"
 #include "url.h"
 #include "url.h"
 
 
@@ -80,7 +81,18 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data,
       header++;
       header++;
 
 
     if(*header) {
     if(*header) {
-      result = Curl_auth_decode_ntlm_type2_message(data, header, ntlm);
+      unsigned char *hdr;
+      size_t hdrlen;
+
+      result = Curl_base64_decode(header, &hdr, &hdrlen);
+      if(!result) {
+        struct bufref hdrbuf;
+
+        Curl_bufref_init(&hdrbuf);
+        Curl_bufref_set(&hdrbuf, hdr, hdrlen, curl_free);
+        result = Curl_auth_decode_ntlm_type2_message(data, &hdrbuf, ntlm);
+        Curl_bufref_free(&hdrbuf);
+      }
       if(result)
       if(result)
         return result;
         return result;
 
 
@@ -116,7 +128,8 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
 {
 {
   char *base64 = NULL;
   char *base64 = NULL;
   size_t len = 0;
   size_t len = 0;
-  CURLcode result;
+  CURLcode result = CURLE_OK;
+  struct bufref ntlmmsg;
 
 
   /* point to the address of the pointer that holds the string to send to the
   /* point to the address of the pointer that holds the string to send to the
      server, which is for a plain host or for a HTTP proxy */
      server, which is for a plain host or for a HTTP proxy */
@@ -140,10 +153,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
   if(proxy) {
   if(proxy) {
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
     allocuserpwd = &data->state.aptr.proxyuserpwd;
     allocuserpwd = &data->state.aptr.proxyuserpwd;
-    userp = conn->http_proxy.user;
-    passwdp = conn->http_proxy.passwd;
+    userp = data->state.aptr.proxyuser;
+    passwdp = data->state.aptr.proxypasswd;
     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
     service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
-              data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+      data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
     hostname = conn->http_proxy.host.name;
     hostname = conn->http_proxy.host.name;
     ntlm = &conn->proxyntlm;
     ntlm = &conn->proxyntlm;
     state = &conn->proxy_ntlm_state;
     state = &conn->proxy_ntlm_state;
@@ -154,10 +167,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
   }
   }
   else {
   else {
     allocuserpwd = &data->state.aptr.userpwd;
     allocuserpwd = &data->state.aptr.userpwd;
-    userp = conn->user;
-    passwdp = conn->passwd;
+    userp = data->state.aptr.user;
+    passwdp = data->state.aptr.passwd;
     service = data->set.str[STRING_SERVICE_NAME] ?
     service = data->set.str[STRING_SERVICE_NAME] ?
-              data->set.str[STRING_SERVICE_NAME] : "HTTP";
+      data->set.str[STRING_SERVICE_NAME] : "HTTP";
     hostname = conn->host.name;
     hostname = conn->host.name;
     ntlm = &conn->ntlm;
     ntlm = &conn->ntlm;
     state = &conn->http_ntlm_state;
     state = &conn->http_ntlm_state;
@@ -173,10 +186,10 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
     passwdp = "";
     passwdp = "";
 
 
 #ifdef USE_WINDOWS_SSPI
 #ifdef USE_WINDOWS_SSPI
-  if(s_hSecDll == NULL) {
+  if(!s_hSecDll) {
     /* not thread safe and leaks - use curl_global_init() to avoid */
     /* not thread safe and leaks - use curl_global_init() to avoid */
     CURLcode err = Curl_sspi_global_init();
     CURLcode err = Curl_sspi_global_init();
-    if(s_hSecDll == NULL)
+    if(!s_hSecDll)
       return err;
       return err;
   }
   }
 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
 #ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
@@ -184,50 +197,52 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
 #endif
 #endif
 #endif
 #endif
 
 
+  Curl_bufref_init(&ntlmmsg);
   switch(*state) {
   switch(*state) {
   case NTLMSTATE_TYPE1:
   case NTLMSTATE_TYPE1:
   default: /* for the weird cases we (re)start here */
   default: /* for the weird cases we (re)start here */
     /* Create a type-1 message */
     /* Create a type-1 message */
     result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp,
     result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp,
                                                  service, hostname,
                                                  service, hostname,
-                                                 ntlm, &base64,
-                                                 &len);
-    if(result)
-      return result;
-
-    if(base64) {
-      free(*allocuserpwd);
-      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
-                              proxy ? "Proxy-" : "",
-                              base64);
-      free(base64);
-      if(!*allocuserpwd)
-        return CURLE_OUT_OF_MEMORY;
-
-      DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+                                                 ntlm, &ntlmmsg);
+    if(!result) {
+      DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
+      result = Curl_base64_encode(data,
+                                  (const char *) Curl_bufref_ptr(&ntlmmsg),
+                                  Curl_bufref_len(&ntlmmsg), &base64, &len);
+      if(!result) {
+        free(*allocuserpwd);
+        *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                                proxy ? "Proxy-" : "",
+                                base64);
+        free(base64);
+        if(!*allocuserpwd)
+          result = CURLE_OUT_OF_MEMORY;
+      }
     }
     }
     break;
     break;
 
 
   case NTLMSTATE_TYPE2:
   case NTLMSTATE_TYPE2:
     /* We already received the type-2 message, create a type-3 message */
     /* We already received the type-2 message, create a type-3 message */
     result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
     result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
-                                                 ntlm, &base64, &len);
-    if(result)
-      return result;
-
-    if(base64) {
-      free(*allocuserpwd);
-      *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
-                              proxy ? "Proxy-" : "",
-                              base64);
-      free(base64);
-      if(!*allocuserpwd)
-        return CURLE_OUT_OF_MEMORY;
-
-      DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
-
-      *state = NTLMSTATE_TYPE3; /* we send a type-3 */
-      authp->done = TRUE;
+                                                 ntlm, &ntlmmsg);
+    if(!result && Curl_bufref_len(&ntlmmsg)) {
+      result = Curl_base64_encode(data,
+                                  (const char *) Curl_bufref_ptr(&ntlmmsg),
+                                  Curl_bufref_len(&ntlmmsg), &base64, &len);
+      if(!result) {
+        free(*allocuserpwd);
+        *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+                                proxy ? "Proxy-" : "",
+                                base64);
+        free(base64);
+        if(!*allocuserpwd)
+          result = CURLE_OUT_OF_MEMORY;
+        else {
+          *state = NTLMSTATE_TYPE3; /* we send a type-3 */
+          authp->done = TRUE;
+        }
+      }
     }
     }
     break;
     break;
 
 
@@ -241,8 +256,9 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
     authp->done = TRUE;
     authp->done = TRUE;
     break;
     break;
   }
   }
+  Curl_bufref_free(&ntlmmsg);
 
 
-  return CURLE_OK;
+  return result;
 }
 }
 
 
 void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)
 void Curl_http_auth_cleanup_ntlm(struct connectdata *conn)

+ 84 - 30
lib/http_proxy.c

@@ -39,6 +39,8 @@
 #include "connect.h"
 #include "connect.h"
 #include "curlx.h"
 #include "curlx.h"
 #include "vtls/vtls.h"
 #include "vtls/vtls.h"
+#include "transfer.h"
+#include "multiif.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -88,29 +90,12 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
   if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
     /* for [protocol] tunneled through HTTP proxy */
     /* for [protocol] tunneled through HTTP proxy */
-    struct HTTP http_proxy;
-    void *prot_save;
     const char *hostname;
     const char *hostname;
     int remote_port;
     int remote_port;
     CURLcode result;
     CURLcode result;
 
 
-    /* BLOCKING */
     /* We want "seamless" operations through HTTP proxy tunnel */
     /* We want "seamless" operations through HTTP proxy tunnel */
 
 
-    /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
-     * member conn->proto.http; we want [protocol] through HTTP and we have
-     * to change the member temporarily for connecting to the HTTP
-     * proxy. After Curl_proxyCONNECT we have to set back the member to the
-     * original pointer
-     *
-     * This function might be called several times in the multi interface case
-     * if the proxy's CONNECT response is not instant.
-     */
-    prot_save = data->req.p.http;
-    memset(&http_proxy, 0, sizeof(http_proxy));
-    data->req.p.http = &http_proxy;
-    connkeep(conn, "HTTP proxy CONNECT");
-
     /* for the secondary socket (FTP), use the "connect to host"
     /* for the secondary socket (FTP), use the "connect to host"
      * but ignore the "connect to port" (use the secondary port)
      * but ignore the "connect to port" (use the secondary port)
      */
      */
@@ -128,8 +113,8 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
       remote_port = conn->conn_to_port;
       remote_port = conn->conn_to_port;
     else
     else
       remote_port = conn->remote_port;
       remote_port = conn->remote_port;
+
     result = Curl_proxyCONNECT(data, sockindex, hostname, remote_port);
     result = Curl_proxyCONNECT(data, sockindex, hostname, remote_port);
-    data->req.p.http = prot_save;
     if(CURLE_OK != result)
     if(CURLE_OK != result)
       return result;
       return result;
     Curl_safefree(data->state.aptr.proxyuserpwd);
     Curl_safefree(data->state.aptr.proxyuserpwd);
@@ -153,18 +138,53 @@ bool Curl_connect_ongoing(struct connectdata *conn)
     (conn->connect_state->tunnel_state != TUNNEL_COMPLETE);
     (conn->connect_state->tunnel_state != TUNNEL_COMPLETE);
 }
 }
 
 
+/* when we've sent a CONNECT to a proxy, we should rather either wait for the
+   socket to become readable to be able to get the response headers or if
+   we're still sending the request, wait for write. */
+int Curl_connect_getsock(struct connectdata *conn)
+{
+  struct HTTP *http;
+  DEBUGASSERT(conn);
+  DEBUGASSERT(conn->connect_state);
+  http = &conn->connect_state->http_proxy;
+
+  if(http->sending)
+    return GETSOCK_WRITESOCK(0);
+
+  return GETSOCK_READSOCK(0);
+}
+
 static CURLcode connect_init(struct Curl_easy *data, bool reinit)
 static CURLcode connect_init(struct Curl_easy *data, bool reinit)
 {
 {
   struct http_connect_state *s;
   struct http_connect_state *s;
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   if(!reinit) {
   if(!reinit) {
+    CURLcode result;
     DEBUGASSERT(!conn->connect_state);
     DEBUGASSERT(!conn->connect_state);
+    /* we might need the upload buffer for streaming a partial request */
+    result = Curl_get_upload_buffer(data);
+    if(result)
+      return result;
+
     s = calloc(1, sizeof(struct http_connect_state));
     s = calloc(1, sizeof(struct http_connect_state));
     if(!s)
     if(!s)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     infof(data, "allocate connect buffer!\n");
     infof(data, "allocate connect buffer!\n");
     conn->connect_state = s;
     conn->connect_state = s;
     Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
     Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
+
+    /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
+     * member conn->proto.http; we want [protocol] through HTTP and we have
+     * to change the member temporarily for connecting to the HTTP
+     * proxy. After Curl_proxyCONNECT we have to set back the member to the
+     * original pointer
+     *
+     * This function might be called several times in the multi interface case
+     * if the proxy's CONNECT response is not instant.
+     */
+    s->prot_save = data->req.p.http;
+    data->req.p.http = &s->http_proxy;
+    connkeep(conn, "HTTP proxy CONNECT");
   }
   }
   else {
   else {
     DEBUGASSERT(conn->connect_state);
     DEBUGASSERT(conn->connect_state);
@@ -184,6 +204,10 @@ static void connect_done(struct Curl_easy *data)
   struct http_connect_state *s = conn->connect_state;
   struct http_connect_state *s = conn->connect_state;
   s->tunnel_state = TUNNEL_COMPLETE;
   s->tunnel_state = TUNNEL_COMPLETE;
   Curl_dyn_free(&s->rcvbuf);
   Curl_dyn_free(&s->rcvbuf);
+  Curl_dyn_free(&s->req);
+
+  /* retore the protocol pointer */
+  data->req.p.http = s->prot_save;
   infof(data, "CONNECT phase completed!\n");
   infof(data, "CONNECT phase completed!\n");
 }
 }
 
 
@@ -231,6 +255,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   curl_socket_t tunnelsocket = conn->sock[sockindex];
   curl_socket_t tunnelsocket = conn->sock[sockindex];
   struct http_connect_state *s = conn->connect_state;
   struct http_connect_state *s = conn->connect_state;
+  struct HTTP *http = data->req.p.http;
   char *linep;
   char *linep;
   size_t perline;
   size_t perline;
 
 
@@ -246,7 +271,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
     timediff_t check;
     timediff_t check;
     if(TUNNEL_INIT == s->tunnel_state) {
     if(TUNNEL_INIT == s->tunnel_state) {
       /* BEGIN CONNECT PHASE */
       /* BEGIN CONNECT PHASE */
-      struct dynbuf req;
+      struct dynbuf *req = &s->req;
       char *hostheader = NULL;
       char *hostheader = NULL;
       char *host = NULL;
       char *host = NULL;
 
 
@@ -259,8 +284,8 @@ static CURLcode CONNECT(struct Curl_easy *data,
       free(data->req.newurl);
       free(data->req.newurl);
       data->req.newurl = NULL;
       data->req.newurl = NULL;
 
 
-      /* initialize a dynamic send-buffer */
-      Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+      /* initialize send-buffer */
+      Curl_dyn_init(req, DYN_HTTP_REQUEST);
 
 
       result = CONNECT_host(data, conn,
       result = CONNECT_host(data, conn,
                             hostname, remote_port, &hostheader, &host);
                             hostname, remote_port, &hostheader, &host);
@@ -285,7 +310,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
           useragent = data->state.aptr.uagent;
           useragent = data->state.aptr.uagent;
 
 
         result =
         result =
-          Curl_dyn_addf(&req,
+          Curl_dyn_addf(req,
                         "CONNECT %s HTTP/%s\r\n"
                         "CONNECT %s HTTP/%s\r\n"
                         "%s"  /* Host: */
                         "%s"  /* Host: */
                         "%s"  /* Proxy-Authorization */
                         "%s"  /* Proxy-Authorization */
@@ -300,16 +325,15 @@ static CURLcode CONNECT(struct Curl_easy *data,
                         proxyconn);
                         proxyconn);
 
 
         if(!result)
         if(!result)
-          result = Curl_add_custom_headers(data, TRUE, &req);
+          result = Curl_add_custom_headers(data, TRUE, req);
 
 
         if(!result)
         if(!result)
           /* CRLF terminate the request */
           /* CRLF terminate the request */
-          result = Curl_dyn_add(&req, "\r\n");
+          result = Curl_dyn_add(req, "\r\n");
 
 
         if(!result) {
         if(!result) {
           /* Send the connect request to the proxy */
           /* Send the connect request to the proxy */
-          /* BLOCKING */
-          result = Curl_buffer_send(&req, data, &data->info.request_size, 0,
+          result = Curl_buffer_send(req, data, &data->info.request_size, 0,
                                     sockindex);
                                     sockindex);
         }
         }
         if(result)
         if(result)
@@ -317,7 +341,6 @@ static CURLcode CONNECT(struct Curl_easy *data,
       }
       }
       free(host);
       free(host);
       free(hostheader);
       free(hostheader);
-      Curl_dyn_free(&req);
       if(result)
       if(result)
         return result;
         return result;
 
 
@@ -330,12 +353,42 @@ static CURLcode CONNECT(struct Curl_easy *data,
       return CURLE_OPERATION_TIMEDOUT;
       return CURLE_OPERATION_TIMEDOUT;
     }
     }
 
 
-    if(!Curl_conn_data_pending(conn, sockindex))
+    if(!Curl_conn_data_pending(conn, sockindex) && !http->sending)
       /* return so we'll be called again polling-style */
       /* return so we'll be called again polling-style */
       return CURLE_OK;
       return CURLE_OK;
 
 
     /* at this point, the tunnel_connecting phase is over. */
     /* at this point, the tunnel_connecting phase is over. */
 
 
+    if(http->sending == HTTPSEND_REQUEST) {
+      if(!s->nsend) {
+        size_t fillcount;
+        k->upload_fromhere = data->state.ulbuf;
+        result = Curl_fillreadbuffer(data, data->set.upload_buffer_size,
+                                     &fillcount);
+        if(result)
+          return result;
+        s->nsend = fillcount;
+      }
+      if(s->nsend) {
+        ssize_t bytes_written;
+        /* write to socket (send away data) */
+        result = Curl_write(data,
+                            conn->writesockfd,  /* socket to send to */
+                            k->upload_fromhere, /* buffer pointer */
+                            s->nsend,           /* buffer size */
+                            &bytes_written);    /* actually sent */
+
+        if(!result)
+          /* send to debug callback! */
+          result = Curl_debug(data, CURLINFO_HEADER_OUT,
+                              k->upload_fromhere, bytes_written);
+
+        s->nsend -= bytes_written;
+        k->upload_fromhere += bytes_written;
+        return result;
+      }
+      /* if nothing left to send, continue */
+    }
     { /* READING RESPONSE PHASE */
     { /* READING RESPONSE PHASE */
       int error = SELECT_OK;
       int error = SELECT_OK;
 
 
@@ -358,7 +411,8 @@ static CURLcode CONNECT(struct Curl_easy *data,
           break;
           break;
         }
         }
         else if(gotbytes <= 0) {
         else if(gotbytes <= 0) {
-          if(data->set.proxyauth && data->state.authproxy.avail) {
+          if(data->set.proxyauth && data->state.authproxy.avail &&
+             data->state.aptr.proxyuserpwd) {
             /* proxy auth was requested and there was proxy auth available,
             /* proxy auth was requested and there was proxy auth available,
                then deem this as "mere" proxy disconnect */
                then deem this as "mere" proxy disconnect */
             conn->bits.proxy_connect_closed = TRUE;
             conn->bits.proxy_connect_closed = TRUE;
@@ -759,7 +813,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
       if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
       if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
          (HYPERE_OK != hyper_request_set_version(req,
          (HYPERE_OK != hyper_request_set_version(req,
                                                  HYPER_HTTP_VERSION_1_0))) {
                                                  HYPER_HTTP_VERSION_1_0))) {
-        failf(data, "error settting HTTP version");
+        failf(data, "error setting HTTP version");
         goto error;
         goto error;
       }
       }
 
 

+ 24 - 0
lib/http_proxy.h

@@ -38,15 +38,39 @@ CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex);
 
 
 bool Curl_connect_complete(struct connectdata *conn);
 bool Curl_connect_complete(struct connectdata *conn);
 bool Curl_connect_ongoing(struct connectdata *conn);
 bool Curl_connect_ongoing(struct connectdata *conn);
+int Curl_connect_getsock(struct connectdata *conn);
 
 
 #else
 #else
 #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
 #define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
 #define Curl_proxy_connect(x,y) CURLE_OK
 #define Curl_proxy_connect(x,y) CURLE_OK
 #define Curl_connect_complete(x) CURLE_OK
 #define Curl_connect_complete(x) CURLE_OK
 #define Curl_connect_ongoing(x) FALSE
 #define Curl_connect_ongoing(x) FALSE
+#define Curl_connect_getsock(x) 0
 #endif
 #endif
 
 
 void Curl_connect_free(struct Curl_easy *data);
 void Curl_connect_free(struct Curl_easy *data);
 void Curl_connect_done(struct Curl_easy *data);
 void Curl_connect_done(struct Curl_easy *data);
 
 
+/* struct for HTTP CONNECT state data */
+struct http_connect_state {
+  struct HTTP http_proxy;
+  struct HTTP *prot_save;
+  struct dynbuf rcvbuf;
+  struct dynbuf req;
+  size_t nsend;
+  enum keeponval {
+    KEEPON_DONE,
+    KEEPON_CONNECT,
+    KEEPON_IGNORE
+  } keepon;
+  curl_off_t cl; /* size of content to read and ignore */
+  enum {
+    TUNNEL_INIT,    /* init/default/no tunnel state */
+    TUNNEL_CONNECT, /* CONNECT has been sent off */
+    TUNNEL_COMPLETE /* CONNECT response received completely */
+  } tunnel_state;
+  BIT(chunked_encoding);
+  BIT(close_connection);
+};
+
 #endif /* HEADER_CURL_HTTP_PROXY_H */
 #endif /* HEADER_CURL_HTTP_PROXY_H */

+ 6 - 4
lib/imap.c

@@ -136,6 +136,7 @@ const struct Curl_handler Curl_handler_imap = {
   imap_disconnect,                  /* disconnect */
   imap_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* connection_check */
   ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
   PORT_IMAP,                        /* defport */
   PORT_IMAP,                        /* defport */
   CURLPROTO_IMAP,                   /* protocol */
   CURLPROTO_IMAP,                   /* protocol */
   CURLPROTO_IMAP,                   /* family */
   CURLPROTO_IMAP,                   /* family */
@@ -164,6 +165,7 @@ const struct Curl_handler Curl_handler_imaps = {
   imap_disconnect,                  /* disconnect */
   imap_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* connection_check */
   ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
   PORT_IMAPS,                       /* defport */
   PORT_IMAPS,                       /* defport */
   CURLPROTO_IMAPS,                  /* protocol */
   CURLPROTO_IMAPS,                  /* protocol */
   CURLPROTO_IMAP,                   /* family */
   CURLPROTO_IMAP,                   /* family */
@@ -919,7 +921,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data,
       /* Do we have a SASL based authentication mechanism? */
       /* Do we have a SASL based authentication mechanism? */
       else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
       else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
         size_t llen;
         size_t llen;
-        unsigned int mechbit;
+        unsigned short mechbit;
 
 
         line += 5;
         line += 5;
         wordlen -= 5;
         wordlen -= 5;
@@ -1519,7 +1521,7 @@ static CURLcode imap_done(struct Curl_easy *data, CURLcode status,
   Curl_safefree(imap->custom_params);
   Curl_safefree(imap->custom_params);
 
 
   /* Clear the transfer mode for the next request */
   /* Clear the transfer mode for the next request */
-  imap->transfer = FTPTRANSFER_BODY;
+  imap->transfer = PPTRANSFER_BODY;
 
 
   return result;
   return result;
 }
 }
@@ -1545,7 +1547,7 @@ static CURLcode imap_perform(struct Curl_easy *data, bool *connected,
 
 
   if(data->set.opt_no_body) {
   if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
     /* Requested no body means no transfer */
-    imap->transfer = FTPTRANSFER_INFO;
+    imap->transfer = PPTRANSFER_INFO;
   }
   }
 
 
   *dophase_done = FALSE; /* not done yet */
   *dophase_done = FALSE; /* not done yet */
@@ -1667,7 +1669,7 @@ static CURLcode imap_dophase_done(struct Curl_easy *data, bool connected)
 
 
   (void)connected;
   (void)connected;
 
 
-  if(imap->transfer != FTPTRANSFER_BODY)
+  if(imap->transfer != PPTRANSFER_BODY)
     /* no data to transfer */
     /* no data to transfer */
     Curl_setup_transfer(data, -1, -1, FALSE, -1);
     Curl_setup_transfer(data, -1, -1, FALSE, -1);
 
 

+ 2 - 2
lib/inet_ntop.c

@@ -1,5 +1,5 @@
 /*
 /*
- * Copyright (C) 1996-2019  Internet Software Consortium.
+ * Copyright (C) 1996-2021  Internet Software Consortium.
  *
  *
  * Permission to use, copy, modify, and distribute this software for any
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * purpose with or without fee is hereby granted, provided that the above
@@ -134,7 +134,7 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
 
 
     /* Are we following an initial run of 0x00s or any real hex?
     /* Are we following an initial run of 0x00s or any real hex?
      */
      */
-    if(i != 0)
+    if(i)
       *tp++ = ':';
       *tp++ = ':';
 
 
     /* Is this address an encapsulated IPv4?
     /* Is this address an encapsulated IPv4?

+ 5 - 17
lib/krb5.c

@@ -159,16 +159,6 @@ krb5_decode(void *app_data, void *buf, int len,
   return len;
   return len;
 }
 }
 
 
-static int
-krb5_overhead(void *app_data, int level, int len)
-{
-  /* no arguments are used */
-  (void)app_data;
-  (void)level;
-  (void)len;
-  return 0;
-}
-
 static int
 static int
 krb5_encode(void *app_data, const void *from, int length, int level, void **to)
 krb5_encode(void *app_data, const void *from, int length, int level, void **to)
 {
 {
@@ -305,7 +295,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
         break;
         break;
       }
       }
 
 
-      if(output_buffer.length != 0) {
+      if(output_buffer.length) {
         char *cmd;
         char *cmd;
 
 
         result = Curl_base64_encode(data, (char *)output_buffer.value,
         result = Curl_base64_encode(data, (char *)output_buffer.value,
@@ -392,7 +382,7 @@ static struct Curl_sec_client_mech Curl_krb5_client_mech = {
   krb5_auth,
   krb5_auth,
   krb5_end,
   krb5_end,
   krb5_check_prot,
   krb5_check_prot,
-  krb5_overhead,
+
   krb5_encode,
   krb5_encode,
   krb5_decode
   krb5_decode
 };
 };
@@ -412,7 +402,7 @@ name_to_level(const char *name)
 {
 {
   int i;
   int i;
   for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
   for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
-    if(checkprefix(name, level_names[i].name))
+    if(curl_strequal(name, level_names[i].name))
       return level_names[i].level;
       return level_names[i].level;
   return PROT_NONE;
   return PROT_NONE;
 }
 }
@@ -657,8 +647,6 @@ static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
 {
 {
   ssize_t tx = 0, len = conn->buffer_size;
   ssize_t tx = 0, len = conn->buffer_size;
 
 
-  len -= conn->mech->overhead(conn->app_data, conn->data_prot,
-                              curlx_sztosi(len));
   if(len <= 0)
   if(len <= 0)
     len = length;
     len = length;
   while(length) {
   while(length) {
@@ -760,7 +748,7 @@ static int sec_set_protection_level(struct Curl_easy *data)
 
 
   if(level) {
   if(level) {
     char *pbsz;
     char *pbsz;
-    static unsigned int buffer_size = 1 << 20; /* 1048576 */
+    unsigned int buffer_size = 1 << 20; /* 1048576 */
 
 
     code = ftp_send_command(data, "PBSZ %u", buffer_size);
     code = ftp_send_command(data, "PBSZ %u", buffer_size);
     if(code < 0)
     if(code < 0)
@@ -817,7 +805,7 @@ static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
   const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
   const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
 
 
   tmp_allocation = realloc(conn->app_data, mech->size);
   tmp_allocation = realloc(conn->app_data, mech->size);
-  if(tmp_allocation == NULL) {
+  if(!tmp_allocation) {
     failf(data, "Failed realloc of size %zu", mech->size);
     failf(data, "Failed realloc of size %zu", mech->size);
     mech = NULL;
     mech = NULL;
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;

+ 26 - 14
lib/ldap.c

@@ -149,6 +149,7 @@ const struct Curl_handler Curl_handler_ldap = {
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_LDAP,                            /* defport */
   PORT_LDAP,                            /* defport */
   CURLPROTO_LDAP,                       /* protocol */
   CURLPROTO_LDAP,                       /* protocol */
   CURLPROTO_LDAP,                       /* family */
   CURLPROTO_LDAP,                       /* family */
@@ -176,6 +177,7 @@ const struct Curl_handler Curl_handler_ldaps = {
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_LDAPS,                           /* defport */
   PORT_LDAPS,                           /* defport */
   CURLPROTO_LDAPS,                      /* protocol */
   CURLPROTO_LDAPS,                      /* protocol */
   CURLPROTO_LDAP,                       /* family */
   CURLPROTO_LDAP,                       /* family */
@@ -296,14 +298,14 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
   *done = TRUE; /* unconditionally */
   *done = TRUE; /* unconditionally */
   infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
   infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
           LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
           LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
-  infof(data, "LDAP local: %s\n", data->change.url);
+  infof(data, "LDAP local: %s\n", data->state.url);
 
 
 #ifdef HAVE_LDAP_URL_PARSE
 #ifdef HAVE_LDAP_URL_PARSE
-  rc = ldap_url_parse(data->change.url, &ludp);
+  rc = ldap_url_parse(data->state.url, &ludp);
 #else
 #else
   rc = _ldap_url_parse(data, conn, &ludp);
   rc = _ldap_url_parse(data, conn, &ludp);
 #endif
 #endif
-  if(rc != 0) {
+  if(rc) {
     failf(data, "LDAP local: %s", ldap_err2string(rc));
     failf(data, "LDAP local: %s", ldap_err2string(rc));
     result = CURLE_LDAP_INVALID_URL;
     result = CURLE_LDAP_INVALID_URL;
     goto quit;
     goto quit;
@@ -387,7 +389,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
       goto quit;
       goto quit;
     }
     }
     server = ldapssl_init(host, (int)conn->port, 1);
     server = ldapssl_init(host, (int)conn->port, 1);
-    if(server == NULL) {
+    if(!server) {
       failf(data, "LDAP local: Cannot connect to %s:%ld",
       failf(data, "LDAP local: Cannot connect to %s:%ld",
             conn->host.dispname, conn->port);
             conn->host.dispname, conn->port);
       result = CURLE_COULDNT_CONNECT;
       result = CURLE_COULDNT_CONNECT;
@@ -428,7 +430,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
       goto quit;
       goto quit;
     }
     }
     server = ldap_init(host, (int)conn->port);
     server = ldap_init(host, (int)conn->port);
-    if(server == NULL) {
+    if(!server) {
       failf(data, "LDAP local: Cannot connect to %s:%ld",
       failf(data, "LDAP local: Cannot connect to %s:%ld",
             conn->host.dispname, conn->port);
             conn->host.dispname, conn->port);
       result = CURLE_COULDNT_CONNECT;
       result = CURLE_COULDNT_CONNECT;
@@ -464,7 +466,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
   }
   }
   else {
   else {
     server = ldap_init(host, (int)conn->port);
     server = ldap_init(host, (int)conn->port);
-    if(server == NULL) {
+    if(!server) {
       failf(data, "LDAP local: Cannot connect to %s:%ld",
       failf(data, "LDAP local: Cannot connect to %s:%ld",
             conn->host.dispname, conn->port);
             conn->host.dispname, conn->port);
       result = CURLE_COULDNT_CONNECT;
       result = CURLE_COULDNT_CONNECT;
@@ -477,7 +479,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
 #else
 #else
   rc = ldap_simple_bind_s(server, user, passwd);
   rc = ldap_simple_bind_s(server, user, passwd);
 #endif
 #endif
-  if(!ldap_ssl && rc != 0) {
+  if(!ldap_ssl && rc) {
     ldap_proto = LDAP_VERSION2;
     ldap_proto = LDAP_VERSION2;
     ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
     ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
 #ifdef USE_WIN32_LDAP
 #ifdef USE_WIN32_LDAP
@@ -486,7 +488,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
     rc = ldap_simple_bind_s(server, user, passwd);
     rc = ldap_simple_bind_s(server, user, passwd);
 #endif
 #endif
   }
   }
-  if(rc != 0) {
+  if(rc) {
 #ifdef USE_WIN32_LDAP
 #ifdef USE_WIN32_LDAP
     failf(data, "LDAP local: bind via ldap_win_bind %s",
     failf(data, "LDAP local: bind via ldap_win_bind %s",
           ldap_err2string(rc));
           ldap_err2string(rc));
@@ -501,7 +503,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
   rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
   rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
                      ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
                      ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
 
 
-  if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
+  if(rc && rc != LDAP_SIZELIMIT_EXCEEDED) {
     failf(data, "LDAP remote: %s", ldap_err2string(rc));
     failf(data, "LDAP remote: %s", ldap_err2string(rc));
     result = CURLE_LDAP_SEARCH_FAILED;
     result = CURLE_LDAP_SEARCH_FAILED;
     goto quit;
     goto quit;
@@ -581,7 +583,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
         result = CURLE_OUT_OF_MEMORY;
         result = CURLE_OUT_OF_MEMORY;
 
 
         goto quit;
         goto quit;
-    }
+      }
 #else
 #else
       char *attr = attribute;
       char *attr = attribute;
 #endif
 #endif
@@ -875,7 +877,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
     ludp->lud_dn = curlx_convert_UTF8_to_tchar(unescaped);
     ludp->lud_dn = curlx_convert_UTF8_to_tchar(unescaped);
 
 
     /* Free the unescaped string as we are done with it */
     /* Free the unescaped string as we are done with it */
-    curlx_unicodefree(unescaped);
+    free(unescaped);
 
 
     if(!ludp->lud_dn) {
     if(!ludp->lud_dn) {
       rc = LDAP_NO_MEMORY;
       rc = LDAP_NO_MEMORY;
@@ -943,7 +945,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
       ludp->lud_attrs[i] = curlx_convert_UTF8_to_tchar(unescaped);
       ludp->lud_attrs[i] = curlx_convert_UTF8_to_tchar(unescaped);
 
 
       /* Free the unescaped string as we are done with it */
       /* Free the unescaped string as we are done with it */
-      curlx_unicodefree(unescaped);
+      free(unescaped);
 
 
       if(!ludp->lud_attrs[i]) {
       if(!ludp->lud_attrs[i]) {
         free(attributes);
         free(attributes);
@@ -1010,7 +1012,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
     ludp->lud_filter = curlx_convert_UTF8_to_tchar(unescaped);
     ludp->lud_filter = curlx_convert_UTF8_to_tchar(unescaped);
 
 
     /* Free the unescaped string as we are done with it */
     /* Free the unescaped string as we are done with it */
-    curlx_unicodefree(unescaped);
+    free(unescaped);
 
 
     if(!ludp->lud_filter) {
     if(!ludp->lud_filter) {
       rc = LDAP_NO_MEMORY;
       rc = LDAP_NO_MEMORY;
@@ -1061,13 +1063,23 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp)
   if(!ludp)
   if(!ludp)
     return;
     return;
 
 
+#if defined(USE_WIN32_LDAP)
+  curlx_unicodefree(ludp->lud_dn);
+  curlx_unicodefree(ludp->lud_filter);
+#else
   free(ludp->lud_dn);
   free(ludp->lud_dn);
   free(ludp->lud_filter);
   free(ludp->lud_filter);
+#endif
 
 
   if(ludp->lud_attrs) {
   if(ludp->lud_attrs) {
     size_t i;
     size_t i;
-    for(i = 0; i < ludp->lud_attrs_dups; i++)
+    for(i = 0; i < ludp->lud_attrs_dups; i++) {
+#if defined(USE_WIN32_LDAP)
+      curlx_unicodefree(ludp->lud_attrs[i]);
+#else
       free(ludp->lud_attrs[i]);
       free(ludp->lud_attrs[i]);
+#endif
+    }
     free(ludp->lud_attrs);
     free(ludp->lud_attrs);
   }
   }
 
 

+ 3 - 3
lib/llist.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -94,13 +94,13 @@ Curl_llist_remove(struct Curl_llist *list, struct Curl_llist_element *e,
                   void *user)
                   void *user)
 {
 {
   void *ptr;
   void *ptr;
-  if(e == NULL || list->size == 0)
+  if(!e || list->size == 0)
     return;
     return;
 
 
   if(e == list->head) {
   if(e == list->head) {
     list->head = e->next;
     list->head = e->next;
 
 
-    if(list->head == NULL)
+    if(!list->head)
       list->tail = NULL;
       list->tail = NULL;
     else
     else
       e->next->prev = NULL;
       e->next->prev = NULL;

+ 3 - 30
lib/md4.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -44,7 +44,7 @@
 #endif
 #endif
 #endif /* USE_MBEDTLS */
 #endif /* USE_MBEDTLS */
 
 
-#if defined(USE_GNUTLS_NETTLE)
+#if defined(USE_GNUTLS)
 
 
 #include <nettle/md4.h>
 #include <nettle/md4.h>
 
 
@@ -70,33 +70,6 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
   md4_digest(ctx, MD4_DIGEST_SIZE, result);
   md4_digest(ctx, MD4_DIGEST_SIZE, result);
 }
 }
 
 
-#elif defined(USE_GNUTLS)
-
-#include <gcrypt.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-typedef gcry_md_hd_t MD4_CTX;
-
-static void MD4_Init(MD4_CTX *ctx)
-{
-  gcry_md_open(ctx, GCRY_MD_MD4, 0);
-}
-
-static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
-{
-  gcry_md_write(*ctx, data, size);
-}
-
-static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
-{
-  memcpy(result, gcry_md_read(*ctx, 0), MD4_DIGEST_LENGTH);
-  gcry_md_close(*ctx);
-}
-
 #elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
 #elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4)
 /* When OpenSSL is available we use the MD4-functions from OpenSSL */
 /* When OpenSSL is available we use the MD4-functions from OpenSSL */
 #include <openssl/md4.h>
 #include <openssl/md4.h>
@@ -201,7 +174,7 @@ static void MD4_Init(MD4_CTX *ctx)
 
 
 static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
 static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
 {
 {
-  if(ctx->data == NULL) {
+  if(!ctx->data) {
     ctx->data = malloc(size);
     ctx->data = malloc(size);
     if(ctx->data != NULL) {
     if(ctx->data != NULL) {
       memcpy(ctx->data, data, size);
       memcpy(ctx->data, data, size);

+ 2 - 29
lib/md5.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -38,7 +38,7 @@
 #endif
 #endif
 #endif /* USE_MBEDTLS */
 #endif /* USE_MBEDTLS */
 
 
-#if defined(USE_GNUTLS_NETTLE)
+#if defined(USE_GNUTLS)
 
 
 #include <nettle/md5.h>
 #include <nettle/md5.h>
 #include "curl_memory.h"
 #include "curl_memory.h"
@@ -64,33 +64,6 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
   md5_digest(ctx, 16, digest);
   md5_digest(ctx, 16, digest);
 }
 }
 
 
-#elif defined(USE_GNUTLS)
-
-#include <gcrypt.h>
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-typedef gcry_md_hd_t MD5_CTX;
-
-static void MD5_Init(MD5_CTX *ctx)
-{
-  gcry_md_open(ctx, GCRY_MD_MD5, 0);
-}
-
-static void MD5_Update(MD5_CTX *ctx,
-                       const unsigned char *input,
-                       unsigned int inputLen)
-{
-  gcry_md_write(*ctx, input, inputLen);
-}
-
-static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
-{
-  memcpy(digest, gcry_md_read(*ctx, 0), 16);
-  gcry_md_close(*ctx);
-}
-
 #elif defined(USE_OPENSSL) && !defined(USE_AMISSL)
 #elif defined(USE_OPENSSL) && !defined(USE_AMISSL)
 /* When OpenSSL is available we use the MD5-function from OpenSSL */
 /* When OpenSSL is available we use the MD5-function from OpenSSL */
 #include <openssl/md5.h>
 #include <openssl/md5.h>

+ 25 - 10
lib/memdebug.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -55,9 +55,24 @@ struct memdebug {
  */
  */
 
 
 FILE *curl_dbg_logfile = NULL;
 FILE *curl_dbg_logfile = NULL;
+static bool registered_cleanup = FALSE; /* atexit registered cleanup */
 static bool memlimit = FALSE; /* enable memory limit */
 static bool memlimit = FALSE; /* enable memory limit */
 static long memsize = 0;  /* set number of mallocs allowed */
 static long memsize = 0;  /* set number of mallocs allowed */
 
 
+/* LeakSantizier (LSAN) calls _exit() instead of exit() when a leak is detected
+   on exit so the logfile must be closed explicitly or data could be lost.
+   Though _exit() does not call atexit handlers such as this, LSAN's call to
+   _exit() comes after the atexit handlers are called. curl/curl#6620 */
+static void curl_dbg_cleanup(void)
+{
+  if(curl_dbg_logfile &&
+     curl_dbg_logfile != stderr &&
+     curl_dbg_logfile != stdout) {
+    fclose(curl_dbg_logfile);
+  }
+  curl_dbg_logfile = NULL;
+}
+
 /* this sets the log file name */
 /* this sets the log file name */
 void curl_dbg_memdebug(const char *logname)
 void curl_dbg_memdebug(const char *logname)
 {
 {
@@ -72,6 +87,8 @@ void curl_dbg_memdebug(const char *logname)
       setbuf(curl_dbg_logfile, (char *)NULL);
       setbuf(curl_dbg_logfile, (char *)NULL);
 #endif
 #endif
   }
   }
+  if(!registered_cleanup)
+    registered_cleanup = !atexit(curl_dbg_cleanup);
 }
 }
 
 
 /* This function sets the number of malloc() calls that should return
 /* This function sets the number of malloc() calls that should return
@@ -91,15 +108,13 @@ static bool countcheck(const char *func, int line, const char *source)
      should not be made */
      should not be made */
   if(memlimit && source) {
   if(memlimit && source) {
     if(!memsize) {
     if(!memsize) {
-      if(source) {
-        /* log to file */
-        curl_dbg_log("LIMIT %s:%d %s reached memlimit\n",
-                     source, line, func);
-        /* log to stderr also */
-        fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
-                source, line, func);
-        fflush(curl_dbg_logfile); /* because it might crash now */
-      }
+      /* log to file */
+      curl_dbg_log("LIMIT %s:%d %s reached memlimit\n",
+                   source, line, func);
+      /* log to stderr also */
+      fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
+              source, line, func);
+      fflush(curl_dbg_logfile); /* because it might crash now */
       errno = ENOMEM;
       errno = ENOMEM;
       return TRUE; /* RETURN ERROR! */
       return TRUE; /* RETURN ERROR! */
     }
     }

+ 2 - 2
lib/mime.c

@@ -152,14 +152,14 @@ curl_off_t VmsRealFileSize(const char *name,
   FILE * file;
   FILE * file;
 
 
   file = fopen(name, FOPEN_READTEXT); /* VMS */
   file = fopen(name, FOPEN_READTEXT); /* VMS */
-  if(file == NULL)
+  if(!file)
     return 0;
     return 0;
 
 
   count = 0;
   count = 0;
   ret_stat = 1;
   ret_stat = 1;
   while(ret_stat > 0) {
   while(ret_stat > 0) {
     ret_stat = fread(buffer, 1, sizeof(buffer), file);
     ret_stat = fread(buffer, 1, sizeof(buffer), file);
-    if(ret_stat != 0)
+    if(ret_stat)
       count += ret_stat;
       count += ret_stat;
   }
   }
   fclose(file);
   fclose(file);

+ 2 - 2
lib/mprintf.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1999 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1999 - 2021, 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
@@ -815,7 +815,7 @@ static int dprintf_formatf(
         size_t len;
         size_t len;
 
 
         str = (char *) p->data.str;
         str = (char *) p->data.str;
-        if(str == NULL) {
+        if(!str) {
           /* Write null[] if there's space.  */
           /* Write null[] if there's space.  */
           if(prec == -1 || prec >= (long) sizeof(null) - 1) {
           if(prec == -1 || prec >= (long) sizeof(null) - 1) {
             str = null;
             str = null;

+ 1 - 0
lib/mqtt.c

@@ -86,6 +86,7 @@ const struct Curl_handler Curl_handler_mqtt = {
   ZERO_NULL,                          /* disconnect */
   ZERO_NULL,                          /* disconnect */
   ZERO_NULL,                          /* readwrite */
   ZERO_NULL,                          /* readwrite */
   ZERO_NULL,                          /* connection_check */
   ZERO_NULL,                          /* connection_check */
+  ZERO_NULL,                          /* attach connection */
   PORT_MQTT,                          /* defport */
   PORT_MQTT,                          /* defport */
   CURLPROTO_MQTT,                     /* protocol */
   CURLPROTO_MQTT,                     /* protocol */
   CURLPROTO_MQTT,                     /* family */
   CURLPROTO_MQTT,                     /* family */

File diff suppressed because it is too large
+ 258 - 151
lib/multi.c


+ 26 - 24
lib/multihandle.h

@@ -40,27 +40,26 @@ struct Curl_message {
    well!
    well!
 */
 */
 typedef enum {
 typedef enum {
-  CURLM_STATE_INIT,         /* 0 - start in this state */
-  CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */
-  CURLM_STATE_CONNECT,      /* 2 - resolve/connect has been sent off */
-  CURLM_STATE_WAITRESOLVE,  /* 3 - awaiting the resolve to finalize */
-  CURLM_STATE_WAITCONNECT,  /* 4 - awaiting the TCP connect to finalize */
-  CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting HTTPS proxy SSL initialization
-                                   to complete and/or proxy CONNECT to
-                                   finalize */
-  CURLM_STATE_SENDPROTOCONNECT, /* 6 - initiate protocol connect procedure */
-  CURLM_STATE_PROTOCONNECT, /* 7 - completing the protocol-specific connect
-                                   phase */
-  CURLM_STATE_DO,           /* 8 - start send off the request (part 1) */
-  CURLM_STATE_DOING,        /* 9 - sending off the request (part 1) */
-  CURLM_STATE_DO_MORE,      /* 10 - send off the request (part 2) */
-  CURLM_STATE_DO_DONE,      /* 11 - done sending off request */
-  CURLM_STATE_PERFORM,      /* 12 - transfer data */
-  CURLM_STATE_TOOFAST,      /* 13 - wait because limit-rate exceeded */
-  CURLM_STATE_DONE,         /* 14 - post data transfer operation */
-  CURLM_STATE_COMPLETED,    /* 15 - operation complete */
-  CURLM_STATE_MSGSENT,      /* 16 - the operation complete message is sent */
-  CURLM_STATE_LAST          /* 17 - not a true state, never use this */
+  MSTATE_INIT,         /* 0 - start in this state */
+  MSTATE_PENDING,      /* 1 - no connections, waiting for one */
+  MSTATE_CONNECT,      /* 2 - resolve/connect has been sent off */
+  MSTATE_RESOLVING,    /* 3 - awaiting the resolve to finalize */
+  MSTATE_CONNECTING,   /* 4 - awaiting the TCP connect to finalize */
+  MSTATE_TUNNELING,    /* 5 - awaiting HTTPS proxy SSL initialization to
+                          complete and/or proxy CONNECT to finalize */
+  MSTATE_PROTOCONNECT, /* 6 - initiate protocol connect procedure */
+  MSTATE_PROTOCONNECTING, /* 7 - completing the protocol-specific connect
+                             phase */
+  MSTATE_DO,           /* 8 - start send off the request (part 1) */
+  MSTATE_DOING,        /* 9 - sending off the request (part 1) */
+  MSTATE_DOING_MORE,   /* 10 - send off the request (part 2) */
+  MSTATE_DID,          /* 11 - done sending off request */
+  MSTATE_PERFORMING,   /* 12 - transfer data */
+  MSTATE_RATELIMITING, /* 13 - wait because limit-rate exceeded */
+  MSTATE_DONE,         /* 14 - post data transfer operation */
+  MSTATE_COMPLETED,    /* 15 - operation complete */
+  MSTATE_MSGSENT,      /* 16 - the operation complete message is sent */
+  MSTATE_LAST          /* 17 - not a true state, never use this */
 } CURLMstate;
 } CURLMstate;
 
 
 /* we support N sockets per easy handle. Set the corresponding bit to what
 /* we support N sockets per easy handle. Set the corresponding bit to what
@@ -71,8 +70,7 @@ typedef enum {
 
 
 #define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
 #define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
 
 
-#if defined(USE_SOCKETPAIR) && !defined(USE_BLOCKING_SOCKETS) &&        \
-  !defined(CURL_DISABLE_SOCKETPAIR)
+#if !defined(CURL_DISABLE_SOCKETPAIR)
 #define ENABLE_WAKEUP
 #define ENABLE_WAKEUP
 #endif
 #endif
 
 
@@ -96,7 +94,7 @@ struct Curl_multi {
   struct Curl_llist msglist; /* a list of messages from completed transfers */
   struct Curl_llist msglist; /* a list of messages from completed transfers */
 
 
   struct Curl_llist pending; /* Curl_easys that are in the
   struct Curl_llist pending; /* Curl_easys that are in the
-                                CURLM_STATE_CONNECT_PEND state */
+                                MSTATE_PENDING state */
 
 
   /* callback function and user data pointer for the *socket() API */
   /* callback function and user data pointer for the *socket() API */
   curl_socket_callback socket_cb;
   curl_socket_callback socket_cb;
@@ -142,9 +140,13 @@ struct Curl_multi {
                                     previous callback */
                                     previous callback */
   unsigned int max_concurrent_streams;
   unsigned int max_concurrent_streams;
 
 
+#ifdef USE_WINSOCK
+  WSAEVENT wsa_event; /* winsock event used for waits */
+#else
 #ifdef ENABLE_WAKEUP
 #ifdef ENABLE_WAKEUP
   curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup
   curl_socket_t wakeup_pair[2]; /* socketpair() used for wakeup
                                    0 is used for read, 1 is used for write */
                                    0 is used for read, 1 is used for write */
+#endif
 #endif
 #endif
   /* multiplexing wanted */
   /* multiplexing wanted */
   bool multiplexing;
   bool multiplexing;

+ 4 - 4
lib/non-ascii.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -127,7 +127,7 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
                &output_ptr, &out_bytes);
                &output_ptr, &out_bytes);
     if(!data)
     if(!data)
       iconv_close(tmpcd);
       iconv_close(tmpcd);
-    if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+    if((rc == ICONV_ERROR) || (in_bytes)) {
       failf(data,
       failf(data,
             "The Curl_convert_to_network iconv call failed with errno %i: %s",
             "The Curl_convert_to_network iconv call failed with errno %i: %s",
             errno, strerror(errno));
             errno, strerror(errno));
@@ -193,7 +193,7 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
                &output_ptr, &out_bytes);
                &output_ptr, &out_bytes);
     if(!data)
     if(!data)
       iconv_close(tmpcd);
       iconv_close(tmpcd);
-    if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+    if((rc == ICONV_ERROR) || (in_bytes)) {
       failf(data,
       failf(data,
             "Curl_convert_from_network iconv call failed with errno %i: %s",
             "Curl_convert_from_network iconv call failed with errno %i: %s",
             errno, strerror(errno));
             errno, strerror(errno));
@@ -260,7 +260,7 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
                &output_ptr, &out_bytes);
                &output_ptr, &out_bytes);
     if(!data)
     if(!data)
       iconv_close(tmpcd);
       iconv_close(tmpcd);
-    if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+    if((rc == ICONV_ERROR) || (in_bytes)) {
       failf(data,
       failf(data,
             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
             "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
             errno, strerror(errno));
             errno, strerror(errno));

+ 2 - 8
lib/nonblock.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -47,13 +47,7 @@
 int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
 int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
                    int nonblock   /* TRUE or FALSE */)
                    int nonblock   /* TRUE or FALSE */)
 {
 {
-#if defined(USE_BLOCKING_SOCKETS)
-  (void)sockfd;
-  (void)nonblock;
-  return 0; /* returns success */
-
-#elif defined(HAVE_FCNTL_O_NONBLOCK)
-
+#if defined(HAVE_FCNTL_O_NONBLOCK)
   /* most recent unix versions */
   /* most recent unix versions */
   int flags;
   int flags;
   flags = sfcntl(sockfd, F_GETFL, 0);
   flags = sfcntl(sockfd, F_GETFL, 0);

+ 78 - 60
lib/openldap.c

@@ -76,16 +76,16 @@ extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
                         LDAP **ld);
                         LDAP **ld);
 #endif
 #endif
 
 
-static CURLcode ldap_setup_connection(struct Curl_easy *data,
-                                      struct connectdata *conn);
-static CURLcode ldap_do(struct Curl_easy *data, bool *done);
-static CURLcode ldap_done(struct Curl_easy *data, CURLcode, bool);
-static CURLcode ldap_connect(struct Curl_easy *data, bool *done);
-static CURLcode ldap_connecting(struct Curl_easy *data, bool *done);
-static CURLcode ldap_disconnect(struct Curl_easy *data,
-                                struct connectdata *conn, bool dead);
+static CURLcode oldap_setup_connection(struct Curl_easy *data,
+                                       struct connectdata *conn);
+static CURLcode oldap_do(struct Curl_easy *data, bool *done);
+static CURLcode oldap_done(struct Curl_easy *data, CURLcode, bool);
+static CURLcode oldap_connect(struct Curl_easy *data, bool *done);
+static CURLcode oldap_connecting(struct Curl_easy *data, bool *done);
+static CURLcode oldap_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn, bool dead);
 
 
-static Curl_recv ldap_recv;
+static Curl_recv oldap_recv;
 
 
 /*
 /*
  * LDAP protocol handler.
  * LDAP protocol handler.
@@ -93,20 +93,21 @@ static Curl_recv ldap_recv;
 
 
 const struct Curl_handler Curl_handler_ldap = {
 const struct Curl_handler Curl_handler_ldap = {
   "LDAP",                               /* scheme */
   "LDAP",                               /* scheme */
-  ldap_setup_connection,                /* setup_connection */
-  ldap_do,                              /* do_it */
-  ldap_done,                            /* done */
+  oldap_setup_connection,               /* setup_connection */
+  oldap_do,                             /* do_it */
+  oldap_done,                           /* done */
   ZERO_NULL,                            /* do_more */
   ZERO_NULL,                            /* do_more */
-  ldap_connect,                         /* connect_it */
-  ldap_connecting,                      /* connecting */
+  oldap_connect,                        /* connect_it */
+  oldap_connecting,                     /* connecting */
   ZERO_NULL,                            /* doing */
   ZERO_NULL,                            /* doing */
   ZERO_NULL,                            /* proto_getsock */
   ZERO_NULL,                            /* proto_getsock */
   ZERO_NULL,                            /* doing_getsock */
   ZERO_NULL,                            /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
   ZERO_NULL,                            /* domore_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
-  ldap_disconnect,                      /* disconnect */
+  oldap_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_LDAP,                            /* defport */
   PORT_LDAP,                            /* defport */
   CURLPROTO_LDAP,                       /* protocol */
   CURLPROTO_LDAP,                       /* protocol */
   CURLPROTO_LDAP,                       /* family */
   CURLPROTO_LDAP,                       /* family */
@@ -120,20 +121,21 @@ const struct Curl_handler Curl_handler_ldap = {
 
 
 const struct Curl_handler Curl_handler_ldaps = {
 const struct Curl_handler Curl_handler_ldaps = {
   "LDAPS",                              /* scheme */
   "LDAPS",                              /* scheme */
-  ldap_setup_connection,                /* setup_connection */
-  ldap_do,                              /* do_it */
-  ldap_done,                            /* done */
+  oldap_setup_connection,               /* setup_connection */
+  oldap_do,                             /* do_it */
+  oldap_done,                           /* done */
   ZERO_NULL,                            /* do_more */
   ZERO_NULL,                            /* do_more */
-  ldap_connect,                         /* connect_it */
-  ldap_connecting,                      /* connecting */
+  oldap_connect,                        /* connect_it */
+  oldap_connecting,                     /* connecting */
   ZERO_NULL,                            /* doing */
   ZERO_NULL,                            /* doing */
   ZERO_NULL,                            /* proto_getsock */
   ZERO_NULL,                            /* proto_getsock */
   ZERO_NULL,                            /* doing_getsock */
   ZERO_NULL,                            /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
   ZERO_NULL,                            /* domore_getsock */
   ZERO_NULL,                            /* perform_getsock */
   ZERO_NULL,                            /* perform_getsock */
-  ldap_disconnect,                      /* disconnect */
+  oldap_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_LDAPS,                           /* defport */
   PORT_LDAPS,                           /* defport */
   CURLPROTO_LDAPS,                      /* protocol */
   CURLPROTO_LDAPS,                      /* protocol */
   CURLPROTO_LDAP,                       /* family */
   CURLPROTO_LDAP,                       /* family */
@@ -171,15 +173,15 @@ struct ldapreqinfo {
   int nument;
   int nument;
 };
 };
 
 
-static CURLcode ldap_setup_connection(struct Curl_easy *data,
-                                      struct connectdata *conn)
+static CURLcode oldap_setup_connection(struct Curl_easy *data,
+                                       struct connectdata *conn)
 {
 {
   struct ldapconninfo *li;
   struct ldapconninfo *li;
   LDAPURLDesc *lud;
   LDAPURLDesc *lud;
   int rc, proto;
   int rc, proto;
   CURLcode status;
   CURLcode status;
 
 
-  rc = ldap_url_parse(data->change.url, &lud);
+  rc = ldap_url_parse(data->state.url, &lud);
   if(rc != LDAP_URL_SUCCESS) {
   if(rc != LDAP_URL_SUCCESS) {
     const char *msg = "url parsing problem";
     const char *msg = "url parsing problem";
     status = CURLE_URL_MALFORMAT;
     status = CURLE_URL_MALFORMAT;
@@ -207,7 +209,7 @@ static CURLcode ldap_setup_connection(struct Curl_easy *data,
 static Sockbuf_IO ldapsb_tls;
 static Sockbuf_IO ldapsb_tls;
 #endif
 #endif
 
 
-static CURLcode ldap_connect(struct Curl_easy *data, bool *done)
+static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapconninfo *li = conn->proto.ldapc;
@@ -255,7 +257,7 @@ static CURLcode ldap_connect(struct Curl_easy *data, bool *done)
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
+static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapconninfo *li = conn->proto.ldapc;
@@ -278,7 +280,7 @@ static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
     if(!li->sslinst) {
     if(!li->sslinst) {
       Sockbuf *sb;
       Sockbuf *sb;
       ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
       ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
-      ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn);
+      ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
       li->sslinst = TRUE;
       li->sslinst = TRUE;
       li->recv = conn->recv[FIRSTSOCKET];
       li->recv = conn->recv[FIRSTSOCKET];
       li->send = conn->send[FIRSTSOCKET];
       li->send = conn->send[FIRSTSOCKET];
@@ -354,21 +356,28 @@ static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
 
 
   if(info)
   if(info)
     ldap_memfree(info);
     ldap_memfree(info);
-  conn->recv[FIRSTSOCKET] = ldap_recv;
+  conn->recv[FIRSTSOCKET] = oldap_recv;
   *done = TRUE;
   *done = TRUE;
 
 
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-static CURLcode ldap_disconnect(struct Curl_easy *data,
-                                struct connectdata *conn, bool dead_connection)
+static CURLcode oldap_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn,
+                                 bool dead_connection)
 {
 {
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapconninfo *li = conn->proto.ldapc;
   (void) dead_connection;
   (void) dead_connection;
-  (void) data;
 
 
   if(li) {
   if(li) {
     if(li->ld) {
     if(li->ld) {
+#ifdef USE_SSL
+      if(conn->ssl[FIRSTSOCKET].use) {
+        Sockbuf *sb;
+        ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+        ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
+      }
+#endif
       ldap_unbind_ext(li->ld, NULL, NULL);
       ldap_unbind_ext(li->ld, NULL, NULL);
       li->ld = NULL;
       li->ld = NULL;
     }
     }
@@ -378,7 +387,7 @@ static CURLcode ldap_disconnect(struct Curl_easy *data,
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-static CURLcode ldap_do(struct Curl_easy *data, bool *done)
+static CURLcode oldap_do(struct Curl_easy *data, bool *done)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapconninfo *li = conn->proto.ldapc;
@@ -390,9 +399,9 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
 
 
   connkeep(conn, "OpenLDAP do");
   connkeep(conn, "OpenLDAP do");
 
 
-  infof(data, "LDAP local: %s\n", data->change.url);
+  infof(data, "LDAP local: %s\n", data->state.url);
 
 
-  rc = ldap_url_parse(data->change.url, &ludp);
+  rc = ldap_url_parse(data->state.url, &ludp);
   if(rc != LDAP_URL_SUCCESS) {
   if(rc != LDAP_URL_SUCCESS) {
     const char *msg = "url parsing problem";
     const char *msg = "url parsing problem";
     status = CURLE_URL_MALFORMAT;
     status = CURLE_URL_MALFORMAT;
@@ -423,8 +432,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-static CURLcode ldap_done(struct Curl_easy *data, CURLcode res,
-                          bool premature)
+static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
+                           bool premature)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   struct ldapreqinfo *lr = data->req.p.ldap;
   struct ldapreqinfo *lr = data->req.p.ldap;
@@ -446,8 +455,8 @@ static CURLcode ldap_done(struct Curl_easy *data, CURLcode res,
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
-static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
-                         size_t len, CURLcode *err)
+static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
+                          size_t len, CURLcode *err)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapconninfo *li = conn->proto.ldapc;
@@ -543,7 +552,7 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
         rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) {
         rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) {
       int i;
       int i;
 
 
-      if(bv.bv_val == NULL)
+      if(!bv.bv_val)
         break;
         break;
 
 
       if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
       if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
@@ -551,7 +560,7 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
       else
       else
         binary = 0;
         binary = 0;
 
 
-      if(bvals == NULL) {
+      if(!bvals) {
         writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
         writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
         if(writeerr) {
         if(writeerr) {
           *err = writeerr;
           *err = writeerr;
@@ -660,7 +669,7 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
 
 
           data->req.bytecount += bvals[i].bv_len + 1;
           data->req.bytecount += bvals[i].bv_len + 1;
         }
         }
-        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
         if(writeerr) {
         if(writeerr) {
           *err = writeerr;
           *err = writeerr;
           return -1;
           return -1;
@@ -669,14 +678,14 @@ static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
         data->req.bytecount++;
         data->req.bytecount++;
       }
       }
       ber_memfree(bvals);
       ber_memfree(bvals);
-      writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+      writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
       if(writeerr) {
       if(writeerr) {
         *err = writeerr;
         *err = writeerr;
         return -1;
         return -1;
       }
       }
       data->req.bytecount++;
       data->req.bytecount++;
     }
     }
-    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
     if(writeerr) {
     if(writeerr) {
       *err = writeerr;
       *err = writeerr;
       return -1;
       return -1;
@@ -716,8 +725,8 @@ ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
 {
 {
   (void)arg;
   (void)arg;
   if(opt == LBER_SB_OPT_DATA_READY) {
   if(opt == LBER_SB_OPT_DATA_READY) {
-    struct connectdata *conn = sbiod->sbiod_pvt;
-    return Curl_ssl_data_pending(conn, FIRSTSOCKET);
+    struct Curl_easy *data = sbiod->sbiod_pvt;
+    return Curl_ssl_data_pending(data->conn, FIRSTSOCKET);
   }
   }
   return 0;
   return 0;
 }
 }
@@ -725,14 +734,19 @@ ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
 static ber_slen_t
 static ber_slen_t
 ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 {
 {
-  struct connectdata *conn = sbiod->sbiod_pvt;
-  struct ldapconninfo *li = conn->proto.ldapc;
-  ber_slen_t ret;
-  CURLcode err = CURLE_RECV_ERROR;
+  struct Curl_easy *data = sbiod->sbiod_pvt;
+  ber_slen_t ret = 0;
+  if(data) {
+    struct connectdata *conn = data->conn;
+    if(conn) {
+      struct ldapconninfo *li = conn->proto.ldapc;
+      CURLcode err = CURLE_RECV_ERROR;
 
 
-  ret = (li->recv)(conn->data, FIRSTSOCKET, buf, len, &err);
-  if(ret < 0 && err == CURLE_AGAIN) {
-    SET_SOCKERRNO(EWOULDBLOCK);
+      ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
+      if(ret < 0 && err == CURLE_AGAIN) {
+        SET_SOCKERRNO(EWOULDBLOCK);
+      }
+    }
   }
   }
   return ret;
   return ret;
 }
 }
@@ -740,14 +754,18 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 static ber_slen_t
 static ber_slen_t
 ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
 {
 {
-  struct connectdata *conn = sbiod->sbiod_pvt;
-  struct ldapconninfo *li = conn->proto.ldapc;
-  ber_slen_t ret;
-  CURLcode err = CURLE_SEND_ERROR;
-
-  ret = (li->send)(conn->data, FIRSTSOCKET, buf, len, &err);
-  if(ret < 0 && err == CURLE_AGAIN) {
-    SET_SOCKERRNO(EWOULDBLOCK);
+  struct Curl_easy *data = sbiod->sbiod_pvt;
+  ber_slen_t ret = 0;
+  if(data) {
+    struct connectdata *conn = data->conn;
+    if(conn) {
+      struct ldapconninfo *li = conn->proto.ldapc;
+      CURLcode err = CURLE_SEND_ERROR;
+      ret = (li->send)(data, FIRSTSOCKET, buf, len, &err);
+      if(ret < 0 && err == CURLE_AGAIN) {
+        SET_SOCKERRNO(EWOULDBLOCK);
+      }
+    }
   }
   }
   return ret;
   return ret;
 }
 }

+ 3 - 4
lib/pingpong.h

@@ -33,10 +33,9 @@
 struct connectdata;
 struct connectdata;
 
 
 typedef enum {
 typedef enum {
-  FTPTRANSFER_BODY, /* yes do transfer a body */
-  FTPTRANSFER_INFO, /* do still go through to get info/headers */
-  FTPTRANSFER_NONE, /* don't get anything and don't get info */
-  FTPTRANSFER_LAST  /* end of list marker, never used */
+  PPTRANSFER_BODY, /* yes do transfer a body */
+  PPTRANSFER_INFO, /* do still go through to get info/headers */
+  PPTRANSFER_NONE  /* don't get anything and don't get info */
 } curl_pp_transfer;
 } curl_pp_transfer;
 
 
 /*
 /*

+ 19 - 8
lib/pop3.c

@@ -131,6 +131,7 @@ const struct Curl_handler Curl_handler_pop3 = {
   pop3_disconnect,                  /* disconnect */
   pop3_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* connection_check */
   ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
   PORT_POP3,                        /* defport */
   PORT_POP3,                        /* defport */
   CURLPROTO_POP3,                   /* protocol */
   CURLPROTO_POP3,                   /* protocol */
   CURLPROTO_POP3,                   /* family */
   CURLPROTO_POP3,                   /* family */
@@ -159,6 +160,7 @@ const struct Curl_handler Curl_handler_pop3s = {
   pop3_disconnect,                  /* disconnect */
   pop3_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* connection_check */
   ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
   PORT_POP3S,                       /* defport */
   PORT_POP3S,                       /* defport */
   CURLPROTO_POP3S,                  /* protocol */
   CURLPROTO_POP3S,                  /* protocol */
   CURLPROTO_POP3,                   /* family */
   CURLPROTO_POP3,                   /* family */
@@ -571,12 +573,12 @@ static CURLcode pop3_perform_command(struct Curl_easy *data)
   const char *command = NULL;
   const char *command = NULL;
 
 
   /* Calculate the default command */
   /* Calculate the default command */
-  if(pop3->id[0] == '\0' || data->set.ftp_list_only) {
+  if(pop3->id[0] == '\0' || data->set.list_only) {
     command = "LIST";
     command = "LIST";
 
 
     if(pop3->id[0] != '\0')
     if(pop3->id[0] != '\0')
       /* Message specific LIST so skip the BODY transfer */
       /* Message specific LIST so skip the BODY transfer */
-      pop3->transfer = FTPTRANSFER_INFO;
+      pop3->transfer = PPTRANSFER_INFO;
   }
   }
   else
   else
     command = "RETR";
     command = "RETR";
@@ -709,7 +711,7 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code,
       for(;;) {
       for(;;) {
         size_t llen;
         size_t llen;
         size_t wordlen;
         size_t wordlen;
-        unsigned int mechbit;
+        unsigned short mechbit;
 
 
         while(len &&
         while(len &&
               (*line == ' ' || *line == '\t' ||
               (*line == ' ' || *line == '\t' ||
@@ -916,7 +918,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
      the strip counter here so that these bytes won't be delivered. */
      the strip counter here so that these bytes won't be delivered. */
   pop3c->strip = 2;
   pop3c->strip = 2;
 
 
-  if(pop3->transfer == FTPTRANSFER_BODY) {
+  if(pop3->transfer == PPTRANSFER_BODY) {
     /* POP3 download */
     /* POP3 download */
     Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
     Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
 
 
@@ -1150,7 +1152,7 @@ static CURLcode pop3_done(struct Curl_easy *data, CURLcode status,
   Curl_safefree(pop3->custom);
   Curl_safefree(pop3->custom);
 
 
   /* Clear the transfer mode for the next request */
   /* Clear the transfer mode for the next request */
-  pop3->transfer = FTPTRANSFER_BODY;
+  pop3->transfer = PPTRANSFER_BODY;
 
 
   return result;
   return result;
 }
 }
@@ -1174,7 +1176,7 @@ static CURLcode pop3_perform(struct Curl_easy *data, bool *connected,
 
 
   if(data->set.opt_no_body) {
   if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
     /* Requested no body means no transfer */
-    pop3->transfer = FTPTRANSFER_INFO;
+    pop3->transfer = PPTRANSFER_INFO;
   }
   }
 
 
   *dophase_done = FALSE; /* not done yet */
   *dophase_done = FALSE; /* not done yet */
@@ -1515,8 +1517,17 @@ CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread)
       if(prev) {
       if(prev) {
         /* If the partial match was the CRLF and dot then only write the CRLF
         /* If the partial match was the CRLF and dot then only write the CRLF
            as the server would have inserted the dot */
            as the server would have inserted the dot */
-        result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
-                                   strip_dot ? prev - 1 : prev);
+        if(strip_dot && prev - 1 > 0) {
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
+                                     prev - 1);
+        }
+        else if(!strip_dot) {
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)POP3_EOB,
+                                     prev);
+        }
+        else {
+          result = CURLE_OK;
+        }
 
 
         if(result)
         if(result)
           return result;
           return result;

+ 41 - 51
lib/progress.c

@@ -85,7 +85,7 @@ static char *max5data(curl_off_t bytes, char *max5)
               CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
               CURL_FORMAT_CURL_OFF_T "M", bytes/ONE_MEGABYTE,
               (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
               (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
 
 
-#if (CURL_SIZEOF_CURL_OFF_T > 4)
+#if (SIZEOF_CURL_OFF_T > 4)
 
 
   else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
   else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
     /* 'XXXXM' is good until we're at 10000MB or above */
     /* 'XXXXM' is good until we're at 10000MB or above */
@@ -241,6 +241,8 @@ void Curl_pgrsStartNow(struct Curl_easy *data)
   data->progress.is_t_startransfer_set = false;
   data->progress.is_t_startransfer_set = false;
   data->progress.ul_limit_start = data->progress.start;
   data->progress.ul_limit_start = data->progress.start;
   data->progress.dl_limit_start = data->progress.start;
   data->progress.dl_limit_start = data->progress.start;
+  data->progress.ul_limit_size = 0;
+  data->progress.dl_limit_size = 0;
   data->progress.downloaded = 0;
   data->progress.downloaded = 0;
   data->progress.uploaded = 0;
   data->progress.uploaded = 0;
   /* clear all bits except HIDE and HEADERS_OUT */
   /* clear all bits except HIDE and HEADERS_OUT */
@@ -321,14 +323,14 @@ void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size)
 void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
 void Curl_ratelimit(struct Curl_easy *data, struct curltime now)
 {
 {
   /* don't set a new stamp unless the time since last update is long enough */
   /* don't set a new stamp unless the time since last update is long enough */
-  if(data->set.max_recv_speed > 0) {
+  if(data->set.max_recv_speed) {
     if(Curl_timediff(now, data->progress.dl_limit_start) >=
     if(Curl_timediff(now, data->progress.dl_limit_start) >=
        MIN_RATE_LIMIT_PERIOD) {
        MIN_RATE_LIMIT_PERIOD) {
       data->progress.dl_limit_start = now;
       data->progress.dl_limit_start = now;
       data->progress.dl_limit_size = data->progress.downloaded;
       data->progress.dl_limit_size = data->progress.downloaded;
     }
     }
   }
   }
-  if(data->set.max_send_speed > 0) {
+  if(data->set.max_send_speed) {
     if(Curl_timediff(now, data->progress.ul_limit_start) >=
     if(Curl_timediff(now, data->progress.ul_limit_start) >=
        MIN_RATE_LIMIT_PERIOD) {
        MIN_RATE_LIMIT_PERIOD) {
       data->progress.ul_limit_start = now;
       data->progress.ul_limit_start = now;
@@ -369,94 +371,82 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
   }
   }
 }
 }
 
 
+/* returns the average speed in bytes / second */
+static curl_off_t trspeed(curl_off_t size, /* number of bytes */
+                          curl_off_t us)   /* microseconds */
+{
+  if(us < 1)
+    return size * 1000000;
+  return (curl_off_t)((long double)size/us * 1000000);
+}
+
 /* returns TRUE if it's time to show the progress meter */
 /* returns TRUE if it's time to show the progress meter */
 static bool progress_calc(struct Curl_easy *data, struct curltime now)
 static bool progress_calc(struct Curl_easy *data, struct curltime now)
 {
 {
-  curl_off_t timespent;
-  curl_off_t timespent_ms; /* milliseconds */
-  curl_off_t dl = data->progress.downloaded;
-  curl_off_t ul = data->progress.uploaded;
   bool timetoshow = FALSE;
   bool timetoshow = FALSE;
+  struct Progress * const p = &data->progress;
 
 
-  /* The time spent so far (from the start) */
-  data->progress.timespent = Curl_timediff_us(now, data->progress.start);
-  timespent = (curl_off_t)data->progress.timespent/1000000; /* seconds */
-  timespent_ms = (curl_off_t)data->progress.timespent/1000; /* ms */
-
-  /* The average download speed this far */
-  if(dl < CURL_OFF_T_MAX/1000)
-    data->progress.dlspeed = (dl * 1000 / (timespent_ms>0?timespent_ms:1));
-  else
-    data->progress.dlspeed = (dl / (timespent>0?timespent:1));
-
-  /* The average upload speed this far */
-  if(ul < CURL_OFF_T_MAX/1000)
-    data->progress.ulspeed = (ul * 1000 / (timespent_ms>0?timespent_ms:1));
-  else
-    data->progress.ulspeed = (ul / (timespent>0?timespent:1));
+  /* The time spent so far (from the start) in microseconds */
+  p->timespent = Curl_timediff_us(now, p->start);
+  p->dlspeed = trspeed(p->downloaded, p->timespent);
+  p->ulspeed = trspeed(p->uploaded, p->timespent);
 
 
   /* Calculations done at most once a second, unless end is reached */
   /* Calculations done at most once a second, unless end is reached */
-  if(data->progress.lastshow != now.tv_sec) {
+  if(p->lastshow != now.tv_sec) {
     int countindex; /* amount of seconds stored in the speeder array */
     int countindex; /* amount of seconds stored in the speeder array */
-    int nowindex = data->progress.speeder_c% CURR_TIME;
-    data->progress.lastshow = now.tv_sec;
+    int nowindex = p->speeder_c% CURR_TIME;
+    p->lastshow = now.tv_sec;
     timetoshow = TRUE;
     timetoshow = TRUE;
 
 
     /* Let's do the "current speed" thing, with the dl + ul speeds
     /* Let's do the "current speed" thing, with the dl + ul speeds
        combined. Store the speed at entry 'nowindex'. */
        combined. Store the speed at entry 'nowindex'. */
-    data->progress.speeder[ nowindex ] =
-      data->progress.downloaded + data->progress.uploaded;
+    p->speeder[ nowindex ] = p->downloaded + p->uploaded;
 
 
     /* remember the exact time for this moment */
     /* remember the exact time for this moment */
-    data->progress.speeder_time [ nowindex ] = now;
+    p->speeder_time [ nowindex ] = now;
 
 
     /* advance our speeder_c counter, which is increased every time we get
     /* advance our speeder_c counter, which is increased every time we get
        here and we expect it to never wrap as 2^32 is a lot of seconds! */
        here and we expect it to never wrap as 2^32 is a lot of seconds! */
-    data->progress.speeder_c++;
+    p->speeder_c++;
 
 
     /* figure out how many index entries of data we have stored in our speeder
     /* figure out how many index entries of data we have stored in our speeder
        array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
        array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
        transfer. Imagine, after one second we have filled in two entries,
        transfer. Imagine, after one second we have filled in two entries,
        after two seconds we've filled in three entries etc. */
        after two seconds we've filled in three entries etc. */
-    countindex = ((data->progress.speeder_c >= CURR_TIME)?
-                  CURR_TIME:data->progress.speeder_c) - 1;
+    countindex = ((p->speeder_c >= CURR_TIME)? CURR_TIME:p->speeder_c) - 1;
 
 
     /* first of all, we don't do this if there's no counted seconds yet */
     /* first of all, we don't do this if there's no counted seconds yet */
     if(countindex) {
     if(countindex) {
       int checkindex;
       int checkindex;
       timediff_t span_ms;
       timediff_t span_ms;
+      curl_off_t amount;
 
 
       /* Get the index position to compare with the 'nowindex' position.
       /* Get the index position to compare with the 'nowindex' position.
          Get the oldest entry possible. While we have less than CURR_TIME
          Get the oldest entry possible. While we have less than CURR_TIME
          entries, the first entry will remain the oldest. */
          entries, the first entry will remain the oldest. */
-      checkindex = (data->progress.speeder_c >= CURR_TIME)?
-        data->progress.speeder_c%CURR_TIME:0;
+      checkindex = (p->speeder_c >= CURR_TIME)? p->speeder_c%CURR_TIME:0;
 
 
       /* Figure out the exact time for the time span */
       /* Figure out the exact time for the time span */
-      span_ms = Curl_timediff(now, data->progress.speeder_time[checkindex]);
+      span_ms = Curl_timediff(now, p->speeder_time[checkindex]);
       if(0 == span_ms)
       if(0 == span_ms)
         span_ms = 1; /* at least one millisecond MUST have passed */
         span_ms = 1; /* at least one millisecond MUST have passed */
 
 
       /* Calculate the average speed the last 'span_ms' milliseconds */
       /* Calculate the average speed the last 'span_ms' milliseconds */
-      {
-        curl_off_t amount = data->progress.speeder[nowindex]-
-          data->progress.speeder[checkindex];
-
-        if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
-          /* the 'amount' value is bigger than would fit in 32 bits if
-             multiplied with 1000, so we use the double math for this */
-          data->progress.current_speed = (curl_off_t)
-            ((double)amount/((double)span_ms/1000.0));
-        else
-          /* the 'amount' value is small enough to fit within 32 bits even
-             when multiplied with 1000 */
-          data->progress.current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
-      }
+      amount = p->speeder[nowindex]- p->speeder[checkindex];
+
+      if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
+        /* the 'amount' value is bigger than would fit in 32 bits if
+           multiplied with 1000, so we use the double math for this */
+        p->current_speed = (curl_off_t)
+          ((double)amount/((double)span_ms/1000.0));
+      else
+        /* the 'amount' value is small enough to fit within 32 bits even
+           when multiplied with 1000 */
+        p->current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
     }
     }
     else
     else
       /* the first second we use the average */
       /* the first second we use the average */
-      data->progress.current_speed =
-        data->progress.ulspeed + data->progress.dlspeed;
+      p->current_speed = p->ulspeed + p->dlspeed;
 
 
   } /* Calculations end */
   } /* Calculations end */
   return timetoshow;
   return timetoshow;

+ 5 - 4
lib/rtsp.c

@@ -109,6 +109,7 @@ const struct Curl_handler Curl_handler_rtsp = {
   rtsp_disconnect,                      /* disconnect */
   rtsp_disconnect,                      /* disconnect */
   rtsp_rtp_readwrite,                   /* readwrite */
   rtsp_rtp_readwrite,                   /* readwrite */
   rtsp_conncheck,                       /* connection_check */
   rtsp_conncheck,                       /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_RTSP,                            /* defport */
   PORT_RTSP,                            /* defport */
   CURLPROTO_RTSP,                       /* protocol */
   CURLPROTO_RTSP,                       /* protocol */
   CURLPROTO_RTSP,                       /* family */
   CURLPROTO_RTSP,                       /* family */
@@ -404,8 +405,8 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
 
 
   /* Referrer */
   /* Referrer */
   Curl_safefree(data->state.aptr.ref);
   Curl_safefree(data->state.aptr.ref);
-  if(data->change.referer && !Curl_checkheaders(data, "Referer"))
-    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+  if(data->state.referer && !Curl_checkheaders(data, "Referer"))
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
   else
   else
     data->state.aptr.ref = NULL;
     data->state.aptr.ref = NULL;
 
 
@@ -680,7 +681,7 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
     }
     }
   }
   }
 
 
-  if(rtp_dataleft != 0 && rtp[0] == '$') {
+  if(rtp_dataleft && rtp[0] == '$') {
     DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft,
     DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft,
           *readmore ? "(READMORE)" : ""));
           *readmore ? "(READMORE)" : ""));
 
 
@@ -824,7 +825,7 @@ CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
 
 
       /* Copy the id substring into a new buffer */
       /* Copy the id substring into a new buffer */
       data->set.str[STRING_RTSP_SESSION_ID] = malloc(idlen + 1);
       data->set.str[STRING_RTSP_SESSION_ID] = malloc(idlen + 1);
-      if(data->set.str[STRING_RTSP_SESSION_ID] == NULL)
+      if(!data->set.str[STRING_RTSP_SESSION_ID])
         return CURLE_OUT_OF_MEMORY;
         return CURLE_OUT_OF_MEMORY;
       memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, idlen);
       memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, idlen);
       (data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0';
       (data->set.str[STRING_RTSP_SESSION_ID])[idlen] = '\0';

+ 1 - 1
lib/select.c

@@ -442,7 +442,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
       if(ufds[i].events & POLLPRI)
       if(ufds[i].events & POLLPRI)
         ufds[i].revents |= POLLPRI;
         ufds[i].revents |= POLLPRI;
     }
     }
-    if(ufds[i].revents != 0)
+    if(ufds[i].revents)
       r++;
       r++;
   }
   }
 
 

+ 16 - 7
lib/sendf.c

@@ -65,7 +65,7 @@ static size_t convert_lineends(struct Curl_easy *data,
   char *inPtr, *outPtr;
   char *inPtr, *outPtr;
 
 
   /* sanity check */
   /* sanity check */
-  if((startPtr == NULL) || (size < 1)) {
+  if(!startPtr || (size < 1)) {
     return size;
     return size;
   }
   }
 
 
@@ -309,6 +309,18 @@ CURLcode Curl_write(struct Curl_easy *data,
   conn = data->conn;
   conn = data->conn;
   num = (sockfd == conn->sock[SECONDARYSOCKET]);
   num = (sockfd == conn->sock[SECONDARYSOCKET]);
 
 
+#ifdef CURLDEBUG
+  {
+    /* Allow debug builds to override this logic to force short sends
+    */
+    char *p = getenv("CURL_SMALLSENDS");
+    if(p) {
+      size_t altsize = (size_t)strtoul(p, NULL, 10);
+      if(altsize)
+        len = CURLMIN(len, altsize);
+    }
+  }
+#endif
   bytes_written = conn->send[num](data, num, mem, len, &result);
   bytes_written = conn->send[num](data, num, mem, len, &result);
 
 
   *written = bytes_written;
   *written = bytes_written;
@@ -498,9 +510,7 @@ static CURLcode pausewrite(struct Curl_easy *data,
     /* store this information in the state struct for later use */
     /* store this information in the state struct for later use */
     Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
     Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
     s->tempwrite[i].type = type;
     s->tempwrite[i].type = type;
-
-    if(newtype)
-      s->tempcount++;
+    s->tempcount++;
   }
   }
 
 
   if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
   if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
@@ -606,7 +616,7 @@ static CURLcode chop_write(struct Curl_easy *data,
 /* Curl_client_write() sends data to the write callback(s)
 /* Curl_client_write() sends data to the write callback(s)
 
 
    The bit pattern defines to what "streams" to write to. Body and/or header.
    The bit pattern defines to what "streams" to write to. Body and/or header.
-   The defines are in sendf.h of course.
+   The defines are in sendf.h of course. "len" is not allowed to be 0.
 
 
    If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
    If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
    local character encoding.  This is a problem and should be changed in
    local character encoding.  This is a problem and should be changed in
@@ -618,9 +628,8 @@ CURLcode Curl_client_write(struct Curl_easy *data,
                            size_t len)
                            size_t len)
 {
 {
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
-  if(0 == len)
-    len = strlen(ptr);
 
 
+  DEBUGASSERT(len);
   DEBUGASSERT(type <= 3);
   DEBUGASSERT(type <= 3);
 
 
   /* FTP data may need conversion. */
   /* FTP data may need conversion. */

+ 123 - 47
lib/setopt.c

@@ -177,7 +177,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
     break;
   case CURLOPT_SSL_CIPHER_LIST:
   case CURLOPT_SSL_CIPHER_LIST:
     /* set a list of cipher we want to use in the SSL connection */
     /* set a list of cipher we want to use in the SSL connection */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -190,7 +190,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
   case CURLOPT_TLS13_CIPHERS:
   case CURLOPT_TLS13_CIPHERS:
     if(Curl_ssl_tls13_ciphersuites()) {
     if(Curl_ssl_tls13_ciphersuites()) {
       /* set preferred list of TLS 1.3 cipher suites */
       /* set preferred list of TLS 1.3 cipher suites */
-      result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_ORIG],
+      result = Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST],
                               va_arg(param, char *));
                               va_arg(param, char *));
     }
     }
     else
     else
@@ -426,6 +426,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       version_max = C_SSLVERSION_MAX_VALUE(arg);
       version_max = C_SSLVERSION_MAX_VALUE(arg);
 
 
       if(version < CURL_SSLVERSION_DEFAULT ||
       if(version < CURL_SSLVERSION_DEFAULT ||
+         version == CURL_SSLVERSION_SSLv2 ||
+         version == CURL_SSLVERSION_SSLv3 ||
          version >= CURL_SSLVERSION_LAST ||
          version >= CURL_SSLVERSION_LAST ||
          version_max < CURL_SSLVERSION_MAX_NONE ||
          version_max < CURL_SSLVERSION_MAX_NONE ||
          version_max >= CURL_SSLVERSION_MAX_LAST)
          version_max >= CURL_SSLVERSION_MAX_LAST)
@@ -653,8 +655,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       data->set.httpauth = CURLAUTH_AWS_SIGV4;
       data->set.httpauth = CURLAUTH_AWS_SIGV4;
     break;
     break;
 
 
-#endif   /* CURL_DISABLE_HTTP */
-
   case CURLOPT_MIMEPOST:
   case CURLOPT_MIMEPOST:
     /*
     /*
      * Set to make us do MIME/form POST
      * Set to make us do MIME/form POST
@@ -671,13 +671,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     /*
     /*
      * String to set in the HTTP Referer: field.
      * String to set in the HTTP Referer: field.
      */
      */
-    if(data->change.referer_alloc) {
-      Curl_safefree(data->change.referer);
-      data->change.referer_alloc = FALSE;
+    if(data->state.referer_alloc) {
+      Curl_safefree(data->state.referer);
+      data->state.referer_alloc = FALSE;
     }
     }
     result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
     result = Curl_setstropt(&data->set.str[STRING_SET_REFERER],
                             va_arg(param, char *));
                             va_arg(param, char *));
-    data->change.referer = data->set.str[STRING_SET_REFERER];
+    data->state.referer = data->set.str[STRING_SET_REFERER];
     break;
     break;
 
 
   case CURLOPT_USERAGENT:
   case CURLOPT_USERAGENT:
@@ -695,7 +695,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     data->set.headers = va_arg(param, struct curl_slist *);
     data->set.headers = va_arg(param, struct curl_slist *);
     break;
     break;
 
 
-#ifndef CURL_DISABLE_HTTP
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXYHEADER:
   case CURLOPT_PROXYHEADER:
     /*
     /*
@@ -747,13 +746,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
         return CURLE_BAD_FUNCTION_ARGUMENT;
         return CURLE_BAD_FUNCTION_ARGUMENT;
       /* append the cookie file name to the list of file names, and deal with
       /* append the cookie file name to the list of file names, and deal with
          them later */
          them later */
-      cl = curl_slist_append(data->change.cookielist, argptr);
+      cl = curl_slist_append(data->state.cookielist, argptr);
       if(!cl) {
       if(!cl) {
-        curl_slist_free_all(data->change.cookielist);
-        data->change.cookielist = NULL;
+        curl_slist_free_all(data->state.cookielist);
+        data->state.cookielist = NULL;
         return CURLE_OUT_OF_MEMORY;
         return CURLE_OUT_OF_MEMORY;
       }
       }
-      data->change.cookielist = cl; /* store the list for later use */
+      data->state.cookielist = cl; /* store the list for later use */
+    }
+    else {
+      /* clear the list of cookie files */
+      curl_slist_free_all(data->state.cookielist);
+      data->state.cookielist = NULL;
+
+      if(!data->share || !data->share->cookies) {
+        /* throw away all existing cookies if this isn't a shared cookie
+           container */
+        Curl_cookie_clearall(data->cookies);
+        Curl_cookie_cleanup(data->cookies);
+      }
+      /* disable the cookie engine */
+      data->cookies = NULL;
     }
     }
     break;
     break;
 
 
@@ -800,7 +813,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
   case CURLOPT_COOKIELIST:
   case CURLOPT_COOKIELIST:
     argptr = va_arg(param, char *);
     argptr = va_arg(param, char *);
 
 
-    if(argptr == NULL)
+    if(!argptr)
       break;
       break;
 
 
     if(strcasecompare(argptr, "ALL")) {
     if(strcasecompare(argptr, "ALL")) {
@@ -891,7 +904,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     if(arg == CURL_HTTP_VERSION_NONE)
     if(arg == CURL_HTTP_VERSION_NONE)
       arg = CURL_HTTP_VERSION_2TLS;
       arg = CURL_HTTP_VERSION_2TLS;
 #endif
 #endif
-    data->set.httpversion = arg;
+    data->set.httpwant = (unsigned char)arg;
     break;
     break;
 
 
   case CURLOPT_EXPECT_100_TIMEOUT_MS:
   case CURLOPT_EXPECT_100_TIMEOUT_MS:
@@ -909,7 +922,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     arg = va_arg(param, unsigned long);
     arg = va_arg(param, unsigned long);
     if(arg > 1L)
     if(arg > 1L)
       return CURLE_BAD_FUNCTION_ARGUMENT;
       return CURLE_BAD_FUNCTION_ARGUMENT;
+#ifdef USE_HYPER
+    /* Hyper does not support HTTP/0.9 */
+    if(arg)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+#else
     data->set.http09_allowed = arg ? TRUE : FALSE;
     data->set.http09_allowed = arg ? TRUE : FALSE;
+#endif
     break;
     break;
 #endif   /* CURL_DISABLE_HTTP */
 #endif   /* CURL_DISABLE_HTTP */
 
 
@@ -1160,7 +1179,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * An option that changes the command to one that asks for a list only, no
      * An option that changes the command to one that asks for a list only, no
      * file info details. Used for FTP, POP3 and SFTP.
      * file info details. Used for FTP, POP3 and SFTP.
      */
      */
-    data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    data->set.list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
     break;
 
 
   case CURLOPT_APPEND:
   case CURLOPT_APPEND:
@@ -1168,7 +1187,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * We want to upload and append to an existing file. Used for FTP and
      * We want to upload and append to an existing file. Used for FTP and
      * SFTP.
      * SFTP.
      */
      */
-    data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
+    data->set.remote_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
     break;
 
 
 #ifndef CURL_DISABLE_FTP
 #ifndef CURL_DISABLE_FTP
@@ -1335,14 +1354,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     /*
     /*
      * The URL to fetch.
      * The URL to fetch.
      */
      */
-    if(data->change.url_alloc) {
+    if(data->state.url_alloc) {
       /* the already set URL is allocated, free it first! */
       /* the already set URL is allocated, free it first! */
-      Curl_safefree(data->change.url);
-      data->change.url_alloc = FALSE;
+      Curl_safefree(data->state.url);
+      data->state.url_alloc = FALSE;
     }
     }
     result = Curl_setstropt(&data->set.str[STRING_SET_URL],
     result = Curl_setstropt(&data->set.str[STRING_SET_URL],
                             va_arg(param, char *));
                             va_arg(param, char *));
-    data->change.url = data->set.str[STRING_SET_URL];
+    data->state.url = data->set.str[STRING_SET_URL];
     break;
     break;
   case CURLOPT_PORT:
   case CURLOPT_PORT:
     /*
     /*
@@ -1416,7 +1435,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     result = Curl_setstropt(&data->set.str[STRING_USERNAME],
     result = Curl_setstropt(&data->set.str[STRING_USERNAME],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
-
   case CURLOPT_PASSWORD:
   case CURLOPT_PASSWORD:
     /*
     /*
      * authentication password to use in the operation
      * authentication password to use in the operation
@@ -1474,7 +1492,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * that aren't actually in use right now will be pruned immediately.
      * that aren't actually in use right now will be pruned immediately.
      */
      */
     data->set.resolve = va_arg(param, struct curl_slist *);
     data->set.resolve = va_arg(param, struct curl_slist *);
-    data->change.resolve = data->set.resolve;
+    data->state.resolve = data->set.resolve;
     break;
     break;
   case CURLOPT_PROGRESSFUNCTION:
   case CURLOPT_PROGRESSFUNCTION:
     /*
     /*
@@ -1666,14 +1684,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     /*
     /*
      * String that holds file name of the SSL certificate to use
      * String that holds file name of the SSL certificate to use
      */
      */
-    result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_CERT],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
   case CURLOPT_SSLCERT_BLOB:
   case CURLOPT_SSLCERT_BLOB:
     /*
     /*
      * Blob that holds file name of the SSL certificate to use
      * Blob that holds file name of the SSL certificate to use
      */
      */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_ORIG],
+    result = Curl_setblobopt(&data->set.blobs[BLOB_CERT],
                              va_arg(param, struct curl_blob *));
                              va_arg(param, struct curl_blob *));
     break;
     break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -1696,7 +1714,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     /*
     /*
      * String that holds file type of the SSL certificate to use
      * String that holds file type of the SSL certificate to use
      */
      */
-    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_CERT_TYPE],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -1712,14 +1730,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     /*
     /*
      * String that holds file name of the SSL key to use
      * String that holds file name of the SSL key to use
      */
      */
-    result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_KEY],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
   case CURLOPT_SSLKEY_BLOB:
   case CURLOPT_SSLKEY_BLOB:
     /*
     /*
      * Blob that holds file name of the SSL key to use
      * Blob that holds file name of the SSL key to use
      */
      */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_ORIG],
+    result = Curl_setblobopt(&data->set.blobs[BLOB_KEY],
                              va_arg(param, struct curl_blob *));
                              va_arg(param, struct curl_blob *));
     break;
     break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -1742,7 +1760,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     /*
     /*
      * String that holds file type of the SSL key to use
      * String that holds file type of the SSL key to use
      */
      */
-    result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_KEY_TYPE],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -1758,7 +1776,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     /*
     /*
      * String that holds the SSL or SSH private key password.
      * String that holds the SSL or SSH private key password.
      */
      */
-    result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_KEY_PASSWD],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -1852,6 +1870,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
         data->set.ssl.primary.verifypeer;
         data->set.ssl.primary.verifypeer;
     }
     }
     break;
     break;
+  case CURLOPT_DOH_SSL_VERIFYPEER:
+    /*
+     * Enable peer SSL verifying for DOH.
+     */
+    data->set.doh_verifypeer = (0 != va_arg(param, long)) ?
+      TRUE : FALSE;
+    break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_SSL_VERIFYPEER:
   case CURLOPT_PROXY_SSL_VERIFYPEER:
     /*
     /*
@@ -1884,6 +1909,15 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
         data->set.ssl.primary.verifyhost;
         data->set.ssl.primary.verifyhost;
     }
     }
     break;
     break;
+  case CURLOPT_DOH_SSL_VERIFYHOST:
+    /*
+     * Enable verification of the host name in the peer certificate for DOH
+     */
+    arg = va_arg(param, long);
+
+    /* Treat both 1 and 2 as TRUE */
+    data->set.doh_verifyhost = (bool)((arg & 3) ? TRUE : FALSE);
+    break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_SSL_VERIFYHOST:
   case CURLOPT_PROXY_SSL_VERIFYHOST:
     /*
     /*
@@ -1919,6 +1953,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
         data->set.ssl.primary.verifystatus;
         data->set.ssl.primary.verifystatus;
     }
     }
     break;
     break;
+  case CURLOPT_DOH_SSL_VERIFYSTATUS:
+    /*
+     * Enable certificate status verifying for DOH.
+     */
+    if(!Curl_ssl_cert_status_request()) {
+      result = CURLE_NOT_BUILT_IN;
+      break;
+    }
+
+    data->set.doh_verifystatus = (0 != va_arg(param, long)) ?
+      TRUE : FALSE;
+    break;
   case CURLOPT_SSL_CTX_FUNCTION:
   case CURLOPT_SSL_CTX_FUNCTION:
     /*
     /*
      * Set a SSL_CTX callback
      * Set a SSL_CTX callback
@@ -1967,7 +2013,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      */
      */
 #ifdef USE_SSL
 #ifdef USE_SSL
     if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY)
     if(Curl_ssl->supports & SSLSUPP_PINNEDPUBKEY)
-      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG],
+      result = Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
                               va_arg(param, char *));
                               va_arg(param, char *));
     else
     else
 #endif
 #endif
@@ -1992,9 +2038,23 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     /*
     /*
      * Set CA info for SSL connection. Specify file name of the CA certificate
      * Set CA info for SSL connection. Specify file name of the CA certificate
      */
      */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
+  case CURLOPT_CAINFO_BLOB:
+    /*
+     * Blob that holds CA info for SSL connection.
+     * Specify entire PEM of the CA certificate
+     */
+#ifdef USE_SSL
+    if(Curl_ssl->supports & SSLSUPP_CAINFO_BLOB)
+      result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO],
+                               va_arg(param, struct curl_blob *));
+    else
+#endif
+      return CURLE_NOT_BUILT_IN;
+
+    break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_CAINFO:
   case CURLOPT_PROXY_CAINFO:
     /*
     /*
@@ -2004,6 +2064,19 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
     result = Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
+  case CURLOPT_PROXY_CAINFO_BLOB:
+    /*
+     * Blob that holds CA info for SSL connection proxy.
+     * Specify entire PEM of the CA certificate
+     */
+#ifdef USE_SSL
+    if(Curl_ssl->supports & SSLSUPP_CAINFO_BLOB)
+      result = Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY],
+                               va_arg(param, struct curl_blob *));
+    else
+#endif
+      return CURLE_NOT_BUILT_IN;
+    break;
 #endif
 #endif
   case CURLOPT_CAPATH:
   case CURLOPT_CAPATH:
     /*
     /*
@@ -2013,7 +2086,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 #ifdef USE_SSL
 #ifdef USE_SSL
     if(Curl_ssl->supports & SSLSUPP_CA_PATH)
     if(Curl_ssl->supports & SSLSUPP_CA_PATH)
       /* This does not work on windows. */
       /* This does not work on windows. */
-      result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_ORIG],
+      result = Curl_setstropt(&data->set.str[STRING_SSL_CAPATH],
                               va_arg(param, char *));
                               va_arg(param, char *));
     else
     else
 #endif
 #endif
@@ -2040,7 +2113,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * Set CRL file info for SSL connection. Specify file name of the CRL
      * Set CRL file info for SSL connection. Specify file name of the CRL
      * to check certificates revocation
      * to check certificates revocation
      */
      */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -2058,14 +2131,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * Set Issuer certificate file
      * Set Issuer certificate file
      * to check certificates issuer
      * to check certificates issuer
      */
      */
-    result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT],
                             va_arg(param, char *));
                             va_arg(param, char *));
     break;
     break;
   case CURLOPT_ISSUERCERT_BLOB:
   case CURLOPT_ISSUERCERT_BLOB:
     /*
     /*
      * Blob that holds Issuer certificate to check certificates issuer
      * Blob that holds Issuer certificate to check certificates issuer
      */
      */
-    result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG],
+    result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT],
                              va_arg(param, struct curl_blob *));
                              va_arg(param, struct curl_blob *));
     break;
     break;
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
@@ -2125,7 +2198,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     else if(arg < UPLOADBUFFER_MIN)
     else if(arg < UPLOADBUFFER_MIN)
       arg = UPLOADBUFFER_MIN;
       arg = UPLOADBUFFER_MIN;
 
 
-    data->set.upload_buffer_size = arg;
+    data->set.upload_buffer_size = (unsigned int)arg;
     Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */
     Curl_safefree(data->state.ulbuf); /* force a realloc next opportunity */
     break;
     break;
 
 
@@ -2238,24 +2311,27 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 
 
   case CURLOPT_SSL_OPTIONS:
   case CURLOPT_SSL_OPTIONS:
     arg = va_arg(param, long);
     arg = va_arg(param, long);
-    data->set.ssl.enable_beast =
-      (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE);
+    data->set.ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
     data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
     data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
     data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
     data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
     data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
     data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
     data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
     data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
+    data->set.ssl.auto_client_cert = !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
+    /* If a setting is added here it should also be added in dohprobe()
+       which sets its own CURLOPT_SSL_OPTIONS based on these settings. */
     break;
     break;
 
 
 #ifndef CURL_DISABLE_PROXY
 #ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_SSL_OPTIONS:
   case CURLOPT_PROXY_SSL_OPTIONS:
     arg = va_arg(param, long);
     arg = va_arg(param, long);
-    data->set.proxy_ssl.enable_beast =
-      (bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE);
+    data->set.proxy_ssl.enable_beast = !!(arg & CURLSSLOPT_ALLOW_BEAST);
     data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
     data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
     data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
     data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
-    data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
     data->set.proxy_ssl.revoke_best_effort =
     data->set.proxy_ssl.revoke_best_effort =
       !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
       !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
+    data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
+    data->set.proxy_ssl.auto_client_cert =
+      !!(arg & CURLSSLOPT_AUTO_CLIENT_CERT);
     break;
     break;
 #endif
 #endif
 
 
@@ -2662,9 +2738,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 #endif
 #endif
 #ifdef USE_TLS_SRP
 #ifdef USE_TLS_SRP
   case CURLOPT_TLSAUTH_USERNAME:
   case CURLOPT_TLSAUTH_USERNAME:
-    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME],
                             va_arg(param, char *));
                             va_arg(param, char *));
-    if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+    if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype)
       data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
       data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
     break;
     break;
   case CURLOPT_PROXY_TLSAUTH_USERNAME:
   case CURLOPT_PROXY_TLSAUTH_USERNAME:
@@ -2677,9 +2753,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 #endif
 #endif
     break;
     break;
   case CURLOPT_TLSAUTH_PASSWORD:
   case CURLOPT_TLSAUTH_PASSWORD:
-    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG],
+    result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD],
                             va_arg(param, char *));
                             va_arg(param, char *));
-    if(data->set.str[STRING_TLSAUTH_USERNAME_ORIG] && !data->set.ssl.authtype)
+    if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype)
       data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
       data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
     break;
     break;
   case CURLOPT_PROXY_TLSAUTH_PASSWORD:
   case CURLOPT_PROXY_TLSAUTH_PASSWORD:
@@ -2863,7 +2939,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     data->set.trailer_data = va_arg(param, void *);
     data->set.trailer_data = va_arg(param, void *);
 #endif
 #endif
     break;
     break;
-#ifdef USE_HSTS
+#ifndef CURL_DISABLE_HSTS
   case CURLOPT_HSTSREADFUNCTION:
   case CURLOPT_HSTSREADFUNCTION:
     data->set.hsts_read = va_arg(param, curl_hstsread_callback);
     data->set.hsts_read = va_arg(param, curl_hstsread_callback);
     break;
     break;

+ 4 - 4
lib/setup-vms.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -87,7 +87,7 @@ static char *vms_translate_path(const char *path)
   /* See if the result is in VMS format, if not, we are done */
   /* See if the result is in VMS format, if not, we are done */
   /* Assume that this is a PATH, not just some data */
   /* Assume that this is a PATH, not just some data */
   test_str = strpbrk(path, ":[<^");
   test_str = strpbrk(path, ":[<^");
-  if(test_str == NULL) {
+  if(!test_str) {
     return (char *)path;
     return (char *)path;
   }
   }
 
 
@@ -119,7 +119,7 @@ static char *vms_getenv(const char *envvar)
 
 
   /* first use the DECC getenv() function */
   /* first use the DECC getenv() function */
   result = decc$getenv(envvar);
   result = decc$getenv(envvar);
-  if(result == NULL) {
+  if(!result) {
     return result;
     return result;
   }
   }
 
 
@@ -154,7 +154,7 @@ static struct passwd *vms_getpwuid(uid_t uid)
 #endif
 #endif
 
 
   my_passwd = decc_getpwuid(uid);
   my_passwd = decc_getpwuid(uid);
-  if(my_passwd == NULL) {
+  if(!my_passwd) {
     return my_passwd;
     return my_passwd;
   }
   }
 
 

+ 6 - 36
lib/sha256.c

@@ -6,7 +6,7 @@
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
  * Copyright (C) 2017, Florin Petriuc, <[email protected]>
  * Copyright (C) 2017, Florin Petriuc, <[email protected]>
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2021, 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
@@ -50,11 +50,10 @@
 /* Please keep the SSL backend-specific #if branches in this order:
 /* Please keep the SSL backend-specific #if branches in this order:
  *
  *
  * 1. USE_OPENSSL
  * 1. USE_OPENSSL
- * 2. USE_GNUTLS_NETTLE
- * 3. USE_GNUTLS
- * 4. USE_MBEDTLS
- * 5. USE_COMMON_CRYPTO
- * 6. USE_WIN32_CRYPTO
+ * 2. USE_GNUTLS
+ * 3. USE_MBEDTLS
+ * 4. USE_COMMON_CRYPTO
+ * 5. USE_WIN32_CRYPTO
  *
  *
  * This ensures that the same SSL branch gets activated throughout this source
  * This ensures that the same SSL branch gets activated throughout this source
  * file even if multiple backends are enabled at the same time.
  * file even if multiple backends are enabled at the same time.
@@ -65,7 +64,7 @@
 /* When OpenSSL is available we use the SHA256-function from OpenSSL */
 /* When OpenSSL is available we use the SHA256-function from OpenSSL */
 #include <openssl/sha.h>
 #include <openssl/sha.h>
 
 
-#elif defined(USE_GNUTLS_NETTLE)
+#elif defined(USE_GNUTLS)
 
 
 #include <nettle/sha.h>
 #include <nettle/sha.h>
 
 
@@ -93,35 +92,6 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
   sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
   sha256_digest(ctx, SHA256_DIGEST_SIZE, digest);
 }
 }
 
 
-#elif defined(USE_GNUTLS)
-
-#include <gcrypt.h>
-
-#include "curl_memory.h"
-
-/* The last #include file should be: */
-#include "memdebug.h"
-
-typedef gcry_md_hd_t SHA256_CTX;
-
-static void SHA256_Init(SHA256_CTX *ctx)
-{
-  gcry_md_open(ctx, GCRY_MD_SHA256, 0);
-}
-
-static void SHA256_Update(SHA256_CTX *ctx,
-                          const unsigned char *data,
-                          unsigned int length)
-{
-  gcry_md_write(*ctx, data, length);
-}
-
-static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
-{
-  memcpy(digest, gcry_md_read(*ctx, 0), SHA256_DIGEST_LENGTH);
-  gcry_md_close(*ctx);
-}
-
 #elif defined(USE_MBEDTLS)
 #elif defined(USE_MBEDTLS)
 
 
 #include <mbedtls/sha256.h>
 #include <mbedtls/sha256.h>

+ 2 - 2
lib/share.c

@@ -235,7 +235,7 @@ Curl_share_lock(struct Curl_easy *data, curl_lock_data type,
 {
 {
   struct Curl_share *share = data->share;
   struct Curl_share *share = data->share;
 
 
-  if(share == NULL)
+  if(!share)
     return CURLSHE_INVALID;
     return CURLSHE_INVALID;
 
 
   if(share->specifier & (1<<type)) {
   if(share->specifier & (1<<type)) {
@@ -252,7 +252,7 @@ Curl_share_unlock(struct Curl_easy *data, curl_lock_data type)
 {
 {
   struct Curl_share *share = data->share;
   struct Curl_share *share = data->share;
 
 
-  if(share == NULL)
+  if(!share)
     return CURLSHE_INVALID;
     return CURLSHE_INVALID;
 
 
   if(share->specifier & (1<<type)) {
   if(share->specifier & (1<<type)) {

+ 2 - 2
lib/sigpipe.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, 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
@@ -24,7 +24,7 @@
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) &&        \
 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) &&        \
-  (defined(USE_OPENSSL) || defined(USE_MBEDTLS))
+  (defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_WOLFSSL))
 #include <signal.h>
 #include <signal.h>
 
 
 struct sigpipe_ignore {
 struct sigpipe_ignore {

+ 6 - 5
lib/smb.c

@@ -24,7 +24,7 @@
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) &&  \
 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) &&  \
-  (CURL_SIZEOF_CURL_OFF_T > 4)
+  (SIZEOF_CURL_OFF_T > 4)
 
 
 #define BUILDING_CURL_SMB_C
 #define BUILDING_CURL_SMB_C
 
 
@@ -88,6 +88,7 @@ const struct Curl_handler Curl_handler_smb = {
   smb_disconnect,                       /* disconnect */
   smb_disconnect,                       /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_SMB,                             /* defport */
   PORT_SMB,                             /* defport */
   CURLPROTO_SMB,                        /* protocol */
   CURLPROTO_SMB,                        /* protocol */
   CURLPROTO_SMB,                        /* family */
   CURLPROTO_SMB,                        /* family */
@@ -114,6 +115,7 @@ const struct Curl_handler Curl_handler_smbs = {
   smb_disconnect,                       /* disconnect */
   smb_disconnect,                       /* disconnect */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* readwrite */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
+  ZERO_NULL,                            /* attach connection */
   PORT_SMBS,                            /* defport */
   PORT_SMBS,                            /* defport */
   CURLPROTO_SMBS,                       /* protocol */
   CURLPROTO_SMBS,                       /* protocol */
   CURLPROTO_SMB,                        /* family */
   CURLPROTO_SMB,                        /* family */
@@ -627,9 +629,8 @@ static CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg)
 
 
   /* Check if there is data in the transfer buffer */
   /* Check if there is data in the transfer buffer */
   if(!smbc->send_size && smbc->upload_size) {
   if(!smbc->send_size && smbc->upload_size) {
-    size_t nread = smbc->upload_size > data->set.upload_buffer_size ?
-      data->set.upload_buffer_size :
-      smbc->upload_size;
+    size_t nread = smbc->upload_size > (size_t)data->set.upload_buffer_size ?
+      (size_t)data->set.upload_buffer_size : smbc->upload_size;
     data->req.upload_fromhere = data->state.ulbuf;
     data->req.upload_fromhere = data->state.ulbuf;
     result = Curl_fillreadbuffer(data, nread, &nread);
     result = Curl_fillreadbuffer(data, nread, &nread);
     if(result && result != CURLE_AGAIN)
     if(result && result != CURLE_AGAIN)
@@ -1022,4 +1023,4 @@ static CURLcode smb_parse_url_path(struct Curl_easy *data,
 }
 }
 
 
 #endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
 #endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
-          CURL_SIZEOF_CURL_OFF_T > 4 */
+          SIZEOF_CURL_OFF_T > 4 */

+ 3 - 3
lib/smb.h

@@ -8,7 +8,7 @@
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
  * Copyright (C) 2014, Bill Nagel <[email protected]>, Exacq Technologies
  * Copyright (C) 2014, Bill Nagel <[email protected]>, Exacq Technologies
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2021, 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
@@ -244,12 +244,12 @@ struct smb_tree_disconnect {
 #endif /* BUILDING_CURL_SMB_C */
 #endif /* BUILDING_CURL_SMB_C */
 
 
 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
 #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \
-    (CURL_SIZEOF_CURL_OFF_T > 4)
+    (SIZEOF_CURL_OFF_T > 4)
 
 
 extern const struct Curl_handler Curl_handler_smb;
 extern const struct Curl_handler Curl_handler_smb;
 extern const struct Curl_handler Curl_handler_smbs;
 extern const struct Curl_handler Curl_handler_smbs;
 
 
 #endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
 #endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE &&
-          CURL_SIZEOF_CURL_OFF_T > 4 */
+          SIZEOF_CURL_OFF_T > 4 */
 
 
 #endif /* HEADER_CURL_SMB_H */
 #endif /* HEADER_CURL_SMB_H */

+ 7 - 5
lib/smtp.c

@@ -136,6 +136,7 @@ const struct Curl_handler Curl_handler_smtp = {
   smtp_disconnect,                  /* disconnect */
   smtp_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* connection_check */
   ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
   PORT_SMTP,                        /* defport */
   PORT_SMTP,                        /* defport */
   CURLPROTO_SMTP,                   /* protocol */
   CURLPROTO_SMTP,                   /* protocol */
   CURLPROTO_SMTP,                   /* family */
   CURLPROTO_SMTP,                   /* family */
@@ -164,6 +165,7 @@ const struct Curl_handler Curl_handler_smtps = {
   smtp_disconnect,                  /* disconnect */
   smtp_disconnect,                  /* disconnect */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* readwrite */
   ZERO_NULL,                        /* connection_check */
   ZERO_NULL,                        /* connection_check */
+  ZERO_NULL,                        /* attach connection */
   PORT_SMTPS,                       /* defport */
   PORT_SMTPS,                       /* defport */
   CURLPROTO_SMTPS,                  /* protocol */
   CURLPROTO_SMTPS,                  /* protocol */
   CURLPROTO_SMTP,                   /* family */
   CURLPROTO_SMTP,                   /* family */
@@ -894,7 +896,7 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data,
       for(;;) {
       for(;;) {
         size_t llen;
         size_t llen;
         size_t wordlen;
         size_t wordlen;
-        unsigned int mechbit;
+        unsigned short mechbit;
 
 
         while(len &&
         while(len &&
               (*line == ' ' || *line == '\t' ||
               (*line == ' ' || *line == '\t' ||
@@ -1433,7 +1435,7 @@ static CURLcode smtp_done(struct Curl_easy *data, CURLcode status,
   }
   }
 
 
   /* Clear the transfer mode for the next request */
   /* Clear the transfer mode for the next request */
-  smtp->transfer = FTPTRANSFER_BODY;
+  smtp->transfer = PPTRANSFER_BODY;
 
 
   return result;
   return result;
 }
 }
@@ -1457,7 +1459,7 @@ static CURLcode smtp_perform(struct Curl_easy *data, bool *connected,
 
 
   if(data->set.opt_no_body) {
   if(data->set.opt_no_body) {
     /* Requested no body means no transfer */
     /* Requested no body means no transfer */
-    smtp->transfer = FTPTRANSFER_INFO;
+    smtp->transfer = PPTRANSFER_INFO;
   }
   }
 
 
   *dophase_done = FALSE; /* not done yet */
   *dophase_done = FALSE; /* not done yet */
@@ -1564,7 +1566,7 @@ static CURLcode smtp_dophase_done(struct Curl_easy *data, bool connected)
 
 
   (void)connected;
   (void)connected;
 
 
-  if(smtp->transfer != FTPTRANSFER_BODY)
+  if(smtp->transfer != PPTRANSFER_BODY)
     /* no data to transfer */
     /* no data to transfer */
     Curl_setup_transfer(data, -1, -1, FALSE, -1);
     Curl_setup_transfer(data, -1, -1, FALSE, -1);
 
 
@@ -1821,7 +1823,7 @@ CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
     }
     }
   }
   }
-  DEBUGASSERT(data->set.upload_buffer_size >= (size_t)nread);
+  DEBUGASSERT((size_t)data->set.upload_buffer_size >= (size_t)nread);
 
 
   /* Have we already sent part of the EOB? */
   /* Have we already sent part of the EOB? */
   eob_sent = smtp->eob;
   eob_sent = smtp->eob;

+ 1 - 4
lib/socketpair.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 2019 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2019 - 2021, 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
@@ -30,7 +30,4 @@ int Curl_socketpair(int domain, int type, int protocol,
 #define Curl_socketpair(a,b,c,d) socketpair(a,b,c,d)
 #define Curl_socketpair(a,b,c,d) socketpair(a,b,c,d)
 #endif
 #endif
 
 
-/* Defined here to allow specific build configs to disable it completely */
-#define USE_SOCKETPAIR 1
-
 #endif /* HEADER_CURL_SOCKETPAIR_H */
 #endif /* HEADER_CURL_SOCKETPAIR_H */

+ 3 - 3
lib/socks.c

@@ -426,7 +426,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
    */
    */
 
 
   /* wrong version ? */
   /* wrong version ? */
-  if(socksreq[0] != 0) {
+  if(socksreq[0]) {
     failf(data,
     failf(data,
           "SOCKS4 reply has wrong version, version should be 0.");
           "SOCKS4 reply has wrong version, version should be 0.");
     return CURLPX_BAD_VERSION;
     return CURLPX_BAD_VERSION;
@@ -742,7 +742,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
       return CURLPX_OK;
       return CURLPX_OK;
     }
     }
     /* ignore the first (VER) byte */
     /* ignore the first (VER) byte */
-    else if(socksreq[1] != 0) { /* status */
+    else if(socksreq[1]) { /* status */
       failf(data, "User was rejected by the SOCKS5 server (%d %d).",
       failf(data, "User was rejected by the SOCKS5 server (%d %d).",
             socksreq[0], socksreq[1]);
             socksreq[0], socksreq[1]);
       return CURLPX_USER_REJECTED;
       return CURLPX_USER_REJECTED;
@@ -927,7 +927,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
             "SOCKS5 reply has wrong version, version should be 5.");
             "SOCKS5 reply has wrong version, version should be 5.");
       return CURLPX_BAD_VERSION;
       return CURLPX_BAD_VERSION;
     }
     }
-    else if(socksreq[1] != 0) { /* Anything besides 0 is an error */
+    else if(socksreq[1]) { /* Anything besides 0 is an error */
       CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
       CURLproxycode rc = CURLPX_REPLY_UNASSIGNED;
       int code = socksreq[1];
       int code = socksreq[1];
       failf(data, "Can't complete SOCKS5 connection to %s. (%d)",
       failf(data, "Can't complete SOCKS5 connection to %s. (%d)",

+ 1 - 1
lib/socks_gssapi.c

@@ -195,7 +195,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     }
     }
 
 
-    if(gss_send_token.length != 0) {
+    if(gss_send_token.length) {
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[1] = 1;    /* authentication message type */
       socksreq[1] = 1;    /* authentication message type */
       us_length = htons((short)gss_send_token.length);
       us_length = htons((short)gss_send_token.length);

+ 1 - 1
lib/socks_sspi.c

@@ -198,7 +198,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
       return CURLE_COULDNT_CONNECT;
       return CURLE_COULDNT_CONNECT;
     }
     }
 
 
-    if(sspi_send_token.cbBuffer != 0) {
+    if(sspi_send_token.cbBuffer) {
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[0] = 1;    /* GSS-API subnegotiation version */
       socksreq[1] = 1;    /* authentication message type */
       socksreq[1] = 1;    /* authentication message type */
       us_length = htons((short)sspi_send_token.cbBuffer);
       us_length = htons((short)sspi_send_token.cbBuffer);

+ 9 - 9
lib/splay.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *                             \___|\___/|_| \_\_____|
  *
  *
- * Copyright (C) 1997 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1997 - 2021, 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
@@ -42,7 +42,7 @@ struct Curl_tree *Curl_splay(struct curltime i,
 {
 {
   struct Curl_tree N, *l, *r, *y;
   struct Curl_tree N, *l, *r, *y;
 
 
-  if(t == NULL)
+  if(!t)
     return t;
     return t;
   N.smaller = N.larger = NULL;
   N.smaller = N.larger = NULL;
   l = r = &N;
   l = r = &N;
@@ -50,14 +50,14 @@ struct Curl_tree *Curl_splay(struct curltime i,
   for(;;) {
   for(;;) {
     long comp = compare(i, t->key);
     long comp = compare(i, t->key);
     if(comp < 0) {
     if(comp < 0) {
-      if(t->smaller == NULL)
+      if(!t->smaller)
         break;
         break;
       if(compare(i, t->smaller->key) < 0) {
       if(compare(i, t->smaller->key) < 0) {
         y = t->smaller;                           /* rotate smaller */
         y = t->smaller;                           /* rotate smaller */
         t->smaller = y->larger;
         t->smaller = y->larger;
         y->larger = t;
         y->larger = t;
         t = y;
         t = y;
-        if(t->smaller == NULL)
+        if(!t->smaller)
           break;
           break;
       }
       }
       r->smaller = t;                               /* link smaller */
       r->smaller = t;                               /* link smaller */
@@ -65,14 +65,14 @@ struct Curl_tree *Curl_splay(struct curltime i,
       t = t->smaller;
       t = t->smaller;
     }
     }
     else if(comp > 0) {
     else if(comp > 0) {
-      if(t->larger == NULL)
+      if(!t->larger)
         break;
         break;
       if(compare(i, t->larger->key) > 0) {
       if(compare(i, t->larger->key) > 0) {
         y = t->larger;                          /* rotate larger */
         y = t->larger;                          /* rotate larger */
         t->larger = y->smaller;
         t->larger = y->smaller;
         y->smaller = t;
         y->smaller = t;
         t = y;
         t = y;
-        if(t->larger == NULL)
+        if(!t->larger)
           break;
           break;
       }
       }
       l->larger = t;                              /* link larger */
       l->larger = t;                              /* link larger */
@@ -104,7 +104,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
     (time_t)-1, (unsigned int)-1
     (time_t)-1, (unsigned int)-1
   }; /* will *NEVER* appear */
   }; /* will *NEVER* appear */
 
 
-  if(node == NULL)
+  if(!node)
     return t;
     return t;
 
 
   if(t != NULL) {
   if(t != NULL) {
@@ -125,7 +125,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i,
     }
     }
   }
   }
 
 
-  if(t == NULL) {
+  if(!t) {
     node->smaller = node->larger = NULL;
     node->smaller = node->larger = NULL;
   }
   }
   else if(compare(i, t->key) < 0) {
   else if(compare(i, t->key) < 0) {
@@ -262,7 +262,7 @@ int Curl_splayremove(struct Curl_tree *t,
   }
   }
   else {
   else {
     /* Remove the root node */
     /* Remove the root node */
-    if(t->smaller == NULL)
+    if(!t->smaller)
       x = t->larger;
       x = t->larger;
     else {
     else {
       x = Curl_splay(removenode->key, t->smaller);
       x = Curl_splay(removenode->key, t->smaller);

Some files were not shown because too many files changed in this diff