Pārlūkot izejas kodu

curl 2025-02-05 (34cf9d54)

Code extracted from:

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

at commit 34cf9d54a46598c44938aa7598820484d7af7133 (curl-8_12_0).
Curl Upstream 8 mēneši atpakaļ
vecāks
revīzija
48b13baebc
100 mainītis faili ar 3434 papildinājumiem un 3956 dzēšanām
  1. 4 2
      CMake/CurlSymbolHiding.cmake
  2. 29 30
      CMake/CurlTests.c
  3. 35 35
      CMake/FindBrotli.cmake
  4. 50 44
      CMake/FindCares.cmake
  5. 5 5
      CMake/FindGSS.cmake
  6. 111 0
      CMake/FindLDAP.cmake
  7. 4 1
      CMake/FindLibgsasl.cmake
  8. 4 1
      CMake/FindLibidn2.cmake
  9. 37 35
      CMake/FindLibpsl.cmake
  10. 102 0
      CMake/FindLibrtmp.cmake
  11. 12 9
      CMake/FindLibssh.cmake
  12. 37 35
      CMake/FindLibssh2.cmake
  13. 4 1
      CMake/FindLibuv.cmake
  14. 5 2
      CMake/FindMSH3.cmake
  15. 7 2
      CMake/FindMbedTLS.cmake
  16. 37 35
      CMake/FindNGHTTP2.cmake
  17. 37 35
      CMake/FindNGHTTP3.cmake
  18. 63 55
      CMake/FindNGTCP2.cmake
  19. 4 1
      CMake/FindNettle.cmake
  20. 4 1
      CMake/FindQuiche.cmake
  21. 35 30
      CMake/FindRustls.cmake
  22. 9 6
      CMake/FindWolfSSL.cmake
  23. 47 45
      CMake/FindZstd.cmake
  24. 17 13
      CMake/Macros.cmake
  25. 11 11
      CMake/OtherTests.cmake
  26. 44 30
      CMake/PickyWarnings.cmake
  27. 25 7
      CMake/Utilities.cmake
  28. 27 8
      CMake/curl-config.cmake.in
  29. 22 11
      CMake/win32-cache.cmake
  30. 354 223
      CMakeLists.txt
  31. 1 1
      COPYING
  32. 49 3
      include/curl/curl.h
  33. 4 4
      include/curl/curlver.h
  34. 1 1
      include/curl/easy.h
  35. 40 96
      include/curl/system.h
  36. 5 11
      lib/CMakeLists.txt
  37. 10 2
      lib/Makefile.inc
  38. 78 67
      lib/altsvc.c
  39. 0 7
      lib/altsvc.h
  40. 2 3
      lib/amigaos.c
  41. 151 107
      lib/asyn-ares.c
  42. 72 38
      lib/asyn-thread.c
  43. 64 0
      lib/asyn.h
  44. 0 23
      lib/bufq.c
  45. 0 8
      lib/bufq.h
  46. 0 1254
      lib/c-hyper.c
  47. 0 63
      lib/c-hyper.h
  48. 1 339
      lib/cf-h1-proxy.c
  49. 2 0
      lib/cf-h2-proxy.c
  50. 232 117
      lib/cf-https-connect.c
  51. 2 2
      lib/cf-https-connect.h
  52. 41 16
      lib/cf-socket.c
  53. 3 3
      lib/cf-socket.h
  54. 24 14
      lib/cfilters.c
  55. 9 20
      lib/cfilters.h
  56. 90 20
      lib/conncache.c
  57. 7 5
      lib/conncache.h
  58. 24 2
      lib/connect.c
  59. 2 0
      lib/connect.h
  60. 61 289
      lib/content_encoding.c
  61. 64 32
      lib/cookie.c
  62. 5 5
      lib/cookie.h
  63. 0 8
      lib/curl_addrinfo.c
  64. 17 26
      lib/curl_config.h.cmake
  65. 1 1
      lib/curl_ctype.h
  66. 2 0
      lib/curl_get_line.c
  67. 6 0
      lib/curl_get_line.h
  68. 4 0
      lib/curl_gethostname.c
  69. 9 0
      lib/curl_gssapi.c
  70. 3 3
      lib/curl_hmac.h
  71. 212 21
      lib/curl_multibyte.c
  72. 6 0
      lib/curl_rtmp.c
  73. 101 95
      lib/curl_setup.h
  74. 10 16
      lib/curl_setup_once.h
  75. 1 1
      lib/curl_sha256.h
  76. 35 42
      lib/curl_sha512_256.c
  77. 6 6
      lib/curl_sspi.h
  78. 71 1
      lib/curl_trc.c
  79. 47 78
      lib/curl_trc.h
  80. 1 0
      lib/dict.c
  81. 54 138
      lib/doh.c
  82. 1 13
      lib/doh.h
  83. 12 0
      lib/dynbuf.c
  84. 5 0
      lib/dynbuf.h
  85. 55 3
      lib/easy.c
  86. 4 2
      lib/easy_lock.h
  87. 1 1
      lib/easyoptions.c
  88. 19 19
      lib/file.c
  89. 1 1
      lib/fopen.c
  90. 19 4
      lib/ftp.c
  91. 1 0
      lib/functypes.h
  92. 13 0
      lib/getinfo.c
  93. 2 0
      lib/gopher.c
  94. 2 0
      lib/hash.c
  95. 3 2
      lib/hmac.c
  96. 8 14
      lib/hostip.c
  97. 8 30
      lib/hostip.h
  98. 37 28
      lib/hsts.c
  99. 1 1
      lib/hsts.h
  100. 430 137
      lib/http.c

+ 4 - 2
CMake/CurlSymbolHiding.cmake

@@ -29,11 +29,13 @@ if(WIN32 AND (ENABLE_DEBUG OR ENABLE_CURLDEBUG))
   # e.g. curl_easy_perform_ev() or curl_dbg_*(),
   # so disable symbol hiding for debug builds and for memory tracking.
   set(CURL_HIDDEN_SYMBOLS OFF)
+elseif(DOS OR AMIGA)
+  set(CURL_HIDDEN_SYMBOLS OFF)
 endif()
 
 set(CURL_HIDES_PRIVATE_SYMBOLS FALSE)
-unset(CURL_EXTERN_SYMBOL)
-unset(CURL_CFLAG_SYMBOLS_HIDE)
+set(CURL_EXTERN_SYMBOL "")
+set(CURL_CFLAG_SYMBOLS_HIDE "")
 
 if(CURL_HIDDEN_SYMBOLS)
   if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT MSVC)

+ 29 - 30
CMake/CurlTests.c

@@ -50,7 +50,6 @@ int main(void)
   int flags = 0;
   if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK))
     return 1;
-  ;
   return 0;
 }
 #endif
@@ -147,24 +146,21 @@ int main(void) { return 0; }
 #endif
 
 #ifdef HAVE_FILE_OFFSET_BITS
-#ifdef _FILE_OFFSET_BITS
 #undef _FILE_OFFSET_BITS
-#endif
 #define _FILE_OFFSET_BITS 64
 #include <sys/types.h>
- /* Check that off_t can represent 2**63 - 1 correctly.
-    We cannot simply define LARGE_OFF_T to be 9223372036854775807,
-    since some C++ compilers masquerading as C compilers
-    incorrectly reject 9223372036854775807.  */
+/* Check that off_t can represent 2**63 - 1 correctly.
+   We cannot simply define LARGE_OFF_T to be 9223372036854775807,
+   since some C++ compilers masquerading as C compilers
+   incorrectly reject 9223372036854775807. */
 #define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62))
-  int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
-                       && LARGE_OFF_T % 2147483647 == 1)
-                      ? 1 : -1];
+int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721
+                     && LARGE_OFF_T % 2147483647 == 1)
+                    ? 1 : -1];
 int main(void) { return 0; }
 #endif
 
 #ifdef HAVE_IOCTLSOCKET
-/* includes start */
 #ifdef _WIN32
 #  include <winsock2.h>
 #endif
@@ -180,10 +176,7 @@ int main(void)
 #endif
 
 #ifdef HAVE_IOCTLSOCKET_CAMEL
-/* includes start */
-#ifdef _WIN32
-#  include <winsock2.h>
-#endif
+#include <proto/bsdsocket.h>
 int main(void)
 {
   /* IoctlSocket source code */
@@ -195,9 +188,9 @@ int main(void)
 #endif
 
 #ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
-/* includes start */
-#ifdef _WIN32
-#  include <winsock2.h>
+#include <proto/bsdsocket.h>
+#ifdef HAVE_SYS_IOCTL_H
+#  include <sys/ioctl.h>
 #endif
 int main(void)
 {
@@ -211,7 +204,6 @@ int main(void)
 #endif
 
 #ifdef HAVE_IOCTLSOCKET_FIONBIO
-/* includes start */
 #ifdef _WIN32
 #  include <winsock2.h>
 #endif
@@ -227,7 +219,6 @@ int main(void)
 
 #ifdef HAVE_IOCTL_FIONBIO
 /* headers for FIONBIO test */
-/* includes start */
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
@@ -255,7 +246,6 @@ int main(void)
 
 #ifdef HAVE_IOCTL_SIOCGIFADDR
 /* headers for FIONBIO test */
-/* includes start */
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
@@ -283,18 +273,15 @@ int main(void)
 #endif
 
 #ifdef HAVE_SETSOCKOPT_SO_NONBLOCK
-/* includes start */
 #ifdef _WIN32
 #  include <winsock2.h>
 #endif
-/* includes start */
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
 #ifdef HAVE_SYS_SOCKET_H
 #  include <sys/socket.h>
 #endif
-/* includes end */
 int main(void)
 {
   if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0))
@@ -372,7 +359,6 @@ int main(void)
 #endif
 
 #ifdef HAVE_ATOMIC
-/* includes start */
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
@@ -382,8 +368,6 @@ int main(void)
 #ifdef HAVE_STDATOMIC_H
 #  include <stdatomic.h>
 #endif
-/* includes end */
-
 int main(void)
 {
   _Atomic int i = 1;
@@ -393,14 +377,12 @@ int main(void)
 #endif
 
 #ifdef HAVE_WIN32_WINNT
-/* includes start */
 #ifdef _WIN32
 #  ifndef NOGDI
-#    define NOGDI
+#  define NOGDI
 #  endif
 #  include <windows.h>
 #endif
-/* includes end */
 
 #define enquote(x) #x
 #define expand(x) enquote(x)
@@ -411,3 +393,20 @@ int main(void)
   return 0;
 }
 #endif
+
+#ifdef MINGW64_VERSION
+#ifdef __MINGW32__
+#  include <_mingw.h>
+#endif
+
+#define enquote(x) #x
+#define expand(x) enquote(x)
+#pragma message("MINGW64_VERSION=" \
+  expand(__MINGW64_VERSION_MAJOR) "." \
+  expand(__MINGW64_VERSION_MINOR))
+
+int main(void)
+{
+  return 0;
+}
+#endif

+ 35 - 35
CMake/FindBrotli.cmake

@@ -34,47 +34,47 @@
 # - `BROTLI_FOUND`:          System has brotli.
 # - `BROTLI_INCLUDE_DIRS`:   The brotli include directories.
 # - `BROTLI_LIBRARIES`:      The brotli library names.
+# - `BROTLI_LIBRARY_DIRS`:   The brotli library directories.
+# - `BROTLI_PC_REQUIRES`:    The brotli pkg-config packages.
+# - `BROTLI_CFLAGS`:         Required compiler flags.
 # - `BROTLI_VERSION`:        Version of brotli.
 
-if(CURL_USE_PKGCONFIG)
+set(BROTLI_PC_REQUIRES "libbrotlidec")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED BROTLI_INCLUDE_DIR AND
+   NOT DEFINED BROTLICOMMON_LIBRARY AND
+   NOT DEFINED BROTLIDEC_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_BROTLI "libbrotlidec")
+  pkg_check_modules(BROTLI "libbrotlicommon")
+  pkg_check_modules(BROTLIDEC ${BROTLI_PC_REQUIRES})
 endif()
 
-find_path(BROTLI_INCLUDE_DIR "brotli/decode.h"
-  HINTS
-    ${PC_BROTLI_INCLUDEDIR}
-    ${PC_BROTLI_INCLUDE_DIRS}
-)
-
-find_library(BROTLICOMMON_LIBRARY NAMES "brotlicommon"
-  HINTS
-    ${PC_BROTLI_LIBDIR}
-    ${PC_BROTLI_LIBRARY_DIRS}
-)
-find_library(BROTLIDEC_LIBRARY NAMES "brotlidec"
-  HINTS
-    ${PC_BROTLI_LIBDIR}
-    ${PC_BROTLI_LIBRARY_DIRS}
-)
+if(BROTLI_FOUND AND BROTLIDEC_FOUND)
+  list(APPEND BROTLIDEC_LIBRARIES ${BROTLI_LIBRARIES})  # order is significant: brotlidec then brotlicommon
+  list(REVERSE BROTLIDEC_LIBRARIES)
+  list(REMOVE_DUPLICATES BROTLIDEC_LIBRARIES)
+  list(REVERSE BROTLIDEC_LIBRARIES)
+  set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARIES})
+  string(REPLACE ";" " " BROTLI_CFLAGS "${BROTLI_CFLAGS}")
+  message(STATUS "Found Brotli (via pkg-config): ${BROTLI_INCLUDE_DIRS} (found version \"${BROTLI_VERSION}\")")
+else()
+  find_path(BROTLI_INCLUDE_DIR "brotli/decode.h")
+  find_library(BROTLICOMMON_LIBRARY NAMES "brotlicommon")
+  find_library(BROTLIDEC_LIBRARY NAMES "brotlidec")
 
-if(PC_BROTLI_VERSION)
-  set(BROTLI_VERSION ${PC_BROTLI_VERSION})
-endif()
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Brotli
+    REQUIRED_VARS
+      BROTLI_INCLUDE_DIR
+      BROTLIDEC_LIBRARY
+      BROTLICOMMON_LIBRARY
+  )
 
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Brotli
-  REQUIRED_VARS
-    BROTLI_INCLUDE_DIR
-    BROTLIDEC_LIBRARY
-    BROTLICOMMON_LIBRARY
-  VERSION_VAR
-    BROTLI_VERSION
-)
+  if(BROTLI_FOUND)
+    set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
+    set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARY} ${BROTLICOMMON_LIBRARY})
+  endif()
 
-if(BROTLI_FOUND)
-  set(BROTLI_INCLUDE_DIRS ${BROTLI_INCLUDE_DIR})
-  set(BROTLI_LIBRARIES ${BROTLIDEC_LIBRARY} ${BROTLICOMMON_LIBRARY})
+  mark_as_advanced(BROTLI_INCLUDE_DIR BROTLIDEC_LIBRARY BROTLICOMMON_LIBRARY)
 endif()
-
-mark_as_advanced(BROTLI_INCLUDE_DIR BROTLIDEC_LIBRARY BROTLICOMMON_LIBRARY)

+ 50 - 44
CMake/FindCares.cmake

@@ -33,58 +33,64 @@
 # - `CARES_FOUND`:         System has c-ares.
 # - `CARES_INCLUDE_DIRS`:  The c-ares include directories.
 # - `CARES_LIBRARIES`:     The c-ares library names.
+# - `CARES_LIBRARY_DIRS`:  The c-ares library directories.
+# - `CARES_PC_REQUIRES`:   The c-ares pkg-config packages.
+# - `CARES_CFLAGS`:        Required compiler flags.
 # - `CARES_VERSION`:       Version of c-ares.
 
-if(CURL_USE_PKGCONFIG)
+set(CARES_PC_REQUIRES "libcares")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED CARES_INCLUDE_DIR AND
+   NOT DEFINED CARES_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_CARES "libcares")
+  pkg_check_modules(CARES ${CARES_PC_REQUIRES})
 endif()
 
-find_path(CARES_INCLUDE_DIR NAMES "ares.h"
-  HINTS
-    ${PC_CARES_INCLUDEDIR}
-    ${PC_CARES_INCLUDE_DIRS}
-)
+if(CARES_FOUND)
+  string(REPLACE ";" " " CARES_CFLAGS "${CARES_CFLAGS}")
+  message(STATUS "Found Cares (via pkg-config): ${CARES_INCLUDE_DIRS} (found version \"${CARES_VERSION}\")")
+else()
+  find_path(CARES_INCLUDE_DIR NAMES "ares.h")
+  find_library(CARES_LIBRARY NAMES ${CARES_NAMES} "cares")
 
-find_library(CARES_LIBRARY NAMES ${CARES_NAMES} "cares"
-  HINTS
-    ${PC_CARES_LIBDIR}
-    ${PC_CARES_LIBRARY_DIRS}
-)
+  unset(CARES_VERSION CACHE)
+  if(CARES_INCLUDE_DIR AND EXISTS "${CARES_INCLUDE_DIR}/ares_version.h")
+    set(_version_regex1 "#[\t ]*define[\t ]+ARES_VERSION_MAJOR[\t ]+([0-9]+).*")
+    set(_version_regex2 "#[\t ]*define[\t ]+ARES_VERSION_MINOR[\t ]+([0-9]+).*")
+    set(_version_regex3 "#[\t ]*define[\t ]+ARES_VERSION_PATCH[\t ]+([0-9]+).*")
+    file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str1 REGEX "${_version_regex1}")
+    file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str2 REGEX "${_version_regex2}")
+    file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str3 REGEX "${_version_regex3}")
+    string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
+    string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
+    string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
+    set(CARES_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
+    unset(_version_regex1)
+    unset(_version_regex2)
+    unset(_version_regex3)
+    unset(_version_str1)
+    unset(_version_str2)
+    unset(_version_str3)
+  endif()
 
-if(PC_CARES_VERSION)
-  set(CARES_VERSION ${PC_CARES_VERSION})
-elseif(CARES_INCLUDE_DIR AND EXISTS "${CARES_INCLUDE_DIR}/ares_version.h")
-  set(_version_regex1 "#[\t ]*define[\t ]+ARES_VERSION_MAJOR[\t ]+([0-9]+).*")
-  set(_version_regex2 "#[\t ]*define[\t ]+ARES_VERSION_MINOR[\t ]+([0-9]+).*")
-  set(_version_regex3 "#[\t ]*define[\t ]+ARES_VERSION_PATCH[\t ]+([0-9]+).*")
-  file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str1 REGEX "${_version_regex1}")
-  file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str2 REGEX "${_version_regex2}")
-  file(STRINGS "${CARES_INCLUDE_DIR}/ares_version.h" _version_str3 REGEX "${_version_regex3}")
-  string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
-  string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
-  string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
-  set(CARES_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
-  unset(_version_regex1)
-  unset(_version_regex2)
-  unset(_version_regex3)
-  unset(_version_str1)
-  unset(_version_str2)
-  unset(_version_str3)
-endif()
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Cares
+    REQUIRED_VARS
+      CARES_INCLUDE_DIR
+      CARES_LIBRARY
+    VERSION_VAR
+      CARES_VERSION
+  )
 
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Cares
-  REQUIRED_VARS
-    CARES_INCLUDE_DIR
-    CARES_LIBRARY
-  VERSION_VAR
-    CARES_VERSION
-)
+  if(CARES_FOUND)
+    set(CARES_INCLUDE_DIRS ${CARES_INCLUDE_DIR})
+    set(CARES_LIBRARIES    ${CARES_LIBRARY})
+  endif()
 
-if(CARES_FOUND)
-  set(CARES_INCLUDE_DIRS ${CARES_INCLUDE_DIR})
-  set(CARES_LIBRARIES    ${CARES_LIBRARY})
+  mark_as_advanced(CARES_INCLUDE_DIR CARES_LIBRARY)
 endif()
 
-mark_as_advanced(CARES_INCLUDE_DIR CARES_LIBRARY)
+if(CARES_FOUND AND WIN32)
+  list(APPEND CARES_LIBRARIES "iphlpapi")  # for if_indextoname and others
+endif()

+ 5 - 5
CMake/FindGSS.cmake

@@ -99,7 +99,7 @@ if(NOT _GSS_FOUND)  # Not found by pkg-config. Let us take more traditional appr
       string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")
 
       foreach(_flag IN LISTS _GSS_CFLAGS)
-        if(_flag MATCHES "^-I.*")
+        if(_flag MATCHES "^-I")
           string(REGEX REPLACE "^-I" "" _val "${_flag}")
           list(APPEND _GSS_INCLUDE_DIRS "${_val}")
         else()
@@ -123,10 +123,10 @@ if(NOT _GSS_FOUND)  # Not found by pkg-config. Let us take more traditional appr
       string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
 
       foreach(_flag IN LISTS _gss_lib_flags)
-        if(_flag MATCHES "^-l.*")
+        if(_flag MATCHES "^-l")
           string(REGEX REPLACE "^-l" "" _val "${_flag}")
           list(APPEND _GSS_LIBRARIES "${_val}")
-        elseif(_flag MATCHES "^-L.*")
+        elseif(_flag MATCHES "^-L")
           string(REGEX REPLACE "^-L" "" _val "${_flag}")
           list(APPEND _GSS_LIBRARY_DIRS "${_val}")
         endif()
@@ -156,7 +156,7 @@ if(NOT _GSS_FOUND)  # Not found by pkg-config. Let us take more traditional appr
     if(_gss_configure_failed)
       set(GSS_FLAVOUR "Heimdal")  # most probably, should not really matter
     else()
-      if(_gss_vendor MATCHES ".*H|heimdal.*")
+      if(_gss_vendor MATCHES "H|heimdal")
         set(GSS_FLAVOUR "Heimdal")
       else()
         set(GSS_FLAVOUR "MIT")
@@ -175,7 +175,7 @@ if(NOT _GSS_FOUND)  # Not found by pkg-config. Let us take more traditional appr
 
     if(_GSS_INCLUDE_DIRS)  # jay, we have found something
       cmake_push_check_state()
-      set(CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIRS}")
+      list(APPEND CMAKE_REQUIRED_INCLUDES "${_GSS_INCLUDE_DIRS}")
       check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
 
       if(_gss_have_mit_headers)

+ 111 - 0
CMake/FindLDAP.cmake

@@ -0,0 +1,111 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the ldap library
+#
+# Input variables:
+#
+# - `LDAP_INCLUDE_DIR`:   The ldap include directory.
+# - `LDAP_LIBRARY`:       Path to `ldap` library.
+# - `LDAP_LBER_LIBRARY`:  Path to `lber` library.
+#
+# Result variables:
+#
+# - `LDAP_FOUND`:         System has ldap.
+# - `LDAP_INCLUDE_DIRS`:  The ldap include directories.
+# - `LDAP_LIBRARIES`:     The ldap library names.
+# - `LDAP_LIBRARY_DIRS`:  The ldap library directories.
+# - `LDAP_PC_REQUIRES`:   The ldap pkg-config packages.
+# - `LDAP_CFLAGS`:        Required compiler flags.
+# - `LDAP_VERSION`:       Version of ldap.
+
+set(LDAP_PC_REQUIRES "ldap")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED LDAP_INCLUDE_DIR AND
+   NOT DEFINED LDAP_LIBRARY AND
+   NOT DEFINED LDAP_LBER_LIBRARY)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(LDAP ${LDAP_PC_REQUIRES})
+  pkg_check_modules(LDAP_LBER "lber")
+endif()
+
+if(LDAP_FOUND AND LDAP_LBER_FOUND)
+  list(APPEND LDAP_LIBRARIES ${LDAP_LBER_LIBRARIES})
+  list(REVERSE LDAP_LIBRARIES)
+  list(REMOVE_DUPLICATES LDAP_LIBRARIES)
+  list(REVERSE LDAP_LIBRARIES)
+  string(REPLACE ";" " " LDAP_CFLAGS "${LDAP_CFLAGS}")
+  message(STATUS "Found LDAP (via pkg-config): ${LDAP_INCLUDE_DIRS} (found version \"${LDAP_VERSION}\")")
+else()
+  set(LDAP_PC_REQUIRES "")  # Depend on pkg-config only when found via pkg-config
+
+  # On Apple the SDK LDAP gets picked up from
+  # 'MacOSX.sdk/System/Library/Frameworks/LDAP.framework/Headers', which contains
+  # ldap.h and lber.h both being stubs to include <ldap.h> and <lber.h>.
+  # This causes an infinite inclusion loop in compile. Also do this for libraries
+  # to avoid picking up the 'ldap.framework' with a full path.
+  set(_save_cmake_system_framework_path ${CMAKE_SYSTEM_FRAMEWORK_PATH})
+  set(CMAKE_SYSTEM_FRAMEWORK_PATH "")
+  find_path(LDAP_INCLUDE_DIR NAMES "ldap.h")
+  find_library(LDAP_LIBRARY NAMES "ldap")
+  find_library(LDAP_LBER_LIBRARY NAMES "lber")
+  set(CMAKE_SYSTEM_FRAMEWORK_PATH ${_save_cmake_system_framework_path})
+
+  unset(LDAP_VERSION CACHE)
+  if(LDAP_INCLUDE_DIR AND EXISTS "${LDAP_INCLUDE_DIR}/ldap_features.h")
+    set(_version_regex1 "#[\t ]*define[\t ]+LDAP_VENDOR_VERSION_MAJOR[\t ]+([0-9]+).*")
+    set(_version_regex2 "#[\t ]*define[\t ]+LDAP_VENDOR_VERSION_MINOR[\t ]+([0-9]+).*")
+    set(_version_regex3 "#[\t ]*define[\t ]+LDAP_VENDOR_VERSION_PATCH[\t ]+([0-9]+).*")
+    file(STRINGS "${LDAP_INCLUDE_DIR}/ldap_features.h" _version_str1 REGEX "${_version_regex1}")
+    file(STRINGS "${LDAP_INCLUDE_DIR}/ldap_features.h" _version_str2 REGEX "${_version_regex2}")
+    file(STRINGS "${LDAP_INCLUDE_DIR}/ldap_features.h" _version_str3 REGEX "${_version_regex3}")
+    string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
+    string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
+    string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
+    set(LDAP_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
+    unset(_version_regex1)
+    unset(_version_regex2)
+    unset(_version_regex3)
+    unset(_version_str1)
+    unset(_version_str2)
+    unset(_version_str3)
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(LDAP
+    REQUIRED_VARS
+      LDAP_INCLUDE_DIR
+      LDAP_LIBRARY
+      LDAP_LBER_LIBRARY
+    VERSION_VAR
+      LDAP_VERSION
+  )
+
+  if(LDAP_FOUND)
+    set(LDAP_INCLUDE_DIRS ${LDAP_INCLUDE_DIR})
+    set(LDAP_LIBRARIES    ${LDAP_LIBRARY} ${LDAP_LBER_LIBRARY})
+  endif()
+
+  mark_as_advanced(LDAP_INCLUDE_DIR LDAP_LIBRARY LDAP_LBER_LIBRARY)
+endif()

+ 4 - 1
CMake/FindLibgsasl.cmake

@@ -34,14 +34,17 @@
 # - `LIBGSASL_INCLUDE_DIRS`:  The libgsasl include directories.
 # - `LIBGSASL_LIBRARIES`:     The libgsasl library names.
 # - `LIBGSASL_LIBRARY_DIRS`:  The libgsasl library directories.
+# - `LIBGSASL_PC_REQUIRES`:   The libgsasl pkg-config packages.
 # - `LIBGSASL_CFLAGS`:        Required compiler flags.
 # - `LIBGSASL_VERSION`:       Version of libgsasl.
 
+set(LIBGSASL_PC_REQUIRES "libgsasl")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBGSASL_INCLUDE_DIR AND
    NOT DEFINED LIBGSASL_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(LIBGSASL "libgsasl")
+  pkg_check_modules(LIBGSASL ${LIBGSASL_PC_REQUIRES})
 endif()
 
 if(LIBGSASL_FOUND)

+ 4 - 1
CMake/FindLibidn2.cmake

@@ -34,14 +34,17 @@
 # - `LIBIDN2_INCLUDE_DIRS`:  The libidn2 include directories.
 # - `LIBIDN2_LIBRARIES`:     The libidn2 library names.
 # - `LIBIDN2_LIBRARY_DIRS`:  The libidn2 library directories.
+# - `LIBIDN2_PC_REQUIRES`:   The libidn2 pkg-config packages.
 # - `LIBIDN2_CFLAGS`:        Required compiler flags.
 # - `LIBIDN2_VERSION`:       Version of libidn2.
 
+set(LIBIDN2_PC_REQUIRES "libidn2")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBIDN2_INCLUDE_DIR AND
    NOT DEFINED LIBIDN2_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(LIBIDN2 "libidn2")
+  pkg_check_modules(LIBIDN2 ${LIBIDN2_PC_REQUIRES})
 endif()
 
 if(LIBIDN2_FOUND)

+ 37 - 35
CMake/FindLibpsl.cmake

@@ -33,48 +33,50 @@
 # - `LIBPSL_FOUND`:         System has libpsl.
 # - `LIBPSL_INCLUDE_DIRS`:  The libpsl include directories.
 # - `LIBPSL_LIBRARIES`:     The libpsl library names.
+# - `LIBPSL_LIBRARY_DIRS`:  The libpsl library directories.
+# - `LIBPSL_PC_REQUIRES`:   The libpsl pkg-config packages.
+# - `LIBPSL_CFLAGS`:        Required compiler flags.
 # - `LIBPSL_VERSION`:       Version of libpsl.
 
-if(CURL_USE_PKGCONFIG)
+set(LIBPSL_PC_REQUIRES "libpsl")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED LIBPSL_INCLUDE_DIR AND
+   NOT DEFINED LIBPSL_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_LIBPSL "libpsl")
+  pkg_check_modules(LIBPSL ${LIBPSL_PC_REQUIRES})
 endif()
 
-find_path(LIBPSL_INCLUDE_DIR NAMES "libpsl.h"
-  HINTS
-    ${PC_LIBPSL_INCLUDEDIR}
-    ${PC_LIBPSL_INCLUDE_DIRS}
-)
+if(LIBPSL_FOUND AND LIBPSL_INCLUDE_DIRS)
+  string(REPLACE ";" " " LIBPSL_CFLAGS "${LIBPSL_CFLAGS}")
+  message(STATUS "Found Libpsl (via pkg-config): ${LIBPSL_INCLUDE_DIRS} (found version \"${LIBPSL_VERSION}\")")
+else()
+  find_path(LIBPSL_INCLUDE_DIR NAMES "libpsl.h")
+  find_library(LIBPSL_LIBRARY NAMES "psl" "libpsl")
 
-find_library(LIBPSL_LIBRARY NAMES "psl" "libpsl"
-  HINTS
-    ${PC_LIBPSL_LIBDIR}
-    ${PC_LIBPSL_LIBRARY_DIRS}
-)
+  unset(LIBPSL_VERSION CACHE)
+  if(LIBPSL_INCLUDE_DIR AND EXISTS "${LIBPSL_INCLUDE_DIR}/libpsl.h")
+    set(_version_regex "#[\t ]*define[\t ]+PSL_VERSION[\t ]+\"([^\"]*)\"")
+    file(STRINGS "${LIBPSL_INCLUDE_DIR}/libpsl.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(LIBPSL_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
+  endif()
 
-if(PC_LIBPSL_VERSION)
-  set(LIBPSL_VERSION ${PC_LIBPSL_VERSION})
-elseif(LIBPSL_INCLUDE_DIR AND EXISTS "${LIBPSL_INCLUDE_DIR}/libpsl.h")
-  set(_version_regex "#[\t ]*define[\t ]+PSL_VERSION[\t ]+\"([^\"]*)\"")
-  file(STRINGS "${LIBPSL_INCLUDE_DIR}/libpsl.h" _version_str REGEX "${_version_regex}")
-  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
-  set(LIBPSL_VERSION "${_version_str}")
-  unset(_version_regex)
-  unset(_version_str)
-endif()
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Libpsl
+    REQUIRED_VARS
+      LIBPSL_INCLUDE_DIR
+      LIBPSL_LIBRARY
+    VERSION_VAR
+      LIBPSL_VERSION
+  )
 
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Libpsl
-  REQUIRED_VARS
-    LIBPSL_INCLUDE_DIR
-    LIBPSL_LIBRARY
-  VERSION_VAR
-    LIBPSL_VERSION
-)
+  if(LIBPSL_FOUND)
+    set(LIBPSL_INCLUDE_DIRS ${LIBPSL_INCLUDE_DIR})
+    set(LIBPSL_LIBRARIES    ${LIBPSL_LIBRARY})
+  endif()
 
-if(LIBPSL_FOUND)
-  set(LIBPSL_INCLUDE_DIRS ${LIBPSL_INCLUDE_DIR})
-  set(LIBPSL_LIBRARIES    ${LIBPSL_LIBRARY})
+  mark_as_advanced(LIBPSL_INCLUDE_DIR LIBPSL_LIBRARY)
 endif()
-
-mark_as_advanced(LIBPSL_INCLUDE_DIR LIBPSL_LIBRARY)

+ 102 - 0
CMake/FindLibrtmp.cmake

@@ -0,0 +1,102 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  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
+#
+###########################################################################
+# Find the librtmp library
+#
+# Input variables:
+#
+# - `LIBRTMP_INCLUDE_DIR`:   The librtmp include directory.
+# - `LIBRTMP_LIBRARY`:       Path to `librtmp` library.
+#
+# Result variables:
+#
+# - `LIBRTMP_FOUND`:         System has librtmp.
+# - `LIBRTMP_INCLUDE_DIRS`:  The librtmp include directories.
+# - `LIBRTMP_LIBRARIES`:     The librtmp library names.
+# - `LIBRTMP_LIBRARY_DIRS`:  The librtmp library directories.
+# - `LIBRTMP_PC_REQUIRES`:   The librtmp pkg-config packages.
+# - `LIBRTMP_CFLAGS`:        Required compiler flags.
+# - `LIBRTMP_VERSION`:       Version of librtmp.
+
+set(LIBRTMP_PC_REQUIRES "librtmp")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED LIBRTMP_INCLUDE_DIR AND
+   NOT DEFINED LIBRTMP_LIBRARY)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(LIBRTMP ${LIBRTMP_PC_REQUIRES})
+endif()
+
+if(LIBRTMP_FOUND AND LIBRTMP_INCLUDE_DIRS)
+  string(REPLACE ";" " " LIBRTMP_CFLAGS "${LIBRTMP_CFLAGS}")
+  message(STATUS "Found Librtmp (via pkg-config): ${LIBRTMP_INCLUDE_DIRS} (found version \"${LIBRTMP_VERSION}\")")
+else()
+  find_path(LIBRTMP_INCLUDE_DIR NAMES "librtmp/rtmp.h")
+  find_library(LIBRTMP_LIBRARY NAMES "rtmp")
+
+  unset(LIBRTMP_VERSION CACHE)
+  if(LIBRTMP_INCLUDE_DIR AND EXISTS "${LIBRTMP_INCLUDE_DIR}/librtmp/rtmp.h")
+    set(_version_regex "#[\t ]*define[\t ]+RTMP_LIB_VERSION[\t ]+0x([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F]).*")
+    file(STRINGS "${LIBRTMP_INCLUDE_DIR}/librtmp/rtmp.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str1 "${_version_str}")
+    string(REGEX REPLACE "${_version_regex}" "\\2" _version_str2 "${_version_str}")
+    if(CMAKE_VERSION VERSION_LESS 3.13)
+      # No support for hex version numbers, just strip leading zeroes
+      string(REGEX REPLACE "^0" "" _version_str1 "${_version_str1}")
+      string(REGEX REPLACE "^0" "" _version_str2 "${_version_str2}")
+    else()
+      math(EXPR _version_str1 "0x${_version_str1}" OUTPUT_FORMAT DECIMAL)
+      math(EXPR _version_str2 "0x${_version_str2}" OUTPUT_FORMAT DECIMAL)
+    endif()
+    set(LIBRTMP_VERSION "${_version_str1}.${_version_str2}")
+    unset(_version_regex)
+    unset(_version_str1)
+    unset(_version_str2)
+  endif()
+
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Librtmp
+    REQUIRED_VARS
+      LIBRTMP_INCLUDE_DIR
+      LIBRTMP_LIBRARY
+    VERSION_VAR
+      LIBRTMP_VERSION
+  )
+
+  if(LIBRTMP_FOUND)
+    set(LIBRTMP_INCLUDE_DIRS ${LIBRTMP_INCLUDE_DIR})
+    set(LIBRTMP_LIBRARIES    ${LIBRTMP_LIBRARY})
+  endif()
+
+  mark_as_advanced(LIBRTMP_INCLUDE_DIR LIBRTMP_LIBRARY)
+
+  # Necessary when linking a static librtmp
+  find_package(OpenSSL)
+  if(OPENSSL_FOUND)
+    list(APPEND LIBRTMP_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
+  endif()
+endif()
+
+if(LIBRTMP_FOUND AND WIN32)
+  list(APPEND LIBRTMP_LIBRARIES "winmm")
+endif()

+ 12 - 9
CMake/FindLibssh.cmake

@@ -25,23 +25,26 @@
 #
 # Input variables:
 #
-# LIBSSH_INCLUDE_DIR   The libssh include directory.
-# LIBSSH_LIBRARY       Path to libssh library.
+# - `LIBSSH_INCLUDE_DIR`:   The libssh include directory.
+# - `LIBSSH_LIBRARY`:       Path to libssh library.
 #
 # Result variables:
 #
-# LIBSSH_FOUND         System has libssh.
-# LIBSSH_INCLUDE_DIRS  The libssh include directories.
-# LIBSSH_LIBRARIES     The libssh library names.
-# LIBSSH_LIBRARY_DIRS  The libssh library directories.
-# LIBSSH_CFLAGS        Required compiler flags.
-# LIBSSH_VERSION       Version of libssh.
+# - `LIBSSH_FOUND`:         System has libssh.
+# - `LIBSSH_INCLUDE_DIRS`:  The libssh include directories.
+# - `LIBSSH_LIBRARIES`:     The libssh library names.
+# - `LIBSSH_LIBRARY_DIRS`:  The libssh library directories.
+# - `LIBSSH_PC_REQUIRES`:   The libssh pkg-config packages.
+# - `LIBSSH_CFLAGS`:        Required compiler flags.
+# - `LIBSSH_VERSION`:       Version of libssh.
+
+set(LIBSSH_PC_REQUIRES "libssh")
 
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBSSH_INCLUDE_DIR AND
    NOT DEFINED LIBSSH_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(LIBSSH "libssh")
+  pkg_check_modules(LIBSSH ${LIBSSH_PC_REQUIRES})
 endif()
 
 if(LIBSSH_FOUND)

+ 37 - 35
CMake/FindLibssh2.cmake

@@ -33,48 +33,50 @@
 # - `LIBSSH2_FOUND`:         System has libssh2.
 # - `LIBSSH2_INCLUDE_DIRS`:  The libssh2 include directories.
 # - `LIBSSH2_LIBRARIES`:     The libssh2 library names.
+# - `LIBSSH2_LIBRARY_DIRS`:  The libssh2 library directories.
+# - `LIBSSH2_PC_REQUIRES`:   The libssh2 pkg-config packages.
+# - `LIBSSH2_CFLAGS`:        Required compiler flags.
 # - `LIBSSH2_VERSION`:       Version of libssh2.
 
-if(CURL_USE_PKGCONFIG)
+set(LIBSSH2_PC_REQUIRES "libssh2")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED LIBSSH2_INCLUDE_DIR AND
+   NOT DEFINED LIBSSH2_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_LIBSSH2 "libssh2")
+  pkg_check_modules(LIBSSH2 ${LIBSSH2_PC_REQUIRES})
 endif()
 
-find_path(LIBSSH2_INCLUDE_DIR NAMES "libssh2.h"
-  HINTS
-    ${PC_LIBSSH2_INCLUDEDIR}
-    ${PC_LIBSSH2_INCLUDE_DIRS}
-)
+if(LIBSSH2_FOUND AND LIBSSH2_INCLUDE_DIRS)
+  string(REPLACE ";" " " LIBSSH2_CFLAGS "${LIBSSH2_CFLAGS}")
+  message(STATUS "Found Libssh2 (via pkg-config): ${LIBSSH2_INCLUDE_DIRS} (found version \"${LIBSSH2_VERSION}\")")
+else()
+  find_path(LIBSSH2_INCLUDE_DIR NAMES "libssh2.h")
+  find_library(LIBSSH2_LIBRARY NAMES "ssh2" "libssh2")
 
-find_library(LIBSSH2_LIBRARY NAMES "ssh2" "libssh2"
-  HINTS
-    ${PC_LIBSSH2_LIBDIR}
-    ${PC_LIBSSH2_LIBRARY_DIRS}
-)
+  unset(LIBSSH2_VERSION CACHE)
+  if(LIBSSH2_INCLUDE_DIR AND EXISTS "${LIBSSH2_INCLUDE_DIR}/libssh2.h")
+    set(_version_regex "#[\t ]*define[\t ]+LIBSSH2_VERSION[\t ]+\"([^\"]*)\"")
+    file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(LIBSSH2_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
+  endif()
 
-if(PC_LIBSSH2_VERSION)
-  set(LIBSSH2_VERSION ${PC_LIBSSH2_VERSION})
-elseif(LIBSSH2_INCLUDE_DIR AND EXISTS "${LIBSSH2_INCLUDE_DIR}/libssh2.h")
-  set(_version_regex "#[\t ]*define[\t ]+LIBSSH2_VERSION[\t ]+\"([^\"]*)\"")
-  file(STRINGS "${LIBSSH2_INCLUDE_DIR}/libssh2.h" _version_str REGEX "${_version_regex}")
-  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
-  set(LIBSSH2_VERSION "${_version_str}")
-  unset(_version_regex)
-  unset(_version_str)
-endif()
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Libssh2
+    REQUIRED_VARS
+      LIBSSH2_INCLUDE_DIR
+      LIBSSH2_LIBRARY
+    VERSION_VAR
+      LIBSSH2_VERSION
+  )
 
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Libssh2
-  REQUIRED_VARS
-    LIBSSH2_INCLUDE_DIR
-    LIBSSH2_LIBRARY
-  VERSION_VAR
-    LIBSSH2_VERSION
-)
+  if(LIBSSH2_FOUND)
+    set(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR})
+    set(LIBSSH2_LIBRARIES    ${LIBSSH2_LIBRARY})
+  endif()
 
-if(LIBSSH2_FOUND)
-  set(LIBSSH2_INCLUDE_DIRS ${LIBSSH2_INCLUDE_DIR})
-  set(LIBSSH2_LIBRARIES    ${LIBSSH2_LIBRARY})
+  mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)
 endif()
-
-mark_as_advanced(LIBSSH2_INCLUDE_DIR LIBSSH2_LIBRARY)

+ 4 - 1
CMake/FindLibuv.cmake

@@ -34,14 +34,17 @@
 # - `LIBUV_INCLUDE_DIRS`:  The libuv include directories.
 # - `LIBUV_LIBRARIES`:     The libuv library names.
 # - `LIBUV_LIBRARY_DIRS`:  The libuv library directories.
+# - `LIBUV_PC_REQUIRES`:   The libuv pkg-config packages.
 # - `LIBUV_CFLAGS`:        Required compiler flags.
 # - `LIBUV_VERSION`:       Version of libuv.
 
+set(LIBUV_PC_REQUIRES "libuv")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBUV_INCLUDE_DIR AND
    NOT DEFINED LIBUV_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(LIBUV "libuv")
+  pkg_check_modules(LIBUV ${LIBUV_PC_REQUIRES})
 endif()
 
 if(LIBUV_FOUND)

+ 5 - 2
CMake/FindMSH3.cmake

@@ -38,18 +38,21 @@
 # - `MSH3_CFLAGS`:        Required compiler flags.
 # - `MSH3_VERSION`:       Version of msh3.
 
+set(MSH3_PC_REQUIRES "libmsh3")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED MSH3_INCLUDE_DIR AND
    NOT DEFINED MSH3_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(MSH3 "libmsh3")
+  pkg_check_modules(MSH3 ${MSH3_PC_REQUIRES})
 endif()
 
 if(MSH3_FOUND)
-  set(MSH3_PC_REQUIRES "libmsh3")
   string(REPLACE ";" " " MSH3_CFLAGS "${MSH3_CFLAGS}")
   message(STATUS "Found MSH3 (via pkg-config): ${MSH3_INCLUDE_DIRS} (found version \"${MSH3_VERSION}\")")
 else()
+  set(MSH3_PC_REQUIRES "")  # Depend on pkg-config only when found via pkg-config
+
   find_path(MSH3_INCLUDE_DIR NAMES "msh3.h")
   find_library(MSH3_LIBRARY NAMES "msh3")
 

+ 7 - 2
CMake/FindMbedTLS.cmake

@@ -46,24 +46,29 @@ if(DEFINED MBEDTLS_INCLUDE_DIRS AND NOT DEFINED MBEDTLS_INCLUDE_DIR)
   unset(MBEDTLS_INCLUDE_DIRS)
 endif()
 
+set(MBEDTLS_PC_REQUIRES "mbedtls")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED MBEDTLS_INCLUDE_DIR AND
    NOT DEFINED MBEDTLS_LIBRARY AND
    NOT DEFINED MBEDX509_LIBRARY AND
    NOT DEFINED MBEDCRYPTO_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(MBEDTLS "mbedtls")
+  pkg_check_modules(MBEDTLS ${MBEDTLS_PC_REQUIRES})
   pkg_check_modules(MBEDX509 "mbedx509")
   pkg_check_modules(MBEDCRYPTO "mbedcrypto")
 endif()
 
 if(MBEDTLS_FOUND AND MBEDX509_FOUND AND MBEDCRYPTO_FOUND)
   list(APPEND MBEDTLS_LIBRARIES ${MBEDX509_LIBRARIES} ${MBEDCRYPTO_LIBRARIES})
+  list(REVERSE MBEDTLS_LIBRARIES)
   list(REMOVE_DUPLICATES MBEDTLS_LIBRARIES)
-  set(MBEDTLS_PC_REQUIRES "mbedtls")
+  list(REVERSE MBEDTLS_LIBRARIES)
   string(REPLACE ";" " " MBEDTLS_CFLAGS "${MBEDTLS_CFLAGS}")
   message(STATUS "Found MbedTLS (via pkg-config): ${MBEDTLS_INCLUDE_DIRS} (found version \"${MBEDTLS_VERSION}\")")
 else()
+  set(MBEDTLS_PC_REQUIRES "")  # Depend on pkg-config only when found via pkg-config
+
   find_path(MBEDTLS_INCLUDE_DIR NAMES "mbedtls/ssl.h")
   find_library(MBEDTLS_LIBRARY NAMES "mbedtls" "libmbedtls")
   find_library(MBEDX509_LIBRARY NAMES "mbedx509" "libmbedx509")

+ 37 - 35
CMake/FindNGHTTP2.cmake

@@ -33,48 +33,50 @@
 # - `NGHTTP2_FOUND`:         System has nghttp2.
 # - `NGHTTP2_INCLUDE_DIRS`:  The nghttp2 include directories.
 # - `NGHTTP2_LIBRARIES`:     The nghttp2 library names.
+# - `NGHTTP2_LIBRARY_DIRS`:  The nghttp2 library directories.
+# - `NGHTTP2_PC_REQUIRES`:   The nghttp2 pkg-config packages.
+# - `NGHTTP2_CFLAGS`:        Required compiler flags.
 # - `NGHTTP2_VERSION`:       Version of nghttp2.
 
-if(CURL_USE_PKGCONFIG)
+set(NGHTTP2_PC_REQUIRES "libnghttp2")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED NGHTTP2_INCLUDE_DIR AND
+   NOT DEFINED NGHTTP2_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_NGHTTP2 "libnghttp2")
+  pkg_check_modules(NGHTTP2 ${NGHTTP2_PC_REQUIRES})
 endif()
 
-find_path(NGHTTP2_INCLUDE_DIR NAMES "nghttp2/nghttp2.h"
-  HINTS
-    ${PC_NGHTTP2_INCLUDEDIR}
-    ${PC_NGHTTP2_INCLUDE_DIRS}
-)
+if(NGHTTP2_FOUND)
+  string(REPLACE ";" " " NGHTTP2_CFLAGS "${NGHTTP2_CFLAGS}")
+  message(STATUS "Found NGHTTP2 (via pkg-config): ${NGHTTP2_INCLUDE_DIRS} (found version \"${NGHTTP2_VERSION}\")")
+else()
+  find_path(NGHTTP2_INCLUDE_DIR NAMES "nghttp2/nghttp2.h")
+  find_library(NGHTTP2_LIBRARY NAMES "nghttp2" "nghttp2_static")
 
-find_library(NGHTTP2_LIBRARY NAMES "nghttp2" "nghttp2_static"
-  HINTS
-    ${PC_NGHTTP2_LIBDIR}
-    ${PC_NGHTTP2_LIBRARY_DIRS}
-)
+  unset(NGHTTP2_VERSION CACHE)
+  if(NGHTTP2_INCLUDE_DIR AND EXISTS "${NGHTTP2_INCLUDE_DIR}/nghttp2/nghttp2ver.h")
+    set(_version_regex "#[\t ]*define[\t ]+NGHTTP2_VERSION[\t ]+\"([^\"]*)\"")
+    file(STRINGS "${NGHTTP2_INCLUDE_DIR}/nghttp2/nghttp2ver.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(NGHTTP2_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
+  endif()
 
-if(PC_NGHTTP2_VERSION)
-  set(NGHTTP2_VERSION ${PC_NGHTTP2_VERSION})
-elseif(NGHTTP2_INCLUDE_DIR AND EXISTS "${NGHTTP2_INCLUDE_DIR}/nghttp2/nghttp2ver.h")
-  set(_version_regex "#[\t ]*define[\t ]+NGHTTP2_VERSION[\t ]+\"([^\"]*)\"")
-  file(STRINGS "${NGHTTP2_INCLUDE_DIR}/nghttp2/nghttp2ver.h" _version_str REGEX "${_version_regex}")
-  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
-  set(NGHTTP2_VERSION "${_version_str}")
-  unset(_version_regex)
-  unset(_version_str)
-endif()
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(NGHTTP2
+    REQUIRED_VARS
+      NGHTTP2_INCLUDE_DIR
+      NGHTTP2_LIBRARY
+    VERSION_VAR
+      NGHTTP2_VERSION
+  )
 
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(NGHTTP2
-  REQUIRED_VARS
-    NGHTTP2_INCLUDE_DIR
-    NGHTTP2_LIBRARY
-  VERSION_VAR
-    NGHTTP2_VERSION
-)
+  if(NGHTTP2_FOUND)
+    set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR})
+    set(NGHTTP2_LIBRARIES    ${NGHTTP2_LIBRARY})
+  endif()
 
-if(NGHTTP2_FOUND)
-  set(NGHTTP2_INCLUDE_DIRS ${NGHTTP2_INCLUDE_DIR})
-  set(NGHTTP2_LIBRARIES    ${NGHTTP2_LIBRARY})
+  mark_as_advanced(NGHTTP2_INCLUDE_DIR NGHTTP2_LIBRARY)
 endif()
-
-mark_as_advanced(NGHTTP2_INCLUDE_DIR NGHTTP2_LIBRARY)

+ 37 - 35
CMake/FindNGHTTP3.cmake

@@ -33,48 +33,50 @@
 # - `NGHTTP3_FOUND`:         System has nghttp3.
 # - `NGHTTP3_INCLUDE_DIRS`:  The nghttp3 include directories.
 # - `NGHTTP3_LIBRARIES`:     The nghttp3 library names.
+# - `NGHTTP3_LIBRARY_DIRS`:  The nghttp3 library directories.
+# - `NGHTTP3_PC_REQUIRES`:   The nghttp3 pkg-config packages.
+# - `NGHTTP3_CFLAGS`:        Required compiler flags.
 # - `NGHTTP3_VERSION`:       Version of nghttp3.
 
-if(CURL_USE_PKGCONFIG)
+set(NGHTTP3_PC_REQUIRES "libnghttp3")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED NGHTTP3_INCLUDE_DIR AND
+   NOT DEFINED NGHTTP3_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_NGHTTP3 "libnghttp3")
+  pkg_check_modules(NGHTTP3 ${NGHTTP3_PC_REQUIRES})
 endif()
 
-find_path(NGHTTP3_INCLUDE_DIR NAMES "nghttp3/nghttp3.h"
-  HINTS
-    ${PC_NGHTTP3_INCLUDEDIR}
-    ${PC_NGHTTP3_INCLUDE_DIRS}
-)
+if(NGHTTP3_FOUND)
+  string(REPLACE ";" " " NGHTTP3_CFLAGS "${NGHTTP3_CFLAGS}")
+  message(STATUS "Found NGHTTP3 (via pkg-config): ${NGHTTP3_INCLUDE_DIRS} (found version \"${NGHTTP3_VERSION}\")")
+else()
+  find_path(NGHTTP3_INCLUDE_DIR NAMES "nghttp3/nghttp3.h")
+  find_library(NGHTTP3_LIBRARY NAMES "nghttp3")
 
-find_library(NGHTTP3_LIBRARY NAMES "nghttp3"
-  HINTS
-    ${PC_NGHTTP3_LIBDIR}
-    ${PC_NGHTTP3_LIBRARY_DIRS}
-)
+  unset(NGHTTP3_VERSION CACHE)
+  if(NGHTTP3_INCLUDE_DIR AND EXISTS "${NGHTTP3_INCLUDE_DIR}/nghttp3/version.h")
+    set(_version_regex "#[\t ]*define[\t ]+NGHTTP3_VERSION[\t ]+\"([^\"]*)\"")
+    file(STRINGS "${NGHTTP3_INCLUDE_DIR}/nghttp3/version.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(NGHTTP3_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
+  endif()
 
-if(PC_NGHTTP3_VERSION)
-  set(NGHTTP3_VERSION ${PC_NGHTTP3_VERSION})
-elseif(NGHTTP3_INCLUDE_DIR AND EXISTS "${NGHTTP3_INCLUDE_DIR}/nghttp3/version.h")
-  set(_version_regex "#[\t ]*define[\t ]+NGHTTP3_VERSION[\t ]+\"([^\"]*)\"")
-  file(STRINGS "${NGHTTP3_INCLUDE_DIR}/nghttp3/version.h" _version_str REGEX "${_version_regex}")
-  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
-  set(NGHTTP3_VERSION "${_version_str}")
-  unset(_version_regex)
-  unset(_version_str)
-endif()
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(NGHTTP3
+    REQUIRED_VARS
+      NGHTTP3_INCLUDE_DIR
+      NGHTTP3_LIBRARY
+    VERSION_VAR
+      NGHTTP3_VERSION
+  )
 
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(NGHTTP3
-  REQUIRED_VARS
-    NGHTTP3_INCLUDE_DIR
-    NGHTTP3_LIBRARY
-  VERSION_VAR
-    NGHTTP3_VERSION
-)
+  if(NGHTTP3_FOUND)
+    set(NGHTTP3_INCLUDE_DIRS ${NGHTTP3_INCLUDE_DIR})
+    set(NGHTTP3_LIBRARIES    ${NGHTTP3_LIBRARY})
+  endif()
 
-if(NGHTTP3_FOUND)
-  set(NGHTTP3_INCLUDE_DIRS ${NGHTTP3_INCLUDE_DIR})
-  set(NGHTTP3_LIBRARIES    ${NGHTTP3_LIBRARY})
+  mark_as_advanced(NGHTTP3_INCLUDE_DIR NGHTTP3_LIBRARY)
 endif()
-
-mark_as_advanced(NGHTTP3_INCLUDE_DIR NGHTTP3_LIBRARY)

+ 63 - 55
CMake/FindNGTCP2.cmake

@@ -41,36 +41,11 @@
 # - `NGTCP2_FOUND`:         System has ngtcp2.
 # - `NGTCP2_INCLUDE_DIRS`:  The ngtcp2 include directories.
 # - `NGTCP2_LIBRARIES`:     The ngtcp2 library names.
+# - `NGTCP2_LIBRARY_DIRS`:  The ngtcp2 library directories.
+# - `NGTCP2_PC_REQUIRES`:   The ngtcp2 pkg-config packages.
+# - `NGTCP2_CFLAGS`:        Required compiler flags.
 # - `NGTCP2_VERSION`:       Version of ngtcp2.
 
-if(CURL_USE_PKGCONFIG)
-  find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_NGTCP2 "libngtcp2")
-endif()
-
-find_path(NGTCP2_INCLUDE_DIR NAMES "ngtcp2/ngtcp2.h"
-  HINTS
-    ${PC_NGTCP2_INCLUDEDIR}
-    ${PC_NGTCP2_INCLUDE_DIRS}
-)
-
-find_library(NGTCP2_LIBRARY NAMES "ngtcp2"
-  HINTS
-    ${PC_NGTCP2_LIBDIR}
-    ${PC_NGTCP2_LIBRARY_DIRS}
-)
-
-if(PC_NGTCP2_VERSION)
-  set(NGTCP2_VERSION ${PC_NGTCP2_VERSION})
-elseif(NGTCP2_INCLUDE_DIR AND EXISTS "${NGTCP2_INCLUDE_DIR}/ngtcp2/version.h")
-  set(_version_regex "#[\t ]*define[\t ]+NGTCP2_VERSION[\t ]+\"([^\"]*)\"")
-  file(STRINGS "${NGTCP2_INCLUDE_DIR}/ngtcp2/version.h" _version_str REGEX "${_version_regex}")
-  string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
-  set(NGTCP2_VERSION "${_version_str}")
-  unset(_version_regex)
-  unset(_version_str)
-endif()
-
 if(NGTCP2_FIND_COMPONENTS)
   set(_ngtcp2_crypto_backend "")
   foreach(_component IN LISTS NGTCP2_FIND_COMPONENTS)
@@ -83,40 +58,73 @@ if(NGTCP2_FIND_COMPONENTS)
   endforeach()
 
   if(_ngtcp2_crypto_backend)
-    string(TOLOWER "ngtcp2_crypto_${_ngtcp2_crypto_backend}" _crypto_library)
+    string(TOLOWER "ngtcp2_crypto_${_ngtcp2_crypto_backend}" _crypto_library_lower)
+    string(TOUPPER "ngtcp2_crypto_${_ngtcp2_crypto_backend}" _crypto_library_upper)
+  endif()
+endif()
 
-    if(CURL_USE_PKGCONFIG)
-      pkg_check_modules(PC_${_crypto_library} "lib${_crypto_library}")
-    endif()
+set(NGTCP2_PC_REQUIRES "libngtcp2")
+if(_ngtcp2_crypto_backend)
+  set(NGTCP2_CRYPTO_PC_REQUIRES "lib${_crypto_library_lower}")
+endif()
 
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED NGTCP2_INCLUDE_DIR AND
+   NOT DEFINED NGTCP2_LIBRARY)
+  find_package(PkgConfig QUIET)
+  pkg_check_modules(NGTCP2 ${NGTCP2_PC_REQUIRES})
+  if(_ngtcp2_crypto_backend)
+    pkg_check_modules("${_crypto_library_upper}" ${NGTCP2_CRYPTO_PC_REQUIRES})
+  else()
+    set("${_crypto_library_upper}_FOUND" TRUE)
+  endif()
+endif()
+
+list(APPEND NGTCP2_PC_REQUIRES ${NGTCP2_CRYPTO_PC_REQUIRES})
+
+if(NGTCP2_FOUND AND "${${_crypto_library_upper}_FOUND}")
+  list(APPEND NGTCP2_LIBRARIES "${${_crypto_library_upper}_LIBRARIES}")
+  list(REMOVE_DUPLICATES NGTCP2_LIBRARIES)
+  string(REPLACE ";" " " NGTCP2_CFLAGS "${NGTCP2_CFLAGS}")
+  message(STATUS "Found NGTCP2 (via pkg-config): ${NGTCP2_INCLUDE_DIRS} (found version \"${NGTCP2_VERSION}\")")
+else()
+  find_path(NGTCP2_INCLUDE_DIR NAMES "ngtcp2/ngtcp2.h")
+  find_library(NGTCP2_LIBRARY NAMES "ngtcp2")
+
+  unset(NGTCP2_VERSION CACHE)
+  if(NGTCP2_INCLUDE_DIR AND EXISTS "${NGTCP2_INCLUDE_DIR}/ngtcp2/version.h")
+    set(_version_regex "#[\t ]*define[\t ]+NGTCP2_VERSION[\t ]+\"([^\"]*)\"")
+    file(STRINGS "${NGTCP2_INCLUDE_DIR}/ngtcp2/version.h" _version_str REGEX "${_version_regex}")
+    string(REGEX REPLACE "${_version_regex}" "\\1" _version_str "${_version_str}")
+    set(NGTCP2_VERSION "${_version_str}")
+    unset(_version_regex)
+    unset(_version_str)
+  endif()
+
+  if(_ngtcp2_crypto_backend)
     get_filename_component(_ngtcp2_library_dir "${NGTCP2_LIBRARY}" DIRECTORY)
-    find_library(${_crypto_library}_LIBRARY NAMES ${_crypto_library}
-      HINTS
-        ${_ngtcp2_library_dir}
-        ${PC_${_crypto_library}_LIBDIR}
-        ${PC_${_crypto_library}_LIBRARY_DIRS}
-    )
+    find_library(${_crypto_library_upper}_LIBRARY NAMES ${_crypto_library_lower} HINTS ${_ngtcp2_library_dir})
 
-    if(${_crypto_library}_LIBRARY)
+    if(${_crypto_library_upper}_LIBRARY)
       set(NGTCP2_${_ngtcp2_crypto_backend}_FOUND TRUE)
-      set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library}_LIBRARY})
+      set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library_upper}_LIBRARY})
     endif()
   endif()
-endif()
 
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(NGTCP2
-  REQUIRED_VARS
-    NGTCP2_INCLUDE_DIR
-    NGTCP2_LIBRARY
-  VERSION_VAR
-    NGTCP2_VERSION
-  HANDLE_COMPONENTS
-)
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(NGTCP2
+    REQUIRED_VARS
+      NGTCP2_INCLUDE_DIR
+      NGTCP2_LIBRARY
+    VERSION_VAR
+      NGTCP2_VERSION
+    HANDLE_COMPONENTS
+  )
 
-if(NGTCP2_FOUND)
-  set(NGTCP2_INCLUDE_DIRS ${NGTCP2_INCLUDE_DIR})
-  set(NGTCP2_LIBRARIES    ${NGTCP2_LIBRARY} ${NGTCP2_CRYPTO_LIBRARY})
-endif()
+  if(NGTCP2_FOUND)
+    set(NGTCP2_INCLUDE_DIRS ${NGTCP2_INCLUDE_DIR})
+    set(NGTCP2_LIBRARIES    ${NGTCP2_LIBRARY} ${NGTCP2_CRYPTO_LIBRARY})
+  endif()
 
-mark_as_advanced(NGTCP2_INCLUDE_DIR NGTCP2_LIBRARY NGTCP2_CRYPTO_LIBRARY)
+  mark_as_advanced(NGTCP2_INCLUDE_DIR NGTCP2_LIBRARY NGTCP2_CRYPTO_LIBRARY)
+endif()

+ 4 - 1
CMake/FindNettle.cmake

@@ -34,14 +34,17 @@
 # - `NETTLE_INCLUDE_DIRS`:  The nettle include directories.
 # - `NETTLE_LIBRARIES`:     The nettle library names.
 # - `NETTLE_LIBRARY_DIRS`:  The nettle library directories.
+# - `NETTLE_PC_REQUIRES`:   The nettle pkg-config packages.
 # - `NETTLE_CFLAGS`:        Required compiler flags.
 # - `NETTLE_VERSION`:       Version of nettle.
 
+set(NETTLE_PC_REQUIRES "nettle")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED NETTLE_INCLUDE_DIR AND
    NOT DEFINED NETTLE_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(NETTLE "nettle")
+  pkg_check_modules(NETTLE ${NETTLE_PC_REQUIRES})
 endif()
 
 if(NETTLE_FOUND)

+ 4 - 1
CMake/FindQuiche.cmake

@@ -34,14 +34,17 @@
 # - `QUICHE_INCLUDE_DIRS`:  The quiche include directories.
 # - `QUICHE_LIBRARIES`:     The quiche library names.
 # - `QUICHE_LIBRARY_DIRS`:  The quiche library directories.
+# - `QUICHE_PC_REQUIRES`:   The quiche pkg-config packages.
 # - `QUICHE_CFLAGS`:        Required compiler flags.
 # - `QUICHE_VERSION`:       Version of quiche.
 
+set(QUICHE_PC_REQUIRES "quiche")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED QUICHE_INCLUDE_DIR AND
    NOT DEFINED QUICHE_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(QUICHE "quiche")
+  pkg_check_modules(QUICHE ${QUICHE_PC_REQUIRES})
 endif()
 
 if(QUICHE_FOUND)

+ 35 - 30
CMake/FindRustls.cmake

@@ -38,18 +38,21 @@
 # - `RUSTLS_CFLAGS`:        Required compiler flags.
 # - `RUSTLS_VERSION`:       Version of Rustls.
 
+set(RUSTLS_PC_REQUIRES "rustls")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED RUSTLS_INCLUDE_DIR AND
    NOT DEFINED RUSTLS_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(RUSTLS "rustls")
+  pkg_check_modules(RUSTLS ${RUSTLS_PC_REQUIRES})
 endif()
 
 if(RUSTLS_FOUND)
-  set(RUSTLS_PC_REQUIRES "rustls")
   string(REPLACE ";" " " RUSTLS_CFLAGS "${RUSTLS_CFLAGS}")
   message(STATUS "Found Rustls (via pkg-config): ${RUSTLS_INCLUDE_DIRS} (found version \"${RUSTLS_VERSION}\")")
 else()
+  set(RUSTLS_PC_REQUIRES "")  # Depend on pkg-config only when found via pkg-config
+
   find_path(RUSTLS_INCLUDE_DIR NAMES "rustls.h")
   find_library(RUSTLS_LIBRARY NAMES "rustls")
 
@@ -68,36 +71,38 @@ else()
   mark_as_advanced(RUSTLS_INCLUDE_DIR RUSTLS_LIBRARY)
 endif()
 
-if(APPLE)
-  find_library(SECURITY_FRAMEWORK "Security")
-  mark_as_advanced(SECURITY_FRAMEWORK)
-  if(NOT SECURITY_FRAMEWORK)
-    message(FATAL_ERROR "Security framework not found")
-  endif()
-  list(APPEND RUSTLS_LIBRARIES "-framework Security")
+if(RUSTLS_FOUND)
+  if(APPLE)
+    find_library(SECURITY_FRAMEWORK NAMES "Security")
+    mark_as_advanced(SECURITY_FRAMEWORK)
+    if(NOT SECURITY_FRAMEWORK)
+      message(FATAL_ERROR "Security framework not found")
+    endif()
+    list(APPEND RUSTLS_LIBRARIES "-framework Security")
 
-  find_library(FOUNDATION_FRAMEWORK "Foundation")
-  mark_as_advanced(FOUNDATION_FRAMEWORK)
-  if(NOT FOUNDATION_FRAMEWORK)
-    message(FATAL_ERROR "Foundation framework not found")
-  endif()
-  list(APPEND RUSTLS_LIBRARIES "-framework Foundation")
-elseif(NOT WIN32)
-  find_library(_pthread_library "pthread")
-  if(_pthread_library)
-    list(APPEND RUSTLS_LIBRARIES "pthread")
-  endif()
-  mark_as_advanced(_pthread_library)
+    find_library(FOUNDATION_FRAMEWORK NAMES "Foundation")
+    mark_as_advanced(FOUNDATION_FRAMEWORK)
+    if(NOT FOUNDATION_FRAMEWORK)
+      message(FATAL_ERROR "Foundation framework not found")
+    endif()
+    list(APPEND RUSTLS_LIBRARIES "-framework Foundation")
+  elseif(NOT WIN32)
+    find_library(PTHREAD_LIBRARY NAMES "pthread")
+    if(PTHREAD_LIBRARY)
+      list(APPEND RUSTLS_LIBRARIES ${PTHREAD_LIBRARY})
+    endif()
+    mark_as_advanced(PTHREAD_LIBRARY)
 
-  find_library(_dl_library "dl")
-  if(_dl_library)
-    list(APPEND RUSTLS_LIBRARIES "dl")
-  endif()
-  mark_as_advanced(_dl_library)
+    find_library(DL_LIBRARY NAMES "dl")
+    if(DL_LIBRARY)
+      list(APPEND RUSTLS_LIBRARIES ${DL_LIBRARY})
+    endif()
+    mark_as_advanced(DL_LIBRARY)
 
-  find_library(_math_library "m")
-  if(_math_library)
-    list(APPEND RUSTLS_LIBRARIES "m")
+    find_library(MATH_LIBRARY NAMES "m")
+    if(MATH_LIBRARY)
+      list(APPEND RUSTLS_LIBRARIES ${MATH_LIBRARY})
+    endif()
+    mark_as_advanced(MATH_LIBRARY)
   endif()
-  mark_as_advanced(_math_library)
 endif()

+ 9 - 6
CMake/FindWolfSSL.cmake

@@ -34,6 +34,7 @@
 # - `WOLFSSL_INCLUDE_DIRS`:  The wolfSSL include directories.
 # - `WOLFSSL_LIBRARIES`:     The wolfSSL library names.
 # - `WOLFSSL_LIBRARY_DIRS`:  The wolfSSL library directories.
+# - `WOLFSSL_PC_REQUIRES`:   The wolfSSL pkg-config packages.
 # - `WOLFSSL_CFLAGS`:        Required compiler flags.
 # - `WOLFSSL_VERSION`:       Version of wolfSSL.
 
@@ -46,11 +47,13 @@ if(DEFINED WolfSSL_LIBRARY AND NOT DEFINED WOLFSSL_LIBRARY)
   set(WOLFSSL_LIBRARY "${WolfSSL_LIBRARY}")
 endif()
 
+set(WOLFSSL_PC_REQUIRES "wolfssl")
+
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED WOLFSSL_INCLUDE_DIR AND
    NOT DEFINED WOLFSSL_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(WOLFSSL "wolfssl")
+  pkg_check_modules(WOLFSSL ${WOLFSSL_PC_REQUIRES})
 endif()
 
 if(WOLFSSL_FOUND)
@@ -87,10 +90,10 @@ else()
   mark_as_advanced(WOLFSSL_INCLUDE_DIR WOLFSSL_LIBRARY)
 endif()
 
-if(NOT WIN32)
-  find_library(_math_library "m")
-  if(_math_library)
-    list(APPEND WOLFSSL_LIBRARIES "m")  # for log and pow
+if(WOLFSSL_FOUND AND NOT WIN32)
+  find_library(MATH_LIBRARY NAMES "m")
+  if(MATH_LIBRARY)
+    list(APPEND WOLFSSL_LIBRARIES ${MATH_LIBRARY})  # for log and pow
   endif()
-  mark_as_advanced(_math_library)
+  mark_as_advanced(MATH_LIBRARY)
 endif()

+ 47 - 45
CMake/FindZstd.cmake

@@ -33,6 +33,9 @@
 # - `ZSTD_FOUND`:         System has zstd.
 # - `ZSTD_INCLUDE_DIRS`:  The zstd include directories.
 # - `ZSTD_LIBRARIES`:     The zstd library names.
+# - `ZSTD_LIBRARY_DIRS`:  The zstd library directories.
+# - `ZSTD_PC_REQUIRES`:   The zstd pkg-config packages.
+# - `ZSTD_CFLAGS`:        Required compiler flags.
 # - `ZSTD_VERSION`:       Version of zstd.
 
 if(DEFINED Zstd_INCLUDE_DIR AND NOT DEFINED ZSTD_INCLUDE_DIR)
@@ -44,56 +47,55 @@ if(DEFINED Zstd_LIBRARY AND NOT DEFINED ZSTD_LIBRARY)
   set(ZSTD_LIBRARY "${Zstd_LIBRARY}")
 endif()
 
-if(CURL_USE_PKGCONFIG)
+set(ZSTD_PC_REQUIRES "libzstd")
+
+if(CURL_USE_PKGCONFIG AND
+   NOT DEFINED ZSTD_INCLUDE_DIR AND
+   NOT DEFINED ZSTD_LIBRARY)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_ZSTD "libzstd")
+  pkg_check_modules(ZSTD ${ZSTD_PC_REQUIRES})
 endif()
 
-find_path(ZSTD_INCLUDE_DIR NAMES "zstd.h"
-  HINTS
-    ${PC_ZSTD_INCLUDEDIR}
-    ${PC_ZSTD_INCLUDE_DIRS}
-)
+if(ZSTD_FOUND)
+  string(REPLACE ";" " " ZSTD_CFLAGS "${ZSTD_CFLAGS}")
+  message(STATUS "Found Zstd (via pkg-config): ${ZSTD_INCLUDE_DIRS} (found version \"${ZSTD_VERSION}\")")
+else()
+  find_path(ZSTD_INCLUDE_DIR NAMES "zstd.h")
+  find_library(ZSTD_LIBRARY NAMES "zstd")
 
-find_library(ZSTD_LIBRARY NAMES "zstd"
-  HINTS
-    ${PC_ZSTD_LIBDIR}
-    ${PC_ZSTD_LIBRARY_DIRS}
-)
+  unset(ZSTD_VERSION CACHE)
+  if(ZSTD_INCLUDE_DIR AND EXISTS "${ZSTD_INCLUDE_DIR}/zstd.h")
+    set(_version_regex1 "#[\t ]*define[ \t]+ZSTD_VERSION_MAJOR[ \t]+([0-9]+).*")
+    set(_version_regex2 "#[\t ]*define[ \t]+ZSTD_VERSION_MINOR[ \t]+([0-9]+).*")
+    set(_version_regex3 "#[\t ]*define[ \t]+ZSTD_VERSION_RELEASE[ \t]+([0-9]+).*")
+    file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str1 REGEX "${_version_regex1}")
+    file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str2 REGEX "${_version_regex2}")
+    file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str3 REGEX "${_version_regex3}")
+    string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
+    string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
+    string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
+    set(ZSTD_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
+    unset(_version_regex1)
+    unset(_version_regex2)
+    unset(_version_regex3)
+    unset(_version_str1)
+    unset(_version_str2)
+    unset(_version_str3)
+  endif()
 
-if(PC_ZSTD_VERSION)
-  set(ZSTD_VERSION ${PC_ZSTD_VERSION})
-elseif(ZSTD_INCLUDE_DIR AND EXISTS "${ZSTD_INCLUDE_DIR}/zstd.h")
-  set(_version_regex1 "#[\t ]*define[ \t]+ZSTD_VERSION_MAJOR[ \t]+([0-9]+).*")
-  set(_version_regex2 "#[\t ]*define[ \t]+ZSTD_VERSION_MINOR[ \t]+([0-9]+).*")
-  set(_version_regex3 "#[\t ]*define[ \t]+ZSTD_VERSION_RELEASE[ \t]+([0-9]+).*")
-  file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str1 REGEX "${_version_regex1}")
-  file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str2 REGEX "${_version_regex2}")
-  file(STRINGS "${ZSTD_INCLUDE_DIR}/zstd.h" _version_str3 REGEX "${_version_regex3}")
-  string(REGEX REPLACE "${_version_regex1}" "\\1" _version_str1 "${_version_str1}")
-  string(REGEX REPLACE "${_version_regex2}" "\\1" _version_str2 "${_version_str2}")
-  string(REGEX REPLACE "${_version_regex3}" "\\1" _version_str3 "${_version_str3}")
-  set(ZSTD_VERSION "${_version_str1}.${_version_str2}.${_version_str3}")
-  unset(_version_regex1)
-  unset(_version_regex2)
-  unset(_version_regex3)
-  unset(_version_str1)
-  unset(_version_str2)
-  unset(_version_str3)
-endif()
+  include(FindPackageHandleStandardArgs)
+  find_package_handle_standard_args(Zstd
+    REQUIRED_VARS
+      ZSTD_INCLUDE_DIR
+      ZSTD_LIBRARY
+    VERSION_VAR
+      ZSTD_VERSION
+  )
 
-include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(Zstd
-  REQUIRED_VARS
-    ZSTD_INCLUDE_DIR
-    ZSTD_LIBRARY
-  VERSION_VAR
-    ZSTD_VERSION
-)
+  if(ZSTD_FOUND)
+    set(ZSTD_INCLUDE_DIRS ${ZSTD_INCLUDE_DIR})
+    set(ZSTD_LIBRARIES    ${ZSTD_LIBRARY})
+  endif()
 
-if(ZSTD_FOUND)
-  set(ZSTD_INCLUDE_DIRS ${ZSTD_INCLUDE_DIR})
-  set(ZSTD_LIBRARIES    ${ZSTD_LIBRARY})
+  mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
 endif()
-
-mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)

+ 17 - 13
CMake/Macros.cmake

@@ -27,7 +27,7 @@
 # This macro is intended to be called multiple times with a sequence of
 # possibly dependent header files.  Some headers depend on others to be
 # compiled correctly.
-macro(check_include_file_concat _file _variable)
+macro(check_include_file_concat_curl _file _variable)
   check_include_files("${CURL_INCLUDES};${_file}" ${_variable})
   if(${_variable})
     list(APPEND CURL_INCLUDES ${_file})
@@ -62,21 +62,25 @@ macro(curl_internal_test _curl_test)
   endif()
 endmacro()
 
-macro(curl_dependency_option _dependency)
-  set(CURL_${_dependency} "AUTO" CACHE STRING "Build curl with ${_dependency} support (AUTO, ON or OFF)")
-  set_property(CACHE CURL_${_dependency} PROPERTY STRINGS "AUTO" "ON" "OFF")
+macro(curl_dependency_option _option_name _find_name _desc_name)
+  set(${_option_name} "AUTO" CACHE STRING "Build curl with ${_desc_name} support (AUTO, ON or OFF)")
+  set_property(CACHE ${_option_name} PROPERTY STRINGS "AUTO" "ON" "OFF")
 
-  if(CURL_${_dependency} STREQUAL "AUTO")
-    find_package(${_dependency})
-  elseif(CURL_${_dependency})
-    find_package(${_dependency} REQUIRED)
+  if(${_option_name} STREQUAL "AUTO")
+    find_package(${_find_name})
+  elseif(${_option_name})
+    find_package(${_find_name} REQUIRED)
   endif()
 endmacro()
 
-# Convert the passed paths to libpath linker options and add them to CMAKE_REQUIRED_LINK_OPTIONS.
+# Convert the passed paths to libpath linker options and add them to CMAKE_REQUIRED_*.
 macro(curl_required_libpaths _libpaths_arg)
-  set(_libpaths "${_libpaths_arg}")
-  foreach(_libpath IN LISTS _libpaths)
-    list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "${CMAKE_LIBRARY_PATH_FLAG}${_libpath}")
-  endforeach()
+  if(CMAKE_VERSION VERSION_LESS 3.31)
+    set(_libpaths "${_libpaths_arg}")
+    foreach(_libpath IN LISTS _libpaths)
+      list(APPEND CMAKE_REQUIRED_LINK_OPTIONS "${CMAKE_LIBRARY_PATH_FLAG}${_libpath}")
+    endforeach()
+  else()
+    list(APPEND CMAKE_REQUIRED_LINK_DIRECTORIES "${_libpaths_arg}")
+  endif()
 endmacro()

+ 11 - 11
CMake/OtherTests.cmake

@@ -25,7 +25,7 @@ include(CheckCSourceCompiles)
 include(CheckCSourceRuns)
 include(CheckTypeSize)
 
-macro(add_header_include _check _header)
+macro(curl_add_header_include _check _header)
   if(${_check})
     set(_source_epilogue "${_source_epilogue}
       #include <${_header}>")
@@ -37,10 +37,10 @@ set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
 
 if(NOT DEFINED HAVE_STRUCT_SOCKADDR_STORAGE)
   cmake_push_check_state()
-  unset(CMAKE_EXTRA_INCLUDE_FILES)
+  set(CMAKE_EXTRA_INCLUDE_FILES "")
   if(WIN32)
     set(CMAKE_EXTRA_INCLUDE_FILES "winsock2.h")
-    set(CMAKE_REQUIRED_LIBRARIES "ws2_32")
+    list(APPEND CMAKE_REQUIRED_LIBRARIES "ws2_32")
   elseif(HAVE_SYS_SOCKET_H)
     set(CMAKE_EXTRA_INCLUDE_FILES "sys/socket.h")
   endif()
@@ -51,8 +51,8 @@ endif()
 
 if(NOT WIN32)
   set(_source_epilogue "#undef inline")
-  add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
-  add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
+  curl_add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
+  curl_add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
   check_c_source_compiles("${_source_epilogue}
     int main(void)
     {
@@ -63,7 +63,7 @@ if(NOT WIN32)
 endif()
 
 set(_source_epilogue "#undef inline")
-add_header_include(HAVE_SYS_TIME_H "sys/time.h")
+curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
 check_c_source_compiles("${_source_epilogue}
   #include <time.h>
   int main(void)
@@ -98,9 +98,9 @@ endif()
 
 if(NOT DEFINED HAVE_GETADDRINFO_THREADSAFE)
   set(_source_epilogue "#undef inline")
-  add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
-  add_header_include(HAVE_SYS_TIME_H "sys/time.h")
-  add_header_include(HAVE_NETDB_H "netdb.h")
+  curl_add_header_include(HAVE_SYS_SOCKET_H "sys/socket.h")
+  curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
+  curl_add_header_include(HAVE_NETDB_H "netdb.h")
   check_c_source_compiles("${_source_epilogue}
     int main(void)
     {
@@ -141,8 +141,8 @@ endif()
 
 if(NOT WIN32 AND NOT DEFINED HAVE_CLOCK_GETTIME_MONOTONIC_RAW)
   set(_source_epilogue "#undef inline")
-  add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
-  add_header_include(HAVE_SYS_TIME_H "sys/time.h")
+  curl_add_header_include(HAVE_SYS_TYPES_H "sys/types.h")
+  curl_add_header_include(HAVE_SYS_TIME_H "sys/time.h")
   check_c_source_compiles("${_source_epilogue}
     #include <time.h>
     int main(void)

+ 44 - 30
CMake/PickyWarnings.cmake

@@ -23,17 +23,15 @@
 ###########################################################################
 include(CheckCCompilerFlag)
 
-unset(_picky)
+set(_picky "")
 
 if(CURL_WERROR AND
    ((CMAKE_COMPILER_IS_GNUCC AND
+     NOT DOS AND  # Watt-32 headers use the '#include_next' GCC extension
      NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0 AND
      NOT CMAKE_VERSION VERSION_LESS 3.23.0) OR  # to avoid check_symbol_exists() conflicting with GCC -pedantic-errors
    CMAKE_C_COMPILER_ID MATCHES "Clang"))
   list(APPEND _picky "-pedantic-errors")
-  if(MSVC)  # clang-cl
-    list(APPEND _picky "-Wno-language-extension-token")  # Override default error to make __int64 size detection pass
-  endif()
 endif()
 
 if(APPLE AND
@@ -77,7 +75,6 @@ if(PICKY_COMPILER)
     list(APPEND _picky_enable
       -Wbad-function-cast                  # clang  2.7  gcc  2.95
       -Wconversion                         # clang  2.7  gcc  2.95
-      -Winline                             # clang  1.0  gcc  1.0
       -Wmissing-declarations               # clang  1.0  gcc  2.7
       -Wmissing-prototypes                 # clang  1.0  gcc  1.0
       -Wnested-externs                     # clang  1.0  gcc  2.7
@@ -106,12 +103,11 @@ if(PICKY_COMPILER)
       -Wmissing-field-initializers         # clang  2.7  gcc  4.1
       -Wmissing-noreturn                   # clang  2.7  gcc  4.1
       -Wno-format-nonliteral               # clang  1.0  gcc  2.96 (3.0)
+      -Wno-sign-conversion                 # clang  2.9  gcc  4.3
       -Wno-system-headers                  # clang  1.0  gcc  3.0
     # -Wpadded                             # clang  2.9  gcc  4.1               # Not used: We cannot change public structs
       -Wold-style-definition               # clang  2.7  gcc  3.4
       -Wredundant-decls                    # clang  2.7  gcc  4.1
-      -Wsign-conversion                    # clang  2.9  gcc  4.3
-        -Wno-error=sign-conversion                                              # FIXME
       -Wstrict-prototypes                  # clang  1.0  gcc  3.3
     # -Wswitch-enum                        # clang  2.7  gcc  4.1               # Not used: It basically disallows default case
       -Wtype-limits                        # clang  2.7  gcc  4.3
@@ -121,13 +117,6 @@ if(PICKY_COMPILER)
       -Wvla                                # clang  2.8  gcc  4.3
     )
 
-    set(_picky_common
-      -Wdouble-promotion                   # clang  3.6  gcc  4.6  appleclang  6.3
-      -Wenum-conversion                    # clang  3.2  gcc 10.0  appleclang  4.6  g++ 11.0
-      -Wpragmas                            # clang  3.5  gcc  4.1  appleclang  6.0
-      -Wunused-const-variable              # clang  3.4  gcc  6.0  appleclang  5.1
-    )
-
     if(CMAKE_C_COMPILER_ID MATCHES "Clang")
       list(APPEND _picky_enable
         ${_picky_common_old}
@@ -137,17 +126,20 @@ if(PICKY_COMPILER)
       )
       if(NOT MSVC)
         list(APPEND _picky_enable
-          -Wlanguage-extension-token         # clang  3.0  # Avoid for clang-cl to allow __int64
+          -Wlanguage-extension-token       # clang  3.0
         )
       endif()
       # Enable based on compiler version
       if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
          (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
         list(APPEND _picky_enable
-          ${_picky_common}
-        # -Wunreachable-code-break         # clang  3.5            appleclang  6.0  # Not used: Silent in "unity" builds
+          -Wdouble-promotion               # clang  3.6  gcc  4.6  appleclang  6.3
+          -Wenum-conversion                # clang  3.2  gcc 10.0  appleclang  4.6  g++ 11.0
           -Wheader-guard                   # clang  3.4            appleclang  5.1
+          -Wpragmas                        # clang  3.5  gcc  4.1  appleclang  6.0
           -Wsometimes-uninitialized        # clang  3.2            appleclang  4.6
+        # -Wunreachable-code-break         # clang  3.5            appleclang  6.0  # Not used: Silent in "unity" builds
+          -Wunused-const-variable          # clang  3.4  gcc  6.0  appleclang  5.1
         )
       endif()
       if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.9) OR
@@ -171,9 +163,6 @@ if(PICKY_COMPILER)
         )
       endif()
     else()  # gcc
-      list(APPEND _picky_detect
-        ${_picky_common}
-      )
       # Enable based on compiler version
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3)
         list(APPEND _picky_enable
@@ -181,8 +170,8 @@ if(PICKY_COMPILER)
           -Wclobbered                      #             gcc  4.3
           -Wmissing-parameter-type         #             gcc  4.3
           -Wold-style-declaration          #             gcc  4.3
+          -Wpragmas                        # clang  3.5  gcc  4.1  appleclang  6.0
           -Wstrict-aliasing=3              #             gcc  4.0
-          -Wtrampolines                    #             gcc  4.3
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND MINGW)
@@ -192,7 +181,9 @@ if(PICKY_COMPILER)
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
         list(APPEND _picky_enable
+          -Wdouble-promotion               # clang  3.6  gcc  4.6  appleclang  6.3
           -Wformat=2                       # clang  3.0  gcc  4.8
+          -Wtrampolines                    #             gcc  4.6
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
@@ -207,6 +198,7 @@ if(PICKY_COMPILER)
             -fdelete-null-pointer-checks
           -Wshift-negative-value           # clang  3.7  gcc  6.0 (clang default)
           -Wshift-overflow=2               # clang  3.0  gcc  6.0 (clang default: -Wshift-overflow)
+          -Wunused-const-variable          # clang  3.4  gcc  6.0  appleclang  5.1
         )
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0)
@@ -221,6 +213,7 @@ if(PICKY_COMPILER)
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0)
         list(APPEND _picky_enable
           -Warith-conversion               #             gcc 10.0
+          -Wenum-conversion                # clang  3.2  gcc 10.0  appleclang  4.6  g++ 11.0
         )
       endif()
     endif()
@@ -242,20 +235,41 @@ if(PICKY_COMPILER)
         list(APPEND _picky "${_ccopt}")
       endif()
     endforeach()
+
+    if(CMAKE_COMPILER_IS_GNUCC)
+      if(CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5)
+        # Avoid false positives
+        list(APPEND _picky "-Wno-shadow")
+        list(APPEND _picky "-Wno-unreachable-code")
+      endif()
+      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.2 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.6)
+        # GCC <4.6 do not support #pragma to suppress warnings locally. Disable them globally instead.
+        list(APPEND _picky "-Wno-overlength-strings")
+      endif()
+      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.0 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.7)
+        list(APPEND _picky "-Wno-missing-field-initializers")  # https://gcc.gnu.org/bugzilla/show_bug.cgi?id=36750
+      endif()
+      if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3 AND CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
+        list(APPEND _picky "-Wno-type-limits")  # Avoid false positives
+      endif()
+    endif()
   endif()
 endif()
 
 # clang-cl
 if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND MSVC)
-  if(CMAKE_VERSION VERSION_LESS 3.12)
-    set(_picky_tmp "")
-    foreach(_ccopt IN LISTS _picky)
-      list(APPEND _picky_tmp "/clang:${_ccopt}")
-    endforeach()
-    set(_picky ${_picky_tmp})
-  else()
-    list(TRANSFORM _picky PREPEND "/clang:")
-  endif()
+  list(APPEND _picky "-Wno-language-extension-token")  # Allow __int64
+
+  set(_picky_tmp "")
+  foreach(_ccopt IN LISTS _picky)
+    # Prefix -Wall, otherwise clang-cl interprets it as an MSVC option and translates it to -Weverything
+    if(_ccopt MATCHES "^-W" AND NOT _ccopt STREQUAL "-Wall")
+      list(APPEND _picky_tmp ${_ccopt})
+    else()
+      list(APPEND _picky_tmp "-clang:${_ccopt}")
+    endif()
+  endforeach()
+  set(_picky ${_picky_tmp})
 endif()
 
 if(_picky)

+ 25 - 7
CMake/Utilities.cmake

@@ -23,13 +23,31 @@
 ###########################################################################
 # File containing various utilities
 
-# Returns number of arguments that evaluate to true
-function(count_true _output_count_var)
-  set(lst_len 0)
-  foreach(option_var IN LISTS ARGN)
-    if(${option_var})
-      math(EXPR lst_len "${lst_len} + 1")
+# Return number of arguments that evaluate to true
+function(curl_count_true _output_count_var)
+  set(_list_len 0)
+  foreach(_option_var IN LISTS ARGN)
+    if(${_option_var})
+      math(EXPR _list_len "${_list_len} + 1")
     endif()
   endforeach()
-  set(${_output_count_var} ${lst_len} PARENT_SCOPE)
+  set(${_output_count_var} ${_list_len} PARENT_SCOPE)
+endfunction()
+
+# Dump all defined variables with their values
+function(curl_dumpvars)
+  message("::group::CMake Variable Dump")
+  get_cmake_property(_vars VARIABLES)
+  foreach(_var IN ITEMS ${_vars})
+    get_property(_var_type CACHE ${_var} PROPERTY TYPE)
+    get_property(_var_advanced CACHE ${_var} PROPERTY ADVANCED)
+    if(_var_type)
+      set(_var_type ":${_var_type}")
+    endif()
+    if(_var_advanced)
+      set(_var_advanced " [adv]")
+    endif()
+    message("${_var}${_var_type}${_var_advanced} = ${${_var}}")
+  endforeach()
+  message("::endgroup::")
 endfunction()

+ 27 - 8
CMake/curl-config.cmake.in

@@ -23,13 +23,6 @@
 ###########################################################################
 @PACKAGE_INIT@
 
-if(UNIX OR VCPKG_TOOLCHAIN OR (MINGW AND NOT CMAKE_CROSSCOMPILING))  # Keep in sync with root CMakeLists.txt
-  set(_curl_use_pkgconfig_default ON)
-else()
-  set(_curl_use_pkgconfig_default OFF)
-endif()
-option(CURL_USE_PKGCONFIG "Enable pkg-config to detect @PROJECT_NAME@ dependencies" ${_curl_use_pkgconfig_default})
-
 include(CMakeFindDependencyMacro)
 if("@USE_OPENSSL@")
   find_dependency(OpenSSL "@OPENSSL_VERSION_MAJOR@")
@@ -39,7 +32,6 @@ if("@HAVE_LIBZ@")
 endif()
 
 include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
-check_required_components("@PROJECT_NAME@")
 
 # Alias for either shared or static library
 if(NOT TARGET @PROJECT_NAME@::libcurl)
@@ -47,5 +39,32 @@ if(NOT TARGET @PROJECT_NAME@::libcurl)
 endif()
 
 # For compatibility with CMake's FindCURL.cmake
+set(CURL_VERSION_STRING "@CURLVERSION@")
 set(CURL_LIBRARIES @PROJECT_NAME@::libcurl)
 set_and_check(CURL_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
+
+set(CURL_SUPPORTED_PROTOCOLS "@CURL_SUPPORTED_PROTOCOLS_LIST@")
+set(CURL_SUPPORTED_FEATURES "@CURL_SUPPORTED_FEATURES_LIST@")
+
+foreach(_item IN LISTS CURL_SUPPORTED_PROTOCOLS CURL_SUPPORTED_FEATURES)
+  set(CURL_SUPPORTS_${_item} TRUE)
+endforeach()
+
+set(_missing_req "")
+foreach(_item IN LISTS CURL_FIND_COMPONENTS)
+  if(CURL_SUPPORTS_${_item})
+    set(CURL_${_item}_FOUND TRUE)
+  elseif(CURL_FIND_REQUIRED_${_item})
+    list(APPEND _missing_req ${_item})
+  endif()
+endforeach()
+
+if(_missing_req)
+  string(REPLACE ";" " " _missing_req "${_missing_req}")
+  if(CURL_FIND_REQUIRED)
+    message(FATAL_ERROR "CURL: missing required components: ${_missing_req}")
+  endif()
+  unset(_missing_req)
+endif()
+
+check_required_components("@PROJECT_NAME@")

+ 22 - 11
CMake/Platforms/WindowsCache.cmake → CMake/win32-cache.cmake

@@ -32,11 +32,11 @@ if(MINGW)
   set(HAVE_UNISTD_H 1)
   set(HAVE_LIBGEN_H 1)
   set(HAVE_STDDEF_H 1)  # detected by CMake internally in check_type_size()
+  set(HAVE_STDINT_H 1)  # detected by CMake internally in check_type_size()
   set(HAVE_STDBOOL_H 1)
   set(HAVE_BOOL_T "${HAVE_STDBOOL_H}")
   set(HAVE_STRTOLL 1)
   set(HAVE_BASENAME 1)
-  set(HAVE_STRCASECMP 1)
   set(HAVE_FTRUNCATE 1)
   set(HAVE_SYS_PARAM_H 1)
   set(HAVE_SYS_TIME_H 1)
@@ -45,9 +45,23 @@ if(MINGW)
   set(HAVE_UTIME_H 1)  # wrapper to sys/utime.h
   set(HAVE_DIRENT_H 1)
   set(HAVE_OPENDIR 1)
+  if(MINGW64_VERSION)
+    if(NOT MINGW64_VERSION VERSION_LESS 4.0)
+      set(HAVE_STRTOK_R 1)
+    else()
+      set(HAVE_STRTOK_R 0)
+    endif()
+  endif()
+  if((CMAKE_COMPILER_IS_GNUCC              AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.9) OR
+     (CMAKE_C_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6))
+    set(HAVE_STDATOMIC_H 1)
+    set(HAVE_ATOMIC 1)
+  else()
+    set(HAVE_STDATOMIC_H 0)
+    set(HAVE_ATOMIC 0)
+  endif()
 else()
   set(HAVE_LIBGEN_H 0)
-  set(HAVE_STRCASECMP 0)
   set(HAVE_FTRUNCATE 0)
   set(HAVE_SYS_PARAM_H 0)
   set(HAVE_SYS_TIME_H 0)
@@ -58,9 +72,13 @@ else()
   set(HAVE_OPENDIR 0)
   if(MSVC)
     set(HAVE_UNISTD_H 0)
-    set(HAVE_LOCALE_H 1)
     set(HAVE_STDDEF_H 1)  # detected by CMake internally in check_type_size()
     set(HAVE_STDATOMIC_H 0)
+    if(NOT MSVC_VERSION LESS 1600)
+      set(HAVE_STDINT_H 1)  # detected by CMake internally in check_type_size()
+    else()
+      set(HAVE_STDINT_H 0)  # detected by CMake internally in check_type_size()
+    endif()
     if(NOT MSVC_VERSION LESS 1800)
       set(HAVE_STDBOOL_H 1)
       set(HAVE_STRTOLL 1)
@@ -85,7 +103,6 @@ endif()
 set(HAVE_GETADDRINFO 1)
 set(HAVE_FREEADDRINFO 1)
 
-set(HAVE_FCHMOD 0)
 set(HAVE_SOCKETPAIR 0)
 set(HAVE_SENDMSG 0)
 set(HAVE_SENDMMSG 0)
@@ -112,10 +129,8 @@ set(HAVE_GETHOSTNAME 1)
 set(HAVE_RECV 1)
 set(HAVE_SEND 1)
 set(HAVE_STROPTS_H 0)
-set(HAVE_SYS_XATTR_H 0)
 set(HAVE_ARC4RANDOM 0)
 set(HAVE_FNMATCH 0)
-set(HAVE_SCHED_YIELD 0)
 set(HAVE_ARPA_INET_H 0)
 set(HAVE_FCNTL_H 1)
 set(HAVE_IFADDRS_H 0)
@@ -132,7 +147,6 @@ set(HAVE_POLL 0)
 set(HAVE_PWD_H 0)
 set(HAVE_SYS_EVENTFD_H 0)
 set(HAVE_SYS_FILIO_H 0)
-set(HAVE_SYS_WAIT_H 0)
 set(HAVE_SYS_IOCTL_H 0)
 set(HAVE_SYS_POLL_H 0)
 set(HAVE_SYS_RESOURCE_H 0)
@@ -147,12 +161,9 @@ set(HAVE_TERMIOS_H 0)
 set(HAVE_TERMIO_H 0)
 set(HAVE_LINUX_TCP_H 0)
 
-set(HAVE_FSEEKO 0)  # mingw-w64 2.0.0 and newer has it
 set(HAVE_SOCKET 1)
 set(HAVE_SELECT 1)
 set(HAVE_STRDUP 1)
-set(HAVE_STRICMP 1)
-set(HAVE_STRCMPI 1)
 set(HAVE_MEMRCHR 0)
 set(HAVE_CLOSESOCKET 1)
 set(HAVE_SIGSETJMP 0)
@@ -178,6 +189,7 @@ set(HAVE_POSIX_STRERROR_R 0)
 set(HAVE_MSG_NOSIGNAL 0)
 set(HAVE_STRUCT_TIMEVAL 1)
 set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
+set(HAVE_TIME_T_UNSIGNED 0)
 
 set(HAVE_GETHOSTBYNAME_R_3 0)
 set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 0)
@@ -186,7 +198,6 @@ set(HAVE_GETHOSTBYNAME_R_5_REENTRANT 0)
 set(HAVE_GETHOSTBYNAME_R_6 0)
 set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
 
-set(HAVE_O_NONBLOCK 0)
 set(HAVE_IN_ADDR_T 0)
 set(STDC_HEADERS 1)
 

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 354 - 223
CMakeLists.txt


+ 1 - 1
COPYING

@@ -1,6 +1,6 @@
 COPYRIGHT AND PERMISSION NOTICE
 
-Copyright (c) 1996 - 2024, Daniel Stenberg, <[email protected]>, and many
+Copyright (c) 1996 - 2025, Daniel Stenberg, <[email protected]>, and many
 contributors, see the THANKS file.
 
 All rights reserved.

+ 49 - 3
include/curl/curl.h

@@ -1959,10 +1959,10 @@ typedef enum {
   /* Set stream weight, 1 - 256 (default is 16) */
   CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239),
 
-  /* Set stream dependency on another CURL handle */
+  /* Set stream dependency on another curl handle */
   CURLOPT(CURLOPT_STREAM_DEPENDS, CURLOPTTYPE_OBJECTPOINT, 240),
 
-  /* Set E-xclusive stream dependency on another CURL handle */
+  /* Set E-xclusive stream dependency on another curl handle */
   CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241),
 
   /* Do not send any tftp option requests to the server */
@@ -2959,7 +2959,9 @@ typedef enum {
   CURLINFO_USED_PROXY       = CURLINFO_LONG + 66,
   CURLINFO_POSTTRANSFER_TIME_T = CURLINFO_OFF_T + 67,
   CURLINFO_EARLYDATA_SENT_T = CURLINFO_OFF_T + 68,
-  CURLINFO_LASTONE          = 68
+  CURLINFO_HTTPAUTH_USED    = CURLINFO_LONG + 69,
+  CURLINFO_PROXYAUTH_USED   = CURLINFO_LONG + 70,
+  CURLINFO_LASTONE          = 70
 } CURLINFO;
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -3230,6 +3232,50 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #define CURLPAUSE_ALL       (CURLPAUSE_RECV|CURLPAUSE_SEND)
 #define CURLPAUSE_CONT      (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
 
+/*
+ * NAME curl_easy_ssls_import()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_ssls_import function adds a previously exported SSL session
+ * to the SSL session cache of the easy handle (or the underlying share).
+ */
+CURL_EXTERN CURLcode curl_easy_ssls_import(CURL *handle,
+                                           const char *session_key,
+                                           const unsigned char *shmac,
+                                           size_t shmac_len,
+                                           const unsigned char *sdata,
+                                           size_t sdata_len);
+
+/* This is the curl_ssls_export_cb callback prototype. It
+ * is passed to curl_easy_ssls_export() to extract SSL sessions/tickets. */
+typedef CURLcode curl_ssls_export_cb(CURL *handle,
+                                     void *userptr,
+                                     const char *session_key,
+                                     const unsigned char *shmac,
+                                     size_t shmac_len,
+                                     const unsigned char *sdata,
+                                     size_t sdata_len,
+                                     curl_off_t valid_until,
+                                     int ietf_tls_id,
+                                     const char *alpn,
+                                     size_t earlydata_max);
+
+/*
+ * NAME curl_easy_ssls_export()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_ssls_export function iterates over all SSL sessions stored
+ * in the easy handle (or underlying share) and invokes the passed
+ * callback.
+ *
+ */
+CURL_EXTERN CURLcode curl_easy_ssls_export(CURL *handle,
+                                           curl_ssls_export_cb *export_fn,
+                                           void *userptr);
+
+
 #ifdef  __cplusplus
 } /* end of extern "C" */
 #endif

+ 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.11.1-DEV"
+#define LIBCURL_VERSION "8.12.0-DEV"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 8
-#define LIBCURL_VERSION_MINOR 11
-#define LIBCURL_VERSION_PATCH 1
+#define LIBCURL_VERSION_MINOR 12
+#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 0x080b01
+#define LIBCURL_VERSION_NUM 0x080c00
 
 /*
  * This is the date and time when the full source package was created. The

+ 1 - 1
include/curl/easy.h

@@ -78,7 +78,7 @@ CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl);
  *
  * DESCRIPTION
  *
- * Re-initializes a CURL handle to the default values. This puts back the
+ * Re-initializes a curl handle to the default values. This puts back the
  * handle to the same state as it was in when it was just created.
  *
  * It does keep: live connections, the Session ID cache, the DNS cache and the

+ 40 - 96
include/curl/system.h

@@ -52,62 +52,24 @@
  *
  */
 
-#if defined(__DJGPP__) || defined(__GO32__)
-#  if defined(__DJGPP__) && (__DJGPP__ > 1)
-#    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 int
-
-#elif defined(__SALFORDC__)
-#  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
+#if defined(__DJGPP__)
+#  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
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 #elif defined(__BORLANDC__)
-#  if (__BORLANDC__ < 0x520)
-#    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
-#  else
-#    define CURL_TYPEOF_CURL_OFF_T     __int64
-#    define CURL_FORMAT_CURL_OFF_T     "I64d"
-#    define CURL_FORMAT_CURL_OFF_TU    "I64u"
-#    define CURL_SUFFIX_CURL_OFF_T     i64
-#    define CURL_SUFFIX_CURL_OFF_TU    ui64
-#  endif
-#  define CURL_TYPEOF_CURL_SOCKLEN_T int
-
-#elif defined(__TURBOC__)
-#  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
+#  define CURL_TYPEOF_CURL_OFF_T     __int64
+#  define CURL_FORMAT_CURL_OFF_T     "I64d"
+#  define CURL_FORMAT_CURL_OFF_TU    "I64u"
+#  define CURL_SUFFIX_CURL_OFF_T     i64
+#  define CURL_SUFFIX_CURL_OFF_TU    ui64
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 #elif defined(__POCC__)
-#  if (__POCC__ < 280)
-#    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
-#  elif defined(_MSC_VER)
+#  if defined(_MSC_VER)
 #    define CURL_TYPEOF_CURL_OFF_T     __int64
 #    define CURL_FORMAT_CURL_OFF_T     "I64d"
 #    define CURL_FORMAT_CURL_OFF_TU    "I64u"
@@ -159,15 +121,21 @@
 #  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
 
 #elif defined(__TANDEM)
-# if ! defined(__LP64)
-   /* Required for 32-bit NonStop builds only. */
-#  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
-#  define CURL_TYPEOF_CURL_SOCKLEN_T int
-# endif
+#  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
+#    define CURL_TYPEOF_CURL_SOCKLEN_T int
+#  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
+#    define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+#  endif
 
 #elif defined(_WIN32_WCE)
 #  define CURL_TYPEOF_CURL_OFF_T     __int64
@@ -220,13 +188,7 @@
 #    define CURL_FORMAT_CURL_OFF_TU    "llu"
 #    define CURL_SUFFIX_CURL_OFF_T     LL
 #    define CURL_SUFFIX_CURL_OFF_TU    ULL
-#  elif defined(_LP64)
-#    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
-#  else
+#  else /* _LP64 and default */
 #    define CURL_TYPEOF_CURL_OFF_T     long
 #    define CURL_FORMAT_CURL_OFF_T     "ld"
 #    define CURL_FORMAT_CURL_OFF_TU    "lu"
@@ -239,22 +201,13 @@
 
 #elif defined(__370__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
-#    if defined(_ILP32)
-#    elif defined(_LP64)
-#    endif
 #    if defined(_LONG_LONG)
 #      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
-#    elif defined(_LP64)
-#      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
-#    else
+#    else /* _LP64 and default */
 #      define CURL_TYPEOF_CURL_OFF_T     long
 #      define CURL_FORMAT_CURL_OFF_T     "ld"
 #      define CURL_FORMAT_CURL_OFF_TU    "lu"
@@ -349,24 +302,15 @@
 #elif defined(_MSC_VER)
 #  if (_MSC_VER >= 1800)
 #    include <inttypes.h>
-#    define CURL_TYPEOF_CURL_OFF_T     __int64
 #    define CURL_FORMAT_CURL_OFF_T     PRId64
 #    define CURL_FORMAT_CURL_OFF_TU    PRIu64
-#    define CURL_SUFFIX_CURL_OFF_T     i64
-#    define CURL_SUFFIX_CURL_OFF_TU    ui64
-#  elif (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
-#    define CURL_TYPEOF_CURL_OFF_T     __int64
+#  else
 #    define CURL_FORMAT_CURL_OFF_T     "I64d"
 #    define CURL_FORMAT_CURL_OFF_TU    "I64u"
-#    define CURL_SUFFIX_CURL_OFF_T     i64
-#    define CURL_SUFFIX_CURL_OFF_TU    ui64
-#  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_OFF_T     __int64
+#  define CURL_SUFFIX_CURL_OFF_T     i64
+#  define CURL_SUFFIX_CURL_OFF_TU    ui64
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 /* ===================================== */
@@ -403,12 +347,12 @@
 
 #else
 /* generic "safe guess" on old 32-bit style */
-# define CURL_TYPEOF_CURL_OFF_T     long
-# define CURL_FORMAT_CURL_OFF_T     "ld"
-# define CURL_FORMAT_CURL_OFF_TU    "lu"
-# define CURL_SUFFIX_CURL_OFF_T     L
-# define CURL_SUFFIX_CURL_OFF_TU    UL
-# define CURL_TYPEOF_CURL_SOCKLEN_T int
+#  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
+#  define CURL_TYPEOF_CURL_SOCKLEN_T int
 #endif
 
 #ifdef _AIX
@@ -462,7 +406,7 @@
 
 #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
   defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
-  defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+  defined(__POCC__) || defined(__HIGHC__) || \
   defined(__ILEC400__)
   /* This compiler is believed to have an ISO compatible preprocessor */
 #define CURL_ISOCPP

+ 5 - 11
lib/CMakeLists.txt

@@ -28,7 +28,7 @@ add_definitions("-DBUILDING_LIBCURL")
 configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
 
 # Get 'CSOURCES', 'HHEADERS' variables
-transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
+curl_transform_makefile_inc("Makefile.inc" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 
 # DllMain is added later for DLL builds only.
@@ -105,9 +105,7 @@ if(SHARE_LIB_OBJECT)
     set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   if(CURL_HAS_LTO)
-    set_target_properties(${LIB_OBJECT} PROPERTIES
-      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
-      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+    set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
   endif()
 
   target_include_directories(${LIB_OBJECT} INTERFACE
@@ -138,9 +136,7 @@ if(BUILD_STATIC_LIBS)
     set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   if(CURL_HAS_LTO)
-    set_target_properties(${LIB_STATIC} PROPERTIES
-      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
-      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+    set_target_properties(${LIB_STATIC} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
   endif()
 
   target_include_directories(${LIB_STATIC} INTERFACE
@@ -177,9 +173,7 @@ if(BUILD_SHARED_LIBS)
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   if(CURL_HAS_LTO)
-    set_target_properties(${LIB_SHARED} PROPERTIES
-      INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE
-      INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE)
+    set_target_properties(${LIB_SHARED} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)
   endif()
 
   target_include_directories(${LIB_SHARED} INTERFACE
@@ -208,7 +202,7 @@ if(BUILD_SHARED_LIBS)
 
   if(CURL_LIBCURL_SOVERSION OR CURL_LIBCURL_VERSIONED_SYMBOLS)
     # Get 'VERSIONCHANGE', 'VERSIONADD', 'VERSIONDEL', 'VERSIONINFO' variables
-    transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
+    curl_transform_makefile_inc("Makefile.soname" "${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
     include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
 
     math(EXPR _cmakesoname "${VERSIONCHANGE} - ${VERSIONDEL}")

+ 10 - 2
lib/Makefile.inc

@@ -56,6 +56,8 @@ LIB_VTLS_CFILES =           \
   vtls/schannel_verify.c    \
   vtls/sectransp.c          \
   vtls/vtls.c               \
+  vtls/vtls_scache.c        \
+  vtls/vtls_spack.c         \
   vtls/wolfssl.c            \
   vtls/x509asn1.c
 
@@ -74,6 +76,8 @@ LIB_VTLS_HFILES =           \
   vtls/sectransp.h          \
   vtls/vtls.h               \
   vtls/vtls_int.h           \
+  vtls/vtls_scache.h        \
+  vtls/vtls_spack.h         \
   vtls/wolfssl.h            \
   vtls/x509asn1.h
 
@@ -112,7 +116,6 @@ LIB_CFILES =         \
   base64.c           \
   bufq.c             \
   bufref.c           \
-  c-hyper.c          \
   cf-h1-proxy.c      \
   cf-h2-proxy.c      \
   cf-haproxy.c       \
@@ -177,6 +180,7 @@ LIB_CFILES =         \
   http_negotiate.c   \
   http_ntlm.c        \
   http_proxy.c       \
+  httpsrr.c          \
   idn.c              \
   if2ip.c            \
   imap.c             \
@@ -223,6 +227,7 @@ LIB_CFILES =         \
   strcase.c          \
   strdup.c           \
   strerror.c         \
+  strparse.c         \
   strtok.c           \
   strtoofft.c        \
   system_win32.c     \
@@ -245,7 +250,6 @@ LIB_HFILES =         \
   asyn.h             \
   bufq.h             \
   bufref.h           \
-  c-hyper.h          \
   cf-h1-proxy.h      \
   cf-h2-proxy.h      \
   cf-haproxy.h       \
@@ -317,6 +321,7 @@ LIB_HFILES =         \
   http_negotiate.h   \
   http_ntlm.h        \
   http_proxy.h       \
+  httpsrr.h          \
   idn.h              \
   if2ip.h            \
   imap.h             \
@@ -344,7 +349,9 @@ LIB_HFILES =         \
   select.h           \
   sendf.h            \
   setopt.h           \
+  setup-os400.h      \
   setup-vms.h        \
+  setup-win32.h      \
   share.h            \
   sigpipe.h          \
   slist.h            \
@@ -358,6 +365,7 @@ LIB_HFILES =         \
   strcase.h          \
   strdup.h           \
   strerror.h         \
+  strparse.h         \
   strtok.h           \
   strtoofft.h        \
   system_win32.h     \

+ 78 - 67
lib/altsvc.c

@@ -40,6 +40,8 @@
 #include "rename.h"
 #include "strdup.h"
 #include "inet_pton.h"
+#include "strparse.h"
+#include "connect.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -47,28 +49,12 @@
 #include "memdebug.h"
 
 #define MAX_ALTSVC_LINE 4095
-#define MAX_ALTSVC_DATELENSTR "64"
-#define MAX_ALTSVC_DATELEN 64
-#define MAX_ALTSVC_HOSTLENSTR "512"
-#define MAX_ALTSVC_HOSTLEN 512
-#define MAX_ALTSVC_ALPNLENSTR "10"
+#define MAX_ALTSVC_DATELEN 256
+#define MAX_ALTSVC_HOSTLEN 2048
 #define MAX_ALTSVC_ALPNLEN 10
 
 #define H3VERSION "h3"
 
-static enum alpnid alpn2alpnid(char *name)
-{
-  if(strcasecompare(name, "h1"))
-    return ALPN_h1;
-  if(strcasecompare(name, "h2"))
-    return ALPN_h2;
-  if(strcasecompare(name, H3VERSION))
-    return ALPN_h3;
-  if(strcasecompare(name, "http/1.1"))
-    return ALPN_h1;
-  return ALPN_none; /* unknown, probably rubbish input */
-}
-
 /* Given the ALPN ID, return the name */
 const char *Curl_alpnid2str(enum alpnid id)
 {
@@ -93,33 +79,33 @@ static void altsvc_free(struct altsvc *as)
 }
 
 static struct altsvc *altsvc_createid(const char *srchost,
+                                      size_t hlen,
                                       const char *dsthost,
                                       size_t dlen, /* dsthost length */
                                       enum alpnid srcalpnid,
                                       enum alpnid dstalpnid,
-                                      unsigned int srcport,
-                                      unsigned int dstport)
+                                      size_t srcport,
+                                      size_t dstport)
 {
   struct altsvc *as = calloc(1, sizeof(struct altsvc));
-  size_t hlen;
   if(!as)
     return NULL;
-  hlen = strlen(srchost);
   DEBUGASSERT(hlen);
   DEBUGASSERT(dlen);
-  if(!hlen || !dlen) {
+  if(!hlen || !dlen)
     /* bad input */
-    free(as);
-    return NULL;
-  }
+    goto error;
   if((hlen > 2) && srchost[0] == '[') {
     /* IPv6 address, strip off brackets */
     srchost++;
     hlen -= 2;
   }
-  else if(srchost[hlen - 1] == '.')
+  else if(srchost[hlen - 1] == '.') {
     /* strip off trailing dot */
     hlen--;
+    if(!hlen)
+      goto error;
+  }
   if((dlen > 2) && dsthost[0] == '[') {
     /* IPv6 address, strip off brackets */
     dsthost++;
@@ -136,8 +122,8 @@ static struct altsvc *altsvc_createid(const char *srchost,
 
   as->src.alpnid = srcalpnid;
   as->dst.alpnid = dstalpnid;
-  as->src.port = curlx_ultous(srcport);
-  as->dst.port = curlx_ultous(dstport);
+  as->src.port = (unsigned short)srcport;
+  as->dst.port = (unsigned short)dstport;
 
   return as;
 error:
@@ -145,18 +131,19 @@ error:
   return NULL;
 }
 
-static struct altsvc *altsvc_create(char *srchost,
-                                    char *dsthost,
-                                    char *srcalpn,
-                                    char *dstalpn,
-                                    unsigned int srcport,
-                                    unsigned int dstport)
+static struct altsvc *altsvc_create(struct Curl_str *srchost,
+                                    struct Curl_str *dsthost,
+                                    struct Curl_str *srcalpn,
+                                    struct Curl_str *dstalpn,
+                                    size_t srcport,
+                                    size_t dstport)
 {
-  enum alpnid dstalpnid = alpn2alpnid(dstalpn);
-  enum alpnid srcalpnid = alpn2alpnid(srcalpn);
+  enum alpnid dstalpnid = Curl_alpn2alpnid(dstalpn->str, dstalpn->len);
+  enum alpnid srcalpnid = Curl_alpn2alpnid(srcalpn->str, srcalpn->len);
   if(!srcalpnid || !dstalpnid)
     return NULL;
-  return altsvc_createid(srchost, dsthost, strlen(dsthost),
+  return altsvc_createid(srchost->str, srchost->len,
+                         dsthost->str, dsthost->len,
                          srcalpnid, dstalpnid,
                          srcport, dstport);
 }
@@ -167,31 +154,50 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
   /* Example line:
      h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
    */
-  char srchost[MAX_ALTSVC_HOSTLEN + 1];
-  char dsthost[MAX_ALTSVC_HOSTLEN + 1];
-  char srcalpn[MAX_ALTSVC_ALPNLEN + 1];
-  char dstalpn[MAX_ALTSVC_ALPNLEN + 1];
-  char date[MAX_ALTSVC_DATELEN + 1];
-  unsigned int srcport;
-  unsigned int dstport;
-  unsigned int prio;
-  unsigned int persist;
-  int rc;
-
-  rc = sscanf(line,
-              "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u "
-              "%" MAX_ALTSVC_ALPNLENSTR "s %" MAX_ALTSVC_HOSTLENSTR "s %u "
-              "\"%" MAX_ALTSVC_DATELENSTR "[^\"]\" %u %u",
-              srcalpn, srchost, &srcport,
-              dstalpn, dsthost, &dstport,
-              date, &persist, &prio);
-  if(9 == rc) {
+  struct Curl_str srchost;
+  struct Curl_str dsthost;
+  struct Curl_str srcalpn;
+  struct Curl_str dstalpn;
+  struct Curl_str date;
+  size_t srcport;
+  size_t dstport;
+  size_t persist;
+  size_t prio;
+
+  if(Curl_str_word(&line, &srcalpn, MAX_ALTSVC_ALPNLEN) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_word(&line, &srchost, MAX_ALTSVC_HOSTLEN) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_number(&line, &srcport, 65535) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_word(&line, &dstalpn, MAX_ALTSVC_ALPNLEN) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_word(&line, &dsthost, MAX_ALTSVC_HOSTLEN) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_number(&line, &dstport, 65535) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_quotedword(&line, &date, MAX_ALTSVC_DATELEN) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_number(&line, &persist, 1) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_number(&line, &prio, 0) ||
+     Curl_str_newline(&line))
+    ;
+  else {
     struct altsvc *as;
-    time_t expires = Curl_getdate_capped(date);
-    as = altsvc_create(srchost, dsthost, srcalpn, dstalpn, srcport, dstport);
+    char dbuf[MAX_ALTSVC_DATELEN + 1];
+    time_t expires;
+
+    /* The date parser works on a null terminated string. The maximum length
+       is upheld by Curl_str_quotedword(). */
+    memcpy(dbuf, date.str, date.len);
+    dbuf[date.len] = 0;
+    expires = Curl_getdate_capped(dbuf);
+    as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, srcport,
+                       dstport);
     if(as) {
       as->expires = expires;
-      as->prio = prio;
+      as->prio = 0; /* not supported to just set zero */
       as->persist = persist ? 1 : 0;
       Curl_llist_append(&asi->list, as, &as->node);
     }
@@ -471,8 +477,6 @@ static time_t altsvc_debugtime(void *unused)
 #define time(x) altsvc_debugtime(x)
 #endif
 
-#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
-
 /*
  * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
  * the data correctly in the cache.
@@ -495,6 +499,8 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
   unsigned short dstport = srcport; /* the same by default */
   CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
   size_t entries = 0;
+  size_t alpnlen = strlen(alpnbuf);
+  size_t srchostlen = strlen(srchost);
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
   (void)data;
 #endif
@@ -515,7 +521,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
   do {
     if(*p == '=') {
       /* [protocol]="[host][:port]" */
-      enum alpnid dstalpnid = alpn2alpnid(alpnbuf); /* the same by default */
+      enum alpnid dstalpnid = Curl_alpn2alpnid(alpnbuf, alpnlen);
       p++;
       if(*p == '\"') {
         const char *dsthost = "";
@@ -633,13 +639,18 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
                this is the first entry of the line. */
             altsvc_flush(asi, srcalpnid, srchost, srcport);
 
-          as = altsvc_createid(srchost, dsthost, dstlen,
+          as = altsvc_createid(srchost, srchostlen,
+                               dsthost, dstlen,
                                srcalpnid, dstalpnid,
                                srcport, dstport);
           if(as) {
-            /* The expires time also needs to take the Age: value (if any) into
-               account. [See RFC 7838 section 3.1] */
-            as->expires = maxage + time(NULL);
+            time_t secs = time(NULL);
+            /* The expires time also needs to take the Age: value (if any)
+               into account. [See RFC 7838 section 3.1] */
+            if(maxage > (TIME_T_MAX - secs))
+              as->expires = TIME_T_MAX;
+            else
+              as->expires = maxage + secs;
             as->persist = persist;
             Curl_llist_append(&asi->list, as, &as->node);
             infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,

+ 0 - 7
lib/altsvc.h

@@ -29,13 +29,6 @@
 #include <curl/curl.h>
 #include "llist.h"
 
-enum alpnid {
-  ALPN_none = 0,
-  ALPN_h1 = CURLALTSVC_H1,
-  ALPN_h2 = CURLALTSVC_H2,
-  ALPN_h3 = CURLALTSVC_H3
-};
-
 struct althost {
   char *host;
   unsigned short port;

+ 2 - 3
lib/amigaos.c

@@ -196,12 +196,11 @@ int Curl_amiga_select(int nfds, fd_set *readfds, fd_set *writefds,
  */
 
 struct Library *SocketBase = NULL;
-extern int errno, h_errno;
 
 #ifdef __libnix__
 void __request(const char *msg);
 #else
-# define __request(msg)       Printf(msg "\n\a")
+# define __request(msg)       Printf((const unsigned char *)(msg "\n\a"), 0)
 #endif
 
 void Curl_amiga_cleanup(void)
@@ -215,7 +214,7 @@ void Curl_amiga_cleanup(void)
 CURLcode Curl_amiga_init(void)
 {
   if(!SocketBase)
-    SocketBase = OpenLibrary("bsdsocket.library", 4);
+    SocketBase = OpenLibrary((const unsigned char *)"bsdsocket.library", 4);
 
   if(!SocketBase) {
     __request("No TCP/IP Stack running!");

+ 151 - 107
lib/asyn-ares.c

@@ -24,14 +24,14 @@
 
 #include "curl_setup.h"
 
+#ifdef USE_ARES
+
 /***********************************************************************
  * Only for ares-enabled builds
  * And only for functions that fulfill the asynch resolver backend API
  * as defined in asyn.h, nothing else belongs in this file!
  **********************************************************************/
 
-#ifdef CURLRES_ARES
-
 #include <limits.h>
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
@@ -59,15 +59,101 @@
 #include "select.h"
 #include "progress.h"
 #include "timediff.h"
+#include "httpsrr.h"
+#include "strdup.h"
 
-#if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
-  defined(_WIN32)
-#  define CARES_STATICLIB
-#endif
 #include <ares.h>
 #include <ares_version.h> /* really old c-ares did not include this by
                              itself */
 
+/*
+ * Curl_ares_getsock() is called when the outside world (using
+ * curl_multi_fdset()) wants to get our fd_set setup and we are talking with
+ * ares. The caller must make sure that this function is only called when we
+ * have a working ares channel.
+ *
+ * Returns: sockets-in-use-bitmap
+ */
+
+int Curl_ares_getsock(struct Curl_easy *data,
+                      ares_channel channel,
+                      curl_socket_t *socks)
+{
+  struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
+  struct timeval timebuf;
+  int max = ares_getsock(channel,
+                         (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
+  struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf);
+  timediff_t milli = curlx_tvtoms(timeout);
+  Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
+  return max;
+}
+
+/*
+ * Curl_ares_perform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on, or -1 on error
+ */
+
+int Curl_ares_perform(ares_channel channel,
+                      timediff_t timeout_ms)
+{
+  int nfds;
+  int bitmask;
+  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+  int i;
+  int num = 0;
+
+  bitmask = ares_getsock(channel, socks, ARES_GETSOCK_MAXNUM);
+
+  for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
+    pfd[i].events = 0;
+    pfd[i].revents = 0;
+    if(ARES_GETSOCK_READABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLRDNORM|POLLIN;
+    }
+    if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+      pfd[i].fd = socks[i];
+      pfd[i].events |= POLLWRNORM|POLLOUT;
+    }
+    if(pfd[i].events)
+      num++;
+    else
+      break;
+  }
+
+  if(num) {
+    nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
+    if(nfds < 0)
+      return -1;
+  }
+  else
+    nfds = 0;
+
+  if(!nfds)
+    /* Call ares_process() unconditionally here, even if we simply timed out
+       above, as otherwise the ares name resolve will not timeout! */
+    ares_process_fd(channel, ARES_SOCKET_BAD, ARES_SOCKET_BAD);
+  else {
+    /* move through the descriptors and ask for processing on them */
+    for(i = 0; i < num; i++)
+      ares_process_fd(channel,
+                      (pfd[i].revents & (POLLRDNORM|POLLIN)) ?
+                      pfd[i].fd : ARES_SOCKET_BAD,
+                      (pfd[i].revents & (POLLWRNORM|POLLOUT)) ?
+                      pfd[i].fd : ARES_SOCKET_BAD);
+  }
+  return nfds;
+}
+
+#ifdef CURLRES_ARES
+
 #if ARES_VERSION >= 0x010500
 /* c-ares 1.5.0 or later, the callback proto is modified */
 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
@@ -93,22 +179,19 @@
 #define HAVE_CARES_GETADDRINFO 1
 #endif
 
+#if ARES_VERSION >= 0x011c00
+/* 1.28.0 and later have ares_query_dnsrec */
+#define HAVE_ARES_QUERY_DNSREC 1
+#ifdef USE_HTTPSRR
+#define USE_HTTPSRR_ARES 1
+#endif
+#endif
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 
-struct thread_data {
-  int num_pending; /* number of outstanding c-ares requests */
-  struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
-                                    parts */
-  int last_status;
-#ifndef HAVE_CARES_GETADDRINFO
-  struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
-#endif
-  char hostname[1];
-};
-
 /* How long we are willing to wait for additional parallel responses after
    obtaining a "definitive" one. For old c-ares without getaddrinfo.
 
@@ -280,89 +363,13 @@ static void destroy_async_data(struct Curl_async *async)
 
 /*
  * Curl_resolver_getsock() is called when someone from the outside world
- * (using curl_multi_fdset()) wants to get our fd_set setup and we are talking
- * with ares. The caller must make sure that this function is only called when
- * we have a working ares channel.
- *
- * Returns: sockets-in-use-bitmap
- */
-
-int Curl_resolver_getsock(struct Curl_easy *data,
-                          curl_socket_t *socks)
-{
-  struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
-  struct timeval timebuf;
-  int max = ares_getsock((ares_channel)data->state.async.resolver,
-                         (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
-  struct timeval *timeout =
-    ares_timeout((ares_channel)data->state.async.resolver, &maxtime, &timebuf);
-  timediff_t milli = curlx_tvtoms(timeout);
-  Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
-  return max;
-}
-
-/*
- * waitperform()
- *
- * 1) Ask ares what sockets it currently plays with, then
- * 2) wait for the timeout period to check for action on ares' sockets.
- * 3) tell ares to act on all the sockets marked as "with action"
- *
- * return number of sockets it worked on, or -1 on error
+ * (using curl_multi_fdset()) wants to get our fd_set setup.
  */
 
-static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
 {
-  int nfds;
-  int bitmask;
-  ares_socket_t socks[ARES_GETSOCK_MAXNUM];
-  struct pollfd pfd[ARES_GETSOCK_MAXNUM];
-  int i;
-  int num = 0;
-
-  bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
-                         ARES_GETSOCK_MAXNUM);
-
-  for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
-    pfd[i].events = 0;
-    pfd[i].revents = 0;
-    if(ARES_GETSOCK_READABLE(bitmask, i)) {
-      pfd[i].fd = socks[i];
-      pfd[i].events |= POLLRDNORM|POLLIN;
-    }
-    if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
-      pfd[i].fd = socks[i];
-      pfd[i].events |= POLLWRNORM|POLLOUT;
-    }
-    if(pfd[i].events)
-      num++;
-    else
-      break;
-  }
-
-  if(num) {
-    nfds = Curl_poll(pfd, (unsigned int)num, timeout_ms);
-    if(nfds < 0)
-      return -1;
-  }
-  else
-    nfds = 0;
-
-  if(!nfds)
-    /* Call ares_process() unconditionally here, even if we simply timed out
-       above, as otherwise the ares name resolve will not timeout! */
-    ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
-                    ARES_SOCKET_BAD);
-  else {
-    /* move through the descriptors and ask for processing on them */
-    for(i = 0; i < num; i++)
-      ares_process_fd((ares_channel)data->state.async.resolver,
-                      (pfd[i].revents & (POLLRDNORM|POLLIN)) ?
-                      pfd[i].fd : ARES_SOCKET_BAD,
-                      (pfd[i].revents & (POLLWRNORM|POLLOUT)) ?
-                      pfd[i].fd : ARES_SOCKET_BAD);
-  }
-  return nfds;
+  return Curl_ares_getsock(data, (ares_channel)data->state.async.resolver,
+                           socks);
 }
 
 /*
@@ -381,7 +388,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
   DEBUGASSERT(dns);
   *dns = NULL;
 
-  if(waitperform(data, 0) < 0)
+  if(Curl_ares_perform((ares_channel)data->state.async.resolver, 0) < 0)
     return CURLE_UNRECOVERABLE_POLL;
 
 #ifndef HAVE_CARES_GETADDRINFO
@@ -417,8 +424,19 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
 
     if(!data->state.async.dns)
       result = Curl_resolver_error(data);
-    else
+    else {
       *dns = data->state.async.dns;
+#ifdef USE_HTTPSRR_ARES
+      {
+        struct Curl_https_rrinfo *lhrr =
+          Curl_memdup(&res->hinfo, sizeof(struct Curl_https_rrinfo));
+        if(!lhrr)
+          result = CURLE_OUT_OF_MEMORY;
+        else
+          (*dns)->hinfo = lhrr;
+      }
+#endif
+    }
 
     destroy_async_data(&data->state.async);
   }
@@ -481,7 +499,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
     else
       timeout_ms = 1000;
 
-    if(waitperform(data, timeout_ms) < 0)
+    if(Curl_ares_perform((ares_channel)data->state.async.resolver,
+                         timeout_ms) < 0)
       return CURLE_UNRECOVERABLE_POLL;
     result = Curl_resolver_is_resolved(data, entry);
 
@@ -745,6 +764,7 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
 }
 
 #endif
+
 /*
  * Curl_resolver_getaddrinfo() - when using ares
  *
@@ -826,6 +846,16 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                          hostname, PF_INET,
                          query_completed_cb, data);
     }
+#endif
+#ifdef USE_HTTPSRR_ARES
+    {
+      res->num_pending++; /* one more */
+      memset(&res->hinfo, 0, sizeof(struct Curl_https_rrinfo));
+      ares_query_dnsrec((ares_channel)data->state.async.resolver,
+                        hostname, ARES_CLASS_IN,
+                        ARES_REC_TYPE_HTTPS,
+                        Curl_dnsrec_done_cb, data, NULL);
+    }
 #endif
     *waitp = 1; /* expect asynchronous response */
   }
@@ -838,14 +868,26 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
   CURLcode result = CURLE_NOT_BUILT_IN;
   int ares_result;
 
-  /* If server is NULL or empty, this would purge all DNS servers
-   * from ares library, which will cause any and all queries to fail.
-   * So, just return OK if none are configured and do not actually make
-   * any changes to c-ares. This lets c-ares use its defaults, which
-   * it gets from the OS (for instance from /etc/resolv.conf on Linux).
+  /* If server is NULL, this purges all DNS servers from c-ares. Reset it to
+   * default.
    */
-  if(!(servers && servers[0]))
-    return CURLE_OK;
+  if(!servers) {
+    Curl_resolver_cleanup(data->state.async.resolver);
+    result = Curl_resolver_init(data, &data->state.async.resolver);
+    if(!result) {
+      /* this now needs to restore the other options set to c-ares */
+      if(data->set.str[STRING_DNS_INTERFACE])
+        (void)Curl_set_dns_interface(data,
+                                     data->set.str[STRING_DNS_INTERFACE]);
+      if(data->set.str[STRING_DNS_LOCAL_IP4])
+        (void)Curl_set_dns_local_ip4(data,
+                                     data->set.str[STRING_DNS_LOCAL_IP4]);
+      if(data->set.str[STRING_DNS_LOCAL_IP6])
+        (void)Curl_set_dns_local_ip6(data,
+                                     data->set.str[STRING_DNS_LOCAL_IP6]);
+    }
+    return result;
+  }
 
 #ifdef HAVE_CARES_SERVERS_CSV
 #ifdef HAVE_CARES_PORTS_CSV
@@ -947,3 +989,5 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
 #endif
 }
 #endif /* CURLRES_ARES */
+
+#endif /* USE_ARES */

+ 72 - 38
lib/asyn-thread.c

@@ -64,6 +64,15 @@
 #include "inet_ntop.h"
 #include "curl_threads.h"
 #include "connect.h"
+#include "strdup.h"
+
+#ifdef USE_ARES
+#include <ares.h>
+#ifdef USE_HTTPSRR
+#define USE_HTTPSRR_ARES 1 /* the combo */
+#endif
+#endif
+
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -145,32 +154,6 @@ static bool init_resolve_thread(struct Curl_easy *data,
                                 const struct addrinfo *hints);
 
 
-/* Data for synchronization between resolver thread and its parent */
-struct thread_sync_data {
-  curl_mutex_t *mtx;
-  int done;
-  int port;
-  char *hostname;        /* hostname to resolve, Curl_async.hostname
-                            duplicate */
-#ifndef CURL_DISABLE_SOCKETPAIR
-  struct Curl_easy *data;
-  curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
-#endif
-  int sock_error;
-  struct Curl_addrinfo *res;
-#ifdef HAVE_GETADDRINFO
-  struct addrinfo hints;
-#endif
-  struct thread_data *td; /* for thread-self cleanup */
-};
-
-struct thread_data {
-  curl_thread_t thread_hnd;
-  unsigned int poll_interval;
-  timediff_t interval_end;
-  struct thread_sync_data tsd;
-};
-
 static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
 {
   return &(data->state.async.tdata->tsd);
@@ -195,9 +178,11 @@ void destroy_thread_sync_data(struct thread_sync_data *tsd)
    * close one end of the socket pair (may be done in resolver thread);
    * the other end (for reading) is always closed in the parent thread.
    */
+#ifndef USE_EVENTFD
   if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
     wakeup_close(tsd->sock_pair[1]);
   }
+#endif
 #endif
   memset(tsd, 0, sizeof(*tsd));
 }
@@ -218,7 +203,7 @@ int init_thread_sync_data(struct thread_data *td,
   /* Treat the request as done until the thread actually starts so any early
    * cleanup gets done properly.
    */
-  tsd->done = 1;
+  tsd->done = TRUE;
 #ifdef HAVE_GETADDRINFO
   DEBUGASSERT(hints);
   tsd->hints = *hints;
@@ -341,7 +326,7 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
       }
     }
 #endif
-    tsd->done = 1;
+    tsd->done = TRUE;
     Curl_mutex_release(tsd->mtx);
   }
 
@@ -380,7 +365,7 @@ CURL_STDCALL gethostbyname_thread(void *arg)
     free(td);
   }
   else {
-    tsd->done = 1;
+    tsd->done = TRUE;
     Curl_mutex_release(tsd->mtx);
   }
 
@@ -396,19 +381,22 @@ static void destroy_async_data(struct Curl_async *async)
 {
   if(async->tdata) {
     struct thread_data *td = async->tdata;
-    int done;
+    bool done;
 #ifndef CURL_DISABLE_SOCKETPAIR
     curl_socket_t sock_rd = td->tsd.sock_pair[0];
     struct Curl_easy *data = td->tsd.data;
 #endif
 
+#ifdef USE_HTTPSRR_ARES
+    ares_destroy(data->state.async.tdata->channel);
+#endif
     /*
      * if the thread is still blocking in the resolve syscall, detach it and
      * let the thread do the cleanup...
      */
     Curl_mutex_acquire(td->tsd.mtx);
     done = td->tsd.done;
-    td->tsd.done = 1;
+    td->tsd.done = TRUE;
     Curl_mutex_release(td->tsd.mtx);
 
     if(!done) {
@@ -437,6 +425,24 @@ static void destroy_async_data(struct Curl_async *async)
   async->hostname = NULL;
 }
 
+#ifdef USE_HTTPSRR_ARES
+static CURLcode resolve_httpsrr(struct Curl_easy *data,
+                                struct Curl_async *asp)
+{
+  int status = ares_init_options(&asp->tdata->channel, NULL, 0);
+  if(status != ARES_SUCCESS)
+    return CURLE_FAILED_INIT;
+
+  memset(&asp->tdata->hinfo, 0, sizeof(struct Curl_https_rrinfo));
+  ares_query_dnsrec(asp->tdata->channel,
+                    asp->hostname, ARES_CLASS_IN,
+                    ARES_REC_TYPE_HTTPS,
+                    Curl_dnsrec_done_cb, data, NULL);
+
+  return CURLE_OK;
+}
+#endif
+
 /*
  * init_resolve_thread() starts a new thread that performs the actual
  * resolve. This function returns before the resolve is done.
@@ -472,8 +478,8 @@ static bool init_resolve_thread(struct Curl_easy *data,
   if(!asp->hostname)
     goto err_exit;
 
-  /* The thread will set this to 1 when complete. */
-  td->tsd.done = 0;
+  /* The thread will set this TRUE when complete. */
+  td->tsd.done = FALSE;
 
 #ifdef HAVE_GETADDRINFO
   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
@@ -483,11 +489,14 @@ static bool init_resolve_thread(struct Curl_easy *data,
 
   if(td->thread_hnd == curl_thread_t_null) {
     /* The thread never started, so mark it as done here for proper cleanup. */
-    td->tsd.done = 1;
+    td->tsd.done = TRUE;
     err = errno;
     goto err_exit;
   }
-
+#ifdef USE_HTTPSRR_ARES
+  if(resolve_httpsrr(data, asp))
+    goto err_exit;
+#endif
   return TRUE;
 
 err_exit:
@@ -585,7 +594,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry)
 {
   struct thread_data *td = data->state.async.tdata;
-  int done = 0;
+  bool done = FALSE;
 
   DEBUGASSERT(entry);
   *entry = NULL;
@@ -594,6 +603,10 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
     DEBUGASSERT(td);
     return CURLE_COULDNT_RESOLVE_HOST;
   }
+#ifdef USE_HTTPSRR_ARES
+  if(Curl_ares_perform(data->state.async.tdata->channel, 0) < 0)
+    return CURLE_UNRECOVERABLE_POLL;
+#endif
 
   Curl_mutex_acquire(td->tsd.mtx);
   done = td->tsd.done;
@@ -607,6 +620,17 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
       destroy_async_data(&data->state.async);
       return result;
     }
+#ifdef USE_HTTPSRR_ARES
+    {
+      struct Curl_https_rrinfo *lhrr =
+        Curl_memdup(&td->hinfo, sizeof(struct Curl_https_rrinfo));
+      if(!lhrr) {
+        destroy_async_data(&data->state.async);
+        return CURLE_OUT_OF_MEMORY;
+      }
+      data->state.async.dns->hinfo = lhrr;
+    }
+#endif
     destroy_async_data(&data->state.async);
     *entry = data->state.async.dns;
   }
@@ -641,18 +665,28 @@ int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
   timediff_t milli;
   timediff_t ms;
   struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+  int socketi = 0;
 #ifndef CURL_DISABLE_SOCKETPAIR
   struct thread_data *td = data->state.async.tdata;
 #else
   (void)socks;
 #endif
 
+#ifdef USE_HTTPSRR_ARES
+  if(data->state.async.tdata) {
+    ret_val = Curl_ares_getsock(data, data->state.async.tdata->channel, socks);
+    for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
+      if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
+         !ARES_GETSOCK_WRITABLE(ret_val, socketi))
+        break;
+  }
+#endif
 #ifndef CURL_DISABLE_SOCKETPAIR
   if(td) {
     /* return read fd to client for polling the DNS resolution status */
-    socks[0] = td->tsd.sock_pair[0];
+    socks[socketi] = td->tsd.sock_pair[0];
     td->tsd.data = data;
-    ret_val = GETSOCK_READSOCK(0);
+    ret_val = GETSOCK_READSOCK(socketi);
   }
   else {
 #endif

+ 64 - 0
lib/asyn.h

@@ -26,6 +26,7 @@
 
 #include "curl_setup.h"
 #include "curl_addrinfo.h"
+#include "httpsrr.h"
 
 struct addrinfo;
 struct hostent;
@@ -33,6 +34,69 @@ struct Curl_easy;
 struct connectdata;
 struct Curl_dns_entry;
 
+#ifdef CURLRES_THREADED
+#include "curl_threads.h"
+
+/* Data for synchronization between resolver thread and its parent */
+struct thread_sync_data {
+  curl_mutex_t *mtx;
+  bool done;
+  int port;
+  char *hostname;        /* hostname to resolve, Curl_async.hostname
+                            duplicate */
+#ifndef CURL_DISABLE_SOCKETPAIR
+  struct Curl_easy *data;
+  curl_socket_t sock_pair[2]; /* eventfd/pipes/socket pair */
+#endif
+  int sock_error;
+  struct Curl_addrinfo *res;
+#ifdef HAVE_GETADDRINFO
+  struct addrinfo hints;
+#endif
+  struct thread_data *td; /* for thread-self cleanup */
+};
+
+struct thread_data {
+  curl_thread_t thread_hnd;
+  unsigned int poll_interval;
+  timediff_t interval_end;
+  struct thread_sync_data tsd;
+#if defined(USE_HTTPSRR) && defined(USE_ARES)
+  struct Curl_https_rrinfo hinfo;
+  ares_channel channel;
+#endif
+};
+
+#elif defined(CURLRES_ARES) /* CURLRES_THREADED */
+
+struct thread_data {
+  int num_pending; /* number of outstanding c-ares requests */
+  struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
+                                    parts */
+  int last_status;
+#ifndef HAVE_CARES_GETADDRINFO
+  struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
+#endif
+#ifdef USE_HTTPSRR
+  struct Curl_https_rrinfo hinfo;
+#endif
+  char hostname[1];
+};
+
+#endif /* CURLRES_ARES */
+
+#ifdef USE_ARES
+#include <ares.h>
+
+/* for HTTPS RR purposes as well */
+int Curl_ares_getsock(struct Curl_easy *data,
+                      ares_channel channel,
+                      curl_socket_t *socks);
+int Curl_ares_perform(ares_channel channel,
+                      timediff_t timeout_ms);
+#endif
+
+
 /*
  * This header defines all functions in the internal asynch resolver interface.
  * All asynch resolvers need to provide these functions.

+ 0 - 23
lib/bufq.c

@@ -45,11 +45,6 @@ static size_t chunk_len(const struct buf_chunk *chunk)
   return chunk->w_offset - chunk->r_offset;
 }
 
-static size_t chunk_space(const struct buf_chunk *chunk)
-{
-  return chunk->dlen - chunk->w_offset;
-}
-
 static void chunk_reset(struct buf_chunk *chunk)
 {
   chunk->next = NULL;
@@ -287,24 +282,6 @@ size_t Curl_bufq_len(const struct bufq *q)
   return len;
 }
 
-size_t Curl_bufq_space(const struct bufq *q)
-{
-  size_t space = 0;
-  if(q->tail)
-    space += chunk_space(q->tail);
-  if(q->spare) {
-    struct buf_chunk *chunk = q->spare;
-    while(chunk) {
-      space += chunk->dlen;
-      chunk = chunk->next;
-    }
-  }
-  if(q->chunk_count < q->max_chunks) {
-    space += (q->max_chunks - q->chunk_count) * q->chunk_size;
-  }
-  return space;
-}
-
 bool Curl_bufq_is_empty(const struct bufq *q)
 {
   return !q->head || chunk_is_empty(q->head);

+ 0 - 8
lib/bufq.h

@@ -150,14 +150,6 @@ void Curl_bufq_free(struct bufq *q);
  */
 size_t Curl_bufq_len(const struct bufq *q);
 
-/**
- * Return the total amount of free space in the queue.
- * The returned length is the number of bytes that can
- * be expected to be written successfully to the bufq,
- * providing no memory allocations fail.
- */
-size_t Curl_bufq_space(const struct bufq *q);
-
 /**
  * Returns TRUE iff there is no data in the buffer queue.
  */

+ 0 - 1254
lib/c-hyper.c

@@ -1,1254 +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.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-
-/* Curl's integration with Hyper. This replaces certain functions in http.c,
- * based on configuration #defines. This implementation supports HTTP/1.1 but
- * not HTTP/2.
- */
-#include "curl_setup.h"
-
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
-
-#ifdef HAVE_NETINET_IN_H
-#include <netinet/in.h>
-#endif
-
-#ifdef HAVE_NETDB_H
-#include <netdb.h>
-#endif
-#ifdef HAVE_ARPA_INET_H
-#include <arpa/inet.h>
-#endif
-#ifdef HAVE_NET_IF_H
-#include <net/if.h>
-#endif
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-
-#ifdef HAVE_SYS_PARAM_H
-#include <sys/param.h>
-#endif
-
-#include <hyper.h>
-#include "urldata.h"
-#include "cfilters.h"
-#include "sendf.h"
-#include "headers.h"
-#include "transfer.h"
-#include "multiif.h"
-#include "progress.h"
-#include "content_encoding.h"
-#include "ws.h"
-
-/* The last 3 #include files should be in this order */
-#include "curl_printf.h"
-#include "curl_memory.h"
-#include "memdebug.h"
-
-
-static CURLcode cr_hyper_add(struct Curl_easy *data);
-
-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)
-{
-  struct hyp_io_ctx *io_ctx = userp;
-  struct Curl_easy *data = io_ctx->data;
-  struct connectdata *conn = data->conn;
-  CURLcode result;
-  ssize_t nread;
-  DEBUGASSERT(conn);
-  (void)ctx;
-
-  DEBUGF(infof(data, "Curl_hyper_recv(%zu)", buflen));
-  result = Curl_conn_recv(data, io_ctx->sockindex,
-                          (char *)buf, buflen, &nread);
-  if(result == CURLE_AGAIN) {
-    /* would block, register interest */
-    DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> EAGAIN", buflen));
-    if(data->hyp.read_waker)
-      hyper_waker_free(data->hyp.read_waker);
-    data->hyp.read_waker = hyper_context_waker(ctx);
-    if(!data->hyp.read_waker) {
-      failf(data, "Couldn't make the read hyper_context_waker");
-      return HYPER_IO_ERROR;
-    }
-    return HYPER_IO_PENDING;
-  }
-  else if(result) {
-    failf(data, "Curl_read failed");
-    return HYPER_IO_ERROR;
-  }
-  DEBUGF(infof(data, "Curl_hyper_recv(%zu) -> %zd", buflen, nread));
-  return (size_t)nread;
-}
-
-size_t Curl_hyper_send(void *userp, hyper_context *ctx,
-                       const uint8_t *buf, size_t buflen)
-{
-  struct hyp_io_ctx *io_ctx = userp;
-  struct Curl_easy *data = io_ctx->data;
-  CURLcode result;
-  size_t nwrote;
-
-  DEBUGF(infof(data, "Curl_hyper_send(%zu)", buflen));
-  result = Curl_conn_send(data, io_ctx->sockindex,
-                          (void *)buf, buflen, FALSE, &nwrote);
-  if(result == CURLE_AGAIN) {
-    DEBUGF(infof(data, "Curl_hyper_send(%zu) -> EAGAIN", buflen));
-    /* would block, register interest */
-    if(data->hyp.write_waker)
-      hyper_waker_free(data->hyp.write_waker);
-    data->hyp.write_waker = hyper_context_waker(ctx);
-    if(!data->hyp.write_waker) {
-      failf(data, "Couldn't make the write hyper_context_waker");
-      return HYPER_IO_ERROR;
-    }
-    return HYPER_IO_PENDING;
-  }
-  else if(result) {
-    failf(data, "Curl_write failed");
-    return HYPER_IO_ERROR;
-  }
-  DEBUGF(infof(data, "Curl_hyper_send(%zu) -> %zd", buflen, nwrote));
-  return (size_t)nwrote;
-}
-
-static int hyper_each_header(void *userdata,
-                             const uint8_t *name,
-                             size_t name_len,
-                             const uint8_t *value,
-                             size_t value_len)
-{
-  struct Curl_easy *data = (struct Curl_easy *)userdata;
-  size_t len;
-  char *headp;
-  CURLcode result;
-  int writetype;
-
-  if(name_len + value_len + 2 > CURL_MAX_HTTP_HEADER) {
-    failf(data, "Too long response header");
-    data->state.hresult = CURLE_TOO_LARGE;
-    return HYPER_ITER_BREAK;
-  }
-
-  Curl_dyn_reset(&data->state.headerb);
-  if(name_len) {
-    if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
-                     (int) name_len, name, (int) value_len, value))
-      return HYPER_ITER_BREAK;
-  }
-  else {
-    if(Curl_dyn_addn(&data->state.headerb, STRCONST("\r\n")))
-      return HYPER_ITER_BREAK;
-  }
-  len = Curl_dyn_len(&data->state.headerb);
-  headp = Curl_dyn_ptr(&data->state.headerb);
-
-  result = Curl_http_header(data, headp, len);
-  if(result) {
-    data->state.hresult = result;
-    return HYPER_ITER_BREAK;
-  }
-
-  Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
-
-  writetype = CLIENTWRITE_HEADER;
-  if(data->state.hconnect)
-    writetype |= CLIENTWRITE_CONNECT;
-  if(data->req.httpcode/100 == 1)
-    writetype |= CLIENTWRITE_1XX;
-  result = Curl_client_write(data, writetype, headp, len);
-  if(result) {
-    data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
-    return HYPER_ITER_BREAK;
-  }
-
-  result = Curl_bump_headersize(data, len, FALSE);
-  if(result) {
-    data->state.hresult = result;
-    return HYPER_ITER_BREAK;
-  }
-  return HYPER_ITER_CONTINUE;
-}
-
-static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
-{
-  char *buf = (char *)hyper_buf_bytes(chunk);
-  size_t len = hyper_buf_len(chunk);
-  struct Curl_easy *data = (struct Curl_easy *)userdata;
-  struct SingleRequest *k = &data->req;
-  CURLcode result = CURLE_OK;
-
-  if(!k->bodywritten) {
-#if defined(USE_NTLM)
-    struct connectdata *conn = data->conn;
-    if(conn->bits.close &&
-       (((data->req.httpcode == 401) &&
-         (conn->http_ntlm_state == NTLMSTATE_TYPE2)) ||
-        ((data->req.httpcode == 407) &&
-         (conn->proxy_ntlm_state == NTLMSTATE_TYPE2)))) {
-      infof(data, "Connection closed while negotiating NTLM");
-      data->state.authproblem = TRUE;
-      Curl_safefree(data->req.newurl);
-    }
-#endif
-    if(Curl_http_exp100_is_selected(data)) {
-      if(data->req.httpcode < 400) {
-        Curl_http_exp100_got100(data);
-        if(data->hyp.send_body_waker) {
-          hyper_waker_wake(data->hyp.send_body_waker);
-          data->hyp.send_body_waker = NULL;
-        }
-      }
-      else { /* >= 4xx */
-        Curl_req_abort_sending(data);
-      }
-    }
-    if(data->state.hconnect && (data->req.httpcode/100 != 2) &&
-       data->state.authproxy.done) {
-      data->req.done = TRUE;
-      result = CURLE_OK;
-    }
-    else
-      result = Curl_http_firstwrite(data);
-    if(result || data->req.done) {
-      infof(data, "Return early from hyper_body_chunk");
-      data->state.hresult = result;
-      return HYPER_ITER_BREAK;
-    }
-  }
-  result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
-
-  if(result) {
-    data->state.hresult = result;
-    return HYPER_ITER_BREAK;
-  }
-
-  return HYPER_ITER_CONTINUE;
-}
-
-/*
- * Hyper does not consider the status line, the first line in an HTTP/1
- * response, to be a header. The libcurl API does. This function sends the
- * status line in the header callback. */
-static CURLcode status_line(struct Curl_easy *data,
-                            struct connectdata *conn,
-                            uint16_t http_status,
-                            int http_version,
-                            const uint8_t *reason, size_t rlen)
-{
-  CURLcode result;
-  size_t len;
-  const char *vstr;
-  int writetype;
-  vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
-    (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
-
-  /* We need to set 'httpcodeq' for functions that check the response code in
-     a single place. */
-  data->req.httpcode = http_status;
-  data->req.httpversion = http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
-                          (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
-  if(data->state.hconnect)
-    /* CONNECT */
-    data->info.httpproxycode = http_status;
-  else {
-    conn->httpversion = (unsigned char)data->req.httpversion;
-    if(http_version == HYPER_HTTP_VERSION_1_0)
-      data->state.httpwant = CURL_HTTP_VERSION_1_0;
-
-    result = Curl_http_statusline(data, conn);
-    if(result)
-      return result;
-  }
-
-  Curl_dyn_reset(&data->state.headerb);
-
-  result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n",
-                         vstr,
-                         (int)http_status,
-                         (int)rlen, reason);
-  if(result)
-    return result;
-  len = Curl_dyn_len(&data->state.headerb);
-  Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
-             len);
-
-  writetype = CLIENTWRITE_HEADER|CLIENTWRITE_STATUS;
-  if(data->state.hconnect)
-    writetype |= CLIENTWRITE_CONNECT;
-  result = Curl_client_write(data, writetype,
-                             Curl_dyn_ptr(&data->state.headerb), len);
-  if(result)
-    return result;
-
-  result = Curl_bump_headersize(data, len, FALSE);
-  return result;
-}
-
-/*
- * Hyper does not pass on the last empty response header. The libcurl API
- * does. This function sends an empty header in the header callback.
- */
-static CURLcode empty_header(struct Curl_easy *data)
-{
-  CURLcode result = Curl_http_size(data);
-  if(!result) {
-    result = hyper_each_header(data, NULL, 0, NULL, 0) ?
-      CURLE_WRITE_ERROR : CURLE_OK;
-    if(result)
-      failf(data, "hyperstream: could not pass blank header");
-    /* Hyper does chunked decoding itself. If it was added during
-     * response header processing, remove it again. */
-    Curl_cwriter_remove_by_name(data, "chunked");
-  }
-  return result;
-}
-
-CURLcode Curl_hyper_stream(struct Curl_easy *data,
-                           struct connectdata *conn,
-                           int *didwhat,
-                           int select_res)
-{
-  hyper_response *resp = NULL;
-  uint16_t http_status;
-  int http_version;
-  hyper_headers *headers = NULL;
-  hyper_body *resp_body = NULL;
-  struct hyptransfer *h = &data->hyp;
-  hyper_task *task;
-  hyper_task *foreach;
-  const uint8_t *reasonp;
-  size_t reason_len;
-  CURLcode result = CURLE_OK;
-  struct SingleRequest *k = &data->req;
-  (void)conn;
-
-  if(data->hyp.send_body_waker) {
-    /* If there is still something to upload, wake it to give it
-     * another try. */
-    hyper_waker_wake(data->hyp.send_body_waker);
-    data->hyp.send_body_waker = NULL;
-  }
-
-  if(select_res & CURL_CSELECT_IN) {
-    if(h->read_waker)
-      hyper_waker_wake(h->read_waker);
-    h->read_waker = NULL;
-  }
-  if(select_res & CURL_CSELECT_OUT) {
-    if(h->write_waker)
-      hyper_waker_wake(h->write_waker);
-    h->write_waker = NULL;
-  }
-
-  while(1) {
-    hyper_task_return_type t;
-    task = hyper_executor_poll(h->exec);
-    if(!task) {
-      *didwhat = KEEP_RECV;
-      break;
-    }
-    t = hyper_task_type(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;
-        infof(data, "hyperstream is done (by early callback)");
-      }
-      else {
-        uint8_t errbuf[256];
-        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);
-        switch(code) {
-        case HYPERE_ABORTED_BY_CALLBACK:
-          result = CURLE_OK;
-          goto out;
-        case HYPERE_UNEXPECTED_EOF:
-          if(!data->req.bytecount)
-            result = CURLE_GOT_NOTHING;
-          else
-            result = CURLE_RECV_ERROR;
-          goto out;
-        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 */
-          goto out;
-        default:
-          result = CURLE_RECV_ERROR;
-          goto out;
-        }
-      }
-      data->req.done = TRUE;
-      hyper_error_free(hypererr);
-      break;
-    }
-    else if(t == HYPER_TASK_EMPTY) {
-      void *userdata = hyper_task_userdata(task);
-      hyper_task_free(task);
-      if(userdata == (void *)USERDATA_RESP_BODY) {
-        /* end of transfer */
-        data->req.done = TRUE;
-        infof(data, "hyperstream is done");
-        if(!k->bodywritten) {
-          /* hyper does not always call the body write callback */
-          result = Curl_http_firstwrite(data);
-        }
-        break;
-      }
-      else {
-        /* A background task for hyper; ignore */
-        DEBUGF(infof(data, "hyper: some background task done"));
-        continue;
-      }
-    }
-    else if(t == HYPER_TASK_RESPONSE) {
-      resp = hyper_task_value(task);
-      hyper_task_free(task);
-
-      *didwhat = KEEP_RECV;
-      if(!resp) {
-        failf(data, "hyperstream: could not get response");
-        result = CURLE_RECV_ERROR;
-        goto out;
-      }
-
-      http_status = hyper_response_status(resp);
-      http_version = hyper_response_version(resp);
-      reasonp = hyper_response_reason_phrase(resp);
-      reason_len = hyper_response_reason_phrase_len(resp);
-
-      if(http_status == 417 && Curl_http_exp100_is_selected(data)) {
-        infof(data, "Got 417 while waiting for a 100");
-        data->state.disableexpect = TRUE;
-        data->req.newurl = strdup(data->state.url);
-        Curl_req_abort_sending(data);
-      }
-
-      result = status_line(data, conn,
-                           http_status, http_version, reasonp, reason_len);
-      if(result)
-        goto out;
-
-      headers = hyper_response_headers(resp);
-      if(!headers) {
-        failf(data, "hyperstream: could not get response headers");
-        result = CURLE_RECV_ERROR;
-        goto out;
-      }
-
-      /* the headers are already received */
-      hyper_headers_foreach(headers, hyper_each_header, data);
-      if(data->state.hresult) {
-        result = data->state.hresult;
-        goto out;
-      }
-
-      result = empty_header(data);
-      if(result)
-        goto out;
-
-      k->deductheadercount =
-        (100 <= http_status && 199 >= http_status) ? k->headerbytecount : 0;
-#ifndef CURL_DISABLE_WEBSOCKETS
-      if(k->upgr101 == UPGR101_WS) {
-        if(http_status == 101) {
-          /* verify the response */
-          result = Curl_ws_accept(data, NULL, 0);
-          if(result)
-            goto out;
-        }
-        else {
-          failf(data, "Expected 101, got %u", k->httpcode);
-          result = CURLE_HTTP_RETURNED_ERROR;
-          goto out;
-        }
-      }
-#endif
-
-      /* Curl_http_auth_act() checks what authentication methods that are
-       * available and decides which one (if any) to use. It will set 'newurl'
-       * if an auth method was picked. */
-      result = Curl_http_auth_act(data);
-      if(result)
-        goto out;
-
-      resp_body = hyper_response_body(resp);
-      if(!resp_body) {
-        failf(data, "hyperstream: could not get response body");
-        result = CURLE_RECV_ERROR;
-        goto out;
-      }
-      foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
-      if(!foreach) {
-        failf(data, "hyperstream: body foreach failed");
-        result = CURLE_OUT_OF_MEMORY;
-        goto out;
-      }
-      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;
-        goto out;
-      }
-
-      hyper_response_free(resp);
-      resp = NULL;
-    }
-    else {
-      DEBUGF(infof(data, "hyper: unhandled tasktype %x", t));
-    }
-  } /* while(1) */
-
-  if(!result && Curl_xfer_needs_flush(data)) {
-    DEBUGF(infof(data, "Curl_hyper_stream(), connection needs flush"));
-    result = Curl_xfer_flush(data);
-  }
-
-out:
-  DEBUGF(infof(data, "Curl_hyper_stream() -> %d", result));
-  if(resp)
-    hyper_response_free(resp);
-  return result;
-}
-
-static CURLcode debug_request(struct Curl_easy *data,
-                              const char *method,
-                              const char *path)
-{
-  char *req = aprintf("%s %s HTTP/1.1\r\n", method, path);
-  if(!req)
-    return CURLE_OUT_OF_MEMORY;
-  Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
-  free(req);
-  return CURLE_OK;
-}
-
-/*
- * Given a full header line "name: value" (optional CRLF in the input, should
- * be in the output), add to Hyper and send to the debug callback.
- *
- * Supports multiple headers.
- */
-
-CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
-                           const char *line)
-{
-  const char *p;
-  const char *n;
-  size_t nlen;
-  const char *v;
-  size_t vlen;
-  bool newline = TRUE;
-  int numh = 0;
-
-  if(!line)
-    return CURLE_OK;
-  n = line;
-  do {
-    size_t linelen = 0;
-
-    p = strchr(n, ':');
-    if(!p)
-      /* this is fine if we already added at least one header */
-      return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
-    nlen = p - n;
-    p++; /* move past the colon */
-    while(*p == ' ')
-      p++;
-    v = p;
-    p = strchr(v, '\r');
-    if(!p) {
-      p = strchr(v, '\n');
-      if(p)
-        linelen = 1; /* LF only */
-      else {
-        p = strchr(v, '\0');
-        newline = FALSE; /* no newline */
-      }
-    }
-    else
-      linelen = 2; /* CRLF ending */
-    linelen += (p - n);
-    vlen = p - v;
-
-    if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
-                                      (uint8_t *)v, vlen)) {
-      failf(data, "hyper refused to add header '%s'", line);
-      return CURLE_OUT_OF_MEMORY;
-    }
-    if(data->set.verbose) {
-      char *ptr = NULL;
-      if(!newline) {
-        ptr = aprintf("%.*s\r\n", (int)linelen, line);
-        if(!ptr)
-          return CURLE_OUT_OF_MEMORY;
-        Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
-        free(ptr);
-      }
-      else
-        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)n, linelen);
-    }
-    numh++;
-    n += linelen;
-  } while(newline);
-  return CURLE_OK;
-}
-
-static CURLcode request_target(struct Curl_easy *data,
-                               struct connectdata *conn,
-                               const char *method,
-                               hyper_request *req)
-{
-  CURLcode result;
-  struct dynbuf r;
-
-  Curl_dyn_init(&r, DYN_HTTP_REQUEST);
-
-  result = Curl_http_target(data, conn, &r);
-  if(result)
-    return result;
-
-  if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
-                                       Curl_dyn_len(&r))) {
-    failf(data, "error setting uri to hyper");
-    result = CURLE_OUT_OF_MEMORY;
-  }
-  else
-    result = debug_request(data, method, Curl_dyn_ptr(&r));
-
-  Curl_dyn_free(&r);
-
-  return result;
-}
-
-static int uploadstreamed(void *userdata, hyper_context *ctx,
-                          hyper_buf **chunk)
-{
-  size_t fillcount;
-  struct Curl_easy *data = (struct Curl_easy *)userdata;
-  CURLcode result;
-  char *xfer_ulbuf;
-  size_t xfer_ulblen;
-  bool eos;
-  int rc = HYPER_POLL_ERROR;
-  (void)ctx;
-
-  result = Curl_multi_xfer_ulbuf_borrow(data, &xfer_ulbuf, &xfer_ulblen);
-  if(result)
-    goto out;
-
-  result = Curl_client_read(data, xfer_ulbuf, xfer_ulblen, &fillcount, &eos);
-  if(result)
-    goto out;
-
-  if(fillcount) {
-    hyper_buf *copy = hyper_buf_copy((uint8_t *)xfer_ulbuf, fillcount);
-    if(copy)
-      *chunk = copy;
-    else {
-      result = CURLE_OUT_OF_MEMORY;
-      goto out;
-    }
-    /* increasing the writebytecount here is a little premature but we
-       do not know exactly when the body is sent */
-    data->req.writebytecount += fillcount;
-    if(eos)
-      data->req.eos_read = TRUE;
-    Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
-    rc = HYPER_POLL_READY;
-  }
-  else if(eos) {
-    data->req.eos_read = TRUE;
-    *chunk = NULL;
-    rc = HYPER_POLL_READY;
-  }
-  else {
-    /* paused, save a waker */
-    if(data->hyp.send_body_waker)
-      hyper_waker_free(data->hyp.send_body_waker);
-    data->hyp.send_body_waker = hyper_context_waker(ctx);
-    rc = HYPER_POLL_PENDING;
-  }
-
-  if(!data->req.upload_done && data->req.eos_read) {
-    DEBUGF(infof(data, "hyper: uploadstreamed(), upload is done"));
-    result = Curl_req_set_upload_done(data);
-  }
-
-out:
-  Curl_multi_xfer_ulbuf_release(data, xfer_ulbuf);
-  data->state.hresult = result;
-  DEBUGF(infof(data, "hyper: uploadstreamed() -> %d", result));
-  return rc;
-}
-
-/*
- * finalize_request() sets up last headers and optional body settings
- */
-static CURLcode finalize_request(struct Curl_easy *data,
-                                 hyper_headers *headers,
-                                 hyper_request *hyperreq,
-                                 Curl_HttpReq httpreq)
-{
-  CURLcode result = CURLE_OK;
-  struct dynbuf req;
-  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
-    Curl_pgrsSetUploadSize(data, 0); /* no request body */
-  }
-  else {
-    hyper_body *body;
-    Curl_dyn_init(&req, DYN_HTTP_REQUEST);
-    result = Curl_http_req_complete(data, &req, httpreq);
-    if(result)
-      return result;
-
-    /* if the "complete" above did produce more than the closing line,
-       parse the added headers */
-    if(Curl_dyn_len(&req) != 2 || strcmp(Curl_dyn_ptr(&req), "\r\n")) {
-      result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
-      if(result)
-        return result;
-    }
-
-    Curl_dyn_free(&req);
-
-    body = hyper_body_new();
-    hyper_body_set_userdata(body, data);
-    hyper_body_set_data_func(body, uploadstreamed);
-
-    if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
-      /* fail */
-      result = CURLE_OUT_OF_MEMORY;
-    }
-  }
-
-  return cr_hyper_add(data);
-}
-
-static CURLcode cookies(struct Curl_easy *data,
-                        struct connectdata *conn,
-                        hyper_headers *headers)
-{
-  struct dynbuf req;
-  CURLcode result;
-  Curl_dyn_init(&req, DYN_HTTP_REQUEST);
-
-  result = Curl_http_cookies(data, conn, &req);
-  if(!result)
-    result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
-  Curl_dyn_free(&req);
-  return result;
-}
-
-/* called on 1xx responses */
-static void http1xx_cb(void *arg, struct hyper_response *resp)
-{
-  struct Curl_easy *data = (struct Curl_easy *)arg;
-  hyper_headers *headers = NULL;
-  CURLcode result = CURLE_OK;
-  uint16_t http_status;
-  int http_version;
-  const uint8_t *reasonp;
-  size_t reason_len;
-
-  infof(data, "Got HTTP 1xx informational");
-
-  http_status = hyper_response_status(resp);
-  http_version = hyper_response_version(resp);
-  reasonp = hyper_response_reason_phrase(resp);
-  reason_len = hyper_response_reason_phrase_len(resp);
-
-  result = status_line(data, data->conn,
-                       http_status, http_version, reasonp, reason_len);
-  if(!result) {
-    headers = hyper_response_headers(resp);
-    if(!headers) {
-      failf(data, "hyperstream: could not get 1xx response headers");
-      result = CURLE_RECV_ERROR;
-    }
-  }
-  data->state.hresult = result;
-
-  if(!result) {
-    /* the headers are already received */
-    hyper_headers_foreach(headers, hyper_each_header, data);
-    /* this callback also sets data->state.hresult on error */
-
-    if(empty_header(data))
-      result = CURLE_OUT_OF_MEMORY;
-  }
-
-  if(data->state.hresult)
-    infof(data, "ERROR in 1xx, bail out");
-}
-
-/*
- * Curl_http() gets called from the generic multi_do() function when an HTTP
- * request is to be performed. This creates and sends a properly constructed
- * HTTP request.
- */
-CURLcode Curl_http(struct Curl_easy *data, bool *done)
-{
-  struct connectdata *conn = data->conn;
-  struct hyptransfer *h = &data->hyp;
-  hyper_io *io = NULL;
-  hyper_clientconn_options *options = NULL;
-  hyper_task *task = NULL; /* for the handshake */
-  hyper_task *sendtask = NULL; /* for the send */
-  hyper_clientconn *client = NULL;
-  hyper_request *req = NULL;
-  hyper_headers *headers = NULL;
-  hyper_task *handshake = NULL;
-  CURLcode result;
-  const char *p_accept; /* Accept: string */
-  const char *method;
-  Curl_HttpReq httpreq;
-  const char *te = NULL; /* transfer-encoding */
-  hyper_code rc;
-
-  /* Always consider the DO phase done after this function call, even if there
-     may be parts of the request that is not yet sent, since we can deal with
-     the rest of the request in the PERFORM phase. */
-  *done = TRUE;
-  result = Curl_client_start(data);
-  if(result)
-    goto out;
-
-  /* Add collecting of headers written to client. For a new connection,
-   * we might have done that already, but reuse
-   * or multiplex needs it here as well. */
-  result = Curl_headers_init(data);
-  if(result)
-    goto out;
-
-  infof(data, "Time for the Hyper dance");
-  memset(h, 0, sizeof(struct hyptransfer));
-
-  result = Curl_http_host(data, conn);
-  if(result)
-    goto out;
-
-  Curl_http_method(data, conn, &method, &httpreq);
-
-  DEBUGASSERT(data->req.bytecount ==  0);
-
-  /* setup the authentication headers */
-  {
-    char *pq = NULL;
-    if(data->state.up.query) {
-      pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
-      if(!pq) {
-        result = CURLE_OUT_OF_MEMORY;
-        goto out;
-      }
-    }
-    result = Curl_http_output_auth(data, conn, method, httpreq,
-                                   (pq ? pq : data->state.up.path), FALSE);
-    free(pq);
-    if(result)
-      goto out;
-  }
-
-  result = Curl_http_req_set_reader(data, httpreq, &te);
-  if(result)
-    goto out;
-
-  result = Curl_http_range(data, httpreq);
-  if(result)
-    goto out;
-
-  result = Curl_http_useragent(data);
-  if(result)
-    goto out;
-
-  io = hyper_io_new();
-  if(!io) {
-    failf(data, "Couldn't create hyper IO");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-  /* tell Hyper how to read/write network data */
-  h->io_ctx.data = data;
-  h->io_ctx.sockindex = FIRSTSOCKET;
-  hyper_io_set_userdata(io, &h->io_ctx);
-  hyper_io_set_read(io, Curl_hyper_recv);
-  hyper_io_set_write(io, Curl_hyper_send);
-
-  /* create an executor to poll futures */
-  if(!h->exec) {
-    h->exec = hyper_executor_new();
-    if(!h->exec) {
-      failf(data, "Couldn't create hyper executor");
-      result = CURLE_OUT_OF_MEMORY;
-      goto out;
-    }
-  }
-
-  options = hyper_clientconn_options_new();
-  if(!options) {
-    failf(data, "Couldn't create hyper client options");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-  if(conn->alpn == CURL_HTTP_VERSION_2) {
-    failf(data, "ALPN protocol h2 not supported with Hyper");
-    result = CURLE_UNSUPPORTED_PROTOCOL;
-    goto out;
-  }
-  hyper_clientconn_options_set_preserve_header_case(options, 1);
-  hyper_clientconn_options_set_preserve_header_order(options, 1);
-  hyper_clientconn_options_http1_allow_multiline_headers(options, 1);
-
-  hyper_clientconn_options_exec(options, h->exec);
-
-  /* "Both the `io` and the `options` are consumed in this function call" */
-  handshake = hyper_clientconn_handshake(io, options);
-  if(!handshake) {
-    failf(data, "Couldn't create hyper client handshake");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-  io = NULL;
-  options = NULL;
-
-  if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
-    failf(data, "Couldn't hyper_executor_push the handshake");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-  handshake = NULL; /* ownership passed on */
-
-  task = hyper_executor_poll(h->exec);
-  if(!task) {
-    failf(data, "Couldn't hyper_executor_poll the handshake");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-
-  client = hyper_task_value(task);
-  hyper_task_free(task);
-
-  req = hyper_request_new();
-  if(!req) {
-    failf(data, "Couldn't hyper_request_new");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-
-  if(!Curl_use_http_1_1plus(data, conn)) {
-    if(HYPERE_OK != hyper_request_set_version(req,
-                                              HYPER_HTTP_VERSION_1_0)) {
-      failf(data, "error setting HTTP version");
-      result = CURLE_OUT_OF_MEMORY;
-      goto out;
-    }
-  }
-
-  if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
-    failf(data, "error setting method");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-
-  result = request_target(data, conn, method, req);
-  if(result)
-    goto out;
-
-  headers = hyper_request_headers(req);
-  if(!headers) {
-    failf(data, "hyper_request_headers");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-
-  rc = hyper_request_on_informational(req, http1xx_cb, data);
-  if(rc) {
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-
-  if(data->state.aptr.host) {
-    result = Curl_hyper_header(data, headers, data->state.aptr.host);
-    if(result)
-      goto out;
-  }
-
-#ifndef CURL_DISABLE_PROXY
-  if(data->state.aptr.proxyuserpwd) {
-    result = Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd);
-    if(result)
-      goto out;
-  }
-#endif
-
-  if(data->state.aptr.userpwd) {
-    result = Curl_hyper_header(data, headers, data->state.aptr.userpwd);
-    if(result)
-      goto out;
-  }
-
-  if((data->state.use_range && data->state.aptr.rangeline)) {
-    result = Curl_hyper_header(data, headers, data->state.aptr.rangeline);
-    if(result)
-      goto out;
-  }
-
-  if(data->set.str[STRING_USERAGENT] &&
-     *data->set.str[STRING_USERAGENT] &&
-     data->state.aptr.uagent) {
-    result = Curl_hyper_header(data, headers, data->state.aptr.uagent);
-    if(result)
-      goto out;
-  }
-
-  p_accept = Curl_checkheaders(data,
-                               STRCONST("Accept")) ? NULL : "Accept: */*\r\n";
-  if(p_accept) {
-    result = Curl_hyper_header(data, headers, p_accept);
-    if(result)
-      goto out;
-  }
-  if(te) {
-    result = Curl_hyper_header(data, headers, te);
-    if(result)
-      goto out;
-  }
-
-#ifndef CURL_DISABLE_ALTSVC
-  if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
-    char *altused = aprintf("Alt-Used: %s:%d\r\n",
-                            conn->conn_to_host.name, conn->conn_to_port);
-    if(!altused) {
-      result = CURLE_OUT_OF_MEMORY;
-      goto out;
-    }
-    result = Curl_hyper_header(data, headers, altused);
-    if(result)
-      goto out;
-    free(altused);
-  }
-#endif
-
-#ifndef CURL_DISABLE_PROXY
-  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
-     !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
-     !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
-    result = Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive");
-    if(result)
-      goto out;
-  }
-#endif
-
-  Curl_safefree(data->state.aptr.ref);
-  if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) {
-    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
-    if(!data->state.aptr.ref)
-      result = CURLE_OUT_OF_MEMORY;
-    else
-      result = Curl_hyper_header(data, headers, data->state.aptr.ref);
-    if(result)
-      goto out;
-  }
-
-#ifdef HAVE_LIBZ
-  /* we only consider transfer-encoding magic if libz support is built-in */
-  result = Curl_transferencode(data);
-  if(result)
-    goto out;
-  result = Curl_hyper_header(data, headers, data->state.aptr.te);
-  if(result)
-    goto out;
-#endif
-
-  if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
-     data->set.str[STRING_ENCODING]) {
-    Curl_safefree(data->state.aptr.accept_encoding);
-    data->state.aptr.accept_encoding =
-      aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
-    if(!data->state.aptr.accept_encoding)
-      result = CURLE_OUT_OF_MEMORY;
-    else
-      result = Curl_hyper_header(data, headers,
-                                 data->state.aptr.accept_encoding);
-    if(result)
-      goto out;
-  }
-  else
-    Curl_safefree(data->state.aptr.accept_encoding);
-
-  result = cookies(data, conn, headers);
-  if(result)
-    goto out;
-
-  if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS))
-    result = Curl_ws_request(data, headers);
-
-  result = Curl_add_timecondition(data, headers);
-  if(result)
-    goto out;
-
-  result = Curl_add_custom_headers(data, FALSE, headers);
-  if(result)
-    goto out;
-
-  result = finalize_request(data, headers, req, httpreq);
-  if(result)
-    goto out;
-
-  Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
-
-  if(data->req.upload_chunky && data->req.authneg) {
-    data->req.upload_chunky = TRUE;
-  }
-  else {
-    data->req.upload_chunky = FALSE;
-  }
-  sendtask = hyper_clientconn_send(client, req);
-  if(!sendtask) {
-    failf(data, "hyper_clientconn_send");
-    result = CURLE_OUT_OF_MEMORY;
-    goto out;
-  }
-  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 out;
-  }
-  sendtask = NULL; /* ownership passed on */
-
-  hyper_clientconn_free(client);
-  client = NULL;
-
-  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
-    /* HTTP GET/HEAD download */
-    Curl_pgrsSetUploadSize(data, 0); /* nothing */
-    result = Curl_req_set_upload_done(data);
-    if(result)
-      goto out;
-  }
-
-  Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE);
-  conn->datastream = Curl_hyper_stream;
-
-  /* clear userpwd and proxyuserpwd to avoid reusing old credentials
-   * from reused connections */
-  Curl_safefree(data->state.aptr.userpwd);
-#ifndef CURL_DISABLE_PROXY
-  Curl_safefree(data->state.aptr.proxyuserpwd);
-#endif
-
-out:
-  if(result) {
-    if(io)
-      hyper_io_free(io);
-    if(options)
-      hyper_clientconn_options_free(options);
-    if(handshake)
-      hyper_task_free(handshake);
-    if(client)
-      hyper_clientconn_free(client);
-    if(req)
-      hyper_request_free(req);
-  }
-  return result;
-}
-
-void Curl_hyper_done(struct Curl_easy *data)
-{
-  struct hyptransfer *h = &data->hyp;
-  if(h->exec) {
-    hyper_executor_free(h->exec);
-    h->exec = NULL;
-  }
-  if(h->read_waker) {
-    hyper_waker_free(h->read_waker);
-    h->read_waker = NULL;
-  }
-  if(h->write_waker) {
-    hyper_waker_free(h->write_waker);
-    h->write_waker = NULL;
-  }
-  if(h->send_body_waker) {
-    hyper_waker_free(h->send_body_waker);
-    h->send_body_waker = NULL;
-  }
-}
-
-static CURLcode cr_hyper_unpause(struct Curl_easy *data,
-                                 struct Curl_creader *reader)
-{
-  (void)reader;
-  if(data->hyp.send_body_waker) {
-    hyper_waker_wake(data->hyp.send_body_waker);
-    data->hyp.send_body_waker = NULL;
-  }
-  return CURLE_OK;
-}
-
-/* Hyper client reader, handling unpausing */
-static const struct Curl_crtype cr_hyper_protocol = {
-  "cr-hyper",
-  Curl_creader_def_init,
-  Curl_creader_def_read,
-  Curl_creader_def_close,
-  Curl_creader_def_needs_rewind,
-  Curl_creader_def_total_length,
-  Curl_creader_def_resume_from,
-  Curl_creader_def_rewind,
-  cr_hyper_unpause,
-  Curl_creader_def_is_paused,
-  Curl_creader_def_done,
-  sizeof(struct Curl_creader)
-};
-
-static CURLcode cr_hyper_add(struct Curl_easy *data)
-{
-  struct Curl_creader *reader = NULL;
-  CURLcode result;
-
-  result = Curl_creader_create(&reader, data, &cr_hyper_protocol,
-                               CURL_CR_PROTOCOL);
-  if(!result)
-    result = Curl_creader_add(data, reader);
-
-  if(result && reader)
-    Curl_creader_free(data, reader);
-  return result;
-}
-
-#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */

+ 0 - 63
lib/c-hyper.h

@@ -1,63 +0,0 @@
-#ifndef HEADER_CURL_HYPER_H
-#define HEADER_CURL_HYPER_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.haxx.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- * SPDX-License-Identifier: curl
- *
- ***************************************************************************/
-#include "curl_setup.h"
-
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
-
-#include <hyper.h>
-
-struct hyp_io_ctx {
-  struct Curl_easy *data;
-  int sockindex;
-};
-
-/* per-transfer data for the Hyper backend */
-struct hyptransfer {
-  hyper_waker *write_waker;
-  hyper_waker *read_waker;
-  const hyper_executor *exec;
-  hyper_waker *send_body_waker;
-  struct hyp_io_ctx io_ctx;
-};
-
-size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
-                       uint8_t *buf, size_t buflen);
-size_t Curl_hyper_send(void *userp, hyper_context *ctx,
-                       const uint8_t *buf, size_t buflen);
-CURLcode Curl_hyper_stream(struct Curl_easy *data,
-                           struct connectdata *conn,
-                           int *didwhat,
-                           int select_res);
-
-CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
-                           const char *line);
-void Curl_hyper_done(struct Curl_easy *);
-
-#else
-#define Curl_hyper_done(x)
-
-#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
-#endif /* HEADER_CURL_HYPER_H */

+ 1 - 339
lib/cf-h1-proxy.c

@@ -27,9 +27,6 @@
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 
 #include <curl/curl.h>
-#ifdef USE_HYPER
-#include <hyper.h>
-#endif
 #include "urldata.h"
 #include "dynbuf.h"
 #include "sendf.h"
@@ -184,9 +181,6 @@ static void h1_tunnel_go_state(struct Curl_cfilter *cf,
        make sure that it is not accidentally used for the document request
        after we have connected. So let's free and clear it here. */
     Curl_safefree(data->state.aptr.proxyuserpwd);
-#ifdef USE_HYPER
-    data->state.hconnect = FALSE;
-#endif
     break;
   }
 }
@@ -209,10 +203,9 @@ static void tunnel_free(struct Curl_cfilter *cf,
 
 static bool tunnel_want_send(struct h1_tunnel_state *ts)
 {
-  return (ts->tunnel_state == H1_TUNNEL_CONNECT);
+  return ts->tunnel_state == H1_TUNNEL_CONNECT;
 }
 
-#ifndef USE_HYPER
 static CURLcode start_CONNECT(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               struct h1_tunnel_state *ts)
@@ -529,337 +522,6 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
   return result;
 }
 
-#else /* USE_HYPER */
-
-static CURLcode CONNECT_host(struct Curl_cfilter *cf,
-                             struct Curl_easy *data,
-                             char **pauthority,
-                             char **phost_header)
-{
-  const char *hostname;
-  int port;
-  bool ipv6_ip;
-  CURLcode result;
-  char *authority; /* for CONNECT, the destination host + port */
-  char *host_header = NULL; /* Host: authority */
-
-  result = Curl_http_proxy_get_destination(cf, &hostname, &port, &ipv6_ip);
-  if(result)
-    return result;
-
-  authority = aprintf("%s%s%s:%d", ipv6_ip ? "[":"", hostname,
-                      ipv6_ip ? "]" : "", port);
-  if(!authority)
-    return CURLE_OUT_OF_MEMORY;
-
-  /* If user is not overriding the Host header later */
-  if(!Curl_checkProxyheaders(data, cf->conn, STRCONST("Host"))) {
-    host_header = aprintf("Host: %s\r\n", authority);
-    if(!host_header) {
-      free(authority);
-      return CURLE_OUT_OF_MEMORY;
-    }
-  }
-  *pauthority = authority;
-  *phost_header = host_header;
-  return CURLE_OK;
-}
-
-/* The Hyper version of CONNECT */
-static CURLcode start_CONNECT(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              struct h1_tunnel_state *ts)
-{
-  struct connectdata *conn = cf->conn;
-  struct hyptransfer *h = &data->hyp;
-  curl_socket_t tunnelsocket = Curl_conn_cf_get_socket(cf, data);
-  hyper_io *io = NULL;
-  hyper_request *req = NULL;
-  hyper_headers *headers = NULL;
-  hyper_clientconn_options *options = NULL;
-  hyper_task *handshake = NULL;
-  hyper_task *task = NULL; /* for the handshake */
-  hyper_clientconn *client = NULL;
-  hyper_task *sendtask = NULL; /* for the send */
-  char *authority = NULL; /* for CONNECT */
-  char *host_header = NULL; /* Host: */
-  CURLcode result = CURLE_OUT_OF_MEMORY;
-  (void)ts;
-
-  io = hyper_io_new();
-  if(!io) {
-    failf(data, "Couldn't create hyper IO");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-  /* tell Hyper how to read/write network data */
-  h->io_ctx.data = data;
-  h->io_ctx.sockindex = cf->sockindex;
-  hyper_io_set_userdata(io, &h->io_ctx);
-  hyper_io_set_read(io, Curl_hyper_recv);
-  hyper_io_set_write(io, Curl_hyper_send);
-  conn->sockfd = tunnelsocket;
-
-  data->state.hconnect = TRUE;
-
-  /* create an executor to poll futures */
-  if(!h->exec) {
-    h->exec = hyper_executor_new();
-    if(!h->exec) {
-      failf(data, "Couldn't create hyper executor");
-      result = CURLE_OUT_OF_MEMORY;
-      goto error;
-    }
-  }
-
-  options = hyper_clientconn_options_new();
-  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);
-
-  /* "Both the `io` and the `options` are consumed in this function
-     call" */
-  handshake = hyper_clientconn_handshake(io, options);
-  if(!handshake) {
-    failf(data, "Couldn't create hyper client handshake");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-  io = NULL;
-  options = NULL;
-
-  if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
-    failf(data, "Couldn't hyper_executor_push the handshake");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-  handshake = NULL; /* ownership passed on */
-
-  task = hyper_executor_poll(h->exec);
-  if(!task) {
-    failf(data, "Couldn't hyper_executor_poll the handshake");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-
-  client = hyper_task_value(task);
-  hyper_task_free(task);
-
-  req = hyper_request_new();
-  if(!req) {
-    failf(data, "Couldn't hyper_request_new");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-  if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
-                              strlen("CONNECT"))) {
-    failf(data, "error setting method");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-
-    /* This only happens if we have looped here due to authentication
-       reasons, and we do not really use the newly cloned URL here
-       then. Just free() it. */
-  Curl_safefree(data->req.newurl);
-
-  result = CONNECT_host(cf, data, &authority, &host_header);
-  if(result)
-    goto error;
-
-  infof(data, "Establish HTTP proxy tunnel to %s", authority);
-
-  if(hyper_request_set_uri(req, (uint8_t *)authority,
-                           strlen(authority))) {
-    failf(data, "error setting path");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-  if(data->set.verbose) {
-    char *se = aprintf("CONNECT %s HTTP/1.1\r\n", authority);
-    if(!se) {
-      result = CURLE_OUT_OF_MEMORY;
-      goto error;
-    }
-    Curl_debug(data, CURLINFO_HEADER_OUT, se, strlen(se));
-    free(se);
-  }
-  /* Setup the proxy-authorization header, if any */
-  result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
-                                 authority, TRUE);
-  if(result)
-    goto error;
-  Curl_safefree(authority);
-
-  /* default is 1.1 */
-  if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
-     (HYPERE_OK != hyper_request_set_version(req,
-                                             HYPER_HTTP_VERSION_1_0))) {
-    failf(data, "error setting HTTP version");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-
-  headers = hyper_request_headers(req);
-  if(!headers) {
-    failf(data, "hyper_request_headers");
-    result = CURLE_OUT_OF_MEMORY;
-    goto error;
-  }
-  if(host_header) {
-    result = Curl_hyper_header(data, headers, host_header);
-    if(result)
-      goto error;
-    Curl_safefree(host_header);
-  }
-
-  if(data->state.aptr.proxyuserpwd) {
-    result = Curl_hyper_header(data, headers,
-                               data->state.aptr.proxyuserpwd);
-    if(result)
-      goto error;
-  }
-
-  if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) &&
-     data->set.str[STRING_USERAGENT] && *data->set.str[STRING_USERAGENT]) {
-    struct dynbuf ua;
-    Curl_dyn_init(&ua, DYN_HTTP_REQUEST);
-    result = Curl_dyn_addf(&ua, "User-Agent: %s\r\n",
-                           data->set.str[STRING_USERAGENT]);
-    if(result)
-      goto error;
-    result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&ua));
-    if(result)
-      goto error;
-    Curl_dyn_free(&ua);
-  }
-
-  if(!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
-    result = Curl_hyper_header(data, headers,
-                               "Proxy-Connection: Keep-Alive");
-    if(result)
-      goto error;
-  }
-
-  result = Curl_add_custom_headers(data, TRUE, headers);
-  if(result)
-    goto error;
-
-  result = Curl_creader_set_null(data);
-  if(result)
-    goto error;
-
-  sendtask = hyper_clientconn_send(client, req);
-  if(!sendtask) {
-    failf(data, "hyper_clientconn_send");
-    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_header);
-  free(authority);
-  if(io)
-    hyper_io_free(io);
-  if(options)
-    hyper_clientconn_options_free(options);
-  if(handshake)
-    hyper_task_free(handshake);
-  if(client)
-    hyper_clientconn_free(client);
-  if(req)
-    hyper_request_free(req);
-
-  return result;
-}
-
-static CURLcode send_CONNECT(struct Curl_cfilter *cf,
-                             struct Curl_easy *data,
-                             struct h1_tunnel_state *ts,
-                             bool *done)
-{
-  struct hyptransfer *h = &data->hyp;
-  struct connectdata *conn = cf->conn;
-  hyper_task *task = NULL;
-  hyper_error *hypererr = NULL;
-  CURLcode result = CURLE_OK;
-
-  (void)ts;
-  (void)conn;
-  do {
-    task = hyper_executor_poll(h->exec);
-    if(task) {
-      bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
-      if(error)
-        hypererr = hyper_task_value(task);
-      hyper_task_free(task);
-      if(error) {
-        /* this could probably use a better error code? */
-        result = CURLE_OUT_OF_MEMORY;
-        goto error;
-      }
-    }
-  } while(task);
-error:
-  *done = (result == CURLE_OK);
-  if(hypererr) {
-    uint8_t errbuf[256];
-    size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
-    failf(data, "Hyper: %.*s", (int)errlen, errbuf);
-    hyper_error_free(hypererr);
-  }
-  return result;
-}
-
-static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
-                                  struct Curl_easy *data,
-                                  struct h1_tunnel_state *ts,
-                                  bool *done)
-{
-  struct hyptransfer *h = &data->hyp;
-  CURLcode result;
-  int didwhat;
-
-  (void)ts;
-  result = Curl_hyper_stream(data, cf->conn, &didwhat,
-                             CURL_CSELECT_IN | CURL_CSELECT_OUT);
-  *done = data->req.done;
-  if(result || !*done)
-    return result;
-  if(h->exec) {
-    hyper_executor_free(h->exec);
-    h->exec = NULL;
-  }
-  if(h->read_waker) {
-    hyper_waker_free(h->read_waker);
-    h->read_waker = NULL;
-  }
-  if(h->write_waker) {
-    hyper_waker_free(h->write_waker);
-    h->write_waker = NULL;
-  }
-  return result;
-}
-
-#endif /* USE_HYPER */
-
 static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            struct h1_tunnel_state *ts)

+ 2 - 0
lib/cf-h2-proxy.c

@@ -865,7 +865,9 @@ static int tunnel_recv_callback(nghttp2_session *session, uint8_t flags,
   if(nwritten < 0) {
     if(result != CURLE_AGAIN)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
+#ifdef DEBUGBUILD
     nwritten = 0;
+#endif
   }
   DEBUGASSERT((size_t)nwritten == len);
   return 0;

+ 232 - 117
lib/cf-https-connect.c

@@ -24,13 +24,14 @@
 
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
 
 #include "urldata.h"
 #include <curl/curl.h>
 #include "curl_trc.h"
 #include "cfilters.h"
 #include "connect.h"
+#include "hostip.h"
 #include "multiif.h"
 #include "cf-https-connect.h"
 #include "http2.h"
@@ -42,6 +43,10 @@
 #include "memdebug.h"
 
 
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
 typedef enum {
   CF_HC_INIT,
   CF_HC_CONNECT,
@@ -55,7 +60,7 @@ struct cf_hc_baller {
   CURLcode result;
   struct curltime started;
   int reply_ms;
-  BIT(enabled);
+  enum alpnid alpn_id;
   BIT(shutdown);
 };
 
@@ -73,7 +78,7 @@ static void cf_hc_baller_reset(struct cf_hc_baller *b,
 
 static bool cf_hc_baller_is_active(struct cf_hc_baller *b)
 {
-  return b->enabled && b->cf && !b->result;
+  return b->cf && !b->result;
 }
 
 static bool cf_hc_baller_has_started(struct cf_hc_baller *b)
@@ -84,7 +89,7 @@ static bool cf_hc_baller_has_started(struct cf_hc_baller *b)
 static int cf_hc_baller_reply_ms(struct cf_hc_baller *b,
                                  struct Curl_easy *data)
 {
-  if(b->reply_ms < 0)
+  if(b->cf && (b->reply_ms < 0))
     b->cf->cft->query(b->cf, data, CF_QUERY_CONNECT_REPLY_MS,
                       &b->reply_ms, NULL);
   return b->reply_ms;
@@ -116,26 +121,53 @@ struct cf_hc_ctx {
   const struct Curl_dns_entry *remotehost;
   struct curltime started;  /* when connect started */
   CURLcode result;          /* overall result */
-  struct cf_hc_baller h3_baller;
-  struct cf_hc_baller h21_baller;
+  struct cf_hc_baller ballers[2];
+  size_t baller_count;
   unsigned int soft_eyeballs_timeout_ms;
   unsigned int hard_eyeballs_timeout_ms;
 };
 
+static void cf_hc_baller_assign(struct cf_hc_baller *b,
+                                enum alpnid alpn_id)
+{
+  b->alpn_id = alpn_id;
+  switch(b->alpn_id) {
+  case ALPN_h3:
+    b->name = "h3";
+    break;
+  case ALPN_h2:
+    b->name = "h2";
+    break;
+  case ALPN_h1:
+    b->name = "h1";
+    break;
+  default:
+    b->result = CURLE_FAILED_INIT;
+    break;
+  }
+}
+
 static void cf_hc_baller_init(struct cf_hc_baller *b,
                               struct Curl_cfilter *cf,
                               struct Curl_easy *data,
-                              const char *name,
                               int transport)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct Curl_cfilter *save = cf->next;
 
-  b->name = name;
   cf->next = NULL;
   b->started = Curl_now();
-  b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost,
-                                         transport, CURL_CF_SSL_ENABLE);
+  switch(b->alpn_id) {
+  case ALPN_h3:
+    transport = TRNSPRT_QUIC;
+    break;
+  default:
+    break;
+  }
+
+  if(!b->result)
+    b->result = Curl_cf_setup_insert_after(cf, data, ctx->remotehost,
+                                           transport, CURL_CF_SSL_ENABLE);
   b->cf = cf->next;
   cf->next = save;
 }
@@ -157,10 +189,11 @@ static CURLcode cf_hc_baller_connect(struct cf_hc_baller *b,
 static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
   if(ctx) {
-    cf_hc_baller_reset(&ctx->h3_baller, data);
-    cf_hc_baller_reset(&ctx->h21_baller, data);
+    for(i = 0; i < ctx->baller_count; ++i)
+      cf_hc_baller_reset(&ctx->ballers[i], data);
     ctx->state = CF_HC_INIT;
     ctx->result = CURLE_OK;
     ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
@@ -175,12 +208,12 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
   struct cf_hc_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
   int reply_ms;
+  size_t i;
 
   DEBUGASSERT(winner->cf);
-  if(winner != &ctx->h3_baller)
-    cf_hc_baller_reset(&ctx->h3_baller, data);
-  if(winner != &ctx->h21_baller)
-    cf_hc_baller_reset(&ctx->h21_baller, data);
+  for(i = 0; i < ctx->baller_count; ++i)
+    if(winner != &ctx->ballers[i])
+      cf_hc_baller_reset(&ctx->ballers[i], data);
 
   reply_ms = cf_hc_baller_reply_ms(winner, data);
   if(reply_ms >= 0)
@@ -218,31 +251,40 @@ static CURLcode baller_connected(struct Curl_cfilter *cf,
 }
 
 
-static bool time_to_start_h21(struct Curl_cfilter *cf,
-                              struct Curl_easy *data,
-                              struct curltime now)
+static bool time_to_start_next(struct Curl_cfilter *cf,
+                               struct Curl_easy *data,
+                               size_t idx, struct curltime now)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   timediff_t elapsed_ms;
+  size_t i;
 
-  if(!ctx->h21_baller.enabled || cf_hc_baller_has_started(&ctx->h21_baller))
+  if(idx >= ctx->baller_count)
     return FALSE;
-
-  if(!ctx->h3_baller.enabled || !cf_hc_baller_is_active(&ctx->h3_baller))
+  if(cf_hc_baller_has_started(&ctx->ballers[idx]))
+    return FALSE;
+  for(i = 0; i < idx; i++) {
+    if(!ctx->ballers[i].result)
+      break;
+  }
+  if(i == idx) {
+    CURL_TRC_CF(data, cf, "all previous ballers have failed, time to start "
+                "baller %zu [%s]", idx, ctx->ballers[idx].name);
     return TRUE;
-
+  }
   elapsed_ms = Curl_timediff(now, ctx->started);
   if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
-    CURL_TRC_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 %s",
+                ctx->hard_eyeballs_timeout_ms, ctx->ballers[idx].name);
     return TRUE;
   }
 
-  if(elapsed_ms >= ctx->soft_eyeballs_timeout_ms) {
-    if(cf_hc_baller_reply_ms(&ctx->h3_baller, data) < 0) {
-      CURL_TRC_CF(data, cf, "soft timeout of %dms reached, h3 has not "
-                  "seen any data, starting h21",
-                  ctx->soft_eyeballs_timeout_ms);
+  if((idx > 0) && (elapsed_ms >= ctx->soft_eyeballs_timeout_ms)) {
+    if(cf_hc_baller_reply_ms(&ctx->ballers[idx - 1], data) < 0) {
+      CURL_TRC_CF(data, cf, "soft timeout of %dms reached, %s has not "
+                  "seen any data, starting %s",
+                  ctx->soft_eyeballs_timeout_ms,
+                  ctx->ballers[idx - 1].name, ctx->ballers[idx].name);
       return TRUE;
     }
     /* set the effective hard timeout again */
@@ -259,6 +301,7 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
   struct cf_hc_ctx *ctx = cf->ctx;
   struct curltime now;
   CURLcode result = CURLE_OK;
+  size_t i, failed_ballers;
 
   (void)blocking;
   if(cf->connected) {
@@ -270,51 +313,57 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
   now = Curl_now();
   switch(ctx->state) {
   case CF_HC_INIT:
-    DEBUGASSERT(!ctx->h3_baller.cf);
-    DEBUGASSERT(!ctx->h21_baller.cf);
     DEBUGASSERT(!cf->next);
+    for(i = 0; i < ctx->baller_count; i++)
+      DEBUGASSERT(!ctx->ballers[i].cf);
     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);
-      if(ctx->h21_baller.enabled)
-        Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
+    cf_hc_baller_init(&ctx->ballers[0], cf, data, cf->conn->transport);
+    if(ctx->baller_count > 1) {
+      Curl_expire(data, ctx->soft_eyeballs_timeout_ms, EXPIRE_ALPN_EYEBALLS);
+      CURL_TRC_CF(data, cf, "set expire for starting next baller in %ums",
+                  ctx->soft_eyeballs_timeout_ms);
     }
-    else if(ctx->h21_baller.enabled)
-      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
-                        cf->conn->transport);
     ctx->state = CF_HC_CONNECT;
     FALLTHROUGH();
 
   case CF_HC_CONNECT:
-    if(cf_hc_baller_is_active(&ctx->h3_baller)) {
-      result = cf_hc_baller_connect(&ctx->h3_baller, cf, data, done);
+    if(cf_hc_baller_is_active(&ctx->ballers[0])) {
+      result = cf_hc_baller_connect(&ctx->ballers[0], cf, data, done);
       if(!result && *done) {
-        result = baller_connected(cf, data, &ctx->h3_baller);
+        result = baller_connected(cf, data, &ctx->ballers[0]);
         goto out;
       }
     }
 
-    if(time_to_start_h21(cf, data, now)) {
-      cf_hc_baller_init(&ctx->h21_baller, cf, data, "h21",
-                        cf->conn->transport);
+    if(time_to_start_next(cf, data, 1, now)) {
+      cf_hc_baller_init(&ctx->ballers[1], cf, data, cf->conn->transport);
     }
 
-    if(cf_hc_baller_is_active(&ctx->h21_baller)) {
-      CURL_TRC_CF(data, cf, "connect, check h21");
-      result = cf_hc_baller_connect(&ctx->h21_baller, cf, data, done);
+    if((ctx->baller_count > 1) && cf_hc_baller_is_active(&ctx->ballers[1])) {
+      CURL_TRC_CF(data, cf, "connect, check %s", ctx->ballers[1].name);
+      result = cf_hc_baller_connect(&ctx->ballers[1], cf, data, done);
       if(!result && *done) {
-        result = baller_connected(cf, data, &ctx->h21_baller);
+        result = baller_connected(cf, data, &ctx->ballers[1]);
         goto out;
       }
     }
 
-    if((!ctx->h3_baller.enabled || ctx->h3_baller.result) &&
-       (!ctx->h21_baller.enabled || ctx->h21_baller.result)) {
-      /* both failed or disabled. we give up */
+    failed_ballers = 0;
+    for(i = 0; i < ctx->baller_count; i++) {
+      if(ctx->ballers[i].result)
+        ++failed_ballers;
+    }
+
+    if(failed_ballers == ctx->baller_count) {
+      /* all have failed. we give up */
       CURL_TRC_CF(data, cf, "connect, all failed");
-      result = ctx->result = ctx->h3_baller.enabled ?
-        ctx->h3_baller.result : ctx->h21_baller.result;
+      for(i = 0; i < ctx->baller_count; i++) {
+        if(ctx->ballers[i].result) {
+          result = ctx->ballers[i].result;
+          break;
+        }
+      }
       ctx->state = CF_HC_FAILURE;
       goto out;
     }
@@ -344,7 +393,6 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
                                struct Curl_easy *data, bool *done)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
-  struct cf_hc_baller *ballers[2];
   size_t i;
   CURLcode result = CURLE_OK;
 
@@ -356,10 +404,8 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
 
   /* shutdown all ballers that have not done so already. If one fails,
    * continue shutting down others until all are shutdown. */
-  ballers[0] = &ctx->h3_baller;
-  ballers[1] = &ctx->h21_baller;
-  for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
-    struct cf_hc_baller *b = ballers[i];
+  for(i = 0; i < ctx->baller_count; i++) {
+    struct cf_hc_baller *b = &ctx->ballers[i];
     bool bdone = FALSE;
     if(!cf_hc_baller_is_active(b) || b->shutdown)
       continue;
@@ -369,14 +415,14 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
   }
 
   *done = TRUE;
-  for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
-    if(ballers[i] && !ballers[i]->shutdown)
+  for(i = 0; i < ctx->baller_count; i++) {
+    if(!ctx->ballers[i].shutdown)
       *done = FALSE;
   }
   if(*done) {
-    for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
-      if(ballers[i] && ballers[i]->result)
-        result = ballers[i]->result;
+    for(i = 0; i < ctx->baller_count; i++) {
+      if(ctx->ballers[i].result)
+        result = ctx->ballers[i].result;
     }
   }
   CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done);
@@ -389,13 +435,10 @@ static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
 {
   if(!cf->connected) {
     struct cf_hc_ctx *ctx = cf->ctx;
-    struct cf_hc_baller *ballers[2];
     size_t i;
 
-    ballers[0] = &ctx->h3_baller;
-    ballers[1] = &ctx->h21_baller;
-    for(i = 0; i < sizeof(ballers)/sizeof(ballers[0]); i++) {
-      struct cf_hc_baller *b = ballers[i];
+    for(i = 0; i < ctx->baller_count; i++) {
+      struct cf_hc_baller *b = &ctx->ballers[i];
       if(!cf_hc_baller_is_active(b))
         continue;
       Curl_conn_cf_adjust_pollset(b->cf, data, ps);
@@ -408,13 +451,16 @@ static bool cf_hc_data_pending(struct Curl_cfilter *cf,
                                const struct Curl_easy *data)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
   if(cf->connected)
     return cf->next->cft->has_data_pending(cf->next, data);
 
   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);
+  for(i = 0; i < ctx->baller_count; i++)
+    if(cf_hc_baller_data_pending(&ctx->ballers[i], data))
+      return TRUE;
+  return FALSE;
 }
 
 static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
@@ -422,21 +468,17 @@ static struct curltime cf_get_max_baller_time(struct Curl_cfilter *cf,
                                               int query)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
-  struct Curl_cfilter *cfb;
   struct curltime t, tmax;
+  size_t i;
 
   memset(&tmax, 0, sizeof(tmax));
-  memset(&t, 0, sizeof(t));
-  cfb = ctx->h21_baller.enabled ? ctx->h21_baller.cf : NULL;
-  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
-    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
-      tmax = t;
-  }
-  memset(&t, 0, sizeof(t));
-  cfb = ctx->h3_baller.enabled ? ctx->h3_baller.cf : NULL;
-  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
-    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
-      tmax = t;
+  for(i = 0; i < ctx->baller_count; i++) {
+    struct Curl_cfilter *cfb = ctx->ballers[i].cf;
+    memset(&t, 0, sizeof(t));
+    if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
+      if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
+        tmax = t;
+    }
   }
   return tmax;
 }
@@ -446,6 +488,7 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
                             int query, int *pres1, void *pres2)
 {
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
   if(!cf->connected) {
     switch(query) {
@@ -460,11 +503,11 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
       return CURLE_OK;
     }
     case CF_QUERY_NEED_FLUSH: {
-      if(cf_hc_baller_needs_flush(&ctx->h3_baller, data)
-         || cf_hc_baller_needs_flush(&ctx->h21_baller, data)) {
-        *pres1 = TRUE;
-        return CURLE_OK;
-      }
+      for(i = 0; i < ctx->baller_count; i++)
+        if(cf_hc_baller_needs_flush(&ctx->ballers[i], data)) {
+          *pres1 = TRUE;
+          return CURLE_OK;
+        }
       break;
     }
     default:
@@ -482,14 +525,17 @@ static CURLcode cf_hc_cntrl(struct Curl_cfilter *cf,
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
+  size_t i;
 
   if(!cf->connected) {
-    result = cf_hc_baller_cntrl(&ctx->h3_baller, data, event, arg1, arg2);
-    if(!result || (result == CURLE_AGAIN))
-      result = cf_hc_baller_cntrl(&ctx->h21_baller, data, event, arg1, arg2);
-    if(result == CURLE_AGAIN)
-      result = CURLE_OK;
+    for(i = 0; i < ctx->baller_count; i++) {
+      result = cf_hc_baller_cntrl(&ctx->ballers[i], data, event, arg1, arg2);
+      if(result && (result != CURLE_AGAIN))
+        goto out;
+    }
+    result = CURLE_OK;
   }
+out:
   return result;
 }
 
@@ -537,23 +583,37 @@ struct Curl_cftype Curl_cft_http_connect = {
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
                              struct Curl_easy *data,
                              const struct Curl_dns_entry *remotehost,
-                             bool try_h3, bool try_h21)
+                             enum alpnid *alpnids, size_t alpn_count)
 {
   struct Curl_cfilter *cf = NULL;
   struct cf_hc_ctx *ctx;
   CURLcode result = CURLE_OK;
+  size_t i;
+
+  DEBUGASSERT(alpnids);
+  DEBUGASSERT(alpn_count);
+  DEBUGASSERT(alpn_count <= ARRAYSIZE(ctx->ballers));
+  if(!alpn_count || (alpn_count > ARRAYSIZE(ctx->ballers))) {
+    failf(data, "https-connect filter create with unsupported %zu ALPN ids",
+          alpn_count);
+    return CURLE_FAILED_INIT;
+  }
 
-  (void)data;
   ctx = calloc(1, sizeof(*ctx));
   if(!ctx) {
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
   ctx->remotehost = remotehost;
-  ctx->h3_baller.enabled = try_h3;
-  ctx->h21_baller.enabled = try_h21;
+  for(i = 0; i < alpn_count; ++i)
+    cf_hc_baller_assign(&ctx->ballers[i], alpnids[i]);
+  for(; i < ARRAYSIZE(ctx->ballers); ++i)
+    ctx->ballers[i].alpn_id = ALPN_none;
+  ctx->baller_count = alpn_count;
 
   result = Curl_cf_create(&cf, &Curl_cft_http_connect, ctx);
+  CURL_TRC_CF(data, cf, "created with %zu ALPNs -> %d",
+              ctx->baller_count, result);
   if(result)
     goto out;
   ctx = NULL;
@@ -569,13 +629,13 @@ static CURLcode cf_http_connect_add(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     int sockindex,
                                     const struct Curl_dns_entry *remotehost,
-                                    bool try_h3, bool try_h21)
+                                    enum alpnid *alpn_ids, size_t alpn_count)
 {
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(data);
-  result = cf_hc_create(&cf, data, remotehost, try_h3, try_h21);
+  result = cf_hc_create(&cf, data, remotehost, alpn_ids, alpn_count);
   if(result)
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -588,33 +648,88 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              int sockindex,
                              const struct Curl_dns_entry *remotehost)
 {
-  bool try_h3 = FALSE, try_h21 = TRUE; /* defaults, for now */
+  enum alpnid alpn_ids[2];
+  size_t alpn_count = 0;
   CURLcode result = CURLE_OK;
 
   (void)sockindex;
   (void)remotehost;
 
-  if(!conn->bits.tls_enable_alpn)
-    goto out;
-
-  if(data->state.httpwant == CURL_HTTP_VERSION_3ONLY) {
-    result = Curl_conn_may_http3(data, conn);
-    if(result) /* cannot do it */
-      goto out;
-    try_h3 = TRUE;
-    try_h21 = FALSE;
+  if(conn->bits.tls_enable_alpn) {
+    switch(data->state.httpwant) {
+    case CURL_HTTP_VERSION_NONE:
+      /* No preferences by transfer setup. Choose best defaults */
+#ifdef USE_HTTPSRR
+      if(conn->dns_entry && conn->dns_entry->hinfo &&
+         !conn->dns_entry->hinfo->no_def_alpn) {
+        size_t i, j;
+        for(i = 0; i < ARRAYSIZE(conn->dns_entry->hinfo->alpns) &&
+                   alpn_count < ARRAYSIZE(alpn_ids); ++i) {
+          bool present = FALSE;
+          enum alpnid alpn = conn->dns_entry->hinfo->alpns[i];
+          for(j = 0; j < alpn_count; ++j) {
+            if(alpn == alpn_ids[j]) {
+              present = TRUE;
+              break;
+            }
+          }
+          if(!present) {
+            switch(alpn) {
+            case ALPN_h3:
+              if(Curl_conn_may_http3(data, conn))
+                break;  /* not possible */
+              FALLTHROUGH();
+            case ALPN_h2:
+            case ALPN_h1:
+              alpn_ids[alpn_count++] = alpn;
+              break;
+            default: /* ignore */
+              break;
+            }
+          }
+        }
+      }
+#endif
+      if(!alpn_count)
+        alpn_ids[alpn_count++] = ALPN_h2;
+      break;
+    case CURL_HTTP_VERSION_3ONLY:
+      result = Curl_conn_may_http3(data, conn);
+      if(result) /* cannot do it */
+        goto out;
+      alpn_ids[alpn_count++] = ALPN_h3;
+      break;
+    case CURL_HTTP_VERSION_3:
+      /* We assume that silently not even trying H3 is ok here */
+      /* TODO: should we fail instead? */
+      if(Curl_conn_may_http3(data, conn) == CURLE_OK)
+        alpn_ids[alpn_count++] = ALPN_h3;
+      alpn_ids[alpn_count++] = ALPN_h2;
+      break;
+    case CURL_HTTP_VERSION_2_0:
+    case CURL_HTTP_VERSION_2TLS:
+    case CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE:
+      alpn_ids[alpn_count++] = ALPN_h2;
+      break;
+    case CURL_HTTP_VERSION_1_0:
+    case CURL_HTTP_VERSION_1_1:
+      alpn_ids[alpn_count++] = ALPN_h1;
+      break;
+    default:
+      alpn_ids[alpn_count++] = ALPN_h2;
+      break;
+    }
   }
-  else if(data->state.httpwant >= CURL_HTTP_VERSION_3) {
-    /* We assume that silently not even trying H3 is ok here */
-    /* TODO: should we fail instead? */
-    try_h3 = (Curl_conn_may_http3(data, conn) == CURLE_OK);
-    try_h21 = TRUE;
+
+  /* If we identified ALPNs to use, install our filter. Otherwise,
+   * install nothing, so our call will use a default connect setup. */
+  if(alpn_count) {
+    result = cf_http_connect_add(data, conn, sockindex, remotehost,
+                                 alpn_ids, alpn_count);
   }
 
-  result = cf_http_connect_add(data, conn, sockindex, remotehost,
-                               try_h3, try_h21);
 out:
   return result;
 }
 
-#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */
+#endif /* !defined(CURL_DISABLE_HTTP) */

+ 2 - 2
lib/cf-https-connect.h

@@ -25,7 +25,7 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
 
 struct Curl_cfilter;
 struct Curl_easy;
@@ -54,5 +54,5 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              const struct Curl_dns_entry *remotehost);
 
 
-#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */
+#endif /* !defined(CURL_DISABLE_HTTP) */
 #endif /* HEADER_CURL_CF_HTTP_H */

+ 41 - 16
lib/cf-socket.c

@@ -306,9 +306,9 @@ tcpkeepalive(struct Curl_easy *data,
  * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
  * set the transport used.
  */
-void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
-                           const struct Curl_addrinfo *ai,
-                           int transport)
+CURLcode Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
+                               const struct Curl_addrinfo *ai,
+                               int transport)
 {
   /*
    * The Curl_sockaddr_ex structure is basically libcurl's external API
@@ -334,9 +334,13 @@ void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
   }
   dest->addrlen = (unsigned int)ai->ai_addrlen;
 
-  if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
-    dest->addrlen = sizeof(struct Curl_sockaddr_storage);
+  if(dest->addrlen > sizeof(struct Curl_sockaddr_storage)) {
+    DEBUGASSERT(0);
+    return CURLE_TOO_LARGE;
+  }
+
   memcpy(&dest->curl_sa_addr, ai->ai_addr, dest->addrlen);
+  return CURLE_OK;
 }
 
 static CURLcode socket_open(struct Curl_easy *data,
@@ -395,12 +399,16 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
                             curl_socket_t *sockfd)
 {
   struct Curl_sockaddr_ex dummy;
+  CURLcode result;
 
   if(!addr)
     /* if the caller does not want info back, use a local temp copy */
     addr = &dummy;
 
-  Curl_sock_assign_addr(addr, ai, transport);
+  result = Curl_sock_assign_addr(addr, ai, transport);
+  if(result)
+    return result;
+
   return socket_open(data, addr, sockfd);
 }
 
@@ -959,14 +967,20 @@ struct cf_socket_ctx {
   BIT(active);
 };
 
-static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
-                               const struct Curl_addrinfo *ai,
-                               int transport)
+static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx,
+                                   const struct Curl_addrinfo *ai,
+                                   int transport)
 {
+  CURLcode result;
+
   memset(ctx, 0, sizeof(*ctx));
   ctx->sock = CURL_SOCKET_BAD;
   ctx->transport = transport;
-  Curl_sock_assign_addr(&ctx->addr, ai, transport);
+
+  result = Curl_sock_assign_addr(&ctx->addr, ai, transport);
+  if(result)
+    return result;
+
 #ifdef DEBUGBUILD
   {
     char *p = getenv("CURL_DBG_SOCK_WBLOCK");
@@ -995,6 +1009,8 @@ static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
     }
   }
 #endif
+
+  return result;
 }
 
 static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
@@ -1282,7 +1298,7 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
 
     rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
 #elif defined(MSG_FASTOPEN) /* old Linux */
-    if(cf->conn->given->flags & PROTOPT_SSL)
+    if(Curl_conn_is_ssl(cf->conn, cf->sockindex))
       rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
     else
       rc = 0; /* Do nothing */
@@ -1443,7 +1459,7 @@ static bool cf_socket_data_pending(struct Curl_cfilter *cf,
 
   (void)data;
   readable = SOCKET_READABLE(ctx->sock, 0);
-  return (readable > 0 && (readable & CURL_CSELECT_IN));
+  return readable > 0 && (readable & CURL_CSELECT_IN);
 }
 
 #ifdef USE_WINSOCK
@@ -1805,7 +1821,10 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
-  cf_socket_ctx_init(ctx, ai, transport);
+
+  result = cf_socket_ctx_init(ctx, ai, transport);
+  if(result)
+    goto out;
 
   result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
 
@@ -1831,7 +1850,7 @@ static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
   /* QUIC needs a connected socket, nonblocking */
   DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
 
-  rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
+  rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,  /* NOLINT FIXME */
                (curl_socklen_t)ctx->addr.addrlen);
   if(-1 == rc) {
     return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
@@ -1954,7 +1973,10 @@ CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
-  cf_socket_ctx_init(ctx, ai, transport);
+
+  result = cf_socket_ctx_init(ctx, ai, transport);
+  if(result)
+    goto out;
 
   result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
 
@@ -2006,7 +2028,10 @@ CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
     result = CURLE_OUT_OF_MEMORY;
     goto out;
   }
-  cf_socket_ctx_init(ctx, ai, transport);
+
+  result = cf_socket_ctx_init(ctx, ai, transport);
+  if(result)
+    goto out;
 
   result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
 

+ 3 - 3
lib/cf-socket.h

@@ -95,9 +95,9 @@ void Curl_sndbuf_init(curl_socket_t sockfd);
  * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
  * set the transport used.
  */
-void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
-                           const struct Curl_addrinfo *ai,
-                           int transport);
+CURLcode Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
+                               const struct Curl_addrinfo *ai,
+                               int transport);
 
 /**
  * Creates a cfilter that opens a TCP socket to the given address

+ 24 - 14
lib/cfilters.c

@@ -494,13 +494,35 @@ bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
   for(; cf; cf = cf->next) {
     if(cf->cft->flags & CF_TYPE_MULTIPLEX)
       return TRUE;
-    if(cf->cft->flags & CF_TYPE_IP_CONNECT
-       || cf->cft->flags & CF_TYPE_SSL)
+    if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL))
       return FALSE;
   }
   return FALSE;
 }
 
+unsigned char Curl_conn_http_version(struct Curl_easy *data)
+{
+  struct Curl_cfilter *cf;
+  CURLcode result = CURLE_UNKNOWN_OPTION;
+  unsigned char v = 0;
+
+  cf = data->conn ? data->conn->cfilter[FIRSTSOCKET] : NULL;
+  for(; cf; cf = cf->next) {
+    if(cf->cft->flags & CF_TYPE_HTTP) {
+      int value = 0;
+      result = cf->cft->query(cf, data, CF_QUERY_HTTP_VERSION, &value, NULL);
+      if(!result && ((value < 0) || (value > 255)))
+        result = CURLE_FAILED_INIT;
+      else
+        v = (unsigned char)value;
+      break;
+    }
+    if(cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_SSL))
+      break;
+  }
+  return (unsigned char)(result ? 0 : v);
+}
+
 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
 {
   struct Curl_cfilter *cf;
@@ -711,18 +733,6 @@ static CURLcode cf_cntrl_all(struct connectdata *conn,
   return result;
 }
 
-void Curl_conn_ev_data_attach(struct connectdata *conn,
-                              struct Curl_easy *data)
-{
-  cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
-}
-
-void Curl_conn_ev_data_detach(struct connectdata *conn,
-                              struct Curl_easy *data)
-{
-  cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
-}
-
 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
 {
   return cf_cntrl_all(data->conn, data, FALSE,

+ 9 - 20
lib/cfilters.h

@@ -132,8 +132,6 @@ typedef CURLcode Curl_cft_conn_keep_alive(struct Curl_cfilter *cf,
  *           to all filters in the chain. Overall result is always CURLE_OK.
  */
 /*      data event                          arg1       arg2     return */
-#define CF_CTRL_DATA_ATTACH           1  /* 0          NULL     ignored */
-#define CF_CTRL_DATA_DETACH           2  /* 0          NULL     ignored */
 #define CF_CTRL_DATA_SETUP            4  /* 0          NULL     first fail */
 #define CF_CTRL_DATA_IDLE             5  /* 0          NULL     first fail */
 #define CF_CTRL_DATA_PAUSE            6  /* on/off     NULL     first fail */
@@ -178,6 +176,7 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf,
 #define CF_QUERY_STREAM_ERROR       6  /* error code - */
 #define CF_QUERY_NEED_FLUSH         7  /* TRUE/FALSE - */
 #define CF_QUERY_IP_INFO            8  /* TRUE/FALSE struct ip_quadruple */
+#define CF_QUERY_HTTP_VERSION       9  /* number (10/11/20/30)   -  */
 
 /**
  * Query the cfilter for properties. Filters ignorant of a query will
@@ -197,11 +196,13 @@ typedef CURLcode Curl_cft_query(struct Curl_cfilter *cf,
  * CF_TYPE_SSL:        provide SSL/TLS
  * CF_TYPE_MULTIPLEX:  provides multiplexing of easy handles
  * CF_TYPE_PROXY       provides proxying
+ * CF_TYPE_HTTP        implement a version of the HTTP protocol
  */
 #define CF_TYPE_IP_CONNECT  (1 << 0)
 #define CF_TYPE_SSL         (1 << 1)
 #define CF_TYPE_MULTIPLEX   (1 << 2)
 #define CF_TYPE_PROXY       (1 << 3)
+#define CF_TYPE_HTTP        (1 << 4)
 
 /* A connection filter type, e.g. specific implementation. */
 struct Curl_cftype {
@@ -394,6 +395,12 @@ bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex);
  */
 bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex);
 
+/**
+ * Return the HTTP version used on the FIRSTSOCKET connection filters
+ * or 0 if unknown. Value otherwise is 09, 10, 11, etc.
+ */
+unsigned char Curl_conn_http_version(struct Curl_easy *data);
+
 /**
  * Close the filter chain at `sockindex` for connection `data->conn`.
   * Filters remain in place and may be connected again afterwards.
@@ -476,24 +483,6 @@ ssize_t Curl_cf_recv(struct Curl_easy *data, int sockindex, char *buf,
 ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
                      const void *buf, size_t len, bool eos, CURLcode *code);
 
-/**
- * The easy handle `data` is being attached to `conn`. This does
- * not mean that data will actually do a transfer. Attachment is
- * also used for temporary actions on the connection.
- */
-void Curl_conn_ev_data_attach(struct connectdata *conn,
-                              struct Curl_easy *data);
-
-/**
- * The easy handle `data` is being detached (no longer served)
- * by connection `conn`. All filters are informed to release any resources
- * related to `data`.
- * Note: there may be several `data` attached to a connection at the same
- * time.
- */
-void Curl_conn_ev_data_detach(struct connectdata *conn,
-                              struct Curl_easy *data);
-
 /**
  * Notify connection filters that they need to setup data for
  * a transfer.

+ 90 - 20
lib/conncache.c

@@ -100,6 +100,8 @@ static void cpool_shutdown_all(struct cpool *cpool,
                                struct Curl_easy *data, int timeout_ms);
 static void cpool_close_and_destroy_all(struct cpool *cpool);
 static struct connectdata *cpool_get_oldest_idle(struct cpool *cpool);
+static size_t cpool_shutdown_dest_count(struct cpool *cpool,
+                                        const char *destination);
 
 static struct cpool_bundle *cpool_bundle_create(const char *dest,
                                                 size_t dest_len)
@@ -285,6 +287,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
   struct cpool_bundle *bundle;
   size_t dest_limit = 0;
   size_t total_limit = 0;
+  size_t shutdowns;
   int result = CPOOL_LIMIT_OK;
 
   if(!cpool)
@@ -300,8 +303,12 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
 
   CPOOL_LOCK(cpool);
   if(dest_limit) {
+    size_t live;
+
     bundle = cpool_find_bundle(cpool, conn);
-    while(bundle && (Curl_llist_count(&bundle->conns) >= dest_limit)) {
+    live = bundle ? Curl_llist_count(&bundle->conns) : 0;
+    shutdowns = cpool_shutdown_dest_count(cpool, conn->destination);
+    while(!shutdowns && bundle && live >= dest_limit) {
       struct connectdata *oldest_idle = NULL;
       /* The bundle is full. Extract the oldest connection that may
        * be removed now, if there is one. */
@@ -317,15 +324,18 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
 
       /* in case the bundle was destroyed in disconnect, look it up again */
       bundle = cpool_find_bundle(cpool, conn);
+      live = bundle ? Curl_llist_count(&bundle->conns) : 0;
+      shutdowns = cpool_shutdown_dest_count(cpool, conn->destination);
     }
-    if(bundle && (Curl_llist_count(&bundle->conns) >= dest_limit)) {
+    if((live + shutdowns) >= dest_limit) {
       result = CPOOL_LIMIT_DEST;
       goto out;
     }
   }
 
   if(total_limit) {
-    while(cpool->num_conn >= total_limit) {
+    shutdowns = Curl_llist_count(&cpool->shutdowns);
+    while((cpool->num_conn + shutdowns) >= total_limit) {
       struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool);
       if(!oldest_idle)
         break;
@@ -335,8 +345,9 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
                    "limit of %zu",
                    oldest_idle->connection_id, cpool->num_conn, total_limit));
       Curl_cpool_disconnect(data, oldest_idle, FALSE);
+      shutdowns = Curl_llist_count(&cpool->shutdowns);
     }
-    if(cpool->num_conn >= total_limit) {
+    if((cpool->num_conn + shutdowns) >= total_limit) {
       result = CPOOL_LIMIT_TOTAL;
       goto out;
     }
@@ -374,7 +385,8 @@ CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
   cpool->num_conn++;
   DEBUGF(infof(data, "Added connection %" FMT_OFF_T ". "
                "The cache now contains %zu members",
-               conn->connection_id, cpool->num_conn));
+               conn->connection_id,
+               cpool->num_conn + Curl_llist_count(&cpool->shutdowns)));
 out:
   CPOOL_UNLOCK(cpool);
 
@@ -612,6 +624,21 @@ bool Curl_cpool_find(struct Curl_easy *data,
   return result;
 }
 
+/* How many connections to the given destination are in shutdown? */
+static size_t cpool_shutdown_dest_count(struct cpool *cpool,
+                                        const char *destination)
+{
+  size_t n = 0;
+  struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
+  while(e) {
+    struct connectdata *conn = Curl_node_elem(e);
+    if(!strcmp(destination, conn->destination))
+      ++n;
+    e = Curl_node_next(e);
+  }
+  return n;
+}
+
 static void cpool_shutdown_discard_all(struct cpool *cpool)
 {
   struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
@@ -742,12 +769,12 @@ static void cpool_discard_conn(struct cpool *cpool,
 
   /* Add the connection to our shutdown list for non-blocking shutdown
    * during multi processing. */
-  if(data->multi && data->multi->max_shutdown_connections > 0 &&
-     (data->multi->max_shutdown_connections >=
-      (long)Curl_llist_count(&cpool->shutdowns))) {
+  if(data->multi && data->multi->max_total_connections > 0 &&
+     (data->multi->max_total_connections <=
+      (long)(cpool->num_conn + Curl_llist_count(&cpool->shutdowns)))) {
     DEBUGF(infof(data, "[CCACHE] discarding oldest shutdown connection "
-                       "due to limit of %ld",
-                       data->multi->max_shutdown_connections));
+                       "due to connection limit of %ld",
+                       data->multi->max_total_connections));
     cpool_shutdown_destroy_oldest(cpool);
   }
 
@@ -767,8 +794,8 @@ static void cpool_discard_conn(struct cpool *cpool,
 
   Curl_llist_append(&cpool->shutdowns, conn, &conn->cpool_node);
   DEBUGF(infof(data, "[CCACHE] added #%" FMT_OFF_T
-               " to shutdown list of length %zu", conn->connection_id,
-               Curl_llist_count(&cpool->shutdowns)));
+               " to shutdowns, now %zu conns in shutdown",
+               conn->connection_id, Curl_llist_count(&cpool->shutdowns)));
 }
 
 void Curl_cpool_disconnect(struct Curl_easy *data,
@@ -926,10 +953,11 @@ CURLcode Curl_cpool_add_pollfds(struct cpool *cpool,
   return result;
 }
 
-CURLcode Curl_cpool_add_waitfds(struct cpool *cpool,
-                                struct curl_waitfds *cwfds)
+/* return information about the shutdown connections */
+unsigned int Curl_cpool_add_waitfds(struct cpool *cpool,
+                                    struct Curl_waitfds *cwfds)
 {
-  CURLcode result = CURLE_OK;
+  unsigned int need = 0;
 
   CPOOL_LOCK(cpool);
   if(Curl_llist_head(&cpool->shutdowns)) {
@@ -945,14 +973,51 @@ CURLcode Curl_cpool_add_waitfds(struct cpool *cpool,
       Curl_conn_adjust_pollset(cpool->idata, &ps);
       Curl_detach_connection(cpool->idata);
 
-      result = Curl_waitfds_add_ps(cwfds, &ps);
-      if(result)
-        goto out;
+      need += Curl_waitfds_add_ps(cwfds, &ps);
+    }
+  }
+  CPOOL_UNLOCK(cpool);
+  return need;
+}
+
+/* return fd_set info about the shutdown connections */
+void Curl_cpool_setfds(struct cpool *cpool,
+                       fd_set *read_fd_set, fd_set *write_fd_set,
+                       int *maxfd)
+{
+  CPOOL_LOCK(cpool);
+  if(Curl_llist_head(&cpool->shutdowns)) {
+    struct Curl_llist_node *e;
+
+    for(e = Curl_llist_head(&cpool->shutdowns); e;
+        e = Curl_node_next(e)) {
+      struct easy_pollset ps;
+      unsigned int i;
+      struct connectdata *conn = Curl_node_elem(e);
+      memset(&ps, 0, sizeof(ps));
+      Curl_attach_connection(cpool->idata, conn);
+      Curl_conn_adjust_pollset(cpool->idata, &ps);
+      Curl_detach_connection(cpool->idata);
+
+      for(i = 0; i < ps.num; i++) {
+#if defined(__DJGPP__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Warith-conversion"
+#endif
+        if(ps.actions[i] & CURL_POLL_IN)
+          FD_SET(ps.sockets[i], read_fd_set);
+        if(ps.actions[i] & CURL_POLL_OUT)
+          FD_SET(ps.sockets[i], write_fd_set);
+#if defined(__DJGPP__)
+#pragma GCC diagnostic pop
+#endif
+        if((ps.actions[i] & (CURL_POLL_OUT | CURL_POLL_IN)) &&
+           ((int)ps.sockets[i] > *maxfd))
+          *maxfd = (int)ps.sockets[i];
+      }
     }
   }
-out:
   CPOOL_UNLOCK(cpool);
-  return result;
 }
 
 static void cpool_perform(struct cpool *cpool)
@@ -1052,6 +1117,11 @@ static void cpool_close_and_destroy(struct cpool *cpool,
   Curl_detach_connection(data);
 
   Curl_conn_free(data, conn);
+
+  if(cpool && cpool->multi) {
+    DEBUGF(infof(data, "[CCACHE] trigger multi connchanged"));
+    Curl_multi_connchanged(cpool->multi);
+  }
 }
 
 

+ 7 - 5
lib/conncache.h

@@ -31,7 +31,7 @@
 struct connectdata;
 struct Curl_easy;
 struct curl_pollfds;
-struct curl_waitfds;
+struct Curl_waitfds;
 struct Curl_multi;
 struct Curl_share;
 
@@ -113,8 +113,6 @@ typedef bool Curl_cpool_done_match_cb(bool result, void *userdata);
  * @param dest_len    destination length, including terminating NUL
  * @param conn_cb     must be present, called for each connection in the
  *                    bundle until it returns TRUE
- * @param result_cb   if not NULL, is called at the end with the result
- *                    of the `conn_cb` or FALSE if never called.
  * @return combined result of last conn_db and result_cb or FALSE if no
                       connections were present.
  */
@@ -185,8 +183,12 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
  */
 CURLcode Curl_cpool_add_pollfds(struct cpool *connc,
                                 struct curl_pollfds *cpfds);
-CURLcode Curl_cpool_add_waitfds(struct cpool *connc,
-                                struct curl_waitfds *cwfds);
+unsigned int Curl_cpool_add_waitfds(struct cpool *connc,
+                                    struct Curl_waitfds *cwfds);
+
+void Curl_cpool_setfds(struct cpool *cpool,
+                       fd_set *read_fd_set, fd_set *write_fd_set,
+                       int *maxfd);
 
 /**
  * Perform maintenance on connections in the pool. Specifically,

+ 24 - 2
lib/connect.c

@@ -78,6 +78,7 @@
 #include "vquic/vquic.h" /* for quic cfilters */
 #include "http_proxy.h"
 #include "socks.h"
+#include "strcase.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -88,6 +89,27 @@
 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
 #endif
 
+#if !defined(CURL_DISABLE_ALTSVC) || defined(USE_HTTPSRR)
+
+enum alpnid Curl_alpn2alpnid(char *name, size_t len)
+{
+  if(len == 2) {
+    if(strncasecompare(name, "h1", 2))
+      return ALPN_h1;
+    if(strncasecompare(name, "h2", 2))
+      return ALPN_h2;
+    if(strncasecompare(name, "h3", 2))
+      return ALPN_h3;
+  }
+  else if(len == 8) {
+    if(strncasecompare(name, "http/1.1", 8))
+      return ALPN_h1;
+  }
+  return ALPN_none; /* unknown, probably rubbish input */
+}
+
+#endif
+
 /*
  * Curl_timeleft() returns the amount of milliseconds left allowed for the
  * transfer/connection. If the value is 0, there is no timeout (ie there is
@@ -1485,7 +1507,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
   DEBUGASSERT(data);
   DEBUGASSERT(conn->handler);
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
   if(!conn->cfilter[sockindex] &&
      conn->handler->protocol == CURLPROTO_HTTPS) {
     DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
@@ -1493,7 +1515,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
     if(result)
       goto out;
   }
-#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */
+#endif /* !defined(CURL_DISABLE_HTTP) */
 
   /* Still no cfilter set, apply default. */
   if(!conn->cfilter[sockindex]) {

+ 2 - 0
lib/connect.h

@@ -32,6 +32,8 @@
 struct Curl_dns_entry;
 struct ip_quadruple;
 
+enum alpnid Curl_alpn2alpnid(char *name, size_t len);
+
 /* generic function that returns how much time there is left to run, according
    to the timeouts set */
 timediff_t Curl_timeleft(struct Curl_easy *data,

+ 61 - 289
lib/content_encoding.c

@@ -65,34 +65,15 @@
 
 /* allow no more than 5 "chained" compression steps */
 #define MAX_ENCODE_STACK 5
-
-#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
-
+#define DECOMPRESS_BUFFER_SIZE 16384 /* buffer size for decompressed data */
 
 #ifdef HAVE_LIBZ
 
-/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
-   (doing so will reduce code size slightly). */
-#define OLD_ZLIB_SUPPORT 1
-
-#define GZIP_MAGIC_0 0x1f
-#define GZIP_MAGIC_1 0x8b
-
-/* gzip flag byte */
-#define ASCII_FLAG   0x01 /* bit 0 set: file probably ASCII text */
-#define HEAD_CRC     0x02 /* bit 1 set: header CRC present */
-#define EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define ORIG_NAME    0x08 /* bit 3 set: original filename present */
-#define COMMENT      0x10 /* bit 4 set: file comment present */
-#define RESERVED     0xE0 /* bits 5..7: reserved */
-
 typedef enum {
   ZLIB_UNINIT,               /* uninitialized */
   ZLIB_INIT,                 /* initialized */
   ZLIB_INFLATING,            /* inflating started. */
   ZLIB_EXTERNAL_TRAILER,     /* reading external trailer */
-  ZLIB_GZIP_HEADER,          /* reading gzip header */
-  ZLIB_GZIP_INFLATING,       /* inflating gzip stream */
   ZLIB_INIT_GZIP             /* initialized in transparent gzip mode */
 } zlibInitState;
 
@@ -100,6 +81,7 @@ typedef enum {
 struct zlib_writer {
   struct Curl_cwriter super;
   zlibInitState zlib_init;   /* zlib init state */
+  char buffer[DECOMPRESS_BUFFER_SIZE]; /* Put the decompressed data here. */
   uInt trailerlen;           /* Remaining trailer byte count. */
   z_stream z;                /* State structure for zlib. */
 };
@@ -137,9 +119,6 @@ static CURLcode
 exit_zlib(struct Curl_easy *data,
           z_stream *z, zlibInitState *zlib_init, CURLcode result)
 {
-  if(*zlib_init == ZLIB_GZIP_HEADER)
-    Curl_safefree(z->next_in);
-
   if(*zlib_init != ZLIB_UNINIT) {
     if(inflateEnd(z) != Z_OK && result == CURLE_OK)
       result = process_zlib_error(data, z);
@@ -183,21 +162,13 @@ static CURLcode inflate_stream(struct Curl_easy *data,
   Bytef *orig_in = z->next_in;
   bool done = FALSE;
   CURLcode result = CURLE_OK;   /* Curl_client_write status */
-  char *decomp;                 /* Put the decompressed data here. */
 
   /* Check state. */
   if(zp->zlib_init != ZLIB_INIT &&
      zp->zlib_init != ZLIB_INFLATING &&
-     zp->zlib_init != ZLIB_INIT_GZIP &&
-     zp->zlib_init != ZLIB_GZIP_INFLATING)
+     zp->zlib_init != ZLIB_INIT_GZIP)
     return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
 
-  /* Dynamically allocate a buffer for decompression because it is uncommonly
-     large to hold on the stack */
-  decomp = malloc(DSIZ);
-  if(!decomp)
-    return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
-
   /* because the buffer size is fixed, iteratively decompress and transfer to
      the client via next_write function. */
   while(!done) {
@@ -205,8 +176,8 @@ static CURLcode inflate_stream(struct Curl_easy *data,
     done = TRUE;
 
     /* (re)set buffer for decompressed output for every iteration */
-    z->next_out = (Bytef *) decomp;
-    z->avail_out = DSIZ;
+    z->next_out = (Bytef *) zp->buffer;
+    z->avail_out = DECOMPRESS_BUFFER_SIZE;
 
 #ifdef Z_BLOCK
     /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */
@@ -217,11 +188,11 @@ static CURLcode inflate_stream(struct Curl_easy *data,
 #endif
 
     /* Flush output data if some. */
-    if(z->avail_out != DSIZ) {
+    if(z->avail_out != DECOMPRESS_BUFFER_SIZE) {
       if(status == Z_OK || status == Z_STREAM_END) {
         zp->zlib_init = started;      /* Data started. */
-        result = Curl_cwriter_write(data, writer->next, type, decomp,
-                                     DSIZ - z->avail_out);
+        result = Curl_cwriter_write(data, writer->next, type, zp->buffer,
+                                    DECOMPRESS_BUFFER_SIZE - z->avail_out);
         if(result) {
           exit_zlib(data, z, &zp->zlib_init, result);
           break;
@@ -264,7 +235,6 @@ static CURLcode inflate_stream(struct Curl_easy *data,
       break;
     }
   }
-  free(decomp);
 
   /* We are about to leave this call so the `nread' data bytes will not be seen
      again. If we are in a state that would wrongly allow restart in raw mode
@@ -278,7 +248,7 @@ static CURLcode inflate_stream(struct Curl_easy *data,
 
 /* Deflate handler. */
 static CURLcode deflate_do_init(struct Curl_easy *data,
-                                    struct Curl_cwriter *writer)
+                                struct Curl_cwriter *writer)
 {
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
@@ -294,8 +264,8 @@ static CURLcode deflate_do_init(struct Curl_easy *data,
 }
 
 static CURLcode deflate_do_write(struct Curl_easy *data,
-                                       struct Curl_cwriter *writer, int type,
-                                       const char *buf, size_t nbytes)
+                                 struct Curl_cwriter *writer, int type,
+                                 const char *buf, size_t nbytes)
 {
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
@@ -315,7 +285,7 @@ static CURLcode deflate_do_write(struct Curl_easy *data,
 }
 
 static void deflate_do_close(struct Curl_easy *data,
-                                 struct Curl_cwriter *writer)
+                             struct Curl_cwriter *writer)
 {
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
@@ -335,124 +305,34 @@ static const struct Curl_cwtype deflate_encoding = {
 
 /* Gzip handler. */
 static CURLcode gzip_do_init(struct Curl_easy *data,
-                                 struct Curl_cwriter *writer)
+                             struct Curl_cwriter *writer)
 {
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
+  const char *v = zlibVersion();
 
   /* Initialize zlib */
   z->zalloc = (alloc_func) zalloc_cb;
   z->zfree = (free_func) zfree_cb;
 
-  if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
-    /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
+  if(strcmp(v, "1.2.0.4") >= 0) {
+    /* zlib version >= 1.2.0.4 supports transparent gzip decompressing */
     if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
       return process_zlib_error(data, z);
     }
     zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
   }
   else {
-    /* we must parse the gzip header and trailer ourselves */
-    if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
-      return process_zlib_error(data, z);
-    }
-    zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */
-    zp->zlib_init = ZLIB_INIT; /* Initial call state */
+    failf(data, "too old zlib version: %s", v);
+    return CURLE_FAILED_INIT;
   }
 
   return CURLE_OK;
 }
 
-#ifdef OLD_ZLIB_SUPPORT
-/* Skip over the gzip header */
-typedef enum {
-  GZIP_OK,
-  GZIP_BAD,
-  GZIP_UNDERFLOW
-} gzip_status;
-
-static gzip_status check_gzip_header(unsigned char const *data, ssize_t len,
-                                     ssize_t *headerlen)
-{
-  int method, flags;
-  const ssize_t totallen = len;
-
-  /* The shortest header is 10 bytes */
-  if(len < 10)
-    return GZIP_UNDERFLOW;
-
-  if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
-    return GZIP_BAD;
-
-  method = data[2];
-  flags = data[3];
-
-  if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
-    /* cannot handle this compression method or unknown flag */
-    return GZIP_BAD;
-  }
-
-  /* Skip over time, xflags, OS code and all previous bytes */
-  len -= 10;
-  data += 10;
-
-  if(flags & EXTRA_FIELD) {
-    ssize_t extra_len;
-
-    if(len < 2)
-      return GZIP_UNDERFLOW;
-
-    extra_len = (data[1] << 8) | data[0];
-
-    if(len < (extra_len + 2))
-      return GZIP_UNDERFLOW;
-
-    len -= (extra_len + 2);
-    data += (extra_len + 2);
-  }
-
-  if(flags & ORIG_NAME) {
-    /* Skip over NUL-terminated filename */
-    while(len && *data) {
-      --len;
-      ++data;
-    }
-    if(!len || *data)
-      return GZIP_UNDERFLOW;
-
-    /* Skip over the NUL */
-    --len;
-    ++data;
-  }
-
-  if(flags & COMMENT) {
-    /* Skip over NUL-terminated comment */
-    while(len && *data) {
-      --len;
-      ++data;
-    }
-    if(!len || *data)
-      return GZIP_UNDERFLOW;
-
-    /* Skip over the NUL */
-    --len;
-  }
-
-  if(flags & HEAD_CRC) {
-    if(len < 2)
-      return GZIP_UNDERFLOW;
-
-    len -= 2;
-  }
-
-  *headerlen = totallen - len;
-  return GZIP_OK;
-}
-#endif
-
 static CURLcode gzip_do_write(struct Curl_easy *data,
-                                    struct Curl_cwriter *writer, int type,
-                                    const char *buf, size_t nbytes)
+                              struct Curl_cwriter *writer, int type,
+                              const char *buf, size_t nbytes)
 {
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
@@ -468,117 +348,8 @@ static CURLcode gzip_do_write(struct Curl_easy *data,
     return inflate_stream(data, writer, type, ZLIB_INIT_GZIP);
   }
 
-#ifndef OLD_ZLIB_SUPPORT
-  /* Support for old zlib versions is compiled away and we are running with
-     an old version, so return an error. */
+  /* We are running with an old version: return error. */
   return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
-
-#else
-  /* This next mess is to get around the potential case where there is not
-   * enough data passed in to skip over the gzip header. If that happens, we
-   * malloc a block and copy what we have then wait for the next call. If
-   * there still is not enough (this is definitely a worst-case scenario), we
-   * make the block bigger, copy the next part in and keep waiting.
-   *
-   * This is only required with zlib versions < 1.2.0.4 as newer versions
-   * can handle the gzip header themselves.
-   */
-
-  switch(zp->zlib_init) {
-  /* Skip over gzip header? */
-  case ZLIB_INIT:
-  {
-    /* Initial call state */
-    ssize_t hlen;
-
-    switch(check_gzip_header((unsigned char *) buf, nbytes, &hlen)) {
-    case GZIP_OK:
-      z->next_in = (Bytef *) buf + hlen;
-      z->avail_in = (uInt) (nbytes - hlen);
-      zp->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
-      break;
-
-    case GZIP_UNDERFLOW:
-      /* We need more data so we can find the end of the gzip header. it is
-       * possible that the memory block we malloc here will never be freed if
-       * the transfer abruptly aborts after this point. Since it is unlikely
-       * that circumstances will be right for this code path to be followed in
-       * the first place, and it is even more unlikely for a transfer to fail
-       * immediately afterwards, it should seldom be a problem.
-       */
-      z->avail_in = (uInt) nbytes;
-      z->next_in = malloc(z->avail_in);
-      if(!z->next_in) {
-        return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
-      }
-      memcpy(z->next_in, buf, z->avail_in);
-      zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
-      /* We do not have any data to inflate yet */
-      return CURLE_OK;
-
-    case GZIP_BAD:
-    default:
-      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
-    }
-
-  }
-  break;
-
-  case ZLIB_GZIP_HEADER:
-  {
-    /* Need more gzip header data state */
-    ssize_t hlen;
-    z->avail_in += (uInt) nbytes;
-    z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
-    if(!z->next_in) {
-      return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
-    }
-    /* Append the new block of data to the previous one */
-    memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
-
-    switch(check_gzip_header(z->next_in, (ssize_t)z->avail_in, &hlen)) {
-    case GZIP_OK:
-      /* This is the zlib stream data */
-      free(z->next_in);
-      /* Do not point into the malloced block since we just freed it */
-      z->next_in = (Bytef *) buf + hlen + nbytes - z->avail_in;
-      z->avail_in = z->avail_in - (uInt)hlen;
-      zp->zlib_init = ZLIB_GZIP_INFLATING;   /* Inflating stream state */
-      break;
-
-    case GZIP_UNDERFLOW:
-      /* We still do not have any data to inflate! */
-      return CURLE_OK;
-
-    case GZIP_BAD:
-    default:
-      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
-    }
-
-  }
-  break;
-
-  case ZLIB_EXTERNAL_TRAILER:
-    z->next_in = (Bytef *) buf;
-    z->avail_in = (uInt) nbytes;
-    return process_trailer(data, zp);
-
-  case ZLIB_GZIP_INFLATING:
-  default:
-    /* Inflating stream state */
-    z->next_in = (Bytef *) buf;
-    z->avail_in = (uInt) nbytes;
-    break;
-  }
-
-  if(z->avail_in == 0) {
-    /* We do not have any data to inflate; wait until next time */
-    return CURLE_OK;
-  }
-
-  /* We have parsed the header, now uncompress the data */
-  return inflate_stream(data, writer, type, ZLIB_GZIP_INFLATING);
-#endif
 }
 
 static void gzip_do_close(struct Curl_easy *data,
@@ -601,11 +372,11 @@ static const struct Curl_cwtype gzip_encoding = {
 
 #endif /* HAVE_LIBZ */
 
-
 #ifdef HAVE_BROTLI
 /* Brotli writer. */
 struct brotli_writer {
   struct Curl_cwriter super;
+  char buffer[DECOMPRESS_BUFFER_SIZE];
   BrotliDecoderState *br;    /* State structure for brotli. */
 };
 
@@ -648,7 +419,7 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
 }
 
 static CURLcode brotli_do_init(struct Curl_easy *data,
-                                   struct Curl_cwriter *writer)
+                               struct Curl_cwriter *writer)
 {
   struct brotli_writer *bp = (struct brotli_writer *) writer;
   (void) data;
@@ -658,12 +429,11 @@ static CURLcode brotli_do_init(struct Curl_easy *data,
 }
 
 static CURLcode brotli_do_write(struct Curl_easy *data,
-                                      struct Curl_cwriter *writer, int type,
-                                      const char *buf, size_t nbytes)
+                                struct Curl_cwriter *writer, int type,
+                                const char *buf, size_t nbytes)
 {
   struct brotli_writer *bp = (struct brotli_writer *) writer;
   const uint8_t *src = (const uint8_t *) buf;
-  char *decomp;
   uint8_t *dst;
   size_t dstleft;
   CURLcode result = CURLE_OK;
@@ -675,18 +445,14 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
   if(!bp->br)
     return CURLE_WRITE_ERROR;  /* Stream already ended. */
 
-  decomp = malloc(DSIZ);
-  if(!decomp)
-    return CURLE_OUT_OF_MEMORY;
-
   while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) &&
         result == CURLE_OK) {
-    dst = (uint8_t *) decomp;
-    dstleft = DSIZ;
+    dst = (uint8_t *) bp->buffer;
+    dstleft = DECOMPRESS_BUFFER_SIZE;
     r = BrotliDecoderDecompressStream(bp->br,
                                       &nbytes, &src, &dstleft, &dst, NULL);
     result = Curl_cwriter_write(data, writer->next, type,
-                                 decomp, DSIZ - dstleft);
+                                bp->buffer, DECOMPRESS_BUFFER_SIZE - dstleft);
     if(result)
       break;
     switch(r) {
@@ -704,7 +470,6 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
       break;
     }
   }
-  free(decomp);
   return result;
 }
 
@@ -712,7 +477,6 @@ static void brotli_do_close(struct Curl_easy *data,
                                 struct Curl_cwriter *writer)
 {
   struct brotli_writer *bp = (struct brotli_writer *) writer;
-
   (void) data;
 
   if(bp->br) {
@@ -731,30 +495,51 @@ static const struct Curl_cwtype brotli_encoding = {
 };
 #endif
 
-
 #ifdef HAVE_ZSTD
 /* Zstd writer. */
 struct zstd_writer {
   struct Curl_cwriter super;
   ZSTD_DStream *zds;    /* State structure for zstd. */
-  void *decomp;
+  char buffer[DECOMPRESS_BUFFER_SIZE];
 };
 
+#ifdef ZSTD_STATIC_LINKING_ONLY
+static void *Curl_zstd_alloc(void *opaque, size_t size)
+{
+  (void)opaque;
+  return Curl_cmalloc(size);
+}
+
+static void Curl_zstd_free(void *opaque, void *address)
+{
+  (void)opaque;
+  Curl_cfree(address);
+}
+#endif
+
 static CURLcode zstd_do_init(struct Curl_easy *data,
-                                 struct Curl_cwriter *writer)
+                             struct Curl_cwriter *writer)
 {
   struct zstd_writer *zp = (struct zstd_writer *) writer;
 
   (void)data;
 
+#ifdef ZSTD_STATIC_LINKING_ONLY
+  zp->zds = ZSTD_createDStream_advanced((ZSTD_customMem) {
+    .customAlloc = Curl_zstd_alloc,
+    .customFree  = Curl_zstd_free,
+    .opaque      = NULL
+  });
+#else
   zp->zds = ZSTD_createDStream();
-  zp->decomp = NULL;
+#endif
+
   return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
 }
 
 static CURLcode zstd_do_write(struct Curl_easy *data,
-                                    struct Curl_cwriter *writer, int type,
-                                    const char *buf, size_t nbytes)
+                              struct Curl_cwriter *writer, int type,
+                              const char *buf, size_t nbytes)
 {
   CURLcode result = CURLE_OK;
   struct zstd_writer *zp = (struct zstd_writer *) writer;
@@ -765,19 +550,14 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
   if(!(type & CLIENTWRITE_BODY) || !nbytes)
     return Curl_cwriter_write(data, writer->next, type, buf, nbytes);
 
-  if(!zp->decomp) {
-    zp->decomp = malloc(DSIZ);
-    if(!zp->decomp)
-      return CURLE_OUT_OF_MEMORY;
-  }
   in.pos = 0;
   in.src = buf;
   in.size = nbytes;
 
   for(;;) {
     out.pos = 0;
-    out.dst = zp->decomp;
-    out.size = DSIZ;
+    out.dst = zp->buffer;
+    out.size = DECOMPRESS_BUFFER_SIZE;
 
     errorCode = ZSTD_decompressStream(zp->zds, &out, &in);
     if(ZSTD_isError(errorCode)) {
@@ -785,7 +565,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
     }
     if(out.pos > 0) {
       result = Curl_cwriter_write(data, writer->next, type,
-                                   zp->decomp, out.pos);
+                                  zp->buffer, out.pos);
       if(result)
         break;
     }
@@ -800,13 +580,8 @@ static void zstd_do_close(struct Curl_easy *data,
                               struct Curl_cwriter *writer)
 {
   struct zstd_writer *zp = (struct zstd_writer *) writer;
-
   (void)data;
 
-  if(zp->decomp) {
-    free(zp->decomp);
-    zp->decomp = NULL;
-  }
   if(zp->zds) {
     ZSTD_freeDStream(zp->zds);
     zp->zds = NULL;
@@ -823,7 +598,6 @@ static const struct Curl_cwtype zstd_encoding = {
 };
 #endif
 
-
 /* Identity handler. */
 static const struct Curl_cwtype identity_encoding = {
   "identity",
@@ -834,7 +608,6 @@ static const struct Curl_cwtype identity_encoding = {
   sizeof(struct Curl_cwriter)
 };
 
-
 /* supported general content decoders. */
 static const struct Curl_cwtype * const general_unencoders[] = {
   &identity_encoding,
@@ -898,7 +671,7 @@ void Curl_all_content_encodings(char *buf, size_t blen)
 
 /* Deferred error dummy writer. */
 static CURLcode error_do_init(struct Curl_easy *data,
-                                  struct Curl_cwriter *writer)
+                              struct Curl_cwriter *writer)
 {
   (void)data;
   (void)writer;
@@ -906,8 +679,8 @@ static CURLcode error_do_init(struct Curl_easy *data,
 }
 
 static CURLcode error_do_write(struct Curl_easy *data,
-                                     struct Curl_cwriter *writer, int type,
-                                     const char *buf, size_t nbytes)
+                               struct Curl_cwriter *writer, int type,
+                               const char *buf, size_t nbytes)
 {
   (void) writer;
   (void) buf;
@@ -1082,5 +855,4 @@ void Curl_all_content_encodings(char *buf, size_t blen)
     strcpy(buf, CONTENT_ENCODING_DEFAULT);
 }
 
-
 #endif /* CURL_DISABLE_HTTP */

+ 64 - 32
lib/cookie.c

@@ -97,6 +97,26 @@ Example set of cookies:
 
 static void strstore(char **str, const char *newstr, size_t len);
 
+/* number of seconds in 400 days */
+#define COOKIES_MAXAGE (400*24*3600)
+
+/* Make sure cookies never expire further away in time than 400 days into the
+   future. (from RFC6265bis draft-19)
+
+   For the sake of easier testing, align the capped time to an even 60 second
+   boundary.
+*/
+static void cap_expires(time_t now, struct Cookie *co)
+{
+  if((TIME_T_MAX - COOKIES_MAXAGE - 30) > now) {
+    timediff_t cap = now + COOKIES_MAXAGE;
+    if(co->expires > cap) {
+      cap += 30;
+      co->expires = (cap/60)*60;
+    }
+  }
+}
+
 static void freecookie(struct Cookie *co)
 {
   free(co->domain);
@@ -438,7 +458,7 @@ static bool bad_domain(const char *domain, size_t len)
   fine. The prime reason for filtering out control bytes is that some HTTP
   servers return 400 for requests that contain such.
 */
-static int invalid_octets(const char *p)
+static bool invalid_octets(const char *p)
 {
   /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */
   static const char badoctets[] = {
@@ -449,7 +469,7 @@ static int invalid_octets(const char *p)
   size_t len;
   /* scan for all the octets that are *not* in cookie-octet */
   len = strcspn(p, badoctets);
-  return (p[len] != '\0');
+  return p[len] != '\0';
 }
 
 #define CERR_OK            0
@@ -469,6 +489,13 @@ static int invalid_octets(const char *p)
 #define CERR_PSL           14 /* a public suffix */
 #define CERR_LIVE_WINS     15
 
+/* The maximum length we accept a date string for the 'expire' keyword. The
+   standard date formats are within the 30 bytes range. This adds an extra
+   margin just to make sure it realistically works with what is used out
+   there.
+*/
+#define MAX_DATE_LENGTH 80
+
 static int
 parse_cookie_header(struct Curl_easy *data,
                     struct Cookie *co,
@@ -707,16 +734,20 @@ parse_cookie_header(struct Curl_easy *data,
             co->expires += now;
           break;
         }
+        cap_expires(now, co);
       }
       else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
-        if(!co->expires) {
+        if(!co->expires && (vlen < MAX_DATE_LENGTH)) {
           /*
            * Let max-age have priority.
            *
            * If the date cannot get parsed for whatever reason, the cookie
            * will be treated as a session cookie
            */
-          co->expires = Curl_getdate_capped(valuep);
+          char dbuf[MAX_DATE_LENGTH + 1];
+          memcpy(dbuf, valuep, vlen);
+          dbuf[vlen] = 0;
+          co->expires = Curl_getdate_capped(dbuf);
 
           /*
            * Session cookies have expires set to 0 so if we get that back
@@ -727,6 +758,7 @@ parse_cookie_header(struct Curl_easy *data,
             co->expires = 1;
           else if(co->expires < 0)
             co->expires = 0;
+          cap_expires(now, co);
         }
       }
 
@@ -805,10 +837,9 @@ parse_netscape(struct Cookie *co,
    * This line is NOT an HTTP header style line, we do offer support for
    * reading the odd netscape cookies-file format here
    */
-  char *ptr;
-  char *firstptr;
-  char *tok_buf = NULL;
+  const char *ptr, *next;
   int fields;
+  size_t len;
 
   /*
    * In 2008, Internet Explorer introduced HTTP-only cookies to prevent XSS
@@ -825,29 +856,22 @@ parse_netscape(struct Cookie *co,
     /* do not even try the comments */
     return CERR_COMMENT;
 
-  /* strip off the possible end-of-line characters */
-  ptr = strchr(lineptr, '\r');
-  if(ptr)
-    *ptr = 0; /* clear it */
-  ptr = strchr(lineptr, '\n');
-  if(ptr)
-    *ptr = 0; /* clear it */
-
-  /* tokenize on TAB */
-  firstptr = Curl_strtok_r((char *)lineptr, "\t", &tok_buf);
-
   /*
    * Now loop through the fields and init the struct we already have
    * allocated
    */
   fields = 0;
-  for(ptr = firstptr; ptr;
-      ptr = Curl_strtok_r(NULL, "\t", &tok_buf), fields++) {
+  for(next = lineptr; next; fields++) {
+    ptr = next;
+    len = strcspn(ptr, "\t\r\n");
+    next = (ptr[len] == '\t' ? &ptr[len + 1] : NULL);
     switch(fields) {
     case 0:
-      if(ptr[0]=='.') /* skip preceding dots */
+      if(ptr[0]=='.') { /* skip preceding dots */
         ptr++;
-      co->domain = strdup(ptr);
+        len--;
+      }
+      co->domain = Curl_memdup0(ptr, len);
       if(!co->domain)
         return CERR_OUT_OF_MEMORY;
       break;
@@ -857,13 +881,13 @@ parse_netscape(struct Cookie *co,
        * domain can access the variable. Set TRUE when the cookie says
        * .domain.com and to false when the domain is complete www.domain.com
        */
-      co->tailmatch = !!strcasecompare(ptr, "TRUE");
+      co->tailmatch = !!strncasecompare(ptr, "TRUE", len);
       break;
     case 2:
       /* The file format allows the path field to remain not filled in */
-      if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
+      if(strncmp("TRUE", ptr, len) && strncmp("FALSE", ptr, len)) {
         /* only if the path does not look like a boolean option! */
-        co->path = strdup(ptr);
+        co->path = Curl_memdup0(ptr, len);
         if(!co->path)
           return CERR_OUT_OF_MEMORY;
         else {
@@ -884,7 +908,7 @@ parse_netscape(struct Cookie *co,
       FALLTHROUGH();
     case 3:
       co->secure = FALSE;
-      if(strcasecompare(ptr, "TRUE")) {
+      if(strncasecompare(ptr, "TRUE", len)) {
         if(secure || ci->running)
           co->secure = TRUE;
         else
@@ -892,11 +916,19 @@ parse_netscape(struct Cookie *co,
       }
       break;
     case 4:
-      if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
-        return CERR_RANGE;
+      {
+        char *endp;
+        const char *p;
+        /* make sure curlx_strtoofft won't read past the current field */
+        for(p = ptr; p < &ptr[len] && ISDIGIT(*p); ++p)
+          ;
+        if(p == ptr || p != &ptr[len] ||
+           curlx_strtoofft(ptr, &endp, 10, &co->expires) || endp != &ptr[len])
+          return CERR_RANGE;
+      }
       break;
     case 5:
-      co->name = strdup(ptr);
+      co->name = Curl_memdup0(ptr, len);
       if(!co->name)
         return CERR_OUT_OF_MEMORY;
       else {
@@ -908,7 +940,7 @@ parse_netscape(struct Cookie *co,
       }
       break;
     case 6:
-      co->value = strdup(ptr);
+      co->value = Curl_memdup0(ptr, len);
       if(!co->value)
         return CERR_OUT_OF_MEMORY;
       break;
@@ -1303,14 +1335,14 @@ static int cookie_sort(const void *p1, const void *p2)
   l2 = c2->path ? strlen(c2->path) : 0;
 
   if(l1 != l2)
-    return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
+    return (l2 > l1) ? 1 : -1; /* avoid size_t <=> int conversions */
 
   /* 2 - compare cookie domain lengths */
   l1 = c1->domain ? strlen(c1->domain) : 0;
   l2 = c2->domain ? strlen(c2->domain) : 0;
 
   if(l1 != l2)
-    return (l2 > l1) ? 1 : -1 ;  /* avoid size_t <=> int conversions */
+    return (l2 > l1) ? 1 : -1; /* avoid size_t <=> int conversions */
 
   /* 3 - compare cookie name lengths */
   l1 = c1->name ? strlen(c1->name) : 0;

+ 5 - 5
lib/cookie.h

@@ -38,7 +38,7 @@ struct Cookie {
   char *spath;        /* sanitized cookie path */
   char *domain;       /* domain = <this> */
   curl_off_t expires; /* expires = <this> */
-  int creationtime;   /* time when the cookie was written */
+  unsigned int creationtime; /* time when the cookie was written */
   BIT(tailmatch);     /* tail-match the domain name */
   BIT(secure);        /* the 'secure' keyword was used */
   BIT(livecookie);    /* updated from a server, not a stored file */
@@ -60,10 +60,10 @@ struct CookieInfo {
   /* linked lists of cookies we know of */
   struct Curl_llist cookielist[COOKIE_HASH_SIZE];
   curl_off_t next_expiration; /* the next time at which expiration happens */
-  int numcookies;  /* number of cookies in the "jar" */
-  int lastct;      /* last creation-time used in the jar */
-  bool running;    /* state info, for cookie adding information */
-  bool newsession; /* new session, discard session cookies on load */
+  unsigned int numcookies;  /* number of cookies in the "jar" */
+  unsigned int lastct;      /* last creation-time used in the jar */
+  BIT(running);    /* state info, for cookie adding information */
+  BIT(newsession); /* new session, discard session cookies on load */
 };
 
 /* The maximum sizes we accept for cookies. RFC 6265 section 6.1 says

+ 0 - 8
lib/curl_addrinfo.c

@@ -318,11 +318,7 @@ Curl_he2ai(const struct hostent *he, int port)
       addr = (void *)ai->ai_addr; /* storage area for this info */
 
       memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
-#ifdef __MINGW32__
-      addr->sin_family = (short)(he->h_addrtype);
-#else
       addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
-#endif
       addr->sin_port = htons((unsigned short)port);
       break;
 
@@ -331,11 +327,7 @@ Curl_he2ai(const struct hostent *he, int port)
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
 
       memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
-#ifdef __MINGW32__
-      addr6->sin6_family = (short)(he->h_addrtype);
-#else
       addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
-#endif
       addr6->sin6_port = htons((unsigned short)port);
       break;
 #endif

+ 17 - 26
lib/curl_config.h.cmake

@@ -565,9 +565,6 @@
 /* Define to 1 if you have the <sys/filio.h> header file. */
 #cmakedefine HAVE_SYS_FILIO_H 1
 
-/* Define to 1 if you have the <sys/wait.h> header file. */
-#cmakedefine HAVE_SYS_WAIT_H 1
-
 /* Define to 1 if you have the <sys/ioctl.h> header file. */
 #cmakedefine HAVE_SYS_IOCTL_H 1
 
@@ -625,8 +622,8 @@
 /* Define this symbol if your OS supports changing the contents of argv */
 #cmakedefine HAVE_WRITABLE_ARGV 1
 
-/* Define to 1 if you need the malloc.h header file even with stdlib.h */
-#cmakedefine NEED_MALLOC_H 1
+/* Define this if time_t is unsigned */
+#cmakedefine HAVE_TIME_T_UNSIGNED 1
 
 /* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
 #cmakedefine NEED_REENTRANT 1
@@ -634,24 +631,6 @@
 /* cpu-machine-OS */
 #cmakedefine CURL_OS ${CURL_OS}
 
-/* Name of package */
-#cmakedefine PACKAGE ${PACKAGE}
-
-/* Define to the address where bug reports for this package should be sent. */
-#cmakedefine PACKAGE_BUGREPORT ${PACKAGE_BUGREPORT}
-
-/* Define to the full name of this package. */
-#cmakedefine PACKAGE_NAME ${PACKAGE_NAME}
-
-/* Define to the full name and version of this package. */
-#cmakedefine PACKAGE_STRING ${PACKAGE_STRING}
-
-/* Define to the one symbol short name of this package. */
-#cmakedefine PACKAGE_TARNAME ${PACKAGE_TARNAME}
-
-/* Define to the version of this package. */
-#cmakedefine PACKAGE_VERSION ${PACKAGE_VERSION}
-
 /*
  Note: SIZEOF_* variables are fetched with CMake through check_type_size().
  As per CMake documentation on CheckTypeSize, C preprocessor code is
@@ -703,6 +682,9 @@ ${SIZEOF_TIME_T_CODE}
 /* if Secure Transport is enabled */
 #cmakedefine USE_SECTRANSP 1
 
+/* if SSL session export support is available */
+#cmakedefine USE_SSLS_EXPORT 1
+
 /* if mbedTLS is enabled */
 #cmakedefine USE_MBEDTLS 1
 
@@ -742,6 +724,9 @@ ${SIZEOF_TIME_T_CODE}
 /* if OpenSSL is in use */
 #cmakedefine USE_OPENSSL 1
 
+/* if AmiSSL is in use */
+#cmakedefine USE_AMISSL 1
+
 /* if librtmp/rtmpdump is in use */
 #cmakedefine USE_LIBRTMP 1
 
@@ -791,12 +776,12 @@ ${SIZEOF_TIME_T_CODE}
 /* to enable Windows SSL  */
 #cmakedefine USE_SCHANNEL 1
 
+/* if Watt-32 is in use */
+#cmakedefine USE_WATT32 1
+
 /* enable multiple SSL backends */
 #cmakedefine CURL_WITH_MULTI_SSL 1
 
-/* Version number of package */
-#cmakedefine VERSION ${VERSION}
-
 /* Number of bits in a file offset, on hosts where this is settable. */
 #cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
 
@@ -841,3 +826,9 @@ ${SIZEOF_TIME_T_CODE}
 
 /* if ECH support is available */
 #cmakedefine USE_ECH 1
+
+/* Define to 1 if you have the wolfSSL_CTX_GenerateEchConfig function. */
+#cmakedefine HAVE_WOLFSSL_CTX_GENERATEECHCONFIG
+
+/* Define to 1 if you have the SSL_set1_ech_config_list function. */
+#cmakedefine HAVE_SSL_SET1_ECH_CONFIG_LIST

+ 1 - 1
lib/curl_ctype.h

@@ -46,6 +46,6 @@
 #define ISURLPUNTCS(x) (((x) == '-') || ((x) == '.') || ((x) == '_') || \
                         ((x) == '~'))
 #define ISUNRESERVED(x) (ISALNUM(x) || ISURLPUNTCS(x))
-
+#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
 
 #endif /* HEADER_CURL_CTYPE_H */

+ 2 - 0
lib/curl_get_line.c

@@ -28,7 +28,9 @@
   !defined(CURL_DISABLE_HSTS) || !defined(CURL_DISABLE_NETRC)
 
 #include "curl_get_line.h"
+#ifdef BUILDING_LIBCURL
 #include "curl_memory.h"
+#endif
 /* The last #include file should be: */
 #include "memdebug.h"
 

+ 6 - 0
lib/curl_get_line.h

@@ -26,6 +26,12 @@
 
 #include "dynbuf.h"
 
+#ifndef BUILDING_LIBCURL
+/* this renames functions so that the tool code can use the same code
+   without getting symbol collisions */
+#define Curl_get_line(a,b) curlx_get_line(a,b)
+#endif
+
 /* Curl_get_line() returns complete lines that end with a newline. */
 int Curl_get_line(struct dynbuf *buf, FILE *input);
 

+ 4 - 0
lib/curl_gethostname.c

@@ -73,7 +73,11 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen)
 #else /* DEBUGBUILD */
 
   name[0] = '\0';
+#ifdef __AMIGA__
+  err = gethostname((unsigned char *)name, namelen);
+#else
   err = gethostname(name, namelen);
+#endif
 
 #endif
 

+ 9 - 0
lib/curl_gssapi.c

@@ -40,6 +40,11 @@
 #define CURL_ALIGN8
 #endif
 
+#if defined(__GNUC__) && defined(__APPLE__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
 gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = {
   6, (char *)"\x2b\x06\x01\x05\x05\x02"
 };
@@ -149,4 +154,8 @@ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
 #endif
 }
 
+#if defined(__GNUC__) && defined(__APPLE__)
+#pragma GCC diagnostic pop
+#endif
+
 #endif /* HAVE_GSSAPI */

+ 3 - 3
lib/curl_hmac.h

@@ -24,9 +24,9 @@
  *
  ***************************************************************************/
 
-#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI))         \
-  || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH)   \
-  || defined(USE_LIBSSH2)
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) ||      \
+  !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) ||   \
+  defined(USE_SSL)
 
 #include <curl/curl.h>
 

+ 212 - 21
lib/curl_multibyte.c

@@ -32,7 +32,7 @@
 
 #include "curl_setup.h"
 
-#if defined(_WIN32)
+#ifdef _WIN32
 
 #include "curl_multibyte.h"
 
@@ -84,16 +84,170 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
   return str_utf8;
 }
 
-#endif /* _WIN32 */
+/* declare GetFullPathNameW for mingw-w64 UWP builds targeting old windows */
+#if defined(CURL_WINDOWS_UWP) && defined(__MINGW32__) && \
+  (_WIN32_WINNT < _WIN32_WINNT_WIN10)
+WINBASEAPI DWORD WINAPI GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR *);
+#endif
+
+/* Fix excessive paths (paths that exceed MAX_PATH length of 260).
+ *
+ * This is a helper function to fix paths that would exceed the MAX_PATH
+ * limitation check done by Windows APIs. It does so by normalizing the passed
+ * in filename or path 'in' to its full canonical path, and if that path is
+ * longer than MAX_PATH then setting 'out' to "\\?\" prefix + that full path.
+ *
+ * For example 'in' filename255chars in current directory C:\foo\bar is
+ * fixed as \\?\C:\foo\bar\filename255chars for 'out' which will tell Windows
+ * it is ok to access that filename even though the actual full path is longer
+ * than 260 chars.
+ *
+ * For non-Unicode builds this function may fail sometimes because only the
+ * Unicode versions of some Windows API functions can access paths longer than
+ * MAX_PATH, for example GetFullPathNameW which is used in this function. When
+ * the full path is then converted from Unicode to multibyte that fails if any
+ * directories in the path contain characters not in the current codepage.
+ */
+static bool fix_excessive_path(const TCHAR *in, TCHAR **out)
+{
+  size_t needed, count;
+  const wchar_t *in_w;
+  wchar_t *fbuf = NULL;
+
+  /* MS documented "approximate" limit for the maximum path length */
+  const size_t max_path_len = 32767;
+
+#ifndef _UNICODE
+  wchar_t *ibuf = NULL;
+  char *obuf = NULL;
+#endif
+
+  *out = NULL;
+
+  /* skip paths already normalized */
+  if(!_tcsncmp(in, _T("\\\\?\\"), 4))
+    goto cleanup;
+
+#ifndef _UNICODE
+  /* convert multibyte input to unicode */
+  needed = mbstowcs(NULL, in, 0);
+  if(needed == (size_t)-1 || needed >= max_path_len)
+    goto cleanup;
+  ++needed; /* for NUL */
+  ibuf = malloc(needed * sizeof(wchar_t));
+  if(!ibuf)
+    goto cleanup;
+  count = mbstowcs(ibuf, in, needed);
+  if(count == (size_t)-1 || count >= needed)
+    goto cleanup;
+  in_w = ibuf;
+#else
+  in_w = in;
+#endif
+
+  /* GetFullPathNameW returns the normalized full path in unicode. It converts
+     forward slashes to backslashes, processes .. to remove directory segments,
+     etc. Unlike GetFullPathNameA it can process paths that exceed MAX_PATH. */
+  needed = (size_t)GetFullPathNameW(in_w, 0, NULL, NULL);
+  if(!needed || needed > max_path_len)
+    goto cleanup;
+  /* skip paths that are not excessive and do not need modification */
+  if(needed <= MAX_PATH)
+    goto cleanup;
+  fbuf = malloc(needed * sizeof(wchar_t));
+  if(!fbuf)
+    goto cleanup;
+  count = (size_t)GetFullPathNameW(in_w, (DWORD)needed, fbuf, NULL);
+  if(!count || count >= needed)
+    goto cleanup;
+
+  /* prepend \\?\ or \\?\UNC\ to the excessively long path.
+   *
+   * c:\longpath            --->    \\?\c:\longpath
+   * \\.\c:\longpath        --->    \\?\c:\longpath
+   * \\?\c:\longpath        --->    \\?\c:\longpath  (unchanged)
+   * \\server\c$\longpath   --->    \\?\UNC\server\c$\longpath
+   *
+   * https://learn.microsoft.com/en-us/dotnet/standard/io/file-path-formats
+   */
+  if(!wcsncmp(fbuf, L"\\\\?\\", 4))
+    ; /* do nothing */
+  else if(!wcsncmp(fbuf, L"\\\\.\\", 4))
+    fbuf[2] = '?';
+  else if(!wcsncmp(fbuf, L"\\\\.", 3) || !wcsncmp(fbuf, L"\\\\?", 3)) {
+    /* Unexpected, not UNC. The formatting doc doesn't allow this AFAICT. */
+    goto cleanup;
+  }
+  else {
+    wchar_t *temp;
+
+    if(!wcsncmp(fbuf, L"\\\\", 2)) {
+      /* "\\?\UNC\" + full path without "\\" + null */
+      needed = 8 + (count - 2) + 1;
+      if(needed > max_path_len)
+        goto cleanup;
+
+      temp = malloc(needed * sizeof(wchar_t));
+      if(!temp)
+        goto cleanup;
 
-#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES)
+      wcsncpy(temp, L"\\\\?\\UNC\\", 8);
+      wcscpy(temp + 8, fbuf + 2);
+    }
+    else {
+      /* "\\?\" + full path + null */
+      needed = 4 + count + 1;
+      if(needed > max_path_len)
+        goto cleanup;
+
+      temp = malloc(needed * sizeof(wchar_t));
+      if(!temp)
+        goto cleanup;
+
+      wcsncpy(temp, L"\\\\?\\", 4);
+      wcscpy(temp + 4, fbuf);
+    }
+
+    free(fbuf);
+    fbuf = temp;
+  }
+
+#ifndef _UNICODE
+  /* convert unicode full path to multibyte output */
+  needed = wcstombs(NULL, fbuf, 0);
+  if(needed == (size_t)-1 || needed >= max_path_len)
+    goto cleanup;
+  ++needed; /* for NUL */
+  obuf = malloc(needed);
+  if(!obuf)
+    goto cleanup;
+  count = wcstombs(obuf, fbuf, needed);
+  if(count == (size_t)-1 || count >= needed)
+    goto cleanup;
+  *out = obuf;
+  obuf = NULL;
+#else
+  *out = fbuf;
+  fbuf = NULL;
+#endif
+
+cleanup:
+  free(fbuf);
+#ifndef _UNICODE
+  free(ibuf);
+  free(obuf);
+#endif
+  return *out ? true : false;
+}
 
 int curlx_win32_open(const char *filename, int oflag, ...)
 {
   int pmode = 0;
+  int result = -1;
+  TCHAR *fixed = NULL;
+  const TCHAR *target = NULL;
 
 #ifdef _UNICODE
-  int result = -1;
   wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
 #endif
 
@@ -105,58 +259,95 @@ int curlx_win32_open(const char *filename, int oflag, ...)
 
 #ifdef _UNICODE
   if(filename_w) {
-    result = _wopen(filename_w, oflag, pmode);
+    if(fix_excessive_path(filename_w, &fixed))
+      target = fixed;
+    else
+      target = filename_w;
+    result = _wopen(target, oflag, pmode);
     curlx_unicodefree(filename_w);
   }
   else
     errno = EINVAL;
-  return result;
 #else
-  return (_open)(filename, oflag, pmode);
+  if(fix_excessive_path(filename, &fixed))
+    target = fixed;
+  else
+    target = filename;
+  result = (_open)(target, oflag, pmode);
 #endif
+
+  free(fixed);
+  return result;
 }
 
 FILE *curlx_win32_fopen(const char *filename, const char *mode)
 {
-#ifdef _UNICODE
   FILE *result = NULL;
+  TCHAR *fixed = NULL;
+  const TCHAR *target = NULL;
+
+#ifdef _UNICODE
   wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
   wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
-  if(filename_w && mode_w)
-    result = _wfopen(filename_w, mode_w);
+  if(filename_w && mode_w) {
+    if(fix_excessive_path(filename_w, &fixed))
+      target = fixed;
+    else
+      target = filename_w;
+    result = _wfopen(target, mode_w);
+  }
   else
     errno = EINVAL;
   curlx_unicodefree(filename_w);
   curlx_unicodefree(mode_w);
-  return result;
 #else
-  return (fopen)(filename, mode);
+  if(fix_excessive_path(filename, &fixed))
+    target = fixed;
+  else
+    target = filename;
+  result = (fopen)(target, mode);
 #endif
+
+  free(fixed);
+  return result;
 }
 
 int curlx_win32_stat(const char *path, struct_stat *buffer)
 {
-#ifdef _UNICODE
   int result = -1;
+  TCHAR *fixed = NULL;
+  const TCHAR *target = NULL;
+
+#ifdef _UNICODE
   wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
   if(path_w) {
-#if defined(USE_WIN32_SMALL_FILES)
-    result = _wstat(path_w, buffer);
+    if(fix_excessive_path(path_w, &fixed))
+      target = fixed;
+    else
+      target = path_w;
+#ifndef USE_WIN32_LARGE_FILES
+    result = _wstat(target, buffer);
 #else
-    result = _wstati64(path_w, buffer);
+    result = _wstati64(target, buffer);
 #endif
     curlx_unicodefree(path_w);
   }
   else
     errno = EINVAL;
-  return result;
 #else
-#if defined(USE_WIN32_SMALL_FILES)
-  return _stat(path, buffer);
+  if(fix_excessive_path(path, &fixed))
+    target = fixed;
+  else
+    target = path;
+#ifndef USE_WIN32_LARGE_FILES
+  result = _stat(target, buffer);
 #else
-  return _stati64(path, buffer);
+  result = _stati64(target, buffer);
 #endif
 #endif
+
+  free(fixed);
+  return result;
 }
 
-#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
+#endif /* _WIN32 */

+ 6 - 0
lib/curl_rtmp.c

@@ -85,6 +85,7 @@ const struct Curl_handler Curl_handler_rtmp = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMP,                       /* protocol */
   CURLPROTO_RTMP,                       /* family */
@@ -109,6 +110,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPT,                      /* protocol */
   CURLPROTO_RTMPT,                      /* family */
@@ -133,6 +135,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMPE,                      /* protocol */
   CURLPROTO_RTMPE,                      /* family */
@@ -157,6 +160,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPTE,                     /* protocol */
   CURLPROTO_RTMPTE,                     /* family */
@@ -181,6 +185,7 @@ const struct Curl_handler Curl_handler_rtmps = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPS,                      /* protocol */
   CURLPROTO_RTMP,                       /* family */
@@ -205,6 +210,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPTS,                     /* protocol */
   CURLPROTO_RTMPT,                      /* family */

+ 101 - 95
lib/curl_setup.h

@@ -31,13 +31,6 @@
 /* Tell "curl/curl.h" not to include "curl/mprintf.h" */
 #define CURL_SKIP_INCLUDE_MPRINTF
 
-/* FIXME: Delete this once the warnings have been fixed. */
-#if !defined(CURL_WARN_SIGN_CONVERSION)
-#if defined(__GNUC__) || defined(__clang__)
-#pragma GCC diagnostic ignored "-Wsign-conversion"
-#endif
-#endif
-
 /* Set default _WIN32_WINNT */
 #ifdef __MINGW32__
 #include <_mingw.h>
@@ -85,13 +78,17 @@
 #endif
 #endif
 
-/*
- * Disable Visual Studio warnings:
- * 4127 "conditional expression is constant"
- */
 #ifdef _MSC_VER
+/* Disable Visual Studio warnings: 4127 "conditional expression is constant" */
 #pragma warning(disable:4127)
+/* Avoid VS2005 and upper complaining about portable C functions. */
+#ifndef _CRT_NONSTDC_NO_DEPRECATE
+#define _CRT_NONSTDC_NO_DEPRECATE  /* for strdup(), write(), etc. */
+#endif
+#ifndef _CRT_SECURE_NO_DEPRECATE
+#define _CRT_SECURE_NO_DEPRECATE  /* for fopen(), getenv(), etc. */
 #endif
+#endif /* _MSC_VER */
 
 #ifdef _WIN32
 /*
@@ -100,26 +97,26 @@
  * Make sure to define this macro before including any Windows headers.
  */
 #  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
 #  endif
 #  ifndef NOGDI
-#    define NOGDI
+#  define NOGDI
 #  endif
 /* Detect Windows App environment which has a restricted access
  * to the Win32 APIs. */
-# if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
-  defined(WINAPI_FAMILY)
-#  include <winapifamily.h>
-#  if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) &&  \
-     !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
-#    define CURL_WINDOWS_UWP
+#  if (defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0602)) || \
+     defined(WINAPI_FAMILY)
+#    include <winapifamily.h>
+#    if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) &&  \
+       !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#      define CURL_WINDOWS_UWP
+#    endif
 #  endif
-# endif
 #endif
 
 /* Compatibility */
-#if defined(ENABLE_IPV6)
-#  define USE_IPV6 1
+#ifdef ENABLE_IPV6
+#define USE_IPV6 1
 #endif
 
 /*
@@ -133,12 +130,8 @@
 
 #else /* HAVE_CONFIG_H */
 
-#ifdef _WIN32_WCE
-#  include "config-win32ce.h"
-#else
-#  ifdef _WIN32
-#    include "config-win32.h"
-#  endif
+#ifdef _WIN32
+#  include "config-win32.h"
 #endif
 
 #ifdef macintosh
@@ -149,10 +142,6 @@
 #  include "config-riscos.h"
 #endif
 
-#ifdef __AMIGA__
-#  include "config-amigaos.h"
-#endif
-
 #ifdef __OS400__
 #  include "config-os400.h"
 #endif
@@ -161,10 +150,6 @@
 #  include "config-plan9.h"
 #endif
 
-#ifdef MSDOS
-#  include "config-dos.h"
-#endif
-
 #endif /* HAVE_CONFIG_H */
 
 /* ================================================================ */
@@ -183,7 +168,7 @@
 
 #ifdef NEED_THREAD_SAFE
 #  ifndef _THREAD_SAFE
-#    define _THREAD_SAFE
+#  define _THREAD_SAFE
 #  endif
 #endif
 
@@ -195,14 +180,14 @@
 
 #ifdef NEED_REENTRANT
 #  ifndef _REENTRANT
-#    define _REENTRANT
+#  define _REENTRANT
 #  endif
 #endif
 
 /* Solaris needs this to get a POSIX-conformant getpwuid_r */
 #if defined(sun) || defined(__sun)
 #  ifndef _POSIX_PTHREAD_SEMANTICS
-#    define _POSIX_PTHREAD_SEMANTICS 1
+#  define _POSIX_PTHREAD_SEMANTICS 1
 #  endif
 #endif
 
@@ -290,14 +275,6 @@
 #  define CURL_DISABLE_HTTP_AUTH 1
 #endif
 
-/*
- * ECH requires HTTPSRR.
- */
-
-#if defined(USE_ECH) && !defined(USE_HTTPSRR)
-#  define USE_HTTPSRR
-#endif
-
 /* ================================================================ */
 /* No system header file shall be included in this file before this */
 /* point.                                                           */
@@ -393,17 +370,23 @@
 #  endif
 #endif
 
+#ifdef USE_ARES
+#  ifndef CARES_NO_DEPRECATED
+#  define CARES_NO_DEPRECATED  /* for ares_getsock() */
+#  endif
+#  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && defined(_WIN32)
+#    define CARES_STATICLIB  /* define it before including ares.h */
+#  endif
+#endif
+
 #ifdef USE_LWIPSOCK
 #  include <lwip/init.h>
 #  include <lwip/sockets.h>
 #  include <lwip/netdb.h>
 #endif
 
-#ifdef HAVE_EXTRA_STRICMP_H
+#ifdef macintosh
 #  include <extra/stricmp.h>
-#endif
-
-#ifdef HAVE_EXTRA_STRDUP_H
 #  include <extra/strdup.h>
 #endif
 
@@ -456,9 +439,9 @@
 #include <assert.h>
 
 #ifdef __TANDEM /* for ns*-tandem-nsk systems */
-# if ! defined __LP64
-#  include <floss.h> /* FLOSS is only used for 32-bit builds. */
-# endif
+#  if ! defined __LP64
+#    include <floss.h> /* FLOSS is only used for 32-bit builds. */
+#  endif
 #endif
 
 #ifndef STDC_HEADERS /* no standard C headers! */
@@ -494,11 +477,19 @@
    FILE *curlx_win32_fopen(const char *filename, const char *mode);
 #endif
 
+#ifdef __DJGPP__
+/* Requires DJGPP 2.04 */
+#  include <unistd.h>
+#  undef  lseek
+#  define lseek(fdes,offset,whence)  llseek(fdes, offset, whence)
+#  define LSEEK_ERROR                (offset_t)-1
+#endif
+
 /*
  * Small file (<2Gb) support using Win32 functions.
  */
 
-#ifdef USE_WIN32_SMALL_FILES
+#if defined(_WIN32) && !defined(USE_WIN32_LARGE_FILES)
 #  include <io.h>
 #  include <sys/types.h>
 #  include <sys/stat.h>
@@ -518,11 +509,11 @@
 #endif
 
 #ifndef struct_stat
-#  define struct_stat struct stat
+#define struct_stat struct stat
 #endif
 
 #ifndef LSEEK_ERROR
-#  define LSEEK_ERROR (off_t)-1
+#define LSEEK_ERROR (off_t)-1
 #endif
 
 #ifndef SIZEOF_TIME_T
@@ -593,8 +584,8 @@
 #  endif
 #  define CURL_UINT64_SUFFIX  CURL_SUFFIX_CURL_OFF_TU
 #  define CURL_UINT64_C(val)  CURL_CONC_MACROS(val,CURL_UINT64_SUFFIX)
-# define FMT_PRId64  CURL_FORMAT_CURL_OFF_T
-# define FMT_PRIu64  CURL_FORMAT_CURL_OFF_TU
+#  define FMT_PRId64  CURL_FORMAT_CURL_OFF_T
+#  define FMT_PRIu64  CURL_FORMAT_CURL_OFF_TU
 #endif
 
 #define FMT_OFF_T CURL_FORMAT_CURL_OFF_T
@@ -693,9 +684,9 @@
 /*
  * MSVC threads support requires a multi-threaded runtime library.
  * _beginthreadex() is not available in single-threaded ones.
+ * Single-threaded option was last available in VS2005: _MSC_VER <= 1400
  */
-
-#if defined(_MSC_VER) && !defined(_MT)
+#if defined(_MSC_VER) && !defined(_MT)  /* available in _MSC_VER <= 1400 */
 #  undef USE_THREADS_POSIX
 #  undef USE_THREADS_WIN32
 #endif
@@ -713,15 +704,15 @@
 #  define CURLRES_IPV4
 #endif
 
-#ifdef USE_ARES
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#  define CURLRES_ASYNCH
+#  define CURLRES_THREADED
+#elif defined(USE_ARES)
 #  define CURLRES_ASYNCH
 #  define CURLRES_ARES
 /* now undef the stock libc functions just to avoid them being used */
 #  undef HAVE_GETADDRINFO
 #  undef HAVE_FREEADDRINFO
-#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
-#  define CURLRES_ASYNCH
-#  define CURLRES_THREADED
 #else
 #  define CURLRES_SYNCH
 #endif
@@ -738,14 +729,23 @@
 #error "libidn2 cannot be enabled with WinIDN or AppleIDN, choose one."
 #endif
 
-#define LIBIDN_REQUIRED_VERSION "0.4.1"
-
 #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
 
+#if defined(USE_OPENSSL) && defined(USE_WOLFSSL)
+#  include <wolfssl/version.h>
+#  if LIBWOLFSSL_VERSION_HEX >= 0x05007006
+#    ifndef OPENSSL_COEXIST
+#    define OPENSSL_COEXIST
+#    endif
+#  else
+#    error "OpenSSL can only coexist with wolfSSL v5.7.6 or upper"
+#  endif
+#endif
+
 #if defined(USE_WOLFSSL) && defined(USE_GNUTLS)
 /* Avoid defining unprefixed wolfSSL SHA macros colliding with nettle ones */
 #define NO_OLD_WC_NAMES
@@ -776,10 +776,6 @@
 #  endif
 #endif
 
-#ifdef CURL_WANTS_CA_BUNDLE_ENV
-#error "No longer supported. Set CURLOPT_CAINFO at runtime instead."
-#endif
-
 #if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH)
 #define USE_SSH
 #endif
@@ -812,7 +808,7 @@
 #if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) || \
   defined(__IAR_SYSTEMS_ICC__)
 #  define CURL_NORETURN  __attribute__((__noreturn__))
-#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+#elif defined(_MSC_VER)
 #  define CURL_NORETURN  __declspec(noreturn)
 #else
 #  define CURL_NORETURN
@@ -843,7 +839,7 @@
  */
 
 #ifndef Curl_nop_stmt
-#  define Curl_nop_stmt do { } while(0)
+#define Curl_nop_stmt do { } while(0)
 #endif
 
 /*
@@ -882,6 +878,14 @@
 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 #endif
 
+/* Since O_BINARY is used in bitmasks, setting it to zero makes it usable in
+   source code but yet it does not ruin anything */
+#ifdef O_BINARY
+#define CURL_O_BINARY O_BINARY
+#else
+#define CURL_O_BINARY 0
+#endif
+
 /* In Windows the default file mode is text but an application can override it.
 Therefore we specify it explicitly. https://github.com/curl/curl/pull/258
 */
@@ -911,6 +915,8 @@ endings either CRLF or LF so 't' is appropriate.
 #    define CURL_SA_FAMILY_T sa_family_t
 #  elif defined(HAVE_ADDRESS_FAMILY)
 #    define CURL_SA_FAMILY_T ADDRESS_FAMILY
+#  elif defined(__AMIGA__)
+#    define CURL_SA_FAMILY_T unsigned char
 #  else
 /* use a sensible default */
 #    define CURL_SA_FAMILY_T unsigned short
@@ -927,8 +933,9 @@ endings either CRLF or LF so 't' is appropriate.
    as their argument */
 #define STRCONST(x) x,sizeof(x)-1
 
-/* Some versions of the Android SDK is missing the declaration */
-#if defined(HAVE_GETPWUID_R) && defined(HAVE_DECL_GETPWUID_R_MISSING)
+/* Some versions of the Android NDK is missing the declaration */
+#if defined(HAVE_GETPWUID_R) && \
+  defined(__ANDROID_API__) && (__ANDROID_API__ < 21)
 struct passwd;
 int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
                size_t buflen, struct passwd **result);
@@ -940,8 +947,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #define UNITTEST static
 #endif
 
-/* Hyper supports HTTP2 also, but Curl's integration with Hyper does not */
-#if defined(USE_NGHTTP2)
+#ifdef USE_NGHTTP2
 #define USE_HTTP2
 #endif
 
@@ -950,7 +956,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
     defined(USE_QUICHE) || defined(USE_MSH3)
 
 #ifdef CURL_WITH_MULTI_SSL
-#error "Multi-SSL combined with QUIC is not supported"
+#error "MultiSSL combined with QUIC is not supported"
 #endif
 
 #define USE_HTTP3
@@ -970,7 +976,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #    define UNIX_PATH_MAX 108
      /* !checksrc! disable TYPEDEFSTRUCT 1 */
      typedef struct sockaddr_un {
-       ADDRESS_FAMILY sun_family;
+       CURL_SA_FAMILY_T sun_family;
        char sun_path[UNIX_PATH_MAX];
      } SOCKADDR_UN, *PSOCKADDR_UN;
 #    define WIN32_SOCKADDR_UN
@@ -983,26 +989,26 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #define OPENSSL_SUPPRESS_DEPRECATED
 #endif
 
-#if defined(inline)
-  /* 'inline' is defined as macro and assumed to be correct */
-  /* No need for 'inline' replacement */
+#if defined(CURL_INLINE)
+/* 'CURL_INLINE' defined, use as-is */
+#elif defined(inline)
+#  define CURL_INLINE inline /* 'inline' defined, assumed correct */
 #elif defined(__cplusplus)
-  /* The code is compiled with C++ compiler.
-     C++ always supports 'inline'. */
-  /* No need for 'inline' replacement */
+/* The code is compiled with C++ compiler.
+   C++ always supports 'inline'. */
+#  define CURL_INLINE inline /* 'inline' keyword supported */
 #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901
-  /* C99 (and later) supports 'inline' keyword */
-  /* No need for 'inline' replacement */
+/* C99 (and later) supports 'inline' keyword */
+#  define CURL_INLINE inline /* 'inline' keyword supported */
 #elif defined(__GNUC__) && __GNUC__ >= 3
-  /* GCC supports '__inline__' as an extension */
-#  define inline __inline__
-#elif defined(_MSC_VER) && _MSC_VER >= 1400
-  /* MSC supports '__inline' from VS 2005 (or even earlier) */
-#  define inline __inline
+/* GCC supports '__inline__' as an extension */
+#  define CURL_INLINE __inline__
+#elif defined(_MSC_VER)
+#  define CURL_INLINE __inline
 #else
-  /* Probably 'inline' is not supported by compiler.
-     Define to the empty string to be on the safe side. */
-#  define inline /* empty */
+/* Probably 'inline' is not supported by compiler.
+   Define to the empty string to be on the safe side. */
+#  define CURL_INLINE /* empty */
 #endif
 
 #endif /* HEADER_CURL_SETUP_H */

+ 10 - 16
lib/curl_setup_once.h

@@ -24,7 +24,6 @@
  *
  ***************************************************************************/
 
-
 /*
  * Inclusion of common header files.
  */
@@ -40,14 +39,6 @@
 #include <sys/types.h>
 #endif
 
-#ifdef NEED_MALLOC_H
-#include <malloc.h>
-#endif
-
-#ifdef NEED_MEMORY_H
-#include <memory.h>
-#endif
-
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
@@ -56,8 +47,11 @@
 #include <sys/time.h>
 #endif
 
-#ifdef _WIN32
+#ifdef HAVE_IO_H
 #include <io.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
 
@@ -111,8 +105,8 @@
 
 #ifndef HAVE_STRUCT_TIMEVAL
 struct timeval {
- long tv_sec;
- long tv_usec;
+  long tv_sec;
+  long tv_usec;
 };
 #endif
 
@@ -195,7 +189,7 @@ struct timeval {
 #  define sclose(x)  closesocket((x))
 #elif defined(HAVE_CLOSESOCKET_CAMEL)
 #  define sclose(x)  CloseSocket((x))
-#elif defined(HAVE_CLOSE_S)
+#elif defined(MSDOS)  /* Watt-32 */
 #  define sclose(x)  close_s((x))
 #elif defined(USE_LWIPSOCK)
 #  define sclose(x)  lwip_close((x))
@@ -233,8 +227,8 @@ struct timeval {
 
 #ifndef HAVE_BOOL_T
   typedef enum {
-      bool_false = 0,
-      bool_true  = 1
+    bool_false = 0,
+    bool_true  = 1
   } bool;
 
 /*
@@ -397,7 +391,7 @@ typedef unsigned int bit;
 #ifdef __VMS
 #define argv_item_t  __char_ptr32
 #elif defined(_UNICODE)
-#define argv_item_t wchar_t *
+#define argv_item_t  wchar_t *
 #else
 #define argv_item_t  char *
 #endif

+ 1 - 1
lib/curl_sha256.h

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

+ 35 - 42
lib/curl_sha512_256.c

@@ -283,28 +283,26 @@ Curl_sha512_256_finish(unsigned char *digest,
 #ifdef __GNUC__
 #  if defined(__has_attribute) && defined(__STDC_VERSION__)
 #    if __has_attribute(always_inline) && __STDC_VERSION__ >= 199901
-#      define MHDX_INLINE inline __attribute__((always_inline))
+#      define CURL_FORCEINLINE CURL_INLINE __attribute__((always_inline))
 #    endif
 #  endif
 #endif
 
-#if !defined(MHDX_INLINE) && \
+#if !defined(CURL_FORCEINLINE) && \
   defined(_MSC_VER) && !defined(__GNUC__) && !defined(__clang__)
-#  if _MSC_VER >= 1400
-#    define MHDX_INLINE __forceinline
-#  endif
+#  define CURL_FORCEINLINE __forceinline
 #endif
 
-#if !defined(MHDX_INLINE)
-   /* Assume that 'inline' keyword works or the
+#if !defined(CURL_FORCEINLINE)
+   /* Assume that 'CURL_INLINE' keyword works or the
     * macro was already defined correctly. */
-#  define MHDX_INLINE inline
+#  define CURL_FORCEINLINE CURL_INLINE
 #endif
 
 /* Bits manipulation macros and functions.
    Can be moved to other headers to reuse. */
 
-#define MHDX_GET_64BIT_BE(ptr)                                  \
+#define CURL_GET_64BIT_BE(ptr)                                  \
   ( ((curl_uint64_t)(((const unsigned char*)(ptr))[0]) << 56) | \
     ((curl_uint64_t)(((const unsigned char*)(ptr))[1]) << 48) | \
     ((curl_uint64_t)(((const unsigned char*)(ptr))[2]) << 40) | \
@@ -314,7 +312,7 @@ Curl_sha512_256_finish(unsigned char *digest,
     ((curl_uint64_t)(((const unsigned char*)(ptr))[6]) << 8)  | \
     (curl_uint64_t)(((const unsigned char*)(ptr))[7]) )
 
-#define MHDX_PUT_64BIT_BE(ptr,val) do {                                 \
+#define CURL_PUT_64BIT_BE(ptr,val) do {                                 \
     ((unsigned char*)(ptr))[7]=(unsigned char)((curl_uint64_t)(val));   \
     ((unsigned char*)(ptr))[6]=(unsigned char)(((curl_uint64_t)(val)) >> 8); \
     ((unsigned char*)(ptr))[5]=(unsigned char)(((curl_uint64_t)(val)) >> 16); \
@@ -328,8 +326,8 @@ Curl_sha512_256_finish(unsigned char *digest,
 /* Defined as a function. The macro version may duplicate the binary code
  * size as each argument is used twice, so if any calculation is used
  * as an argument, the calculation could be done twice. */
-static MHDX_INLINE curl_uint64_t
-MHDx_rotr64(curl_uint64_t value, unsigned int bits)
+static CURL_FORCEINLINE curl_uint64_t
+Curl_rotr64(curl_uint64_t value, unsigned int bits)
 {
   bits %= 64;
   if(0 == bits)
@@ -388,7 +386,7 @@ MHDx_rotr64(curl_uint64_t value, unsigned int bits)
 /**
  * SHA-512/256 calculation context
  */
-struct mhdx_sha512_256ctx
+struct Curl_sha512_256ctx
 {
   /**
    * Intermediate hash value. The variable is properly aligned. Smart
@@ -416,7 +414,7 @@ struct mhdx_sha512_256ctx
 /**
  * Context type used for SHA-512/256 calculations
  */
-typedef struct mhdx_sha512_256ctx Curl_sha512_256_ctx;
+typedef struct Curl_sha512_256ctx Curl_sha512_256_ctx;
 
 
 /**
@@ -426,9 +424,9 @@ typedef struct mhdx_sha512_256ctx Curl_sha512_256_ctx;
  * @return always CURLE_OK
  */
 static CURLcode
-MHDx_sha512_256_init(void *context)
+Curl_sha512_256_init(void *context)
 {
-  struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *) context;
+  struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context;
 
   /* Check whether the header and this file use the same numbers */
   DEBUGASSERT(CURL_SHA512_256_DIGEST_LENGTH == CURL_SHA512_256_DIGEST_SIZE);
@@ -462,7 +460,7 @@ MHDx_sha512_256_init(void *context)
  * @param data  the data buffer with #CURL_SHA512_256_BLOCK_SIZE bytes block
  */
 static void
-MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
+Curl_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
                           const void *data)
 {
   /* Working variables,
@@ -488,13 +486,13 @@ MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
   /* Four 'Sigma' macro functions.
      See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
 #define SIG0(x)                                                         \
-  ( MHDx_rotr64((x), 28) ^ MHDx_rotr64((x), 34) ^ MHDx_rotr64((x), 39) )
+  ( Curl_rotr64((x), 28) ^ Curl_rotr64((x), 34) ^ Curl_rotr64((x), 39) )
 #define SIG1(x)                                                         \
-  ( MHDx_rotr64((x), 14) ^ MHDx_rotr64((x), 18) ^ MHDx_rotr64((x), 41) )
+  ( Curl_rotr64((x), 14) ^ Curl_rotr64((x), 18) ^ Curl_rotr64((x), 41) )
 #define sig0(x)                                                 \
-  ( MHDx_rotr64((x), 1) ^ MHDx_rotr64((x), 8) ^ ((x) >> 7) )
+  ( Curl_rotr64((x), 1) ^ Curl_rotr64((x), 8) ^ ((x) >> 7) )
 #define sig1(x)                                                 \
-  ( MHDx_rotr64((x), 19) ^ MHDx_rotr64((x), 61) ^ ((x) >> 6) )
+  ( Curl_rotr64((x), 19) ^ Curl_rotr64((x), 61) ^ ((x) >> 6) )
 
   if(1) {
     unsigned int t;
@@ -577,7 +575,7 @@ MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
        Input data must be read in big-endian bytes order,
        see FIPS PUB 180-4 section 3.1.2. */
 #define SHA512_GET_W_FROM_DATA(buf,t)                                   \
-    MHDX_GET_64BIT_BE(                                                  \
+    CURL_GET_64BIT_BE(                                                  \
       ((const unsigned char*) (buf)) + (t) * SHA512_256_BYTES_IN_WORD)
 
     /* During first 16 steps, before making any calculation on each step, the
@@ -628,12 +626,12 @@ MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
  * @return always CURLE_OK
  */
 static CURLcode
-MHDx_sha512_256_update(void *context,
+Curl_sha512_256_update(void *context,
                        const unsigned char *data,
                        size_t length)
 {
   unsigned int bytes_have; /**< Number of bytes in the context buffer */
-  struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *)context;
+  struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context;
   /* the void pointer here is required to mute Intel compiler warning */
   void *const ctx_buf = ctx->buffer;
 
@@ -661,7 +659,7 @@ MHDx_sha512_256_update(void *context,
              bytes_left);
       data += bytes_left;
       length -= bytes_left;
-      MHDx_sha512_256_transform(ctx->H, ctx->buffer);
+      Curl_sha512_256_transform(ctx->H, ctx->buffer);
       bytes_have = 0;
     }
   }
@@ -669,7 +667,7 @@ MHDx_sha512_256_update(void *context,
   while(CURL_SHA512_256_BLOCK_SIZE <= length) {
     /* Process any full blocks of new data directly,
        without copying to the buffer. */
-    MHDx_sha512_256_transform(ctx->H, data);
+    Curl_sha512_256_transform(ctx->H, data);
     data += CURL_SHA512_256_BLOCK_SIZE;
     length -= CURL_SHA512_256_BLOCK_SIZE;
   }
@@ -705,10 +703,10 @@ MHDx_sha512_256_update(void *context,
  * @return always CURLE_OK
  */
 static CURLcode
-MHDx_sha512_256_finish(unsigned char *digest,
+Curl_sha512_256_finish(unsigned char *digest,
                        void *context)
 {
-  struct mhdx_sha512_256ctx *const ctx = (struct mhdx_sha512_256ctx *)context;
+  struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context;
   curl_uint64_t num_bits;   /**< Number of processed bits */
   unsigned int bytes_have; /**< Number of bytes in the context buffer */
   /* the void pointer here is required to mute Intel compiler warning */
@@ -742,7 +740,7 @@ MHDx_sha512_256_finish(unsigned char *digest,
       memset(((unsigned char *) ctx_buf) + bytes_have, 0,
              CURL_SHA512_256_BLOCK_SIZE - bytes_have);
     /* Process the full block. */
-    MHDx_sha512_256_transform(ctx->H, ctx->buffer);
+    Curl_sha512_256_transform(ctx->H, ctx->buffer);
     /* Start the new block. */
     bytes_have = 0;
   }
@@ -754,37 +752,32 @@ MHDx_sha512_256_finish(unsigned char *digest,
      part of number of bits as big-endian values.
      See FIPS PUB 180-4 section 5.1.2. */
   /* Note: the target location is predefined and buffer is always aligned */
-  MHDX_PUT_64BIT_BE(((unsigned char *) ctx_buf)  \
+  CURL_PUT_64BIT_BE(((unsigned char *) ctx_buf)  \
                       + CURL_SHA512_256_BLOCK_SIZE    \
                       - SHA512_256_SIZE_OF_LEN_ADD,   \
                       ctx->count_bits_hi);
-  MHDX_PUT_64BIT_BE(((unsigned char *) ctx_buf)      \
+  CURL_PUT_64BIT_BE(((unsigned char *) ctx_buf)      \
                       + CURL_SHA512_256_BLOCK_SIZE        \
                       - SHA512_256_SIZE_OF_LEN_ADD        \
                       + SHA512_256_BYTES_IN_WORD,         \
                       num_bits);
   /* Process the full final block. */
-  MHDx_sha512_256_transform(ctx->H, ctx->buffer);
+  Curl_sha512_256_transform(ctx->H, ctx->buffer);
 
   /* Put in BE mode the leftmost part of the hash as the final digest.
      See FIPS PUB 180-4 section 6.7. */
 
-  MHDX_PUT_64BIT_BE((digest + 0 * SHA512_256_BYTES_IN_WORD), ctx->H[0]);
-  MHDX_PUT_64BIT_BE((digest + 1 * SHA512_256_BYTES_IN_WORD), ctx->H[1]);
-  MHDX_PUT_64BIT_BE((digest + 2 * SHA512_256_BYTES_IN_WORD), ctx->H[2]);
-  MHDX_PUT_64BIT_BE((digest + 3 * SHA512_256_BYTES_IN_WORD), ctx->H[3]);
+  CURL_PUT_64BIT_BE((digest + 0 * SHA512_256_BYTES_IN_WORD), ctx->H[0]);
+  CURL_PUT_64BIT_BE((digest + 1 * SHA512_256_BYTES_IN_WORD), ctx->H[1]);
+  CURL_PUT_64BIT_BE((digest + 2 * SHA512_256_BYTES_IN_WORD), ctx->H[2]);
+  CURL_PUT_64BIT_BE((digest + 3 * SHA512_256_BYTES_IN_WORD), ctx->H[3]);
 
   /* Erase potentially sensitive data. */
-  memset(ctx, 0, sizeof(struct mhdx_sha512_256ctx));
+  memset(ctx, 0, sizeof(struct Curl_sha512_256ctx));
 
   return CURLE_OK;
 }
 
-/* Map to the local implementation */
-#define Curl_sha512_256_init    MHDx_sha512_256_init
-#define Curl_sha512_256_update  MHDx_sha512_256_update
-#define Curl_sha512_256_finish  MHDx_sha512_256_finish
-
 #endif /* Local SHA-512/256 code */
 
 

+ 6 - 6
lib/curl_sspi.h

@@ -81,27 +81,27 @@ extern PSecurityFunctionTable Curl_pSecFn;
 #endif
 
 #ifndef SEC_I_SIGNATURE_NEEDED
-# define SEC_I_SIGNATURE_NEEDED               ((HRESULT)0x0009035CL)
+#define SEC_I_SIGNATURE_NEEDED                ((HRESULT)0x0009035CL)
 #endif
 
 #ifndef CRYPT_E_REVOKED
-# define CRYPT_E_REVOKED                      ((HRESULT)0x80092010L)
+#define CRYPT_E_REVOKED                       ((HRESULT)0x80092010L)
 #endif
 
 #ifndef CRYPT_E_NO_REVOCATION_DLL
-# define CRYPT_E_NO_REVOCATION_DLL            ((HRESULT)0x80092011L)
+#define CRYPT_E_NO_REVOCATION_DLL             ((HRESULT)0x80092011L)
 #endif
 
 #ifndef CRYPT_E_NO_REVOCATION_CHECK
-# define CRYPT_E_NO_REVOCATION_CHECK          ((HRESULT)0x80092012L)
+#define CRYPT_E_NO_REVOCATION_CHECK           ((HRESULT)0x80092012L)
 #endif
 
 #ifndef CRYPT_E_REVOCATION_OFFLINE
-# define CRYPT_E_REVOCATION_OFFLINE           ((HRESULT)0x80092013L)
+#define CRYPT_E_REVOCATION_OFFLINE            ((HRESULT)0x80092013L)
 #endif
 
 #ifndef CRYPT_E_NOT_IN_REVOCATION_DATABASE
-# define CRYPT_E_NOT_IN_REVOCATION_DATABASE   ((HRESULT)0x80092014L)
+#define CRYPT_E_NOT_IN_REVOCATION_DATABASE    ((HRESULT)0x80092014L)
 #endif
 
 #ifdef UNICODE

+ 71 - 1
lib/curl_trc.c

@@ -239,6 +239,24 @@ void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
 }
 #endif /* !CURL_DISABLE_SMTP */
 
+#ifdef USE_SSL
+struct curl_trc_feat Curl_trc_feat_ssls = {
+  "SSLS",
+  CURL_LOG_LVL_NONE,
+};
+
+void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
+{
+  DEBUGASSERT(!strchr(fmt, '\n'));
+  if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) {
+    va_list ap;
+    va_start(ap, fmt);
+    trc_infof(data, &Curl_trc_feat_ssls, fmt, ap);
+    va_end(ap);
+  }
+}
+#endif /* USE_SSL */
+
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 struct curl_trc_feat Curl_trc_feat_ws = {
   "WS",
@@ -279,6 +297,9 @@ static struct trc_feat_def trc_feats[] = {
 #ifndef CURL_DISABLE_SMTP
   { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
 #endif
+#ifdef USE_SSL
+  { &Curl_trc_feat_ssls,      TRC_CT_NETWORK },
+#endif
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
   { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
 #endif
@@ -319,7 +340,7 @@ static struct trc_cft_def trc_cfts[] = {
 #ifdef USE_HTTP3
   { &Curl_cft_http3,          TRC_CT_PROTOCOL },
 #endif
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
   { &Curl_cft_http_connect,   TRC_CT_PROTOCOL },
 #endif
 };
@@ -427,4 +448,53 @@ CURLcode Curl_trc_init(void)
   return CURLE_OK;
 }
 
+void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+
+void Curl_trc_cf_infof(struct Curl_easy *data,
+                       struct Curl_cfilter *cf,
+                       const char *fmt, ...)
+{
+  (void)data; (void)cf; (void)fmt;
+}
+
+struct curl_trc_feat;
+
+void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+
+void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+
+#ifndef CURL_DISABLE_FTP
+void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+#endif
+#ifndef CURL_DISABLE_SMTP
+void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+#endif
+#if !defined(CURL_DISABLE_WEBSOCKETS) || !defined(CURL_DISABLE_HTTP)
+void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data; (void)fmt;
+}
+#endif
+
+void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...)
+{
+  (void)data;
+  (void)fmt;
+}
+
 #endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */

+ 47 - 78
lib/curl_trc.h

@@ -70,7 +70,45 @@ void Curl_failf(struct Curl_easy *data,
 #define CURL_HAVE_C99
 #endif
 
-#ifdef CURL_HAVE_C99
+/**
+ * Output an informational message when transfer's verbose logging is enabled.
+ */
+void Curl_infof(struct Curl_easy *data,
+                const char *fmt, ...) CURL_PRINTF(2, 3);
+
+/**
+ * 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,
+                       const char *fmt, ...) CURL_PRINTF(3, 4);
+void Curl_trc_write(struct Curl_easy *data,
+                    const char *fmt, ...) CURL_PRINTF(2, 3);
+void Curl_trc_read(struct Curl_easy *data,
+                   const char *fmt, ...) CURL_PRINTF(2, 3);
+
+#ifndef CURL_DISABLE_FTP
+extern struct curl_trc_feat Curl_trc_feat_ftp;
+void Curl_trc_ftp(struct Curl_easy *data,
+                  const char *fmt, ...) CURL_PRINTF(2, 3);
+#endif
+#ifndef CURL_DISABLE_SMTP
+extern struct curl_trc_feat Curl_trc_feat_smtp;
+void Curl_trc_smtp(struct Curl_easy *data,
+                   const char *fmt, ...) CURL_PRINTF(2, 3);
+#endif
+#ifdef USE_SSL
+extern struct curl_trc_feat Curl_trc_feat_ssls;
+void Curl_trc_ssls(struct Curl_easy *data,
+                   const char *fmt, ...) CURL_PRINTF(2, 3);
+#endif
+#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
+extern struct curl_trc_feat Curl_trc_feat_ws;
+void Curl_trc_ws(struct Curl_easy *data,
+                 const char *fmt, ...) CURL_PRINTF(2, 3);
+#endif
+
+#if defined(CURL_HAVE_C99) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
 #define infof(data, ...) \
   do { if(Curl_trc_is_verbose(data)) \
          Curl_infof(data, __VA_ARGS__); } while(0)
@@ -94,6 +132,11 @@ void Curl_failf(struct Curl_easy *data,
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) \
          Curl_trc_smtp(data, __VA_ARGS__); } while(0)
 #endif /* !CURL_DISABLE_SMTP */
+#ifdef USE_SSL
+#define CURL_TRC_SSLS(data, ...) \
+  do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ssls)) \
+         Curl_trc_ssls(data, __VA_ARGS__); } while(0)
+#endif /* USE_SSL */
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #define CURL_TRC_WS(data, ...)                             \
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \
@@ -113,6 +156,9 @@ void Curl_failf(struct Curl_easy *data,
 #ifndef CURL_DISABLE_SMTP
 #define CURL_TRC_SMTP  Curl_trc_smtp
 #endif
+#ifdef USE_SSL
+#define CURL_TRC_SSLS  Curl_trc_ssls
+#endif
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #define CURL_TRC_WS    Curl_trc_ws
 #endif
@@ -140,40 +186,6 @@ extern struct curl_trc_feat Curl_trc_feat_write;
             (Curl_trc_is_verbose(data) && \
              (ft)->log_level >= CURL_LOG_LVL_INFO)
 
-/**
- * Output an informational message when transfer's verbose logging is enabled.
- */
-void Curl_infof(struct Curl_easy *data,
-                const char *fmt, ...) CURL_PRINTF(2, 3);
-
-/**
- * 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,
-                       const char *fmt, ...) CURL_PRINTF(3, 4);
-void Curl_trc_write(struct Curl_easy *data,
-                    const char *fmt, ...) CURL_PRINTF(2, 3);
-void Curl_trc_read(struct Curl_easy *data,
-                   const char *fmt, ...) CURL_PRINTF(2, 3);
-
-#ifndef CURL_DISABLE_FTP
-extern struct curl_trc_feat Curl_trc_feat_ftp;
-void Curl_trc_ftp(struct Curl_easy *data,
-                  const char *fmt, ...) CURL_PRINTF(2, 3);
-#endif
-#ifndef CURL_DISABLE_SMTP
-extern struct curl_trc_feat Curl_trc_feat_smtp;
-void Curl_trc_smtp(struct Curl_easy *data,
-                   const char *fmt, ...) CURL_PRINTF(2, 3);
-#endif
-#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
-extern struct curl_trc_feat Curl_trc_feat_ws;
-void Curl_trc_ws(struct Curl_easy *data,
-                 const char *fmt, ...) CURL_PRINTF(2, 3);
-#endif
-
-
 #else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
 /* All informational messages are not compiled in for size savings */
 
@@ -181,49 +193,6 @@ void Curl_trc_ws(struct Curl_easy *data,
 #define Curl_trc_cf_is_verbose(x,y)   (FALSE)
 #define Curl_trc_ft_is_verbose(x,y)   (FALSE)
 
-static void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
-{
-  (void)data; (void)fmt;
-}
-
-static void Curl_trc_cf_infof(struct Curl_easy *data,
-                              struct Curl_cfilter *cf,
-                              const char *fmt, ...)
-{
-  (void)data; (void)cf; (void)fmt;
-}
-
-struct curl_trc_feat;
-
-static void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...)
-{
-  (void)data; (void)fmt;
-}
-
-static void Curl_trc_read(struct Curl_easy *data, const char *fmt, ...)
-{
-  (void)data; (void)fmt;
-}
-
-#ifndef CURL_DISABLE_FTP
-static void Curl_trc_ftp(struct Curl_easy *data, const char *fmt, ...)
-{
-  (void)data; (void)fmt;
-}
-#endif
-#ifndef CURL_DISABLE_SMTP
-static void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...)
-{
-  (void)data; (void)fmt;
-}
-#endif
-#if !defined(CURL_DISABLE_WEBSOCKETS) || !defined(CURL_DISABLE_HTTP)
-static void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...)
-{
-  (void)data; (void)fmt;
-}
-#endif
-
 #endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
 
 #endif /* HEADER_CURL_TRC_H */

+ 1 - 0
lib/dict.c

@@ -93,6 +93,7 @@ const struct Curl_handler Curl_handler_dict = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_DICT,                            /* defport */
   CURLPROTO_DICT,                       /* protocol */
   CURLPROTO_DICT,                       /* family */

+ 54 - 138
lib/doh.c

@@ -410,12 +410,6 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
   struct doh_probes *dohp;
   struct connectdata *conn = data->conn;
   size_t i;
-#ifdef USE_HTTPSRR
-  /* for now, this is only used when ECH is enabled */
-# ifdef USE_ECH
-  char *qname = NULL;
-# endif
-#endif
   *waitp = FALSE;
   (void)hostname;
   (void)port;
@@ -462,34 +456,23 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
 #endif
 
 #ifdef USE_HTTPSRR
-  /*
-   * TODO: Figure out the conditions under which we want to make
-   * a request for an HTTPS RR when we are not doing ECH. For now,
-   * making this request breaks a bunch of DoH tests, e.g. test2100,
-   * where the additional request does not match the pre-cooked data
-   * files, so there is a bit of work attached to making the request
-   * in a non-ECH use-case. For the present, we will only make the
-   * request when ECH is enabled in the build and is being used for
-   * the curl operation.
-   */
-# ifdef USE_ECH
-  if(data->set.tls_ech & CURLECH_ENABLE
-     || data->set.tls_ech & CURLECH_HARD) {
-    if(port == 443)
-      qname = strdup(hostname);
-    else
+  if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+    /* Only use HTTPS RR for HTTP(S) transfers */
+    char *qname = NULL;
+    if(port != PORT_HTTPS) {
       qname = aprintf("_%d._https.%s", port, hostname);
-    if(!qname)
-      goto error;
+      if(!qname)
+        goto error;
+    }
     result = doh_run_probe(data, &dohp->probe[DOH_SLOT_HTTPS_RR],
-                           DNS_TYPE_HTTPS, qname, data->set.str[STRING_DOH],
+                           DNS_TYPE_HTTPS,
+                           qname ? qname : hostname, data->set.str[STRING_DOH],
                            data->multi, dohp->req_hds);
-    Curl_safefree(qname);
+    free(qname);
     if(result)
       goto error;
     dohp->pending++;
   }
-# endif
 #endif
   *waitp = TRUE; /* this never returns synchronously */
   return NULL;
@@ -961,11 +944,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
       addr = (void *)ai->ai_addr; /* storage area for this info */
       DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
       memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
-#ifdef __MINGW32__
-      addr->sin_family = (short)addrtype;
-#else
-      addr->sin_family = addrtype;
-#endif
+      addr->sin_family = (CURL_SA_FAMILY_T)addrtype;
       addr->sin_port = htons((unsigned short)port);
       break;
 
@@ -974,11 +953,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname,
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
       DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
       memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
-#ifdef __MINGW32__
-      addr6->sin6_family = (short)addrtype;
-#else
-      addr6->sin6_family = addrtype;
-#endif
+      addr6->sin6_family = (CURL_SA_FAMILY_T)addrtype;
       addr6->sin6_port = htons((unsigned short)port);
       break;
 #endif
@@ -1089,62 +1064,6 @@ static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
   return CURLE_OK;
 }
 
-static CURLcode doh_decode_rdata_alpn(unsigned char *rrval, size_t len,
-                                      char **alpns)
-{
-  /*
-   * spec here is as per draft-ietf-dnsop-svcb-https, section-7.1.1
-   * encoding is catenated list of strings each preceded by a one
-   * octet length
-   * output is comma-sep list of the strings
-   * implementations may or may not handle quoting of comma within
-   * string values, so we might see a comma within the wire format
-   * version of a string, in which case we will precede that by a
-   * backslash - same goes for a backslash character, and of course
-   * we need to use two backslashes in strings when we mean one;-)
-   */
-  int remaining = (int) len;
-  char *oval;
-  size_t i;
-  unsigned char *cp = rrval;
-  struct dynbuf dval;
-
-  if(!alpns)
-    return CURLE_OUT_OF_MEMORY;
-  Curl_dyn_init(&dval, DYN_DOH_RESPONSE);
-  remaining = (int)len;
-  cp = rrval;
-  while(remaining > 0) {
-    size_t tlen = (size_t) *cp++;
-
-    /* if not 1st time, add comma */
-    if(remaining != (int)len && Curl_dyn_addn(&dval, ",", 1))
-      goto err;
-    remaining--;
-    if(tlen > (size_t)remaining)
-      goto err;
-    /* add escape char if needed, clunky but easier to read */
-    for(i = 0; i != tlen; i++) {
-      if('\\' == *cp || ',' == *cp) {
-        if(Curl_dyn_addn(&dval, "\\", 1))
-          goto err;
-      }
-      if(Curl_dyn_addn(&dval, cp++, 1))
-        goto err;
-    }
-    remaining -= (int)tlen;
-  }
-  /* this string is always null terminated */
-  oval = Curl_dyn_ptr(&dval);
-  if(!oval)
-    goto err;
-  *alpns = oval;
-  return CURLE_OK;
-err:
-  Curl_dyn_free(&dval);
-  return CURLE_BAD_CONTENT_ENCODING;
-}
-
 #ifdef DEBUGBUILD
 static CURLcode doh_test_alpn_escapes(void)
 {
@@ -1156,24 +1075,20 @@ static CURLcode doh_test_alpn_escapes(void)
     0x68, 0x32                                      /* value "h2" */
   };
   size_t example_len = sizeof(example);
-  char *aval = NULL;
-  static const char *expected = "f\\\\oo\\,bar,h2";
+  unsigned char aval[MAX_HTTPSRR_ALPNS] = { 0 };
+  static const char expected[2] = { ALPN_h2, ALPN_none };
 
-  if(doh_decode_rdata_alpn(example, example_len, &aval) != CURLE_OK)
+  if(Curl_httpsrr_decode_alpn(example, example_len, aval) != CURLE_OK)
     return CURLE_BAD_CONTENT_ENCODING;
-  if(strlen(aval) != strlen(expected))
-    return CURLE_BAD_CONTENT_ENCODING;
-  if(memcmp(aval, expected, strlen(aval)))
+  if(memcmp(aval, expected, sizeof(expected)))
     return CURLE_BAD_CONTENT_ENCODING;
   return CURLE_OK;
 }
 #endif
 
-static CURLcode doh_resp_decode_httpsrr(unsigned char *rrval, size_t len,
+static CURLcode doh_resp_decode_httpsrr(unsigned char *cp, size_t len,
                                         struct Curl_https_rrinfo **hrr)
 {
-  size_t remaining = len;
-  unsigned char *cp = rrval;
   uint16_t pcode = 0, plen = 0;
   struct Curl_https_rrinfo *lhrr = NULL;
   char *dnsname = NULL;
@@ -1183,73 +1098,73 @@ static CURLcode doh_resp_decode_httpsrr(unsigned char *rrval, size_t len,
   if(doh_test_alpn_escapes() != CURLE_OK)
     return CURLE_OUT_OF_MEMORY;
 #endif
+  if(len <= 2)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
   lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
   if(!lhrr)
     return CURLE_OUT_OF_MEMORY;
-  lhrr->val = Curl_memdup(rrval, len);
-  if(!lhrr->val)
-    goto err;
-  lhrr->len = len;
-  if(remaining <= 2)
-    goto err;
-  lhrr->priority = (uint16_t)((cp[0] << 8) + cp[1]);
+  lhrr->priority = doh_get16bit(cp, 0);
   cp += 2;
-  remaining -= (uint16_t)2;
-  if(doh_decode_rdata_name(&cp, &remaining, &dnsname) != CURLE_OK)
+  len -= 2;
+  if(doh_decode_rdata_name(&cp, &len, &dnsname) != CURLE_OK)
     goto err;
   lhrr->target = dnsname;
-  while(remaining >= 4) {
-    pcode = (uint16_t)((*cp << 8) + (*(cp + 1)));
-    cp += 2;
-    plen = (uint16_t)((*cp << 8) + (*(cp + 1)));
-    cp += 2;
-    remaining -= 4;
-    if(pcode == HTTPS_RR_CODE_ALPN) {
-      if(doh_decode_rdata_alpn(cp, plen, &lhrr->alpns) != CURLE_OK)
+  lhrr->port = -1; /* until set */
+  while(len >= 4) {
+    pcode = doh_get16bit(cp, 0);
+    plen = doh_get16bit(cp, 2);
+    cp += 4;
+    len -= 4;
+    switch(pcode) {
+    case HTTPS_RR_CODE_ALPN:
+      if(Curl_httpsrr_decode_alpn(cp, plen, lhrr->alpns) != CURLE_OK)
         goto err;
-    }
-    if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
+      break;
+    case HTTPS_RR_CODE_NO_DEF_ALPN:
       lhrr->no_def_alpn = TRUE;
-    else if(pcode == HTTPS_RR_CODE_IPV4) {
+      break;
+    case HTTPS_RR_CODE_IPV4:
       if(!plen)
         goto err;
       lhrr->ipv4hints = Curl_memdup(cp, plen);
       if(!lhrr->ipv4hints)
         goto err;
       lhrr->ipv4hints_len = (size_t)plen;
-    }
-    else if(pcode == HTTPS_RR_CODE_ECH) {
+      break;
+    case HTTPS_RR_CODE_ECH:
       if(!plen)
         goto err;
       lhrr->echconfiglist = Curl_memdup(cp, plen);
       if(!lhrr->echconfiglist)
         goto err;
       lhrr->echconfiglist_len = (size_t)plen;
-    }
-    else if(pcode == HTTPS_RR_CODE_IPV6) {
+      break;
+    case HTTPS_RR_CODE_IPV6:
       if(!plen)
         goto err;
       lhrr->ipv6hints = Curl_memdup(cp, plen);
       if(!lhrr->ipv6hints)
         goto err;
       lhrr->ipv6hints_len = (size_t)plen;
+      break;
+    case HTTPS_RR_CODE_PORT:
+      lhrr->port = doh_get16bit(cp, 0);
+      break;
+    default:
+      break;
     }
-    if(plen > 0 && plen <= remaining) {
+    if(plen > 0 && plen <= len) {
       cp += plen;
-      remaining -= plen;
+      len -= plen;
     }
   }
-  DEBUGASSERT(!remaining);
+  DEBUGASSERT(!len);
   *hrr = lhrr;
   return CURLE_OK;
 err:
-  if(lhrr) {
-    Curl_safefree(lhrr->target);
-    Curl_safefree(lhrr->echconfiglist);
-    Curl_safefree(lhrr->val);
-    Curl_safefree(lhrr->alpns);
-    Curl_safefree(lhrr);
-  }
+  Curl_safefree(lhrr->target);
+  Curl_safefree(lhrr->echconfiglist);
+  Curl_safefree(lhrr);
   return CURLE_OUT_OF_MEMORY;
 }
 
@@ -1260,8 +1175,9 @@ static void doh_print_httpsrr(struct Curl_easy *data,
   DEBUGASSERT(hrr);
   infof(data, "HTTPS RR: priority %d, target: %s",
         hrr->priority, hrr->target);
-  if(hrr->alpns)
-    infof(data, "HTTPS RR: alpns %s", hrr->alpns);
+  if(hrr->alpns[0] != ALPN_none)
+    infof(data, "HTTPS RR: alpns %u %u %u %u",
+          hrr->alpns[0], hrr->alpns[1], hrr->alpns[2], hrr->alpns[3]);
   else
     infof(data, "HTTPS RR: no alpns");
   if(hrr->no_def_alpn)

+ 1 - 13
lib/doh.h

@@ -28,6 +28,7 @@
 #include "curl_addrinfo.h"
 #ifdef USE_HTTPSRR
 # include <stdint.h>
+# include "httpsrr.h"
 #endif
 
 #ifndef CURL_DISABLE_DOH
@@ -123,19 +124,6 @@ struct dohaddr {
 
 #ifdef USE_HTTPSRR
 
-/*
- * These are the code points for DNS wire format SvcParams as
- * per draft-ietf-dnsop-svcb-https
- * Not all are supported now, and even those that are may need
- * more work in future to fully support the spec.
- */
-#define HTTPS_RR_CODE_ALPN            0x01
-#define HTTPS_RR_CODE_NO_DEF_ALPN     0x02
-#define HTTPS_RR_CODE_PORT            0x03
-#define HTTPS_RR_CODE_IPV4            0x04
-#define HTTPS_RR_CODE_ECH             0x05
-#define HTTPS_RR_CODE_IPV6            0x06
-
 /*
  * These may need escaping when found within an ALPN string
  * value.

+ 12 - 0
lib/dynbuf.c

@@ -244,6 +244,18 @@ char *Curl_dyn_ptr(const struct dynbuf *s)
   return s->bufr;
 }
 
+char *Curl_dyn_take(struct dynbuf *s, size_t *plen)
+{
+  char *ptr = s->bufr;
+  DEBUGASSERT(s);
+  DEBUGASSERT(s->init == DYNINIT);
+  *plen = s->leng;
+  s->bufr = NULL;
+  s->leng = 0;
+  s->allc = 0;
+  return ptr;
+}
+
 /*
  * Returns an unsigned pointer to the buffer.
  */

+ 5 - 0
lib/dynbuf.h

@@ -39,6 +39,7 @@
 #define Curl_dyn_uptr(a) curlx_dyn_uptr(a)
 #define Curl_dyn_len(a) curlx_dyn_len(a)
 #define Curl_dyn_reset(a) curlx_dyn_reset(a)
+#define Curl_dyn_take(a,b) curlx_dyn_take(a,b)
 #define Curl_dyn_tail(a,b) curlx_dyn_tail(a,b)
 #define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b)
 #define curlx_dynbuf dynbuf /* for the struct name */
@@ -75,6 +76,10 @@ size_t Curl_dyn_len(const struct dynbuf *s);
 /* The implementation of this function exists in mprintf.c */
 int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
 
+/* Take the buffer out of the dynbuf. Caller has ownership and
+ * dynbuf resets to initial state. */
+char *Curl_dyn_take(struct dynbuf *s, size_t *plen);
+
 /* Dynamic buffer max sizes */
 #define DYN_DOH_RESPONSE    3000
 #define DYN_DOH_CNAME       256

+ 55 - 3
lib/easy.c

@@ -48,6 +48,7 @@
 #include <curl/curl.h>
 #include "transfer.h"
 #include "vtls/vtls.h"
+#include "vtls/vtls_scache.h"
 #include "url.h"
 #include "getinfo.h"
 #include "hostip.h"
@@ -761,12 +762,25 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
     return CURLE_FAILED_INIT;
   }
 
+  /* if the handle has a connection still attached (it is/was a connect-only
+     handle) then disconnect before performing */
+  if(data->conn) {
+    struct connectdata *c;
+    curl_socket_t s;
+    Curl_detach_connection(data);
+    s = Curl_getconnectinfo(data, &c);
+    if((s != CURL_SOCKET_BAD) && c) {
+      Curl_cpool_disconnect(data, c, TRUE);
+    }
+    DEBUGASSERT(!data->conn);
+  }
+
   if(data->multi_easy)
     multi = data->multi_easy;
   else {
-    /* this multi handle will only ever have a single easy handled attached
-       to it, so make it use minimal hashes */
-    multi = Curl_multi_handle(1, 3, 7);
+    /* this multi handle will only ever have a single easy handle attached to
+       it, so make it use minimal hash sizes */
+    multi = Curl_multi_handle(1, 3, 7, 3);
     if(!multi)
       return CURLE_OUT_OF_MEMORY;
   }
@@ -1336,3 +1350,41 @@ CURLcode curl_easy_upkeep(CURL *d)
   /* Use the common function to keep connections alive. */
   return Curl_cpool_upkeep(data);
 }
+
+CURLcode curl_easy_ssls_import(CURL *d, const char *session_key,
+                               const unsigned char *shmac, size_t shmac_len,
+                               const unsigned char *sdata, size_t sdata_len)
+{
+#ifdef USE_SSLS_EXPORT
+  struct Curl_easy *data = d;
+  if(!GOOD_EASY_HANDLE(data))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  return Curl_ssl_session_import(data, session_key,
+                                 shmac, shmac_len, sdata, sdata_len);
+#else
+  (void)d;
+  (void)session_key;
+  (void)shmac;
+  (void)shmac_len;
+  (void)sdata;
+  (void)sdata_len;
+  return CURLE_NOT_BUILT_IN;
+#endif
+}
+
+CURLcode curl_easy_ssls_export(CURL *d,
+                               curl_ssls_export_cb *export_fn,
+                               void *userptr)
+{
+#ifdef USE_SSLS_EXPORT
+  struct Curl_easy *data = d;
+  if(!GOOD_EASY_HANDLE(data))
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  return Curl_ssl_session_export(data, export_fn, userptr);
+#else
+  (void)d;
+  (void)export_fn;
+  (void)userptr;
+  return CURLE_NOT_BUILT_IN;
+#endif
+}

+ 4 - 2
lib/easy_lock.h

@@ -69,7 +69,7 @@
 
 #endif
 
-static inline void curl_simple_lock_lock(curl_simple_lock *lock)
+static CURL_INLINE void curl_simple_lock_lock(curl_simple_lock *lock)
 {
   for(;;) {
     if(!atomic_exchange_explicit(lock, true, memory_order_acquire))
@@ -81,6 +81,8 @@ static inline void curl_simple_lock_lock(curl_simple_lock *lock)
       __builtin_ia32_pause();
 #elif defined(__aarch64__)
       __asm__ volatile("yield" ::: "memory");
+#elif defined(_WIN32)
+      Sleep(1);
 #elif defined(HAVE_SCHED_YIELD)
       sched_yield();
 #endif
@@ -88,7 +90,7 @@ static inline void curl_simple_lock_lock(curl_simple_lock *lock)
   }
 }
 
-static inline void curl_simple_lock_unlock(curl_simple_lock *lock)
+static CURL_INLINE void curl_simple_lock_unlock(curl_simple_lock *lock)
 {
   atomic_store_explicit(lock, false, memory_order_release);
 }

+ 1 - 1
lib/easyoptions.c

@@ -377,6 +377,6 @@ struct curl_easyoption Curl_easyopts[] = {
  */
 int Curl_easyopts_check(void)
 {
-  return ((CURLOPT_LASTENTRY%10000) != (326 + 1));
+  return (CURLOPT_LASTENTRY % 10000) != (326 + 1);
 }
 #endif

+ 19 - 19
lib/file.c

@@ -78,18 +78,12 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-#if defined(_WIN32) || defined(MSDOS) || defined(__EMX__)
+#if defined(_WIN32) || defined(MSDOS)
 #define DOS_FILESYSTEM 1
 #elif defined(__amigaos4__)
 #define AMIGA_FILESYSTEM 1
 #endif
 
-#ifdef OPEN_NEEDS_ARG3
-#  define open_readonly(p,f) open((p),(f),(0))
-#else
-#  define open_readonly(p,f) open((p),(f))
-#endif
-
 /*
  * Forward declarations.
  */
@@ -126,6 +120,7 @@ const struct Curl_handler Curl_handler_file = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   0,                                    /* defport */
   CURLPROTO_FILE,                       /* protocol */
   CURLPROTO_FILE,                       /* family */
@@ -209,7 +204,7 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
       return CURLE_URL_MALFORMAT;
     }
 
-  fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
+  fd = open(actual_path, O_RDONLY|CURL_O_BINARY);
   file->path = actual_path;
 #else
   if(memchr(real_path, 0, real_path_len)) {
@@ -233,16 +228,16 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
     extern int __unix_path_semantics;
     if(strchr(real_path + 1, ':')) {
       /* Amiga absolute path */
-      fd = open_readonly(real_path + 1, O_RDONLY);
+      fd = open(real_path + 1, O_RDONLY);
       file->path++;
     }
     else if(__unix_path_semantics) {
       /* -lunix fallback */
-      fd = open_readonly(real_path, O_RDONLY);
+      fd = open(real_path, O_RDONLY);
     }
   }
   #else
-  fd = open_readonly(real_path, O_RDONLY);
+  fd = open(real_path, O_RDONLY);
   file->path = real_path;
   #endif
 #endif
@@ -318,18 +313,18 @@ static CURLcode file_upload(struct Curl_easy *data)
   if(!dir[1])
     return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
 
-#ifdef O_BINARY
-#define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY
-#else
-#define MODE_DEFAULT O_WRONLY|O_CREAT
-#endif
-
+  mode = O_WRONLY|O_CREAT|CURL_O_BINARY;
   if(data->state.resume_from)
-    mode = MODE_DEFAULT|O_APPEND;
+    mode |= O_APPEND;
   else
-    mode = MODE_DEFAULT|O_TRUNC;
+    mode |= O_TRUNC;
 
+#if (defined(ANDROID) || defined(__ANDROID__)) && \
+    (defined(__i386__) || defined(__arm__))
+  fd = open(file->path, mode, (mode_t)data->set.new_file_perms);
+#else
   fd = open(file->path, mode, data->set.new_file_perms);
+#endif
   if(fd < 0) {
     failf(data, "cannot open %s for writing", file->path);
     return CURLE_WRITE_ERROR;
@@ -553,8 +548,13 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
 
   if(data->state.resume_from) {
     if(!S_ISDIR(statbuf.st_mode)) {
+#ifdef __AMIGA__
+      if(data->state.resume_from !=
+          lseek(fd, (off_t)data->state.resume_from, SEEK_SET))
+#else
       if(data->state.resume_from !=
           lseek(fd, data->state.resume_from, SEEK_SET))
+#endif
         return CURLE_BAD_DOWNLOAD_RESUME;
     }
     else {

+ 1 - 1
lib/fopen.c

@@ -53,7 +53,7 @@
 #ifdef _WIN32
 #define PATHSEP "\\"
 #define IS_SEP(x) (((x) == '/') || ((x) == '\\'))
-#elif defined(MSDOS) || defined(__EMX__) || defined(OS2)
+#elif defined(MSDOS) || defined(OS2)
 #define PATHSEP "\\"
 #define IS_SEP(x) ((x) == '\\')
 #else

+ 19 - 4
lib/ftp.c

@@ -250,6 +250,7 @@ const struct Curl_handler Curl_handler_ftp = {
   ZERO_NULL,                       /* write_resp_hd */
   ZERO_NULL,                       /* connection_check */
   ZERO_NULL,                       /* attach connection */
+  ZERO_NULL,                       /* follow */
   PORT_FTP,                        /* defport */
   CURLPROTO_FTP,                   /* protocol */
   CURLPROTO_FTP,                   /* family */
@@ -282,6 +283,7 @@ const struct Curl_handler Curl_handler_ftps = {
   ZERO_NULL,                       /* write_resp_hd */
   ZERO_NULL,                       /* connection_check */
   ZERO_NULL,                       /* attach connection */
+  ZERO_NULL,                       /* follow */
   PORT_FTPS,                       /* defport */
   CURLPROTO_FTPS,                  /* protocol */
   CURLPROTO_FTP,                   /* family */
@@ -2079,10 +2081,19 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
       /* If we asked for a time of the file and we actually got one as well,
          we "emulate" an HTTP-style header in our output. */
 
+#if defined(__GNUC__) && (defined(__DJGPP__) || defined(__AMIGA__))
+#pragma GCC diagnostic push
+/* 'time_t' is unsigned in MSDOS and AmigaOS. Silence:
+   warning: comparison of unsigned expression in '>= 0' is always true */
+#pragma GCC diagnostic ignored "-Wtype-limits"
+#endif
       if(data->req.no_body &&
          ftpc->file &&
          data->set.get_filetime &&
          (data->info.filetime >= 0) ) {
+#if defined(__GNUC__) && (defined(__DJGPP__) || defined(__AMIGA__))
+#pragma GCC diagnostic pop
+#endif
         char headerbuf[128];
         int headerbuflen;
         time_t filetime = data->info.filetime;
@@ -3154,7 +3165,7 @@ static CURLcode ftp_connect(struct Curl_easy *data,
 
   PINGPONG_SETUP(pp, ftp_statemachine, ftp_endofresp);
 
-  if(conn->handler->flags & PROTOPT_SSL) {
+  if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
     /* BLOCKING */
     result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
     if(result)
@@ -4097,8 +4108,8 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
 }
 
 #ifdef _MSC_VER
-/* warning C4706: assignment within conditional expression */
-#pragma warning(disable:4706)
+#pragma warning(push)
+#pragma warning(disable:4706) /* assignment within conditional expression */
 #endif
 
 /***********************************************************************
@@ -4244,7 +4255,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
       else
         n -= ftpc->file ? strlen(ftpc->file) : 0;
 
-      if((strlen(oldPath) == n) && !strncmp(rawPath, oldPath, n)) {
+      if((strlen(oldPath) == n) && rawPath && !strncmp(rawPath, oldPath, n)) {
         infof(data, "Request has same path as previous transfer");
         ftpc->cwddone = TRUE;
       }
@@ -4255,6 +4266,10 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
   return CURLE_OK;
 }
 
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
 /* call this when the DO phase has completed */
 static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
 {

+ 1 - 0
lib/functypes.h

@@ -62,6 +62,7 @@
 
 /* int send(int, const char *, int, int); */
 #define SEND_TYPE_ARG1 int
+#define SEND_QUAL_ARG2
 #define SEND_TYPE_ARG2 char *
 #define SEND_TYPE_ARG3 int
 #define SEND_TYPE_RETV int

+ 13 - 0
lib/getinfo.c

@@ -69,6 +69,8 @@ CURLcode Curl_initinfo(struct Curl_easy *data)
   info->request_size = 0;
   info->proxyauthavail = 0;
   info->httpauthavail = 0;
+  info->proxyauthpicked = 0;
+  info->httpauthpicked = 0;
   info->numconnects = 0;
 
   free(info->contenttype);
@@ -238,8 +240,10 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
   case CURLINFO_FILETIME:
     if(data->info.filetime > LONG_MAX)
       *param_longp = LONG_MAX;
+#if !defined(MSDOS) && !defined(__AMIGA__)
     else if(data->info.filetime < LONG_MIN)
       *param_longp = LONG_MIN;
+#endif
     else
       *param_longp = (long)data->info.filetime;
     break;
@@ -270,6 +274,14 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
     lptr.to_long = param_longp;
     *lptr.to_ulong = data->info.proxyauthavail;
     break;
+  case CURLINFO_HTTPAUTH_USED:
+    lptr.to_long = param_longp;
+    *lptr.to_ulong = data->info.httpauthpicked;
+    break;
+  case CURLINFO_PROXYAUTH_USED:
+    lptr.to_long = param_longp;
+    *lptr.to_ulong = data->info.proxyauthpicked;
+    break;
   case CURLINFO_OS_ERRNO:
     *param_longp = data->state.os_errno;
     break;
@@ -377,6 +389,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
     case CURLINFO_APPCONNECT_TIME_T:
     case CURLINFO_PRETRANSFER_TIME_T:
     case CURLINFO_POSTTRANSFER_TIME_T:
+    case CURLINFO_QUEUE_TIME_T:
     case CURLINFO_STARTTRANSFER_TIME_T:
     case CURLINFO_REDIRECT_TIME_T:
     case CURLINFO_SPEED_DOWNLOAD_T:

+ 2 - 0
lib/gopher.c

@@ -79,6 +79,7 @@ const struct Curl_handler Curl_handler_gopher = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHER,                     /* protocol */
   CURLPROTO_GOPHER,                     /* family */
@@ -104,6 +105,7 @@ const struct Curl_handler Curl_handler_gophers = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHERS,                    /* protocol */
   CURLPROTO_GOPHER,                     /* family */

+ 2 - 0
lib/hash.c

@@ -42,6 +42,8 @@ hash_element_dtor(void *user, void *element)
 {
   struct Curl_hash *h = (struct Curl_hash *) user;
   struct Curl_hash_element *e = (struct Curl_hash_element *) element;
+  DEBUGASSERT(h);
+  DEBUGASSERT(e);
 
   if(e->ptr) {
     if(e->dtor)

+ 3 - 2
lib/hmac.c

@@ -26,8 +26,9 @@
 
 #include "curl_setup.h"
 
-#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI))         \
-  || !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH)
+#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) ||      \
+  !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) ||   \
+  defined(USE_SSL)
 
 #include <curl/curl.h>
 

+ 8 - 14
lib/hostip.c

@@ -198,7 +198,7 @@ hostcache_entry_is_stale(void *datap, void *hc)
   if(dns->timestamp) {
     /* age in seconds */
     time_t age = prune->now - dns->timestamp;
-    if(age >= prune->max_age_sec)
+    if(age >= (time_t)prune->max_age_sec)
       return TRUE;
     if(age > prune->oldest)
       prune->oldest = age;
@@ -541,7 +541,9 @@ static struct Curl_addrinfo *get_localhost6(int port, const char *name)
   sa6.sin6_family = AF_INET6;
   sa6.sin6_port = htons(port16);
   sa6.sin6_flowinfo = 0;
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
   sa6.sin6_scope_id = 0;
+#endif
 
   (void)Curl_inet_pton(AF_INET6, "::1", ipv6);
   memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
@@ -630,7 +632,7 @@ bool Curl_ipv6works(struct Curl_easy *data)
       ipv6_works = 1;
       sclose(s);
     }
-    return (ipv6_works > 0);
+    return ipv6_works > 0;
   }
 }
 #endif /* USE_IPV6 */
@@ -1077,18 +1079,10 @@ static void hostcache_unlink_entry(void *entry)
     Curl_freeaddrinfo(dns->addr);
 #ifdef USE_HTTPSRR
     if(dns->hinfo) {
-      if(dns->hinfo->target)
-        free(dns->hinfo->target);
-      if(dns->hinfo->alpns)
-        free(dns->hinfo->alpns);
-      if(dns->hinfo->ipv4hints)
-        free(dns->hinfo->ipv4hints);
-      if(dns->hinfo->echconfiglist)
-        free(dns->hinfo->echconfiglist);
-      if(dns->hinfo->ipv6hints)
-        free(dns->hinfo->ipv6hints);
-      if(dns->hinfo->val)
-        free(dns->hinfo->val);
+      free(dns->hinfo->target);
+      free(dns->hinfo->ipv4hints);
+      free(dns->hinfo->echconfiglist);
+      free(dns->hinfo->ipv6hints);
       free(dns->hinfo);
     }
 #endif

+ 8 - 30
lib/hostip.h

@@ -29,6 +29,7 @@
 #include "curl_addrinfo.h"
 #include "timeval.h" /* for timediff_t */
 #include "asyn.h"
+#include "httpsrr.h"
 
 #include <setjmp.h>
 
@@ -53,6 +54,13 @@ struct hostent;
 struct Curl_easy;
 struct connectdata;
 
+enum alpnid {
+  ALPN_none = 0,
+  ALPN_h1 = CURLALTSVC_H1,
+  ALPN_h2 = CURLALTSVC_H2,
+  ALPN_h3 = CURLALTSVC_H3
+};
+
 /*
  * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
  * Global DNS cache is general badness. Do not use. This will be removed in
@@ -62,36 +70,6 @@ struct connectdata;
  */
 struct Curl_hash *Curl_global_host_cache_init(void);
 
-#ifdef USE_HTTPSRR
-
-#define CURL_MAXLEN_host_name 253
-
-struct Curl_https_rrinfo {
-  size_t len; /* raw encoded length */
-  unsigned char *val; /* raw encoded octets */
-  /*
-   * fields from HTTPS RR, with the mandatory fields
-   * first (priority, target), then the others in the
-   * order of the keytag numbers defined at
-   * https://datatracker.ietf.org/doc/html/rfc9460#section-14.3.2
-   */
-  uint16_t priority;
-  char *target;
-  char *alpns; /* keytag = 1 */
-  bool no_def_alpn; /* keytag = 2 */
-  /*
-   * we do not support ports (keytag = 3) as we do not support
-   * port-switching yet
-   */
-  unsigned char *ipv4hints; /* keytag = 4 */
-  size_t ipv4hints_len;
-  unsigned char *echconfiglist; /* keytag = 5 */
-  size_t echconfiglist_len;
-  unsigned char *ipv6hints; /* keytag = 6 */
-  size_t ipv6hints_len;
-};
-#endif
-
 struct Curl_dns_entry {
   struct Curl_addrinfo *addr;
 #ifdef USE_HTTPSRR

+ 37 - 28
lib/hsts.c

@@ -41,6 +41,7 @@
 #include "rename.h"
 #include "share.h"
 #include "strdup.h"
+#include "strparse.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -48,10 +49,8 @@
 #include "memdebug.h"
 
 #define MAX_HSTS_LINE 4095
-#define MAX_HSTS_HOSTLEN 256
-#define MAX_HSTS_HOSTLENSTR "256"
-#define MAX_HSTS_DATELEN 64
-#define MAX_HSTS_DATELENSTR "64"
+#define MAX_HSTS_HOSTLEN 2048
+#define MAX_HSTS_DATELEN 256
 #define UNLIMITED "unlimited"
 
 #if defined(DEBUGBUILD) || defined(UNITTESTS)
@@ -109,14 +108,13 @@ void Curl_hsts_cleanup(struct hsts **hp)
 
 static CURLcode hsts_create(struct hsts *h,
                             const char *hostname,
+                            size_t hlen,
                             bool subdomains,
                             curl_off_t expires)
 {
-  size_t hlen;
   DEBUGASSERT(h);
   DEBUGASSERT(hostname);
 
-  hlen = strlen(hostname);
   if(hlen && (hostname[hlen - 1] == '.'))
     /* strip off any trailing dot */
     --hlen;
@@ -150,6 +148,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
   bool subdomains = FALSE;
   struct stsentry *sts;
   time_t now = time(NULL);
+  size_t hlen = strlen(hostname);
 
   if(Curl_host_is_ipnum(hostname))
     /* "explicit IP address identification of all forms is excluded."
@@ -218,7 +217,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
 
   if(!expires) {
     /* remove the entry if present verbatim (without subdomain match) */
-    sts = Curl_hsts(h, hostname, FALSE);
+    sts = Curl_hsts(h, hostname, hlen, FALSE);
     if(sts) {
       Curl_node_remove(&sts->node);
       hsts_free(sts);
@@ -233,14 +232,14 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
     expires += now;
 
   /* check if it already exists */
-  sts = Curl_hsts(h, hostname, FALSE);
+  sts = Curl_hsts(h, hostname, hlen, FALSE);
   if(sts) {
     /* just update these fields */
     sts->expires = expires;
     sts->includeSubDomains = subdomains;
   }
   else
-    return hsts_create(h, hostname, subdomains, expires);
+    return hsts_create(h, hostname, hlen, subdomains, expires);
 
   return CURLE_OK;
 }
@@ -252,12 +251,11 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
  * attempted.
  */
 struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
-                           bool subdomain)
+                           size_t hlen, bool subdomain)
 {
   struct stsentry *bestsub = NULL;
   if(h) {
     time_t now = time(NULL);
-    size_t hlen = strlen(hostname);
     struct Curl_llist_node *e;
     struct Curl_llist_node *n;
     size_t blen = 0;
@@ -424,29 +422,40 @@ static CURLcode hsts_add(struct hsts *h, char *line)
      example.com "20191231 10:00:00"
      .example.net "20191231 10:00:00"
    */
-  char host[MAX_HSTS_HOSTLEN + 1];
-  char date[MAX_HSTS_DATELEN + 1];
-  int rc;
-
-  rc = sscanf(line,
-              "%" MAX_HSTS_HOSTLENSTR "s \"%" MAX_HSTS_DATELENSTR "[^\"]\"",
-              host, date);
-  if(2 == rc) {
-    time_t expires = strcmp(date, UNLIMITED) ? Curl_getdate_capped(date) :
-      TIME_T_MAX;
+  struct Curl_str host;
+  struct Curl_str date;
+
+  if(Curl_str_word(&line, &host, MAX_HSTS_HOSTLEN) ||
+     Curl_str_singlespace(&line) ||
+     Curl_str_quotedword(&line, &date, MAX_HSTS_DATELEN) ||
+     Curl_str_newline(&line))
+    ;
+  else {
     CURLcode result = CURLE_OK;
-    char *p = host;
     bool subdomain = FALSE;
     struct stsentry *e;
-    if(p[0] == '.') {
-      p++;
+    char dbuf[MAX_HSTS_DATELEN + 1];
+    time_t expires;
+
+    /* The date parser works on a null terminated string. The maximum length
+       is upheld by Curl_str_quotedword(). */
+    memcpy(dbuf, date.str, date.len);
+    dbuf[date.len] = 0;
+
+    expires = strcmp(dbuf, UNLIMITED) ? Curl_getdate_capped(dbuf) :
+      TIME_T_MAX;
+
+    if(host.str[0] == '.') {
+      host.str++;
+      host.len--;
       subdomain = TRUE;
     }
     /* only add it if not already present */
-    e = Curl_hsts(h, p, subdomain);
+    e = Curl_hsts(h, host.str, host.len, subdomain);
     if(!e)
-      result = hsts_create(h, p, subdomain, expires);
-    else if(strcasecompare(p, e->host)) {
+      result = hsts_create(h, host.str, host.len, subdomain, expires);
+    else if((strlen(e->host) == host.len) &&
+            strncasecompare(host.str, e->host, host.len)) {
       /* the same hostname, use the largest expire time */
       if(expires > e->expires)
         e->expires = expires;
@@ -488,7 +497,7 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
           expires = Curl_getdate_capped(e.expire);
         else
           expires = TIME_T_MAX; /* the end of time */
-        result = hsts_create(h, e.name,
+        result = hsts_create(h, e.name, strlen(e.name),
                              /* bitfield to bool conversion: */
                              e.includeSubDomains ? TRUE : FALSE,
                              expires);

+ 1 - 1
lib/hsts.h

@@ -52,7 +52,7 @@ void Curl_hsts_cleanup(struct hsts **hp);
 CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
                          const char *sts);
 struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
-                           bool subdomain);
+                           size_t hlen, bool subdomain);
 CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
                         const char *file);
 CURLcode Curl_hsts_loadfile(struct Curl_easy *data,

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 430 - 137
lib/http.c


Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels