Browse Source

curl 2023-09-13 (6fa1d817)

Code extracted from:

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

at commit 6fa1d817e5b1a00d7d0c8168091877476b499317 (curl-8_3_0).
Curl Upstream 2 years ago
parent
commit
017637e40f
100 changed files with 2637 additions and 1760 deletions
  1. 1 1
      CMake/CurlTests.c
  2. 0 40
      CMake/FindNSS.cmake
  3. 1 2
      CMake/OtherTests.cmake
  4. 37 1
      CMake/Platforms/WindowsCache.cmake
  5. 3 0
      CMake/curl-config.cmake.in
  6. 133 95
      CMakeLists.txt
  7. 20 5
      include/curl/curl.h
  8. 4 4
      include/curl/curlver.h
  9. 28 10
      include/curl/mprintf.h
  10. 1 1
      include/curl/multi.h
  11. 18 0
      include/curl/system.h
  12. 2 1
      include/curl/urlapi.h
  13. 140 74
      lib/CMakeLists.txt
  14. 2 6
      lib/Makefile.inc
  15. 69 13
      lib/altsvc.c
  16. 0 1
      lib/amigaos.h
  17. 13 3
      lib/asyn-ares.c
  18. 6 2
      lib/asyn-thread.c
  19. 3 2
      lib/base64.c
  20. 69 45
      lib/c-hyper.c
  21. 0 1
      lib/c-hyper.h
  22. 32 22
      lib/cf-h1-proxy.c
  23. 252 122
      lib/cf-h2-proxy.c
  24. 5 5
      lib/cf-haproxy.c
  25. 19 19
      lib/cf-https-connect.c
  26. 126 75
      lib/cf-socket.c
  27. 1 2
      lib/cfilters.c
  28. 35 31
      lib/connect.c
  29. 8 1
      lib/curl_base64.h
  30. 28 19
      lib/curl_config.h.cmake
  31. 5 6
      lib/curl_des.c
  32. 5 6
      lib/curl_des.h
  33. 2 1
      lib/curl_hmac.h
  34. 0 121
      lib/curl_log.h
  35. 5 4
      lib/curl_md4.h
  36. 3 1
      lib/curl_md5.h
  37. 9 77
      lib/curl_ntlm_core.c
  38. 0 9
      lib/curl_ntlm_core.h
  39. 4 4
      lib/curl_sasl.c
  40. 13 14
      lib/curl_setup.h
  41. 3 1
      lib/curl_sha256.h
  42. 53 30
      lib/curl_trc.c
  43. 150 0
      lib/curl_trc.h
  44. 24 8
      lib/easy.c
  45. 2 2
      lib/formdata.c
  46. 2 5
      lib/formdata.h
  47. 3 6
      lib/ftp.c
  48. 2 2
      lib/gopher.c
  49. 10 3
      lib/headers.c
  50. 3 2
      lib/hmac.c
  51. 15 15
      lib/hostip.c
  52. 133 43
      lib/http.c
  53. 10 8
      lib/http.h
  54. 1 1
      lib/http1.c
  55. 322 201
      lib/http2.c
  56. 200 49
      lib/http_aws_sigv4.c
  57. 1 1
      lib/http_digest.c
  58. 2 2
      lib/http_digest.h
  59. 6 6
      lib/http_proxy.c
  60. 100 20
      lib/idn.c
  61. 2 4
      lib/idn.h
  62. 4 0
      lib/if2ip.c
  63. 35 68
      lib/imap.c
  64. 3 2
      lib/inet_ntop.c
  65. 6 7
      lib/krb5.c
  66. 2 2
      lib/ldap.c
  67. 5 12
      lib/macos.c
  68. 2 1
      lib/macos.h
  69. 30 12
      lib/md4.c
  70. 5 3
      lib/md5.c
  71. 10 8
      lib/mime.c
  72. 1 3
      lib/mqtt.c
  73. 69 83
      lib/multi.c
  74. 5 0
      lib/multiif.h
  75. 5 7
      lib/pingpong.c
  76. 5 8
      lib/pop3.c
  77. 2 1
      lib/rand.c
  78. 0 14
      lib/rand.h
  79. 48 33
      lib/sendf.c
  80. 8 1
      lib/sendf.h
  81. 14 3
      lib/setopt.c
  82. 3 88
      lib/setup-os400.h
  83. 0 1
      lib/setup-vms.h
  84. 15 6
      lib/sha256.c
  85. 4 6
      lib/smb.c
  86. 0 3
      lib/smtp.c
  87. 1 1
      lib/strerror.c
  88. 3 2
      lib/system_win32.h
  89. 4 4
      lib/telnet.c
  90. 11 11
      lib/transfer.c
  91. 45 35
      lib/url.c
  92. 46 6
      lib/urlapi.c
  93. 56 19
      lib/urldata.h
  94. 2 2
      lib/vauth/cram.c
  95. 3 3
      lib/vauth/digest.c
  96. 1 1
      lib/vauth/digest.h
  97. 2 2
      lib/vauth/digest_sspi.c
  98. 1 12
      lib/vauth/ntlm.c
  99. 3 3
      lib/vauth/vauth.h
  100. 32 32
      lib/vquic/curl_msh3.c

+ 1 - 1
CMake/CurlTests.c

@@ -510,7 +510,7 @@ main() {
 int
 main() {
   _Atomic int i = 1;
-  i = 0;  // Force an atomic-write operation.
+  i = 0;  /* Force an atomic-write operation. */
   return i;
 }
 #endif

+ 0 - 40
CMake/FindNSS.cmake

@@ -1,40 +0,0 @@
-#***************************************************************************
-#                                  _   _ ____  _
-#  Project                     ___| | | |  _ \| |
-#                             / __| | | | |_) | |
-#                            | (__| |_| |  _ <| |___
-#                             \___|\___/|_| \_\_____|
-#
-# Copyright (C) Daniel Stenberg, <[email protected]>, et al.
-#
-# This software is licensed as described in the file COPYING, which
-# you should have received as part of this distribution. The terms
-# are also available at https://curl.se/docs/copyright.html.
-#
-# You may opt to use, copy, modify, merge, publish, distribute and/or sell
-# copies of the Software, and permit persons to whom the Software is
-# furnished to do so, under the terms of the COPYING file.
-#
-# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
-# KIND, either express or implied.
-#
-# SPDX-License-Identifier: curl
-#
-###########################################################################
-if(UNIX)
-  find_package(PkgConfig QUIET)
-  pkg_search_module(PC_NSS nss)
-endif()
-if(NOT PC_NSS_FOUND)
-  return()
-endif()
-
-set(NSS_LIBRARIES ${PC_NSS_LINK_LIBRARIES})
-set(NSS_INCLUDE_DIRS ${PC_NSS_INCLUDE_DIRS})
-
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(NSS
-    REQUIRED_VARS NSS_LIBRARIES NSS_INCLUDE_DIRS
-    VERSION_VAR PC_NSS_VERSION)
-
-mark_as_advanced(NSS_INCLUDE_DIRS NSS_LIBRARIES)

+ 1 - 2
CMake/OtherTests.cmake

@@ -38,7 +38,7 @@ if(HAVE_WINDOWS_H)
   set(_source_epilogue
       "${_source_epilogue}\n#ifndef WIN32_LEAN_AND_MEAN\n#define WIN32_LEAN_AND_MEAN\n#endif")
   set(signature_call_conv "PASCAL")
-  if(HAVE_LIBWS2_32)
+  if(WIN32)
     set(CMAKE_REQUIRED_LIBRARIES ws2_32)
   endif()
 else()
@@ -133,4 +133,3 @@ if(NOT CMAKE_CROSSCOMPILING)
     }" HAVE_POLL_FINE)
   endif()
 endif()
-

+ 37 - 1
CMake/Platforms/WindowsCache.cmake

@@ -23,30 +23,64 @@
 ###########################################################################
 if(NOT UNIX)
   if(WIN32)
+
+    set(HAVE_WINDOWS_H 1)
+    set(HAVE_WS2TCPIP_H 1)
+    set(HAVE_WINSOCK2_H 1)
+
+    if(MINGW)
+      set(HAVE_SNPRINTF 1)
+      set(HAVE_UNISTD_H 1)
+      set(HAVE_INTTYPES_H 1)
+      set(HAVE_STRTOLL 1)
+    elseif(MSVC)
+      if(NOT MSVC_VERSION LESS 1800)
+        set(HAVE_INTTYPES_H 1)
+        set(HAVE_STRTOLL 1)
+      else()
+        set(HAVE_INTTYPES_H 0)
+        set(HAVE_STRTOLL 0)
+      endif()
+      if(NOT MSVC_VERSION LESS 1900)
+        set(HAVE_SNPRINTF 1)
+      else()
+        set(HAVE_SNPRINTF 0)
+      endif()
+    endif()
+
     set(HAVE_LIBSOCKET 0)
     set(HAVE_GETHOSTNAME 1)
     set(HAVE_LIBZ 0)
 
     set(HAVE_ARPA_INET_H 0)
+    set(HAVE_ARPA_TFTP_H 0)
     set(HAVE_FCNTL_H 1)
+    set(HAVE_IFADDRS_H 0)
     set(HAVE_IO_H 1)
     set(HAVE_NETDB_H 0)
     set(HAVE_NETINET_IN_H 0)
+    set(HAVE_NETINET_TCP_H 0)
     set(HAVE_NET_IF_H 0)
+    set(HAVE_IOCTL_SIOCGIFADDR 0)
+    set(HAVE_POLL_H 0)
     set(HAVE_PWD_H 0)
     set(HAVE_SETJMP_H 1)
     set(HAVE_SIGNAL_H 1)
     set(HAVE_STDLIB_H 1)
     set(HAVE_STRINGS_H 0)
     set(HAVE_STRING_H 1)
+    set(HAVE_SYS_FILIO_H 0)
+    set(HAVE_SYS_IOCTL_H 0)
     set(HAVE_SYS_PARAM_H 0)
     set(HAVE_SYS_POLL_H 0)
+    set(HAVE_SYS_RESOURCE_H 0)
     set(HAVE_SYS_SELECT_H 0)
     set(HAVE_SYS_SOCKET_H 0)
     set(HAVE_SYS_SOCKIO_H 0)
     set(HAVE_SYS_STAT_H 1)
     set(HAVE_SYS_TIME_H 0)
     set(HAVE_SYS_TYPES_H 1)
+    set(HAVE_SYS_UN_H 0)
     set(HAVE_SYS_UTIME_H 1)
     set(HAVE_TERMIOS_H 0)
     set(HAVE_TERMIO_H 0)
@@ -66,10 +100,12 @@ if(NOT UNIX)
     set(HAVE_GETPWUID 0)
     set(HAVE_GETEUID 0)
     set(HAVE_UTIME 1)
-    set(HAVE_RAND_EGD 0)
     set(HAVE_GMTIME_R 0)
     set(HAVE_GETHOSTBYNAME_R 0)
     set(HAVE_SIGNAL 1)
+    set(HAVE_LINUX_TCP_H 0)
+    set(HAVE_GLIBC_STRERROR_R 0)
+    set(HAVE_MACH_ABSOLUTE_TIME 0)
 
     set(HAVE_GETHOSTBYNAME_R_3 0)
     set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)

+ 3 - 0
CMake/curl-config.cmake.in

@@ -33,3 +33,6 @@ endif()
 
 include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
 check_required_components("@PROJECT_NAME@")
+
+# Alias for either shared or static library
+add_library(@PROJECT_NAME@::libcurl ALIAS @PROJECT_NAME@::@LIB_SELECTED@)

+ 133 - 95
CMakeLists.txt

@@ -49,10 +49,9 @@
 # https://cmake.org/cmake/help/latest/module/FetchContent.html#integrating-with-find-package
 #
 # The following variables are available:
-#   HAVE_RAND_EGD: `RAND_egd` present in OpenSSL
+#   HAVE_SSL_SET0_WBIO: `SSL_set0_wbio` present in OpenSSL
 #   HAVE_AWSLC: OpenSSL is AWS-LC
 #   HAVE_BORINGSSL: OpenSSL is BoringSSL
-#   HAVE_PK11_CREATEMANAGEDGENERICOBJECTL: `PK11_CreateManagedGenericObject` present in NSS
 #   HAVE_SSL_CTX_SET_QUIC_METHOD: `SSL_CTX_set_quic_method` present in OpenSSL/wolfSSL
 #   HAVE_QUICHE_CONN_SET_QLOG_FD: `quiche_conn_set_qlog_fd` present in QUICHE
 #   HAVE_ZSTD_CREATEDSTREAM: `ZSTD_createDStream` present in Zstd
@@ -103,6 +102,8 @@ option(CURL_WERROR "Turn compiler warnings into errors" OFF)
 option(PICKY_COMPILER "Enable picky compiler options" ON)
 option(BUILD_CURL_EXE "Set to ON to build curl executable." ON)
 option(BUILD_SHARED_LIBS "Build shared libraries" ON)
+option(BUILD_STATIC_LIBS "Build shared libraries" OFF)
+option(BUILD_STATIC_CURL "Build curl executable with static libcurl" OFF)
 option(ENABLE_ARES "Set to ON to enable c-ares support" OFF)
 if(WIN32)
   option(CURL_STATIC_CRT "Set to ON to build libcurl with static CRT on Windows (/MT)." OFF)
@@ -146,6 +147,32 @@ if(NOT DEFINED CMAKE_DEBUG_POSTFIX)
   set(CMAKE_DEBUG_POSTFIX "-d")
 endif()
 
+set(LIB_STATIC "libcurl_static")
+set(LIB_SHARED "libcurl_shared")
+
+if(NOT BUILD_SHARED_LIBS AND NOT BUILD_STATIC_LIBS)
+  set(BUILD_STATIC_LIBS ON)
+endif()
+if(NOT BUILD_STATIC_CURL AND NOT BUILD_SHARED_LIBS)
+  set(BUILD_STATIC_CURL ON)
+elseif(BUILD_STATIC_CURL AND NOT BUILD_STATIC_LIBS)
+  set(BUILD_STATIC_CURL OFF)
+endif()
+
+# lib flavour selected for curl tool
+if(BUILD_STATIC_CURL)
+  set(LIB_SELECTED_FOR_EXE ${LIB_STATIC})
+else()
+  set(LIB_SELECTED_FOR_EXE ${LIB_SHARED})
+endif()
+
+# lib flavour selected for example and test programs.
+if(BUILD_SHARED_LIBS)
+  set(LIB_SELECTED ${LIB_SHARED})
+else()
+  set(LIB_SELECTED ${LIB_STATIC})
+endif()
+
 # initialize CURL_LIBS
 set(CURL_LIBS "")
 
@@ -164,14 +191,27 @@ option(CURL_DISABLE_ALTSVC "disables alt-svc support" OFF)
 mark_as_advanced(CURL_DISABLE_ALTSVC)
 option(CURL_DISABLE_COOKIES "disables cookies support" OFF)
 mark_as_advanced(CURL_DISABLE_COOKIES)
-option(CURL_DISABLE_CRYPTO_AUTH "disables cryptographic authentication" OFF)
-mark_as_advanced(CURL_DISABLE_CRYPTO_AUTH)
+option(CURL_DISABLE_BASIC_AUTH "disables Basic authentication" OFF)
+mark_as_advanced(CURL_DISABLE_BASIC_AUTH)
+option(CURL_DISABLE_BEARER_AUTH "disables Bearer authentication" OFF)
+mark_as_advanced(CURL_DISABLE_BEARER_AUTH)
+option(CURL_DISABLE_DIGEST_AUTH "disables Digest authentication" OFF)
+mark_as_advanced(CURL_DISABLE_DIGEST_AUTH)
+option(CURL_DISABLE_KERBEROS_AUTH "disables Kerberos authentication" OFF)
+mark_as_advanced(CURL_DISABLE_KERBEROS_AUTH)
+option(CURL_DISABLE_NEGOTIATE_AUTH "disables negotiate authentication" OFF)
+mark_as_advanced(CURL_DISABLE_NEGOTIATE_AUTH)
+option(CURL_DISABLE_AWS "disables AWS-SIG4" OFF)
+mark_as_advanced(CURL_DISABLE_AWS)
 option(CURL_DISABLE_DICT "disables DICT" OFF)
 mark_as_advanced(CURL_DISABLE_DICT)
 option(CURL_DISABLE_DOH "disables DNS-over-HTTPS" OFF)
 mark_as_advanced(CURL_DISABLE_DOH)
 option(CURL_DISABLE_FILE "disables FILE" OFF)
 mark_as_advanced(CURL_DISABLE_FILE)
+cmake_dependent_option(CURL_DISABLE_FORM_API "disables form api" OFF
+                       "NOT CURL_DISABLE_MIME" ON)
+mark_as_advanced(CURL_DISABLE_FORM_API)
 option(CURL_DISABLE_FTP "disables FTP" OFF)
 mark_as_advanced(CURL_DISABLE_FTP)
 option(CURL_DISABLE_GETOPTIONS "disables curl_easy_options API for existing options to curl_easy_setopt" OFF)
@@ -341,8 +381,10 @@ check_library_exists_concat("socket" connect      HAVE_LIBSOCKET)
 check_function_exists(gethostname HAVE_GETHOSTNAME)
 
 if(WIN32)
-  check_library_exists_concat("ws2_32" getch        HAVE_LIBWS2_32)
-  check_library_exists_concat("winmm"  getch        HAVE_LIBWINMM)
+  list(APPEND CURL_LIBS "ws2_32")
+  if(USE_LIBRTMP)
+    list(APPEND CURL_LIBS "winmm")
+  endif()
 
   # Matching logic used for Curl_win32_random()
   if(MINGW)
@@ -359,24 +401,23 @@ if(WIN32)
 endif()
 
 # check SSL libraries
-# TODO support GnuTLS
 option(CURL_ENABLE_SSL "Enable SSL support" ON)
 
 if(APPLE)
-  cmake_dependent_option(CURL_USE_SECTRANSP "enable Apple OS native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+  cmake_dependent_option(CURL_USE_SECTRANSP "Enable Apple OS native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 endif()
 if(WIN32)
-  cmake_dependent_option(CURL_USE_SCHANNEL "enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+  cmake_dependent_option(CURL_USE_SCHANNEL "Enable Windows native SSL/TLS" OFF CURL_ENABLE_SSL OFF)
   cmake_dependent_option(CURL_WINDOWS_SSPI "Use windows libraries to allow NTLM authentication without OpenSSL" ON
     CURL_USE_SCHANNEL OFF)
 endif()
 cmake_dependent_option(CURL_USE_MBEDTLS "Enable mbedTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 cmake_dependent_option(CURL_USE_BEARSSL "Enable BearSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
-cmake_dependent_option(CURL_USE_NSS "Enable NSS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
-cmake_dependent_option(CURL_USE_WOLFSSL "enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+cmake_dependent_option(CURL_USE_WOLFSSL "Enable wolfSSL for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
+cmake_dependent_option(CURL_USE_GNUTLS "Enable GNUTLS for SSL/TLS" OFF CURL_ENABLE_SSL OFF)
 
 set(openssl_default ON)
-if(WIN32 OR CURL_USE_SECTRANSP OR CURL_USE_SCHANNEL OR CURL_USE_MBEDTLS OR CURL_USE_NSS OR CURL_USE_WOLFSSL)
+if(WIN32 OR CURL_USE_SECTRANSP OR CURL_USE_SCHANNEL OR CURL_USE_MBEDTLS OR CURL_USE_WOLFSSL)
   set(openssl_default OFF)
 endif()
 cmake_dependent_option(CURL_USE_OPENSSL "Use OpenSSL code. Experimental" ${openssl_default} CURL_ENABLE_SSL OFF)
@@ -388,7 +429,6 @@ count_true(enabled_ssl_options_count
   CURL_USE_OPENSSL
   CURL_USE_MBEDTLS
   CURL_USE_BEARSSL
-  CURL_USE_NSS
   CURL_USE_WOLFSSL
 )
 if(enabled_ssl_options_count GREATER "1")
@@ -449,9 +489,6 @@ if(CURL_USE_OPENSSL)
   endif()
 
   set(CMAKE_REQUIRED_INCLUDES ${OPENSSL_INCLUDE_DIR})
-  if(NOT DEFINED HAVE_RAND_EGD)
-    check_symbol_exists(RAND_egd "${CURL_INCLUDES}" HAVE_RAND_EGD)
-  endif()
   if(NOT DEFINED HAVE_BORINGSSL)
     check_symbol_exists(OPENSSL_IS_BORINGSSL "openssl/base.h" HAVE_BORINGSSL)
   endif()
@@ -484,23 +521,13 @@ if(CURL_USE_WOLFSSL)
   include_directories(${WolfSSL_INCLUDE_DIRS})
 endif()
 
-if(CURL_USE_NSS)
-  find_package(NSS REQUIRED)
-  include_directories(${NSS_INCLUDE_DIRS})
-  list(APPEND CURL_LIBS ${NSS_LIBRARIES})
-  set(SSL_ENABLED ON)
-  set(USE_NSS ON)
-  if(NOT DEFINED HAVE_PK11_CREATEMANAGEDGENERICOBJECT)
-    cmake_push_check_state()
-    set(CMAKE_REQUIRED_INCLUDES ${NSS_INCLUDE_DIRS})
-    set(CMAKE_REQUIRED_LIBRARIES ${NSS_LIBRARIES})
-    check_symbol_exists(PK11_CreateManagedGenericObject "pk11pub.h" HAVE_PK11_CREATEMANAGEDGENERICOBJECT)
-    cmake_pop_check_state()
-  endif()
+if(CURL_USE_GNUTLS)
+   set(SSL_ENABLED ON)
+   set(USE_GNUTLS ON)
 endif()
 
 # Keep ZLIB detection after TLS detection,
-# and before calling CheckQuicSupportInOpenSSL.
+# and before calling openssl_check_symbol_exists().
 
 set(HAVE_LIBZ OFF)
 set(USE_ZLIB OFF)
@@ -552,50 +579,50 @@ if(CURL_ZSTD)
   endif()
 endif()
 
-option(USE_NGHTTP2 "Use Nghttp2 library" OFF)
+# Check symbol in OpenSSL-like TLS backends.
+macro(openssl_check_symbol_exists SYMBOL FILES VARIABLE)
+  cmake_push_check_state()
+  if(USE_OPENSSL)
+    set(CMAKE_REQUIRED_INCLUDES   "${OPENSSL_INCLUDE_DIR}")
+    set(CMAKE_REQUIRED_LIBRARIES  "${OPENSSL_LIBRARIES}")
+    if(HAVE_LIBZ)
+      list(APPEND CMAKE_REQUIRED_LIBRARIES "${ZLIB_LIBRARIES}")
+    endif()
+    if(WIN32)
+      list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
+      if(NOT HAVE_MINGW_ORIGINAL)
+        list(APPEND CMAKE_REQUIRED_LIBRARIES "bcrypt")  # for OpenSSL/LibreSSL
+      endif()
+    endif()
+  elseif(USE_WOLFSSL)
+    set(CMAKE_REQUIRED_INCLUDES   "${WolfSSL_INCLUDE_DIRS}")
+    set(CMAKE_REQUIRED_LIBRARIES  "${WolfSSL_LIBRARIES}")
+    if(HAVE_LIBZ)
+      list(APPEND CMAKE_REQUIRED_INCLUDES  "${ZLIB_INCLUDE_DIRS}")  # Public wolfSSL headers require zlib headers
+      list(APPEND CMAKE_REQUIRED_LIBRARIES "${ZLIB_LIBRARIES}")
+    endif()
+    if(WIN32)
+      list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32" "crypt32")
+    endif()
+    list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_UINTPTR_T)  # to pull in stdint.h (as of wolfSSL v5.5.4)
+  endif()
+  check_symbol_exists("${SYMBOL}" "${FILES}" "${VARIABLE}")
+  cmake_pop_check_state()
+endmacro()
+
+if(USE_OPENSSL OR USE_WOLFSSL)
+  if(NOT DEFINED HAVE_SSL_SET0_WBIO)
+    openssl_check_symbol_exists(SSL_set0_wbio "openssl/ssl.h" HAVE_SSL_SET0_WBIO)
+  endif()
+endif()
+
+option(USE_NGHTTP2 "Use nghttp2 library" OFF)
 if(USE_NGHTTP2)
   find_package(NGHTTP2 REQUIRED)
   include_directories(${NGHTTP2_INCLUDE_DIRS})
   list(APPEND CURL_LIBS ${NGHTTP2_LIBRARIES})
 endif()
 
-function(CheckQuicSupportInOpenSSL)
-  # Be sure that the OpenSSL/wolfSSL library actually supports QUIC.
-  if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD)
-    cmake_push_check_state()
-    if(USE_WOLFSSL)
-      set(CMAKE_REQUIRED_INCLUDES   "${WolfSSL_INCLUDE_DIRS}")
-      set(CMAKE_REQUIRED_LIBRARIES  "${WolfSSL_LIBRARIES}")
-      if(HAVE_LIBZ)
-        list(APPEND CMAKE_REQUIRED_INCLUDES  "${ZLIB_INCLUDE_DIRS}")  # Public wolfSSL headers require zlib headers
-        list(APPEND CMAKE_REQUIRED_LIBRARIES "${ZLIB_LIBRARIES}")
-      endif()
-      if(WIN32)
-        list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32" "crypt32")
-      endif()
-      list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_UINTPTR_T)  # to pull in stdint.h (as of wolfSSL v5.5.4)
-      check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
-    else()
-      set(CMAKE_REQUIRED_INCLUDES   "${OPENSSL_INCLUDE_DIR}")
-      set(CMAKE_REQUIRED_LIBRARIES  "${OPENSSL_LIBRARIES}")
-      if(HAVE_LIBZ)
-        list(APPEND CMAKE_REQUIRED_LIBRARIES "${ZLIB_LIBRARIES}")
-      endif()
-      if(WIN32)
-        list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
-        if(NOT HAVE_MINGW_ORIGINAL)
-          list(APPEND CMAKE_REQUIRED_LIBRARIES "bcrypt")  # for OpenSSL/LibreSSL
-        endif()
-      endif()
-      check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
-    endif()
-    cmake_pop_check_state()
-  endif()
-  if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD)
-    message(FATAL_ERROR "QUIC support is missing in OpenSSL/LibreSSL/BoringSSL/wolfSSL. Try setting -DOPENSSL_ROOT_DIR")
-  endif()
-endfunction()
-
 option(USE_NGTCP2 "Use ngtcp2 and nghttp3 libraries for HTTP/3 support" OFF)
 if(USE_NGTCP2)
   if(USE_OPENSSL OR USE_WOLFSSL)
@@ -606,7 +633,19 @@ if(USE_NGTCP2)
     else()
       find_package(NGTCP2 REQUIRED quictls)
     endif()
-    CheckQuicSupportInOpenSSL()
+
+    # Be sure that the OpenSSL/wolfSSL library actually supports QUIC.
+    if(NOT DEFINED HAVE_SSL_CTX_SET_QUIC_METHOD)
+      if(USE_OPENSSL)
+        openssl_check_symbol_exists(SSL_CTX_set_quic_method "openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
+      elseif(USE_WOLFSSL)
+        openssl_check_symbol_exists(wolfSSL_set_quic_method "wolfssl/options.h;wolfssl/openssl/ssl.h" HAVE_SSL_CTX_SET_QUIC_METHOD)
+      endif()
+    endif()
+    if(NOT HAVE_SSL_CTX_SET_QUIC_METHOD)
+      message(FATAL_ERROR "QUIC support is missing in OpenSSL/LibreSSL/BoringSSL/wolfSSL. Try setting -DOPENSSL_ROOT_DIR")
+    endif()
+
   elseif(USE_GNUTLS)
     # TODO add GnuTLS support as vtls library.
     find_package(NGTCP2 REQUIRED GnuTLS)
@@ -656,10 +695,8 @@ if(NOT CURL_DISABLE_LDAP)
   if(WIN32)
     option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)
     if(USE_WIN32_LDAP)
-      check_library_exists_concat("wldap32" cldap_open HAVE_WLDAP32)
-      if(NOT HAVE_WLDAP32)
-        set(USE_WIN32_LDAP OFF)
-      elseif(NOT CURL_DISABLE_LDAPS)
+      list(APPEND CURL_LIBS "wldap32")
+      if(NOT CURL_DISABLE_LDAPS)
         set(HAVE_LDAP_SSL ON)
       endif()
     endif()
@@ -922,7 +959,7 @@ elseif("${CURL_CA_PATH}" STREQUAL "none")
   unset(CURL_CA_PATH CACHE)
 elseif("${CURL_CA_PATH}" STREQUAL "auto")
   unset(CURL_CA_PATH CACHE)
-  if(NOT CMAKE_CROSSCOMPILING AND NOT USE_NSS)
+  if(NOT CMAKE_CROSSCOMPILING)
     set(CURL_CA_PATH_AUTODETECT TRUE)
   endif()
 else()
@@ -975,7 +1012,6 @@ if(NOT UNIX)
   check_include_file_concat("windows.h"      HAVE_WINDOWS_H)
   check_include_file_concat("ws2tcpip.h"     HAVE_WS2TCPIP_H)
   check_include_file_concat("winsock2.h"     HAVE_WINSOCK2_H)
-  check_include_file_concat("wincrypt.h"     HAVE_WINCRYPT_H)
 endif()
 
 check_include_file_concat("inttypes.h"       HAVE_INTTYPES_H)
@@ -1011,7 +1047,6 @@ check_include_file_concat("poll.h"           HAVE_POLL_H)
 check_include_file_concat("pwd.h"            HAVE_PWD_H)
 check_include_file_concat("setjmp.h"         HAVE_SETJMP_H)
 check_include_file_concat("signal.h"         HAVE_SIGNAL_H)
-check_include_file_concat("ssl.h"            HAVE_SSL_H)
 check_include_file_concat("stdatomic.h"      HAVE_STDATOMIC_H)
 check_include_file_concat("stdbool.h"        HAVE_STDBOOL_H)
 check_include_file_concat("stdint.h"         HAVE_STDINT_H)
@@ -1026,7 +1061,6 @@ check_include_file_concat("unistd.h"         HAVE_UNISTD_H)
 check_include_file_concat("utime.h"          HAVE_UTIME_H)
 
 check_include_file_concat("stddef.h"         HAVE_STDDEF_H)
-check_include_file_concat("sys/utsname.h"   HAVE_SYS_UTSNAME_H)
 
 check_type_size(size_t  SIZEOF_SIZE_T)
 check_type_size(ssize_t  SIZEOF_SSIZE_T)
@@ -1055,7 +1089,7 @@ if(NOT CMAKE_CROSSCOMPILING)
 endif()
 
 # Check for some functions that are used
-if(HAVE_LIBWS2_32)
+if(WIN32)
   set(CMAKE_REQUIRED_LIBRARIES ws2_32)
 elseif(HAVE_LIBSOCKET)
   set(CMAKE_REQUIRED_LIBRARIES socket)
@@ -1312,11 +1346,8 @@ if(WIN32)
   # Use the manifest embedded in the Windows Resource
   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 "windows.h;wincrypt.h" USE_WINCRYPT)
-  endif()
-  if(USE_WINCRYPT)
+  # We use crypto functions that are not available for UWP apps
+  if(NOT WINDOWS_STORE)
     set(USE_WIN32_CRYPTO ON)
   endif()
 
@@ -1427,8 +1458,8 @@ 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 OR CURL_DISABLE_NTLM) AND
-    (USE_OPENSSL OR USE_MBEDTLS OR USE_DARWINSSL OR USE_WIN32_CRYPTO))
+if(NOT (CURL_DISABLE_NTLM) AND
+    (USE_OPENSSL OR USE_MBEDTLS OR USE_DARWINSSL OR USE_WIN32_CRYPTO OR USE_GNUTLS))
   set(use_curl_ntlm_core ON)
 endif()
 
@@ -1450,16 +1481,16 @@ _add_if("GSS-API"       HAVE_GSSAPI)
 _add_if("alt-svc"       NOT CURL_DISABLE_ALTSVC)
 _add_if("HSTS"          NOT CURL_DISABLE_HSTS)
 # TODO SSP1 missing for SPNEGO
-_add_if("SPNEGO"        NOT CURL_DISABLE_CRYPTO_AUTH AND
+_add_if("SPNEGO"        NOT CURL_DISABLE_NEGOTIATE_AUTH AND
                         (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
-_add_if("Kerberos"      NOT CURL_DISABLE_CRYPTO_AUTH AND
+_add_if("Kerberos"      NOT CURL_DISABLE_KERBEROS_AUTH AND
                         (HAVE_GSSAPI OR USE_WINDOWS_SSPI))
 # NTLM support requires crypto function adaptions from various SSL libs
 # TODO alternative SSL libs tests for SSP1, GNUTLS, NSS
-_add_if("NTLM"          NOT (CURL_DISABLE_CRYPTO_AUTH OR CURL_DISABLE_NTLM) AND
+_add_if("NTLM"          NOT (CURL_DISABLE_NTLM) AND
                         (use_curl_ntlm_core OR USE_WINDOWS_SSPI))
 # TODO missing option (autoconf: --enable-ntlm-wb)
-_add_if("NTLM_WB"       NOT (CURL_DISABLE_CRYPTO_AUTH OR CURL_DISABLE_NTLM) AND
+_add_if("NTLM_WB"       NOT (CURL_DISABLE_NTLM) 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
@@ -1469,7 +1500,7 @@ _add_if("HTTP2"         USE_NGHTTP2)
 _add_if("HTTP3"         USE_NGTCP2 OR USE_QUICHE)
 _add_if("MultiSSL"      CURL_WITH_MULTI_SSL)
 # TODO wolfSSL only support this from v5.0.0 onwards
-_add_if("HTTPS-proxy"   SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS OR USE_NSS
+_add_if("HTTPS-proxy"   SSL_ENABLED AND (USE_OPENSSL OR USE_GNUTLS
                         OR USE_SCHANNEL OR USE_RUSTLS OR USE_BEARSSL OR
                         USE_MBEDTLS OR USE_SECTRANSP))
 _add_if("unicode"       ENABLE_UNICODE)
@@ -1527,20 +1558,22 @@ _add_if("OpenSSL"          SSL_ENABLED AND USE_OPENSSL)
 _add_if("Secure Transport" SSL_ENABLED AND USE_SECTRANSP)
 _add_if("mbedTLS"          SSL_ENABLED AND USE_MBEDTLS)
 _add_if("BearSSL"          SSL_ENABLED AND USE_BEARSSL)
-_add_if("NSS"              SSL_ENABLED AND USE_NSS)
 _add_if("wolfSSL"          SSL_ENABLED AND USE_WOLFSSL)
+_add_if("GnuTLS"           SSL_ENABLED AND USE_GNUTLS)
+
 if(_items)
   list(SORT _items)
 endif()
 string(REPLACE ";" " " SSL_BACKENDS "${_items}")
 message(STATUS "Enabled SSL backends: ${SSL_BACKENDS}")
+if(CURL_DEFAULT_SSL_BACKEND)
+  message(STATUS "Default SSL backend: ${CURL_DEFAULT_SSL_BACKEND}")
+endif()
 
 # curl-config needs the following options to be set.
 set(CC                      "${CMAKE_C_COMPILER}")
 # TODO probably put a -D... options here?
 set(CONFIGURE_OPTIONS       "")
-# TODO when to set "-DCURL_STATICLIB" for CPPFLAG_CURL_STATICLIB?
-set(CPPFLAG_CURL_STATICLIB  "")
 set(CURLVERSION             "${CURL_VERSION}")
 set(exec_prefix             "\${prefix}")
 set(includedir              "\${prefix}/include")
@@ -1570,12 +1603,17 @@ foreach(_lib ${CMAKE_C_IMPLICIT_LINK_LIBRARIES} ${CURL_LIBS})
 endforeach()
 if(BUILD_SHARED_LIBS)
   set(ENABLE_SHARED         "yes")
-  set(ENABLE_STATIC         "no")
   set(LIBCURL_NO_SHARED     "")
+  set(CPPFLAG_CURL_STATICLIB "")
 else()
   set(ENABLE_SHARED         "no")
-  set(ENABLE_STATIC         "yes")
   set(LIBCURL_NO_SHARED     "${LIBCURL_LIBS}")
+  set(CPPFLAG_CURL_STATICLIB "-DCURL_STATICLIB")
+endif()
+if(BUILD_STATIC_LIBS)
+  set(ENABLE_STATIC         "yes")
+else()
+  set(ENABLE_STATIC         "no")
 endif()
 # "a" (Linux) or "lib" (Windows)
 string(REPLACE "." "" libext "${CMAKE_STATIC_LIBRARY_SUFFIX}")

+ 20 - 5
include/curl/curl.h

@@ -161,7 +161,7 @@ typedef enum {
   CURLSSLBACKEND_GNUTLS = 2,
   CURLSSLBACKEND_NSS = 3,
   CURLSSLBACKEND_OBSOLETE4 = 4,  /* Was QSOSSL. */
-  CURLSSLBACKEND_GSKIT = 5,
+  CURLSSLBACKEND_GSKIT                  CURL_DEPRECATED(8.3.0, "") = 5,
   CURLSSLBACKEND_POLARSSL               CURL_DEPRECATED(7.69.0, "") = 6,
   CURLSSLBACKEND_WOLFSSL = 7,
   CURLSSLBACKEND_SCHANNEL = 8,
@@ -2731,6 +2731,20 @@ CURL_EXTERN CURLcode curl_global_init_mem(long flags,
  */
 CURL_EXTERN void curl_global_cleanup(void);
 
+/*
+ * NAME curl_global_trace()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_trace() can be invoked at application start to
+ * configure which components in curl should participate in tracing.
+
+ * This function is thread-safe if CURL_VERSION_THREADSAFE is set in the
+ * curl_version_info_data.features flag (fetch by curl_version_info()).
+
+ */
+CURL_EXTERN CURLcode curl_global_trace(const char *config);
+
 /* linked-list structure for the CURLOPT_QUOTE option (and other) */
 struct curl_slist {
   char *data;
@@ -2810,13 +2824,14 @@ CURL_EXTERN void curl_slist_free_all(struct curl_slist *list);
  */
 CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
 
-/* info about the certificate chain, only for OpenSSL, GnuTLS, Schannel, NSS
-   and GSKit builds. Asked for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+/* info about the certificate chain, for SSL backends that support it. Asked
+   for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
 struct curl_certinfo {
   int num_of_certs;             /* number of certificates with information */
   struct curl_slist **certinfo; /* for each index in this array, there's a
-                                   linked list with textual information in the
-                                   format "name: value" */
+                                   linked list with textual information for a
+                                   certificate in the format "name:content".
+                                   eg "Subject:foo", "Issuer:bar", etc. */
 };
 
 /* Information about the SSL library used and the respective internal SSL

+ 4 - 4
include/curl/curlver.h

@@ -32,13 +32,13 @@
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "8.2.1-DEV"
+#define LIBCURL_VERSION "8.3.0-DEV"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 2
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 3
+#define LIBCURL_VERSION_PATCH 0
 
 /* This is the numeric version of the libcurl version number, meant for easier
    parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will
@@ -59,7 +59,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x080201
+#define LIBCURL_VERSION_NUM 0x080300
 
 /*
  * This is the date and time when the full source package was created. The

+ 28 - 10
include/curl/mprintf.h

@@ -32,18 +32,36 @@
 extern "C" {
 #endif
 
-CURL_EXTERN int curl_mprintf(const char *format, ...);
-CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...);
-CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...);
+#if (defined(__GNUC__) || defined(__clang__)) &&                        \
+  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) &&         \
+  !defined(__MINGW32__) && !defined(CURL_NO_FMT_CHECKS)
+#define CURL_TEMP_PRINTF(a,b) __attribute__ ((format(printf, a, b)))
+#else
+#define CURL_TEMP_PRINTF(a,b)
+#endif
+
+CURL_EXTERN int curl_mprintf(const char *format, ...) CURL_TEMP_PRINTF(1, 2);
+CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...)
+  CURL_TEMP_PRINTF(2, 3);
+CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...)
+  CURL_TEMP_PRINTF(2, 3);
 CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
-                               const char *format, ...);
-CURL_EXTERN int curl_mvprintf(const char *format, va_list args);
-CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args);
-CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args);
+                               const char *format, ...) CURL_TEMP_PRINTF(3, 4);
+CURL_EXTERN int curl_mvprintf(const char *format, va_list args)
+  CURL_TEMP_PRINTF(1, 0);
+CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args)
+  CURL_TEMP_PRINTF(2, 0);
+CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args)
+  CURL_TEMP_PRINTF(2, 0);
 CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
-                                const char *format, va_list args);
-CURL_EXTERN char *curl_maprintf(const char *format, ...);
-CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
+                                const char *format, va_list args)
+  CURL_TEMP_PRINTF(3, 0);
+CURL_EXTERN char *curl_maprintf(const char *format, ...)
+  CURL_TEMP_PRINTF(1, 2);
+CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args)
+  CURL_TEMP_PRINTF(1, 0);
+
+#undef CURL_TEMP_PRINTF
 
 #ifdef  __cplusplus
 } /* end of extern "C" */

+ 1 - 1
include/curl/multi.h

@@ -118,7 +118,7 @@ typedef struct CURLMsg CURLMsg;
 struct curl_waitfd {
   curl_socket_t fd;
   short events;
-  short revents; /* not supported yet */
+  short revents;
 };
 
 /*

+ 18 - 0
include/curl/system.h

@@ -347,6 +347,24 @@
 #  define CURL_PULL_SYS_TYPES_H      1
 #  define CURL_PULL_SYS_SOCKET_H     1
 
+#elif defined(__hpux) /* HP aCC compiler */
+#  if !defined(_LP64)
+#    define CURL_TYPEOF_CURL_OFF_T     long long
+#    define CURL_FORMAT_CURL_OFF_T     "lld"
+#    define CURL_FORMAT_CURL_OFF_TU    "llu"
+#    define CURL_SUFFIX_CURL_OFF_T     LL
+#    define CURL_SUFFIX_CURL_OFF_TU    ULL
+#  else
+#    define CURL_TYPEOF_CURL_OFF_T     long
+#    define CURL_FORMAT_CURL_OFF_T     "ld"
+#    define CURL_FORMAT_CURL_OFF_TU    "lu"
+#    define CURL_SUFFIX_CURL_OFF_T     L
+#    define CURL_SUFFIX_CURL_OFF_TU    UL
+#  endif
+#  define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+#  define CURL_PULL_SYS_TYPES_H      1
+#  define CURL_PULL_SYS_SOCKET_H     1
+
 /* ===================================== */
 /*    KEEP MSVC THE PENULTIMATE ENTRY    */
 /* ===================================== */

+ 2 - 1
include/curl/urlapi.h

@@ -96,7 +96,8 @@ typedef enum {
 #define CURLU_NO_AUTHORITY (1<<10)      /* Allow empty authority when the
                                            scheme is unknown. */
 #define CURLU_ALLOW_SPACE (1<<11)       /* Allow spaces in the URL */
-#define CURLU_PUNYCODE (1<<12)          /* get the host name in pynycode */
+#define CURLU_PUNYCODE (1<<12)          /* get the host name in punycode */
+#define CURLU_PUNY2IDN (1<<13)          /* punycode => IDN conversion */
 
 typedef struct Curl_URL CURLU;
 

+ 140 - 74
lib/CMakeLists.txt

@@ -25,14 +25,6 @@ set(LIB_NAME libcurl)
 set(LIBCURL_OUTPUT_NAME libcurl CACHE STRING "Basename of the curl library")
 add_definitions(-DBUILDING_LIBCURL)
 
-if(BUILD_SHARED_LIBS)
-  set(CURL_STATICLIB NO)
-else()
-  set(CURL_STATICLIB YES)
-endif()
-
-# Use:
-# * CURL_STATICLIB
 configure_file(curl_config.h.cmake
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h)
 
@@ -43,10 +35,6 @@ list(APPEND HHEADERS
   ${CMAKE_CURRENT_BINARY_DIR}/curl_config.h
   )
 
-if(WIN32 AND NOT CURL_STATICLIB)
-  list(APPEND CSOURCES libcurl.rc)
-endif()
-
 # The rest of the build
 
 include_directories(${CMAKE_CURRENT_BINARY_DIR}/../include)
@@ -59,11 +47,6 @@ if(USE_ARES)
   include_directories(${CARES_INCLUDE_DIR})
 endif()
 
-add_library(
-  ${LIB_NAME}
-  ${HHEADERS} ${CSOURCES}
-  )
-
 add_library(
   curlu # special libcurlu library just for unittests
   STATIC
@@ -72,32 +55,16 @@ add_library(
 )
 target_compile_definitions(curlu PUBLIC UNITTESTS CURL_STATICLIB)
 
-add_library(
-  ${PROJECT_NAME}::${LIB_NAME}
-  ALIAS ${LIB_NAME}
-  )
-
 if(ENABLE_CURLDEBUG)
   # We must compile memdebug.c separately to avoid memdebug.h redefinitions
   # being applied to memdebug.c itself.
   set_source_files_properties(memdebug.c PROPERTIES SKIP_UNITY_BUILD_INCLUSION ON)
 endif()
-
-if(NOT BUILD_SHARED_LIBS)
-    set_target_properties(${LIB_NAME} PROPERTIES INTERFACE_COMPILE_DEFINITIONS CURL_STATICLIB)
-endif()
-
-target_link_libraries(${LIB_NAME} PRIVATE ${CURL_LIBS})
 target_link_libraries(curlu PRIVATE ${CURL_LIBS})
 
 transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
 include(${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake)
 
-set_target_properties(${LIB_NAME} PROPERTIES
-  COMPILE_DEFINITIONS BUILDING_LIBCURL
-  OUTPUT_NAME ${LIBCURL_OUTPUT_NAME}
-  )
-
 if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
   CMAKE_SYSTEM_NAME STREQUAL "Linux" OR
   CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
@@ -114,39 +81,11 @@ if(CMAKE_SYSTEM_NAME STREQUAL "AIX" OR
 
   math(EXPR CMAKESONAME "${VERSIONCHANGE} - ${VERSIONDEL}")
   set(CMAKEVERSION "${CMAKESONAME}.${VERSIONDEL}.${VERSIONADD}")
-
-  set_target_properties(${LIB_NAME} PROPERTIES
-    VERSION ${CMAKEVERSION}
-    SOVERSION ${CMAKESONAME}
-  )
-
-endif()
-
-
-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_FLAGS ${CURL_CFLAG_SYMBOLS_HIDE})
-endif()
-
-# Remove the "lib" prefix since the library is already named "libcurl".
-set_target_properties(${LIB_NAME} PROPERTIES PREFIX "")
-set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "")
-
-if(CURL_HAS_LTO)
-  set_target_properties(${LIB_NAME} PROPERTIES
-    INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
-    INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+else()
+  unset(CMAKESONAME)
 endif()
 
-if(WIN32)
-  if(BUILD_SHARED_LIBS)
-    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()
-elseif(NOT CMAKE_CROSSCOMPILING)
+if(NOT WIN32 AND NOT CMAKE_CROSSCOMPILING)
   # on not-Windows and not-crosscompiling, check for writable argv[]
     include(CheckCSourceRuns)
     check_c_source_runs("
@@ -159,19 +98,146 @@ int main(int argc, char **argv)
       HAVE_WRITABLE_ARGV)
 endif()
 
-target_include_directories(${LIB_NAME} INTERFACE
-  $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
-  $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+## Library definition
+
+# Add "_imp" as a suffix before the extension to avoid conflicting with
+# the statically linked "libcurl.lib" (typically with MSVC)
+if(WIN32 AND
+   NOT IMPORT_LIB_SUFFIX AND
+   CMAKE_STATIC_LIBRARY_SUFFIX STREQUAL CMAKE_IMPORT_LIBRARY_SUFFIX)
+  set(IMPORT_LIB_SUFFIX "_imp")
+endif()
+
+# Whether to do a single compilation pass for libcurl sources and reuse these
+# objects to generate both static and shared target.
+if(NOT DEFINED SHARE_LIB_OBJECT)
+  # Enable it by default on platforms where PIC is the default for both shared
+  # and static and there is a way to tell the linker which libcurl symbols it
+  # should export (vs. marking these symbols exportable at compile-time).
+  if(WIN32)
+    set(SHARE_LIB_OBJECT ON)
+  else()
+    # On other platforms, make it an option disabled by default
+    set(SHARE_LIB_OBJECT OFF)
+  endif()
+endif()
+
+if(SHARE_LIB_OBJECT)
+  set(LIB_OBJECT "libcurl_object")
+  add_library(${LIB_OBJECT} OBJECT ${HHEADERS} ${CSOURCES})
+  target_link_libraries(${LIB_OBJECT} PRIVATE ${CURL_LIBS})
+  set_target_properties(${LIB_OBJECT} PROPERTIES
+    COMPILE_DEFINITIONS "BUILDING_LIBCURL"
+    INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB"
+    POSITION_INDEPENDENT_CODE ON)
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_target_properties(${LIB_OBJECT} PROPERTIES
+      COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS"
+      COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_OBJECT} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+
+  target_include_directories(${LIB_OBJECT} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+
+  set(LIB_SOURCE $<TARGET_OBJECTS:${LIB_OBJECT}>)
+else()
+  set(LIB_SOURCE ${HHEADERS} ${CSOURCES})
+endif()
+
+# we want it to be called libcurl on all platforms
+if(BUILD_STATIC_LIBS)
+  list(APPEND libcurl_export ${LIB_STATIC})
+  add_library(${LIB_STATIC} STATIC ${LIB_SOURCE})
+  add_library(${PROJECT_NAME}::${LIB_STATIC} ALIAS ${LIB_STATIC})
+  target_link_libraries(${LIB_STATIC} PRIVATE ${CURL_LIBS})
+  # Remove the "lib" prefix since the library is already named "libcurl".
+  set_target_properties(${LIB_STATIC} PROPERTIES
+    PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
+    SUFFIX "${STATIC_LIB_SUFFIX}${CMAKE_STATIC_LIBRARY_SUFFIX}"
+    COMPILE_DEFINITIONS "BUILDING_LIBCURL"
+    INTERFACE_COMPILE_DEFINITIONS "CURL_STATICLIB")
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_target_properties(${LIB_STATIC} PROPERTIES
+      COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS"
+      COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_STATIC} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+  if(CMAKEVERSION AND CMAKESONAME)
+    set_target_properties(${LIB_STATIC} PROPERTIES
+      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
+  endif()
+
+  target_include_directories(${LIB_STATIC} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+endif()
+
+if(BUILD_SHARED_LIBS)
+  list(APPEND libcurl_export ${LIB_SHARED})
+  add_library(${LIB_SHARED} SHARED ${LIB_SOURCE})
+  add_library(${PROJECT_NAME}::${LIB_SHARED} ALIAS ${LIB_SHARED})
+  if(WIN32)
+    set_property(TARGET ${LIB_SHARED} APPEND PROPERTY SOURCES libcurl.rc ${CURL_SOURCE_DIR}/libcurl.def)
+  endif()
+  target_link_libraries(${LIB_SHARED} PRIVATE ${CURL_LIBS})
+  # Remove the "lib" prefix since the library is already named "libcurl".
+  set_target_properties(${LIB_SHARED} PROPERTIES
+    PREFIX "" OUTPUT_NAME "${LIBCURL_OUTPUT_NAME}"
+    IMPORT_PREFIX "" IMPORT_SUFFIX "${IMPORT_LIB_SUFFIX}${CMAKE_IMPORT_LIBRARY_SUFFIX}"
+    COMPILE_DEFINITIONS "BUILDING_LIBCURL"
+    POSITION_INDEPENDENT_CODE ON)
+  if(HIDES_CURL_PRIVATE_SYMBOLS)
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS"
+      COMPILE_FLAGS "${CURL_CFLAG_SYMBOLS_HIDE}")
+  endif()
+  if(CURL_HAS_LTO)
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
+      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+  endif()
+  if(CMAKEVERSION AND CMAKESONAME)
+    set_target_properties(${LIB_SHARED} PROPERTIES
+      VERSION ${CMAKEVERSION} SOVERSION ${CMAKESONAME})
+  endif()
+
+  target_include_directories(${LIB_SHARED} INTERFACE
+    $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
+    $<BUILD_INTERFACE:${CURL_SOURCE_DIR}/include>)
+endif()
+
+add_library(${LIB_NAME} ALIAS ${LIB_SELECTED})
+add_library(${PROJECT_NAME}::${LIB_NAME} ALIAS ${LIB_SELECTED})
 
 if(CURL_ENABLE_EXPORT_TARGET)
-  install(TARGETS ${LIB_NAME}
-    EXPORT ${TARGETS_EXPORT_NAME}
-    ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
-    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
-    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
-  )
+  if(BUILD_STATIC_LIBS)
+    install(TARGETS ${LIB_STATIC}
+      EXPORT ${TARGETS_EXPORT_NAME}
+      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    )
+  endif()
+  if(BUILD_SHARED_LIBS)
+    install(TARGETS ${LIB_SHARED}
+      EXPORT ${TARGETS_EXPORT_NAME}
+      ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+      RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
+    )
+  endif()
 
-  export(TARGETS ${LIB_NAME}
+  export(TARGETS ${libcurl_export}
          FILE ${PROJECT_BINARY_DIR}/libcurl-target.cmake
          NAMESPACE ${PROJECT_NAME}::
   )

+ 2 - 6
lib/Makefile.inc

@@ -44,13 +44,11 @@ LIB_VAUTH_HFILES =      \
 
 LIB_VTLS_CFILES =           \
   vtls/bearssl.c            \
-  vtls/gskit.c              \
   vtls/gtls.c               \
   vtls/hostcheck.c          \
   vtls/keylog.c             \
   vtls/mbedtls.c            \
   vtls/mbedtls_threadlock.c \
-  vtls/nss.c                \
   vtls/openssl.c            \
   vtls/rustls.c             \
   vtls/schannel.c           \
@@ -62,13 +60,11 @@ LIB_VTLS_CFILES =           \
 
 LIB_VTLS_HFILES =           \
   vtls/bearssl.h            \
-  vtls/gskit.h              \
   vtls/gtls.h               \
   vtls/hostcheck.h          \
   vtls/keylog.h             \
   vtls/mbedtls.h            \
   vtls/mbedtls_threadlock.h \
-  vtls/nssg.h               \
   vtls/openssl.h            \
   vtls/rustls.h             \
   vtls/schannel.h           \
@@ -126,7 +122,6 @@ LIB_CFILES =         \
   curl_get_line.c    \
   curl_gethostname.c \
   curl_gssapi.c      \
-  curl_log.c         \
   curl_memrchr.c     \
   curl_multibyte.c   \
   curl_ntlm_core.c   \
@@ -137,6 +132,7 @@ LIB_CFILES =         \
   curl_sasl.c        \
   curl_sspi.c        \
   curl_threads.c     \
+  curl_trc.c         \
   dict.c             \
   doh.c              \
   dynbuf.c           \
@@ -262,7 +258,6 @@ LIB_HFILES =         \
   curl_hmac.h        \
   curl_krb5.h        \
   curl_ldap.h        \
-  curl_log.h         \
   curl_md4.h         \
   curl_md5.h         \
   curl_memory.h      \
@@ -280,6 +275,7 @@ LIB_HFILES =         \
   curl_sha256.h      \
   curl_sspi.h        \
   curl_threads.h     \
+  curl_trc.h         \
   curlx.h            \
   dict.h             \
   doh.h              \

+ 69 - 13
lib/altsvc.c

@@ -38,6 +38,8 @@
 #include "warnless.h"
 #include "fopen.h"
 #include "rename.h"
+#include "strdup.h"
+#include "inet_pton.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -97,19 +99,39 @@ static struct altsvc *altsvc_createid(const char *srchost,
 {
   struct altsvc *as = calloc(sizeof(struct altsvc), 1);
   size_t hlen;
+  size_t dlen;
   if(!as)
     return NULL;
   hlen = strlen(srchost);
+  dlen = strlen(dsthost);
   DEBUGASSERT(hlen);
-  as->src.host = strdup(srchost);
+  DEBUGASSERT(dlen);
+  if(!hlen || !dlen)
+    /* bad input */
+    return NULL;
+  if((hlen > 2) && srchost[0] == '[') {
+    /* IPv6 address, strip off brackets */
+    srchost++;
+    hlen -= 2;
+  }
+  else if(srchost[hlen - 1] == '.')
+    /* strip off trailing dot */
+    hlen--;
+  if((dlen > 2) && dsthost[0] == '[') {
+    /* IPv6 address, strip off brackets */
+    dsthost++;
+    dlen -= 2;
+  }
+
+  as->src.host = Curl_memdup(srchost, hlen + 1);
   if(!as->src.host)
     goto error;
-  if(hlen && (srchost[hlen - 1] == '.'))
-    /* strip off trailing any dot */
-    as->src.host[--hlen] = 0;
-  as->dst.host = strdup(dsthost);
+  as->src.host[hlen] = 0;
+
+  as->dst.host = Curl_memdup(dsthost, dlen + 1);
   if(!as->dst.host)
     goto error;
+  as->dst.host[dlen] = 0;
 
   as->src.alpnid = srcalpnid;
   as->dst.alpnid = dstalpnid;
@@ -231,18 +253,40 @@ fail:
 static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
 {
   struct tm stamp;
+  const char *dst6_pre = "";
+  const char *dst6_post = "";
+  const char *src6_pre = "";
+  const char *src6_post = "";
   CURLcode result = Curl_gmtime(as->expires, &stamp);
   if(result)
     return result;
-
+#ifdef ENABLE_IPV6
+  else {
+    char ipv6_unused[16];
+    if(1 == Curl_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) {
+      dst6_pre = "[";
+      dst6_post = "]";
+    }
+    if(1 == Curl_inet_pton(AF_INET6, as->src.host, ipv6_unused)) {
+      src6_pre = "[";
+      src6_post = "]";
+    }
+  }
+#endif
   fprintf(fp,
-          "%s %s %u "
-          "%s %s %u "
+          "%s %s%s%s %u "
+          "%s %s%s%s %u "
           "\"%d%02d%02d "
           "%02d:%02d:%02d\" "
           "%u %d\n",
-          Curl_alpnid2str(as->src.alpnid), as->src.host, as->src.port,
-          Curl_alpnid2str(as->dst.alpnid), as->dst.host, as->dst.port,
+          Curl_alpnid2str(as->src.alpnid),
+          src6_pre, as->src.host, src6_post,
+          as->src.port,
+
+          Curl_alpnid2str(as->dst.alpnid),
+          dst6_pre, as->dst.host, dst6_post,
+          as->dst.port,
+
           stamp.tm_year + 1900, stamp.tm_mon + 1, stamp.tm_mday,
           stamp.tm_hour, stamp.tm_min, stamp.tm_sec,
           as->persist, as->prio);
@@ -500,9 +544,21 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
         if(*p != ':') {
           /* host name starts here */
           const char *hostp = p;
-          while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
-            p++;
-          len = p - hostp;
+          if(*p == '[') {
+            /* pass all valid IPv6 letters - does not handle zone id */
+            len = strspn(++p, "0123456789abcdefABCDEF:.");
+            if(p[len] != ']')
+              /* invalid host syntax, bail out */
+              break;
+            /* we store the IPv6 numerical address *with* brackets */
+            len += 2;
+            p = &p[len-1];
+          }
+          else {
+            while(*p && (ISALNUM(*p) || (*p == '.') || (*p == '-')))
+              p++;
+            len = p - hostp;
+          }
           if(!len || (len >= MAX_ALTSVC_HOSTLEN)) {
             infof(data, "Excessive alt-svc host name, ignoring.");
             valid = FALSE;

+ 0 - 1
lib/amigaos.h

@@ -39,4 +39,3 @@ void Curl_amiga_cleanup(void);
 #endif
 
 #endif /* HEADER_CURL_AMIGAOS_H */
-

+ 13 - 3
lib/asyn-ares.c

@@ -110,7 +110,7 @@ struct thread_data {
 };
 
 /* How long we are willing to wait for additional parallel responses after
-   obtaining a "definitive" one.
+   obtaining a "definitive" one. For old c-ares without getaddrinfo.
 
    This is intended to equal the c-ares default timeout.  cURL always uses that
    default value.  Unfortunately, c-ares doesn't expose its default timeout in
@@ -120,6 +120,8 @@ struct thread_data {
  */
 #define HAPPY_EYEBALLS_DNS_TIMEOUT 5000
 
+#define CARES_TIMEOUT_PER_ATTEMPT 2000
+
 /*
  * Curl_resolver_global_init() - the generic low-level asynchronous name
  * resolve API.  Called from curl_global_init() to initialize global resolver
@@ -173,6 +175,9 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
   int optmask = ARES_OPT_SOCK_STATE_CB;
   options.sock_state_cb = sock_state_cb;
   options.sock_state_cb_data = easy;
+  options.timeout = CARES_TIMEOUT_PER_ATTEMPT;
+  optmask |= ARES_OPT_TIMEOUTMS;
+
   status = ares_init_options((ares_channel*)resolver, &options, optmask);
   if(status != ARES_SUCCESS) {
     if(status == ARES_ENOMEM)
@@ -770,9 +775,14 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
       int pf = PF_INET;
       memset(&hints, 0, sizeof(hints));
 #ifdef CURLRES_IPV6
-      if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data))
+      if((data->conn->ip_version != CURL_IPRESOLVE_V4) &&
+         Curl_ipv6works(data)) {
         /* The stack seems to be IPv6-enabled */
-        pf = PF_UNSPEC;
+        if(data->conn->ip_version == CURL_IPRESOLVE_V6)
+          pf = PF_INET6;
+        else
+          pf = PF_UNSPEC;
+      }
 #endif /* CURLRES_IPV6 */
       hints.ai_family = pf;
       hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?

+ 6 - 2
lib/asyn-thread.c

@@ -696,9 +696,13 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
   *waitp = 0; /* default to synchronous response */
 
 #ifdef CURLRES_IPV6
-  if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data))
+  if((data->conn->ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) {
     /* The stack seems to be IPv6-enabled */
-    pf = PF_UNSPEC;
+    if(data->conn->ip_version == CURL_IPRESOLVE_V6)
+      pf = PF_INET6;
+    else
+      pf = PF_UNSPEC;
+  }
 #endif /* CURLRES_IPV6 */
 
   memset(&hints, 0, sizeof(hints));

+ 3 - 2
lib/base64.c

@@ -32,13 +32,14 @@
   !defined(CURL_DISABLE_POP3) || \
   !defined(CURL_DISABLE_IMAP) || \
   !defined(CURL_DISABLE_DOH) || defined(USE_SSL)
-
-#include "urldata.h" /* for the Curl_easy definition */
+#include "curl/curl.h"
 #include "warnless.h"
 #include "curl_base64.h"
 
 /* The last 2 #include files should be in this order */
+#ifdef BUILDING_LIBCURL
 #include "curl_memory.h"
+#endif
 #include "memdebug.h"
 
 /* ---- Base64 Encoding/Decoding Table --- */

+ 69 - 45
lib/c-hyper.c

@@ -61,6 +61,11 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
+typedef enum {
+    USERDATA_NOT_SET = 0, /* for tasks with no userdata set; must be zero */
+    USERDATA_RESP_BODY
+} userdata_t;
+
 size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
                        uint8_t *buf, size_t buflen)
 {
@@ -182,8 +187,11 @@ static int hyper_each_header(void *userdata,
     }
   }
 
-  data->info.header_size += (curl_off_t)len;
-  data->req.headerbytecount += (curl_off_t)len;
+  result = Curl_bump_headersize(data, len, FALSE);
+  if(result) {
+    data->state.hresult = result;
+    return HYPER_ITER_BREAK;
+  }
   return HYPER_ITER_CONTINUE;
 }
 
@@ -313,9 +321,8 @@ static CURLcode status_line(struct Curl_easy *data,
     if(result)
       return result;
   }
-  data->info.header_size += (curl_off_t)len;
-  data->req.headerbytecount += (curl_off_t)len;
-  return CURLE_OK;
+  result = Curl_bump_headersize(data, len, FALSE);
+  return result;
 }
 
 /*
@@ -348,7 +355,6 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
   struct hyptransfer *h = &data->hyp;
   hyper_task *task;
   hyper_task *foreach;
-  hyper_error *hypererr = NULL;
   const uint8_t *reasonp;
   size_t reason_len;
   CURLcode result = CURLE_OK;
@@ -391,19 +397,9 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
       break;
     }
     t = hyper_task_type(task);
-    switch(t) {
-    case HYPER_TASK_ERROR:
-      hypererr = hyper_task_value(task);
-      break;
-    case HYPER_TASK_RESPONSE:
-      resp = hyper_task_value(task);
-      break;
-    default:
-      break;
-    }
-    hyper_task_free(task);
-
     if(t == HYPER_TASK_ERROR) {
+      hyper_error *hypererr = hyper_task_value(task);
+      hyper_task_free(task);
       if(data->state.hresult) {
         /* override Hyper's view, might not even be an error */
         result = data->state.hresult;
@@ -414,36 +410,55 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
         size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
         hyper_code code = hyper_error_code(hypererr);
         failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
-        if(code == HYPERE_ABORTED_BY_CALLBACK)
+        switch(code) {
+        case HYPERE_ABORTED_BY_CALLBACK:
           result = CURLE_OK;
-        else if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount)
-          result = CURLE_GOT_NOTHING;
-        else if(code == HYPERE_INVALID_PEER_MESSAGE)
+          break;
+        case HYPERE_UNEXPECTED_EOF:
+          if(!data->req.bytecount)
+            result = CURLE_GOT_NOTHING;
+          else
+            result = CURLE_RECV_ERROR;
+          break;
+        case HYPERE_INVALID_PEER_MESSAGE:
+          /* bump headerbytecount to avoid the count remaining at zero and
+             appearing to not having read anything from the peer at all */
+          data->req.headerbytecount++;
           result = CURLE_UNSUPPORTED_PROTOCOL; /* maybe */
-        else
+          break;
+        default:
           result = CURLE_RECV_ERROR;
+          break;
+        }
       }
       *done = TRUE;
       hyper_error_free(hypererr);
       break;
     }
-    else if(h->endtask == task) {
-      /* end of transfer, forget the task handled, we might get a
-       * new one with the same address in the future. */
-      *done = TRUE;
-      h->endtask = NULL;
-      infof(data, "hyperstream is done");
-      if(!k->bodywrites) {
-        /* hyper doesn't always call the body write callback */
-        bool stilldone;
-        result = Curl_http_firstwrite(data, data->conn, &stilldone);
+    else if(t == HYPER_TASK_EMPTY) {
+      void *userdata = hyper_task_userdata(task);
+      hyper_task_free(task);
+      if((userdata_t)userdata == USERDATA_RESP_BODY) {
+        /* end of transfer */
+        *done = TRUE;
+        infof(data, "hyperstream is done");
+        if(!k->bodywrites) {
+          /* hyper doesn't always call the body write callback */
+          bool stilldone;
+          result = Curl_http_firstwrite(data, data->conn, &stilldone);
+        }
+        break;
+      }
+      else {
+        /* A background task for hyper; ignore */
+        continue;
       }
-      break;
-    }
-    else if(t != HYPER_TASK_RESPONSE) {
-      continue;
     }
-    /* HYPER_TASK_RESPONSE */
+
+    DEBUGASSERT(HYPER_TASK_RESPONSE);
+
+    resp = hyper_task_value(task);
+    hyper_task_free(task);
 
     *didwhat = KEEP_RECV;
     if(!resp) {
@@ -523,13 +538,12 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
       result = CURLE_OUT_OF_MEMORY;
       break;
     }
-    DEBUGASSERT(hyper_task_type(foreach) == HYPER_TASK_EMPTY);
+    hyper_task_set_userdata(foreach, (void *)USERDATA_RESP_BODY);
     if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
       failf(data, "Couldn't hyper_executor_push the body-foreach");
       result = CURLE_OUT_OF_MEMORY;
       break;
     }
-    h->endtask = foreach;
 
     hyper_response_free(resp);
     resp = NULL;
@@ -757,7 +771,7 @@ static int uploadstreamed(void *userdata, hyper_context *ctx,
     /* increasing the writebytecount here is a little premature but we
        don't know exactly when the body is sent */
     data->req.writebytecount += fillcount;
-    Curl_pgrsSetUploadCounter(data, fillcount);
+    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
   }
   return HYPER_POLL_READY;
 }
@@ -794,15 +808,16 @@ static CURLcode bodysend(struct Curl_easy *data,
       hyper_body_set_data_func(body, uploadpostfields);
     else {
       result = Curl_get_upload_buffer(data);
-      if(result)
+      if(result) {
+        hyper_body_free(body);
         return result;
+      }
       /* init the "upload from here" pointer */
       data->req.upload_fromhere = data->state.ulbuf;
       hyper_body_set_data_func(body, uploadstreamed);
     }
     if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
       /* fail */
-      hyper_body_free(body);
       result = CURLE_OUT_OF_MEMORY;
     }
   }
@@ -1194,14 +1209,17 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     result = CURLE_OUT_OF_MEMORY;
     goto error;
   }
+  req = NULL;
 
   if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
     failf(data, "Couldn't hyper_executor_push the send");
     result = CURLE_OUT_OF_MEMORY;
     goto error;
   }
+  sendtask = NULL; /* ownership passed on */
 
   hyper_clientconn_free(client);
+  client = NULL;
 
   if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
     /* HTTP GET/HEAD download */
@@ -1214,8 +1232,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
        the full request has been sent. */
     data->req.start100 = Curl_now();
 
-  /* clear userpwd and proxyuserpwd to avoid re-using old credentials
-   * from re-used connections */
+  /* clear userpwd and proxyuserpwd to avoid reusing old credentials
+   * from reused connections */
   Curl_safefree(data->state.aptr.userpwd);
   Curl_safefree(data->state.aptr.proxyuserpwd);
   return CURLE_OK;
@@ -1230,6 +1248,12 @@ error:
   if(handshake)
     hyper_task_free(handshake);
 
+  if(client)
+    hyper_clientconn_free(client);
+
+  if(req)
+    hyper_request_free(req);
+
   return result;
 }
 

+ 0 - 1
lib/c-hyper.h

@@ -34,7 +34,6 @@ struct hyptransfer {
   hyper_waker *write_waker;
   hyper_waker *read_waker;
   const hyper_executor *exec;
-  hyper_task *endtask;
   hyper_waker *exp100_waker;
   hyper_waker *send_body_waker;
 };

+ 32 - 22
lib/cf-h1-proxy.c

@@ -41,7 +41,7 @@
 #include "cfilters.h"
 #include "cf-h1-proxy.h"
 #include "connect.h"
-#include "curl_log.h"
+#include "curl_trc.h"
 #include "curlx.h"
 #include "vtls/vtls.h"
 #include "transfer.h"
@@ -175,36 +175,36 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
   /* entering this one */
   switch(new_state) {
   case H1_TUNNEL_INIT:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'init'"));
+    CURL_TRC_CF(data, cf, "new tunnel state 'init'");
     tunnel_reinit(ts, cf->conn, data);
     break;
 
   case H1_TUNNEL_CONNECT:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'connect'"));
+    CURL_TRC_CF(data, cf, "new tunnel state 'connect'");
     ts->tunnel_state = H1_TUNNEL_CONNECT;
     ts->keepon = KEEPON_CONNECT;
     Curl_dyn_reset(&ts->rcvbuf);
     break;
 
   case H1_TUNNEL_RECEIVE:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'receive'"));
+    CURL_TRC_CF(data, cf, "new tunnel state 'receive'");
     ts->tunnel_state = H1_TUNNEL_RECEIVE;
     break;
 
   case H1_TUNNEL_RESPONSE:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'response'"));
+    CURL_TRC_CF(data, cf, "new tunnel state 'response'");
     ts->tunnel_state = H1_TUNNEL_RESPONSE;
     break;
 
   case H1_TUNNEL_ESTABLISHED:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'established'"));
+    CURL_TRC_CF(data, cf, "new tunnel state 'established'");
     infof(data, "CONNECT phase completed");
     data->state.authproxy.done = TRUE;
     data->state.authproxy.multipass = FALSE;
     /* FALLTHROUGH */
   case H1_TUNNEL_FAILED:
     if(new_state == H1_TUNNEL_FAILED)
-      DEBUGF(LOG_CF(data, cf, "new tunnel state 'failed'"));
+      CURL_TRC_CF(data, cf, "new tunnel state 'failed'");
     ts->tunnel_state = new_state;
     Curl_dyn_reset(&ts->rcvbuf);
     Curl_dyn_reset(&ts->req);
@@ -416,7 +416,7 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf,
     if(!auth)
       return CURLE_OUT_OF_MEMORY;
 
-    DEBUGF(LOG_CF(data, cf, "CONNECT: fwd auth header '%s'", header));
+    CURL_TRC_CF(data, cf, "CONNECT: fwd auth header '%s'", header);
     result = Curl_http_input_auth(data, proxy, auth);
 
     free(auth);
@@ -587,7 +587,9 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
         return result;
     }
 
-    data->info.header_size += (long)perline;
+    result = Curl_bump_headersize(data, perline, TRUE);
+    if(result)
+      return result;
 
     /* Newlines are CRLF, so the CR is ignored as the line isn't
        really terminated until the LF comes. Treat a following CR
@@ -636,7 +638,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
           /* without content-length or chunked encoding, we
              can't keep the connection alive since the close is
              the end signal so we bail out at once instead */
-          DEBUGF(LOG_CF(data, cf, "CONNECT: no content-length or chunked"));
+          CURL_TRC_CF(data, cf, "CONNECT: no content-length or chunked");
           ts->keepon = KEEPON_DONE;
         }
       }
@@ -713,14 +715,13 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
   }
 
   options = hyper_clientconn_options_new();
-  hyper_clientconn_options_set_preserve_header_case(options, 1);
-  hyper_clientconn_options_set_preserve_header_order(options, 1);
-
   if(!options) {
     failf(data, "Couldn't create hyper client options");
     result = CURLE_OUT_OF_MEMORY;
     goto error;
   }
+  hyper_clientconn_options_set_preserve_header_case(options, 1);
+  hyper_clientconn_options_set_preserve_header_order(options, 1);
 
   hyper_clientconn_options_exec(options, h->exec);
 
@@ -751,6 +752,7 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
 
   client = hyper_task_value(task);
   hyper_task_free(task);
+
   req = hyper_request_new();
   if(!req) {
     failf(data, "Couldn't hyper_request_new");
@@ -859,12 +861,17 @@ static CURLcode start_CONNECT(struct Curl_cfilter *cf,
     result = CURLE_OUT_OF_MEMORY;
     goto error;
   }
+  req = NULL;
 
   if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
     failf(data, "Couldn't hyper_executor_push the send");
     result = CURLE_OUT_OF_MEMORY;
     goto error;
   }
+  sendtask = NULL; /* ownership passed on */
+
+  hyper_clientconn_free(client);
+  client = NULL;
 
 error:
   free(host);
@@ -877,6 +884,9 @@ error:
     hyper_task_free(handshake);
   if(client)
     hyper_clientconn_free(client);
+  if(req)
+    hyper_request_free(req);
+
   return result;
 }
 
@@ -975,7 +985,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
     switch(ts->tunnel_state) {
     case H1_TUNNEL_INIT:
       /* Prepare the CONNECT request and make a first attempt to send. */
-      DEBUGF(LOG_CF(data, cf, "CONNECT start"));
+      CURL_TRC_CF(data, cf, "CONNECT start");
       result = start_CONNECT(cf, data, ts);
       if(result)
         goto out;
@@ -984,7 +994,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
 
     case H1_TUNNEL_CONNECT:
       /* see that the request is completely sent */
-      DEBUGF(LOG_CF(data, cf, "CONNECT send"));
+      CURL_TRC_CF(data, cf, "CONNECT send");
       result = send_CONNECT(data, cf->conn, ts, &done);
       if(result || !done)
         goto out;
@@ -993,7 +1003,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
 
     case H1_TUNNEL_RECEIVE:
       /* read what is there */
-      DEBUGF(LOG_CF(data, cf, "CONNECT receive"));
+      CURL_TRC_CF(data, cf, "CONNECT receive");
       result = recv_CONNECT_resp(cf, data, ts, &done);
       if(Curl_pgrsUpdate(data)) {
         result = CURLE_ABORTED_BY_CALLBACK;
@@ -1007,7 +1017,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
       /* FALLTHROUGH */
 
     case H1_TUNNEL_RESPONSE:
-      DEBUGF(LOG_CF(data, cf, "CONNECT response"));
+      CURL_TRC_CF(data, cf, "CONNECT response");
       if(data->req.newurl) {
         /* not the "final" response, we need to do a follow up request.
          * If the other side indicated a connection close, or if someone
@@ -1019,7 +1029,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
            * reset our tunnel state. To avoid recursion, we return
            * and expect to be called again.
            */
-          DEBUGF(LOG_CF(data, cf, "CONNECT need to close+open"));
+          CURL_TRC_CF(data, cf, "CONNECT need to close+open");
           infof(data, "Connect me again please");
           Curl_conn_cf_close(cf, data);
           connkeep(conn, "HTTP proxy CONNECT");
@@ -1043,7 +1053,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
   if(data->info.httpproxycode/100 != 2) {
     /* a non-2xx response and we have no next url to try. */
     Curl_safefree(data->req.newurl);
-    /* failure, close this connection to avoid re-use */
+    /* failure, close this connection to avoid reuse */
     streamclose(conn, "proxy CONNECT failure");
     h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data);
     failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode);
@@ -1073,7 +1083,7 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf,
     return CURLE_OK;
   }
 
-  DEBUGF(LOG_CF(data, cf, "connect"));
+  CURL_TRC_CF(data, cf, "connect");
   result = cf->next->cft->do_connect(cf->next, data, blocking, done);
   if(result || !*done)
     return result;
@@ -1133,14 +1143,14 @@ static int cf_h1_proxy_get_select_socks(struct Curl_cfilter *cf,
 static void cf_h1_proxy_destroy(struct Curl_cfilter *cf,
                                 struct Curl_easy *data)
 {
-  DEBUGF(LOG_CF(data, cf, "destroy"));
+  CURL_TRC_CF(data, cf, "destroy");
   tunnel_free(cf, data);
 }
 
 static void cf_h1_proxy_close(struct Curl_cfilter *cf,
                               struct Curl_easy *data)
 {
-  DEBUGF(LOG_CF(data, cf, "close"));
+  CURL_TRC_CF(data, cf, "close");
   cf->connected = FALSE;
   if(cf->ctx) {
     h1_tunnel_go_state(cf, cf->ctx, H1_TUNNEL_INIT, data);

+ 252 - 122
lib/cf-h2-proxy.c

@@ -30,11 +30,12 @@
 #include "urldata.h"
 #include "cfilters.h"
 #include "connect.h"
-#include "curl_log.h"
+#include "curl_trc.h"
 #include "bufq.h"
 #include "dynbuf.h"
 #include "dynhds.h"
 #include "http1.h"
+#include "http2.h"
 #include "http_proxy.h"
 #include "multiif.h"
 #include "cf-h2-proxy.h"
@@ -44,16 +45,16 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-#define H2_CHUNK_SIZE  (16*1024)
+#define PROXY_H2_CHUNK_SIZE  (16*1024)
 
 #define PROXY_HTTP2_HUGE_WINDOW_SIZE (100 * 1024 * 1024)
 #define H2_TUNNEL_WINDOW_SIZE        (10 * 1024 * 1024)
 
-#define PROXY_H2_NW_RECV_CHUNKS  (H2_TUNNEL_WINDOW_SIZE / H2_CHUNK_SIZE)
+#define PROXY_H2_NW_RECV_CHUNKS  (H2_TUNNEL_WINDOW_SIZE / PROXY_H2_CHUNK_SIZE)
 #define PROXY_H2_NW_SEND_CHUNKS   1
 
-#define H2_TUNNEL_RECV_CHUNKS   (H2_TUNNEL_WINDOW_SIZE / H2_CHUNK_SIZE)
-#define H2_TUNNEL_SEND_CHUNKS   ((128 * 1024) / H2_CHUNK_SIZE)
+#define H2_TUNNEL_RECV_CHUNKS   (H2_TUNNEL_WINDOW_SIZE / PROXY_H2_CHUNK_SIZE)
+#define H2_TUNNEL_SEND_CHUNKS   ((128 * 1024) / PROXY_H2_CHUNK_SIZE)
 
 
 typedef enum {
@@ -87,9 +88,9 @@ static CURLcode tunnel_stream_init(struct Curl_cfilter *cf,
 
   ts->state = H2_TUNNEL_INIT;
   ts->stream_id = -1;
-  Curl_bufq_init2(&ts->recvbuf, H2_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS,
+  Curl_bufq_init2(&ts->recvbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_RECV_CHUNKS,
                   BUFQ_OPT_SOFT_LIMIT);
-  Curl_bufq_init(&ts->sendbuf, H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS);
+  Curl_bufq_init(&ts->sendbuf, PROXY_H2_CHUNK_SIZE, H2_TUNNEL_SEND_CHUNKS);
 
   if(cf->conn->bits.conn_to_host)
     hostname = cf->conn->conn_to_host.name;
@@ -146,29 +147,30 @@ static void h2_tunnel_go_state(struct Curl_cfilter *cf,
   /* entering this one */
   switch(new_state) {
   case H2_TUNNEL_INIT:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'init'"));
+    CURL_TRC_CF(data, cf, "[%d] new tunnel state 'init'", ts->stream_id);
     tunnel_stream_clear(ts);
     break;
 
   case H2_TUNNEL_CONNECT:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'connect'"));
+    CURL_TRC_CF(data, cf, "[%d] new tunnel state 'connect'", ts->stream_id);
     ts->state = H2_TUNNEL_CONNECT;
     break;
 
   case H2_TUNNEL_RESPONSE:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'response'"));
+    CURL_TRC_CF(data, cf, "[%d] new tunnel state 'response'", ts->stream_id);
     ts->state = H2_TUNNEL_RESPONSE;
     break;
 
   case H2_TUNNEL_ESTABLISHED:
-    DEBUGF(LOG_CF(data, cf, "new tunnel state 'established'"));
+    CURL_TRC_CF(data, cf, "[%d] new tunnel state 'established'",
+                ts->stream_id);
     infof(data, "CONNECT phase completed");
     data->state.authproxy.done = TRUE;
     data->state.authproxy.multipass = FALSE;
     /* FALLTHROUGH */
   case H2_TUNNEL_FAILED:
     if(new_state == H2_TUNNEL_FAILED)
-      DEBUGF(LOG_CF(data, cf, "new tunnel state 'failed'"));
+      CURL_TRC_CF(data, cf, "[%d] new tunnel state 'failed'", ts->stream_id);
     ts->state = new_state;
     /* If a proxy-authorization header was used for the proxy, then we should
        make sure that it isn't accidentally used for the document request
@@ -231,9 +233,9 @@ static void drain_tunnel(struct Curl_cfilter *cf,
   bits = CURL_CSELECT_IN;
   if(!tunnel->closed && !tunnel->reset && tunnel->upload_blocked_len)
     bits |= CURL_CSELECT_OUT;
-  if(data->state.dselect_bits != bits) {
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%d] DRAIN dselect_bits=%x",
-                  tunnel->stream_id, bits));
+  if(data->state.dselect_bits != bits || 1) {
+    CURL_TRC_CF(data, cf, "[%d] DRAIN dselect_bits=%x",
+                tunnel->stream_id, bits);
     data->state.dselect_bits = bits;
     Curl_expire(data, 0, EXPIRE_RUN_NOW);
   }
@@ -244,12 +246,17 @@ static ssize_t proxy_nw_in_reader(void *reader_ctx,
                                   CURLcode *err)
 {
   struct Curl_cfilter *cf = reader_ctx;
-  struct Curl_easy *data = CF_DATA_CURRENT(cf);
   ssize_t nread;
 
-  nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
-  DEBUGF(LOG_CF(data, cf, "nw_in_reader(len=%zu) -> %zd, %d",
-         buflen, nread, *err));
+  if(cf) {
+    struct Curl_easy *data = CF_DATA_CURRENT(cf);
+    nread = Curl_conn_cf_recv(cf->next, data, (char *)buf, buflen, err);
+    CURL_TRC_CF(data, cf, "[0] nw_in_reader(len=%zu) -> %zd, %d",
+                buflen, nread, *err);
+  }
+  else {
+    nread = 0;
+  }
   return nread;
 }
 
@@ -258,12 +265,18 @@ static ssize_t proxy_h2_nw_out_writer(void *writer_ctx,
                                       CURLcode *err)
 {
   struct Curl_cfilter *cf = writer_ctx;
-  struct Curl_easy *data = CF_DATA_CURRENT(cf);
   ssize_t nwritten;
 
-  nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen, err);
-  DEBUGF(LOG_CF(data, cf, "nw_out_writer(len=%zu) -> %zd, %d",
-                buflen, nwritten, *err));
+  if(cf) {
+    struct Curl_easy *data = CF_DATA_CURRENT(cf);
+    nwritten = Curl_conn_cf_send(cf->next, data, (const char *)buf, buflen,
+                                 err);
+    CURL_TRC_CF(data, cf, "[0] nw_out_writer(len=%zu) -> %zd, %d",
+                buflen, nwritten, *err);
+  }
+  else {
+    nwritten = 0;
+  }
   return nwritten;
 }
 
@@ -295,6 +308,10 @@ static ssize_t on_session_send(nghttp2_session *h2,
 static int proxy_h2_on_frame_recv(nghttp2_session *session,
                                   const nghttp2_frame *frame,
                                   void *userp);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
+                         void *userp);
+#endif
 static int proxy_h2_on_stream_close(nghttp2_session *session,
                                     int32_t stream_id,
                                     uint32_t error_code, void *userp);
@@ -322,8 +339,8 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
   DEBUGASSERT(!ctx->h2);
   memset(&ctx->tunnel, 0, sizeof(ctx->tunnel));
 
-  Curl_bufq_init(&ctx->inbufq, H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
-  Curl_bufq_init(&ctx->outbufq, H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
+  Curl_bufq_init(&ctx->inbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_RECV_CHUNKS);
+  Curl_bufq_init(&ctx->outbufq, PROXY_H2_CHUNK_SIZE, PROXY_H2_NW_SEND_CHUNKS);
 
   if(tunnel_stream_init(cf, &ctx->tunnel))
     goto out;
@@ -337,6 +354,9 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
   nghttp2_session_callbacks_set_send_callback(cbs, on_session_send);
   nghttp2_session_callbacks_set_on_frame_recv_callback(
     cbs, proxy_h2_on_frame_recv);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  nghttp2_session_callbacks_set_on_frame_send_callback(cbs, on_frame_send);
+#endif
   nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
     cbs, tunnel_recv_callback);
   nghttp2_session_callbacks_set_on_stream_close_callback(
@@ -384,11 +404,11 @@ static CURLcode cf_h2_proxy_ctx_init(struct Curl_cfilter *cf,
 out:
   if(cbs)
     nghttp2_session_callbacks_del(cbs);
-  DEBUGF(LOG_CF(data, cf, "init proxy ctx -> %d", result));
+  CURL_TRC_CF(data, cf, "[0] init proxy ctx -> %d", result);
   return result;
 }
 
-static int should_close_session(struct cf_h2_proxy_ctx *ctx)
+static int proxy_h2_should_close_session(struct cf_h2_proxy_ctx *ctx)
 {
   return !nghttp2_session_want_read(ctx->h2) &&
     !nghttp2_session_want_write(ctx->h2);
@@ -409,13 +429,13 @@ static CURLcode proxy_h2_nw_out_flush(struct Curl_cfilter *cf,
                             &result);
   if(nwritten < 0) {
     if(result == CURLE_AGAIN) {
-      DEBUGF(LOG_CF(data, cf, "flush nw send buffer(%zu) -> EAGAIN",
-                    Curl_bufq_len(&ctx->outbufq)));
+      CURL_TRC_CF(data, cf, "[0] flush nw send buffer(%zu) -> EAGAIN",
+                  Curl_bufq_len(&ctx->outbufq));
       ctx->nw_out_blocked = 1;
     }
     return result;
   }
-  DEBUGF(LOG_CF(data, cf, "nw send buffer flushed"));
+  CURL_TRC_CF(data, cf, "[0] nw send buffer flushed");
   return Curl_bufq_is_empty(&ctx->outbufq)? CURLE_OK: CURLE_AGAIN;
 }
 
@@ -436,8 +456,7 @@ static int proxy_h2_process_pending_input(struct Curl_cfilter *cf,
   while(Curl_bufq_peek(&ctx->inbufq, &buf, &blen)) {
 
     rv = nghttp2_session_mem_recv(ctx->h2, (const uint8_t *)buf, blen);
-    DEBUGF(LOG_CF(data, cf,
-                 "fed %zu bytes from nw to nghttp2 -> %zd", blen, rv));
+    CURL_TRC_CF(data, cf, "[0] %zu bytes to nghttp2 -> %zd", blen, rv);
     if(rv < 0) {
       failf(data,
             "process_pending_input: nghttp2_session_mem_recv() returned "
@@ -447,12 +466,12 @@ static int proxy_h2_process_pending_input(struct Curl_cfilter *cf,
     }
     Curl_bufq_skip(&ctx->inbufq, (size_t)rv);
     if(Curl_bufq_is_empty(&ctx->inbufq)) {
-      DEBUGF(LOG_CF(data, cf, "all data in connection buffer processed"));
+      CURL_TRC_CF(data, cf, "[0] all data in connection buffer processed");
       break;
     }
     else {
-      DEBUGF(LOG_CF(data, cf, "process_pending_input: %zu bytes left "
-                    "in connection buffer", Curl_bufq_len(&ctx->inbufq)));
+      CURL_TRC_CF(data, cf, "[0] process_pending_input: %zu bytes left "
+                  "in connection buffer", Curl_bufq_len(&ctx->inbufq));
     }
   }
 
@@ -468,8 +487,8 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
 
   /* Process network input buffer fist */
   if(!Curl_bufq_is_empty(&ctx->inbufq)) {
-    DEBUGF(LOG_CF(data, cf, "Process %zu bytes in connection buffer",
-                  Curl_bufq_len(&ctx->inbufq)));
+    CURL_TRC_CF(data, cf, "[0] process %zu bytes in connection buffer",
+                Curl_bufq_len(&ctx->inbufq));
     if(proxy_h2_process_pending_input(cf, data, &result) < 0)
       return result;
   }
@@ -482,8 +501,8 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf,
         !Curl_bufq_is_full(&ctx->tunnel.recvbuf)) {
 
     nread = Curl_bufq_slurp(&ctx->inbufq, proxy_nw_in_reader, cf, &result);
-    DEBUGF(LOG_CF(data, cf, "read %zu bytes nw data -> %zd, %d",
-                  Curl_bufq_len(&ctx->inbufq), nread, result));
+    CURL_TRC_CF(data, cf, "[0] read %zu bytes nw data -> %zd, %d",
+                Curl_bufq_len(&ctx->inbufq), nread, result);
     if(nread < 0) {
       if(result != CURLE_AGAIN) {
         failf(data, "Failed receiving HTTP2 data");
@@ -518,8 +537,8 @@ static CURLcode proxy_h2_progress_egress(struct Curl_cfilter *cf,
     rv = nghttp2_session_send(ctx->h2);
 
   if(nghttp2_is_fatal(rv)) {
-    DEBUGF(LOG_CF(data, cf, "nghttp2_session_send error (%s)%d",
-                  nghttp2_strerror(rv), rv));
+    CURL_TRC_CF(data, cf, "[0] nghttp2_session_send error (%s)%d",
+                nghttp2_strerror(rv), rv);
     return CURLE_SEND_ERROR;
   }
   return proxy_h2_nw_out_flush(cf, data);
@@ -555,6 +574,97 @@ static ssize_t on_session_send(nghttp2_session *h2,
   return nwritten;
 }
 
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static int fr_print(const nghttp2_frame *frame, char *buffer, size_t blen)
+{
+  switch(frame->hd.type) {
+    case NGHTTP2_DATA: {
+      return msnprintf(buffer, blen,
+                       "FRAME[DATA, len=%d, eos=%d, padlen=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM),
+                       (int)frame->data.padlen);
+    }
+    case NGHTTP2_HEADERS: {
+      return msnprintf(buffer, blen,
+                       "FRAME[HEADERS, len=%d, hend=%d, eos=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS),
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM));
+    }
+    case NGHTTP2_PRIORITY: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PRIORITY, len=%d, flags=%d]",
+                       (int)frame->hd.length, frame->hd.flags);
+    }
+    case NGHTTP2_RST_STREAM: {
+      return msnprintf(buffer, blen,
+                       "FRAME[RST_STREAM, len=%d, flags=%d, error=%u]",
+                       (int)frame->hd.length, frame->hd.flags,
+                       frame->rst_stream.error_code);
+    }
+    case NGHTTP2_SETTINGS: {
+      if(frame->hd.flags & NGHTTP2_FLAG_ACK) {
+        return msnprintf(buffer, blen, "FRAME[SETTINGS, ack=1]");
+      }
+      return msnprintf(buffer, blen,
+                       "FRAME[SETTINGS, len=%d]", (int)frame->hd.length);
+    }
+    case NGHTTP2_PUSH_PROMISE: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PUSH_PROMISE, len=%d, hend=%d]",
+                       (int)frame->hd.length,
+                       !!(frame->hd.flags & NGHTTP2_FLAG_END_HEADERS));
+    }
+    case NGHTTP2_PING: {
+      return msnprintf(buffer, blen,
+                       "FRAME[PING, len=%d, ack=%d]",
+                       (int)frame->hd.length,
+                       frame->hd.flags&NGHTTP2_FLAG_ACK);
+    }
+    case NGHTTP2_GOAWAY: {
+      char scratch[128];
+      size_t s_len = sizeof(scratch)/sizeof(scratch[0]);
+        size_t len = (frame->goaway.opaque_data_len < s_len)?
+                      frame->goaway.opaque_data_len : s_len-1;
+        if(len)
+          memcpy(scratch, frame->goaway.opaque_data, len);
+        scratch[len] = '\0';
+        return msnprintf(buffer, blen, "FRAME[GOAWAY, error=%d, reason='%s', "
+                         "last_stream=%d]", frame->goaway.error_code,
+                         scratch, frame->goaway.last_stream_id);
+    }
+    case NGHTTP2_WINDOW_UPDATE: {
+      return msnprintf(buffer, blen,
+                       "FRAME[WINDOW_UPDATE, incr=%d]",
+                       frame->window_update.window_size_increment);
+    }
+    default:
+      return msnprintf(buffer, blen, "FRAME[%d, len=%d, flags=%d]",
+                       frame->hd.type, (int)frame->hd.length,
+                       frame->hd.flags);
+  }
+}
+
+static int on_frame_send(nghttp2_session *session, const nghttp2_frame *frame,
+                         void *userp)
+{
+  struct Curl_cfilter *cf = userp;
+  struct Curl_easy *data = CF_DATA_CURRENT(cf);
+
+  (void)session;
+  DEBUGASSERT(data);
+  if(data && Curl_trc_cf_is_verbose(cf, data)) {
+    char buffer[256];
+    int len;
+    len = fr_print(frame, buffer, sizeof(buffer)-1);
+    buffer[len] = 0;
+    CURL_TRC_CF(data, cf, "[%d] -> %s", frame->hd.stream_id, buffer);
+  }
+  return 0;
+}
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
 static int proxy_h2_on_frame_recv(nghttp2_session *session,
                                   const nghttp2_frame *frame,
                                   void *userp)
@@ -566,75 +676,74 @@ static int proxy_h2_on_frame_recv(nghttp2_session *session,
 
   (void)session;
   DEBUGASSERT(data);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  if(Curl_trc_cf_is_verbose(cf, data)) {
+    char buffer[256];
+    int len;
+    len = fr_print(frame, buffer, sizeof(buffer)-1);
+    buffer[len] = 0;
+    CURL_TRC_CF(data, cf, "[%d] <- %s",frame->hd.stream_id, buffer);
+  }
+#endif /* !CURL_DISABLE_VERBOSE_STRINGS */
+
   if(!stream_id) {
     /* stream ID zero is for connection-oriented stuff */
     DEBUGASSERT(data);
     switch(frame->hd.type) {
     case NGHTTP2_SETTINGS:
-      /* we do not do anything with this for now */
+      /* Since the initial stream window is 64K, a request might be on HOLD,
+       * due to exhaustion. The (initial) SETTINGS may announce a much larger
+       * window and *assume* that we treat this like a WINDOW_UPDATE. Some
+       * servers send an explicit WINDOW_UPDATE, but not all seem to do that.
+       * To be safe, we UNHOLD a stream in order not to stall. */
+      if((data->req.keepon & KEEP_SEND_HOLD) &&
+         (data->req.keepon & KEEP_SEND)) {
+        data->req.keepon &= ~KEEP_SEND_HOLD;
+        drain_tunnel(cf, data, &ctx->tunnel);
+        CURL_TRC_CF(data, cf, "[%d] un-holding after SETTINGS",
+                    stream_id);
+      }
       break;
     case NGHTTP2_GOAWAY:
-      infof(data, "recveived GOAWAY, error=%d, last_stream=%u",
-                  frame->goaway.error_code, frame->goaway.last_stream_id);
       ctx->goaway = TRUE;
       break;
-    case NGHTTP2_WINDOW_UPDATE:
-      DEBUGF(LOG_CF(data, cf, "recv frame WINDOW_UPDATE"));
-      break;
     default:
-      DEBUGF(LOG_CF(data, cf, "recv frame %x on 0", frame->hd.type));
+      break;
     }
     return 0;
   }
 
   if(stream_id != ctx->tunnel.stream_id) {
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] rcvd FRAME not for tunnel",
-                  stream_id));
+    CURL_TRC_CF(data, cf, "[%d] rcvd FRAME not for tunnel", stream_id);
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
 
   switch(frame->hd.type) {
-  case NGHTTP2_DATA:
-    /* If body started on this stream, then receiving DATA is illegal. */
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv frame DATA", stream_id));
-    break;
   case NGHTTP2_HEADERS:
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv frame HEADERS", stream_id));
-
     /* nghttp2 guarantees that :status is received, and we store it to
        stream->status_code. Fuzzing has proven this can still be reached
        without status code having been set. */
     if(!ctx->tunnel.resp)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     /* Only final status code signals the end of header */
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] got http status: %d",
-           stream_id, ctx->tunnel.resp->status));
+    CURL_TRC_CF(data, cf, "[%d] got http status: %d",
+                stream_id, ctx->tunnel.resp->status);
     if(!ctx->tunnel.has_final_response) {
       if(ctx->tunnel.resp->status / 100 != 1) {
         ctx->tunnel.has_final_response = TRUE;
       }
     }
     break;
-  case NGHTTP2_PUSH_PROMISE:
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv PUSH_PROMISE", stream_id));
-    return NGHTTP2_ERR_CALLBACK_FAILURE;
-  case NGHTTP2_RST_STREAM:
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv RST", stream_id));
-    ctx->tunnel.reset = TRUE;
-    break;
   case NGHTTP2_WINDOW_UPDATE:
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv WINDOW_UPDATE", stream_id));
     if((data->req.keepon & KEEP_SEND_HOLD) &&
        (data->req.keepon & KEEP_SEND)) {
       data->req.keepon &= ~KEEP_SEND_HOLD;
       Curl_expire(data, 0, EXPIRE_RUN_NOW);
-      DEBUGF(LOG_CF(data, cf, "[h2sid=%u] unpausing after win update",
-             stream_id));
+      CURL_TRC_CF(data, cf, "[%d] unpausing after win update",
+                  stream_id);
     }
     break;
   default:
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] recv frame %x",
-                  stream_id, frame->hd.type));
     break;
   }
   return 0;
@@ -658,10 +767,9 @@ static int proxy_h2_on_header(nghttp2_session *session,
   (void)session;
   DEBUGASSERT(stream_id); /* should never be a zero stream ID here */
   if(stream_id != ctx->tunnel.stream_id) {
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] header for non-tunnel stream: "
-                  "%.*s: %.*s", stream_id,
-                  (int)namelen, name,
-                  (int)valuelen, value));
+    CURL_TRC_CF(data, cf, "[%d] header for non-tunnel stream: "
+                "%.*s: %.*s", stream_id,
+                (int)namelen, name, (int)valuelen, value);
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -689,8 +797,8 @@ static int proxy_h2_on_header(nghttp2_session *session,
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     resp->prev = ctx->tunnel.resp;
     ctx->tunnel.resp = resp;
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] status: HTTP/2 %03d",
-                  stream_id, ctx->tunnel.resp->status));
+    CURL_TRC_CF(data, cf, "[%d] status: HTTP/2 %03d",
+                stream_id, ctx->tunnel.resp->status);
     return 0;
   }
 
@@ -703,10 +811,8 @@ static int proxy_h2_on_header(nghttp2_session *session,
   if(result)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] header: %.*s: %.*s",
-                stream_id,
-                (int)namelen, name,
-                (int)valuelen, value));
+  CURL_TRC_CF(data, cf, "[%d] header: %.*s: %.*s",
+              stream_id, (int)namelen, name, (int)valuelen, value);
 
   return 0; /* 0 is successful */
 }
@@ -746,8 +852,8 @@ static ssize_t tunnel_send_callback(nghttp2_session *session,
   if(ts->closed && Curl_bufq_is_empty(&ts->sendbuf))
     *data_flags = NGHTTP2_DATA_FLAG_EOF;
 
-  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] tunnel_send_callback -> %zd",
-                ts->stream_id, nread));
+  CURL_TRC_CF(data, cf, "[%d] tunnel_send_callback -> %zd",
+              ts->stream_id, nread);
   return nread;
 }
 
@@ -791,8 +897,8 @@ static int proxy_h2_on_stream_close(nghttp2_session *session,
   if(stream_id != ctx->tunnel.stream_id)
     return 0;
 
-  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] proxy_h2_on_stream_close, %s (err %d)",
-                stream_id, nghttp2_http2_strerror(error_code), error_code));
+  CURL_TRC_CF(data, cf, "[%d] proxy_h2_on_stream_close, %s (err %d)",
+              stream_id, nghttp2_http2_strerror(error_code), error_code);
   ctx->tunnel.closed = TRUE;
   ctx->tunnel.error = error_code;
 
@@ -910,8 +1016,8 @@ static CURLcode submit_CONNECT(struct Curl_cfilter *cf,
   result = proxy_h2_submit(&ts->stream_id, cf, data, ctx->h2, req,
                            NULL, ts, tunnel_send_callback, cf);
   if(result) {
-    DEBUGF(LOG_CF(data, cf, "send: nghttp2_submit_request error (%s)%u",
-                  nghttp2_strerror(ts->stream_id), ts->stream_id));
+    CURL_TRC_CF(data, cf, "[%d] send, nghttp2_submit_request error: %s",
+                ts->stream_id, nghttp2_strerror(ts->stream_id));
   }
 
 out:
@@ -945,8 +1051,8 @@ static CURLcode inspect_response(struct Curl_cfilter *cf,
   }
 
   if(auth_reply) {
-    DEBUGF(LOG_CF(data, cf, "CONNECT: fwd auth header '%s'",
-                  auth_reply->value));
+    CURL_TRC_CF(data, cf, "[0] CONNECT: fwd auth header '%s'",
+                auth_reply->value);
     result = Curl_http_input_auth(data, ts->resp->status == 407,
                                   auth_reply->value);
     if(result)
@@ -976,7 +1082,7 @@ static CURLcode H2_CONNECT(struct Curl_cfilter *cf,
     switch(ts->state) {
     case H2_TUNNEL_INIT:
       /* Prepare the CONNECT request and make a first attempt to send. */
-      DEBUGF(LOG_CF(data, cf, "CONNECT start for %s", ts->authority));
+      CURL_TRC_CF(data, cf, "[0] CONNECT start for %s", ts->authority);
       result = submit_CONNECT(cf, data, ts);
       if(result)
         goto out;
@@ -1143,8 +1249,8 @@ static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
   ssize_t rv = 0;
 
   if(ctx->tunnel.error == NGHTTP2_REFUSED_STREAM) {
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] REFUSED_STREAM, try again on a new "
-                  "connection", ctx->tunnel.stream_id));
+    CURL_TRC_CF(data, cf, "[%d] REFUSED_STREAM, try again on a new "
+                "connection", ctx->tunnel.stream_id);
     connclose(cf->conn, "REFUSED_STREAM"); /* don't use this anymore */
     *err = CURLE_RECV_ERROR; /* trigger Curl_retry_request() later */
     return -1;
@@ -1164,7 +1270,8 @@ static ssize_t h2_handle_tunnel_close(struct Curl_cfilter *cf,
 
   *err = CURLE_OK;
   rv = 0;
-  DEBUGF(LOG_CF(data, cf, "handle_tunnel_close -> %zd, %d", rv, *err));
+  CURL_TRC_CF(data, cf, "[%d] handle_tunnel_close -> %zd, %d",
+              ctx->tunnel.stream_id, rv, *err);
   return rv;
 }
 
@@ -1200,8 +1307,8 @@ static ssize_t tunnel_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   }
 
 out:
-  DEBUGF(LOG_CF(data, cf, "tunnel_recv(len=%zu) -> %zd, %d",
-                len, nread, *err));
+  CURL_TRC_CF(data, cf, "[%d] tunnel_recv(len=%zu) -> %zd, %d",
+              ctx->tunnel.stream_id, len, nread, *err);
   return nread;
 }
 
@@ -1229,13 +1336,22 @@ static ssize_t cf_h2_proxy_recv(struct Curl_cfilter *cf,
   nread = tunnel_recv(cf, data, buf, len, err);
 
   if(nread > 0) {
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%u] increase window by %zd",
-                  ctx->tunnel.stream_id, nread));
+    CURL_TRC_CF(data, cf, "[%d] increase window by %zd",
+                ctx->tunnel.stream_id, nread);
     nghttp2_session_consume(ctx->h2, ctx->tunnel.stream_id, (size_t)nread);
   }
 
   result = proxy_h2_progress_egress(cf, data);
-  if(result && result != CURLE_AGAIN) {
+  if(result == CURLE_AGAIN) {
+    /* pending data to send, need to be called again. Ideally, we'd
+     * monitor the socket for POLLOUT, but we might not be in SENDING
+     * transfer state any longer and are unable to make this happen.
+     */
+    CURL_TRC_CF(data, cf, "[%d] egress blocked, DRAIN",
+                ctx->tunnel.stream_id);
+    drain_tunnel(cf, data, &ctx->tunnel);
+  }
+  else if(result) {
     *err = result;
     nread = -1;
   }
@@ -1247,8 +1363,8 @@ out:
      * draining to avoid stalling when no socket events happen. */
     drain_tunnel(cf, data, &ctx->tunnel);
   }
-  DEBUGF(LOG_CF(data, cf, "[h2sid=%u] cf_recv(len=%zu) -> %zd %d",
-                ctx->tunnel.stream_id, len, nread, *err));
+  CURL_TRC_CF(data, cf, "[%d] cf_recv(len=%zu) -> %zd %d",
+              ctx->tunnel.stream_id, len, nread, *err);
   CF_DATA_RESTORE(cf, save);
   return nread;
 }
@@ -1276,12 +1392,12 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
     goto out;
   }
   else if(ctx->tunnel.upload_blocked_len) {
-    /* the data in `buf` has alread been submitted or added to the
+    /* the data in `buf` has already been submitted or added to the
      * buffers, but have been EAGAINed on the last invocation. */
     DEBUGASSERT(len >= ctx->tunnel.upload_blocked_len);
     if(len < ctx->tunnel.upload_blocked_len) {
       /* Did we get called again with a smaller `len`? This should not
-       * happend. We are not prepared to handle that. */
+       * happen. We are not prepared to handle that. */
       failf(data, "HTTP/2 proxy, send again with decreased length");
       *err = CURLE_HTTP2;
       nwritten = -1;
@@ -1289,6 +1405,7 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
     }
     nwritten = (ssize_t)ctx->tunnel.upload_blocked_len;
     ctx->tunnel.upload_blocked_len = 0;
+    *err = CURLE_OK;
   }
   else {
     nwritten = Curl_bufq_write(&ctx->tunnel.sendbuf, buf, len, err);
@@ -1309,6 +1426,13 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
     }
   }
 
+  result = proxy_h2_progress_ingress(cf, data);
+  if(result) {
+    *err = result;
+    nwritten = -1;
+    goto out;
+  }
+
   /* Call the nghttp2 send loop and flush to write ALL buffered data,
    * headers and/or request body completely out to the network */
   result = proxy_h2_progress_egress(cf, data);
@@ -1339,24 +1463,25 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
        * proxy connection AND to UNHOLD all of them again when the
        * window increases.
        * We *could* iterate over all data on this conn maybe? */
-      DEBUGF(LOG_CF(data, cf, "[h2sid=%d] remote flow "
-             "window is exhausted", ctx->tunnel.stream_id));
+      CURL_TRC_CF(data, cf, "[%d] remote flow "
+                  "window is exhausted", ctx->tunnel.stream_id);
     }
 
     /* Whatever the cause, we need to return CURL_EAGAIN for this call.
      * We have unwritten state that needs us being invoked again and EAGAIN
      * is the only way to ensure that. */
     ctx->tunnel.upload_blocked_len = nwritten;
-    DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) BLOCK: win %u/%zu "
-           "blocked_len=%zu",
-           ctx->tunnel.stream_id, len,
-           nghttp2_session_get_remote_window_size(ctx->h2), rwin,
-           nwritten));
+    CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) BLOCK: win %u/%zu "
+                "blocked_len=%zu",
+                ctx->tunnel.stream_id, len,
+                nghttp2_session_get_remote_window_size(ctx->h2), rwin,
+                nwritten);
+    drain_tunnel(cf, data, &ctx->tunnel);
     *err = CURLE_AGAIN;
     nwritten = -1;
     goto out;
   }
-  else if(should_close_session(ctx)) {
+  else if(proxy_h2_should_close_session(ctx)) {
     /* nghttp2 thinks this session is done. If the stream has not been
      * closed, this is an error state for out transfer */
     if(ctx->tunnel.closed) {
@@ -1364,22 +1489,27 @@ static ssize_t cf_h2_proxy_send(struct Curl_cfilter *cf,
       nwritten = -1;
     }
     else {
-      DEBUGF(LOG_CF(data, cf, "send: nothing to do in this session"));
+      CURL_TRC_CF(data, cf, "[0] send: nothing to do in this session");
       *err = CURLE_HTTP2;
       nwritten = -1;
     }
   }
 
 out:
-  DEBUGF(LOG_CF(data, cf, "[h2sid=%d] cf_send(len=%zu) -> %zd, %d, "
-                "h2 windows %d-%d (stream-conn), "
-                "buffers %zu-%zu (stream-conn)",
-                ctx->tunnel.stream_id, len, nwritten, *err,
-                nghttp2_session_get_stream_remote_window_size(
+  if(!Curl_bufq_is_empty(&ctx->tunnel.recvbuf) &&
+     (nwritten >= 0 || *err == CURLE_AGAIN)) {
+    /* data pending and no fatal error to report. Need to trigger
+     * draining to avoid stalling when no socket events happen. */
+    drain_tunnel(cf, data, &ctx->tunnel);
+  }
+  CURL_TRC_CF(data, cf, "[%d] cf_send(len=%zu) -> %zd, %d, "
+              "h2 windows %d-%d (stream-conn), buffers %zu-%zu (stream-conn)",
+              ctx->tunnel.stream_id, len, nwritten, *err,
+              nghttp2_session_get_stream_remote_window_size(
                   ctx->h2, ctx->tunnel.stream_id),
-                nghttp2_session_get_remote_window_size(ctx->h2),
-                Curl_bufq_len(&ctx->tunnel.sendbuf),
-                Curl_bufq_len(&ctx->outbufq)));
+              nghttp2_session_get_remote_window_size(ctx->h2),
+              Curl_bufq_len(&ctx->tunnel.sendbuf),
+              Curl_bufq_len(&ctx->outbufq));
   CF_DATA_RESTORE(cf, save);
   return nwritten;
 }
@@ -1409,7 +1539,7 @@ static bool proxy_h2_connisalive(struct Curl_cfilter *cf,
         /* immediate error, considered dead */
         alive = FALSE;
       else {
-        alive = !should_close_session(ctx);
+        alive = !proxy_h2_should_close_session(ctx);
       }
     }
     else if(result != CURLE_AGAIN) {
@@ -1431,8 +1561,8 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
 
   CF_DATA_SAVE(save, cf, data);
   result = (ctx && ctx->h2 && proxy_h2_connisalive(cf, data, input_pending));
-  DEBUGF(LOG_CF(data, cf, "conn alive -> %d, input_pending=%d",
-         result, *input_pending));
+  CURL_TRC_CF(data, cf, "[0] conn alive -> %d, input_pending=%d",
+              result, *input_pending);
   CF_DATA_RESTORE(cf, save);
   return result;
 }
@@ -1440,7 +1570,7 @@ static bool cf_h2_proxy_is_alive(struct Curl_cfilter *cf,
 struct Curl_cftype Curl_cft_h2_proxy = {
   "H2-PROXY",
   CF_TYPE_IP_CONNECT,
-  CURL_LOG_DEFAULT,
+  CURL_LOG_LVL_NONE,
   cf_h2_proxy_destroy,
   cf_h2_proxy_connect,
   cf_h2_proxy_close,

+ 5 - 5
lib/cf-haproxy.c

@@ -30,7 +30,7 @@
 #include "urldata.h"
 #include "cfilters.h"
 #include "cf-haproxy.h"
-#include "curl_log.h"
+#include "curl_trc.h"
 #include "multiif.h"
 
 /* The last 3 #include files should be in this order */
@@ -86,12 +86,12 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf,
   if(data->set.str[STRING_HAPROXY_CLIENT_IP])
     client_ip = data->set.str[STRING_HAPROXY_CLIENT_IP];
   else
-    client_ip = data->info.conn_primary_ip;
+    client_ip = data->info.conn_local_ip;
 
   result = Curl_dyn_addf(&ctx->data_out, "PROXY %s %s %s %i %i\r\n",
                          tcp_version,
-                         data->info.conn_local_ip,
                          client_ip,
+                         data->info.conn_primary_ip,
                          data->info.conn_local_port,
                          data->info.conn_primary_port);
 
@@ -157,14 +157,14 @@ static void cf_haproxy_destroy(struct Curl_cfilter *cf,
                                struct Curl_easy *data)
 {
   (void)data;
-  DEBUGF(LOG_CF(data, cf, "destroy"));
+  CURL_TRC_CF(data, cf, "destroy");
   cf_haproxy_ctx_free(cf->ctx);
 }
 
 static void cf_haproxy_close(struct Curl_cfilter *cf,
                              struct Curl_easy *data)
 {
-  DEBUGF(LOG_CF(data, cf, "close"));
+  CURL_TRC_CF(data, cf, "close");
   cf->connected = FALSE;
   cf_haproxy_ctx_reset(cf->ctx);
   if(cf->next)

+ 19 - 19
lib/cf-https-connect.c

@@ -28,7 +28,7 @@
 
 #include "urldata.h"
 #include <curl/curl.h>
-#include "curl_log.h"
+#include "curl_trc.h"
 #include "cfilters.h"
 #include "connect.h"
 #include "multiif.h"
@@ -165,9 +165,9 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
   if(winner != &ctx->h21_baller)
     cf_hc_baller_reset(&ctx->h21_baller, data);
 
-  DEBUGF(LOG_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
-                winner->name, (int)Curl_timediff(Curl_now(), winner->started),
-                cf_hc_baller_reply_ms(winner, data)));
+  CURL_TRC_CF(data, cf, "connect+handshake %s: %dms, 1st data: %dms",
+              winner->name, (int)Curl_timediff(Curl_now(), winner->started),
+              cf_hc_baller_reply_ms(winner, data));
   cf->next = winner->cf;
   winner->cf = NULL;
 
@@ -218,16 +218,16 @@ static bool time_to_start_h21(struct Curl_cfilter *cf,
 
   elapsed_ms = Curl_timediff(now, ctx->started);
   if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
-    DEBUGF(LOG_CF(data, cf, "hard timeout of %dms reached, starting h21",
-                  ctx->hard_eyeballs_timeout_ms));
+    CURL_TRC_CF(data, cf, "hard timeout of %dms reached, starting h21",
+                ctx->hard_eyeballs_timeout_ms);
     return TRUE;
   }
 
   if(elapsed_ms >= ctx->soft_eyeballs_timeout_ms) {
     if(cf_hc_baller_reply_ms(&ctx->h3_baller, data) < 0) {
-      DEBUGF(LOG_CF(data, cf, "soft timeout of %dms reached, h3 has not "
-                    "seen any data, starting h21",
-                    ctx->soft_eyeballs_timeout_ms));
+      CURL_TRC_CF(data, cf, "soft timeout of %dms reached, h3 has not "
+                  "seen any data, starting h21",
+                  ctx->soft_eyeballs_timeout_ms);
       return TRUE;
     }
     /* set the effective hard timeout again */
@@ -258,7 +258,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
     DEBUGASSERT(!ctx->h3_baller.cf);
     DEBUGASSERT(!ctx->h21_baller.cf);
     DEBUGASSERT(!cf->next);
-    DEBUGF(LOG_CF(data, cf, "connect, init"));
+    CURL_TRC_CF(data, cf, "connect, init");
     ctx->started = now;
     if(ctx->h3_baller.enabled) {
       cf_hc_baller_init(&ctx->h3_baller, cf, data, "h3", TRNSPRT_QUIC);
@@ -286,7 +286,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
     }
 
     if(cf_hc_baller_is_active(&ctx->h21_baller)) {
-      DEBUGF(LOG_CF(data, cf, "connect, check h21"));
+      CURL_TRC_CF(data, cf, "connect, check h21");
       result = cf_hc_baller_connect(&ctx->h21_baller, cf, data, done);
       if(!result && *done) {
         result = baller_connected(cf, data, &ctx->h21_baller);
@@ -297,7 +297,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
     if((!ctx->h3_baller.enabled || ctx->h3_baller.result) &&
        (!ctx->h21_baller.enabled || ctx->h21_baller.result)) {
       /* both failed or disabled. we give up */
-      DEBUGF(LOG_CF(data, cf, "connect, all failed"));
+      CURL_TRC_CF(data, cf, "connect, all failed");
       result = ctx->result = ctx->h3_baller.enabled?
                               ctx->h3_baller.result : ctx->h21_baller.result;
       ctx->state = CF_HC_FAILURE;
@@ -321,7 +321,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
   }
 
 out:
-  DEBUGF(LOG_CF(data, cf, "connect -> %d, done=%d", result, *done));
+  CURL_TRC_CF(data, cf, "connect -> %d, done=%d", result, *done);
   return result;
 }
 
@@ -345,7 +345,7 @@ static int cf_hc_get_select_socks(struct Curl_cfilter *cf,
     if(!cf_hc_baller_is_active(b))
       continue;
     brc = Curl_conn_cf_get_select_socks(b->cf, data, bsocks);
-    DEBUGF(LOG_CF(data, cf, "get_selected_socks(%s) -> %x", b->name, brc));
+    CURL_TRC_CF(data, cf, "get_selected_socks(%s) -> %x", b->name, brc);
     if(!brc)
       continue;
     for(j = 0; j < MAX_SOCKSPEREASYHANDLE && s < MAX_SOCKSPEREASYHANDLE; ++j) {
@@ -359,7 +359,7 @@ static int cf_hc_get_select_socks(struct Curl_cfilter *cf,
       }
     }
   }
-  DEBUGF(LOG_CF(data, cf, "get_selected_socks -> %x", rc));
+  CURL_TRC_CF(data, cf, "get_selected_socks -> %x", rc);
   return rc;
 }
 
@@ -371,7 +371,7 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
   if(cf->connected)
     return cf->next->cft->has_data_pending(cf->next, data);
 
-  DEBUGF(LOG_CF((struct Curl_easy *)data, cf, "data_pending"));
+  CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
   return cf_hc_baller_data_pending(&ctx->h3_baller, data)
          || cf_hc_baller_data_pending(&ctx->h21_baller, data);
 }
@@ -427,7 +427,7 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
 
 static void cf_hc_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
-  DEBUGF(LOG_CF(data, cf, "close"));
+  CURL_TRC_CF(data, cf, "close");
   cf_hc_reset(cf, data);
   cf->connected = FALSE;
 
@@ -442,7 +442,7 @@ static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
   struct cf_hc_ctx *ctx = cf->ctx;
 
   (void)data;
-  DEBUGF(LOG_CF(data, cf, "destroy"));
+  CURL_TRC_CF(data, cf, "destroy");
   cf_hc_reset(cf, data);
   Curl_safefree(ctx);
 }
@@ -450,7 +450,7 @@ static void cf_hc_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
 struct Curl_cftype Curl_cft_http_connect = {
   "HTTPS-CONNECT",
   0,
-  CURL_LOG_DEFAULT,
+  CURL_LOG_LVL_NONE,
   cf_hc_destroy,
   cf_hc_connect,
   cf_hc_close,

+ 126 - 75
lib/cf-socket.c

@@ -71,6 +71,7 @@
 #include "warnless.h"
 #include "conncache.h"
 #include "multihandle.h"
+#include "rand.h"
 #include "share.h"
 #include "version_win32.h"
 
@@ -390,6 +391,7 @@ void Curl_sndbufset(curl_socket_t sockfd)
 }
 #endif
 
+#ifndef CURL_DISABLE_BINDLOCAL
 static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
                           curl_socket_t sockfd, int af, unsigned int scope)
 {
@@ -444,29 +446,24 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
     /* interface */
     if(!is_host) {
 #ifdef SO_BINDTODEVICE
-      /* I am not sure any other OSs than Linux that provide this feature,
-       * and at the least I cannot test. --Ben
-       *
-       * This feature allows one to tightly bind the local socket to a
-       * particular interface.  This will force even requests to other
-       * local interfaces to go out the external interface.
-       *
-       *
-       * Only bind to the interface when specified as interface, not just
-       * as a hostname or ip address.
+      /*
+       * This binds the local socket to a particular interface. This will
+       * force even requests to other local interfaces to go out the external
+       * interface. Only bind to the interface when specified as interface,
+       * not just as a hostname or ip address.
        *
-       * interface might be a VRF, eg: vrf-blue, which means it cannot be
-       * converted to an IP address and would fail Curl_if2ip. Simply try
-       * to use it straight away.
+       * The interface might be a VRF, eg: vrf-blue, which means it cannot be
+       * converted to an IP address and would fail Curl_if2ip. Simply try to
+       * use it straight away.
        */
       if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
                     dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
-        /* This is typically "errno 1, error: Operation not permitted" if
-         * you're not running as root or another suitable privileged
-         * user.
-         * If it succeeds it means the parameter was a valid interface and
-         * not an IP address. Return immediately.
+        /* This is often "errno 1, error: Operation not permitted" if you're
+         * not running as root or another suitable privileged user. If it
+         * succeeds it means the parameter was a valid interface and not an IP
+         * address. Return immediately.
          */
+        infof(data, "socket successfully bound to interface '%s'", dev);
         return CURLE_OK;
       }
 #endif
@@ -632,8 +629,8 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
       port++; /* try next port */
       if(port == 0)
         break;
-      infof(data, "Bind to local port %hu failed, trying next", port - 1);
-      /* We re-use/clobber the port variable here below */
+      infof(data, "Bind to local port %d failed, trying next", port - 1);
+      /* We reuse/clobber the port variable here below */
       if(sock->sa_family == AF_INET)
         si4->sin_port = ntohs(port);
 #ifdef ENABLE_IPV6
@@ -653,6 +650,7 @@ static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
 
   return CURLE_INTERFACE_FAILED;
 }
+#endif
 
 /*
  * verifyconnect() returns TRUE if the connect really has happened.
@@ -727,8 +725,6 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
 static CURLcode socket_connect_result(struct Curl_easy *data,
                                       const char *ipaddress, int error)
 {
-  char buffer[STRERROR_LEN];
-
   switch(error) {
   case EINPROGRESS:
   case EWOULDBLOCK:
@@ -745,8 +741,15 @@ static CURLcode socket_connect_result(struct Curl_easy *data,
 
   default:
     /* unknown error, fallthrough and try another address! */
-    infof(data, "Immediate connect fail for %s: %s",
-          ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+    (void)ipaddress;
+#else
+    {
+      char buffer[STRERROR_LEN];
+      infof(data, "Immediate connect fail for %s: %s",
+            ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
+    }
+#endif
     data->state.os_errno = error;
     /* connect failed */
     return CURLE_COULDNT_CONNECT;
@@ -775,6 +778,10 @@ struct cf_socket_ctx {
   struct curltime connected_at;      /* when socket connected/got first byte */
   struct curltime first_byte_at;     /* when first byte was recvd */
   int error;                         /* errno of last failure or 0 */
+#ifdef DEBUGBUILD
+  int wblock_percent;                /* percent of writes doing EAGAIN */
+  int wpartial_percent;              /* percent of bytes written in send */
+#endif
   BIT(got_first_byte);               /* if first byte was received */
   BIT(accepted);                     /* socket was accepted, not connected */
   BIT(active);
@@ -790,6 +797,22 @@ static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
   ctx->transport = transport;
   Curl_sock_assign_addr(&ctx->addr, ai, transport);
   Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
+#ifdef DEBUGBUILD
+  {
+    char *p = getenv("CURL_DBG_SOCK_WBLOCK");
+    if(p) {
+      long l = strtol(p, NULL, 10);
+      if(l >= 0 && l <= 100)
+        ctx->wblock_percent = (int)l;
+    }
+    p = getenv("CURL_DBG_SOCK_WPARTIAL");
+    if(p) {
+      long l = strtol(p, NULL, 10);
+      if(l >= 0 && l <= 100)
+        ctx->wpartial_percent = (int)l;
+    }
+  }
+#endif
 }
 
 struct reader_ctx {
@@ -836,8 +859,8 @@ static ssize_t nw_in_read(void *reader_ctx,
       nread = -1;
     }
   }
-  DEBUGF(LOG_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu) -> %d, err=%d",
-               len, (int)nread, *err));
+  CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu) -> %d, err=%d",
+              len, (int)nread, *err);
   return nread;
 }
 
@@ -852,14 +875,14 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
        * closed it) and we just forget about it.
        */
       if(ctx->sock == cf->conn->sock[cf->sockindex]) {
-        DEBUGF(LOG_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
-                      ", active)", ctx->sock));
+        CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
+                    ", active)", ctx->sock);
         socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
         cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
       }
       else {
-        DEBUGF(LOG_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
-                      ") no longer at conn->sock[], discarding", ctx->sock));
+        CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
+                    ") no longer at conn->sock[], discarding", ctx->sock);
         /* TODO: we do not want this to happen. Need to check which
          * code is messing with conn->sock[cf->sockindex] */
       }
@@ -869,8 +892,8 @@ static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
     }
     else {
       /* this is our local socket, we did never publish it */
-      DEBUGF(LOG_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
-                    ", not active)", ctx->sock));
+      CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
+                  ", not active)", ctx->sock);
       socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
       ctx->sock = CURL_SOCKET_BAD;
     }
@@ -889,7 +912,7 @@ static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
   struct cf_socket_ctx *ctx = cf->ctx;
 
   cf_socket_close(cf, data);
-  DEBUGF(LOG_CF(data, cf, "destroy"));
+  CURL_TRC_CF(data, cf, "destroy");
   Curl_bufq_free(&ctx->recvbuf);
   free(ctx);
   cf->ctx = NULL;
@@ -957,7 +980,6 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
   bool isconnected = FALSE;
   CURLcode result = CURLE_COULDNT_CONNECT;
   bool is_tcp;
-  const char *ipmsg;
 
   (void)data;
   DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
@@ -970,15 +992,20 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
   if(result)
     goto out;
 
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  {
+    const char *ipmsg;
 #ifdef ENABLE_IPV6
-  if(ctx->addr.family == AF_INET6) {
-    set_ipv6_v6only(ctx->sock, 0);
-    ipmsg = "  Trying [%s]:%d...";
+    if(ctx->addr.family == AF_INET6) {
+      set_ipv6_v6only(ctx->sock, 0);
+      ipmsg = "  Trying [%s]:%d...";
+    }
+    else
+#endif
+      ipmsg = "  Trying %s:%d...";
+    infof(data, ipmsg, ctx->r_ip, ctx->r_port);
   }
-  else
 #endif
-    ipmsg = "  Trying %s:%d...";
-  infof(data, ipmsg, ctx->r_ip, ctx->r_port);
 
 #ifdef ENABLE_IPV6
   is_tcp = (ctx->addr.family == AF_INET
@@ -1014,6 +1041,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
     }
   }
 
+#ifndef CURL_DISABLE_BINDLOCAL
   /* possibly bind the local end to an IP, interface or port */
   if(ctx->addr.family == AF_INET
 #ifdef ENABLE_IPV6
@@ -1031,6 +1059,7 @@ static CURLcode cf_socket_open(struct Curl_cfilter *cf,
       goto out;
     }
   }
+#endif
 
   /* set socket non-blocking */
   (void)curlx_nonblock(ctx->sock, TRUE);
@@ -1047,8 +1076,8 @@ out:
     ctx->connected_at = Curl_now();
     cf->connected = TRUE;
   }
-  DEBUGF(LOG_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
-                result, ctx->sock));
+  CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
+              result, ctx->sock);
   return result;
 }
 
@@ -1155,7 +1184,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
   rc = SOCKET_WRITABLE(ctx->sock, 0);
 
   if(rc == 0) { /* no connection yet */
-    DEBUGF(LOG_CF(data, cf, "not connected yet"));
+    CURL_TRC_CF(data, cf, "not connected yet");
     return CURLE_OK;
   }
   else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
@@ -1165,7 +1194,7 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
       set_local_ip(cf, data);
       *done = TRUE;
       cf->connected = TRUE;
-      DEBUGF(LOG_CF(data, cf, "connected"));
+      CURL_TRC_CF(data, cf, "connected");
       return CURLE_OK;
     }
   }
@@ -1245,11 +1274,34 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
   struct cf_socket_ctx *ctx = cf->ctx;
   curl_socket_t fdsave;
   ssize_t nwritten;
+  size_t orig_len = len;
 
   *err = CURLE_OK;
   fdsave = cf->conn->sock[cf->sockindex];
   cf->conn->sock[cf->sockindex] = ctx->sock;
 
+#ifdef DEBUGBUILD
+  /* simulate network blocking/partial writes */
+  if(ctx->wblock_percent > 0) {
+    unsigned char c;
+    Curl_rand(data, &c, 1);
+    if(c >= ((100-ctx->wblock_percent)*256/100)) {
+      CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
+      *err = CURLE_AGAIN;
+      nwritten = -1;
+      cf->conn->sock[cf->sockindex] = fdsave;
+      return nwritten;
+    }
+  }
+  if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
+    len = len * ctx->wpartial_percent / 100;
+    if(!len)
+      len = 1;
+    CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
+                orig_len, len);
+  }
+#endif
+
 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
   if(cf->conn->bits.tcp_fastopen) {
     nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
@@ -1288,8 +1340,8 @@ static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
     }
   }
 
-  DEBUGF(LOG_CF(data, cf, "send(len=%zu) -> %d, err=%d",
-                len, (int)nwritten, *err));
+  CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
+              orig_len, (int)nwritten, *err);
   cf->conn->sock[cf->sockindex] = fdsave;
   return nwritten;
 }
@@ -1307,7 +1359,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   cf->conn->sock[cf->sockindex] = ctx->sock;
 
   if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
-    DEBUGF(LOG_CF(data, cf, "recv from buffer"));
+    CURL_TRC_CF(data, cf, "recv from buffer");
     nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
   }
   else {
@@ -1324,7 +1376,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
       if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
         /* we have a partial read with an error. need to deliver
          * what we got, return the error later. */
-        DEBUGF(LOG_CF(data, cf, "partial read: empty buffer first"));
+        CURL_TRC_CF(data, cf, "partial read: empty buffer first");
         nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
       }
       else if(nwritten < 0) {
@@ -1337,7 +1389,7 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
         nread = 0;
       }
       else {
-        DEBUGF(LOG_CF(data, cf, "buffered %zd additional bytes", nwritten));
+        CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
         nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
       }
     }
@@ -1347,8 +1399,8 @@ static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   }
 
 out:
-  DEBUGF(LOG_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
-                *err));
+  CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
+              *err);
   if(nread > 0 && !ctx->got_first_byte) {
     ctx->first_byte_at = Curl_now();
     ctx->got_first_byte = TRUE;
@@ -1455,19 +1507,19 @@ static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
 
   r = Curl_poll(pfd, 1, 0);
   if(r < 0) {
-    DEBUGF(LOG_CF(data, cf, "is_alive: poll error, assume dead"));
+    CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
     return FALSE;
   }
   else if(r == 0) {
-    DEBUGF(LOG_CF(data, cf, "is_alive: poll timeout, assume alive"));
+    CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
     return TRUE;
   }
   else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
-    DEBUGF(LOG_CF(data, cf, "is_alive: err/hup/etc events, assume dead"));
+    CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
     return FALSE;
   }
 
-  DEBUGF(LOG_CF(data, cf, "is_alive: valid events, looks alive"));
+  CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
   *input_pending = TRUE;
   return TRUE;
 }
@@ -1520,7 +1572,7 @@ static CURLcode cf_socket_query(struct Curl_cfilter *cf,
 struct Curl_cftype Curl_cft_tcp = {
   "TCP",
   CF_TYPE_IP_CONNECT,
-  CURL_LOG_DEFAULT,
+  CURL_LOG_LVL_NONE,
   cf_socket_destroy,
   cf_tcp_connect,
   cf_socket_close,
@@ -1581,10 +1633,10 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
     return socket_connect_result(data, ctx->r_ip, SOCKERRNO);
   }
   set_local_ip(cf, data);
-  DEBUGF(LOG_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
-                " connected: [%s:%d] -> [%s:%d]",
-                (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
-                ctx->sock, ctx->l_ip, ctx->l_port, ctx->r_ip, ctx->r_port));
+  CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
+              " connected: [%s:%d] -> [%s:%d]",
+              (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
+              ctx->sock, ctx->l_ip, ctx->l_port, ctx->r_ip, ctx->r_port);
 
   (void)curlx_nonblock(ctx->sock, TRUE);
   switch(ctx->addr.family) {
@@ -1624,7 +1676,7 @@ static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
   if(ctx->sock == CURL_SOCKET_BAD) {
     result = cf_socket_open(cf, data);
     if(result) {
-      DEBUGF(LOG_CF(data, cf, "cf_udp_connect(), open failed -> %d", result));
+      CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
       goto out;
     }
 
@@ -1632,13 +1684,13 @@ static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
       result = cf_udp_setup_quic(cf, data);
       if(result)
         goto out;
-      DEBUGF(LOG_CF(data, cf, "cf_udp_connect(), opened socket=%"
-                    CURL_FORMAT_SOCKET_T " (%s:%d)",
-                    ctx->sock, ctx->l_ip, ctx->l_port));
+      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
+                  CURL_FORMAT_SOCKET_T " (%s:%d)",
+                  ctx->sock, ctx->l_ip, ctx->l_port);
     }
     else {
-      DEBUGF(LOG_CF(data, cf, "cf_udp_connect(), opened socket=%"
-                    CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock));
+      CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
+                  CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock);
     }
     *done = TRUE;
     cf->connected = TRUE;
@@ -1650,7 +1702,7 @@ out:
 struct Curl_cftype Curl_cft_udp = {
   "UDP",
   CF_TYPE_IP_CONNECT,
-  CURL_LOG_DEFAULT,
+  CURL_LOG_LVL_NONE,
   cf_socket_destroy,
   cf_udp_connect,
   cf_socket_close,
@@ -1701,7 +1753,7 @@ out:
 struct Curl_cftype Curl_cft_unix = {
   "UNIX",
   CF_TYPE_IP_CONNECT,
-  CURL_LOG_DEFAULT,
+  CURL_LOG_LVL_NONE,
   cf_socket_destroy,
   cf_tcp_connect,
   cf_socket_close,
@@ -1765,7 +1817,7 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
 struct Curl_cftype Curl_cft_tcp_accept = {
   "TCP-ACCEPT",
   CF_TYPE_IP_CONNECT,
-  CURL_LOG_DEFAULT,
+  CURL_LOG_LVL_NONE,
   cf_socket_destroy,
   cf_tcp_accept_connect,
   cf_socket_close,
@@ -1810,8 +1862,8 @@ CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
   ctx->active = TRUE;
   ctx->connected_at = Curl_now();
   cf->connected = TRUE;
-  DEBUGF(LOG_CF(data, cf, "Curl_conn_tcp_listen_set(%"
-                CURL_FORMAT_SOCKET_T ")", ctx->sock));
+  CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%"
+              CURL_FORMAT_SOCKET_T ")", ctx->sock);
 
 out:
   if(result) {
@@ -1875,9 +1927,9 @@ CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
   ctx->accepted = TRUE;
   ctx->connected_at = Curl_now();
   cf->connected = TRUE;
-  DEBUGF(LOG_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
-                ", remote=%s port=%d)",
-                ctx->sock, ctx->r_ip, ctx->r_port));
+  CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
+              ", remote=%s port=%d)",
+              ctx->sock, ctx->r_ip, ctx->r_port);
 
   return CURLE_OK;
 }
@@ -1922,4 +1974,3 @@ CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
   }
   return CURLE_FAILED_INIT;
 }
-

+ 1 - 2
lib/cfilters.c

@@ -238,7 +238,7 @@ void Curl_conn_cf_add(struct Curl_easy *data,
   cf->conn = conn;
   cf->sockindex = index;
   conn->cfilter[index] = cf;
-  DEBUGF(LOG_CF(data, cf, "added"));
+  CURL_TRC_CF(data, cf, "added");
 }
 
 void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
@@ -646,4 +646,3 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
                               &n, NULL) : CURLE_UNKNOWN_OPTION;
   return (result || n <= 0)? 1 : (size_t)n;
 }
-

+ 35 - 31
lib/connect.c

@@ -381,6 +381,11 @@ struct cf_he_ctx {
   struct curltime started;
 };
 
+/* when there are more than one IP address left to use, this macro returns how
+   much of the given timeout to spend on *this* attempt */
+#define TIMEOUT_LARGE 600
+#define USETIME(ms) ((ms > TIMEOUT_LARGE) ? (ms / 2) : ms)
+
 static CURLcode eyeballer_new(struct eyeballer **pballer,
                               cf_ip_connect_create *cf_create,
                               const struct Curl_addrinfo *addr,
@@ -408,7 +413,7 @@ static CURLcode eyeballer_new(struct eyeballer **pballer,
   baller->primary = primary;
   baller->delay_ms = delay_ms;
   baller->timeoutms = addr_next_match(baller->addr, baller->ai_family)?
-                        timeout_ms / 2 : timeout_ms;
+    USETIME(timeout_ms) : timeout_ms;
   baller->timeout_id = timeout_id;
   baller->result = CURLE_COULDNT_CONNECT;
 
@@ -475,7 +480,7 @@ static void baller_initiate(struct Curl_cfilter *cf,
 
 out:
   if(result) {
-    DEBUGF(LOG_CF(data, cf, "%s failed", baller->name));
+    CURL_TRC_CF(data, cf, "%s failed", baller->name);
     baller_close(baller, data);
   }
   if(cf_prev)
@@ -501,7 +506,7 @@ static CURLcode baller_start(struct Curl_cfilter *cf,
   while(baller->addr) {
     baller->started = Curl_now();
     baller->timeoutms = addr_next_match(baller->addr, baller->ai_family) ?
-                         timeoutms / 2 : timeoutms;
+      USETIME(timeoutms) : timeoutms;
     baller_initiate(cf, data, baller);
     if(!baller->result)
       break;
@@ -601,8 +606,8 @@ evaluate:
       continue;
     }
     baller->result = baller_connect(cf, data, baller, &now, connected);
-    DEBUGF(LOG_CF(data, cf, "%s connect -> %d, connected=%d",
-                  baller->name, baller->result, *connected));
+    CURL_TRC_CF(data, cf, "%s connect -> %d, connected=%d",
+                baller->name, baller->result, *connected);
 
     if(!baller->result) {
       if(*connected) {
@@ -623,11 +628,11 @@ evaluate:
       }
       baller_start_next(cf, data, baller, Curl_timeleft(data, &now, TRUE));
       if(baller->is_done) {
-        DEBUGF(LOG_CF(data, cf, "%s done", baller->name));
+        CURL_TRC_CF(data, cf, "%s done", baller->name);
       }
       else {
         /* next attempt was started */
-        DEBUGF(LOG_CF(data, cf, "%s trying next", baller->name));
+        CURL_TRC_CF(data, cf, "%s trying next", baller->name);
         ++ongoing;
       }
     }
@@ -661,12 +666,12 @@ evaluate:
           Curl_timediff(now, ctx->started) >= baller->delay_ms) {
         baller_start(cf, data, baller, Curl_timeleft(data, &now, TRUE));
         if(baller->is_done) {
-          DEBUGF(LOG_CF(data, cf, "%s done", baller->name));
+          CURL_TRC_CF(data, cf, "%s done", baller->name);
         }
         else {
-          DEBUGF(LOG_CF(data, cf, "%s starting (timeout=%"
-                        CURL_FORMAT_TIMEDIFF_T "ms)",
-                        baller->name, baller->timeoutms));
+          CURL_TRC_CF(data, cf, "%s starting (timeout=%"
+                      CURL_FORMAT_TIMEDIFF_T "ms)",
+                      baller->name, baller->timeoutms);
           ++ongoing;
           ++added;
         }
@@ -683,14 +688,14 @@ evaluate:
   }
 
   /* all ballers have failed to connect. */
-  DEBUGF(LOG_CF(data, cf, "all eyeballers failed"));
+  CURL_TRC_CF(data, cf, "all eyeballers failed");
   result = CURLE_COULDNT_CONNECT;
   for(i = 0; i < sizeof(ctx->baller)/sizeof(ctx->baller[0]); i++) {
     struct eyeballer *baller = ctx->baller[i];
-    DEBUGF(LOG_CF(data, cf, "%s assess started=%d, result=%d",
-                  baller?baller->name:NULL,
-                  baller?baller->has_started:0,
-                  baller?baller->result:0));
+    CURL_TRC_CF(data, cf, "%s assess started=%d, result=%d",
+                baller?baller->name:NULL,
+                baller?baller->has_started:0,
+                baller?baller->result:0);
     if(baller && baller->has_started && baller->result) {
       result = baller->result;
       break;
@@ -803,9 +808,9 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
                           timeout_ms,  EXPIRE_DNS_PER_NAME);
   if(result)
     return result;
-  DEBUGF(LOG_CF(data, cf, "created %s (timeout %"
-                CURL_FORMAT_TIMEDIFF_T "ms)",
-                ctx->baller[0]->name, ctx->baller[0]->timeoutms));
+  CURL_TRC_CF(data, cf, "created %s (timeout %"
+              CURL_FORMAT_TIMEDIFF_T "ms)",
+              ctx->baller[0]->name, ctx->baller[0]->timeoutms);
   if(addr1) {
     /* second one gets a delayed start */
     result = eyeballer_new(&ctx->baller[1], ctx->cf_create, addr1, ai_family1,
@@ -815,9 +820,9 @@ static CURLcode start_connect(struct Curl_cfilter *cf,
                             timeout_ms,  EXPIRE_DNS_PER_NAME2);
     if(result)
       return result;
-    DEBUGF(LOG_CF(data, cf, "created %s (timeout %"
-                  CURL_FORMAT_TIMEDIFF_T "ms)",
-                  ctx->baller[1]->name, ctx->baller[1]->timeoutms));
+    CURL_TRC_CF(data, cf, "created %s (timeout %"
+                CURL_FORMAT_TIMEDIFF_T "ms)",
+                ctx->baller[1]->name, ctx->baller[1]->timeoutms);
   }
 
   Curl_expire(data, data->set.happy_eyeballs_timeout,
@@ -931,7 +936,7 @@ static void cf_he_close(struct Curl_cfilter *cf,
 {
   struct cf_he_ctx *ctx = cf->ctx;
 
-  DEBUGF(LOG_CF(data, cf, "close"));
+  CURL_TRC_CF(data, cf, "close");
   cf_he_ctx_clear(cf, data);
   cf->connected = FALSE;
   ctx->state = SCFST_INIT;
@@ -1007,7 +1012,7 @@ static CURLcode cf_he_query(struct Curl_cfilter *cf,
         }
       }
       *pres1 = reply_ms;
-      DEBUGF(LOG_CF(data, cf, "query connect reply: %dms", *pres1));
+      CURL_TRC_CF(data, cf, "query connect reply: %dms", *pres1);
       return CURLE_OK;
     }
     case CF_QUERY_TIMER_CONNECT: {
@@ -1034,7 +1039,7 @@ static void cf_he_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   struct cf_he_ctx *ctx = cf->ctx;
 
-  DEBUGF(LOG_CF(data, cf, "destroy"));
+  CURL_TRC_CF(data, cf, "destroy");
   if(ctx) {
     cf_he_ctx_clear(cf, data);
   }
@@ -1045,7 +1050,7 @@ static void cf_he_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
 struct Curl_cftype Curl_cft_happy_eyeballs = {
   "HAPPY-EYEBALLS",
   0,
-  CURL_LOG_DEFAULT,
+  CURL_LOG_LVL_NONE,
   cf_he_destroy,
   cf_he_connect,
   cf_he_close,
@@ -1148,7 +1153,7 @@ static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at,
   DEBUGASSERT(cf_at);
   cf_create = get_cf_create(transport);
   if(!cf_create) {
-    DEBUGF(LOG_CF(data, cf_at, "unsupported transport type %d", transport));
+    CURL_TRC_CF(data, cf_at, "unsupported transport type %d", transport);
     return CURLE_UNSUPPORTED_PROTOCOL;
   }
   result = cf_happy_eyeballs_create(&cf, data, cf_at->conn,
@@ -1286,7 +1291,7 @@ static void cf_setup_close(struct Curl_cfilter *cf,
 {
   struct cf_setup_ctx *ctx = cf->ctx;
 
-  DEBUGF(LOG_CF(data, cf, "close"));
+  CURL_TRC_CF(data, cf, "close");
   cf->connected = FALSE;
   ctx->state = CF_SETUP_INIT;
 
@@ -1301,7 +1306,7 @@ static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
   struct cf_setup_ctx *ctx = cf->ctx;
 
   (void)data;
-  DEBUGF(LOG_CF(data, cf, "destroy"));
+  CURL_TRC_CF(data, cf, "destroy");
   Curl_safefree(ctx);
 }
 
@@ -1309,7 +1314,7 @@ static void cf_setup_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
 struct Curl_cftype Curl_cft_setup = {
   "SETUP",
   0,
-  CURL_LOG_DEFAULT,
+  CURL_LOG_LVL_NONE,
   cf_setup_destroy,
   cf_setup_connect,
   cf_setup_close,
@@ -1441,4 +1446,3 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
 out:
   return result;
 }
-

+ 8 - 1
lib/curl_base64.h

@@ -24,11 +24,18 @@
  *
  ***************************************************************************/
 
+#ifndef BUILDING_LIBCURL
+/* this renames functions so that the tool code can use the same code
+   without getting symbol collisions */
+#define Curl_base64_encode(a,b,c,d) curlx_base64_encode(a,b,c,d)
+#define Curl_base64url_encode(a,b,c,d) curlx_base64url_encode(a,b,c,d)
+#define Curl_base64_decode(a,b,c) curlx_base64_decode(a,b,c)
+#endif
+
 CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
                             char **outptr, size_t *outlen);
 CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
                                char **outptr, size_t *outlen);
 CURLcode Curl_base64_decode(const char *src,
                             unsigned char **outptr, size_t *outlen);
-
 #endif /* HEADER_CURL_BASE64_H */

+ 28 - 19
lib/curl_config.h.cmake

@@ -32,14 +32,32 @@
 /* Location of default ca path */
 #cmakedefine CURL_CA_PATH "${CURL_CA_PATH}"
 
+/* Default SSL backend */
+#cmakedefine CURL_DEFAULT_SSL_BACKEND "${CURL_DEFAULT_SSL_BACKEND}"
+
 /* disables alt-svc */
 #cmakedefine CURL_DISABLE_ALTSVC 1
 
 /* disables cookies support */
 #cmakedefine CURL_DISABLE_COOKIES 1
 
-/* disables cryptographic authentication */
-#cmakedefine CURL_DISABLE_CRYPTO_AUTH 1
+/* disables Basic authentication */
+#cmakedefine CURL_DISABLE_BASIC_AUTH 1
+
+/* disables Bearer authentication */
+#cmakedefine CURL_DISABLE_BEARER_AUTH 1
+
+/* disables Digest authentication */
+#cmakedefine CURL_DISABLE_DIGEST_AUTH 1
+
+/* disables Kerberos authentication */
+#cmakedefine CURL_DISABLE_KERBEROS_AUTH 1
+
+/* disables negotiate authentication */
+#cmakedefine CURL_DISABLE_NEGOTIATE_AUTH 1
+
+/* disables AWS-SIG4 */
+#cmakedefine CURL_DISABLE_AWS 1
 
 /* disables DICT */
 #cmakedefine CURL_DISABLE_DICT 1
@@ -50,6 +68,9 @@
 /* disables FILE */
 #cmakedefine CURL_DISABLE_FILE 1
 
+/* disables form api */
+#cmakedefine CURL_DISABLE_FORM_API 1
+
 /* disables FTP */
 #cmakedefine CURL_DISABLE_FTP 1
 
@@ -132,12 +153,6 @@
 /* Use Windows LDAP implementation */
 #cmakedefine USE_WIN32_LDAP 1
 
-/* when not building a shared library */
-#cmakedefine CURL_STATICLIB 1
-
-/* your Entropy Gathering Daemon socket pathname */
-#cmakedefine EGD_SOCKET ${EGD_SOCKET}
-
 /* Define if you want to enable IPv6 support */
 #cmakedefine ENABLE_IPV6 1
 
@@ -397,8 +412,8 @@
 /* Define to 1 if you have the <pwd.h> header file. */
 #cmakedefine HAVE_PWD_H 1
 
-/* Define to 1 if you have the `RAND_egd' function. */
-#cmakedefine HAVE_RAND_EGD 1
+/* Define to 1 if OpenSSL has the `SSL_set0_wbio` function. */
+#cmakedefine HAVE_SSL_SET0_WBIO 1
 
 /* Define to 1 if you have the recv function. */
 #cmakedefine HAVE_RECV 1
@@ -460,9 +475,6 @@
 /* Define to 1 if you have the socketpair function. */
 #cmakedefine HAVE_SOCKETPAIR 1
 
-/* Define to 1 if you have the <ssl.h> header file. */
-#cmakedefine HAVE_SSL_H 1
-
 /* Define to 1 if you have the <stdatomic.h> header file. */
 #cmakedefine HAVE_STDATOMIC_H 1
 
@@ -637,6 +649,9 @@ ${SIZEOF_INT_CODE}
 /* The size of `long', as computed by sizeof. */
 ${SIZEOF_LONG_CODE}
 
+/* The size of `long long', as computed by sizeof. */
+${SIZEOF_LONG_LONG_CODE}
+
 /* The size of `off_t', as computed by sizeof. */
 ${SIZEOF_OFF_T_CODE}
 
@@ -691,12 +706,6 @@ ${SIZEOF_TIME_T_CODE}
 /* If you want to build curl with the built-in manual */
 #cmakedefine USE_MANUAL 1
 
-/* if NSS is enabled */
-#cmakedefine USE_NSS 1
-
-/* if you have the PK11_CreateManagedGenericObject function */
-#cmakedefine HAVE_PK11_CREATEMANAGEDGENERICOBJECT 1
-
 /* if you want to use OpenLDAP code instead of legacy ldap implementation */
 #cmakedefine USE_OPENLDAP 1
 

+ 5 - 6
lib/curl_des.c

@@ -24,12 +24,11 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) && \
-    (defined(USE_GNUTLS) || \
-     defined(USE_NSS) || \
-     defined(USE_SECTRANSP) || \
-     defined(USE_OS400CRYPTO) || \
-     defined(USE_WIN32_CRYPTO))
+#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) &&     \
+  (defined(USE_GNUTLS) ||                                       \
+   defined(USE_SECTRANSP) ||                                    \
+   defined(USE_OS400CRYPTO) ||                                  \
+   defined(USE_WIN32_CRYPTO))
 
 #include "curl_des.h"
 

+ 5 - 6
lib/curl_des.h

@@ -26,12 +26,11 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) && \
-    (defined(USE_GNUTLS) || \
-     defined(USE_NSS) || \
-     defined(USE_SECTRANSP) || \
-     defined(USE_OS400CRYPTO) || \
-     defined(USE_WIN32_CRYPTO))
+#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) &&     \
+  (defined(USE_GNUTLS) ||                                       \
+   defined(USE_SECTRANSP) ||                                    \
+   defined(USE_OS400CRYPTO) ||                                  \
+   defined(USE_WIN32_CRYPTO))
 
 /* Applies odd parity to the given byte array */
 void Curl_des_set_odd_parity(unsigned char *bytes, size_t length);

+ 2 - 1
lib/curl_hmac.h

@@ -24,7 +24,8 @@
  *
  ***************************************************************************/
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \
+    || !defined(CURL_DISABLE_AWS)
 
 #include <curl/curl.h>
 

+ 0 - 121
lib/curl_log.h

@@ -1,121 +0,0 @@
-#ifndef HEADER_CURL_LOG_H
-#define HEADER_CURL_LOG_H
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-struct Curl_easy;
-struct Curl_cfilter;
-
-/**
- * Init logging, return != 0 on failure.
- */
-CURLcode Curl_log_init(void);
-
-
-void Curl_infof(struct Curl_easy *, const char *fmt, ...);
-void Curl_failf(struct Curl_easy *, const char *fmt, ...);
-
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
-
-#if defined(HAVE_VARIADIC_MACROS_C99)
-#define infof(...)  Curl_nop_stmt
-#elif defined(HAVE_VARIADIC_MACROS_GCC)
-#define infof(x...)  Curl_nop_stmt
-#else
-#error "missing VARIADIC macro define, fix and rebuild!"
-#endif
-
-#else /* CURL_DISABLE_VERBOSE_STRINGS */
-
-#define infof Curl_infof
-
-#endif /* CURL_DISABLE_VERBOSE_STRINGS */
-
-#define failf Curl_failf
-
-
-#define CURL_LOG_DEFAULT  0
-#define CURL_LOG_DEBUG    1
-#define CURL_LOG_TRACE    2
-
-
-/* the function used to output verbose information */
-void Curl_debug(struct Curl_easy *data, curl_infotype type,
-                char *ptr, size_t size);
-
-#ifdef DEBUGBUILD
-
-/* explainer: we have some mix configuration and werror settings
- * that define HAVE_VARIADIC_MACROS_C99 even though C89 is enforced
- * on gnuc and some other compiler. Need to treat carefully.
- */
-#if defined(HAVE_VARIADIC_MACROS_C99) && \
-    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
-
-#define LOG_CF(data, cf, ...) \
-  do { if(Curl_log_cf_is_debug(cf, data)) \
-         Curl_log_cf_debug(data, cf, __VA_ARGS__); } while(0)
-#else
-#define LOG_CF Curl_log_cf_debug
-#endif
-
-void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf,
-#if defined(__GNUC__) && !defined(printf) &&                    \
-  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
-  !defined(__MINGW32__)
-                       const char *fmt, ...)
-                       __attribute__((format(printf, 3, 4)));
-#else
-                       const char *fmt, ...);
-#endif
-
-#define Curl_log_cf_is_debug(cf, data) \
-    ((data) && (data)->set.verbose && \
-     (cf) && (cf)->cft->log_level >= CURL_LOG_DEBUG)
-
-
-#else /* !DEBUGBUILD */
-
-#if defined(HAVE_VARIADIC_MACROS_C99) && \
-    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
-#define LOG_CF(...)               Curl_nop_stmt
-#define Curl_log_cf_debug(...)    Curl_nop_stmt
-#elif defined(HAVE_VARIADIC_MACROS_GCC) && \
-    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
-#define LOG_CF(x...)              Curl_nop_stmt
-#define Curl_log_cf_debug(x...)   Curl_nop_stmt
-#else
-#define LOG_CF                    Curl_log_cf_debug
-/* without c99, we seem unable to completely define away this function. */
-void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf,
-                       const char *fmt, ...);
-#endif
-
-#define Curl_log_cf_is_debug(x,y)   ((void)(x), (void)(y), FALSE)
-
-#endif  /* !DEBUGBUILD */
-
-#define LOG_CF_IS_DEBUG(cf, data)        Curl_log_cf_is_debug(cf, data)
-
-#endif /* HEADER_CURL_LOG_H */

+ 5 - 4
lib/curl_md4.h

@@ -25,14 +25,15 @@
  ***************************************************************************/
 
 #include "curl_setup.h"
+#include <curl/curl.h>
 
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if defined(USE_CURL_NTLM_CORE)
 
 #define MD4_DIGEST_LENGTH 16
 
-void Curl_md4it(unsigned char *output, const unsigned char *input,
-                const size_t len);
+CURLcode Curl_md4it(unsigned char *output, const unsigned char *input,
+                    const size_t len);
 
-#endif /* !defined(CURL_DISABLE_CRYPTO_AUTH) */
+#endif /* defined(USE_CURL_NTLM_CORE) */
 
 #endif /* HEADER_CURL_MD4_H */

+ 3 - 1
lib/curl_md5.h

@@ -24,7 +24,9 @@
  *
  ***************************************************************************/
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \
+    || !defined(CURL_DISABLE_DIGEST_AUTH)
+
 #include "curl_hmac.h"
 
 #define MD5_DIGEST_LEN  16

+ 9 - 77
lib/curl_ntlm_core.c

@@ -38,7 +38,7 @@
    1. USE_OPENSSL
    2. USE_WOLFSSL
    3. USE_GNUTLS
-   4. USE_NSS
+   4. -
    5. USE_MBEDTLS
    6. USE_SECTRANSP
    7. USE_OS400CRYPTO
@@ -47,7 +47,7 @@
    This ensures that:
    - the same SSL branch gets activated throughout this source
      file even if multiple backends are enabled at the same time.
-   - OpenSSL and NSS have higher priority than Windows Crypt, due
+   - OpenSSL has higher priority than Windows Crypt, due
      to issues with the latter supporting NTLM2Session responses
      in NTLM type-3 messages.
  */
@@ -96,12 +96,6 @@
 
 #  include <nettle/des.h>
 
-#elif defined(USE_NSS)
-
-#  include <nss.h>
-#  include <pk11pub.h>
-#  include <hasht.h>
-
 #elif defined(USE_MBEDTLS)
 
 #  include <mbedtls/des.h>
@@ -188,70 +182,6 @@ static void setup_des_key(const unsigned char *key_56,
   des_set_key(des, (const uint8_t *) key);
 }
 
-#elif defined(USE_NSS)
-
-/*
- * encrypt_des() expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of
- * data, using the expanded key. IN should point to 64 bits of source data,
- * OUT to a 64 bit output buffer.
- */
-static bool encrypt_des(const unsigned char *in, unsigned char *out,
-                        const unsigned char *key_56)
-{
-  const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */
-  char key[8];                                /* expanded 64 bit key */
-  SECItem key_item;
-  PK11SymKey *symkey = NULL;
-  SECItem *param = NULL;
-  PK11Context *ctx = NULL;
-  int out_len;                                /* not used, required by NSS */
-  bool rv = FALSE;
-
-  /* use internal slot for DES encryption (requires NSS to be initialized) */
-  PK11SlotInfo *slot = PK11_GetInternalKeySlot();
-  if(!slot)
-    return FALSE;
-
-  /* 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));
-
-  /* Import the key */
-  key_item.data = (unsigned char *)key;
-  key_item.len = sizeof(key);
-  symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT,
-                             &key_item, NULL);
-  if(!symkey)
-    goto fail;
-
-  /* Create the DES encryption context */
-  param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL);
-  if(!param)
-    goto fail;
-  ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param);
-  if(!ctx)
-    goto fail;
-
-  /* Perform the encryption */
-  if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8,
-                                 (unsigned char *)in, /* inbuflen */ 8)
-      && SECSuccess == PK11_Finalize(ctx))
-    rv = /* all OK */ TRUE;
-
-fail:
-  /* cleanup */
-  if(ctx)
-    PK11_DestroyContext(ctx, PR_TRUE);
-  if(symkey)
-    PK11_FreeSymKey(symkey);
-  if(param)
-    SECITEM_FreeItem(param, PR_TRUE);
-  PK11_FreeSlot(slot);
-  return rv;
-}
-
 #elif defined(USE_MBEDTLS)
 
 static bool encrypt_des(const unsigned char *in, unsigned char *out,
@@ -402,7 +332,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
   des_encrypt(&des, 8, results + 8, plaintext);
   setup_des_key(keys + 14, &des);
   des_encrypt(&des, 8, results + 16, plaintext);
-#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
+#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP)            \
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
   encrypt_des(plaintext, results, keys);
   encrypt_des(plaintext, results + 8, keys + 7);
@@ -444,7 +374,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
     des_encrypt(&des, 8, lmbuffer, magic);
     setup_des_key(pw + 7, &des);
     des_encrypt(&des, 8, lmbuffer + 8, magic);
-#elif defined(USE_NSS) || defined(USE_MBEDTLS) || defined(USE_SECTRANSP) \
+#elif defined(USE_MBEDTLS) || defined(USE_SECTRANSP)            \
   || defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO)
     encrypt_des(magic, lmbuffer, pw);
     encrypt_des(magic, lmbuffer + 8, pw + 7);
@@ -489,6 +419,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
 {
   size_t len = strlen(password);
   unsigned char *pw;
+  CURLcode result;
   if(len > SIZE_T_MAX/2) /* avoid integer overflow */
     return CURLE_OUT_OF_MEMORY;
   pw = len ? malloc(len * 2) : (unsigned char *)strdup("");
@@ -498,12 +429,13 @@ CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
   ascii_to_unicode_le(pw, password, len);
 
   /* Create NT hashed password. */
-  Curl_md4it(ntbuffer, pw, 2 * len);
-  memset(ntbuffer + 16, 0, 21 - 16);
+  result = Curl_md4it(ntbuffer, pw, 2 * len);
+  if(!result)
+    memset(ntbuffer + 16, 0, 21 - 16);
 
   free(pw);
 
-  return CURLE_OK;
+  return result;
 }
 
 #if !defined(USE_WINDOWS_SSPI)

+ 0 - 9
lib/curl_ntlm_core.h

@@ -28,15 +28,6 @@
 
 #if defined(USE_CURL_NTLM_CORE)
 
-/* If NSS is the first available SSL backend (see order in curl_ntlm_core.c)
-   then it must be initialized to be used by NTLM. */
-#if !defined(USE_OPENSSL) && \
-    !defined(USE_WOLFSSL) && \
-    !defined(USE_GNUTLS) && \
-    defined(USE_NSS)
-#define NTLM_NEEDS_NSS_INIT
-#endif
-
 #if defined(USE_OPENSSL)
 #  include <openssl/ssl.h>
 #elif defined(USE_WOLFSSL)

+ 4 - 4
lib/curl_sasl.c

@@ -420,7 +420,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
     }
     else
 #endif
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
     if((enabledmechs & SASL_MECH_DIGEST_MD5) &&
        Curl_auth_is_digest_supported()) {
       mech = SASL_MECH_STRING_DIGEST_MD5;
@@ -530,8 +530,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
   struct bufref resp;
   const char *hostname, *disp_hostname;
   int port;
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) ||     \
-  defined(USE_NTLM)
+#if defined(USE_KERBEROS5) || defined(USE_NTLM) \
+    || !defined(CURL_DISABLE_DIGEST_AUTH)
   const char *service = data->set.str[STRING_SERVICE_NAME] ?
     data->set.str[STRING_SERVICE_NAME] :
     sasl->params->service;
@@ -577,7 +577,6 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
   case SASL_EXTERNAL:
     result = Curl_auth_create_external_message(conn->user, &resp);
     break;
-#ifndef CURL_DISABLE_CRYPTO_AUTH
 #ifdef USE_GSASL
   case SASL_GSASL:
     result = get_server_message(sasl, data, &serverdata);
@@ -587,6 +586,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
       newstate = SASL_GSASL;
     break;
 #endif
+#ifndef CURL_DISABLE_DIGEST_AUTH
   case SASL_CRAMMD5:
     result = get_server_message(sasl, data, &serverdata);
     if(!result)

+ 13 - 14
lib/curl_setup.h

@@ -258,8 +258,9 @@
 #if defined(__APPLE__) && !defined(USE_ARES)
 #include <TargetConditionals.h>
 #define USE_RESOLVE_ON_IPS 1
-#  if !defined(TARGET_OS_OSX) || TARGET_OS_OSX
-#    define CURL_OSX_CALL_COPYPROXIES 1
+#  if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \
+     defined(ENABLE_IPV6)
+#    define CURL_MACOS_CALL_COPYPROXIES 1
 #  endif
 #endif
 
@@ -644,32 +645,30 @@
 
 #define LIBIDN_REQUIRED_VERSION "0.4.1"
 
-#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
-    defined(USE_MBEDTLS) || \
-    defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
-    defined(USE_SECTRANSP) || defined(USE_GSKIT) || \
-    defined(USE_BEARSSL) || defined(USE_RUSTLS)
+#if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
+  defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
+  defined(USE_BEARSSL) || defined(USE_RUSTLS)
 #define USE_SSL    /* SSL support has been enabled */
 #endif
 
 /* Single point where USE_SPNEGO definition might be defined */
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \
+#if !defined(CURL_DISABLE_NEGOTIATE_AUTH) && \
     (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
 #define USE_SPNEGO
 #endif
 
 /* Single point where USE_KERBEROS5 definition might be defined */
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) && \
+#if !defined(CURL_DISABLE_KERBEROS_AUTH) && \
     (defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI))
 #define USE_KERBEROS5
 #endif
 
 /* Single point where USE_NTLM definition might be defined */
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) && !defined(CURL_DISABLE_NTLM)
-#  if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                       \
-      defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) ||  \
-      defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
-      (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
+#if !defined(CURL_DISABLE_NTLM)
+#  if defined(USE_OPENSSL) || defined(USE_MBEDTLS) ||                   \
+  defined(USE_GNUTLS) || defined(USE_SECTRANSP) ||                      \
+  defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) ||              \
+  (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_ECB_ENCRYPT))
 #    define USE_CURL_NTLM_CORE
 #  endif
 #  if defined(USE_CURL_NTLM_CORE) || defined(USE_WINDOWS_SSPI)

+ 3 - 1
lib/curl_sha256.h

@@ -25,7 +25,9 @@
  *
  ***************************************************************************/
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \
+    || defined(USE_LIBSSH2)
+
 #include <curl/curl.h>
 #include "curl_hmac.h"
 

+ 53 - 30
lib/curl_log.c → lib/curl_trc.c

@@ -26,7 +26,7 @@
 
 #include <curl/curl.h>
 
-#include "curl_log.h"
+#include "curl_trc.h"
 #include "urldata.h"
 #include "easyif.h"
 #include "cfilters.h"
@@ -124,13 +124,13 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
   }
 }
 
-#ifdef DEBUGBUILD
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
 
-void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf,
+void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
                        const char *fmt, ...)
 {
   DEBUGASSERT(cf);
-  if(data && Curl_log_cf_is_debug(cf, data)) {
+  if(data && Curl_trc_cf_is_verbose(cf, data)) {
     va_list ap;
     int len;
     char buffer[MAXINFO + 2];
@@ -179,44 +179,67 @@ static struct Curl_cftype *cf_types[] = {
   NULL,
 };
 
-#ifndef ARRAYSIZE
-#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
-#endif
-
-CURLcode Curl_log_init(void)
+CURLcode Curl_trc_opt(const char *config)
 {
-  const char *setting = getenv("CURL_DEBUG");
-  if(setting) {
-    char *token, *tok_buf, *tmp;
-    size_t i;
-
-    tmp = strdup(setting);
-    if(!tmp)
-      return CURLE_OUT_OF_MEMORY;
-
-    token = strtok_r(tmp, ", ", &tok_buf);
-    while(token) {
-      for(i = 0; cf_types[i]; ++i) {
-        if(strcasecompare(token, cf_types[i]->name)) {
-          cf_types[i]->log_level = CURL_LOG_DEBUG;
-          break;
-        }
+  char *token, *tok_buf, *tmp;
+  size_t i;
+  int lvl;
+
+  tmp = strdup(config);
+  if(!tmp)
+    return CURLE_OUT_OF_MEMORY;
+
+  token = strtok_r(tmp, ", ", &tok_buf);
+  while(token) {
+    switch(*token) {
+      case '-':
+        lvl = CURL_LOG_LVL_NONE;
+        ++token;
+        break;
+      case '+':
+        lvl = CURL_LOG_LVL_INFO;
+        ++token;
+        break;
+      default:
+        lvl = CURL_LOG_LVL_INFO;
+        break;
+    }
+    for(i = 0; cf_types[i]; ++i) {
+      if(strcasecompare(token, "all")) {
+        cf_types[i]->log_level = lvl;
+      }
+      else if(strcasecompare(token, cf_types[i]->name)) {
+        cf_types[i]->log_level = lvl;
+        break;
       }
-      token = strtok_r(NULL, ", ", &tok_buf);
     }
-    free(tmp);
+    token = strtok_r(NULL, ", ", &tok_buf);
+  }
+  free(tmp);
+  return CURLE_OK;
+}
+
+CURLcode Curl_trc_init(void)
+{
+#ifdef DEBUGBUILD
+  /* WIP: we use the auto-init from an env var only in DEBUG builds for
+   * convenience. */
+  const char *config = getenv("CURL_DEBUG");
+  if(config) {
+    return Curl_trc_opt(config);
   }
+#endif
   return CURLE_OK;
 }
-#else /* DEBUGBUILD */
+#else /* !CURL_DISABLE_VERBOSE_STRINGS) */
 
-CURLcode Curl_log_init(void)
+CURLcode Curl_trc_init(void)
 {
   return CURLE_OK;
 }
 
 #if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
-void Curl_log_cf_debug(struct Curl_easy *data, struct Curl_cfilter *cf,
+void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
                        const char *fmt, ...)
 {
   (void)data;

+ 150 - 0
lib/curl_trc.h

@@ -0,0 +1,150 @@
+#ifndef HEADER_CURL_TRC_H
+#define HEADER_CURL_TRC_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ * SPDX-License-Identifier: curl
+ *
+ ***************************************************************************/
+
+struct Curl_easy;
+struct Curl_cfilter;
+
+/**
+ * Init logging, return != 0 on failure.
+ */
+CURLcode Curl_trc_init(void);
+
+/**
+ * Configure tracing. May be called several times during global
+ * initialization. Later calls may not take effect.
+ *
+ * Configuration format supported:
+ * - comma-separated list of component names to enable logging on.
+ *   E.g. 'http/2,ssl'. Unknown names are ignored. Names are compared
+ *   case-insensitive.
+ * - component 'all' applies to all known log components
+ * - prefixing a component with '+' or '-' will en-/disable logging for
+ *   that component
+ * Example: 'all,-ssl' would enable logging for all components but the
+ * SSL filters.
+ *
+ * @param config configuration string
+ */
+CURLcode Curl_trc_opt(const char *config);
+
+/* the function used to output verbose information */
+void Curl_debug(struct Curl_easy *data, curl_infotype type,
+                char *ptr, size_t size);
+
+/**
+ * Output an informational message when transfer's verbose logging is enabled.
+ */
+void Curl_infof(struct Curl_easy *data,
+#if defined(__GNUC__) && !defined(printf) &&                    \
+  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+  !defined(__MINGW32__)
+                       const char *fmt, ...)
+                       __attribute__((format(printf, 2, 3)));
+#else
+                       const char *fmt, ...);
+#endif
+
+/**
+ * Output a failure message on registered callbacks for transfer.
+ */
+void Curl_failf(struct Curl_easy *data,
+#if defined(__GNUC__) && !defined(printf) &&                    \
+  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+  !defined(__MINGW32__)
+                       const char *fmt, ...)
+                       __attribute__((format(printf, 2, 3)));
+#else
+                       const char *fmt, ...);
+#endif
+
+#define failf Curl_failf
+
+/**
+ * Output an informational message when both transfer's verbose logging
+ * and connection filters verbose logging are enabled.
+ */
+void Curl_trc_cf_infof(struct Curl_easy *data, struct Curl_cfilter *cf,
+#if defined(__GNUC__) && !defined(printf) &&                    \
+  defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
+  !defined(__MINGW32__)
+                       const char *fmt, ...)
+                       __attribute__((format(printf, 3, 4)));
+#else
+                       const char *fmt, ...);
+#endif
+
+#define CURL_LOG_LVL_NONE  0
+#define CURL_LOG_LVL_INFO  1
+
+
+#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
+/* informational messages enabled */
+
+#define Curl_trc_is_verbose(data)    ((data) && (data)->set.verbose)
+#define Curl_trc_cf_is_verbose(cf, data) \
+                            ((data) && (data)->set.verbose && \
+                            (cf) && (cf)->cft->log_level >= CURL_LOG_LVL_INFO)
+
+/* explainer: we have some mix configuration and werror settings
+ * that define HAVE_VARIADIC_MACROS_C99 even though C89 is enforced
+ * on gnuc and some other compiler. Need to treat carefully.
+ */
+#if defined(HAVE_VARIADIC_MACROS_C99) && \
+    defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)
+
+#define infof(data, ...) \
+  do { if(Curl_trc_is_verbose(data)) \
+         Curl_infof(data, __VA_ARGS__); } while(0)
+#define CURL_TRC_CF(data, cf, ...) \
+  do { if(Curl_trc_cf_is_verbose(cf, data)) \
+         Curl_trc_cf_infof(data, cf, __VA_ARGS__); } while(0)
+
+#else /* no variadic macro args */
+#define infof Curl_infof
+#define CURL_TRC_CF Curl_trc_cf_infof
+#endif /* variadic macro args */
+
+#else /* !CURL_DISABLE_VERBOSE_STRINGS */
+/* All informational messages are not compiled in for size savings */
+
+#define Curl_trc_is_verbose(d)        ((void)(d), FALSE)
+#define Curl_trc_cf_is_verbose(x,y)   ((void)(x), (void)(y), FALSE)
+
+#if defined(HAVE_VARIADIC_MACROS_C99)
+#define infof(...)  Curl_nop_stmt
+#define CURL_TRC_CF(...)  Curl_nop_stmt
+#define Curl_trc_cf_infof(...)  Curl_nop_stmt
+#elif defined(HAVE_VARIADIC_MACROS_GCC)
+#define infof(x...)  Curl_nop_stmt
+#define CURL_TRC_CF(x...)  Curl_nop_stmt
+#define Curl_trc_cf_infof(x...)  Curl_nop_stmt
+#else
+#error "missing VARIADIC macro define, fix and rebuild!"
+#endif
+
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+
+#endif /* HEADER_CURL_TRC_H */

+ 24 - 8
lib/easy.c

@@ -158,8 +158,8 @@ static CURLcode global_init(long flags, bool memoryfuncs)
 #endif
   }
 
-  if(Curl_log_init()) {
-    DEBUGF(fprintf(stderr, "Error: Curl_log_init failed\n"));
+  if(Curl_trc_init()) {
+    DEBUGF(fprintf(stderr, "Error: Curl_trc_init failed\n"));
     goto fail;
   }
 
@@ -168,19 +168,15 @@ static CURLcode global_init(long flags, bool memoryfuncs)
     goto fail;
   }
 
-#ifdef WIN32
   if(Curl_win32_init(flags)) {
     DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
     goto fail;
   }
-#endif
 
-#ifdef __AMIGA__
   if(Curl_amiga_init()) {
     DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
     goto fail;
   }
-#endif
 
   if(Curl_macos_init()) {
     DEBUGF(fprintf(stderr, "Error: Curl_macos_init failed\n"));
@@ -319,6 +315,26 @@ void curl_global_cleanup(void)
   global_init_unlock();
 }
 
+/**
+ * curl_global_trace() globally initializes curl logging.
+ */
+CURLcode curl_global_trace(const char *config)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+  CURLcode result;
+  global_init_lock();
+
+  result = Curl_trc_opt(config);
+
+  global_init_unlock();
+
+  return result;
+#else
+  (void)config;
+  return CURLE_OK;
+#endif
+}
+
 /*
  * curl_global_sslset() globally initializes the SSL backend to use.
  */
@@ -699,7 +715,7 @@ static CURLcode easy_transfer(struct Curl_multi *multi)
  *
  * REALITY: it can't just create and destroy the multi handle that easily. It
  * needs to keep it around since if this easy handle is used again by this
- * function, the same multi handle must be re-used so that the same pools and
+ * function, the same multi handle must be reused so that the same pools and
  * caches can be used.
  *
  * DEBUG: if 'events' is set TRUE, this function will use a replacement engine
@@ -1048,7 +1064,7 @@ void curl_easy_reset(struct Curl_easy *data)
   memset(&data->state.authhost, 0, sizeof(struct auth));
   memset(&data->state.authproxy, 0, sizeof(struct auth));
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
   Curl_http_auth_cleanup_digest(data);
 #endif
 }

+ 2 - 2
lib/formdata.c

@@ -27,7 +27,7 @@
 #include <curl/curl.h>
 
 #include "formdata.h"
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_MIME)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_FORM_API)
 
 #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
 #include <libgen.h>
@@ -941,7 +941,7 @@ int curl_formget(struct curl_httppost *form, void *arg,
 void curl_formfree(struct curl_httppost *form)
 {
   (void)form;
-  /* does nothing HTTP is disabled */
+  /* Nothing to do. */
 }
 
 #endif  /* if disabled */

+ 2 - 5
lib/formdata.h

@@ -26,7 +26,7 @@
 
 #include "curl_setup.h"
 
-#ifndef CURL_DISABLE_MIME
+#ifndef CURL_DISABLE_FORM_API
 
 /* used by FormAdd for temporary storage */
 struct FormInfo {
@@ -53,10 +53,7 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
                           curl_mimepart *,
                           struct curl_httppost *post,
                           curl_read_callback fread_func);
-#else
-/* disabled */
-#define Curl_getformdata(a,b,c,d) CURLE_NOT_BUILT_IN
-#endif
+#endif /* CURL_DISABLE_FORM_API */
 
 
 #endif /* HEADER_CURL_FORMDATA_H */

+ 3 - 6
lib/ftp.c

@@ -32,9 +32,6 @@
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
-#ifdef HAVE_UTSNAME_H
-#include <sys/utsname.h>
-#endif
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
@@ -865,7 +862,7 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data,
     if(conn->bits.reuse && ftpc->entrypath &&
        /* no need to go to entrypath when we have an absolute path */
        !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) {
-      /* This is a re-used connection. Since we change directory to where the
+      /* This is a reused connection. Since we change directory to where the
          transfer is taking place, we must first get back to the original dir
          where we ended up after login: */
       ftpc->cwdcount = 0; /* we count this as the first path, then we add one
@@ -975,7 +972,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
         if(ip_end) {
           /* either ipv6 or (ipv4|domain|interface):port(-range) */
 #ifdef ENABLE_IPV6
-          if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
+          if(Curl_inet_pton(AF_INET6, string_ftpport, &sa6->sin6_addr) == 1) {
             /* ipv6 */
             port_min = port_max = 0;
             strcpy(addr, string_ftpport);
@@ -1900,7 +1897,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data,
     if(data->set.ftp_skip_ip) {
       /* told to ignore the remotely given IP but instead use the host we used
          for the control connection */
-      infof(data, "Skip %u.%u.%u.%u for data connection, re-use %s instead",
+      infof(data, "Skip %u.%u.%u.%u for data connection, reuse %s instead",
             ip[0], ip[1], ip[2], ip[3],
             conn->host.name);
       ftpc->newhost = strdup(control_address(conn));

+ 2 - 2
lib/gopher.c

@@ -185,7 +185,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
     if(strlen(sel) < 1)
       break;
 
-    result = Curl_write(data, sockfd, sel, k, &amount);
+    result = Curl_nwrite(data, FIRSTSOCKET, sel, k, &amount);
     if(!result) { /* Which may not have written it all! */
       result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
       if(result)
@@ -227,7 +227,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
   free(sel_org);
 
   if(!result)
-    result = Curl_write(data, sockfd, "\r\n", 2, &amount);
+    result = Curl_nwrite(data, FIRSTSOCKET, "\r\n", 2, &amount);
   if(result) {
     failf(data, "Failed sending Gopher request");
     return result;

+ 10 - 3
lib/headers.c

@@ -300,9 +300,16 @@ CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
     if(data->state.prevhead)
       /* line folding, append value to the previous header's value */
       return unfold_value(data, header, hlen);
-    else
-      /* can't unfold without a previous header */
-      return CURLE_BAD_FUNCTION_ARGUMENT;
+    else {
+      /* Can't unfold without a previous header. Instead of erroring, just
+         pass the leading blanks. */
+      while(hlen && ISBLANK(*header)) {
+        header++;
+        hlen--;
+      }
+      if(!hlen)
+        return CURLE_WEIRD_SERVER_REPLY;
+    }
   }
 
   hs = calloc(1, sizeof(*hs) + hlen);

+ 3 - 2
lib/hmac.c

@@ -26,7 +26,8 @@
 
 #include "curl_setup.h"
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \
+    || !defined(CURL_DISABLE_AWS)
 
 #include <curl/curl.h>
 
@@ -169,4 +170,4 @@ CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
   return CURLE_OK;
 }
 
-#endif /* CURL_DISABLE_CRYPTO_AUTH */
+#endif /* Using NTLM (without SSPI) or AWS */

+ 15 - 15
lib/hostip.c

@@ -121,19 +121,6 @@
 
 static void freednsentry(void *freethis);
 
-/*
- * Return # of addresses in a Curl_addrinfo struct
- */
-static int num_addresses(const struct Curl_addrinfo *addr)
-{
-  int i = 0;
-  while(addr) {
-    addr = addr->ai_next;
-    i++;
-  }
-  return i;
-}
-
 /*
  * Curl_printable_address() stores a printable version of the 1st address
  * given in the 'ai' argument. The result will be stored in the buf that is
@@ -388,6 +375,19 @@ Curl_fetch_addr(struct Curl_easy *data,
 }
 
 #ifndef CURL_DISABLE_SHUFFLE_DNS
+/*
+ * Return # of addresses in a Curl_addrinfo struct
+ */
+static int num_addresses(const struct Curl_addrinfo *addr)
+{
+  int i = 0;
+  while(addr) {
+    addr = addr->ai_next;
+    i++;
+  }
+  return i;
+}
+
 UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
                                     struct Curl_addrinfo **addr);
 /*
@@ -601,7 +601,7 @@ bool Curl_ipv6works(struct Curl_easy *data)
   if(data) {
     /* the nature of most system is that IPv6 status doesn't come and go
        during a program's lifetime so we only probe the first time and then we
-       have the info kept for fast re-use */
+       have the info kept for fast reuse */
     DEBUGASSERT(data);
     DEBUGASSERT(data->multi);
     if(data->multi->ipv6_up == IPV6_UNKNOWN) {
@@ -1240,7 +1240,7 @@ err:
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
       if(dns) {
-        infof(data, "RESOLVE %.*s:%d is - old addresses discarded",
+        infof(data, "RESOLVE %.*s:%d - old addresses discarded",
               (int)hlen, host_begin, port);
         /* delete old entry, there are two reasons for this
          1. old entry may have different addresses.

+ 133 - 43
lib/http.c

@@ -233,7 +233,6 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
   if(!http)
     return CURLE_OUT_OF_MEMORY;
 
-  Curl_mime_initpart(&http->form);
   data->req.p.http = http;
   connkeep(conn, "HTTP default");
 
@@ -342,6 +341,8 @@ char *Curl_copy_header_value(const char *header)
 }
 
 #ifndef CURL_DISABLE_HTTP_AUTH
+
+#ifndef CURL_DISABLE_BASIC_AUTH
 /*
  * http_output_basic() sets up an Authorization: header (or the proxy version)
  * for HTTP Basic authentication.
@@ -403,6 +404,9 @@ fail:
   return result;
 }
 
+#endif
+
+#ifndef CURL_DISABLE_BEARER_AUTH
 /*
  * http_output_bearer() sets up an Authorization: header
  * for HTTP Bearer authentication.
@@ -430,6 +434,8 @@ fail:
 
 #endif
 
+#endif
+
 /* pickoneauth() selects the most favourable authentication method from the
  * ones available and the ones we want.
  *
@@ -446,18 +452,26 @@ static bool pickoneauth(struct auth *pick, unsigned long mask)
      of preference in case of the existence of multiple accepted types. */
   if(avail & CURLAUTH_NEGOTIATE)
     pick->picked = CURLAUTH_NEGOTIATE;
+#ifndef CURL_DISABLE_BEARER_AUTH
   else if(avail & CURLAUTH_BEARER)
     pick->picked = CURLAUTH_BEARER;
+#endif
+#ifndef CURL_DISABLE_DIGEST_AUTH
   else if(avail & CURLAUTH_DIGEST)
     pick->picked = CURLAUTH_DIGEST;
+#endif
   else if(avail & CURLAUTH_NTLM)
     pick->picked = CURLAUTH_NTLM;
   else if(avail & CURLAUTH_NTLM_WB)
     pick->picked = CURLAUTH_NTLM_WB;
+#ifndef CURL_DISABLE_BASIC_AUTH
   else if(avail & CURLAUTH_BASIC)
     pick->picked = CURLAUTH_BASIC;
+#endif
+#ifndef CURL_DISABLE_AWS
   else if(avail & CURLAUTH_AWS_SIGV4)
     pick->picked = CURLAUTH_AWS_SIGV4;
+#endif
   else {
     pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
     picked = FALSE;
@@ -723,11 +737,11 @@ output_auth_headers(struct Curl_easy *data,
   CURLcode result = CURLE_OK;
   (void)conn;
 
-#ifdef CURL_DISABLE_CRYPTO_AUTH
+#ifdef CURL_DISABLE_DIGEST_AUTH
   (void)request;
   (void)path;
 #endif
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_AWS
   if(authstatus->picked == CURLAUTH_AWS_SIGV4) {
     auth = "AWS_SIGV4";
     result = Curl_output_aws_sigv4(data, proxy);
@@ -763,7 +777,7 @@ output_auth_headers(struct Curl_easy *data,
   }
   else
 #endif
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
   if(authstatus->picked == CURLAUTH_DIGEST) {
     auth = "Digest";
     result = Curl_output_digest(data,
@@ -775,6 +789,7 @@ output_auth_headers(struct Curl_easy *data,
   }
   else
 #endif
+#ifndef CURL_DISABLE_BASIC_AUTH
   if(authstatus->picked == CURLAUTH_BASIC) {
     /* Basic */
     if(
@@ -794,6 +809,8 @@ output_auth_headers(struct Curl_easy *data,
        functions work that way */
     authstatus->done = TRUE;
   }
+#endif
+#ifndef CURL_DISABLE_BEARER_AUTH
   if(authstatus->picked == CURLAUTH_BEARER) {
     /* Bearer */
     if((!proxy && data->set.str[STRING_BEARER] &&
@@ -808,6 +825,7 @@ output_auth_headers(struct Curl_easy *data,
        functions work that way */
     authstatus->done = TRUE;
   }
+#endif
 
   if(auth) {
 #ifndef CURL_DISABLE_PROXY
@@ -866,7 +884,12 @@ Curl_http_output_auth(struct Curl_easy *data,
 #ifndef CURL_DISABLE_PROXY
     (conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
 #endif
-     data->state.aptr.user || data->set.str[STRING_BEARER])
+     data->state.aptr.user ||
+#ifdef USE_SPNEGO
+     authhost->want & CURLAUTH_NEGOTIATE ||
+     authproxy->want & CURLAUTH_NEGOTIATE ||
+#endif
+     data->set.str[STRING_BEARER])
     /* continue please */;
   else {
     authhost->done = TRUE;
@@ -1064,7 +1087,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
       }
       else
 #endif
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
         if(checkprefix("Digest", auth) && is_valid_auth_separator(auth[6])) {
           if((authp->avail & CURLAUTH_DIGEST) != 0)
             infof(data, "Ignoring duplicate digest auth header.");
@@ -1087,6 +1110,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
         }
         else
 #endif
+#ifndef CURL_DISABLE_BASIC_AUTH
           if(checkprefix("Basic", auth) &&
              is_valid_auth_separator(auth[5])) {
             *availp |= CURLAUTH_BASIC;
@@ -1101,6 +1125,8 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
             }
           }
           else
+#endif
+#ifndef CURL_DISABLE_BEARER_AUTH
             if(checkprefix("Bearer", auth) &&
                is_valid_auth_separator(auth[6])) {
               *availp |= CURLAUTH_BEARER;
@@ -1113,6 +1139,7 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
                 data->state.authproblem = TRUE;
               }
             }
+#endif
 
     /* there may be multiple methods on one line, so keep reading */
     while(*auth && *auth != ',') /* read up to the next comma */
@@ -1277,7 +1304,7 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
                           curl_off_t *bytes_written,
                           /* how much of the buffer contains body data */
                           curl_off_t included_body_bytes,
-                          int socketindex)
+                          int sockindex)
 {
   ssize_t amount;
   CURLcode result;
@@ -1285,12 +1312,9 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
   size_t size;
   struct connectdata *conn = data->conn;
   size_t sendsize;
-  curl_socket_t sockfd;
   size_t headersize;
 
-  DEBUGASSERT(socketindex <= SECONDARYSOCKET);
-
-  sockfd = Curl_conn_get_socket(data, socketindex);
+  DEBUGASSERT(sockindex <= SECONDARYSOCKET && sockindex >= 0);
 
   /* The looping below is required since we use non-blocking sockets, but due
      to the circumstances we will just loop and try again and again etc */
@@ -1372,9 +1396,25 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
       else
         sendsize = size;
     }
+
+    /* We currently cannot send more that this for http here:
+     * - if sending blocks, it return 0 as amount
+     * - we then whisk aside the `in` into the `http` struct
+     *   and install our own `data->state.fread_func` that
+     *   on subsequent calls reads `in` empty.
+     * - when the whisked away `in` is empty, the `fread_func`
+     *   is restored ot its original state.
+     * The problem is that `fread_func` can only return
+     * `upload_buffer_size` lengths. If the send we do here
+     * is larger and blocks, we do re-sending with smaller
+     * amounts of data and connection filters do not like
+     * that.
+     */
+    if(http && (sendsize > (size_t)data->set.upload_buffer_size))
+      sendsize = (size_t)data->set.upload_buffer_size;
   }
 
-  result = Curl_write(data, sockfd, ptr, sendsize, &amount);
+  result = Curl_nwrite(data, sockindex, ptr, sendsize, &amount);
 
   if(!result) {
     /*
@@ -1527,7 +1567,7 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
   struct connectdata *conn = data->conn;
 
   /* We default to persistent connections. We set this already in this connect
-     function to make the re-use checks properly be able to check this bit. */
+     function to make the reuse checks properly be able to check this bit. */
   connkeep(conn, "HTTP default");
 
   return Curl_conn_connect(data, FIRSTSOCKET, FALSE, done);
@@ -1572,7 +1612,6 @@ CURLcode Curl_http_done(struct Curl_easy *data,
     return CURLE_OK;
 
   Curl_dyn_free(&http->send_buffer);
-  Curl_mime_cleanpart(&http->form);
   Curl_dyn_reset(&data->state.headerb);
   Curl_hyper_done(data);
   Curl_ws_done(data);
@@ -2370,45 +2409,53 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
 
   switch(httpreq) {
   case HTTPREQ_POST_MIME:
-    http->sendit = &data->set.mimepost;
+    data->state.mimepost = &data->set.mimepost;
     break;
+#ifndef CURL_DISABLE_FORM_API
   case HTTPREQ_POST_FORM:
-    /* Convert the form structure into a mime structure. */
-    Curl_mime_cleanpart(&http->form);
-    result = Curl_getformdata(data, &http->form, data->set.httppost,
-                              data->state.fread_func);
-    if(result)
-      return result;
-    http->sendit = &http->form;
+    /* Convert the form structure into a mime structure, then keep
+       the conversion */
+    if(!data->state.formp) {
+      data->state.formp = calloc(sizeof(curl_mimepart), 1);
+      if(!data->state.formp)
+        return CURLE_OUT_OF_MEMORY;
+      Curl_mime_cleanpart(data->state.formp);
+      result = Curl_getformdata(data, data->state.formp, data->set.httppost,
+                                data->state.fread_func);
+      if(result)
+        return result;
+      data->state.mimepost = data->state.formp;
+    }
     break;
+#endif
   default:
-    http->sendit = NULL;
+    data->state.mimepost = NULL;
   }
 
 #ifndef CURL_DISABLE_MIME
-  if(http->sendit) {
+  if(data->state.mimepost) {
     const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
 
     /* Read and seek body only. */
-    http->sendit->flags |= MIME_BODY_ONLY;
+    data->state.mimepost->flags |= MIME_BODY_ONLY;
 
     /* Prepare the mime structure headers & set content type. */
 
     if(cthdr)
       for(cthdr += 13; *cthdr == ' '; cthdr++)
         ;
-    else if(http->sendit->kind == MIMEKIND_MULTIPART)
+    else if(data->state.mimepost->kind == MIMEKIND_MULTIPART)
       cthdr = "multipart/form-data";
 
-    curl_mime_headers(http->sendit, data->set.headers, 0);
-    result = Curl_mime_prepare_headers(data, http->sendit, cthdr,
+    curl_mime_headers(data->state.mimepost, data->set.headers, 0);
+    result = Curl_mime_prepare_headers(data, data->state.mimepost, cthdr,
                                        NULL, MIMESTRATEGY_FORM);
-    curl_mime_headers(http->sendit, NULL, 0);
+    curl_mime_headers(data->state.mimepost, NULL, 0);
     if(!result)
-      result = Curl_mime_rewind(http->sendit);
+      result = Curl_mime_rewind(data->state.mimepost);
     if(result)
       return result;
-    http->postsize = Curl_mime_size(http->sendit);
+    http->postsize = Curl_mime_size(data->state.mimepost);
   }
 #endif
 
@@ -2564,7 +2611,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
     {
       struct curl_slist *hdr;
 
-      for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
+      for(hdr = data->state.mimepost->curlheaders; hdr; hdr = hdr->next) {
         result = Curl_dyn_addf(r, "%s\r\n", hdr->data);
         if(result)
           return result;
@@ -2599,7 +2646,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
 
     /* Read from mime structure. */
     data->state.fread_func = (curl_read_callback) Curl_mime_read;
-    data->state.in = (void *) http->sendit;
+    data->state.in = (void *) data->state.mimepost;
     http->sending = HTTPSEND_BODY;
 
     /* this sends the buffer and frees all the buffer resources */
@@ -2683,7 +2730,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
 
         if(!data->req.upload_chunky) {
           /* We're not sending it 'chunked', append it to the request
-             already now to reduce the number if send() calls */
+             already now to reduce the number of send() calls */
           result = Curl_dyn_addn(r, data->set.postfields,
                                  (size_t)http->postsize);
           included_body = http->postsize;
@@ -3024,7 +3071,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
       *done = TRUE;
       return CURLE_OK;
     }
-    /* We have a new url to load, but since we want to be able to re-use this
+    /* We have a new url to load, but since we want to be able to reuse this
        connection properly, we read the full response in "ignore more" */
     k->ignorebody = TRUE;
     infof(data, "Ignoring the response-body");
@@ -3064,7 +3111,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
       data->info.httpcode = 304;
       infof(data, "Simulate an HTTP 304 response");
       /* we abort the transfer before it is completed == we ruin the
-         re-use ability. Close the connection */
+         reuse ability. Close the connection */
       streamclose(conn, "Simulated 304 handling");
       return CURLE_OK;
     }
@@ -3308,8 +3355,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
                   altused ? altused : ""
       );
 
-  /* clear userpwd and proxyuserpwd to avoid re-using old credentials
-   * from re-used connections */
+  /* clear userpwd and proxyuserpwd to avoid reusing old credentials
+   * from reused connections */
   Curl_safefree(data->state.aptr.userpwd);
   Curl_safefree(data->state.aptr.proxyuserpwd);
   free(altused);
@@ -3918,6 +3965,29 @@ static CURLcode verify_header(struct Curl_easy *data)
   return CURLE_OK;
 }
 
+CURLcode Curl_bump_headersize(struct Curl_easy *data,
+                              size_t delta,
+                              bool connect_only)
+{
+  size_t bad = 0;
+  if(delta < MAX_HTTP_RESP_HEADER_SIZE) {
+    if(!connect_only)
+      data->req.headerbytecount += (unsigned int)delta;
+    data->info.header_size += (unsigned int)delta;
+    if(data->info.header_size > MAX_HTTP_RESP_HEADER_SIZE)
+      bad = data->info.header_size;
+  }
+  else
+    bad = data->info.header_size + delta;
+  if(bad) {
+    failf(data, "Too large response headers: %zu > %u",
+          bad, MAX_HTTP_RESP_HEADER_SIZE);
+    return CURLE_RECV_ERROR;
+  }
+  return CURLE_OK;
+}
+
+
 /*
  * Read any HTTP header lines from the server and pass them to the client app.
  */
@@ -4056,6 +4126,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           /* Switching Protocols */
           if(k->upgr101 == UPGR101_H2) {
             /* Switching to HTTP/2 */
+            DEBUGASSERT(conn->httpversion < 20);
             infof(data, "Received 101, Switching to HTTP/2");
             k->upgr101 = UPGR101_RECEIVED;
 
@@ -4098,6 +4169,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
         }
       }
       else {
+        if(k->upgr101 == UPGR101_H2) {
+          /* A requested upgrade was denied, poke the multi handle to possibly
+             allow a pending pipewait to continue */
+          Curl_multi_connchanged(data->multi);
+        }
         k->header = FALSE; /* no more header to parse! */
 
         if((k->size == -1) && !k->chunk && !conn->bits.close &&
@@ -4165,8 +4241,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
       if(result)
         return result;
 
-      data->info.header_size += (long)headerlen;
-      data->req.headerbytecount += (long)headerlen;
+      result = Curl_bump_headersize(data, headerlen, FALSE);
+      if(result)
+        return result;
 
       /*
        * When all the headers have been parsed, see if we should give
@@ -4229,7 +4306,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
               if((k->httpcode == 417) && data->state.expect100header) {
                 /* 417 Expectation Failed - try again without the Expect
                    header */
-                infof(data, "Got 417 while waiting for a 100");
+                if(!k->writebytecount &&
+                   k->exp100 == EXP100_AWAITING_CONTINUE) {
+                  infof(data, "Got HTTP failure 417 while waiting for a 100");
+                }
+                else {
+                  infof(data, "Got HTTP failure 417 while sending data");
+                  streamclose(conn,
+                              "Stop sending data before everything sent");
+                  result = http_perhapsrewind(data, conn);
+                  if(result)
+                    return result;
+                }
                 data->state.disableexpect = TRUE;
                 DEBUGASSERT(!data->req.newurl);
                 data->req.newurl = strdup(data->state.url);
@@ -4488,8 +4576,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
     if(result)
       return result;
 
-    data->info.header_size += Curl_dyn_len(&data->state.headerb);
-    data->req.headerbytecount += Curl_dyn_len(&data->state.headerb);
+    result = Curl_bump_headersize(data, Curl_dyn_len(&data->state.headerb),
+                                  FALSE);
+    if(result)
+      return result;
 
     Curl_dyn_reset(&data->state.headerb);
   }

+ 10 - 8
lib/http.h

@@ -64,6 +64,10 @@ extern const struct Curl_handler Curl_handler_wss;
 
 struct dynhds;
 
+CURLcode Curl_bump_headersize(struct Curl_easy *data,
+                              size_t delta,
+                              bool connect_only);
+
 /* Header specific functions */
 bool Curl_compareheader(const char *headerline,  /* line to check */
                         const char *header,   /* header keyword _with_ colon */
@@ -183,21 +187,19 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
 #define EXPECT_100_THRESHOLD (1024*1024)
 #endif
 
+/* MAX_HTTP_RESP_HEADER_SIZE is the maximum size of all response headers
+   combined that libcurl allows for a single HTTP response, any HTTP
+   version. This count includes CONNECT response headers. */
+#define MAX_HTTP_RESP_HEADER_SIZE (300*1024)
+
 #endif /* CURL_DISABLE_HTTP */
 
 /****************************************************************************
  * HTTP unique setup
  ***************************************************************************/
 struct HTTP {
-  curl_mimepart *sendit;
   curl_off_t postsize; /* off_t to handle large file sizes */
   const char *postdata;
-
-  const char *p_pragma;      /* Pragma: string */
-
-  /* For FORM posting */
-  curl_mimepart form;
-
   struct back {
     curl_read_callback fread_func; /* backup storage for fread pointer */
     void *fread_in;           /* backup storage for fread_in pointer */
@@ -292,7 +294,7 @@ void Curl_http_req_free(struct httpreq *req);
 
 /**
  * Create the list of HTTP/2 headers which represent the request,
- * using HTTP/2 pseudo headers preceeding the `req->headers`.
+ * using HTTP/2 pseudo headers preceding the `req->headers`.
  *
  * Applies the following transformations:
  * - if `authority` is set, any "Host" header is removed.

+ 1 - 1
lib/http1.c

@@ -163,7 +163,7 @@ static CURLcode start_req(struct h1_req_parser *parser,
       break;
     }
   }
-  /* no SPACE found or empty TARGET or empy HTTP_VERSION */
+  /* no SPACE found or empty TARGET or empty HTTP_VERSION */
   if(!target_len || !hv_len)
     goto out;
 

File diff suppressed because it is too large
+ 322 - 201
lib/http2.c


+ 200 - 49
lib/http_aws_sigv4.c

@@ -24,7 +24,7 @@
 
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS)
 
 #include "urldata.h"
 #include "strcase.h"
@@ -44,16 +44,16 @@
 
 #include "slist.h"
 
-#define HMAC_SHA256(k, kl, d, dl, o)        \
-  do {                                      \
-    ret = Curl_hmacit(Curl_HMAC_SHA256,     \
-                      (unsigned char *)k,   \
-                      kl,                   \
-                      (unsigned char *)d,   \
-                      dl, o);               \
-    if(ret) {                               \
-      goto fail;                            \
-    }                                       \
+#define HMAC_SHA256(k, kl, d, dl, o)           \
+  do {                                         \
+    result = Curl_hmacit(Curl_HMAC_SHA256,     \
+                         (unsigned char *)k,   \
+                         kl,                   \
+                         (unsigned char *)d,   \
+                         dl, o);               \
+    if(result) {                               \
+      goto fail;                               \
+    }                                          \
   } while(0)
 
 #define TIMESTAMP_SIZE 17
@@ -199,10 +199,41 @@ static CURLcode make_headers(struct Curl_easy *data,
     head = tmp_head;
   }
 
+  /* copy user headers to our header list. the logic is based on how http.c
+     handles user headers.
+
+     user headers in format 'name:' with no value are used to signal that an
+     internal header of that name should be removed. those user headers are not
+     added to this list.
+
+     user headers in format 'name;' with no value are used to signal that a
+     header of that name with no value should be sent. those user headers are
+     added to this list but in the format that they will be sent, ie the
+     semi-colon is changed to a colon for format 'name:'.
+
+     user headers with a value of whitespace only, or without a colon or
+     semi-colon, are not added to this list.
+     */
   for(l = data->set.headers; l; l = l->next) {
-    tmp_head = curl_slist_append(head, l->data);
-    if(!tmp_head)
+    char *dupdata, *ptr;
+    char *sep = strchr(l->data, ':');
+    if(!sep)
+      sep = strchr(l->data, ';');
+    if(!sep || (*sep == ':' && !*(sep + 1)))
+      continue;
+    for(ptr = sep + 1; ISSPACE(*ptr); ++ptr)
+      ;
+    if(!*ptr && ptr != sep + 1) /* a value of whitespace only */
+      continue;
+    dupdata = strdup(l->data);
+    if(!dupdata)
       goto fail;
+    dupdata[sep - l->data] = ':';
+    tmp_head = Curl_slist_append_nodup(head, dupdata);
+    if(!tmp_head) {
+      free(dupdata);
+      goto fail;
+    }
     head = tmp_head;
   }
 
@@ -214,23 +245,22 @@ static CURLcode make_headers(struct Curl_easy *data,
     if(!tmp_head)
       goto fail;
     head = tmp_head;
-    *date_header = curl_maprintf("%s: %s", date_hdr_key, timestamp);
+    *date_header = curl_maprintf("%s: %s\r\n", date_hdr_key, timestamp);
   }
   else {
     char *value;
 
-    *date_header = strdup(*date_header);
-    if(!*date_header)
-      goto fail;
-
     value = strchr(*date_header, ':');
-    if(!value)
+    if(!value) {
+      *date_header = NULL;
       goto fail;
+    }
     ++value;
     while(ISBLANK(*value))
       ++value;
     strncpy(timestamp, value, TIMESTAMP_SIZE - 1);
     timestamp[TIMESTAMP_SIZE - 1] = 0;
+    *date_header = NULL;
   }
 
   /* alpha-sort in a case sensitive manner */
@@ -370,9 +400,112 @@ fail:
   return ret;
 }
 
+struct pair {
+  const char *p;
+  size_t len;
+};
+
+static int compare_func(const void *a, const void *b)
+{
+  const struct pair *aa = a;
+  const struct pair *bb = b;
+  return strncmp(aa->p, bb->p, aa->len < bb->len ? aa->len : bb->len);
+}
+
+#define MAX_QUERYPAIRS 64
+
+static CURLcode canon_query(struct Curl_easy *data,
+                            const char *query, struct dynbuf *dq)
+{
+  CURLcode result = CURLE_OK;
+  int entry = 0;
+  int i;
+  const char *p = query;
+  struct pair array[MAX_QUERYPAIRS];
+  struct pair *ap = &array[0];
+  if(!query)
+    return result;
+
+  /* sort the name=value pairs first */
+  do {
+    char *amp;
+    entry++;
+    ap->p = p;
+    amp = strchr(p, '&');
+    if(amp)
+      ap->len = amp - p; /* excluding the ampersand */
+    else {
+      ap->len = strlen(p);
+      break;
+    }
+    ap++;
+    p = amp + 1;
+  } while(entry < MAX_QUERYPAIRS);
+  if(entry == MAX_QUERYPAIRS) {
+    /* too many query pairs for us */
+    failf(data, "aws-sigv4: too many query pairs in URL");
+    return CURLE_URL_MALFORMAT;
+  }
+
+  qsort(&array[0], entry, sizeof(struct pair), compare_func);
+
+  ap = &array[0];
+  for(i = 0; !result && (i < entry); i++, ap++) {
+    size_t len;
+    const char *q = ap->p;
+    if(!ap->len)
+      continue;
+    for(len = ap->len; len && !result; q++, len--) {
+      if(ISALNUM(*q))
+        result = Curl_dyn_addn(dq, q, 1);
+      else {
+        switch(*q) {
+        case '-':
+        case '.':
+        case '_':
+        case '~':
+        case '=':
+          /* allowed as-is */
+          result = Curl_dyn_addn(dq, q, 1);
+          break;
+        case '%':
+          /* uppercase the following if hexadecimal */
+          if(ISXDIGIT(q[1]) && ISXDIGIT(q[2])) {
+            char tmp[3]="%";
+            tmp[1] = Curl_raw_toupper(q[1]);
+            tmp[2] = Curl_raw_toupper(q[2]);
+            result = Curl_dyn_addn(dq, tmp, 3);
+            q += 2;
+            len -= 2;
+          }
+          else
+            /* '%' without a following two-digit hex, encode it */
+            result = Curl_dyn_addn(dq, "%25", 3);
+          break;
+        default: {
+          /* URL encode */
+          const char hex[] = "0123456789ABCDEF";
+          char out[3]={'%'};
+          out[1] = hex[((unsigned char)*q)>>4];
+          out[2] = hex[*q & 0xf];
+          result = Curl_dyn_addn(dq, out, 3);
+          break;
+        }
+        }
+      }
+    }
+    if(i < entry - 1) {
+      /* insert ampersands between query pairs */
+      result = Curl_dyn_addn(dq, "&", 1);
+    }
+  }
+  return result;
+}
+
+
 CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
 {
-  CURLcode ret = CURLE_OUT_OF_MEMORY;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
   struct connectdata *conn = data->conn;
   size_t len;
   const char *arg;
@@ -388,6 +521,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   char date[9];
   struct dynbuf canonical_headers;
   struct dynbuf signed_headers;
+  struct dynbuf canonical_query;
   char *date_header = NULL;
   Curl_HttpReq httpreq;
   const char *method = NULL;
@@ -416,6 +550,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
 
   /* we init those buffers here, so goto fail will free initialized dynbuf */
   Curl_dyn_init(&canonical_headers, CURL_MAX_HTTP_HEADER);
+  Curl_dyn_init(&canonical_query, CURL_MAX_HTTP_HEADER);
   Curl_dyn_init(&signed_headers, CURL_MAX_HTTP_HEADER);
 
   /*
@@ -431,15 +566,15 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   /* provider1[:provider2[:region[:service]]]
 
      No string can be longer than N bytes of non-whitespace
-   */
+  */
   (void)sscanf(arg, "%" MAX_SIGV4_LEN_TXT "[^:]"
                ":%" MAX_SIGV4_LEN_TXT "[^:]"
                ":%" MAX_SIGV4_LEN_TXT "[^:]"
                ":%" MAX_SIGV4_LEN_TXT "s",
                provider0, provider1, region, service);
   if(!provider0[0]) {
-    failf(data, "first provider can't be empty");
-    ret = CURLE_BAD_FUNCTION_ARGUMENT;
+    failf(data, "first aws-sigv4 provider can't be empty");
+    result = CURLE_BAD_FUNCTION_ARGUMENT;
     goto fail;
   }
   else if(!provider1[0])
@@ -448,35 +583,38 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   if(!service[0]) {
     char *hostdot = strchr(hostname, '.');
     if(!hostdot) {
-      failf(data, "service missing in parameters and hostname");
-      ret = CURLE_URL_MALFORMAT;
+      failf(data, "aws-sigv4: service missing in parameters and hostname");
+      result = CURLE_URL_MALFORMAT;
       goto fail;
     }
     len = hostdot - hostname;
     if(len > MAX_SIGV4_LEN) {
-      failf(data, "service too long in hostname");
-      ret = CURLE_URL_MALFORMAT;
+      failf(data, "aws-sigv4: service too long in hostname");
+      result = CURLE_URL_MALFORMAT;
       goto fail;
     }
     strncpy(service, hostname, len);
     service[len] = '\0';
 
+    infof(data, "aws_sigv4: picked service %s from host", service);
+
     if(!region[0]) {
       const char *reg = hostdot + 1;
       const char *hostreg = strchr(reg, '.');
       if(!hostreg) {
-        failf(data, "region missing in parameters and hostname");
-        ret = CURLE_URL_MALFORMAT;
+        failf(data, "aws-sigv4: region missing in parameters and hostname");
+        result = CURLE_URL_MALFORMAT;
         goto fail;
       }
       len = hostreg - reg;
       if(len > MAX_SIGV4_LEN) {
-        failf(data, "region too long in hostname");
-        ret = CURLE_URL_MALFORMAT;
+        failf(data, "aws-sigv4: region too long in hostname");
+        result = CURLE_URL_MALFORMAT;
         goto fail;
       }
       strncpy(region, reg, len);
       region[len] = '\0';
+      infof(data, "aws_sigv4: picked region %s from host", region);
     }
   }
 
@@ -491,11 +629,11 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
 
   if(!payload_hash) {
     if(sign_as_s3)
-      ret = calc_s3_payload_hash(data, httpreq, provider1, sha_hash,
-                                 sha_hex, content_sha256_hdr);
+      result = calc_s3_payload_hash(data, httpreq, provider1, sha_hash,
+                                    sha_hex, content_sha256_hdr);
     else
-      ret = calc_payload_hash(data, sha_hash, sha_hex);
-    if(ret)
+      result = calc_payload_hash(data, sha_hash, sha_hex);
+    if(result)
       goto fail;
 
     payload_hash = sha_hex;
@@ -514,21 +652,20 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
 #else
   time(&clock);
 #endif
-  ret = Curl_gmtime(clock, &tm);
-  if(ret) {
+  result = Curl_gmtime(clock, &tm);
+  if(result) {
     goto fail;
   }
   if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
-    ret = CURLE_OUT_OF_MEMORY;
+    result = CURLE_OUT_OF_MEMORY;
     goto fail;
   }
 
-  ret = make_headers(data, hostname, timestamp, provider1,
-                     &date_header, content_sha256_hdr,
-                     &canonical_headers, &signed_headers);
-  if(ret)
+  result = make_headers(data, hostname, timestamp, provider1,
+                        &date_header, content_sha256_hdr,
+                        &canonical_headers, &signed_headers);
+  if(result)
     goto fail;
-  ret = CURLE_OUT_OF_MEMORY;
 
   if(*content_sha256_hdr) {
     /* make_headers() needed this without the \r\n for canonicalization */
@@ -540,6 +677,11 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   memcpy(date, timestamp, sizeof(date));
   date[sizeof(date) - 1] = 0;
 
+  result = canon_query(data, data->state.up.query, &canonical_query);
+  if(result)
+    goto fail;
+  result = CURLE_OUT_OF_MEMORY;
+
   canonical_request =
     curl_maprintf("%s\n" /* HTTPRequestMethod */
                   "%s\n" /* CanonicalURI */
@@ -549,13 +691,16 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
                   "%.*s",  /* HashedRequestPayload in hex */
                   method,
                   data->state.up.path,
-                  data->state.up.query ? data->state.up.query : "",
+                  Curl_dyn_ptr(&canonical_query) ?
+                  Curl_dyn_ptr(&canonical_query) : "",
                   Curl_dyn_ptr(&canonical_headers),
                   Curl_dyn_ptr(&signed_headers),
                   (int)payload_hash_len, payload_hash);
   if(!canonical_request)
     goto fail;
 
+  DEBUGF(infof(data, "Canonical request: %s", canonical_request));
+
   /* provider 0 lowercase */
   Curl_strntolower(provider0, provider0, strlen(provider0));
   request_type = curl_maprintf("%s4_request", provider0);
@@ -612,14 +757,19 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
                                "Credential=%s/%s, "
                                "SignedHeaders=%s, "
                                "Signature=%s\r\n"
-                               "%s\r\n"
+                               /*
+                                * date_header is added here, only if it wasn't
+                                * user-specified (using CURLOPT_HTTPHEADER).
+                                * date_header includes \r\n
+                                */
+                               "%s"
                                "%s", /* optional sha256 header includes \r\n */
                                provider0,
                                user,
                                credential_scope,
                                Curl_dyn_ptr(&signed_headers),
                                sha_hex,
-                               date_header,
+                               date_header ? date_header : "",
                                content_sha256_hdr);
   if(!auth_headers) {
     goto fail;
@@ -628,9 +778,10 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   Curl_safefree(data->state.aptr.userpwd);
   data->state.aptr.userpwd = auth_headers;
   data->state.authhost.done = TRUE;
-  ret = CURLE_OK;
+  result = CURLE_OK;
 
 fail:
+  Curl_dyn_free(&canonical_query);
   Curl_dyn_free(&canonical_headers);
   Curl_dyn_free(&signed_headers);
   free(canonical_request);
@@ -639,7 +790,7 @@ fail:
   free(str_to_sign);
   free(secret);
   free(date_header);
-  return ret;
+  return result;
 }
 
-#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) */
+#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */

+ 1 - 1
lib/http_digest.c

@@ -24,7 +24,7 @@
 
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
 
 #include "urldata.h"
 #include "strcase.h"

+ 2 - 2
lib/http_digest.h

@@ -25,7 +25,7 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
 
 /* this is for digest header input */
 CURLcode Curl_input_digest(struct Curl_easy *data,
@@ -39,6 +39,6 @@ CURLcode Curl_output_digest(struct Curl_easy *data,
 
 void Curl_http_auth_cleanup_digest(struct Curl_easy *data);
 
-#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_CRYPTO_AUTH */
+#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_DIGEST_AUTH */
 
 #endif /* HEADER_CURL_HTTP_DIGEST_H */

+ 6 - 6
lib/http_proxy.c

@@ -69,7 +69,7 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf,
     return CURLE_OK;
   }
 
-  DEBUGF(LOG_CF(data, cf, "connect"));
+  CURL_TRC_CF(data, cf, "connect");
 connect_sub:
   result = cf->next->cft->do_connect(cf->next, data, blocking, done);
   if(result || !*done)
@@ -86,7 +86,7 @@ connect_sub:
     case CURL_HTTP_VERSION_NONE:
     case CURL_HTTP_VERSION_1_0:
     case CURL_HTTP_VERSION_1_1:
-      DEBUGF(LOG_CF(data, cf, "installing subfilter for HTTP/1.1"));
+      CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.1");
       infof(data, "CONNECT tunnel: HTTP/1.%d negotiated",
             (alpn == CURL_HTTP_VERSION_1_0)? 0 : 1);
       result = Curl_cf_h1_proxy_insert_after(cf, data);
@@ -96,7 +96,7 @@ connect_sub:
       break;
 #ifdef USE_NGHTTP2
     case CURL_HTTP_VERSION_2:
-      DEBUGF(LOG_CF(data, cf, "installing subfilter for HTTP/2"));
+      CURL_TRC_CF(data, cf, "installing subfilter for HTTP/2");
       infof(data, "CONNECT tunnel: HTTP/2 negotiated");
       result = Curl_cf_h2_proxy_insert_after(cf, data);
       if(result)
@@ -105,7 +105,7 @@ connect_sub:
       break;
 #endif
     default:
-      DEBUGF(LOG_CF(data, cf, "installing subfilter for default HTTP/1.1"));
+      CURL_TRC_CF(data, cf, "installing subfilter for default HTTP/1.1");
       infof(data, "CONNECT tunnel: unsupported ALPN(%d) negotiated", alpn);
       result = CURLE_COULDNT_CONNECT;
       goto out;
@@ -156,7 +156,7 @@ static void http_proxy_cf_destroy(struct Curl_cfilter *cf,
   struct cf_proxy_ctx *ctx = cf->ctx;
 
   (void)data;
-  DEBUGF(LOG_CF(data, cf, "destroy"));
+  CURL_TRC_CF(data, cf, "destroy");
   free(ctx);
 }
 
@@ -165,7 +165,7 @@ static void http_proxy_cf_close(struct Curl_cfilter *cf,
 {
   struct cf_proxy_ctx *ctx = cf->ctx;
 
-  DEBUGF(LOG_CF(data, cf, "close"));
+  CURL_TRC_CF(data, cf, "close");
   cf->connected = FALSE;
   if(ctx->cf_protocol) {
     struct Curl_cfilter *f;

+ 100 - 20
lib/idn.c

@@ -68,27 +68,59 @@ WINBASEAPI int WINAPI IdnToUnicode(DWORD dwFlags,
 
 #define IDN_MAX_LENGTH 255
 
-bool Curl_win32_idn_to_ascii(const char *in, char **out)
+static CURLcode win32_idn_to_ascii(const char *in, char **out)
 {
-  bool success = FALSE;
-
   wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
+  *out = NULL;
   if(in_w) {
     wchar_t punycode[IDN_MAX_LENGTH];
-    int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
+    int chars = IdnToAscii(0, in_w, (int)(wcslen(in_w) + 1), punycode,
+                           IDN_MAX_LENGTH);
     curlx_unicodefree(in_w);
     if(chars) {
       char *mstr = curlx_convert_wchar_to_UTF8(punycode);
       if(mstr) {
         *out = strdup(mstr);
         curlx_unicodefree(mstr);
-        if(*out)
-          success = TRUE;
+        if(!*out)
+          return CURLE_OUT_OF_MEMORY;
       }
+      else
+        return CURLE_OUT_OF_MEMORY;
     }
+    else
+      return CURLE_URL_MALFORMAT;
   }
 
-  return success;
+  return CURLE_OK;
+}
+
+static CURLcode win32_ascii_to_idn(const char *in, char **output)
+{
+  char *out = NULL;
+
+  wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
+  if(in_w) {
+    WCHAR idn[IDN_MAX_LENGTH]; /* stores a UTF-16 string */
+    int chars = IdnToUnicode(0, in_w, (int)(wcslen(in_w) + 1), idn,
+                             IDN_MAX_LENGTH);
+    if(chars) {
+      /* 'chars' is "the number of characters retrieved" */
+      char *mstr = curlx_convert_wchar_to_UTF8(idn);
+      if(mstr) {
+        out = strdup(mstr);
+        curlx_unicodefree(mstr);
+        if(!out)
+          return CURLE_OUT_OF_MEMORY;
+      }
+    }
+    else
+      return CURLE_URL_MALFORMAT;
+  }
+  else
+    return CURLE_URL_MALFORMAT;
+  *output = out;
+  return CURLE_OK;
 }
 
 #endif /* USE_WIN32_IDN */
@@ -115,10 +147,15 @@ bool Curl_is_ASCII_name(const char *hostname)
 /*
  * Curl_idn_decode() returns an allocated IDN decoded string if it was
  * possible. NULL on error.
+ *
+ * CURLE_URL_MALFORMAT - the host name could not be converted
+ * CURLE_OUT_OF_MEMORY - memory problem
+ *
  */
-static char *idn_decode(const char *input)
+static CURLcode idn_decode(const char *input, char **output)
 {
   char *decoded = NULL;
+  CURLcode result = CURLE_OK;
 #ifdef USE_LIBIDN2
   if(idn2_check_version(IDN2_VERSION)) {
     int flags = IDN2_NFC_INPUT
@@ -135,26 +172,68 @@ static char *idn_decode(const char *input)
          compatibility */
       rc = IDN2_LOOKUP(input, &decoded, IDN2_TRANSITIONAL);
     if(rc != IDN2_OK)
-      decoded = NULL;
+      result = CURLE_URL_MALFORMAT;
   }
 #elif defined(USE_WIN32_IDN)
-  if(!Curl_win32_idn_to_ascii(input, &decoded))
-    decoded = NULL;
+  result = win32_idn_to_ascii(input, &decoded);
+#endif
+  if(!result)
+    *output = decoded;
+  return result;
+}
+
+static CURLcode idn_encode(const char *puny, char **output)
+{
+  char *enc = NULL;
+#ifdef USE_LIBIDN2
+  int rc = idn2_to_unicode_8z8z(puny, &enc, 0);
+  if(rc != IDNA_SUCCESS)
+    return rc == IDNA_MALLOC_ERROR ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT;
+#elif defined(USE_WIN32_IDN)
+  CURLcode result = win32_ascii_to_idn(puny, &enc);
+  if(result)
+    return result;
 #endif
-  return decoded;
+  *output = enc;
+  return CURLE_OK;
 }
 
-char *Curl_idn_decode(const char *input)
+CURLcode Curl_idn_decode(const char *input, char **output)
 {
-  char *d = idn_decode(input);
+  char *d = NULL;
+  CURLcode result = idn_decode(input, &d);
 #ifdef USE_LIBIDN2
-  if(d) {
+  if(!result) {
     char *c = strdup(d);
     idn2_free(d);
-    d = c;
+    if(c)
+      d = c;
+    else
+      result = CURLE_OUT_OF_MEMORY;
   }
 #endif
-  return d;
+  if(!result)
+    *output = d;
+  return result;
+}
+
+CURLcode Curl_idn_encode(const char *puny, char **output)
+{
+  char *d = NULL;
+  CURLcode result = idn_encode(puny, &d);
+#ifdef USE_LIBIDN2
+  if(!result) {
+    char *c = strdup(d);
+    idn2_free(d);
+    if(c)
+      d = c;
+    else
+      result = CURLE_OUT_OF_MEMORY;
+  }
+#endif
+  if(!result)
+    *output = d;
+  return result;
 }
 
 /*
@@ -182,8 +261,9 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host)
 #ifdef USE_IDN
   /* Check name for non-ASCII and convert hostname if we can */
   if(!Curl_is_ASCII_name(host->name)) {
-    char *decoded = idn_decode(host->name);
-    if(decoded) {
+    char *decoded;
+    CURLcode result = idn_decode(host->name, &decoded);
+    if(!result) {
       if(!*decoded) {
         /* zero length is a bad host name */
         Curl_idn_free(decoded);
@@ -195,7 +275,7 @@ CURLcode Curl_idnconvert_hostname(struct hostname *host)
       host->name = host->encalloc;
     }
     else
-      return CURLE_URL_MALFORMAT;
+      return result;
   }
 #endif
   return CURLE_OK;

+ 2 - 4
lib/idn.h

@@ -24,15 +24,13 @@
  *
  ***************************************************************************/
 
-#ifdef USE_WIN32_IDN
-bool Curl_win32_idn_to_ascii(const char *in, char **out);
-#endif /* USE_WIN32_IDN */
 bool Curl_is_ASCII_name(const char *hostname);
 CURLcode Curl_idnconvert_hostname(struct hostname *host);
 #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN)
 #define USE_IDN
 void Curl_free_idnconverted_hostname(struct hostname *host);
-char *Curl_idn_decode(const char *input);
+CURLcode Curl_idn_decode(const char *input, char **output);
+CURLcode Curl_idn_encode(const char *input, char **output);
 #ifdef USE_LIBIDN2
 #define Curl_idn_free(x) idn2_free(x)
 #else

+ 4 - 0
lib/if2ip.c

@@ -92,6 +92,8 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
 }
 #endif
 
+#ifndef CURL_DISABLE_BINDLOCAL
+
 #if defined(HAVE_GETIFADDRS)
 
 if2ip_result_t Curl_if2ip(int af,
@@ -254,3 +256,5 @@ if2ip_result_t Curl_if2ip(int af,
 }
 
 #endif
+
+#endif /* CURL_DISABLE_BINDLOCAL */

+ 35 - 68
lib/imap.c

@@ -45,9 +45,6 @@
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
-#ifdef HAVE_UTSNAME_H
-#include <sys/utsname.h>
-#endif
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
@@ -1094,10 +1091,19 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
 
   if(imapcode == '*') {
     /* See if this is an UIDVALIDITY response */
-    char tmp[20];
-    if(sscanf(line + 2, "OK [UIDVALIDITY %19[0123456789]]", tmp) == 1) {
-      Curl_safefree(imapc->mailbox_uidvalidity);
-      imapc->mailbox_uidvalidity = strdup(tmp);
+    if(checkprefix("OK [UIDVALIDITY ", line + 2)) {
+      size_t len = 0;
+      const char *p = &line[2] + strlen("OK [UIDVALIDITY ");
+      while((len < 20) && p[len] && ISDIGIT(p[len]))
+        len++;
+      if(len && (p[len] == ']')) {
+        struct dynbuf uid;
+        Curl_dyn_init(&uid, 20);
+        if(Curl_dyn_addn(&uid, p, len))
+          return CURLE_OUT_OF_MEMORY;
+        Curl_safefree(imapc->mailbox_uidvalidity);
+        imapc->mailbox_uidvalidity = Curl_dyn_ptr(&uid);
+      }
     }
   }
   else if(imapcode == IMAP_RESP_OK) {
@@ -1109,7 +1115,10 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, int imapcode,
     }
     else {
       /* Note the currently opened mailbox on this connection */
+      DEBUGASSERT(!imapc->mailbox);
       imapc->mailbox = strdup(imap->mailbox);
+      if(!imapc->mailbox)
+        return CURLE_OUT_OF_MEMORY;
 
       if(imap->custom)
         result = imap_perform_list(data);
@@ -1806,79 +1815,37 @@ static CURLcode imap_sendf(struct Curl_easy *data, const char *fmt, ...)
  */
 static char *imap_atom(const char *str, bool escape_only)
 {
-  /* !checksrc! disable PARENBRACE 1 */
-  const char atom_specials[] = "(){ %*]";
-  const char *p1;
-  char *p2;
-  size_t backsp_count = 0;
-  size_t quote_count = 0;
-  bool others_exists = FALSE;
-  size_t newlen = 0;
-  char *newstr = NULL;
+  struct dynbuf line;
+  size_t nclean;
+  size_t len;
 
   if(!str)
     return NULL;
 
-  /* Look for "atom-specials", counting the backslash and quote characters as
-     these will need escaping */
-  p1 = str;
-  while(*p1) {
-    if(*p1 == '\\')
-      backsp_count++;
-    else if(*p1 == '"')
-      quote_count++;
-    else if(!escape_only) {
-      const char *p3 = atom_specials;
-
-      while(*p3 && !others_exists) {
-        if(*p1 == *p3)
-          others_exists = TRUE;
-
-        p3++;
-      }
-    }
-
-    p1++;
-  }
-
-  /* Does the input contain any "atom-special" characters? */
-  if(!backsp_count && !quote_count && !others_exists)
+  len = strlen(str);
+  nclean = strcspn(str, "() {%*]\\\"");
+  if(len == nclean)
+    /* nothing to escape, return a strdup */
     return strdup(str);
 
-  /* Calculate the new string length */
-  newlen = strlen(str) + backsp_count + quote_count + (escape_only ? 0 : 2);
+  Curl_dyn_init(&line, 2000);
 
-  /* Allocate the new string */
-  newstr = (char *) malloc((newlen + 1) * sizeof(char));
-  if(!newstr)
+  if(!escape_only && Curl_dyn_addn(&line, "\"", 1))
     return NULL;
 
-  /* Surround the string in quotes if necessary */
-  p2 = newstr;
-  if(!escape_only) {
-    newstr[0] = '"';
-    newstr[newlen - 1] = '"';
-    p2++;
+  while(*str) {
+    if((*str == '\\' || *str == '"') &&
+       Curl_dyn_addn(&line, "\\", 1))
+      return NULL;
+    if(Curl_dyn_addn(&line, str, 1))
+      return NULL;
+    str++;
   }
 
-  /* Copy the string, escaping backslash and quote characters along the way */
-  p1 = str;
-  while(*p1) {
-    if(*p1 == '\\' || *p1 == '"') {
-      *p2 = '\\';
-      p2++;
-    }
-
-   *p2 = *p1;
-
-    p1++;
-    p2++;
-  }
-
-  /* Terminate the string */
-  newstr[newlen] = '\0';
+  if(!escape_only && Curl_dyn_addn(&line, "\"", 1))
+    return NULL;
 
-  return newstr;
+  return Curl_dyn_ptr(&line);
 }
 
 /***********************************************************************

+ 3 - 2
lib/inet_ntop.c

@@ -117,8 +117,9 @@ static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
 
   for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
     if(words[i] == 0) {
-      if(cur.base == -1)
-        cur.base = i, cur.len = 1;
+      if(cur.base == -1) {
+        cur.base = i; cur.len = 1;
+      }
       else
         cur.len++;
     }

+ 6 - 7
lib/krb5.c

@@ -72,7 +72,7 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
   char *sptr = s;
   CURLcode result = CURLE_OK;
 #ifdef HAVE_GSSAPI
-  enum protection_level data_sec = conn->data_prot;
+  unsigned char data_sec = conn->data_prot;
 #endif
 
   if(!cmd)
@@ -91,7 +91,7 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
 #ifdef HAVE_GSSAPI
     conn->data_prot = PROT_CMD;
 #endif
-    result = Curl_write(data, conn->sock[FIRSTSOCKET], sptr, write_len,
+    result = Curl_nwrite(data, FIRSTSOCKET, sptr, write_len,
                         &bytes_written);
 #ifdef HAVE_GSSAPI
     DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
@@ -385,7 +385,7 @@ static const struct Curl_sec_client_mech Curl_krb5_client_mech = {
 };
 
 static const struct {
-  enum protection_level level;
+  unsigned char level;
   const char *name;
 } level_names[] = {
   { PROT_CLEAR, "clear" },
@@ -394,8 +394,7 @@ static const struct {
   { PROT_PRIVATE, "private" }
 };
 
-static enum protection_level
-name_to_level(const char *name)
+static unsigned char name_to_level(const char *name)
 {
   int i;
   for(i = 0; i < (int)sizeof(level_names)/(int)sizeof(level_names[0]); i++)
@@ -734,7 +733,7 @@ static int sec_set_protection_level(struct Curl_easy *data)
 {
   int code;
   struct connectdata *conn = data->conn;
-  enum protection_level level = conn->request_data_prot;
+  unsigned char level = conn->request_data_prot;
 
   DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
 
@@ -793,7 +792,7 @@ static int sec_set_protection_level(struct Curl_easy *data)
 int
 Curl_sec_request_prot(struct connectdata *conn, const char *level)
 {
-  enum protection_level l = name_to_level(level);
+  unsigned char l = name_to_level(level);
   if(l == PROT_NONE)
     return -1;
   DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);

+ 2 - 2
lib/ldap.c

@@ -239,7 +239,7 @@ static int ldap_win_bind_auth(LDAP *server, const char *user,
   }
   else
 #endif
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if !defined(CURL_DISABLE_DIGEST_AUTH)
   if(authflags & CURLAUTH_DIGEST) {
     method = LDAP_AUTH_DIGEST;
   }
@@ -762,7 +762,7 @@ quit:
 
   /* no data to transfer */
   Curl_setup_transfer(data, -1, -1, FALSE, -1);
-  connclose(conn, "LDAP connection always disable re-use");
+  connclose(conn, "LDAP connection always disable reuse");
 
   return result;
 }

+ 5 - 12
lib/macos.c

@@ -24,21 +24,16 @@
 
 #include "curl_setup.h"
 
-#if defined(__APPLE__)
-
-#if !defined(TARGET_OS_OSX) || TARGET_OS_OSX
+#ifdef CURL_MACOS_CALL_COPYPROXIES
 
 #include <curl/curl.h>
 
 #include "macos.h"
 
-#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
 #include <SystemConfiguration/SCDynamicStoreCopySpecific.h>
-#endif
 
 CURLcode Curl_macos_init(void)
 {
-#if defined(ENABLE_IPV6) && defined(CURL_OSX_CALL_COPYPROXIES)
   {
     /*
      * The automagic conversion from IPv4 literals to IPv6 literals only
@@ -46,17 +41,15 @@ CURLcode Curl_macos_init(void)
      * 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.
+     * This function is only available on macOS and is not needed for
+     * IPv4-only builds, hence the conditions for defining
+     * CURL_MACOS_CALL_COPYPROXIES in curl_setup.h.
      */
     CFDictionaryRef dict = SCDynamicStoreCopyProxies(NULL);
     if(dict)
       CFRelease(dict);
   }
-#endif
   return CURLE_OK;
 }
 
-#endif /* TARGET_OS_OSX */
-
-#endif /* __APPLE__ */
+#endif

+ 2 - 1
lib/macos.h

@@ -23,9 +23,10 @@
  * SPDX-License-Identifier: curl
  *
  ***************************************************************************/
+
 #include "curl_setup.h"
 
-#if defined(__APPLE__) && (!defined(TARGET_OS_OSX) || TARGET_OS_OSX)
+#ifdef CURL_MACOS_CALL_COPYPROXIES
 
 CURLcode Curl_macos_init(void);
 

+ 30 - 12
lib/md4.c

@@ -42,6 +42,7 @@
 
 #ifdef USE_WOLFSSL
 #include <wolfssl/options.h>
+#define VOID_MD4_INIT
 #ifdef NO_MD4
 #define WOLFSSL_NO_MD4
 #endif
@@ -92,9 +93,10 @@
 
 typedef struct md4_ctx MD4_CTX;
 
-static void MD4_Init(MD4_CTX *ctx)
+static int MD4_Init(MD4_CTX *ctx)
 {
   md4_init(ctx);
+  return 1;
 }
 
 static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
@@ -114,9 +116,9 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
 #elif defined(AN_APPLE_OS)
 typedef CC_MD4_CTX MD4_CTX;
 
-static void MD4_Init(MD4_CTX *ctx)
+static int MD4_Init(MD4_CTX *ctx)
 {
-  (void)CC_MD4_Init(ctx);
+  return CC_MD4_Init(ctx);
 }
 
 static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
@@ -137,15 +139,22 @@ struct md4_ctx {
 };
 typedef struct md4_ctx MD4_CTX;
 
-static void MD4_Init(MD4_CTX *ctx)
+static int MD4_Init(MD4_CTX *ctx)
 {
   ctx->hCryptProv = 0;
   ctx->hHash = 0;
 
-  if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
-                         CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
-    CryptCreateHash(ctx->hCryptProv, CALG_MD4, 0, 0, &ctx->hHash);
+  if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
+                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    return 0;
+
+  if(!CryptCreateHash(ctx->hCryptProv, CALG_MD4, 0, 0, &ctx->hHash)) {
+    CryptReleaseContext(ctx->hCryptProv, 0);
+    ctx->hCryptProv = 0;
+    return 0;
   }
+
+  return 1;
 }
 
 static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
@@ -176,10 +185,11 @@ struct md4_ctx {
 };
 typedef struct md4_ctx MD4_CTX;
 
-static void MD4_Init(MD4_CTX *ctx)
+static int MD4_Init(MD4_CTX *ctx)
 {
   ctx->data = NULL;
   ctx->size = 0;
+  return 1;
 }
 
 static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
@@ -258,7 +268,7 @@ struct md4_ctx {
 };
 typedef struct md4_ctx MD4_CTX;
 
-static void MD4_Init(MD4_CTX *ctx);
+static int MD4_Init(MD4_CTX *ctx);
 static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size);
 static void MD4_Final(unsigned char *result, MD4_CTX *ctx);
 
@@ -397,7 +407,7 @@ static const void *body(MD4_CTX *ctx, const void *data, unsigned long size)
   return ptr;
 }
 
-static void MD4_Init(MD4_CTX *ctx)
+static int MD4_Init(MD4_CTX *ctx)
 {
   ctx->a = 0x67452301;
   ctx->b = 0xefcdab89;
@@ -406,6 +416,7 @@ static void MD4_Init(MD4_CTX *ctx)
 
   ctx->lo = 0;
   ctx->hi = 0;
+  return 1;
 }
 
 static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size)
@@ -496,14 +507,21 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
 
 #endif /* CRYPTO LIBS */
 
-void Curl_md4it(unsigned char *output, const unsigned char *input,
-                const size_t len)
+CURLcode Curl_md4it(unsigned char *output, const unsigned char *input,
+                    const size_t len)
 {
   MD4_CTX ctx;
 
+#ifdef VOID_MD4_INIT
   MD4_Init(&ctx);
+#else
+  if(!MD4_Init(&ctx))
+    return CURLE_FAILED_INIT;
+#endif
+
   MD4_Update(&ctx, input, curlx_uztoui(len));
   MD4_Final(output, &ctx);
+  return CURLE_OK;
 }
 
 #endif /* USE_CURL_NTLM_CORE */

+ 5 - 3
lib/md5.c

@@ -24,7 +24,8 @@
 
 #include "curl_setup.h"
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \
+    || !defined(CURL_DISABLE_DIGEST_AUTH)
 
 #include <string.h>
 #include <curl/curl.h>
@@ -213,7 +214,8 @@ static CURLcode my_md5_init(my_md5_ctx *ctx)
 
   if(!CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash)) {
     CryptReleaseContext(ctx->hCryptProv, 0);
-    return CURLE_OUT_OF_MEMORY;
+    ctx->hCryptProv = 0;
+    return CURLE_FAILED_INIT;
   }
 
   return CURLE_OK;
@@ -651,4 +653,4 @@ CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result)
   return CURLE_OK;
 }
 
-#endif /* CURL_DISABLE_CRYPTO_AUTH */
+#endif /* Using NTLM (without SSPI) || Digest */

+ 10 - 8
lib/mime.c

@@ -1167,14 +1167,16 @@ static void mime_subparts_unbind(void *ptr)
 
 void Curl_mime_cleanpart(curl_mimepart *part)
 {
-  cleanup_part_content(part);
-  curl_slist_free_all(part->curlheaders);
-  if(part->flags & MIME_USERHEADERS_OWNER)
-    curl_slist_free_all(part->userheaders);
-  Curl_safefree(part->mimetype);
-  Curl_safefree(part->name);
-  Curl_safefree(part->filename);
-  Curl_mime_initpart(part);
+  if(part) {
+    cleanup_part_content(part);
+    curl_slist_free_all(part->curlheaders);
+    if(part->flags & MIME_USERHEADERS_OWNER)
+      curl_slist_free_all(part->userheaders);
+    Curl_safefree(part->mimetype);
+    Curl_safefree(part->name);
+    Curl_safefree(part->filename);
+    Curl_mime_initpart(part);
+  }
 }
 
 /* Recursively delete a mime handle and its parts. */

+ 1 - 3
lib/mqtt.c

@@ -117,11 +117,9 @@ static CURLcode mqtt_send(struct Curl_easy *data,
                           char *buf, size_t len)
 {
   CURLcode result = CURLE_OK;
-  struct connectdata *conn = data->conn;
-  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   struct MQTT *mq = data->req.p.mqtt;
   ssize_t n;
-  result = Curl_write(data, sockfd, buf, len, &n);
+  result = Curl_nwrite(data, FIRSTSOCKET, buf, len, &n);
   if(result)
     return result;
   Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);

+ 69 - 83
lib/multi.c

@@ -459,7 +459,7 @@ struct Curl_multi *curl_multi_init(void)
                            CURL_DNS_HASH_SIZE);
 }
 
-#ifdef DEBUGBUILD
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
 static void multi_warn_debug(struct Curl_multi *multi, struct Curl_easy *data)
 {
   if(!multi->warned) {
@@ -638,7 +638,6 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
   CONNCACHE_UNLOCK(data);
 
   multi_warn_debug(multi, data);
-  infof(data, "processing: %s", data->state.url);
 
   return CURLM_OK;
 }
@@ -668,8 +667,14 @@ static CURLcode multi_done(struct Curl_easy *data,
   struct connectdata *conn = data->conn;
   unsigned int i;
 
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  DEBUGF(infof(data, "multi_done[%s]: status: %d prem: %d done: %d",
+               multi_statename[data->mstate],
+               (int)status, (int)premature, data->state.done));
+#else
   DEBUGF(infof(data, "multi_done: status: %d prem: %d done: %d",
                (int)status, (int)premature, data->state.done));
+#endif
 
   if(data->state.done)
     /* Stop if multi_done() has already been called */
@@ -752,7 +757,7 @@ static CURLcode multi_done(struct Curl_easy *data,
 
      if premature is TRUE, it means this connection was said to be DONE before
      the entire request operation is complete and thus we can't know in what
-     state it is for re-using, so we're forced to close it. In a perfect world
+     state it is for reusing, so we're forced to close it. In a perfect world
      we can add code that keep track of if we really must close it here or not,
      but currently we have no such detail knowledge.
   */
@@ -769,7 +774,7 @@ static CURLcode multi_done(struct Curl_easy *data,
 #endif
      ) || conn->bits.close
        || (premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) {
-    DEBUGF(infof(data, "multi_done, not re-using connection=%"
+    DEBUGF(infof(data, "multi_done, not reusing connection=%"
                        CURL_FORMAT_CURL_OFF_T ", forbid=%d"
                        ", close=%d, premature=%d, conn_multiplex=%d",
                  conn->connection_id,
@@ -1105,8 +1110,7 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
   if(multi->in_callback)
     return CURLM_RECURSIVE_API_CALL;
 
-  data = multi->easyp;
-  while(data) {
+  for(data = multi->easyp; data; data = data->next) {
     int bitmap;
 #ifdef __clang_analyzer_
     /* to prevent "The left operand of '>=' is a garbage value" warnings */
@@ -1115,30 +1119,21 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
     bitmap = multi_getsock(data, sockbunch);
 
     for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
-      curl_socket_t s = CURL_SOCKET_BAD;
-
-      if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK(sockbunch[i])) {
-        if(!FDSET_SOCK(sockbunch[i]))
-          /* pretend it doesn't exist */
-          continue;
-        FD_SET(sockbunch[i], read_fd_set);
-        s = sockbunch[i];
-      }
-      if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK(sockbunch[i])) {
+      if((bitmap & GETSOCK_MASK_RW(i)) && VALID_SOCK((sockbunch[i]))) {
         if(!FDSET_SOCK(sockbunch[i]))
           /* pretend it doesn't exist */
           continue;
-        FD_SET(sockbunch[i], write_fd_set);
-        s = sockbunch[i];
+        if(bitmap & GETSOCK_READSOCK(i))
+          FD_SET(sockbunch[i], read_fd_set);
+        if(bitmap & GETSOCK_WRITESOCK(i))
+          FD_SET(sockbunch[i], write_fd_set);
+        if((int)sockbunch[i] > this_max_fd)
+          this_max_fd = (int)sockbunch[i];
       }
-      if(s == CURL_SOCKET_BAD)
-        /* this socket is unused, break out of loop */
+      else {
         break;
-      if((int)s > this_max_fd)
-        this_max_fd = (int)s;
+      }
     }
-
-    data = data->next; /* check next handle */
   }
 
   *max_fd = this_max_fd;
@@ -1201,27 +1196,17 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
     return CURLM_BAD_FUNCTION_ARGUMENT;
 
   /* Count up how many fds we have from the multi handle */
-  data = multi->easyp;
-  while(data) {
+  for(data = multi->easyp; data; data = data->next) {
     bitmap = multi_getsock(data, sockbunch);
 
-    for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
-      curl_socket_t s = CURL_SOCKET_BAD;
-
-      if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
-        ++nfds;
-        s = sockbunch[i];
-      }
-      if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+    for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
+      if((bitmap & GETSOCK_MASK_RW(i)) && VALID_SOCK((sockbunch[i]))) {
         ++nfds;
-        s = sockbunch[i];
       }
-      if(s == CURL_SOCKET_BAD) {
+      else {
         break;
       }
     }
-
-    data = data->next; /* check next handle */
   }
 
   /* If the internally desired timeout is actually shorter than requested from
@@ -1261,49 +1246,42 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
 
   if(curlfds) {
     /* Add the curl handles to our pollfds first */
-    data = multi->easyp;
-    while(data) {
+    for(data = multi->easyp; data; data = data->next) {
       bitmap = multi_getsock(data, sockbunch);
 
       for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
-        curl_socket_t s = CURL_SOCKET_BAD;
+        if((bitmap & GETSOCK_MASK_RW(i)) && VALID_SOCK((sockbunch[i]))) {
+          struct pollfd *ufd = &ufds[nfds++];
 #ifdef USE_WINSOCK
-        long mask = 0;
+          long mask = 0;
 #endif
-        if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
-          s = sockbunch[i];
+          ufd->fd = sockbunch[i];
+          ufd->events = 0;
+          if(bitmap & GETSOCK_READSOCK(i)) {
 #ifdef USE_WINSOCK
-          mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+            mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
 #endif
-          ufds[nfds].fd = s;
-          ufds[nfds].events = POLLIN;
-          ++nfds;
-        }
-        if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
-          s = sockbunch[i];
+            ufd->events |= POLLIN;
+          }
+          if(bitmap & GETSOCK_WRITESOCK(i)) {
+#ifdef USE_WINSOCK
+            mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+            reset_socket_fdwrite(sockbunch[i]);
+#endif
+            ufd->events |= POLLOUT;
+          }
 #ifdef USE_WINSOCK
-          mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
-          reset_socket_fdwrite(s);
+          if(WSAEventSelect(sockbunch[i], multi->wsa_event, mask) != 0) {
+            if(ufds_malloc)
+              free(ufds);
+            return CURLM_INTERNAL_ERROR;
+          }
 #endif
-          ufds[nfds].fd = s;
-          ufds[nfds].events = POLLOUT;
-          ++nfds;
         }
-        /* s is only set if either being readable or writable is checked */
-        if(s == CURL_SOCKET_BAD) {
-          /* break on entry not checked for being readable or writable */
+        else {
           break;
         }
-#ifdef USE_WINSOCK
-        if(WSAEventSelect(s, multi->wsa_event, mask) != 0) {
-          if(ufds_malloc)
-            free(ufds);
-          return CURLM_INTERNAL_ERROR;
-        }
-#endif
       }
-
-      data = data->next; /* check next handle */
     }
   }
 
@@ -1412,8 +1390,8 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
       /* Count up all our own sockets that had activity,
          and remove them from the event. */
       if(curlfds) {
-        data = multi->easyp;
-        while(data) {
+
+        for(data = multi->easyp; data; data = data->next) {
           bitmap = multi_getsock(data, sockbunch);
 
           for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
@@ -1430,8 +1408,6 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
               break;
             }
           }
-
-          data = data->next;
         }
       }
 
@@ -1577,6 +1553,18 @@ static bool multi_ischanged(struct Curl_multi *multi, bool clear)
   return retval;
 }
 
+/*
+ * Curl_multi_connchanged() is called to tell that there is a connection in
+ * this multi handle that has changed state (multiplexing become possible, the
+ * number of allowed streams changed or similar), and a subsequent use of this
+ * multi handle should move CONNECT_PEND handles back to CONNECT to have them
+ * retry.
+ */
+void Curl_multi_connchanged(struct Curl_multi *multi)
+{
+  multi->recheckstate = TRUE;
+}
+
 CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
                                  struct Curl_easy *data,
                                  struct connectdata *conn)
@@ -1611,7 +1599,6 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
   DEBUGASSERT(conn->handler);
 
   if(conn->handler->do_it)
-    /* generic protocol-specific function pointer set in curl_connect() */
     result = conn->handler->do_it(data, done);
 
   return result;
@@ -1787,9 +1774,8 @@ static CURLcode protocol_connect(struct Curl_easy *data,
  */
 static CURLcode readrewind(struct Curl_easy *data)
 {
-  struct connectdata *conn = data->conn;
   curl_mimepart *mimepart = &data->set.mimepost;
-  DEBUGASSERT(conn);
+  DEBUGASSERT(data->conn);
 
   data->state.rewindbeforesend = FALSE; /* we rewind now */
 
@@ -1802,12 +1788,12 @@ static CURLcode readrewind(struct Curl_easy *data)
   /* We have sent away data. If not using CURLOPT_POSTFIELDS or
      CURLOPT_HTTPPOST, call app to rewind
   */
-  if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
-    struct HTTP *http = data->req.p.http;
-
-    if(http->sendit)
-      mimepart = http->sendit;
+#ifndef CURL_DISABLE_HTTP
+  if(data->conn->handler->protocol & PROTO_FAMILY_HTTP) {
+    if(data->state.mimepost)
+      mimepart = data->state.mimepost;
   }
+#endif
   if(data->set.postfields ||
      (data->state.httpreq == HTTPREQ_GET) ||
      (data->state.httpreq == HTTPREQ_HEAD))
@@ -2460,7 +2446,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 
       if(done || (result == CURLE_RECV_ERROR)) {
         /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
-         * condition and the server closed the re-used connection exactly when
+         * condition and the server closed the reused connection exactly when
          * we wanted to use it, so figure out if that is indeed the case.
          */
         CURLcode ret = Curl_retry_request(data, &newurl);
@@ -2502,7 +2488,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       if(result) {
         /*
          * The transfer phase returned error, we mark the connection to get
-         * closed to prevent being re-used. This is because we can't possibly
+         * closed to prevent being reused. This is because we can't possibly
          * know if the connection is in a good shape or not now.  Unless it is
          * a protocol which uses two "channels" like FTP, as then the error
          * happened in the data connection.
@@ -2933,7 +2919,7 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
 
   /* walk over the sockets we got right now */
   for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
-        (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
+      (curraction & GETSOCK_MASK_RW(i));
       i++) {
     unsigned char action = CURL_POLL_NONE;
     unsigned char prevaction = 0;

+ 5 - 0
lib/multiif.h

@@ -41,6 +41,8 @@ void Curl_set_in_callback(struct Curl_easy *data, bool value);
 bool Curl_is_in_callback(struct Curl_easy *easy);
 CURLcode Curl_preconnect(struct Curl_easy *data);
 
+void Curl_multi_connchanged(struct Curl_multi *multi);
+
 /* Internal version of curl_multi_init() accepts size parameters for the
    socket, connection and dns hashes */
 struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize,
@@ -57,6 +59,9 @@ struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize,
 /* set the bit for the given sock number to make the bitmap for readable */
 #define GETSOCK_READSOCK(x) (1 << (x))
 
+/* mask for checking if read and/or write is set for index x */
+#define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x))
+
 #ifdef DEBUGBUILD
  /*
   * Curl_multi_dump is not a stable public function, this is only meant to

+ 5 - 7
lib/pingpong.c

@@ -204,8 +204,7 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
 #ifdef HAVE_GSSAPI
   conn->data_prot = PROT_CMD;
 #endif
-  result = Curl_write(data, conn->sock[FIRSTSOCKET], s, write_len,
-                      &bytes_written);
+  result = Curl_nwrite(data, FIRSTSOCKET, s, write_len, &bytes_written);
   if(result)
     return result;
 #ifdef HAVE_GSSAPI
@@ -341,7 +340,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
       ssize_t clipamount = 0;
       bool restart = FALSE;
 
-      data->req.headerbytecount += (long)gotbytes;
+      data->req.headerbytecount += (unsigned int)gotbytes;
 
       pp->nread_resp += gotbytes;
       for(i = 0; i < gotbytes; ptr++, i++) {
@@ -467,11 +466,10 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
                            struct pingpong *pp)
 {
   /* we have a piece of a command still left to send */
-  struct connectdata *conn = data->conn;
   ssize_t written;
-  curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  CURLcode result = Curl_write(data, sock, pp->sendthis + pp->sendsize -
-                               pp->sendleft, pp->sendleft, &written);
+  CURLcode result = Curl_nwrite(data, FIRSTSOCKET,
+                                pp->sendthis + pp->sendsize - pp->sendleft,
+                                pp->sendleft, &written);
   if(result)
     return result;
 

+ 5 - 8
lib/pop3.c

@@ -47,9 +47,6 @@
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
-#ifdef HAVE_UTSNAME_H
-#include <sys/utsname.h>
-#endif
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif
@@ -422,7 +419,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data,
   return result;
 }
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
 /***********************************************************************
  *
  * pop3_perform_apop()
@@ -566,7 +563,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
   }
 
   if(!result && progress == SASL_IDLE) {
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
     if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
       /* Perform APOP authentication */
       result = pop3_perform_apop(data, conn);
@@ -834,7 +831,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
       pop3_state(data, POP3_STOP);  /* Authenticated */
       break;
     case SASL_IDLE:            /* No mechanism left after cancellation */
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
       if(pop3c->authtypes & pop3c->preftype & POP3_TYPE_APOP)
         /* Perform APOP authentication */
         result = pop3_perform_apop(data, conn);
@@ -855,7 +852,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data,
   return result;
 }
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
 /* For APOP responses */
 static CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code,
                                      pop3state instate)
@@ -1018,7 +1015,7 @@ static CURLcode pop3_statemachine(struct Curl_easy *data,
       result = pop3_state_auth_resp(data, pop3code, pop3c->state);
       break;
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
     case POP3_APOP:
       result = pop3_state_apop_resp(data, pop3code, pop3c->state);
       break;

+ 2 - 1
lib/rand.c

@@ -36,6 +36,7 @@ uint32_t arc4random(void);
 #endif
 
 #include <curl/curl.h>
+#include "urldata.h"
 #include "vtls/vtls.h"
 #include "sendf.h"
 #include "timeval.h"
@@ -187,7 +188,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
  * 'rnd' points to.
  *
  * If libcurl is built without TLS support or with a TLS backend that lacks a
- * proper random API (rustls, Gskit or mbedTLS), this function will use "weak"
+ * proper random API (rustls or mbedTLS), this function will use "weak"
  * random.
  *
  * When built *with* TLS support and a backend that offers strong random, it

+ 0 - 14
lib/rand.h

@@ -24,20 +24,6 @@
  *
  ***************************************************************************/
 
-/*
- * Curl_rand() stores 'num' number of random unsigned characters in the buffer
- * 'rnd' points to.
- *
- * If libcurl is built without TLS support or with a TLS backend that lacks a
- * proper random API (Gskit or mbedTLS), this function will use "weak" random.
- *
- * When built *with* TLS support and a backend that offers strong random, it
- * will return error if it cannot provide strong random values.
- *
- * NOTE: 'data' may be passed in as NULL when coming from external API without
- * easy handle!
- *
- */
 CURLcode Curl_rand(struct Curl_easy *data, unsigned char *rnd, size_t num);
 
 /*

+ 48 - 33
lib/sendf.c

@@ -139,27 +139,27 @@ static size_t convert_lineends(struct Curl_easy *data,
 #endif /* CURL_DO_LINEEND_CONV && !CURL_DISABLE_FTP */
 
 /*
- * Curl_write() is an internal write function that sends data to the
- * server. Works with plain sockets, SCP, SSL or kerberos.
+ * Curl_nwrite() is an internal write function that sends data to the
+ * server. Works with a socket index for the connection.
  *
- * If the write would block (CURLE_AGAIN), we return CURLE_OK and
- * (*written == 0). Otherwise we return regular CURLcode value.
+ * If the write would block (CURLE_AGAIN), it returns CURLE_OK and
+ * (*nwritten == 0). Otherwise we return regular CURLcode value.
  */
-CURLcode Curl_write(struct Curl_easy *data,
-                    curl_socket_t sockfd,
-                    const void *mem,
-                    size_t len,
-                    ssize_t *written)
+CURLcode Curl_nwrite(struct Curl_easy *data,
+                     int sockindex,
+                     const void *buf,
+                     size_t blen,
+                     ssize_t *pnwritten)
 {
-  ssize_t bytes_written;
+  ssize_t nwritten;
   CURLcode result = CURLE_OK;
   struct connectdata *conn;
-  int num;
+
+  DEBUGASSERT(sockindex >= 0 && sockindex < 2);
+  DEBUGASSERT(pnwritten);
   DEBUGASSERT(data);
   DEBUGASSERT(data->conn);
   conn = data->conn;
-  num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
-
 #ifdef CURLDEBUG
   {
     /* Allow debug builds to override this logic to force short sends
@@ -168,31 +168,47 @@ CURLcode Curl_write(struct Curl_easy *data,
     if(p) {
       size_t altsize = (size_t)strtoul(p, NULL, 10);
       if(altsize)
-        len = CURLMIN(len, altsize);
+        blen = CURLMIN(blen, altsize);
     }
   }
 #endif
-  bytes_written = conn->send[num](data, num, mem, len, &result);
-
-  *written = bytes_written;
-  if(bytes_written >= 0)
-    /* we completely ignore the curlcode value when subzero is not returned */
-    return CURLE_OK;
+  nwritten = conn->send[sockindex](data, sockindex, buf, blen, &result);
+  if(result == CURLE_AGAIN) {
+    nwritten = 0;
+    result = CURLE_OK;
+  }
+  else if(result) {
+    nwritten = -1; /* make sure */
+  }
+  else {
+    DEBUGASSERT(nwritten >= 0);
+  }
 
-  /* handle CURLE_AGAIN or a send failure */
-  switch(result) {
-  case CURLE_AGAIN:
-    *written = 0;
-    return CURLE_OK;
+  *pnwritten = nwritten;
+  return result;
+}
 
-  case CURLE_OK:
-    /* general send failure */
-    return CURLE_SEND_ERROR;
+/*
+ * Curl_write() is an internal write function that sends data to the
+ * server. Works with plain sockets, SCP, SSL or kerberos.
+ *
+ * If the write would block (CURLE_AGAIN), we return CURLE_OK and
+ * (*written == 0). Otherwise we return regular CURLcode value.
+ */
+CURLcode Curl_write(struct Curl_easy *data,
+                    curl_socket_t sockfd,
+                    const void *mem,
+                    size_t len,
+                    ssize_t *written)
+{
+  struct connectdata *conn;
+  int num;
 
-  default:
-    /* we got a specific curlcode, forward it */
-    return result;
-  }
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  conn = data->conn;
+  num = (sockfd != CURL_SOCKET_BAD && sockfd == conn->sock[SECONDARYSOCKET]);
+  return Curl_nwrite(data, num, mem, len, written);
 }
 
 static CURLcode pausewrite(struct Curl_easy *data,
@@ -421,4 +437,3 @@ CURLcode Curl_read(struct Curl_easy *data,   /* transfer */
 out:
   return result;
 }
-

+ 8 - 1
lib/sendf.h

@@ -26,7 +26,7 @@
 
 #include "curl_setup.h"
 
-#include "curl_log.h"
+#include "curl_trc.h"
 
 
 #define CLIENTWRITE_BODY    (1<<0)
@@ -51,4 +51,11 @@ CURLcode Curl_write(struct Curl_easy *data,
                     const void *mem, size_t len,
                     ssize_t *written);
 
+/* internal write-function, using sockindex for connection destination */
+CURLcode Curl_nwrite(struct Curl_easy *data,
+                     int sockindex,
+                     const void *buf,
+                     size_t blen,
+                     ssize_t *pnwritten);
+
 #endif /* HEADER_CURL_SENDF_H */

+ 14 - 3
lib/setopt.c

@@ -666,17 +666,20 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       data->set.method = HTTPREQ_GET;
     break;
 
-#ifndef CURL_DISABLE_MIME
+#ifndef CURL_DISABLE_FORM_API
   case CURLOPT_HTTPPOST:
     /*
-     * Set to make us do HTTP POST
+     * Set to make us do HTTP POST. Legacy API-style.
      */
     data->set.httppost = va_arg(param, struct curl_httppost *);
     data->set.method = HTTPREQ_POST_FORM;
     data->set.opt_no_body = FALSE; /* this is implied */
+    Curl_mime_cleanpart(data->state.formp);
+    Curl_safefree(data->state.formp);
     break;
 #endif
 
+#if !defined(CURL_DISABLE_AWS)
   case CURLOPT_AWS_SIGV4:
     /*
      * String that is merged to some authentication
@@ -690,6 +693,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     if(data->set.str[STRING_AWS_SIGV4])
       data->set.httpauth = CURLAUTH_AWS_SIGV4;
     break;
+#endif
 
   case CURLOPT_REFERER:
     /*
@@ -985,6 +989,10 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     if(!result) {
       data->set.method = HTTPREQ_POST_MIME;
       data->set.opt_no_body = FALSE; /* this is implied */
+#ifndef CURL_DISABLE_FORM_API
+      Curl_mime_cleanpart(data->state.formp);
+      Curl_safefree(data->state.formp);
+#endif
     }
     break;
 
@@ -1237,6 +1245,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     data->set.out = va_arg(param, void *);
     break;
 
+#ifdef CURL_LIST_ONLY_PROTOCOL
   case CURLOPT_DIRLISTONLY:
     /*
      * An option that changes the command to one that asks for a list only, no
@@ -1244,7 +1253,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      */
     data->set.list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
     break;
-
+#endif
   case CURLOPT_APPEND:
     /*
      * We want to upload and append to an existing file. Used for FTP and
@@ -1885,6 +1894,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     result = Curl_setstropt(&data->set.str[STRING_DEVICE],
                             va_arg(param, char *));
     break;
+#ifndef CURL_DISABLE_BINDLOCAL
   case CURLOPT_LOCALPORT:
     /*
      * Set what local port to bind the socket to when performing an operation.
@@ -1903,6 +1913,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       return CURLE_BAD_FUNCTION_ARGUMENT;
     data->set.localportrange = curlx_sltous(arg);
     break;
+#endif
   case CURLOPT_GSSAPI_DELEGATION:
     /*
      * GSS-API credential delegation bitmask

+ 3 - 88
lib/setup-os400.h

@@ -34,6 +34,9 @@
 /* No OS/400 header file defines u_int32_t. */
 typedef unsigned long   u_int32_t;
 
+/* OS/400 has no idea of a tty! */
+#define isatty(fd)      0
+
 
 /* System API wrapper prototypes & definitions to support ASCII parameters. */
 
@@ -57,94 +60,6 @@ extern int Curl_getnameinfo_a(const struct sockaddr *sa,
                               int flags);
 #define getnameinfo             Curl_getnameinfo_a
 
-
-/* GSKit wrappers. */
-
-extern int      Curl_gsk_environment_open(gsk_handle * my_env_handle);
-#define gsk_environment_open    Curl_gsk_environment_open
-
-extern int      Curl_gsk_secure_soc_open(gsk_handle my_env_handle,
-                                         gsk_handle * my_session_handle);
-#define gsk_secure_soc_open     Curl_gsk_secure_soc_open
-
-extern int      Curl_gsk_environment_close(gsk_handle * my_env_handle);
-#define gsk_environment_close   Curl_gsk_environment_close
-
-extern int      Curl_gsk_secure_soc_close(gsk_handle * my_session_handle);
-#define gsk_secure_soc_close    Curl_gsk_secure_soc_close
-
-extern int      Curl_gsk_environment_init(gsk_handle my_env_handle);
-#define gsk_environment_init    Curl_gsk_environment_init
-
-extern int      Curl_gsk_secure_soc_init(gsk_handle my_session_handle);
-#define gsk_secure_soc_init     Curl_gsk_secure_soc_init
-
-extern int      Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle,
-                                                GSK_BUF_ID bufID,
-                                                const char *buffer,
-                                                int bufSize);
-#define gsk_attribute_set_buffer        Curl_gsk_attribute_set_buffer_a
-
-extern int      Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle,
-                                            GSK_ENUM_ID enumID,
-                                            GSK_ENUM_VALUE enumValue);
-#define gsk_attribute_set_enum  Curl_gsk_attribute_set_enum
-
-extern int      Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle,
-                                                     GSK_NUM_ID numID,
-                                                     int numValue);
-#define gsk_attribute_set_numeric_value Curl_gsk_attribute_set_numeric_value
-
-extern int      Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle,
-                                                GSK_CALLBACK_ID callBackID,
-                                                void *callBackAreaPtr);
-#define gsk_attribute_set_callback      Curl_gsk_attribute_set_callback
-
-extern int      Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle,
-                                                GSK_BUF_ID bufID,
-                                                const char **buffer,
-                                                int *bufSize);
-#define gsk_attribute_get_buffer        Curl_gsk_attribute_get_buffer_a
-
-extern int      Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle,
-                                            GSK_ENUM_ID enumID,
-                                            GSK_ENUM_VALUE *enumValue);
-#define gsk_attribute_get_enum  Curl_gsk_attribute_get_enum
-
-extern int      Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle,
-                                                     GSK_NUM_ID numID,
-                                                     int *numValue);
-#define gsk_attribute_get_numeric_value Curl_gsk_attribute_get_numeric_value
-
-extern int      Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle,
-                                 GSK_CERT_ID certID,
-                                 const gsk_cert_data_elem **certDataElem,
-                                 int *certDataElementCount);
-#define gsk_attribute_get_cert_info     Curl_gsk_attribute_get_cert_info
-
-extern int      Curl_gsk_secure_soc_misc(gsk_handle my_session_handle,
-                                         GSK_MISC_ID miscID);
-#define gsk_secure_soc_misc     Curl_gsk_secure_soc_misc
-
-extern int      Curl_gsk_secure_soc_read(gsk_handle my_session_handle,
-                                         char *readBuffer,
-                                         int readBufSize, int *amtRead);
-#define gsk_secure_soc_read     Curl_gsk_secure_soc_read
-
-extern int      Curl_gsk_secure_soc_write(gsk_handle my_session_handle,
-                                          char *writeBuffer,
-                                          int writeBufSize, int *amtWritten);
-#define gsk_secure_soc_write    Curl_gsk_secure_soc_write
-
-extern const char *     Curl_gsk_strerror_a(int gsk_return_value);
-#define gsk_strerror    Curl_gsk_strerror_a
-
-extern int      Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle,
-                                      int IOCompletionPort,
-                                      Qso_OverlappedIO_t * communicationsArea);
-#define gsk_secure_soc_startInit        Curl_gsk_secure_soc_startInit
-
-
 /* GSSAPI wrappers. */
 
 extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status,

+ 0 - 1
lib/setup-vms.h

@@ -262,7 +262,6 @@ static struct passwd *vms_getpwuid(uid_t uid)
 #define PKCS12_parse PKCS12_PARSE
 #define RAND_add RAND_ADD
 #define RAND_bytes RAND_BYTES
-#define RAND_egd RAND_EGD
 #define RAND_file_name RAND_FILE_NAME
 #define RAND_load_file RAND_LOAD_FILE
 #define RAND_status RAND_STATUS

+ 15 - 6
lib/sha256.c

@@ -25,7 +25,8 @@
 
 #include "curl_setup.h"
 
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \
+    || defined(USE_LIBSSH2)
 
 #include "warnless.h"
 #include "curl_sha256.h"
@@ -110,7 +111,10 @@ static CURLcode my_sha256_init(my_sha256_ctx *ctx)
   if(!ctx->openssl_ctx)
     return CURLE_OUT_OF_MEMORY;
 
-  EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL);
+  if(!EVP_DigestInit_ex(ctx->openssl_ctx, EVP_sha256(), NULL)) {
+    EVP_MD_CTX_destroy(ctx->openssl_ctx);
+    return CURLE_FAILED_INIT;
+  }
   return CURLE_OK;
 }
 
@@ -218,9 +222,14 @@ typedef struct sha256_ctx my_sha256_ctx;
 
 static CURLcode my_sha256_init(my_sha256_ctx *ctx)
 {
-  if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
-                         CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
-    CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash);
+  if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_AES,
+                         CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    return CURLE_OUT_OF_MEMORY;
+
+  if(!CryptCreateHash(ctx->hCryptProv, CALG_SHA_256, 0, 0, &ctx->hHash)) {
+    CryptReleaseContext(ctx->hCryptProv, 0);
+    ctx->hCryptProv = 0;
+    return CURLE_FAILED_INIT;
   }
 
   return CURLE_OK;
@@ -533,4 +542,4 @@ const struct HMAC_params Curl_HMAC_SHA256[] = {
 };
 
 
-#endif /* CURL_DISABLE_CRYPTO_AUTH */
+#endif /* AWS, DIGEST, or libSSH2 */

+ 4 - 6
lib/smb.c

@@ -564,12 +564,11 @@ static CURLcode smb_send(struct Curl_easy *data, ssize_t len,
                          size_t upload_size)
 {
   struct connectdata *conn = data->conn;
-  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   struct smb_conn *smbc = &conn->proto.smbc;
   ssize_t bytes_written;
   CURLcode result;
 
-  result = Curl_write(data, sockfd, data->state.ulbuf,
+  result = Curl_nwrite(data, FIRSTSOCKET, data->state.ulbuf,
                       len, &bytes_written);
   if(result)
     return result;
@@ -587,7 +586,6 @@ static CURLcode smb_send(struct Curl_easy *data, ssize_t len,
 static CURLcode smb_flush(struct Curl_easy *data)
 {
   struct connectdata *conn = data->conn;
-  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   struct smb_conn *smbc = &conn->proto.smbc;
   ssize_t bytes_written;
   ssize_t len = smbc->send_size - smbc->sent;
@@ -596,9 +594,9 @@ static CURLcode smb_flush(struct Curl_easy *data)
   if(!smbc->send_size)
     return CURLE_OK;
 
-  result = Curl_write(data, sockfd,
-                      data->state.ulbuf + smbc->sent,
-                      len, &bytes_written);
+  result = Curl_nwrite(data, FIRSTSOCKET,
+                       data->state.ulbuf + smbc->sent,
+                       len, &bytes_written);
   if(result)
     return result;
 

+ 0 - 3
lib/smtp.c

@@ -49,9 +49,6 @@
 #ifdef HAVE_ARPA_INET_H
 #include <arpa/inet.h>
 #endif
-#ifdef HAVE_UTSNAME_H
-#include <sys/utsname.h>
-#endif
 #ifdef HAVE_NETDB_H
 #include <netdb.h>
 #endif

+ 1 - 1
lib/strerror.c

@@ -938,7 +938,7 @@ const char *Curl_winapi_strerror(DWORD err, char *buf, size_t buflen)
 
 #ifndef CURL_DISABLE_VERBOSE_STRINGS
   if(!get_winapi_error(err, buf, buflen)) {
-    msnprintf(buf, buflen, "Unknown error %u (0x%08X)", err, err);
+    msnprintf(buf, buflen, "Unknown error %lu (0x%08lX)", err, err);
   }
 #else
   {

+ 3 - 2
lib/system_win32.h

@@ -42,7 +42,8 @@ extern IF_NAMETOINDEX_FN Curl_if_nametoindex;
 
 /* This is used to dynamically load DLLs */
 HMODULE Curl_load_library(LPCTSTR filename);
-
-#endif /* WIN32 */
+#else  /* WIN32 */
+#define Curl_win32_init(x) CURLE_OK
+#endif /* !WIN32 */
 
 #endif /* HEADER_CURL_SYSTEM_WIN32_H */

+ 4 - 4
lib/telnet.c

@@ -1266,10 +1266,10 @@ static CURLcode send_telnet_data(struct Curl_easy *data,
         break;
       default:                    /* write! */
         bytes_written = 0;
-        result = Curl_write(data, conn->sock[FIRSTSOCKET],
-                            outbuf + total_written,
-                            outlen - total_written,
-                            &bytes_written);
+        result = Curl_nwrite(data, FIRSTSOCKET,
+                             outbuf + total_written,
+                             outlen - total_written,
+                             &bytes_written);
         total_written += bytes_written;
         break;
     }

+ 11 - 11
lib/transfer.c

@@ -431,6 +431,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
   curl_off_t max_recv = data->set.max_recv_speed?
                         data->set.max_recv_speed : CURL_OFF_T_MAX;
   char *buf = data->state.buffer;
+  bool data_eof_handled = FALSE;
   DEBUGASSERT(buf);
 
   *done = FALSE;
@@ -448,8 +449,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
        to ensure that http2_handle_stream_close is called when we read all
        incoming bytes for a particular stream. */
     bool is_http3 = Curl_conn_is_http3(data, conn, FIRSTSOCKET);
-    bool data_eof_handled = is_http3
-                            || Curl_conn_is_http2(data, conn, FIRSTSOCKET);
+    data_eof_handled = is_http3 || Curl_conn_is_http2(data, conn, FIRSTSOCKET);
 
     if(!data_eof_handled && k->size != -1 && !k->header) {
       /* make sure we don't read too much */
@@ -492,15 +492,16 @@ static CURLcode readwrite_data(struct Curl_easy *data,
     if(0 < nread || is_empty_data) {
       buf[nread] = 0;
     }
-    else {
+    if(!nread) {
       /* if we receive 0 or less here, either the data transfer is done or the
          server closed the connection and we bail out from this! */
       if(data_eof_handled)
         DEBUGF(infof(data, "nread == 0, stream closed, bailing"));
       else
         DEBUGF(infof(data, "nread <= 0, server closed connection, bailing"));
-      k->keepon &= ~KEEP_RECV;
-      break;
+      k->keepon = 0; /* stop sending as well */
+      if(!is_empty_data)
+        break;
     }
 
     /* Default buffer to use when we write the buffer, it may be changed
@@ -761,7 +762,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
   }
 
   if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
-     conn->bits.close) {
+     (conn->bits.close || data_eof_handled)) {
     /* When we've read the entire thing and the close bit is set, the server
        may now close the connection. If there's now any kind of sending going
        on from our side, we need to stop that immediately. */
@@ -824,9 +825,6 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
   bool sending_http_headers = FALSE;
   struct SingleRequest *k = &data->req;
 
-  if((k->bytecount == 0) && (k->writebytecount == 0))
-    Curl_pgrsTime(data, TIMER_STARTTRANSFER);
-
   *didwhat |= KEEP_SEND;
 
   do {
@@ -1335,7 +1333,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
   }
 
   data->state.prefer_ascii = data->set.prefer_ascii;
+#ifdef CURL_LIST_ONLY_PROTOCOL
   data->state.list_only = data->set.list_only;
+#endif
   data->state.httpreq = data->set.method;
   data->state.url = data->set.str[STRING_SET_URL];
 
@@ -1397,7 +1397,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
     Curl_pgrsResetTransferSizes(data);
     Curl_pgrsStartNow(data);
 
-    /* In case the handle is re-used and an authentication method was picked
+    /* In case the handle is reused and an authentication method was picked
        in the session we need to make sure we only use the one(s) we now
        consider to be fine */
     data->state.authhost.picked &= data->state.authhost.want;
@@ -1787,7 +1787,7 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url)
      && (data->set.rtspreq != RTSPREQ_RECEIVE)
 #endif
     )
-    /* We got no data, we attempted to re-use a connection. For HTTP this
+    /* We got no data, we attempted to reuse a connection. For HTTP this
        can be a retry so we try again regardless if we expected a body.
        For other protocols we only try again only if we expected a body.
 

+ 45 - 35
lib/url.c

@@ -414,7 +414,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
     Curl_hsts_cleanup(&data->hsts);
   curl_slist_free_all(data->set.hstslist); /* clean up list */
 #endif
-#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_DIGEST_AUTH)
   Curl_http_auth_cleanup_digest(data);
 #endif
   Curl_safefree(data->info.contenttype);
@@ -457,6 +457,11 @@ CURLcode Curl_close(struct Curl_easy **datap)
   }
 #endif
 
+  Curl_mime_cleanpart(data->state.formp);
+#ifndef CURL_DISABLE_HTTP
+  Curl_safefree(data->state.formp);
+#endif
+
   /* destruct wildcard structures if it is needed */
   Curl_wildcard_dtor(&data->wildcard);
   Curl_freeset(data);
@@ -490,7 +495,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
 
   set->filesize = -1;        /* we don't know the size */
   set->postfieldsize = -1;   /* unknown size */
-  set->maxredirs = -1;       /* allow any amount by default */
+  set->maxredirs = 30;       /* sensible default */
 
   set->method = HTTPREQ_GET; /* Default HTTP request */
 #ifndef CURL_DISABLE_RTSP
@@ -948,7 +953,7 @@ static bool extract_if_dead(struct connectdata *conn,
          * that we expect - in general - no waiting input data. Input
          * waiting might be a TLS Notify Close, for example. We reject
          * that.
-         * For protocols where data from other other end may arrive at
+         * For protocols where data from other end may arrive at
          * any time (HTTP/2 PING for example), the protocol handler needs
          * to install its own `connection_check` callback.
          */
@@ -1073,6 +1078,9 @@ ConnectionExists(struct Curl_easy *data,
   bool wantProxyNTLMhttp = FALSE;
 #endif
 #endif
+  /* plain HTTP with upgrade */
+  bool h2upgrade = (data->state.httpwant == CURL_HTTP_VERSION_2_0) &&
+    (needle->handler->protocol & CURLPROTO_HTTP);
 
   *force_reuse = FALSE;
   *waitpipe = FALSE;
@@ -1095,7 +1103,7 @@ ConnectionExists(struct Curl_easy *data,
           infof(data, "Server doesn't support multiplex yet, wait");
           *waitpipe = TRUE;
           CONNCACHE_UNLOCK(data);
-          return FALSE; /* no re-use */
+          return FALSE; /* no reuse */
         }
 
         infof(data, "Server doesn't support multiplex (yet)");
@@ -1135,7 +1143,7 @@ ConnectionExists(struct Curl_easy *data,
       }
 
       if(data->set.ipver != CURL_IPRESOLVE_WHATEVER
-          && data->set.ipver != check->ip_version) {
+         && data->set.ipver != check->ip_version) {
         /* skip because the connection is not via the requested IP version */
         continue;
       }
@@ -1150,16 +1158,11 @@ ConnectionExists(struct Curl_easy *data,
           continue;
         }
 
-        if(Curl_resolver_asynch()) {
-          /* primary_ip[0] is NUL only if the resolving of the name hasn't
-             completed yet and until then we don't re-use this connection */
-          if(!check->primary_ip[0]) {
-            infof(data, "Connection #%" CURL_FORMAT_CURL_OFF_T " is still "
-                        "name resolving, can't reuse",
-                  check->connection_id);
-            continue;
-          }
-        }
+        if(Curl_resolver_asynch() &&
+           /* primary_ip[0] is NUL only if the resolving of the name hasn't
+              completed yet and until then we don't reuse this connection */
+           !check->primary_ip[0])
+          continue;
       }
 
       if(!Curl_conn_is_connected(check, FIRSTSOCKET)) {
@@ -1238,6 +1241,17 @@ ConnectionExists(struct Curl_easy *data,
       }
 #endif
 
+      if(h2upgrade && !check->httpversion && canmultiplex) {
+        if(data->set.pipewait) {
+          infof(data, "Server upgrade doesn't support multiplex yet, wait");
+          *waitpipe = TRUE;
+          CONNCACHE_UNLOCK(data);
+          return FALSE; /* no reuse */
+        }
+        infof(data, "Server upgrade cannot be used");
+        continue; /* can't be used atm */
+      }
+
       if(!canmultiplex && CONN_INUSE(check))
         /* this request can't be multiplexed but the checked connection is
            already in use so we skip it */
@@ -1254,14 +1268,14 @@ ConnectionExists(struct Curl_easy *data,
 
       if(needle->localdev || needle->localport) {
         /* If we are bound to a specific local end (IP+port), we must not
-           re-use a random other one, although if we didn't ask for a
+           reuse a random other one, although if we didn't ask for a
            particular one we can reuse one that was bound.
 
            This comparison is a bit rough and too strict. Since the input
            parameters can be specified in numerous ways and still end up the
            same it would take a lot of processing to make it really accurate.
-           Instead, this matching will assume that re-uses of bound connections
-           will most likely also re-use the exact same binding parameters and
+           Instead, this matching will assume that reuses of bound connections
+           will most likely also reuse the exact same binding parameters and
            missing out a few edge cases shouldn't hurt anyone very much.
         */
         if((check->localport != needle->localport) ||
@@ -1294,7 +1308,7 @@ ConnectionExists(struct Curl_easy *data,
          (((check->httpversion >= 20) &&
            (data->state.httpwant < CURL_HTTP_VERSION_2_0))
           || ((check->httpversion >= 30) &&
-           (data->state.httpwant < CURL_HTTP_VERSION_3))))
+              (data->state.httpwant < CURL_HTTP_VERSION_3))))
         continue;
 #ifdef USE_SSH
       else if(get_protocol_family(needle->handler) & PROTO_FAMILY_SSH) {
@@ -1485,13 +1499,7 @@ void Curl_verboseconnect(struct Curl_easy *data,
 {
   if(data->set.verbose)
     infof(data, "Connected to %s (%s) port %u",
-#ifndef CURL_DISABLE_PROXY
-          conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
-          conn->bits.httpproxy ? conn->http_proxy.host.dispname :
-#endif
-          conn->bits.conn_to_host ? conn->conn_to_host.dispname :
-          conn->host.dispname,
-          conn->primary_ip, conn->port);
+          CURL_CONN_HOST_DISPNAME(conn), conn->primary_ip, conn->port);
 }
 #endif
 
@@ -1587,8 +1595,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
     if(!conn->localdev)
       goto error;
   }
+#ifndef CURL_DISABLE_BINDLOCAL
   conn->localportrange = data->set.localportrange;
   conn->localport = data->set.localport;
+#endif
 
   /* the close socket stuff needs to be copied to the connection struct as
      it may live on without (this specific) Curl_easy */
@@ -2120,7 +2130,7 @@ static char *detect_proxy(struct Curl_easy *data,
 
 /*
  * If this is supposed to use a proxy, we need to figure out the proxy
- * host name, so that we can re-use an existing connection
+ * host name, so that we can reuse an existing connection
  * that may exist registered to the same proxy host.
  */
 static CURLcode parse_proxy(struct Curl_easy *data,
@@ -2441,7 +2451,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data,
 
   /***********************************************************************
    * If this is supposed to use a proxy, we need to figure out the proxy host
-   * name, proxy type and port number, so that we can re-use an existing
+   * name, proxy type and port number, so that we can reuse an existing
    * connection that may exist registered to the same proxy host.
    ***********************************************************************/
   if(proxy || socksproxy) {
@@ -3259,7 +3269,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
   /* Resolve the name of the server or proxy */
   if(conn->bits.reuse) {
     /* We're reusing the connection - no need to resolve anything, and
-       idnconvert_hostname() was called already in create_conn() for the re-use
+       idnconvert_hostname() was called already in create_conn() for the reuse
        case. */
     *async = FALSE;
     return CURLE_OK;
@@ -3278,7 +3288,7 @@ static void reuse_conn(struct Curl_easy *data,
                        struct connectdata *existing)
 {
   /* get the user+password information from the temp struct since it may
-   * be new for this request even when we re-use an existing connection */
+   * be new for this request even when we reuse an existing connection */
   if(temp->user) {
     /* use the new user name and password though */
     Curl_safefree(existing->user);
@@ -3338,14 +3348,14 @@ static void reuse_conn(struct Curl_easy *data,
   existing->hostname_resolve = temp->hostname_resolve;
   temp->hostname_resolve = NULL;
 
-  /* re-use init */
-  existing->bits.reuse = TRUE; /* yes, we're re-using here */
+  /* reuse init */
+  existing->bits.reuse = TRUE; /* yes, we're reusing here */
 
   conn_free(data, temp);
 }
 
 /**
- * create_conn() sets up a new connectdata struct, or re-uses an already
+ * create_conn() sets up a new connectdata struct, or reuses an already
  * existing one, and resolves host name.
  *
  * if this function returns CURLE_OK and *async is set to TRUE, the resolve
@@ -3657,7 +3667,7 @@ static CURLcode create_conn(struct Curl_easy *data,
 
   /*************************************************************
    * Check the current list of connections to see if we can
-   * re-use an already existing one or if we have to create a
+   * reuse an already existing one or if we have to create a
    * new one.
    *************************************************************/
 
@@ -3665,7 +3675,7 @@ static CURLcode create_conn(struct Curl_easy *data,
   DEBUGASSERT(conn->passwd);
 
   /* reuse_fresh is TRUE if we are told to use a new connection by force, but
-     we only acknowledge this option if this is not a re-used connection
+     we only acknowledge this option if this is not a reused connection
      already (which happens due to follow-location or during an HTTP
      authentication phase). CONNECT_ONLY transfers also refuse reuse. */
   if((data->set.reuse_fresh && !data->state.followlocation) ||

+ 46 - 6
lib/urlapi.c

@@ -1109,6 +1109,7 @@ static CURLUcode parseurl(const char *url, CURLU *u, unsigned int flags)
     if('/' == path[0] && STARTS_WITH_URL_DRIVE_PREFIX(&path[1])) {
       /* This cannot be done with strcpy, as the memory chunks overlap! */
       path++;
+      pathlen--;
     }
 #endif
 
@@ -1384,6 +1385,7 @@ CURLU *curl_url_dup(const CURLU *in)
     DUP(u, in, path);
     DUP(u, in, query);
     DUP(u, in, fragment);
+    DUP(u, in, zoneid);
     u->portnum = in->portnum;
   }
   return u;
@@ -1401,6 +1403,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
   bool urldecode = (flags & CURLU_URLDECODE)?1:0;
   bool urlencode = (flags & CURLU_URLENCODE)?1:0;
   bool punycode = FALSE;
+  bool depunyfy = FALSE;
   bool plusdecode = FALSE;
   (void)flags;
   if(!u)
@@ -1431,6 +1434,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
     ptr = u->host;
     ifmissing = CURLUE_NO_HOST;
     punycode = (flags & CURLU_PUNYCODE)?1:0;
+    depunyfy = (flags & CURLU_PUNY2IDN)?1:0;
     break;
   case CURLUPART_ZONEID:
     ptr = u->zoneid;
@@ -1481,6 +1485,7 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
     char *port = u->port;
     char *allochost = NULL;
     punycode = (flags & CURLU_PUNYCODE)?1:0;
+    depunyfy = (flags & CURLU_PUNY2IDN)?1:0;
     if(u->scheme && strcasecompare("file", u->scheme)) {
       url = aprintf("file://%s%s%s",
                     u->path,
@@ -1540,9 +1545,23 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
 #ifndef USE_IDN
           return CURLUE_LACKS_IDN;
 #else
-          allochost = Curl_idn_decode(u->host);
-          if(!allochost)
-            return CURLUE_OUT_OF_MEMORY;
+          CURLcode result = Curl_idn_decode(u->host, &allochost);
+          if(result)
+            return (result == CURLE_OUT_OF_MEMORY) ?
+              CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
+#endif
+        }
+      }
+      else if(depunyfy) {
+        if(Curl_is_ASCII_name(u->host) && !strncmp("xn--", u->host, 4)) {
+#ifndef USE_IDN
+          return CURLUE_LACKS_IDN;
+#else
+          CURLcode result = Curl_idn_encode(u->host, &allochost);
+          if(result)
+            /* this is the most likely error */
+            return (result == CURLE_OUT_OF_MEMORY) ?
+              CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
 #endif
         }
       }
@@ -1616,9 +1635,26 @@ CURLUcode curl_url_get(const CURLU *u, CURLUPart what,
 #ifndef USE_IDN
         return CURLUE_LACKS_IDN;
 #else
-        char *allochost = Curl_idn_decode(*part);
-        if(!allochost)
-          return CURLUE_OUT_OF_MEMORY;
+        char *allochost;
+        CURLcode result = Curl_idn_decode(*part, &allochost);
+        if(result)
+          return (result == CURLE_OUT_OF_MEMORY) ?
+            CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
+        free(*part);
+        *part = allochost;
+#endif
+      }
+    }
+    else if(depunyfy) {
+      if(Curl_is_ASCII_name(u->host)  && !strncmp("xn--", u->host, 4)) {
+#ifndef USE_IDN
+        return CURLUE_LACKS_IDN;
+#else
+        char *allochost;
+        CURLcode result = Curl_idn_encode(*part, &allochost);
+        if(result)
+          return (result == CURLE_OUT_OF_MEMORY) ?
+            CURLUE_OUT_OF_MEMORY : CURLUE_BAD_HOSTNAME;
         free(*part);
         *part = allochost;
 #endif
@@ -1780,6 +1816,10 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
     char *oldurl;
     char *redired_url;
 
+    if(!nalloc)
+      /* a blank URL is not a valid URL */
+      return CURLUE_MALFORMED_INPUT;
+
     /* if the new thing is absolute or the old one is not
      * (we could not get an absolute url in 'oldurl'),
      * then replace the existing with the new. */

+ 56 - 19
lib/urldata.h

@@ -101,6 +101,12 @@ typedef unsigned int curl_prot_t;
 #define PROTO_FAMILY_SMTP (CURLPROTO_SMTP|CURLPROTO_SMTPS)
 #define PROTO_FAMILY_SSH  (CURLPROTO_SCP|CURLPROTO_SFTP)
 
+#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) ||   \
+  !defined(CURL_DISABLE_POP3)
+/* these protocols support CURLOPT_DIRLISTONLY */
+#define CURL_LIST_ONLY_PROTOCOL 1
+#endif
+
 #define DEFAULT_CONNCACHE_SIZE 5
 
 /* length of longest IPv6 address string including the trailing null */
@@ -330,6 +336,7 @@ struct Curl_ssl_session {
 #include "curl_sspi.h"
 #endif
 
+#ifndef CURL_DISABLE_DIGEST_AUTH
 /* Struct used for Digest challenge-response authentication */
 struct digestdata {
 #if defined(USE_WINDOWS_SSPI)
@@ -353,6 +360,7 @@ struct digestdata {
   BIT(userhash);
 #endif
 };
+#endif
 
 typedef enum {
   NTLMSTATE_NONE,
@@ -489,7 +497,7 @@ struct ConnectBits {
 #endif
   /* always modify bits.close with the connclose() and connkeep() macros! */
   BIT(close); /* if set, we close the connection after this request */
-  BIT(reuse); /* if set, this is a re-used connection */
+  BIT(reuse); /* if set, this is a reused connection */
   BIT(altused); /* this is an alt-svc "redirect" */
   BIT(conn_to_host); /* if set, this connection has a "connect to host"
                         that overrides the host in the URL */
@@ -629,17 +637,16 @@ struct SingleRequest {
   curl_off_t bytecount;         /* total number of bytes read */
   curl_off_t writebytecount;    /* number of bytes written */
 
-  curl_off_t headerbytecount;   /* only count received headers */
-  curl_off_t deductheadercount; /* this amount of bytes doesn't count when we
-                                   check if anything has been transferred at
-                                   the end of a connection. We use this
-                                   counter to make only a 100 reply (without a
-                                   following second response code) result in a
-                                   CURLE_GOT_NOTHING error code */
-
   curl_off_t pendingheader;      /* this many bytes left to send is actually
                                     header and not body */
   struct curltime start;         /* transfer started at this time */
+  unsigned int headerbytecount;  /* only count received headers */
+  unsigned int deductheadercount; /* this amount of bytes doesn't count when
+                                     we check if anything has been transferred
+                                     at the end of a connection. We use this
+                                     counter to make only a 100 reply (without
+                                     a following second response code) result
+                                     in a CURLE_GOT_NOTHING error code */
   enum {
     HEADER_NORMAL,              /* no bad header at all */
     HEADER_PARTHEADER,          /* part of the chunk is a bad header, the rest
@@ -701,7 +708,9 @@ struct SingleRequest {
   struct curltime last_sndbuf_update;  /* last time readwrite_upload called
                                           win_update_buffer_size */
 #endif
+#ifndef CURL_DISABLE_COOKIES
   unsigned char setcookies;
+#endif
   unsigned char writer_stack_depth; /* Unencoding stack depth. */
   BIT(header);        /* incoming data has HTTP header */
   BIT(content_range); /* set TRUE if Content-Range: was found */
@@ -747,7 +756,7 @@ struct Curl_handler {
    * after the connect() and everything is done, as a step in the connection.
    * The 'done' pointer points to a bool that should be set to TRUE if the
    * function completes before return. If it doesn't complete, the caller
-   * should call the curl_connecting() function until it is.
+   * should call the ->connecting() function until it is.
    */
   CURLcode (*connect_it)(struct Curl_easy *data, bool *done);
 
@@ -887,7 +896,7 @@ struct connectdata {
 
   /* 'dns_entry' is the particular host we use. This points to an entry in the
      DNS cache and it will not get pruned while locked. It gets unlocked in
-     multi_done(). This entry will be NULL if the connection is re-used as then
+     multi_done(). This entry will be NULL if the connection is reused as then
      there is no name resolve done. */
   struct Curl_dns_entry *dns_entry;
 
@@ -1024,14 +1033,19 @@ struct connectdata {
 #ifndef CURL_DISABLE_SMB
     struct smb_conn smbc;
 #endif
+#ifdef USE_LIBRTMP
     void *rtmp;
+#endif
+#ifdef USE_OPENLDAP
     struct ldapconninfo *ldapc;
+#endif
 #ifndef CURL_DISABLE_MQTT
     struct mqtt_conn mqtt;
 #endif
 #ifdef USE_WEBSOCKETS
     struct websocket *ws;
 #endif
+    unsigned int unused:1; /* avoids empty union */
   } proto;
 
   struct connectbundle *bundle; /* The bundle we are member of */
@@ -1045,7 +1059,7 @@ struct connectdata {
   /* When this connection is created, store the conditions for the local end
      bind. This is stored before the actual bind and before any connection is
      made and will serve the purpose of being used for comparison reasons so
-     that subsequent bound-requested connections aren't accidentally re-using
+     that subsequent bound-requested connections aren't accidentally reusing
      wrong connections. */
   char *localdev;
   unsigned short localportrange;
@@ -1077,6 +1091,18 @@ struct connectdata {
   unsigned char gssapi_delegation; /* inherited from set.gssapi_delegation */
 };
 
+#ifndef CURL_DISABLE_PROXY
+#define CURL_CONN_HOST_DISPNAME(c) \
+          ((c)->bits.socksproxy ? (c)->socks_proxy.host.dispname : \
+            (c)->bits.httpproxy ? (c)->http_proxy.host.dispname : \
+              (c)->bits.conn_to_host ? (c)->conn_to_host.dispname : \
+                (c)->host.dispname)
+#else
+#define CURL_CONN_HOST_DISPNAME(c) \
+          (c)->bits.conn_to_host ? (c)->conn_to_host.dispname : \
+            (c)->host.dispname
+#endif
+
 /* The end of connectdata. */
 
 /*
@@ -1089,7 +1115,6 @@ struct PureInfo {
   int httpversion; /* the http version number X.Y = X*10+Y */
   time_t filetime; /* If requested, this is might get set. Set to -1 if the
                       time was unretrievable. */
-  curl_off_t header_size;  /* size of read header(s) in bytes */
   curl_off_t request_size; /* the amount of bytes sent in the request(s) */
   unsigned long proxyauthavail; /* what proxy auth types were announced */
   unsigned long httpauthavail;  /* what host auth types were announced */
@@ -1097,6 +1122,7 @@ struct PureInfo {
   char *contenttype; /* the content type of the object */
   char *wouldredirect; /* URL this would've been redirected to if asked to */
   curl_off_t retry_after; /* info from Retry-After: header */
+  unsigned int header_size;  /* size of read header(s) in bytes */
 
   /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip'
      and, 'conn_local_port' are copied over from the connectdata struct in
@@ -1116,10 +1142,8 @@ struct PureInfo {
   int conn_local_port;
   const char *conn_scheme;
   unsigned int conn_protocol;
-  struct curl_certinfo certs; /* info about the certs, only populated in
-                                 OpenSSL, GnuTLS, Schannel, NSS and GSKit
-                                 builds. Asked for with CURLOPT_CERTINFO
-                                 / CURLINFO_CERTINFO */
+  struct curl_certinfo certs; /* info about the certs. Asked for with
+                                 CURLOPT_CERTINFO / CURLINFO_CERTINFO */
   CURLproxycode pxcode;
   BIT(timecond);  /* set to TRUE if the time condition didn't match, which
                      thus made the document NOT get fetched */
@@ -1325,7 +1349,7 @@ struct UrlState {
   /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
   void (*prev_signal)(int sig);
 #endif
-#ifndef CURL_DISABLE_CRYPTO_AUTH
+#ifndef CURL_DISABLE_DIGEST_AUTH
   struct digestdata digest;      /* state data for host Digest auth */
   struct digestdata proxydigest; /* state data for proxy Digest auth */
 #endif
@@ -1383,6 +1407,9 @@ struct UrlState {
   struct curl_slist *resolve; /* set to point to the set.resolve list when
                                  this should be dealt with in pretransfer */
 #ifndef CURL_DISABLE_HTTP
+  curl_mimepart *mimepost;
+  curl_mimepart *formp; /* storage for old API form-posting, alloced on
+                           demand */
   size_t trailers_bytes_sent;
   struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
                                  headers */
@@ -1454,9 +1481,13 @@ struct UrlState {
                 when multi_done() is called, to prevent multi_done() to get
                 invoked twice when the multi interface is used. */
   BIT(previouslypending); /* this transfer WAS in the multi->pending queue */
+#ifndef CURL_DISABLE_COOKIES
   BIT(cookie_engine);
+#endif
   BIT(prefer_ascii);   /* ASCII rather than binary */
+#ifdef CURL_LIST_ONLY_PROTOCOL
   BIT(list_only);      /* list directory contents */
+#endif
   BIT(url_alloc);   /* URL string is malloc()'ed */
   BIT(referer_alloc); /* referer string is malloc()ed */
   BIT(wildcard_resolve); /* Set to true if any resolve change is a wildcard */
@@ -1613,10 +1644,12 @@ struct UserDefined {
   curl_off_t postfieldsize; /* if POST, this might have a size to use instead
                                of strlen(), and then the data *may* be binary
                                (contain zero bytes) */
+#ifndef CURL_DISABLE_BINDLOCAL
   unsigned short localport; /* local port number to bind to */
   unsigned short localportrange; /* number of additional port numbers to test
                                     in case the 'localport' one can't be
                                     bind()ed */
+#endif
   curl_write_callback fwrite_func;   /* function that stores the output */
   curl_write_callback fwrite_header; /* function that stores headers */
   curl_write_callback fwrite_rtp;    /* function that stores interleaved RTP */
@@ -1804,7 +1837,9 @@ struct UserDefined {
   BIT(tftp_no_options); /* do not send TFTP options requests */
 #endif
   BIT(sep_headers);     /* handle host and proxy headers separately */
+#ifndef CURL_DISABLE_COOKIES
   BIT(cookiesession);   /* new cookie session? */
+#endif
   BIT(crlf);            /* convert crlf on ftp upload(?) */
   BIT(ssh_compression);            /* enable SSH compression */
 
@@ -1819,7 +1854,9 @@ struct UserDefined {
   BIT(tunnel_thru_httpproxy); /* use CONNECT through an HTTP proxy */
   BIT(prefer_ascii);     /* ASCII rather than binary */
   BIT(remote_append);    /* append, not overwrite, on upload */
+#ifdef CURL_LIST_ONLY_PROTOCOL
   BIT(list_only);        /* list directory */
+#endif
 #ifndef CURL_DISABLE_FTP
   BIT(ftp_use_port);     /* use the FTP PORT command */
   BIT(ftp_use_epsv);     /* if EPSV is to be attempted or not */
@@ -1843,7 +1880,7 @@ struct UserDefined {
   BIT(verbose);        /* output verbosity */
   BIT(krb);            /* Kerberos connection requested */
   BIT(reuse_forbid);   /* forbidden to be reused, close after use */
-  BIT(reuse_fresh);    /* do not re-use an existing connection  */
+  BIT(reuse_fresh);    /* do not reuse an existing connection  */
   BIT(no_signal);      /* do not use any signal/alarm handler */
   BIT(tcp_nodelay);    /* whether to enable TCP_NODELAY or not */
   BIT(ignorecl);       /* ignore content length */

+ 2 - 2
lib/vauth/cram.c

@@ -26,7 +26,7 @@
 
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+#ifndef CURL_DISABLE_DIGEST_AUTH
 
 #include <curl/curl.h>
 #include "urldata.h"
@@ -94,4 +94,4 @@ CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
   return CURLE_OK;
 }
 
-#endif /* !CURL_DISABLE_CRYPTO_AUTH */
+#endif /* !CURL_DISABLE_DIGEST_AUTH */

+ 3 - 3
lib/vauth/digest.c

@@ -27,7 +27,7 @@
 
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+#ifndef CURL_DISABLE_DIGEST_AUTH
 
 #include <curl/curl.h>
 
@@ -420,7 +420,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
     msnprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
 
   /* Generate our SPN */
-  spn = Curl_auth_build_spn(service, realm, NULL);
+  spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
   if(!spn)
     return CURLE_OUT_OF_MEMORY;
 
@@ -992,4 +992,4 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
 }
 #endif  /* !USE_WINDOWS_SSPI */
 
-#endif  /* CURL_DISABLE_CRYPTO_AUTH */
+#endif  /* !CURL_DISABLE_DIGEST_AUTH */

+ 1 - 1
lib/vauth/digest.h

@@ -26,7 +26,7 @@
 
 #include <curl/curl.h>
 
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+#ifndef CURL_DISABLE_DIGEST_AUTH
 
 #define DIGEST_MAX_VALUE_LENGTH           256
 #define DIGEST_MAX_CONTENT_LENGTH         1024

+ 2 - 2
lib/vauth/digest_sspi.c

@@ -27,7 +27,7 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_DIGEST_AUTH)
 
 #include <curl/curl.h>
 
@@ -665,4 +665,4 @@ void Curl_auth_digest_cleanup(struct digestdata *digest)
   Curl_safefree(digest->passwd);
 }
 
-#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_CRYPTO_AUTH */
+#endif /* USE_WINDOWS_SSPI && !CURL_DISABLE_DIGEST_AUTH */

+ 1 - 12
lib/vauth/ntlm.c

@@ -45,12 +45,6 @@
 #include "rand.h"
 #include "vtls/vtls.h"
 
-/* SSL backend-specific #if branches in this file must be kept in the order
-   documented in curl_ntlm_core. */
-#if defined(NTLM_NEEDS_NSS_INIT)
-#include "vtls/nssg.h" /* for Curl_nss_force_init() */
-#endif
-
 #define BUILDING_CURL_NTLM_MSGS_C
 #include "vauth/vauth.h"
 #include "vauth/ntlm.h"
@@ -274,12 +268,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data,
   const unsigned char *type2 = Curl_bufref_ptr(type2ref);
   size_t type2len = Curl_bufref_len(type2ref);
 
-#if defined(NTLM_NEEDS_NSS_INIT)
-  /* Make sure the crypto backend is initialized */
-  result = Curl_nss_force_init(data);
-  if(result)
-    return result;
-#elif defined(CURL_DISABLE_VERBOSE_STRINGS)
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
   (void)data;
 #endif
 

+ 3 - 3
lib/vauth/vauth.h

@@ -30,7 +30,7 @@
 
 struct Curl_easy;
 
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+#if !defined(CURL_DISABLE_DIGEST_AUTH)
 struct digestdata;
 #endif
 
@@ -86,7 +86,7 @@ CURLcode Curl_auth_create_login_message(const char *value,
 CURLcode Curl_auth_create_external_message(const char *user,
                                            struct bufref *out);
 
-#if !defined(CURL_DISABLE_CRYPTO_AUTH)
+#ifndef CURL_DISABLE_DIGEST_AUTH
 /* This is used to generate a CRAM-MD5 response message */
 CURLcode Curl_auth_create_cram_md5_message(const struct bufref *chlg,
                                            const char *userp,
@@ -119,7 +119,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
 
 /* This is used to clean up the digest specific data */
 void Curl_auth_digest_cleanup(struct digestdata *digest);
-#endif /* !CURL_DISABLE_CRYPTO_AUTH */
+#endif /* !CURL_DISABLE_DIGEST_AUTH */
 
 #ifdef USE_GSASL
 /* This is used to evaluate if MECH is supported by gsasl */

+ 32 - 32
lib/vquic/curl_msh3.c

@@ -30,7 +30,7 @@
 #include "timeval.h"
 #include "multiif.h"
 #include "sendf.h"
-#include "curl_log.h"
+#include "curl_trc.h"
 #include "cfilters.h"
 #include "cf-socket.h"
 #include "connect.h"
@@ -173,7 +173,7 @@ static CURLcode h3_data_setup(struct Curl_cfilter *cf,
   msh3_lock_initialize(&stream->recv_lock);
   Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE,
                   H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT);
-  DEBUGF(LOG_CF(data, cf, "data setup"));
+  CURL_TRC_CF(data, cf, "data setup");
   return CURLE_OK;
 }
 
@@ -183,7 +183,7 @@ static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data)
 
   (void)cf;
   if(stream) {
-    DEBUGF(LOG_CF(data, cf, "easy handle is done"));
+    CURL_TRC_CF(data, cf, "easy handle is done");
     Curl_bufq_free(&stream->recvbuf);
     free(stream);
     H3_STREAM_LCTX(data) = NULL;
@@ -235,7 +235,7 @@ static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection,
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
   (void)Connection;
 
-  DEBUGF(LOG_CF(data, cf, "[MSH3] connected"));
+  CURL_TRC_CF(data, cf, "[MSH3] connected");
   ctx->handshake_succeeded = true;
   ctx->connected = true;
   ctx->handshake_complete = true;
@@ -249,7 +249,7 @@ static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection,
   struct Curl_easy *data = CF_DATA_CURRENT(cf);
 
   (void)Connection;
-  DEBUGF(LOG_CF(data, cf, "[MSH3] shutdown complete"));
+  CURL_TRC_CF(data, cf, "[MSH3] shutdown complete");
   ctx->connected = false;
   ctx->handshake_complete = true;
 }
@@ -474,18 +474,18 @@ static ssize_t recv_closed_stream(struct Curl_cfilter *cf,
   if(stream->reset) {
     failf(data, "HTTP/3 stream reset by server");
     *err = CURLE_PARTIAL_FILE;
-    DEBUGF(LOG_CF(data, cf, "cf_recv, was reset -> %d", *err));
+    CURL_TRC_CF(data, cf, "cf_recv, was reset -> %d", *err);
     goto out;
   }
   else if(stream->error3) {
     failf(data, "HTTP/3 stream was not closed cleanly: (error %zd)",
           (ssize_t)stream->error3);
     *err = CURLE_HTTP3;
-    DEBUGF(LOG_CF(data, cf, "cf_recv, closed uncleanly -> %d", *err));
+    CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly -> %d", *err);
     goto out;
   }
   else {
-    DEBUGF(LOG_CF(data, cf, "cf_recv, closed ok -> %d", *err));
+    CURL_TRC_CF(data, cf, "cf_recv, closed ok -> %d", *err);
   }
   *err = CURLE_OK;
   nread = 0;
@@ -523,7 +523,7 @@ static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
     return -1;
   }
   CF_DATA_SAVE(save, cf, data);
-  DEBUGF(LOG_CF(data, cf, "req: recv with %zu byte buffer", len));
+  CURL_TRC_CF(data, cf, "req: recv with %zu byte buffer", len);
 
   msh3_lock_acquire(&stream->recv_lock);
 
@@ -538,8 +538,8 @@ static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
   if(!Curl_bufq_is_empty(&stream->recvbuf)) {
     nread = Curl_bufq_read(&stream->recvbuf,
                            (unsigned char *)buf, len, err);
-    DEBUGF(LOG_CF(data, cf, "read recvbuf(len=%zu) -> %zd, %d",
-                  len, nread, *err));
+    CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %zd, %d",
+                len, nread, *err);
     if(nread < 0)
       goto out;
     if(stream->closed)
@@ -550,7 +550,7 @@ static ssize_t cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
     goto out;
   }
   else {
-    DEBUGF(LOG_CF(data, cf, "req: nothing here, call again"));
+    CURL_TRC_CF(data, cf, "req: nothing here, call again");
     *err = CURLE_AGAIN;
   }
 
@@ -581,7 +581,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
 
   /* Sizes must match for cast below to work" */
   DEBUGASSERT(stream);
-  DEBUGF(LOG_CF(data, cf, "req: send %zu bytes", len));
+  CURL_TRC_CF(data, cf, "req: send %zu bytes", len);
 
   if(!stream->req) {
     /* The first send on the request contains the headers and possibly some
@@ -630,7 +630,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
       break;
     }
 
-    DEBUGF(LOG_CF(data, cf, "req: send %zu headers", nheader));
+    CURL_TRC_CF(data, cf, "req: send %zu headers", nheader);
     stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data,
                                   nva, nheader,
                                   eos ? MSH3_REQUEST_FLAG_FIN :
@@ -646,7 +646,7 @@ static ssize_t cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data,
   }
   else {
     /* request is open */
-    DEBUGF(LOG_CF(data, cf, "req: send %zu body bytes", len));
+    CURL_TRC_CF(data, cf, "req: send %zu body bytes", len);
     if(len > 0xFFFFFFFF) {
       len = 0xFFFFFFFF;
     }
@@ -694,7 +694,7 @@ static int cf_msh3_get_select_socks(struct Curl_cfilter *cf,
       drain_stream(cf, data);
     }
   }
-  DEBUGF(LOG_CF(data, cf, "select_sock -> %d", bitmap));
+  CURL_TRC_CF(data, cf, "select_sock -> %d", bitmap);
   CF_DATA_RESTORE(cf, save);
   return bitmap;
 }
@@ -711,8 +711,8 @@ static bool cf_msh3_data_pending(struct Curl_cfilter *cf,
   (void)cf;
   if(stream && stream->req) {
     msh3_lock_acquire(&stream->recv_lock);
-    DEBUGF(LOG_CF((struct Curl_easy *)data, cf, "data pending = %zu",
-                  Curl_bufq_len(&stream->recvbuf)));
+    CURL_TRC_CF((struct Curl_easy *)data, cf, "data pending = %zu",
+                Curl_bufq_len(&stream->recvbuf));
     pending = !Curl_bufq_is_empty(&stream->recvbuf);
     msh3_lock_release(&stream->recv_lock);
     if(pending)
@@ -774,7 +774,7 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
     h3_data_done(cf, data);
     break;
   case CF_CTRL_DATA_DONE_SEND:
-    DEBUGF(LOG_CF(data, cf, "req: send done"));
+    CURL_TRC_CF(data, cf, "req: send done");
     if(stream) {
       stream->upload_done = TRUE;
       if(stream->req) {
@@ -787,7 +787,7 @@ static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf,
     }
     break;
   case CF_CTRL_CONN_INFO_UPDATE:
-    DEBUGF(LOG_CF(data, cf, "req: update info"));
+    CURL_TRC_CF(data, cf, "req: update info");
     cf_msh3_active(cf, data);
     break;
   default:
@@ -813,17 +813,17 @@ static CURLcode cf_connect_start(struct Curl_cfilter *cf,
     /* TODO: need a way to provide trust anchors to MSH3 */
 #ifdef DEBUGBUILD
     /* we need this for our test cases to run */
-    DEBUGF(LOG_CF(data, cf, "non-standard CA not supported, "
-                  "switching off verifypeer in DEBUG mode"));
+    CURL_TRC_CF(data, cf, "non-standard CA not supported, "
+                "switching off verifypeer in DEBUG mode");
     verify = 0;
 #else
-    DEBUGF(LOG_CF(data, cf, "non-standard CA not supported, "
-                  "attempting with built-in verification"));
+    CURL_TRC_CF(data, cf, "non-standard CA not supported, "
+                "attempting with built-in verification");
 #endif
   }
 
-  DEBUGF(LOG_CF(data, cf, "connecting to %s:%d (verify=%d)",
-                cf->conn->host.name, (int)cf->conn->remote_port, verify));
+  CURL_TRC_CF(data, cf, "connecting to %s:%d (verify=%d)",
+              cf->conn->host.name, (int)cf->conn->remote_port, verify);
 
   ctx->api = MsH3ApiOpen();
   if(!ctx->api) {
@@ -888,7 +888,7 @@ static CURLcode cf_msh3_connect(struct Curl_cfilter *cf,
   if(ctx->handshake_complete) {
     ctx->handshake_at = Curl_now();
     if(ctx->handshake_succeeded) {
-      DEBUGF(LOG_CF(data, cf, "handshake succeeded"));
+      CURL_TRC_CF(data, cf, "handshake succeeded");
       cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */
       cf->conn->httpversion = 30;
       cf->conn->bundle->multiuse = BUNDLE_MULTIPLEX;
@@ -918,7 +918,7 @@ static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data)
   CF_DATA_SAVE(save, cf, data);
 
   if(ctx) {
-    DEBUGF(LOG_CF(data, cf, "destroying"));
+    CURL_TRC_CF(data, cf, "destroying");
     if(ctx->qconn) {
       MsH3ConnectionClose(ctx->qconn);
       ctx->qconn = NULL;
@@ -935,13 +935,13 @@ static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data)
        */
       ctx->active = FALSE;
       if(ctx->sock[SP_LOCAL] == cf->conn->sock[cf->sockindex]) {
-        DEBUGF(LOG_CF(data, cf, "cf_msh3_close(%d) active",
-                      (int)ctx->sock[SP_LOCAL]));
+        CURL_TRC_CF(data, cf, "cf_msh3_close(%d) active",
+                    (int)ctx->sock[SP_LOCAL]);
         cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
       }
       else {
-        DEBUGF(LOG_CF(data, cf, "cf_socket_close(%d) no longer at "
-                      "conn->sock[], discarding", (int)ctx->sock[SP_LOCAL]));
+        CURL_TRC_CF(data, cf, "cf_socket_close(%d) no longer at "
+                    "conn->sock[], discarding", (int)ctx->sock[SP_LOCAL]);
         ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD;
       }
       if(cf->sockindex == FIRSTSOCKET)

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