ソースを参照

curl 2025-02-05 (34cf9d54)

Code extracted from:

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

at commit 34cf9d54a46598c44938aa7598820484d7af7133 (curl-8_12_0).
Curl Upstream 8 ヶ月 前
コミット
48b13baebc
100 ファイル変更3434 行追加3956 行削除
  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_*(),
   # e.g. curl_easy_perform_ev() or curl_dbg_*(),
   # so disable symbol hiding for debug builds and for memory tracking.
   # so disable symbol hiding for debug builds and for memory tracking.
   set(CURL_HIDDEN_SYMBOLS OFF)
   set(CURL_HIDDEN_SYMBOLS OFF)
+elseif(DOS OR AMIGA)
+  set(CURL_HIDDEN_SYMBOLS OFF)
 endif()
 endif()
 
 
 set(CURL_HIDES_PRIVATE_SYMBOLS FALSE)
 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(CURL_HIDDEN_SYMBOLS)
   if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT MSVC)
   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;
   int flags = 0;
   if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK))
   if(0 != fcntl(0, F_SETFL, flags | O_NONBLOCK))
     return 1;
     return 1;
-  ;
   return 0;
   return 0;
 }
 }
 #endif
 #endif
@@ -147,24 +146,21 @@ int main(void) { return 0; }
 #endif
 #endif
 
 
 #ifdef HAVE_FILE_OFFSET_BITS
 #ifdef HAVE_FILE_OFFSET_BITS
-#ifdef _FILE_OFFSET_BITS
 #undef _FILE_OFFSET_BITS
 #undef _FILE_OFFSET_BITS
-#endif
 #define _FILE_OFFSET_BITS 64
 #define _FILE_OFFSET_BITS 64
 #include <sys/types.h>
 #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))
 #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; }
 int main(void) { return 0; }
 #endif
 #endif
 
 
 #ifdef HAVE_IOCTLSOCKET
 #ifdef HAVE_IOCTLSOCKET
-/* includes start */
 #ifdef _WIN32
 #ifdef _WIN32
 #  include <winsock2.h>
 #  include <winsock2.h>
 #endif
 #endif
@@ -180,10 +176,7 @@ int main(void)
 #endif
 #endif
 
 
 #ifdef HAVE_IOCTLSOCKET_CAMEL
 #ifdef HAVE_IOCTLSOCKET_CAMEL
-/* includes start */
-#ifdef _WIN32
-#  include <winsock2.h>
-#endif
+#include <proto/bsdsocket.h>
 int main(void)
 int main(void)
 {
 {
   /* IoctlSocket source code */
   /* IoctlSocket source code */
@@ -195,9 +188,9 @@ int main(void)
 #endif
 #endif
 
 
 #ifdef HAVE_IOCTLSOCKET_CAMEL_FIONBIO
 #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
 #endif
 int main(void)
 int main(void)
 {
 {
@@ -211,7 +204,6 @@ int main(void)
 #endif
 #endif
 
 
 #ifdef HAVE_IOCTLSOCKET_FIONBIO
 #ifdef HAVE_IOCTLSOCKET_FIONBIO
-/* includes start */
 #ifdef _WIN32
 #ifdef _WIN32
 #  include <winsock2.h>
 #  include <winsock2.h>
 #endif
 #endif
@@ -227,7 +219,6 @@ int main(void)
 
 
 #ifdef HAVE_IOCTL_FIONBIO
 #ifdef HAVE_IOCTL_FIONBIO
 /* headers for FIONBIO test */
 /* headers for FIONBIO test */
-/* includes start */
 #ifdef HAVE_SYS_TYPES_H
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #  include <sys/types.h>
 #endif
 #endif
@@ -255,7 +246,6 @@ int main(void)
 
 
 #ifdef HAVE_IOCTL_SIOCGIFADDR
 #ifdef HAVE_IOCTL_SIOCGIFADDR
 /* headers for FIONBIO test */
 /* headers for FIONBIO test */
-/* includes start */
 #ifdef HAVE_SYS_TYPES_H
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #  include <sys/types.h>
 #endif
 #endif
@@ -283,18 +273,15 @@ int main(void)
 #endif
 #endif
 
 
 #ifdef HAVE_SETSOCKOPT_SO_NONBLOCK
 #ifdef HAVE_SETSOCKOPT_SO_NONBLOCK
-/* includes start */
 #ifdef _WIN32
 #ifdef _WIN32
 #  include <winsock2.h>
 #  include <winsock2.h>
 #endif
 #endif
-/* includes start */
 #ifdef HAVE_SYS_TYPES_H
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #  include <sys/types.h>
 #endif
 #endif
 #ifdef HAVE_SYS_SOCKET_H
 #ifdef HAVE_SYS_SOCKET_H
 #  include <sys/socket.h>
 #  include <sys/socket.h>
 #endif
 #endif
-/* includes end */
 int main(void)
 int main(void)
 {
 {
   if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0))
   if(0 != setsockopt(0, SOL_SOCKET, SO_NONBLOCK, 0, 0))
@@ -372,7 +359,6 @@ int main(void)
 #endif
 #endif
 
 
 #ifdef HAVE_ATOMIC
 #ifdef HAVE_ATOMIC
-/* includes start */
 #ifdef HAVE_SYS_TYPES_H
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
 #  include <sys/types.h>
 #endif
 #endif
@@ -382,8 +368,6 @@ int main(void)
 #ifdef HAVE_STDATOMIC_H
 #ifdef HAVE_STDATOMIC_H
 #  include <stdatomic.h>
 #  include <stdatomic.h>
 #endif
 #endif
-/* includes end */
-
 int main(void)
 int main(void)
 {
 {
   _Atomic int i = 1;
   _Atomic int i = 1;
@@ -393,14 +377,12 @@ int main(void)
 #endif
 #endif
 
 
 #ifdef HAVE_WIN32_WINNT
 #ifdef HAVE_WIN32_WINNT
-/* includes start */
 #ifdef _WIN32
 #ifdef _WIN32
 #  ifndef NOGDI
 #  ifndef NOGDI
-#    define NOGDI
+#  define NOGDI
 #  endif
 #  endif
 #  include <windows.h>
 #  include <windows.h>
 #endif
 #endif
-/* includes end */
 
 
 #define enquote(x) #x
 #define enquote(x) #x
 #define expand(x) enquote(x)
 #define expand(x) enquote(x)
@@ -411,3 +393,20 @@ int main(void)
   return 0;
   return 0;
 }
 }
 #endif
 #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_FOUND`:          System has brotli.
 # - `BROTLI_INCLUDE_DIRS`:   The brotli include directories.
 # - `BROTLI_INCLUDE_DIRS`:   The brotli include directories.
 # - `BROTLI_LIBRARIES`:      The brotli library names.
 # - `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.
 # - `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)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_BROTLI "libbrotlidec")
+  pkg_check_modules(BROTLI "libbrotlicommon")
+  pkg_check_modules(BROTLIDEC ${BROTLI_PC_REQUIRES})
 endif()
 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()
 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_FOUND`:         System has c-ares.
 # - `CARES_INCLUDE_DIRS`:  The c-ares include directories.
 # - `CARES_INCLUDE_DIRS`:  The c-ares include directories.
 # - `CARES_LIBRARIES`:     The c-ares library names.
 # - `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.
 # - `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)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_CARES "libcares")
+  pkg_check_modules(CARES ${CARES_PC_REQUIRES})
 endif()
 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()
 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}")
       string(REGEX REPLACE " +-([^I][^ \\t;]*)" ";-\\1" _GSS_CFLAGS "${_GSS_CFLAGS}")
 
 
       foreach(_flag IN LISTS _GSS_CFLAGS)
       foreach(_flag IN LISTS _GSS_CFLAGS)
-        if(_flag MATCHES "^-I.*")
+        if(_flag MATCHES "^-I")
           string(REGEX REPLACE "^-I" "" _val "${_flag}")
           string(REGEX REPLACE "^-I" "" _val "${_flag}")
           list(APPEND _GSS_INCLUDE_DIRS "${_val}")
           list(APPEND _GSS_INCLUDE_DIRS "${_val}")
         else()
         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}")
       string(REGEX REPLACE " +-([^Ll][^ \\t;]*)" ";-\\1" _gss_lib_flags "${_gss_lib_flags}")
 
 
       foreach(_flag IN LISTS _gss_lib_flags)
       foreach(_flag IN LISTS _gss_lib_flags)
-        if(_flag MATCHES "^-l.*")
+        if(_flag MATCHES "^-l")
           string(REGEX REPLACE "^-l" "" _val "${_flag}")
           string(REGEX REPLACE "^-l" "" _val "${_flag}")
           list(APPEND _GSS_LIBRARIES "${_val}")
           list(APPEND _GSS_LIBRARIES "${_val}")
-        elseif(_flag MATCHES "^-L.*")
+        elseif(_flag MATCHES "^-L")
           string(REGEX REPLACE "^-L" "" _val "${_flag}")
           string(REGEX REPLACE "^-L" "" _val "${_flag}")
           list(APPEND _GSS_LIBRARY_DIRS "${_val}")
           list(APPEND _GSS_LIBRARY_DIRS "${_val}")
         endif()
         endif()
@@ -156,7 +156,7 @@ if(NOT _GSS_FOUND)  # Not found by pkg-config. Let us take more traditional appr
     if(_gss_configure_failed)
     if(_gss_configure_failed)
       set(GSS_FLAVOUR "Heimdal")  # most probably, should not really matter
       set(GSS_FLAVOUR "Heimdal")  # most probably, should not really matter
     else()
     else()
-      if(_gss_vendor MATCHES ".*H|heimdal.*")
+      if(_gss_vendor MATCHES "H|heimdal")
         set(GSS_FLAVOUR "Heimdal")
         set(GSS_FLAVOUR "Heimdal")
       else()
       else()
         set(GSS_FLAVOUR "MIT")
         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
     if(_GSS_INCLUDE_DIRS)  # jay, we have found something
       cmake_push_check_state()
       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)
       check_include_files("gssapi/gssapi_generic.h;gssapi/gssapi_krb5.h" _gss_have_mit_headers)
 
 
       if(_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_INCLUDE_DIRS`:  The libgsasl include directories.
 # - `LIBGSASL_LIBRARIES`:     The libgsasl library names.
 # - `LIBGSASL_LIBRARIES`:     The libgsasl library names.
 # - `LIBGSASL_LIBRARY_DIRS`:  The libgsasl library directories.
 # - `LIBGSASL_LIBRARY_DIRS`:  The libgsasl library directories.
+# - `LIBGSASL_PC_REQUIRES`:   The libgsasl pkg-config packages.
 # - `LIBGSASL_CFLAGS`:        Required compiler flags.
 # - `LIBGSASL_CFLAGS`:        Required compiler flags.
 # - `LIBGSASL_VERSION`:       Version of libgsasl.
 # - `LIBGSASL_VERSION`:       Version of libgsasl.
 
 
+set(LIBGSASL_PC_REQUIRES "libgsasl")
+
 if(CURL_USE_PKGCONFIG AND
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBGSASL_INCLUDE_DIR AND
    NOT DEFINED LIBGSASL_INCLUDE_DIR AND
    NOT DEFINED LIBGSASL_LIBRARY)
    NOT DEFINED LIBGSASL_LIBRARY)
   find_package(PkgConfig QUIET)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(LIBGSASL "libgsasl")
+  pkg_check_modules(LIBGSASL ${LIBGSASL_PC_REQUIRES})
 endif()
 endif()
 
 
 if(LIBGSASL_FOUND)
 if(LIBGSASL_FOUND)

+ 4 - 1
CMake/FindLibidn2.cmake

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

+ 37 - 35
CMake/FindLibpsl.cmake

@@ -33,48 +33,50 @@
 # - `LIBPSL_FOUND`:         System has libpsl.
 # - `LIBPSL_FOUND`:         System has libpsl.
 # - `LIBPSL_INCLUDE_DIRS`:  The libpsl include directories.
 # - `LIBPSL_INCLUDE_DIRS`:  The libpsl include directories.
 # - `LIBPSL_LIBRARIES`:     The libpsl library names.
 # - `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.
 # - `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)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_LIBPSL "libpsl")
+  pkg_check_modules(LIBPSL ${LIBPSL_PC_REQUIRES})
 endif()
 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()
 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:
 # 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:
 # 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
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBSSH_INCLUDE_DIR AND
    NOT DEFINED LIBSSH_INCLUDE_DIR AND
    NOT DEFINED LIBSSH_LIBRARY)
    NOT DEFINED LIBSSH_LIBRARY)
   find_package(PkgConfig QUIET)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(LIBSSH "libssh")
+  pkg_check_modules(LIBSSH ${LIBSSH_PC_REQUIRES})
 endif()
 endif()
 
 
 if(LIBSSH_FOUND)
 if(LIBSSH_FOUND)

+ 37 - 35
CMake/FindLibssh2.cmake

@@ -33,48 +33,50 @@
 # - `LIBSSH2_FOUND`:         System has libssh2.
 # - `LIBSSH2_FOUND`:         System has libssh2.
 # - `LIBSSH2_INCLUDE_DIRS`:  The libssh2 include directories.
 # - `LIBSSH2_INCLUDE_DIRS`:  The libssh2 include directories.
 # - `LIBSSH2_LIBRARIES`:     The libssh2 library names.
 # - `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.
 # - `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)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_LIBSSH2 "libssh2")
+  pkg_check_modules(LIBSSH2 ${LIBSSH2_PC_REQUIRES})
 endif()
 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()
 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_INCLUDE_DIRS`:  The libuv include directories.
 # - `LIBUV_LIBRARIES`:     The libuv library names.
 # - `LIBUV_LIBRARIES`:     The libuv library names.
 # - `LIBUV_LIBRARY_DIRS`:  The libuv library directories.
 # - `LIBUV_LIBRARY_DIRS`:  The libuv library directories.
+# - `LIBUV_PC_REQUIRES`:   The libuv pkg-config packages.
 # - `LIBUV_CFLAGS`:        Required compiler flags.
 # - `LIBUV_CFLAGS`:        Required compiler flags.
 # - `LIBUV_VERSION`:       Version of libuv.
 # - `LIBUV_VERSION`:       Version of libuv.
 
 
+set(LIBUV_PC_REQUIRES "libuv")
+
 if(CURL_USE_PKGCONFIG AND
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED LIBUV_INCLUDE_DIR AND
    NOT DEFINED LIBUV_INCLUDE_DIR AND
    NOT DEFINED LIBUV_LIBRARY)
    NOT DEFINED LIBUV_LIBRARY)
   find_package(PkgConfig QUIET)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(LIBUV "libuv")
+  pkg_check_modules(LIBUV ${LIBUV_PC_REQUIRES})
 endif()
 endif()
 
 
 if(LIBUV_FOUND)
 if(LIBUV_FOUND)

+ 5 - 2
CMake/FindMSH3.cmake

@@ -38,18 +38,21 @@
 # - `MSH3_CFLAGS`:        Required compiler flags.
 # - `MSH3_CFLAGS`:        Required compiler flags.
 # - `MSH3_VERSION`:       Version of msh3.
 # - `MSH3_VERSION`:       Version of msh3.
 
 
+set(MSH3_PC_REQUIRES "libmsh3")
+
 if(CURL_USE_PKGCONFIG AND
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED MSH3_INCLUDE_DIR AND
    NOT DEFINED MSH3_INCLUDE_DIR AND
    NOT DEFINED MSH3_LIBRARY)
    NOT DEFINED MSH3_LIBRARY)
   find_package(PkgConfig QUIET)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(MSH3 "libmsh3")
+  pkg_check_modules(MSH3 ${MSH3_PC_REQUIRES})
 endif()
 endif()
 
 
 if(MSH3_FOUND)
 if(MSH3_FOUND)
-  set(MSH3_PC_REQUIRES "libmsh3")
   string(REPLACE ";" " " MSH3_CFLAGS "${MSH3_CFLAGS}")
   string(REPLACE ";" " " MSH3_CFLAGS "${MSH3_CFLAGS}")
   message(STATUS "Found MSH3 (via pkg-config): ${MSH3_INCLUDE_DIRS} (found version \"${MSH3_VERSION}\")")
   message(STATUS "Found MSH3 (via pkg-config): ${MSH3_INCLUDE_DIRS} (found version \"${MSH3_VERSION}\")")
 else()
 else()
+  set(MSH3_PC_REQUIRES "")  # Depend on pkg-config only when found via pkg-config
+
   find_path(MSH3_INCLUDE_DIR NAMES "msh3.h")
   find_path(MSH3_INCLUDE_DIR NAMES "msh3.h")
   find_library(MSH3_LIBRARY NAMES "msh3")
   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)
   unset(MBEDTLS_INCLUDE_DIRS)
 endif()
 endif()
 
 
+set(MBEDTLS_PC_REQUIRES "mbedtls")
+
 if(CURL_USE_PKGCONFIG AND
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED MBEDTLS_INCLUDE_DIR AND
    NOT DEFINED MBEDTLS_INCLUDE_DIR AND
    NOT DEFINED MBEDTLS_LIBRARY AND
    NOT DEFINED MBEDTLS_LIBRARY AND
    NOT DEFINED MBEDX509_LIBRARY AND
    NOT DEFINED MBEDX509_LIBRARY AND
    NOT DEFINED MBEDCRYPTO_LIBRARY)
    NOT DEFINED MBEDCRYPTO_LIBRARY)
   find_package(PkgConfig QUIET)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(MBEDTLS "mbedtls")
+  pkg_check_modules(MBEDTLS ${MBEDTLS_PC_REQUIRES})
   pkg_check_modules(MBEDX509 "mbedx509")
   pkg_check_modules(MBEDX509 "mbedx509")
   pkg_check_modules(MBEDCRYPTO "mbedcrypto")
   pkg_check_modules(MBEDCRYPTO "mbedcrypto")
 endif()
 endif()
 
 
 if(MBEDTLS_FOUND AND MBEDX509_FOUND AND MBEDCRYPTO_FOUND)
 if(MBEDTLS_FOUND AND MBEDX509_FOUND AND MBEDCRYPTO_FOUND)
   list(APPEND MBEDTLS_LIBRARIES ${MBEDX509_LIBRARIES} ${MBEDCRYPTO_LIBRARIES})
   list(APPEND MBEDTLS_LIBRARIES ${MBEDX509_LIBRARIES} ${MBEDCRYPTO_LIBRARIES})
+  list(REVERSE MBEDTLS_LIBRARIES)
   list(REMOVE_DUPLICATES MBEDTLS_LIBRARIES)
   list(REMOVE_DUPLICATES MBEDTLS_LIBRARIES)
-  set(MBEDTLS_PC_REQUIRES "mbedtls")
+  list(REVERSE MBEDTLS_LIBRARIES)
   string(REPLACE ";" " " MBEDTLS_CFLAGS "${MBEDTLS_CFLAGS}")
   string(REPLACE ";" " " MBEDTLS_CFLAGS "${MBEDTLS_CFLAGS}")
   message(STATUS "Found MbedTLS (via pkg-config): ${MBEDTLS_INCLUDE_DIRS} (found version \"${MBEDTLS_VERSION}\")")
   message(STATUS "Found MbedTLS (via pkg-config): ${MBEDTLS_INCLUDE_DIRS} (found version \"${MBEDTLS_VERSION}\")")
 else()
 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_path(MBEDTLS_INCLUDE_DIR NAMES "mbedtls/ssl.h")
   find_library(MBEDTLS_LIBRARY NAMES "mbedtls" "libmbedtls")
   find_library(MBEDTLS_LIBRARY NAMES "mbedtls" "libmbedtls")
   find_library(MBEDX509_LIBRARY NAMES "mbedx509" "libmbedx509")
   find_library(MBEDX509_LIBRARY NAMES "mbedx509" "libmbedx509")

+ 37 - 35
CMake/FindNGHTTP2.cmake

@@ -33,48 +33,50 @@
 # - `NGHTTP2_FOUND`:         System has nghttp2.
 # - `NGHTTP2_FOUND`:         System has nghttp2.
 # - `NGHTTP2_INCLUDE_DIRS`:  The nghttp2 include directories.
 # - `NGHTTP2_INCLUDE_DIRS`:  The nghttp2 include directories.
 # - `NGHTTP2_LIBRARIES`:     The nghttp2 library names.
 # - `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.
 # - `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)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_NGHTTP2 "libnghttp2")
+  pkg_check_modules(NGHTTP2 ${NGHTTP2_PC_REQUIRES})
 endif()
 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()
 endif()
-
-mark_as_advanced(NGHTTP2_INCLUDE_DIR NGHTTP2_LIBRARY)

+ 37 - 35
CMake/FindNGHTTP3.cmake

@@ -33,48 +33,50 @@
 # - `NGHTTP3_FOUND`:         System has nghttp3.
 # - `NGHTTP3_FOUND`:         System has nghttp3.
 # - `NGHTTP3_INCLUDE_DIRS`:  The nghttp3 include directories.
 # - `NGHTTP3_INCLUDE_DIRS`:  The nghttp3 include directories.
 # - `NGHTTP3_LIBRARIES`:     The nghttp3 library names.
 # - `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.
 # - `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)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_NGHTTP3 "libnghttp3")
+  pkg_check_modules(NGHTTP3 ${NGHTTP3_PC_REQUIRES})
 endif()
 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()
 endif()
-
-mark_as_advanced(NGHTTP3_INCLUDE_DIR NGHTTP3_LIBRARY)

+ 63 - 55
CMake/FindNGTCP2.cmake

@@ -41,36 +41,11 @@
 # - `NGTCP2_FOUND`:         System has ngtcp2.
 # - `NGTCP2_FOUND`:         System has ngtcp2.
 # - `NGTCP2_INCLUDE_DIRS`:  The ngtcp2 include directories.
 # - `NGTCP2_INCLUDE_DIRS`:  The ngtcp2 include directories.
 # - `NGTCP2_LIBRARIES`:     The ngtcp2 library names.
 # - `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.
 # - `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)
 if(NGTCP2_FIND_COMPONENTS)
   set(_ngtcp2_crypto_backend "")
   set(_ngtcp2_crypto_backend "")
   foreach(_component IN LISTS NGTCP2_FIND_COMPONENTS)
   foreach(_component IN LISTS NGTCP2_FIND_COMPONENTS)
@@ -83,40 +58,73 @@ if(NGTCP2_FIND_COMPONENTS)
   endforeach()
   endforeach()
 
 
   if(_ngtcp2_crypto_backend)
   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)
     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_${_ngtcp2_crypto_backend}_FOUND TRUE)
-      set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library}_LIBRARY})
+      set(NGTCP2_CRYPTO_LIBRARY ${${_crypto_library_upper}_LIBRARY})
     endif()
     endif()
   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_INCLUDE_DIRS`:  The nettle include directories.
 # - `NETTLE_LIBRARIES`:     The nettle library names.
 # - `NETTLE_LIBRARIES`:     The nettle library names.
 # - `NETTLE_LIBRARY_DIRS`:  The nettle library directories.
 # - `NETTLE_LIBRARY_DIRS`:  The nettle library directories.
+# - `NETTLE_PC_REQUIRES`:   The nettle pkg-config packages.
 # - `NETTLE_CFLAGS`:        Required compiler flags.
 # - `NETTLE_CFLAGS`:        Required compiler flags.
 # - `NETTLE_VERSION`:       Version of nettle.
 # - `NETTLE_VERSION`:       Version of nettle.
 
 
+set(NETTLE_PC_REQUIRES "nettle")
+
 if(CURL_USE_PKGCONFIG AND
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED NETTLE_INCLUDE_DIR AND
    NOT DEFINED NETTLE_INCLUDE_DIR AND
    NOT DEFINED NETTLE_LIBRARY)
    NOT DEFINED NETTLE_LIBRARY)
   find_package(PkgConfig QUIET)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(NETTLE "nettle")
+  pkg_check_modules(NETTLE ${NETTLE_PC_REQUIRES})
 endif()
 endif()
 
 
 if(NETTLE_FOUND)
 if(NETTLE_FOUND)

+ 4 - 1
CMake/FindQuiche.cmake

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

+ 35 - 30
CMake/FindRustls.cmake

@@ -38,18 +38,21 @@
 # - `RUSTLS_CFLAGS`:        Required compiler flags.
 # - `RUSTLS_CFLAGS`:        Required compiler flags.
 # - `RUSTLS_VERSION`:       Version of Rustls.
 # - `RUSTLS_VERSION`:       Version of Rustls.
 
 
+set(RUSTLS_PC_REQUIRES "rustls")
+
 if(CURL_USE_PKGCONFIG AND
 if(CURL_USE_PKGCONFIG AND
    NOT DEFINED RUSTLS_INCLUDE_DIR AND
    NOT DEFINED RUSTLS_INCLUDE_DIR AND
    NOT DEFINED RUSTLS_LIBRARY)
    NOT DEFINED RUSTLS_LIBRARY)
   find_package(PkgConfig QUIET)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(RUSTLS "rustls")
+  pkg_check_modules(RUSTLS ${RUSTLS_PC_REQUIRES})
 endif()
 endif()
 
 
 if(RUSTLS_FOUND)
 if(RUSTLS_FOUND)
-  set(RUSTLS_PC_REQUIRES "rustls")
   string(REPLACE ";" " " RUSTLS_CFLAGS "${RUSTLS_CFLAGS}")
   string(REPLACE ";" " " RUSTLS_CFLAGS "${RUSTLS_CFLAGS}")
   message(STATUS "Found Rustls (via pkg-config): ${RUSTLS_INCLUDE_DIRS} (found version \"${RUSTLS_VERSION}\")")
   message(STATUS "Found Rustls (via pkg-config): ${RUSTLS_INCLUDE_DIRS} (found version \"${RUSTLS_VERSION}\")")
 else()
 else()
+  set(RUSTLS_PC_REQUIRES "")  # Depend on pkg-config only when found via pkg-config
+
   find_path(RUSTLS_INCLUDE_DIR NAMES "rustls.h")
   find_path(RUSTLS_INCLUDE_DIR NAMES "rustls.h")
   find_library(RUSTLS_LIBRARY NAMES "rustls")
   find_library(RUSTLS_LIBRARY NAMES "rustls")
 
 
@@ -68,36 +71,38 @@ else()
   mark_as_advanced(RUSTLS_INCLUDE_DIR RUSTLS_LIBRARY)
   mark_as_advanced(RUSTLS_INCLUDE_DIR RUSTLS_LIBRARY)
 endif()
 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()
   endif()
-  mark_as_advanced(_math_library)
 endif()
 endif()

+ 9 - 6
CMake/FindWolfSSL.cmake

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

+ 47 - 45
CMake/FindZstd.cmake

@@ -33,6 +33,9 @@
 # - `ZSTD_FOUND`:         System has zstd.
 # - `ZSTD_FOUND`:         System has zstd.
 # - `ZSTD_INCLUDE_DIRS`:  The zstd include directories.
 # - `ZSTD_INCLUDE_DIRS`:  The zstd include directories.
 # - `ZSTD_LIBRARIES`:     The zstd library names.
 # - `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.
 # - `ZSTD_VERSION`:       Version of zstd.
 
 
 if(DEFINED Zstd_INCLUDE_DIR AND NOT DEFINED ZSTD_INCLUDE_DIR)
 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}")
   set(ZSTD_LIBRARY "${Zstd_LIBRARY}")
 endif()
 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)
   find_package(PkgConfig QUIET)
-  pkg_check_modules(PC_ZSTD "libzstd")
+  pkg_check_modules(ZSTD ${ZSTD_PC_REQUIRES})
 endif()
 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()
 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
 # This macro is intended to be called multiple times with a sequence of
 # possibly dependent header files.  Some headers depend on others to be
 # possibly dependent header files.  Some headers depend on others to be
 # compiled correctly.
 # compiled correctly.
-macro(check_include_file_concat _file _variable)
+macro(check_include_file_concat_curl _file _variable)
   check_include_files("${CURL_INCLUDES};${_file}" ${_variable})
   check_include_files("${CURL_INCLUDES};${_file}" ${_variable})
   if(${_variable})
   if(${_variable})
     list(APPEND CURL_INCLUDES ${_file})
     list(APPEND CURL_INCLUDES ${_file})
@@ -62,21 +62,25 @@ macro(curl_internal_test _curl_test)
   endif()
   endif()
 endmacro()
 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()
   endif()
 endmacro()
 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)
 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()
 endmacro()

+ 11 - 11
CMake/OtherTests.cmake

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

+ 44 - 30
CMake/PickyWarnings.cmake

@@ -23,17 +23,15 @@
 ###########################################################################
 ###########################################################################
 include(CheckCCompilerFlag)
 include(CheckCCompilerFlag)
 
 
-unset(_picky)
+set(_picky "")
 
 
 if(CURL_WERROR AND
 if(CURL_WERROR AND
    ((CMAKE_COMPILER_IS_GNUCC 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_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
      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"))
    CMAKE_C_COMPILER_ID MATCHES "Clang"))
   list(APPEND _picky "-pedantic-errors")
   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()
 endif()
 
 
 if(APPLE AND
 if(APPLE AND
@@ -77,7 +75,6 @@ if(PICKY_COMPILER)
     list(APPEND _picky_enable
     list(APPEND _picky_enable
       -Wbad-function-cast                  # clang  2.7  gcc  2.95
       -Wbad-function-cast                  # clang  2.7  gcc  2.95
       -Wconversion                         # 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-declarations               # clang  1.0  gcc  2.7
       -Wmissing-prototypes                 # clang  1.0  gcc  1.0
       -Wmissing-prototypes                 # clang  1.0  gcc  1.0
       -Wnested-externs                     # clang  1.0  gcc  2.7
       -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-field-initializers         # clang  2.7  gcc  4.1
       -Wmissing-noreturn                   # 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-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
       -Wno-system-headers                  # clang  1.0  gcc  3.0
     # -Wpadded                             # clang  2.9  gcc  4.1               # Not used: We cannot change public structs
     # -Wpadded                             # clang  2.9  gcc  4.1               # Not used: We cannot change public structs
       -Wold-style-definition               # clang  2.7  gcc  3.4
       -Wold-style-definition               # clang  2.7  gcc  3.4
       -Wredundant-decls                    # clang  2.7  gcc  4.1
       -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
       -Wstrict-prototypes                  # clang  1.0  gcc  3.3
     # -Wswitch-enum                        # clang  2.7  gcc  4.1               # Not used: It basically disallows default case
     # -Wswitch-enum                        # clang  2.7  gcc  4.1               # Not used: It basically disallows default case
       -Wtype-limits                        # clang  2.7  gcc  4.3
       -Wtype-limits                        # clang  2.7  gcc  4.3
@@ -121,13 +117,6 @@ if(PICKY_COMPILER)
       -Wvla                                # clang  2.8  gcc  4.3
       -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")
     if(CMAKE_C_COMPILER_ID MATCHES "Clang")
       list(APPEND _picky_enable
       list(APPEND _picky_enable
         ${_picky_common_old}
         ${_picky_common_old}
@@ -137,17 +126,20 @@ if(PICKY_COMPILER)
       )
       )
       if(NOT MSVC)
       if(NOT MSVC)
         list(APPEND _picky_enable
         list(APPEND _picky_enable
-          -Wlanguage-extension-token         # clang  3.0  # Avoid for clang-cl to allow __int64
+          -Wlanguage-extension-token       # clang  3.0
         )
         )
       endif()
       endif()
       # Enable based on compiler version
       # Enable based on compiler version
       if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.6) OR
       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))
          (CMAKE_C_COMPILER_ID STREQUAL "AppleClang" AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 6.3))
         list(APPEND _picky_enable
         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
           -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
           -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()
       endif()
       if((CMAKE_C_COMPILER_ID STREQUAL "Clang"      AND NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 3.9) OR
       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()
       endif()
     else()  # gcc
     else()  # gcc
-      list(APPEND _picky_detect
-        ${_picky_common}
-      )
       # Enable based on compiler version
       # Enable based on compiler version
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3)
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.3)
         list(APPEND _picky_enable
         list(APPEND _picky_enable
@@ -181,8 +170,8 @@ if(PICKY_COMPILER)
           -Wclobbered                      #             gcc  4.3
           -Wclobbered                      #             gcc  4.3
           -Wmissing-parameter-type         #             gcc  4.3
           -Wmissing-parameter-type         #             gcc  4.3
           -Wold-style-declaration          #             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
           -Wstrict-aliasing=3              #             gcc  4.0
-          -Wtrampolines                    #             gcc  4.3
         )
         )
       endif()
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND MINGW)
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.5 AND MINGW)
@@ -192,7 +181,9 @@ if(PICKY_COMPILER)
       endif()
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 4.8)
         list(APPEND _picky_enable
         list(APPEND _picky_enable
+          -Wdouble-promotion               # clang  3.6  gcc  4.6  appleclang  6.3
           -Wformat=2                       # clang  3.0  gcc  4.8
           -Wformat=2                       # clang  3.0  gcc  4.8
+          -Wtrampolines                    #             gcc  4.6
         )
         )
       endif()
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 5.0)
@@ -207,6 +198,7 @@ if(PICKY_COMPILER)
             -fdelete-null-pointer-checks
             -fdelete-null-pointer-checks
           -Wshift-negative-value           # clang  3.7  gcc  6.0 (clang default)
           -Wshift-negative-value           # clang  3.7  gcc  6.0 (clang default)
           -Wshift-overflow=2               # clang  3.0  gcc  6.0 (clang default: -Wshift-overflow)
           -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()
       endif()
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 7.0)
       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)
       if(NOT CMAKE_C_COMPILER_VERSION VERSION_LESS 10.0)
         list(APPEND _picky_enable
         list(APPEND _picky_enable
           -Warith-conversion               #             gcc 10.0
           -Warith-conversion               #             gcc 10.0
+          -Wenum-conversion                # clang  3.2  gcc 10.0  appleclang  4.6  g++ 11.0
         )
         )
       endif()
       endif()
     endif()
     endif()
@@ -242,20 +235,41 @@ if(PICKY_COMPILER)
         list(APPEND _picky "${_ccopt}")
         list(APPEND _picky "${_ccopt}")
       endif()
       endif()
     endforeach()
     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()
 endif()
 endif()
 
 
 # clang-cl
 # clang-cl
 if(CMAKE_C_COMPILER_ID STREQUAL "Clang" AND MSVC)
 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()
 endif()
 
 
 if(_picky)
 if(_picky)

+ 25 - 7
CMake/Utilities.cmake

@@ -23,13 +23,31 @@
 ###########################################################################
 ###########################################################################
 # File containing various utilities
 # 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()
     endif()
   endforeach()
   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()
 endfunction()

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

@@ -23,13 +23,6 @@
 ###########################################################################
 ###########################################################################
 @PACKAGE_INIT@
 @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)
 include(CMakeFindDependencyMacro)
 if("@USE_OPENSSL@")
 if("@USE_OPENSSL@")
   find_dependency(OpenSSL "@OPENSSL_VERSION_MAJOR@")
   find_dependency(OpenSSL "@OPENSSL_VERSION_MAJOR@")
@@ -39,7 +32,6 @@ if("@HAVE_LIBZ@")
 endif()
 endif()
 
 
 include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
 include("${CMAKE_CURRENT_LIST_DIR}/@[email protected]")
-check_required_components("@PROJECT_NAME@")
 
 
 # Alias for either shared or static library
 # Alias for either shared or static library
 if(NOT TARGET @PROJECT_NAME@::libcurl)
 if(NOT TARGET @PROJECT_NAME@::libcurl)
@@ -47,5 +39,32 @@ if(NOT TARGET @PROJECT_NAME@::libcurl)
 endif()
 endif()
 
 
 # For compatibility with CMake's FindCURL.cmake
 # For compatibility with CMake's FindCURL.cmake
+set(CURL_VERSION_STRING "@CURLVERSION@")
 set(CURL_LIBRARIES @PROJECT_NAME@::libcurl)
 set(CURL_LIBRARIES @PROJECT_NAME@::libcurl)
 set_and_check(CURL_INCLUDE_DIRS "@PACKAGE_CMAKE_INSTALL_INCLUDEDIR@")
 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_UNISTD_H 1)
   set(HAVE_LIBGEN_H 1)
   set(HAVE_LIBGEN_H 1)
   set(HAVE_STDDEF_H 1)  # detected by CMake internally in check_type_size()
   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_STDBOOL_H 1)
   set(HAVE_BOOL_T "${HAVE_STDBOOL_H}")
   set(HAVE_BOOL_T "${HAVE_STDBOOL_H}")
   set(HAVE_STRTOLL 1)
   set(HAVE_STRTOLL 1)
   set(HAVE_BASENAME 1)
   set(HAVE_BASENAME 1)
-  set(HAVE_STRCASECMP 1)
   set(HAVE_FTRUNCATE 1)
   set(HAVE_FTRUNCATE 1)
   set(HAVE_SYS_PARAM_H 1)
   set(HAVE_SYS_PARAM_H 1)
   set(HAVE_SYS_TIME_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_UTIME_H 1)  # wrapper to sys/utime.h
   set(HAVE_DIRENT_H 1)
   set(HAVE_DIRENT_H 1)
   set(HAVE_OPENDIR 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()
 else()
   set(HAVE_LIBGEN_H 0)
   set(HAVE_LIBGEN_H 0)
-  set(HAVE_STRCASECMP 0)
   set(HAVE_FTRUNCATE 0)
   set(HAVE_FTRUNCATE 0)
   set(HAVE_SYS_PARAM_H 0)
   set(HAVE_SYS_PARAM_H 0)
   set(HAVE_SYS_TIME_H 0)
   set(HAVE_SYS_TIME_H 0)
@@ -58,9 +72,13 @@ else()
   set(HAVE_OPENDIR 0)
   set(HAVE_OPENDIR 0)
   if(MSVC)
   if(MSVC)
     set(HAVE_UNISTD_H 0)
     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_STDDEF_H 1)  # detected by CMake internally in check_type_size()
     set(HAVE_STDATOMIC_H 0)
     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)
     if(NOT MSVC_VERSION LESS 1800)
       set(HAVE_STDBOOL_H 1)
       set(HAVE_STDBOOL_H 1)
       set(HAVE_STRTOLL 1)
       set(HAVE_STRTOLL 1)
@@ -85,7 +103,6 @@ endif()
 set(HAVE_GETADDRINFO 1)
 set(HAVE_GETADDRINFO 1)
 set(HAVE_FREEADDRINFO 1)
 set(HAVE_FREEADDRINFO 1)
 
 
-set(HAVE_FCHMOD 0)
 set(HAVE_SOCKETPAIR 0)
 set(HAVE_SOCKETPAIR 0)
 set(HAVE_SENDMSG 0)
 set(HAVE_SENDMSG 0)
 set(HAVE_SENDMMSG 0)
 set(HAVE_SENDMMSG 0)
@@ -112,10 +129,8 @@ set(HAVE_GETHOSTNAME 1)
 set(HAVE_RECV 1)
 set(HAVE_RECV 1)
 set(HAVE_SEND 1)
 set(HAVE_SEND 1)
 set(HAVE_STROPTS_H 0)
 set(HAVE_STROPTS_H 0)
-set(HAVE_SYS_XATTR_H 0)
 set(HAVE_ARC4RANDOM 0)
 set(HAVE_ARC4RANDOM 0)
 set(HAVE_FNMATCH 0)
 set(HAVE_FNMATCH 0)
-set(HAVE_SCHED_YIELD 0)
 set(HAVE_ARPA_INET_H 0)
 set(HAVE_ARPA_INET_H 0)
 set(HAVE_FCNTL_H 1)
 set(HAVE_FCNTL_H 1)
 set(HAVE_IFADDRS_H 0)
 set(HAVE_IFADDRS_H 0)
@@ -132,7 +147,6 @@ set(HAVE_POLL 0)
 set(HAVE_PWD_H 0)
 set(HAVE_PWD_H 0)
 set(HAVE_SYS_EVENTFD_H 0)
 set(HAVE_SYS_EVENTFD_H 0)
 set(HAVE_SYS_FILIO_H 0)
 set(HAVE_SYS_FILIO_H 0)
-set(HAVE_SYS_WAIT_H 0)
 set(HAVE_SYS_IOCTL_H 0)
 set(HAVE_SYS_IOCTL_H 0)
 set(HAVE_SYS_POLL_H 0)
 set(HAVE_SYS_POLL_H 0)
 set(HAVE_SYS_RESOURCE_H 0)
 set(HAVE_SYS_RESOURCE_H 0)
@@ -147,12 +161,9 @@ set(HAVE_TERMIOS_H 0)
 set(HAVE_TERMIO_H 0)
 set(HAVE_TERMIO_H 0)
 set(HAVE_LINUX_TCP_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_SOCKET 1)
 set(HAVE_SELECT 1)
 set(HAVE_SELECT 1)
 set(HAVE_STRDUP 1)
 set(HAVE_STRDUP 1)
-set(HAVE_STRICMP 1)
-set(HAVE_STRCMPI 1)
 set(HAVE_MEMRCHR 0)
 set(HAVE_MEMRCHR 0)
 set(HAVE_CLOSESOCKET 1)
 set(HAVE_CLOSESOCKET 1)
 set(HAVE_SIGSETJMP 0)
 set(HAVE_SIGSETJMP 0)
@@ -178,6 +189,7 @@ set(HAVE_POSIX_STRERROR_R 0)
 set(HAVE_MSG_NOSIGNAL 0)
 set(HAVE_MSG_NOSIGNAL 0)
 set(HAVE_STRUCT_TIMEVAL 1)
 set(HAVE_STRUCT_TIMEVAL 1)
 set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
 set(HAVE_STRUCT_SOCKADDR_STORAGE 1)
+set(HAVE_TIME_T_UNSIGNED 0)
 
 
 set(HAVE_GETHOSTBYNAME_R_3 0)
 set(HAVE_GETHOSTBYNAME_R_3 0)
 set(HAVE_GETHOSTBYNAME_R_3_REENTRANT 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 0)
 set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
 set(HAVE_GETHOSTBYNAME_R_6_REENTRANT 0)
 
 
-set(HAVE_O_NONBLOCK 0)
 set(HAVE_IN_ADDR_T 0)
 set(HAVE_IN_ADDR_T 0)
 set(STDC_HEADERS 1)
 set(STDC_HEADERS 1)
 
 

ファイルの差分が大きいため隠しています
+ 354 - 223
CMakeLists.txt


+ 1 - 1
COPYING

@@ -1,6 +1,6 @@
 COPYRIGHT AND PERMISSION NOTICE
 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.
 contributors, see the THANKS file.
 
 
 All rights reserved.
 All rights reserved.

+ 49 - 3
include/curl/curl.h

@@ -1959,10 +1959,10 @@ typedef enum {
   /* Set stream weight, 1 - 256 (default is 16) */
   /* Set stream weight, 1 - 256 (default is 16) */
   CURLOPT(CURLOPT_STREAM_WEIGHT, CURLOPTTYPE_LONG, 239),
   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),
   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),
   CURLOPT(CURLOPT_STREAM_DEPENDS_E, CURLOPTTYPE_OBJECTPOINT, 241),
 
 
   /* Do not send any tftp option requests to the server */
   /* Do not send any tftp option requests to the server */
@@ -2959,7 +2959,9 @@ typedef enum {
   CURLINFO_USED_PROXY       = CURLINFO_LONG + 66,
   CURLINFO_USED_PROXY       = CURLINFO_LONG + 66,
   CURLINFO_POSTTRANSFER_TIME_T = CURLINFO_OFF_T + 67,
   CURLINFO_POSTTRANSFER_TIME_T = CURLINFO_OFF_T + 67,
   CURLINFO_EARLYDATA_SENT_T = CURLINFO_OFF_T + 68,
   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;
 
 
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
 /* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
@@ -3230,6 +3232,50 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #define CURLPAUSE_ALL       (CURLPAUSE_RECV|CURLPAUSE_SEND)
 #define CURLPAUSE_ALL       (CURLPAUSE_RECV|CURLPAUSE_SEND)
 #define CURLPAUSE_CONT      (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
 #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
 #ifdef  __cplusplus
 } /* end of extern "C" */
 } /* end of extern "C" */
 #endif
 #endif

+ 4 - 4
include/curl/curlver.h

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

+ 1 - 1
include/curl/easy.h

@@ -78,7 +78,7 @@ CURL_EXTERN CURL *curl_easy_duphandle(CURL *curl);
  *
  *
  * DESCRIPTION
  * 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.
  * 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
  * 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
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__BORLANDC__)
 #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
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 #elif defined(__POCC__)
 #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_TYPEOF_CURL_OFF_T     __int64
 #    define CURL_FORMAT_CURL_OFF_T     "I64d"
 #    define CURL_FORMAT_CURL_OFF_T     "I64d"
 #    define CURL_FORMAT_CURL_OFF_TU    "I64u"
 #    define CURL_FORMAT_CURL_OFF_TU    "I64u"
@@ -159,15 +121,21 @@
 #  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
 #  define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
 
 
 #elif defined(__TANDEM)
 #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)
 #elif defined(_WIN32_WCE)
 #  define CURL_TYPEOF_CURL_OFF_T     __int64
 #  define CURL_TYPEOF_CURL_OFF_T     __int64
@@ -220,13 +188,7 @@
 #    define CURL_FORMAT_CURL_OFF_TU    "llu"
 #    define CURL_FORMAT_CURL_OFF_TU    "llu"
 #    define CURL_SUFFIX_CURL_OFF_T     LL
 #    define CURL_SUFFIX_CURL_OFF_T     LL
 #    define CURL_SUFFIX_CURL_OFF_TU    ULL
 #    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_TYPEOF_CURL_OFF_T     long
 #    define CURL_FORMAT_CURL_OFF_T     "ld"
 #    define CURL_FORMAT_CURL_OFF_T     "ld"
 #    define CURL_FORMAT_CURL_OFF_TU    "lu"
 #    define CURL_FORMAT_CURL_OFF_TU    "lu"
@@ -239,22 +201,13 @@
 
 
 #elif defined(__370__)
 #elif defined(__370__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
 #  if defined(__IBMC__) || defined(__IBMCPP__)
-#    if defined(_ILP32)
-#    elif defined(_LP64)
-#    endif
 #    if defined(_LONG_LONG)
 #    if defined(_LONG_LONG)
 #      define CURL_TYPEOF_CURL_OFF_T     long long
 #      define CURL_TYPEOF_CURL_OFF_T     long long
 #      define CURL_FORMAT_CURL_OFF_T     "lld"
 #      define CURL_FORMAT_CURL_OFF_T     "lld"
 #      define CURL_FORMAT_CURL_OFF_TU    "llu"
 #      define CURL_FORMAT_CURL_OFF_TU    "llu"
 #      define CURL_SUFFIX_CURL_OFF_T     LL
 #      define CURL_SUFFIX_CURL_OFF_T     LL
 #      define CURL_SUFFIX_CURL_OFF_TU    ULL
 #      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_TYPEOF_CURL_OFF_T     long
 #      define CURL_FORMAT_CURL_OFF_T     "ld"
 #      define CURL_FORMAT_CURL_OFF_T     "ld"
 #      define CURL_FORMAT_CURL_OFF_TU    "lu"
 #      define CURL_FORMAT_CURL_OFF_TU    "lu"
@@ -349,24 +302,15 @@
 #elif defined(_MSC_VER)
 #elif defined(_MSC_VER)
 #  if (_MSC_VER >= 1800)
 #  if (_MSC_VER >= 1800)
 #    include <inttypes.h>
 #    include <inttypes.h>
-#    define CURL_TYPEOF_CURL_OFF_T     __int64
 #    define CURL_FORMAT_CURL_OFF_T     PRId64
 #    define CURL_FORMAT_CURL_OFF_T     PRId64
 #    define CURL_FORMAT_CURL_OFF_TU    PRIu64
 #    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_T     "I64d"
 #    define CURL_FORMAT_CURL_OFF_TU    "I64u"
 #    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
 #  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
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 
 /* ===================================== */
 /* ===================================== */
@@ -403,12 +347,12 @@
 
 
 #else
 #else
 /* generic "safe guess" on old 32-bit style */
 /* 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
 #endif
 
 
 #ifdef _AIX
 #ifdef _AIX
@@ -462,7 +406,7 @@
 
 
 #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
 #if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
   defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
   defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
-  defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+  defined(__POCC__) || defined(__HIGHC__) || \
   defined(__ILEC400__)
   defined(__ILEC400__)
   /* This compiler is believed to have an ISO compatible preprocessor */
   /* This compiler is believed to have an ISO compatible preprocessor */
 #define CURL_ISOCPP
 #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")
 configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h")
 
 
 # Get 'CSOURCES', 'HHEADERS' variables
 # 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")
 include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.inc.cmake")
 
 
 # DllMain is added later for DLL builds only.
 # 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")
     set_property(TARGET ${LIB_OBJECT} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   endif()
   if(CURL_HAS_LTO)
   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()
   endif()
 
 
   target_include_directories(${LIB_OBJECT} INTERFACE
   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")
     set_property(TARGET ${LIB_STATIC} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   endif()
   if(CURL_HAS_LTO)
   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()
   endif()
 
 
   target_include_directories(${LIB_STATIC} INTERFACE
   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")
     set_property(TARGET ${LIB_SHARED} APPEND PROPERTY COMPILE_DEFINITIONS "CURL_HIDDEN_SYMBOLS")
   endif()
   endif()
   if(CURL_HAS_LTO)
   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()
   endif()
 
 
   target_include_directories(${LIB_SHARED} INTERFACE
   target_include_directories(${LIB_SHARED} INTERFACE
@@ -208,7 +202,7 @@ if(BUILD_SHARED_LIBS)
 
 
   if(CURL_LIBCURL_SOVERSION OR CURL_LIBCURL_VERSIONED_SYMBOLS)
   if(CURL_LIBCURL_SOVERSION OR CURL_LIBCURL_VERSIONED_SYMBOLS)
     # Get 'VERSIONCHANGE', 'VERSIONADD', 'VERSIONDEL', 'VERSIONINFO' variables
     # 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")
     include("${CMAKE_CURRENT_BINARY_DIR}/Makefile.soname.cmake")
 
 
     math(EXPR _cmakesoname "${VERSIONCHANGE} - ${VERSIONDEL}")
     math(EXPR _cmakesoname "${VERSIONCHANGE} - ${VERSIONDEL}")

+ 10 - 2
lib/Makefile.inc

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

+ 78 - 67
lib/altsvc.c

@@ -40,6 +40,8 @@
 #include "rename.h"
 #include "rename.h"
 #include "strdup.h"
 #include "strdup.h"
 #include "inet_pton.h"
 #include "inet_pton.h"
+#include "strparse.h"
+#include "connect.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -47,28 +49,12 @@
 #include "memdebug.h"
 #include "memdebug.h"
 
 
 #define MAX_ALTSVC_LINE 4095
 #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 MAX_ALTSVC_ALPNLEN 10
 
 
 #define H3VERSION "h3"
 #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 */
 /* Given the ALPN ID, return the name */
 const char *Curl_alpnid2str(enum alpnid id)
 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,
 static struct altsvc *altsvc_createid(const char *srchost,
+                                      size_t hlen,
                                       const char *dsthost,
                                       const char *dsthost,
                                       size_t dlen, /* dsthost length */
                                       size_t dlen, /* dsthost length */
                                       enum alpnid srcalpnid,
                                       enum alpnid srcalpnid,
                                       enum alpnid dstalpnid,
                                       enum alpnid dstalpnid,
-                                      unsigned int srcport,
-                                      unsigned int dstport)
+                                      size_t srcport,
+                                      size_t dstport)
 {
 {
   struct altsvc *as = calloc(1, sizeof(struct altsvc));
   struct altsvc *as = calloc(1, sizeof(struct altsvc));
-  size_t hlen;
   if(!as)
   if(!as)
     return NULL;
     return NULL;
-  hlen = strlen(srchost);
   DEBUGASSERT(hlen);
   DEBUGASSERT(hlen);
   DEBUGASSERT(dlen);
   DEBUGASSERT(dlen);
-  if(!hlen || !dlen) {
+  if(!hlen || !dlen)
     /* bad input */
     /* bad input */
-    free(as);
-    return NULL;
-  }
+    goto error;
   if((hlen > 2) && srchost[0] == '[') {
   if((hlen > 2) && srchost[0] == '[') {
     /* IPv6 address, strip off brackets */
     /* IPv6 address, strip off brackets */
     srchost++;
     srchost++;
     hlen -= 2;
     hlen -= 2;
   }
   }
-  else if(srchost[hlen - 1] == '.')
+  else if(srchost[hlen - 1] == '.') {
     /* strip off trailing dot */
     /* strip off trailing dot */
     hlen--;
     hlen--;
+    if(!hlen)
+      goto error;
+  }
   if((dlen > 2) && dsthost[0] == '[') {
   if((dlen > 2) && dsthost[0] == '[') {
     /* IPv6 address, strip off brackets */
     /* IPv6 address, strip off brackets */
     dsthost++;
     dsthost++;
@@ -136,8 +122,8 @@ static struct altsvc *altsvc_createid(const char *srchost,
 
 
   as->src.alpnid = srcalpnid;
   as->src.alpnid = srcalpnid;
   as->dst.alpnid = dstalpnid;
   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;
   return as;
 error:
 error:
@@ -145,18 +131,19 @@ error:
   return NULL;
   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)
   if(!srcalpnid || !dstalpnid)
     return NULL;
     return NULL;
-  return altsvc_createid(srchost, dsthost, strlen(dsthost),
+  return altsvc_createid(srchost->str, srchost->len,
+                         dsthost->str, dsthost->len,
                          srcalpnid, dstalpnid,
                          srcalpnid, dstalpnid,
                          srcport, dstport);
                          srcport, dstport);
 }
 }
@@ -167,31 +154,50 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
   /* Example line:
   /* Example line:
      h2 example.com 443 h3 shiny.example.com 8443 "20191231 10:00:00" 1
      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;
     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) {
     if(as) {
       as->expires = expires;
       as->expires = expires;
-      as->prio = prio;
+      as->prio = 0; /* not supported to just set zero */
       as->persist = persist ? 1 : 0;
       as->persist = persist ? 1 : 0;
       Curl_llist_append(&asi->list, as, &as->node);
       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)
 #define time(x) altsvc_debugtime(x)
 #endif
 #endif
 
 
-#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
-
 /*
 /*
  * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
  * Curl_altsvc_parse() takes an incoming alt-svc response header and stores
  * the data correctly in the cache.
  * 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 */
   unsigned short dstport = srcport; /* the same by default */
   CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
   CURLcode result = getalnum(&p, alpnbuf, sizeof(alpnbuf));
   size_t entries = 0;
   size_t entries = 0;
+  size_t alpnlen = strlen(alpnbuf);
+  size_t srchostlen = strlen(srchost);
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
   (void)data;
   (void)data;
 #endif
 #endif
@@ -515,7 +521,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
   do {
   do {
     if(*p == '=') {
     if(*p == '=') {
       /* [protocol]="[host][:port]" */
       /* [protocol]="[host][:port]" */
-      enum alpnid dstalpnid = alpn2alpnid(alpnbuf); /* the same by default */
+      enum alpnid dstalpnid = Curl_alpn2alpnid(alpnbuf, alpnlen);
       p++;
       p++;
       if(*p == '\"') {
       if(*p == '\"') {
         const char *dsthost = "";
         const char *dsthost = "";
@@ -633,13 +639,18 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
                this is the first entry of the line. */
                this is the first entry of the line. */
             altsvc_flush(asi, srcalpnid, srchost, srcport);
             altsvc_flush(asi, srcalpnid, srchost, srcport);
 
 
-          as = altsvc_createid(srchost, dsthost, dstlen,
+          as = altsvc_createid(srchost, srchostlen,
+                               dsthost, dstlen,
                                srcalpnid, dstalpnid,
                                srcalpnid, dstalpnid,
                                srcport, dstport);
                                srcport, dstport);
           if(as) {
           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;
             as->persist = persist;
             Curl_llist_append(&asi->list, as, &as->node);
             Curl_llist_append(&asi->list, as, &as->node);
             infof(data, "Added alt-svc: %s:%d over %s", dsthost, dstport,
             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 <curl/curl.h>
 #include "llist.h"
 #include "llist.h"
 
 
-enum alpnid {
-  ALPN_none = 0,
-  ALPN_h1 = CURLALTSVC_H1,
-  ALPN_h2 = CURLALTSVC_H2,
-  ALPN_h3 = CURLALTSVC_H3
-};
-
 struct althost {
 struct althost {
   char *host;
   char *host;
   unsigned short port;
   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;
 struct Library *SocketBase = NULL;
-extern int errno, h_errno;
 
 
 #ifdef __libnix__
 #ifdef __libnix__
 void __request(const char *msg);
 void __request(const char *msg);
 #else
 #else
-# define __request(msg)       Printf(msg "\n\a")
+# define __request(msg)       Printf((const unsigned char *)(msg "\n\a"), 0)
 #endif
 #endif
 
 
 void Curl_amiga_cleanup(void)
 void Curl_amiga_cleanup(void)
@@ -215,7 +214,7 @@ void Curl_amiga_cleanup(void)
 CURLcode Curl_amiga_init(void)
 CURLcode Curl_amiga_init(void)
 {
 {
   if(!SocketBase)
   if(!SocketBase)
-    SocketBase = OpenLibrary("bsdsocket.library", 4);
+    SocketBase = OpenLibrary((const unsigned char *)"bsdsocket.library", 4);
 
 
   if(!SocketBase) {
   if(!SocketBase) {
     __request("No TCP/IP Stack running!");
     __request("No TCP/IP Stack running!");

+ 151 - 107
lib/asyn-ares.c

@@ -24,14 +24,14 @@
 
 
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
+#ifdef USE_ARES
+
 /***********************************************************************
 /***********************************************************************
  * Only for ares-enabled builds
  * Only for ares-enabled builds
  * And only for functions that fulfill the asynch resolver backend API
  * And only for functions that fulfill the asynch resolver backend API
  * as defined in asyn.h, nothing else belongs in this file!
  * as defined in asyn.h, nothing else belongs in this file!
  **********************************************************************/
  **********************************************************************/
 
 
-#ifdef CURLRES_ARES
-
 #include <limits.h>
 #include <limits.h>
 #ifdef HAVE_NETINET_IN_H
 #ifdef HAVE_NETINET_IN_H
 #include <netinet/in.h>
 #include <netinet/in.h>
@@ -59,15 +59,101 @@
 #include "select.h"
 #include "select.h"
 #include "progress.h"
 #include "progress.h"
 #include "timediff.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.h>
 #include <ares_version.h> /* really old c-ares did not include this by
 #include <ares_version.h> /* really old c-ares did not include this by
                              itself */
                              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
 #if ARES_VERSION >= 0x010500
 /* c-ares 1.5.0 or later, the callback proto is modified */
 /* c-ares 1.5.0 or later, the callback proto is modified */
 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
 #define HAVE_CARES_CALLBACK_TIMEOUTS 1
@@ -93,22 +179,19 @@
 #define HAVE_CARES_GETADDRINFO 1
 #define HAVE_CARES_GETADDRINFO 1
 #endif
 #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 */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "curl_memory.h"
 #include "memdebug.h"
 #include "memdebug.h"
 
 
-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
 /* How long we are willing to wait for additional parallel responses after
    obtaining a "definitive" one. For old c-ares without getaddrinfo.
    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
  * 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);
   DEBUGASSERT(dns);
   *dns = NULL;
   *dns = NULL;
 
 
-  if(waitperform(data, 0) < 0)
+  if(Curl_ares_perform((ares_channel)data->state.async.resolver, 0) < 0)
     return CURLE_UNRECOVERABLE_POLL;
     return CURLE_UNRECOVERABLE_POLL;
 
 
 #ifndef HAVE_CARES_GETADDRINFO
 #ifndef HAVE_CARES_GETADDRINFO
@@ -417,8 +424,19 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
 
 
     if(!data->state.async.dns)
     if(!data->state.async.dns)
       result = Curl_resolver_error(data);
       result = Curl_resolver_error(data);
-    else
+    else {
       *dns = data->state.async.dns;
       *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);
     destroy_async_data(&data->state.async);
   }
   }
@@ -481,7 +499,8 @@ CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
     else
     else
       timeout_ms = 1000;
       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;
       return CURLE_UNRECOVERABLE_POLL;
     result = Curl_resolver_is_resolved(data, entry);
     result = Curl_resolver_is_resolved(data, entry);
 
 
@@ -745,6 +764,7 @@ static void addrinfo_cb(void *arg, int status, int timeouts,
 }
 }
 
 
 #endif
 #endif
+
 /*
 /*
  * Curl_resolver_getaddrinfo() - when using ares
  * Curl_resolver_getaddrinfo() - when using ares
  *
  *
@@ -826,6 +846,16 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                          hostname, PF_INET,
                          hostname, PF_INET,
                          query_completed_cb, data);
                          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
 #endif
     *waitp = 1; /* expect asynchronous response */
     *waitp = 1; /* expect asynchronous response */
   }
   }
@@ -838,14 +868,26 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
   CURLcode result = CURLE_NOT_BUILT_IN;
   CURLcode result = CURLE_NOT_BUILT_IN;
   int ares_result;
   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_SERVERS_CSV
 #ifdef HAVE_CARES_PORTS_CSV
 #ifdef HAVE_CARES_PORTS_CSV
@@ -947,3 +989,5 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
 #endif
 #endif
 }
 }
 #endif /* CURLRES_ARES */
 #endif /* CURLRES_ARES */
+
+#endif /* USE_ARES */

+ 72 - 38
lib/asyn-thread.c

@@ -64,6 +64,15 @@
 #include "inet_ntop.h"
 #include "inet_ntop.h"
 #include "curl_threads.h"
 #include "curl_threads.h"
 #include "connect.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 */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
 #include "curl_memory.h"
 #include "curl_memory.h"
@@ -145,32 +154,6 @@ static bool init_resolve_thread(struct Curl_easy *data,
                                 const struct addrinfo *hints);
                                 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)
 static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
 {
 {
   return &(data->state.async.tdata->tsd);
   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);
    * close one end of the socket pair (may be done in resolver thread);
    * the other end (for reading) is always closed in the parent thread.
    * the other end (for reading) is always closed in the parent thread.
    */
    */
+#ifndef USE_EVENTFD
   if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
   if(tsd->sock_pair[1] != CURL_SOCKET_BAD) {
     wakeup_close(tsd->sock_pair[1]);
     wakeup_close(tsd->sock_pair[1]);
   }
   }
+#endif
 #endif
 #endif
   memset(tsd, 0, sizeof(*tsd));
   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
   /* Treat the request as done until the thread actually starts so any early
    * cleanup gets done properly.
    * cleanup gets done properly.
    */
    */
-  tsd->done = 1;
+  tsd->done = TRUE;
 #ifdef HAVE_GETADDRINFO
 #ifdef HAVE_GETADDRINFO
   DEBUGASSERT(hints);
   DEBUGASSERT(hints);
   tsd->hints = *hints;
   tsd->hints = *hints;
@@ -341,7 +326,7 @@ CURL_STDCALL getaddrinfo_thread(void *arg)
       }
       }
     }
     }
 #endif
 #endif
-    tsd->done = 1;
+    tsd->done = TRUE;
     Curl_mutex_release(tsd->mtx);
     Curl_mutex_release(tsd->mtx);
   }
   }
 
 
@@ -380,7 +365,7 @@ CURL_STDCALL gethostbyname_thread(void *arg)
     free(td);
     free(td);
   }
   }
   else {
   else {
-    tsd->done = 1;
+    tsd->done = TRUE;
     Curl_mutex_release(tsd->mtx);
     Curl_mutex_release(tsd->mtx);
   }
   }
 
 
@@ -396,19 +381,22 @@ static void destroy_async_data(struct Curl_async *async)
 {
 {
   if(async->tdata) {
   if(async->tdata) {
     struct thread_data *td = async->tdata;
     struct thread_data *td = async->tdata;
-    int done;
+    bool done;
 #ifndef CURL_DISABLE_SOCKETPAIR
 #ifndef CURL_DISABLE_SOCKETPAIR
     curl_socket_t sock_rd = td->tsd.sock_pair[0];
     curl_socket_t sock_rd = td->tsd.sock_pair[0];
     struct Curl_easy *data = td->tsd.data;
     struct Curl_easy *data = td->tsd.data;
 #endif
 #endif
 
 
+#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
      * if the thread is still blocking in the resolve syscall, detach it and
      * let the thread do the cleanup...
      * let the thread do the cleanup...
      */
      */
     Curl_mutex_acquire(td->tsd.mtx);
     Curl_mutex_acquire(td->tsd.mtx);
     done = td->tsd.done;
     done = td->tsd.done;
-    td->tsd.done = 1;
+    td->tsd.done = TRUE;
     Curl_mutex_release(td->tsd.mtx);
     Curl_mutex_release(td->tsd.mtx);
 
 
     if(!done) {
     if(!done) {
@@ -437,6 +425,24 @@ static void destroy_async_data(struct Curl_async *async)
   async->hostname = NULL;
   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
  * init_resolve_thread() starts a new thread that performs the actual
  * resolve. This function returns before the resolve is done.
  * 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)
   if(!asp->hostname)
     goto err_exit;
     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
 #ifdef HAVE_GETADDRINFO
   td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
   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) {
   if(td->thread_hnd == curl_thread_t_null) {
     /* The thread never started, so mark it as done here for proper cleanup. */
     /* The thread never started, so mark it as done here for proper cleanup. */
-    td->tsd.done = 1;
+    td->tsd.done = TRUE;
     err = errno;
     err = errno;
     goto err_exit;
     goto err_exit;
   }
   }
-
+#ifdef USE_HTTPSRR_ARES
+  if(resolve_httpsrr(data, asp))
+    goto err_exit;
+#endif
   return TRUE;
   return TRUE;
 
 
 err_exit:
 err_exit:
@@ -585,7 +594,7 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry)
                                    struct Curl_dns_entry **entry)
 {
 {
   struct thread_data *td = data->state.async.tdata;
   struct thread_data *td = data->state.async.tdata;
-  int done = 0;
+  bool done = FALSE;
 
 
   DEBUGASSERT(entry);
   DEBUGASSERT(entry);
   *entry = NULL;
   *entry = NULL;
@@ -594,6 +603,10 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
     DEBUGASSERT(td);
     DEBUGASSERT(td);
     return CURLE_COULDNT_RESOLVE_HOST;
     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);
   Curl_mutex_acquire(td->tsd.mtx);
   done = td->tsd.done;
   done = td->tsd.done;
@@ -607,6 +620,17 @@ CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
       destroy_async_data(&data->state.async);
       destroy_async_data(&data->state.async);
       return result;
       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);
     destroy_async_data(&data->state.async);
     *entry = data->state.async.dns;
     *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 milli;
   timediff_t ms;
   timediff_t ms;
   struct resdata *reslv = (struct resdata *)data->state.async.resolver;
   struct resdata *reslv = (struct resdata *)data->state.async.resolver;
+  int socketi = 0;
 #ifndef CURL_DISABLE_SOCKETPAIR
 #ifndef CURL_DISABLE_SOCKETPAIR
   struct thread_data *td = data->state.async.tdata;
   struct thread_data *td = data->state.async.tdata;
 #else
 #else
   (void)socks;
   (void)socks;
 #endif
 #endif
 
 
+#ifdef USE_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
 #ifndef CURL_DISABLE_SOCKETPAIR
   if(td) {
   if(td) {
     /* return read fd to client for polling the DNS resolution status */
     /* return read fd to client for polling the DNS resolution status */
-    socks[0] = td->tsd.sock_pair[0];
+    socks[socketi] = td->tsd.sock_pair[0];
     td->tsd.data = data;
     td->tsd.data = data;
-    ret_val = GETSOCK_READSOCK(0);
+    ret_val = GETSOCK_READSOCK(socketi);
   }
   }
   else {
   else {
 #endif
 #endif

+ 64 - 0
lib/asyn.h

@@ -26,6 +26,7 @@
 
 
 #include "curl_setup.h"
 #include "curl_setup.h"
 #include "curl_addrinfo.h"
 #include "curl_addrinfo.h"
+#include "httpsrr.h"
 
 
 struct addrinfo;
 struct addrinfo;
 struct hostent;
 struct hostent;
@@ -33,6 +34,69 @@ struct Curl_easy;
 struct connectdata;
 struct connectdata;
 struct Curl_dns_entry;
 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.
  * This header defines all functions in the internal asynch resolver interface.
  * All asynch resolvers need to provide these functions.
  * 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;
   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)
 static void chunk_reset(struct buf_chunk *chunk)
 {
 {
   chunk->next = NULL;
   chunk->next = NULL;
@@ -287,24 +282,6 @@ size_t Curl_bufq_len(const struct bufq *q)
   return len;
   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)
 bool Curl_bufq_is_empty(const struct bufq *q)
 {
 {
   return !q->head || chunk_is_empty(q->head);
   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);
 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.
  * 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)
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 
 
 #include <curl/curl.h>
 #include <curl/curl.h>
-#ifdef USE_HYPER
-#include <hyper.h>
-#endif
 #include "urldata.h"
 #include "urldata.h"
 #include "dynbuf.h"
 #include "dynbuf.h"
 #include "sendf.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
        make sure that it is not accidentally used for the document request
        after we have connected. So let's free and clear it here. */
        after we have connected. So let's free and clear it here. */
     Curl_safefree(data->state.aptr.proxyuserpwd);
     Curl_safefree(data->state.aptr.proxyuserpwd);
-#ifdef USE_HYPER
-    data->state.hconnect = FALSE;
-#endif
     break;
     break;
   }
   }
 }
 }
@@ -209,10 +203,9 @@ static void tunnel_free(struct Curl_cfilter *cf,
 
 
 static bool tunnel_want_send(struct h1_tunnel_state *ts)
 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,
 static CURLcode start_CONNECT(struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               struct Curl_easy *data,
                               struct h1_tunnel_state *ts)
                               struct h1_tunnel_state *ts)
@@ -529,337 +522,6 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
   return result;
   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,
 static CURLcode H1_CONNECT(struct Curl_cfilter *cf,
                            struct Curl_easy *data,
                            struct Curl_easy *data,
                            struct h1_tunnel_state *ts)
                            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(nwritten < 0) {
     if(result != CURLE_AGAIN)
     if(result != CURLE_AGAIN)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
       return NGHTTP2_ERR_CALLBACK_FAILURE;
+#ifdef DEBUGBUILD
     nwritten = 0;
     nwritten = 0;
+#endif
   }
   }
   DEBUGASSERT((size_t)nwritten == len);
   DEBUGASSERT((size_t)nwritten == len);
   return 0;
   return 0;

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

@@ -24,13 +24,14 @@
 
 
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
 
 
 #include "urldata.h"
 #include "urldata.h"
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include "curl_trc.h"
 #include "curl_trc.h"
 #include "cfilters.h"
 #include "cfilters.h"
 #include "connect.h"
 #include "connect.h"
+#include "hostip.h"
 #include "multiif.h"
 #include "multiif.h"
 #include "cf-https-connect.h"
 #include "cf-https-connect.h"
 #include "http2.h"
 #include "http2.h"
@@ -42,6 +43,10 @@
 #include "memdebug.h"
 #include "memdebug.h"
 
 
 
 
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
+#endif
+
 typedef enum {
 typedef enum {
   CF_HC_INIT,
   CF_HC_INIT,
   CF_HC_CONNECT,
   CF_HC_CONNECT,
@@ -55,7 +60,7 @@ struct cf_hc_baller {
   CURLcode result;
   CURLcode result;
   struct curltime started;
   struct curltime started;
   int reply_ms;
   int reply_ms;
-  BIT(enabled);
+  enum alpnid alpn_id;
   BIT(shutdown);
   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)
 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)
 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,
 static int cf_hc_baller_reply_ms(struct cf_hc_baller *b,
                                  struct Curl_easy *data)
                                  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->cf->cft->query(b->cf, data, CF_QUERY_CONNECT_REPLY_MS,
                       &b->reply_ms, NULL);
                       &b->reply_ms, NULL);
   return b->reply_ms;
   return b->reply_ms;
@@ -116,26 +121,53 @@ struct cf_hc_ctx {
   const struct Curl_dns_entry *remotehost;
   const struct Curl_dns_entry *remotehost;
   struct curltime started;  /* when connect started */
   struct curltime started;  /* when connect started */
   CURLcode result;          /* overall result */
   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 soft_eyeballs_timeout_ms;
   unsigned int hard_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,
 static void cf_hc_baller_init(struct cf_hc_baller *b,
                               struct Curl_cfilter *cf,
                               struct Curl_cfilter *cf,
                               struct Curl_easy *data,
                               struct Curl_easy *data,
-                              const char *name,
                               int transport)
                               int transport)
 {
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct cf_hc_ctx *ctx = cf->ctx;
   struct Curl_cfilter *save = cf->next;
   struct Curl_cfilter *save = cf->next;
 
 
-  b->name = name;
   cf->next = NULL;
   cf->next = NULL;
   b->started = Curl_now();
   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;
   b->cf = cf->next;
   cf->next = save;
   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)
 static void cf_hc_reset(struct Curl_cfilter *cf, struct Curl_easy *data)
 {
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
 
   if(ctx) {
   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->state = CF_HC_INIT;
     ctx->result = CURLE_OK;
     ctx->result = CURLE_OK;
     ctx->hard_eyeballs_timeout_ms = data->set.happy_eyeballs_timeout;
     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;
   struct cf_hc_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
   int reply_ms;
   int reply_ms;
+  size_t i;
 
 
   DEBUGASSERT(winner->cf);
   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);
   reply_ms = cf_hc_baller_reply_ms(winner, data);
   if(reply_ms >= 0)
   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;
   struct cf_hc_ctx *ctx = cf->ctx;
   timediff_t elapsed_ms;
   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;
     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;
     return TRUE;
-
+  }
   elapsed_ms = Curl_timediff(now, ctx->started);
   elapsed_ms = Curl_timediff(now, ctx->started);
   if(elapsed_ms >= ctx->hard_eyeballs_timeout_ms) {
   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;
     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;
       return TRUE;
     }
     }
     /* set the effective hard timeout again */
     /* 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 cf_hc_ctx *ctx = cf->ctx;
   struct curltime now;
   struct curltime now;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
+  size_t i, failed_ballers;
 
 
   (void)blocking;
   (void)blocking;
   if(cf->connected) {
   if(cf->connected) {
@@ -270,51 +313,57 @@ static CURLcode cf_hc_connect(struct Curl_cfilter *cf,
   now = Curl_now();
   now = Curl_now();
   switch(ctx->state) {
   switch(ctx->state) {
   case CF_HC_INIT:
   case CF_HC_INIT:
-    DEBUGASSERT(!ctx->h3_baller.cf);
-    DEBUGASSERT(!ctx->h21_baller.cf);
     DEBUGASSERT(!cf->next);
     DEBUGASSERT(!cf->next);
+    for(i = 0; i < ctx->baller_count; i++)
+      DEBUGASSERT(!ctx->ballers[i].cf);
     CURL_TRC_CF(data, cf, "connect, init");
     CURL_TRC_CF(data, cf, "connect, init");
     ctx->started = now;
     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;
     ctx->state = CF_HC_CONNECT;
     FALLTHROUGH();
     FALLTHROUGH();
 
 
   case CF_HC_CONNECT:
   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) {
       if(!result && *done) {
-        result = baller_connected(cf, data, &ctx->h3_baller);
+        result = baller_connected(cf, data, &ctx->ballers[0]);
         goto out;
         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) {
       if(!result && *done) {
-        result = baller_connected(cf, data, &ctx->h21_baller);
+        result = baller_connected(cf, data, &ctx->ballers[1]);
         goto out;
         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");
       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;
       ctx->state = CF_HC_FAILURE;
       goto out;
       goto out;
     }
     }
@@ -344,7 +393,6 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
                                struct Curl_easy *data, bool *done)
                                struct Curl_easy *data, bool *done)
 {
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct cf_hc_ctx *ctx = cf->ctx;
-  struct cf_hc_baller *ballers[2];
   size_t i;
   size_t i;
   CURLcode result = CURLE_OK;
   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,
   /* shutdown all ballers that have not done so already. If one fails,
    * continue shutting down others until all are shutdown. */
    * 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;
     bool bdone = FALSE;
     if(!cf_hc_baller_is_active(b) || b->shutdown)
     if(!cf_hc_baller_is_active(b) || b->shutdown)
       continue;
       continue;
@@ -369,14 +415,14 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
   }
   }
 
 
   *done = TRUE;
   *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;
       *done = FALSE;
   }
   }
   if(*done) {
   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);
   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) {
   if(!cf->connected) {
     struct cf_hc_ctx *ctx = cf->ctx;
     struct cf_hc_ctx *ctx = cf->ctx;
-    struct cf_hc_baller *ballers[2];
     size_t i;
     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))
       if(!cf_hc_baller_is_active(b))
         continue;
         continue;
       Curl_conn_cf_adjust_pollset(b->cf, data, ps);
       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)
                                const struct Curl_easy *data)
 {
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
 
   if(cf->connected)
   if(cf->connected)
     return cf->next->cft->has_data_pending(cf->next, data);
     return cf->next->cft->has_data_pending(cf->next, data);
 
 
   CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
   CURL_TRC_CF((struct Curl_easy *)data, cf, "data_pending");
-  return cf_hc_baller_data_pending(&ctx->h3_baller, data)
-         || cf_hc_baller_data_pending(&ctx->h21_baller, data);
+  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,
 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)
                                               int query)
 {
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct cf_hc_ctx *ctx = cf->ctx;
-  struct Curl_cfilter *cfb;
   struct curltime t, tmax;
   struct curltime t, tmax;
+  size_t i;
 
 
   memset(&tmax, 0, sizeof(tmax));
   memset(&tmax, 0, sizeof(tmax));
-  memset(&t, 0, sizeof(t));
-  cfb = ctx->h21_baller.enabled ? ctx->h21_baller.cf : NULL;
-  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
-    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
-      tmax = t;
-  }
-  memset(&t, 0, sizeof(t));
-  cfb = ctx->h3_baller.enabled ? ctx->h3_baller.cf : NULL;
-  if(cfb && !cfb->cft->query(cfb, data, query, NULL, &t)) {
-    if((t.tv_sec || t.tv_usec) && Curl_timediff_us(t, tmax) > 0)
-      tmax = t;
+  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;
   return tmax;
 }
 }
@@ -446,6 +488,7 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
                             int query, int *pres1, void *pres2)
                             int query, int *pres1, void *pres2)
 {
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct cf_hc_ctx *ctx = cf->ctx;
+  size_t i;
 
 
   if(!cf->connected) {
   if(!cf->connected) {
     switch(query) {
     switch(query) {
@@ -460,11 +503,11 @@ static CURLcode cf_hc_query(struct Curl_cfilter *cf,
       return CURLE_OK;
       return CURLE_OK;
     }
     }
     case CF_QUERY_NEED_FLUSH: {
     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;
       break;
     }
     }
     default:
     default:
@@ -482,14 +525,17 @@ static CURLcode cf_hc_cntrl(struct Curl_cfilter *cf,
 {
 {
   struct cf_hc_ctx *ctx = cf->ctx;
   struct cf_hc_ctx *ctx = cf->ctx;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
+  size_t i;
 
 
   if(!cf->connected) {
   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;
   return result;
 }
 }
 
 
@@ -537,23 +583,37 @@ struct Curl_cftype Curl_cft_http_connect = {
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
 static CURLcode cf_hc_create(struct Curl_cfilter **pcf,
                              struct Curl_easy *data,
                              struct Curl_easy *data,
                              const struct Curl_dns_entry *remotehost,
                              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 Curl_cfilter *cf = NULL;
   struct cf_hc_ctx *ctx;
   struct cf_hc_ctx *ctx;
   CURLcode result = CURLE_OK;
   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));
   ctx = calloc(1, sizeof(*ctx));
   if(!ctx) {
   if(!ctx) {
     result = CURLE_OUT_OF_MEMORY;
     result = CURLE_OUT_OF_MEMORY;
     goto out;
     goto out;
   }
   }
   ctx->remotehost = remotehost;
   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);
   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)
   if(result)
     goto out;
     goto out;
   ctx = NULL;
   ctx = NULL;
@@ -569,13 +629,13 @@ static CURLcode cf_http_connect_add(struct Curl_easy *data,
                                     struct connectdata *conn,
                                     struct connectdata *conn,
                                     int sockindex,
                                     int sockindex,
                                     const struct Curl_dns_entry *remotehost,
                                     const struct Curl_dns_entry *remotehost,
-                                    bool try_h3, bool try_h21)
+                                    enum alpnid *alpn_ids, size_t alpn_count)
 {
 {
   struct Curl_cfilter *cf;
   struct Curl_cfilter *cf;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
 
 
   DEBUGASSERT(data);
   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)
   if(result)
     goto out;
     goto out;
   Curl_conn_cf_add(data, conn, sockindex, cf);
   Curl_conn_cf_add(data, conn, sockindex, cf);
@@ -588,33 +648,88 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              int sockindex,
                              int sockindex,
                              const struct Curl_dns_entry *remotehost)
                              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;
   CURLcode result = CURLE_OK;
 
 
   (void)sockindex;
   (void)sockindex;
   (void)remotehost;
   (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:
 out:
   return result;
   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"
 #include "curl_setup.h"
 
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
 
 
 struct Curl_cfilter;
 struct Curl_cfilter;
 struct Curl_easy;
 struct Curl_easy;
@@ -54,5 +54,5 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data,
                              const struct Curl_dns_entry *remotehost);
                              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 */
 #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
  * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
  * set the transport used.
  * 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
    * 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;
   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);
   memcpy(&dest->curl_sa_addr, ai->ai_addr, dest->addrlen);
+  return CURLE_OK;
 }
 }
 
 
 static CURLcode socket_open(struct Curl_easy *data,
 static CURLcode socket_open(struct Curl_easy *data,
@@ -395,12 +399,16 @@ CURLcode Curl_socket_open(struct Curl_easy *data,
                             curl_socket_t *sockfd)
                             curl_socket_t *sockfd)
 {
 {
   struct Curl_sockaddr_ex dummy;
   struct Curl_sockaddr_ex dummy;
+  CURLcode result;
 
 
   if(!addr)
   if(!addr)
     /* if the caller does not want info back, use a local temp copy */
     /* if the caller does not want info back, use a local temp copy */
     addr = &dummy;
     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);
   return socket_open(data, addr, sockfd);
 }
 }
 
 
@@ -959,14 +967,20 @@ struct cf_socket_ctx {
   BIT(active);
   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));
   memset(ctx, 0, sizeof(*ctx));
   ctx->sock = CURL_SOCKET_BAD;
   ctx->sock = CURL_SOCKET_BAD;
   ctx->transport = transport;
   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
 #ifdef DEBUGBUILD
   {
   {
     char *p = getenv("CURL_DBG_SOCK_WBLOCK");
     char *p = getenv("CURL_DBG_SOCK_WBLOCK");
@@ -995,6 +1009,8 @@ static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
     }
     }
   }
   }
 #endif
 #endif
+
+  return result;
 }
 }
 
 
 static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
 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);
     rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
 #elif defined(MSG_FASTOPEN) /* old Linux */
 #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);
       rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
     else
     else
       rc = 0; /* Do nothing */
       rc = 0; /* Do nothing */
@@ -1443,7 +1459,7 @@ static bool cf_socket_data_pending(struct Curl_cfilter *cf,
 
 
   (void)data;
   (void)data;
   readable = SOCKET_READABLE(ctx->sock, 0);
   readable = SOCKET_READABLE(ctx->sock, 0);
-  return (readable > 0 && (readable & CURL_CSELECT_IN));
+  return readable > 0 && (readable & CURL_CSELECT_IN);
 }
 }
 
 
 #ifdef USE_WINSOCK
 #ifdef USE_WINSOCK
@@ -1805,7 +1821,10 @@ CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
     result = CURLE_OUT_OF_MEMORY;
     result = CURLE_OUT_OF_MEMORY;
     goto out;
     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);
   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 */
   /* QUIC needs a connected socket, nonblocking */
   DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
   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);
                (curl_socklen_t)ctx->addr.addrlen);
   if(-1 == rc) {
   if(-1 == rc) {
     return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
     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;
     result = CURLE_OUT_OF_MEMORY;
     goto out;
     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);
   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;
     result = CURLE_OUT_OF_MEMORY;
     goto out;
     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);
   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
  * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
  * set the transport used.
  * 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
  * 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) {
   for(; cf; cf = cf->next) {
     if(cf->cft->flags & CF_TYPE_MULTIPLEX)
     if(cf->cft->flags & CF_TYPE_MULTIPLEX)
       return TRUE;
       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;
   }
   }
   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)
 bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
 {
 {
   struct Curl_cfilter *cf;
   struct Curl_cfilter *cf;
@@ -711,18 +733,6 @@ static CURLcode cf_cntrl_all(struct connectdata *conn,
   return result;
   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)
 CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
 {
 {
   return cf_cntrl_all(data->conn, data, FALSE,
   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.
  *           to all filters in the chain. Overall result is always CURLE_OK.
  */
  */
 /*      data event                          arg1       arg2     return */
 /*      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_SETUP            4  /* 0          NULL     first fail */
 #define CF_CTRL_DATA_IDLE             5  /* 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 */
 #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_STREAM_ERROR       6  /* error code - */
 #define CF_QUERY_NEED_FLUSH         7  /* TRUE/FALSE - */
 #define CF_QUERY_NEED_FLUSH         7  /* TRUE/FALSE - */
 #define CF_QUERY_IP_INFO            8  /* TRUE/FALSE struct ip_quadruple */
 #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
  * 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_SSL:        provide SSL/TLS
  * CF_TYPE_MULTIPLEX:  provides multiplexing of easy handles
  * CF_TYPE_MULTIPLEX:  provides multiplexing of easy handles
  * CF_TYPE_PROXY       provides proxying
  * 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_IP_CONNECT  (1 << 0)
 #define CF_TYPE_SSL         (1 << 1)
 #define CF_TYPE_SSL         (1 << 1)
 #define CF_TYPE_MULTIPLEX   (1 << 2)
 #define CF_TYPE_MULTIPLEX   (1 << 2)
 #define CF_TYPE_PROXY       (1 << 3)
 #define CF_TYPE_PROXY       (1 << 3)
+#define CF_TYPE_HTTP        (1 << 4)
 
 
 /* A connection filter type, e.g. specific implementation. */
 /* A connection filter type, e.g. specific implementation. */
 struct Curl_cftype {
 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);
 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`.
  * Close the filter chain at `sockindex` for connection `data->conn`.
   * Filters remain in place and may be connected again afterwards.
   * 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,
 ssize_t Curl_cf_send(struct Curl_easy *data, int sockindex,
                      const void *buf, size_t len, bool eos, CURLcode *code);
                      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
  * Notify connection filters that they need to setup data for
  * a transfer.
  * 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);
                                struct Curl_easy *data, int timeout_ms);
 static void cpool_close_and_destroy_all(struct cpool *cpool);
 static void cpool_close_and_destroy_all(struct cpool *cpool);
 static struct connectdata *cpool_get_oldest_idle(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,
 static struct cpool_bundle *cpool_bundle_create(const char *dest,
                                                 size_t dest_len)
                                                 size_t dest_len)
@@ -285,6 +287,7 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
   struct cpool_bundle *bundle;
   struct cpool_bundle *bundle;
   size_t dest_limit = 0;
   size_t dest_limit = 0;
   size_t total_limit = 0;
   size_t total_limit = 0;
+  size_t shutdowns;
   int result = CPOOL_LIMIT_OK;
   int result = CPOOL_LIMIT_OK;
 
 
   if(!cpool)
   if(!cpool)
@@ -300,8 +303,12 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
 
 
   CPOOL_LOCK(cpool);
   CPOOL_LOCK(cpool);
   if(dest_limit) {
   if(dest_limit) {
+    size_t live;
+
     bundle = cpool_find_bundle(cpool, conn);
     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;
       struct connectdata *oldest_idle = NULL;
       /* The bundle is full. Extract the oldest connection that may
       /* The bundle is full. Extract the oldest connection that may
        * be removed now, if there is one. */
        * 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 */
       /* in case the bundle was destroyed in disconnect, look it up again */
       bundle = cpool_find_bundle(cpool, conn);
       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;
       result = CPOOL_LIMIT_DEST;
       goto out;
       goto out;
     }
     }
   }
   }
 
 
   if(total_limit) {
   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);
       struct connectdata *oldest_idle = cpool_get_oldest_idle(cpool);
       if(!oldest_idle)
       if(!oldest_idle)
         break;
         break;
@@ -335,8 +345,9 @@ int Curl_cpool_check_limits(struct Curl_easy *data,
                    "limit of %zu",
                    "limit of %zu",
                    oldest_idle->connection_id, cpool->num_conn, total_limit));
                    oldest_idle->connection_id, cpool->num_conn, total_limit));
       Curl_cpool_disconnect(data, oldest_idle, FALSE);
       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;
       result = CPOOL_LIMIT_TOTAL;
       goto out;
       goto out;
     }
     }
@@ -374,7 +385,8 @@ CURLcode Curl_cpool_add_conn(struct Curl_easy *data,
   cpool->num_conn++;
   cpool->num_conn++;
   DEBUGF(infof(data, "Added connection %" FMT_OFF_T ". "
   DEBUGF(infof(data, "Added connection %" FMT_OFF_T ". "
                "The cache now contains %zu members",
                "The cache now contains %zu members",
-               conn->connection_id, cpool->num_conn));
+               conn->connection_id,
+               cpool->num_conn + Curl_llist_count(&cpool->shutdowns)));
 out:
 out:
   CPOOL_UNLOCK(cpool);
   CPOOL_UNLOCK(cpool);
 
 
@@ -612,6 +624,21 @@ bool Curl_cpool_find(struct Curl_easy *data,
   return result;
   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)
 static void cpool_shutdown_discard_all(struct cpool *cpool)
 {
 {
   struct Curl_llist_node *e = Curl_llist_head(&cpool->shutdowns);
   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
   /* Add the connection to our shutdown list for non-blocking shutdown
    * during multi processing. */
    * 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 "
     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);
     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);
   Curl_llist_append(&cpool->shutdowns, conn, &conn->cpool_node);
   DEBUGF(infof(data, "[CCACHE] added #%" FMT_OFF_T
   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,
 void Curl_cpool_disconnect(struct Curl_easy *data,
@@ -926,10 +953,11 @@ CURLcode Curl_cpool_add_pollfds(struct cpool *cpool,
   return result;
   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);
   CPOOL_LOCK(cpool);
   if(Curl_llist_head(&cpool->shutdowns)) {
   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_conn_adjust_pollset(cpool->idata, &ps);
       Curl_detach_connection(cpool->idata);
       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);
   CPOOL_UNLOCK(cpool);
-  return result;
 }
 }
 
 
 static void cpool_perform(struct cpool *cpool)
 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_detach_connection(data);
 
 
   Curl_conn_free(data, conn);
   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 connectdata;
 struct Curl_easy;
 struct Curl_easy;
 struct curl_pollfds;
 struct curl_pollfds;
-struct curl_waitfds;
+struct Curl_waitfds;
 struct Curl_multi;
 struct Curl_multi;
 struct Curl_share;
 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 dest_len    destination length, including terminating NUL
  * @param conn_cb     must be present, called for each connection in the
  * @param conn_cb     must be present, called for each connection in the
  *                    bundle until it returns TRUE
  *                    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
  * @return combined result of last conn_db and result_cb or FALSE if no
                       connections were present.
                       connections were present.
  */
  */
@@ -185,8 +183,12 @@ void Curl_cpool_do_locked(struct Curl_easy *data,
  */
  */
 CURLcode Curl_cpool_add_pollfds(struct cpool *connc,
 CURLcode Curl_cpool_add_pollfds(struct cpool *connc,
                                 struct curl_pollfds *cpfds);
                                 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,
  * 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 "vquic/vquic.h" /* for quic cfilters */
 #include "http_proxy.h"
 #include "http_proxy.h"
 #include "socks.h"
 #include "socks.h"
+#include "strcase.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -88,6 +89,27 @@
 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
 #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
 #endif
 #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
  * 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
  * 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(data);
   DEBUGASSERT(conn->handler);
   DEBUGASSERT(conn->handler);
 
 
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
   if(!conn->cfilter[sockindex] &&
   if(!conn->cfilter[sockindex] &&
      conn->handler->protocol == CURLPROTO_HTTPS) {
      conn->handler->protocol == CURLPROTO_HTTPS) {
     DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
     DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE);
@@ -1493,7 +1515,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data,
     if(result)
     if(result)
       goto out;
       goto out;
   }
   }
-#endif /* !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER) */
+#endif /* !defined(CURL_DISABLE_HTTP) */
 
 
   /* Still no cfilter set, apply default. */
   /* Still no cfilter set, apply default. */
   if(!conn->cfilter[sockindex]) {
   if(!conn->cfilter[sockindex]) {

+ 2 - 0
lib/connect.h

@@ -32,6 +32,8 @@
 struct Curl_dns_entry;
 struct Curl_dns_entry;
 struct ip_quadruple;
 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
 /* generic function that returns how much time there is left to run, according
    to the timeouts set */
    to the timeouts set */
 timediff_t Curl_timeleft(struct Curl_easy *data,
 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 */
 /* allow no more than 5 "chained" compression steps */
 #define MAX_ENCODE_STACK 5
 #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
 #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 {
 typedef enum {
   ZLIB_UNINIT,               /* uninitialized */
   ZLIB_UNINIT,               /* uninitialized */
   ZLIB_INIT,                 /* initialized */
   ZLIB_INIT,                 /* initialized */
   ZLIB_INFLATING,            /* inflating started. */
   ZLIB_INFLATING,            /* inflating started. */
   ZLIB_EXTERNAL_TRAILER,     /* reading external trailer */
   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 */
   ZLIB_INIT_GZIP             /* initialized in transparent gzip mode */
 } zlibInitState;
 } zlibInitState;
 
 
@@ -100,6 +81,7 @@ typedef enum {
 struct zlib_writer {
 struct zlib_writer {
   struct Curl_cwriter super;
   struct Curl_cwriter super;
   zlibInitState zlib_init;   /* zlib init state */
   zlibInitState zlib_init;   /* zlib init state */
+  char buffer[DECOMPRESS_BUFFER_SIZE]; /* Put the decompressed data here. */
   uInt trailerlen;           /* Remaining trailer byte count. */
   uInt trailerlen;           /* Remaining trailer byte count. */
   z_stream z;                /* State structure for zlib. */
   z_stream z;                /* State structure for zlib. */
 };
 };
@@ -137,9 +119,6 @@ static CURLcode
 exit_zlib(struct Curl_easy *data,
 exit_zlib(struct Curl_easy *data,
           z_stream *z, zlibInitState *zlib_init, CURLcode result)
           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(*zlib_init != ZLIB_UNINIT) {
     if(inflateEnd(z) != Z_OK && result == CURLE_OK)
     if(inflateEnd(z) != Z_OK && result == CURLE_OK)
       result = process_zlib_error(data, z);
       result = process_zlib_error(data, z);
@@ -183,21 +162,13 @@ static CURLcode inflate_stream(struct Curl_easy *data,
   Bytef *orig_in = z->next_in;
   Bytef *orig_in = z->next_in;
   bool done = FALSE;
   bool done = FALSE;
   CURLcode result = CURLE_OK;   /* Curl_client_write status */
   CURLcode result = CURLE_OK;   /* Curl_client_write status */
-  char *decomp;                 /* Put the decompressed data here. */
 
 
   /* Check state. */
   /* Check state. */
   if(zp->zlib_init != ZLIB_INIT &&
   if(zp->zlib_init != ZLIB_INIT &&
      zp->zlib_init != ZLIB_INFLATING &&
      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);
     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
   /* because the buffer size is fixed, iteratively decompress and transfer to
      the client via next_write function. */
      the client via next_write function. */
   while(!done) {
   while(!done) {
@@ -205,8 +176,8 @@ static CURLcode inflate_stream(struct Curl_easy *data,
     done = TRUE;
     done = TRUE;
 
 
     /* (re)set buffer for decompressed output for every iteration */
     /* (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
 #ifdef Z_BLOCK
     /* Z_BLOCK is only available in zlib ver. >= 1.2.0.5 */
     /* 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
 #endif
 
 
     /* Flush output data if some. */
     /* 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) {
       if(status == Z_OK || status == Z_STREAM_END) {
         zp->zlib_init = started;      /* Data started. */
         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) {
         if(result) {
           exit_zlib(data, z, &zp->zlib_init, result);
           exit_zlib(data, z, &zp->zlib_init, result);
           break;
           break;
@@ -264,7 +235,6 @@ static CURLcode inflate_stream(struct Curl_easy *data,
       break;
       break;
     }
     }
   }
   }
-  free(decomp);
 
 
   /* We are about to leave this call so the `nread' data bytes will not be seen
   /* 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
      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. */
 /* Deflate handler. */
 static CURLcode deflate_do_init(struct Curl_easy *data,
 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;
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
   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,
 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;
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
   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,
 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;
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
   z_stream *z = &zp->z;     /* zlib state structure */
@@ -335,124 +305,34 @@ static const struct Curl_cwtype deflate_encoding = {
 
 
 /* Gzip handler. */
 /* Gzip handler. */
 static CURLcode gzip_do_init(struct Curl_easy *data,
 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;
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
   z_stream *z = &zp->z;     /* zlib state structure */
+  const char *v = zlibVersion();
 
 
   /* Initialize zlib */
   /* Initialize zlib */
   z->zalloc = (alloc_func) zalloc_cb;
   z->zalloc = (alloc_func) zalloc_cb;
   z->zfree = (free_func) zfree_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) {
     if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
       return process_zlib_error(data, z);
       return process_zlib_error(data, z);
     }
     }
     zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
     zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
   }
   }
   else {
   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;
   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,
 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;
   struct zlib_writer *zp = (struct zlib_writer *) writer;
   z_stream *z = &zp->z;     /* zlib state structure */
   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);
     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);
   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,
 static void gzip_do_close(struct Curl_easy *data,
@@ -601,11 +372,11 @@ static const struct Curl_cwtype gzip_encoding = {
 
 
 #endif /* HAVE_LIBZ */
 #endif /* HAVE_LIBZ */
 
 
-
 #ifdef HAVE_BROTLI
 #ifdef HAVE_BROTLI
 /* Brotli writer. */
 /* Brotli writer. */
 struct brotli_writer {
 struct brotli_writer {
   struct Curl_cwriter super;
   struct Curl_cwriter super;
+  char buffer[DECOMPRESS_BUFFER_SIZE];
   BrotliDecoderState *br;    /* State structure for brotli. */
   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,
 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;
   struct brotli_writer *bp = (struct brotli_writer *) writer;
   (void) data;
   (void) data;
@@ -658,12 +429,11 @@ static CURLcode brotli_do_init(struct Curl_easy *data,
 }
 }
 
 
 static CURLcode brotli_do_write(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;
   struct brotli_writer *bp = (struct brotli_writer *) writer;
   const uint8_t *src = (const uint8_t *) buf;
   const uint8_t *src = (const uint8_t *) buf;
-  char *decomp;
   uint8_t *dst;
   uint8_t *dst;
   size_t dstleft;
   size_t dstleft;
   CURLcode result = CURLE_OK;
   CURLcode result = CURLE_OK;
@@ -675,18 +445,14 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
   if(!bp->br)
   if(!bp->br)
     return CURLE_WRITE_ERROR;  /* Stream already ended. */
     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) &&
   while((nbytes || r == BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT) &&
         result == CURLE_OK) {
         result == CURLE_OK) {
-    dst = (uint8_t *) decomp;
-    dstleft = DSIZ;
+    dst = (uint8_t *) bp->buffer;
+    dstleft = DECOMPRESS_BUFFER_SIZE;
     r = BrotliDecoderDecompressStream(bp->br,
     r = BrotliDecoderDecompressStream(bp->br,
                                       &nbytes, &src, &dstleft, &dst, NULL);
                                       &nbytes, &src, &dstleft, &dst, NULL);
     result = Curl_cwriter_write(data, writer->next, type,
     result = Curl_cwriter_write(data, writer->next, type,
-                                 decomp, DSIZ - dstleft);
+                                bp->buffer, DECOMPRESS_BUFFER_SIZE - dstleft);
     if(result)
     if(result)
       break;
       break;
     switch(r) {
     switch(r) {
@@ -704,7 +470,6 @@ static CURLcode brotli_do_write(struct Curl_easy *data,
       break;
       break;
     }
     }
   }
   }
-  free(decomp);
   return result;
   return result;
 }
 }
 
 
@@ -712,7 +477,6 @@ static void brotli_do_close(struct Curl_easy *data,
                                 struct Curl_cwriter *writer)
                                 struct Curl_cwriter *writer)
 {
 {
   struct brotli_writer *bp = (struct brotli_writer *) writer;
   struct brotli_writer *bp = (struct brotli_writer *) writer;
-
   (void) data;
   (void) data;
 
 
   if(bp->br) {
   if(bp->br) {
@@ -731,30 +495,51 @@ static const struct Curl_cwtype brotli_encoding = {
 };
 };
 #endif
 #endif
 
 
-
 #ifdef HAVE_ZSTD
 #ifdef HAVE_ZSTD
 /* Zstd writer. */
 /* Zstd writer. */
 struct zstd_writer {
 struct zstd_writer {
   struct Curl_cwriter super;
   struct Curl_cwriter super;
   ZSTD_DStream *zds;    /* State structure for zstd. */
   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,
 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;
   struct zstd_writer *zp = (struct zstd_writer *) writer;
 
 
   (void)data;
   (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->zds = ZSTD_createDStream();
-  zp->decomp = NULL;
+#endif
+
   return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
   return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
 }
 }
 
 
 static CURLcode zstd_do_write(struct Curl_easy *data,
 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;
   CURLcode result = CURLE_OK;
   struct zstd_writer *zp = (struct zstd_writer *) writer;
   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)
   if(!(type & CLIENTWRITE_BODY) || !nbytes)
     return Curl_cwriter_write(data, writer->next, type, buf, 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.pos = 0;
   in.src = buf;
   in.src = buf;
   in.size = nbytes;
   in.size = nbytes;
 
 
   for(;;) {
   for(;;) {
     out.pos = 0;
     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);
     errorCode = ZSTD_decompressStream(zp->zds, &out, &in);
     if(ZSTD_isError(errorCode)) {
     if(ZSTD_isError(errorCode)) {
@@ -785,7 +565,7 @@ static CURLcode zstd_do_write(struct Curl_easy *data,
     }
     }
     if(out.pos > 0) {
     if(out.pos > 0) {
       result = Curl_cwriter_write(data, writer->next, type,
       result = Curl_cwriter_write(data, writer->next, type,
-                                   zp->decomp, out.pos);
+                                  zp->buffer, out.pos);
       if(result)
       if(result)
         break;
         break;
     }
     }
@@ -800,13 +580,8 @@ static void zstd_do_close(struct Curl_easy *data,
                               struct Curl_cwriter *writer)
                               struct Curl_cwriter *writer)
 {
 {
   struct zstd_writer *zp = (struct zstd_writer *) writer;
   struct zstd_writer *zp = (struct zstd_writer *) writer;
-
   (void)data;
   (void)data;
 
 
-  if(zp->decomp) {
-    free(zp->decomp);
-    zp->decomp = NULL;
-  }
   if(zp->zds) {
   if(zp->zds) {
     ZSTD_freeDStream(zp->zds);
     ZSTD_freeDStream(zp->zds);
     zp->zds = NULL;
     zp->zds = NULL;
@@ -823,7 +598,6 @@ static const struct Curl_cwtype zstd_encoding = {
 };
 };
 #endif
 #endif
 
 
-
 /* Identity handler. */
 /* Identity handler. */
 static const struct Curl_cwtype identity_encoding = {
 static const struct Curl_cwtype identity_encoding = {
   "identity",
   "identity",
@@ -834,7 +608,6 @@ static const struct Curl_cwtype identity_encoding = {
   sizeof(struct Curl_cwriter)
   sizeof(struct Curl_cwriter)
 };
 };
 
 
-
 /* supported general content decoders. */
 /* supported general content decoders. */
 static const struct Curl_cwtype * const general_unencoders[] = {
 static const struct Curl_cwtype * const general_unencoders[] = {
   &identity_encoding,
   &identity_encoding,
@@ -898,7 +671,7 @@ void Curl_all_content_encodings(char *buf, size_t blen)
 
 
 /* Deferred error dummy writer. */
 /* Deferred error dummy writer. */
 static CURLcode error_do_init(struct Curl_easy *data,
 static CURLcode error_do_init(struct Curl_easy *data,
-                                  struct Curl_cwriter *writer)
+                              struct Curl_cwriter *writer)
 {
 {
   (void)data;
   (void)data;
   (void)writer;
   (void)writer;
@@ -906,8 +679,8 @@ static CURLcode error_do_init(struct Curl_easy *data,
 }
 }
 
 
 static CURLcode error_do_write(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) writer;
   (void) buf;
   (void) buf;
@@ -1082,5 +855,4 @@ void Curl_all_content_encodings(char *buf, size_t blen)
     strcpy(buf, CONTENT_ENCODING_DEFAULT);
     strcpy(buf, CONTENT_ENCODING_DEFAULT);
 }
 }
 
 
-
 #endif /* CURL_DISABLE_HTTP */
 #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);
 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)
 static void freecookie(struct Cookie *co)
 {
 {
   free(co->domain);
   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
   fine. The prime reason for filtering out control bytes is that some HTTP
   servers return 400 for requests that contain such.
   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 */
   /* Reject all bytes \x01 - \x1f (*except* \x09, TAB) + \x7f */
   static const char badoctets[] = {
   static const char badoctets[] = {
@@ -449,7 +469,7 @@ static int invalid_octets(const char *p)
   size_t len;
   size_t len;
   /* scan for all the octets that are *not* in cookie-octet */
   /* scan for all the octets that are *not* in cookie-octet */
   len = strcspn(p, badoctets);
   len = strcspn(p, badoctets);
-  return (p[len] != '\0');
+  return p[len] != '\0';
 }
 }
 
 
 #define CERR_OK            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_PSL           14 /* a public suffix */
 #define CERR_LIVE_WINS     15
 #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
 static int
 parse_cookie_header(struct Curl_easy *data,
 parse_cookie_header(struct Curl_easy *data,
                     struct Cookie *co,
                     struct Cookie *co,
@@ -707,16 +734,20 @@ parse_cookie_header(struct Curl_easy *data,
             co->expires += now;
             co->expires += now;
           break;
           break;
         }
         }
+        cap_expires(now, co);
       }
       }
       else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
       else if((nlen == 7) && strncasecompare("expires", namep, 7)) {
-        if(!co->expires) {
+        if(!co->expires && (vlen < MAX_DATE_LENGTH)) {
           /*
           /*
            * Let max-age have priority.
            * Let max-age have priority.
            *
            *
            * If the date cannot get parsed for whatever reason, the cookie
            * If the date cannot get parsed for whatever reason, the cookie
            * will be treated as a session 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
            * 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;
             co->expires = 1;
           else if(co->expires < 0)
           else if(co->expires < 0)
             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
    * This line is NOT an HTTP header style line, we do offer support for
    * reading the odd netscape cookies-file format here
    * reading the odd netscape cookies-file format here
    */
    */
-  char *ptr;
-  char *firstptr;
-  char *tok_buf = NULL;
+  const char *ptr, *next;
   int fields;
   int fields;
+  size_t len;
 
 
   /*
   /*
    * In 2008, Internet Explorer introduced HTTP-only cookies to prevent XSS
    * 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 */
     /* do not even try the comments */
     return CERR_COMMENT;
     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
    * Now loop through the fields and init the struct we already have
    * allocated
    * allocated
    */
    */
   fields = 0;
   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) {
     switch(fields) {
     case 0:
     case 0:
-      if(ptr[0]=='.') /* skip preceding dots */
+      if(ptr[0]=='.') { /* skip preceding dots */
         ptr++;
         ptr++;
-      co->domain = strdup(ptr);
+        len--;
+      }
+      co->domain = Curl_memdup0(ptr, len);
       if(!co->domain)
       if(!co->domain)
         return CERR_OUT_OF_MEMORY;
         return CERR_OUT_OF_MEMORY;
       break;
       break;
@@ -857,13 +881,13 @@ parse_netscape(struct Cookie *co,
        * domain can access the variable. Set TRUE when the cookie says
        * domain can access the variable. Set TRUE when the cookie says
        * .domain.com and to false when the domain is complete www.domain.com
        * .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;
       break;
     case 2:
     case 2:
       /* The file format allows the path field to remain not filled in */
       /* 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! */
         /* only if the path does not look like a boolean option! */
-        co->path = strdup(ptr);
+        co->path = Curl_memdup0(ptr, len);
         if(!co->path)
         if(!co->path)
           return CERR_OUT_OF_MEMORY;
           return CERR_OUT_OF_MEMORY;
         else {
         else {
@@ -884,7 +908,7 @@ parse_netscape(struct Cookie *co,
       FALLTHROUGH();
       FALLTHROUGH();
     case 3:
     case 3:
       co->secure = FALSE;
       co->secure = FALSE;
-      if(strcasecompare(ptr, "TRUE")) {
+      if(strncasecompare(ptr, "TRUE", len)) {
         if(secure || ci->running)
         if(secure || ci->running)
           co->secure = TRUE;
           co->secure = TRUE;
         else
         else
@@ -892,11 +916,19 @@ parse_netscape(struct Cookie *co,
       }
       }
       break;
       break;
     case 4:
     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;
       break;
     case 5:
     case 5:
-      co->name = strdup(ptr);
+      co->name = Curl_memdup0(ptr, len);
       if(!co->name)
       if(!co->name)
         return CERR_OUT_OF_MEMORY;
         return CERR_OUT_OF_MEMORY;
       else {
       else {
@@ -908,7 +940,7 @@ parse_netscape(struct Cookie *co,
       }
       }
       break;
       break;
     case 6:
     case 6:
-      co->value = strdup(ptr);
+      co->value = Curl_memdup0(ptr, len);
       if(!co->value)
       if(!co->value)
         return CERR_OUT_OF_MEMORY;
         return CERR_OUT_OF_MEMORY;
       break;
       break;
@@ -1303,14 +1335,14 @@ static int cookie_sort(const void *p1, const void *p2)
   l2 = c2->path ? strlen(c2->path) : 0;
   l2 = c2->path ? strlen(c2->path) : 0;
 
 
   if(l1 != l2)
   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 */
   /* 2 - compare cookie domain lengths */
   l1 = c1->domain ? strlen(c1->domain) : 0;
   l1 = c1->domain ? strlen(c1->domain) : 0;
   l2 = c2->domain ? strlen(c2->domain) : 0;
   l2 = c2->domain ? strlen(c2->domain) : 0;
 
 
   if(l1 != l2)
   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 */
   /* 3 - compare cookie name lengths */
   l1 = c1->name ? strlen(c1->name) : 0;
   l1 = c1->name ? strlen(c1->name) : 0;

+ 5 - 5
lib/cookie.h

@@ -38,7 +38,7 @@ struct Cookie {
   char *spath;        /* sanitized cookie path */
   char *spath;        /* sanitized cookie path */
   char *domain;       /* domain = <this> */
   char *domain;       /* domain = <this> */
   curl_off_t expires; /* expires = <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(tailmatch);     /* tail-match the domain name */
   BIT(secure);        /* the 'secure' keyword was used */
   BIT(secure);        /* the 'secure' keyword was used */
   BIT(livecookie);    /* updated from a server, not a stored file */
   BIT(livecookie);    /* updated from a server, not a stored file */
@@ -60,10 +60,10 @@ struct CookieInfo {
   /* linked lists of cookies we know of */
   /* linked lists of cookies we know of */
   struct Curl_llist cookielist[COOKIE_HASH_SIZE];
   struct Curl_llist cookielist[COOKIE_HASH_SIZE];
   curl_off_t next_expiration; /* the next time at which expiration happens */
   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
 /* 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 */
       addr = (void *)ai->ai_addr; /* storage area for this info */
 
 
       memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
       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);
       addr->sin_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
-#endif
       addr->sin_port = htons((unsigned short)port);
       addr->sin_port = htons((unsigned short)port);
       break;
       break;
 
 
@@ -331,11 +327,7 @@ Curl_he2ai(const struct hostent *he, int port)
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
 
 
       memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
       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);
       addr6->sin6_family = (CURL_SA_FAMILY_T)(he->h_addrtype);
-#endif
       addr6->sin6_port = htons((unsigned short)port);
       addr6->sin6_port = htons((unsigned short)port);
       break;
       break;
 #endif
 #endif

+ 17 - 26
lib/curl_config.h.cmake

@@ -565,9 +565,6 @@
 /* Define to 1 if you have the <sys/filio.h> header file. */
 /* Define to 1 if you have the <sys/filio.h> header file. */
 #cmakedefine HAVE_SYS_FILIO_H 1
 #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. */
 /* Define to 1 if you have the <sys/ioctl.h> header file. */
 #cmakedefine HAVE_SYS_IOCTL_H 1
 #cmakedefine HAVE_SYS_IOCTL_H 1
 
 
@@ -625,8 +622,8 @@
 /* Define this symbol if your OS supports changing the contents of argv */
 /* Define this symbol if your OS supports changing the contents of argv */
 #cmakedefine HAVE_WRITABLE_ARGV 1
 #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. */
 /* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
 #cmakedefine NEED_REENTRANT 1
 #cmakedefine NEED_REENTRANT 1
@@ -634,24 +631,6 @@
 /* cpu-machine-OS */
 /* cpu-machine-OS */
 #cmakedefine CURL_OS ${CURL_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().
  Note: SIZEOF_* variables are fetched with CMake through check_type_size().
  As per CMake documentation on CheckTypeSize, C preprocessor code is
  As per CMake documentation on CheckTypeSize, C preprocessor code is
@@ -703,6 +682,9 @@ ${SIZEOF_TIME_T_CODE}
 /* if Secure Transport is enabled */
 /* if Secure Transport is enabled */
 #cmakedefine USE_SECTRANSP 1
 #cmakedefine USE_SECTRANSP 1
 
 
+/* if SSL session export support is available */
+#cmakedefine USE_SSLS_EXPORT 1
+
 /* if mbedTLS is enabled */
 /* if mbedTLS is enabled */
 #cmakedefine USE_MBEDTLS 1
 #cmakedefine USE_MBEDTLS 1
 
 
@@ -742,6 +724,9 @@ ${SIZEOF_TIME_T_CODE}
 /* if OpenSSL is in use */
 /* if OpenSSL is in use */
 #cmakedefine USE_OPENSSL 1
 #cmakedefine USE_OPENSSL 1
 
 
+/* if AmiSSL is in use */
+#cmakedefine USE_AMISSL 1
+
 /* if librtmp/rtmpdump is in use */
 /* if librtmp/rtmpdump is in use */
 #cmakedefine USE_LIBRTMP 1
 #cmakedefine USE_LIBRTMP 1
 
 
@@ -791,12 +776,12 @@ ${SIZEOF_TIME_T_CODE}
 /* to enable Windows SSL  */
 /* to enable Windows SSL  */
 #cmakedefine USE_SCHANNEL 1
 #cmakedefine USE_SCHANNEL 1
 
 
+/* if Watt-32 is in use */
+#cmakedefine USE_WATT32 1
+
 /* enable multiple SSL backends */
 /* enable multiple SSL backends */
 #cmakedefine CURL_WITH_MULTI_SSL 1
 #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. */
 /* Number of bits in a file offset, on hosts where this is settable. */
 #cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
 #cmakedefine _FILE_OFFSET_BITS ${_FILE_OFFSET_BITS}
 
 
@@ -841,3 +826,9 @@ ${SIZEOF_TIME_T_CODE}
 
 
 /* if ECH support is available */
 /* if ECH support is available */
 #cmakedefine USE_ECH 1
 #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) == '_') || \
 #define ISURLPUNTCS(x) (((x) == '-') || ((x) == '.') || ((x) == '_') || \
                         ((x) == '~'))
                         ((x) == '~'))
 #define ISUNRESERVED(x) (ISALNUM(x) || ISURLPUNTCS(x))
 #define ISUNRESERVED(x) (ISALNUM(x) || ISURLPUNTCS(x))
-
+#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
 
 
 #endif /* HEADER_CURL_CTYPE_H */
 #endif /* HEADER_CURL_CTYPE_H */

+ 2 - 0
lib/curl_get_line.c

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

+ 6 - 0
lib/curl_get_line.h

@@ -26,6 +26,12 @@
 
 
 #include "dynbuf.h"
 #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. */
 /* Curl_get_line() returns complete lines that end with a newline. */
 int Curl_get_line(struct dynbuf *buf, FILE *input);
 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 */
 #else /* DEBUGBUILD */
 
 
   name[0] = '\0';
   name[0] = '\0';
+#ifdef __AMIGA__
+  err = gethostname((unsigned char *)name, namelen);
+#else
   err = gethostname(name, namelen);
   err = gethostname(name, namelen);
+#endif
 
 
 #endif
 #endif
 
 

+ 9 - 0
lib/curl_gssapi.c

@@ -40,6 +40,11 @@
 #define CURL_ALIGN8
 #define CURL_ALIGN8
 #endif
 #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 = {
 gss_OID_desc Curl_spnego_mech_oid CURL_ALIGN8 = {
   6, (char *)"\x2b\x06\x01\x05\x05\x02"
   6, (char *)"\x2b\x06\x01\x05\x05\x02"
 };
 };
@@ -149,4 +154,8 @@ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
 #endif
 #endif
 }
 }
 
 
+#if defined(__GNUC__) && defined(__APPLE__)
+#pragma GCC diagnostic pop
+#endif
+
 #endif /* HAVE_GSSAPI */
 #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>
 #include <curl/curl.h>
 
 

+ 212 - 21
lib/curl_multibyte.c

@@ -32,7 +32,7 @@
 
 
 #include "curl_setup.h"
 #include "curl_setup.h"
 
 
-#if defined(_WIN32)
+#ifdef _WIN32
 
 
 #include "curl_multibyte.h"
 #include "curl_multibyte.h"
 
 
@@ -84,16 +84,170 @@ char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
   return str_utf8;
   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 curlx_win32_open(const char *filename, int oflag, ...)
 {
 {
   int pmode = 0;
   int pmode = 0;
+  int result = -1;
+  TCHAR *fixed = NULL;
+  const TCHAR *target = NULL;
 
 
 #ifdef _UNICODE
 #ifdef _UNICODE
-  int result = -1;
   wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
   wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
 #endif
 #endif
 
 
@@ -105,58 +259,95 @@ int curlx_win32_open(const char *filename, int oflag, ...)
 
 
 #ifdef _UNICODE
 #ifdef _UNICODE
   if(filename_w) {
   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);
     curlx_unicodefree(filename_w);
   }
   }
   else
   else
     errno = EINVAL;
     errno = EINVAL;
-  return result;
 #else
 #else
-  return (_open)(filename, oflag, pmode);
+  if(fix_excessive_path(filename, &fixed))
+    target = fixed;
+  else
+    target = filename;
+  result = (_open)(target, oflag, pmode);
 #endif
 #endif
+
+  free(fixed);
+  return result;
 }
 }
 
 
 FILE *curlx_win32_fopen(const char *filename, const char *mode)
 FILE *curlx_win32_fopen(const char *filename, const char *mode)
 {
 {
-#ifdef _UNICODE
   FILE *result = NULL;
   FILE *result = NULL;
+  TCHAR *fixed = NULL;
+  const TCHAR *target = NULL;
+
+#ifdef _UNICODE
   wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
   wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
   wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
   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
   else
     errno = EINVAL;
     errno = EINVAL;
   curlx_unicodefree(filename_w);
   curlx_unicodefree(filename_w);
   curlx_unicodefree(mode_w);
   curlx_unicodefree(mode_w);
-  return result;
 #else
 #else
-  return (fopen)(filename, mode);
+  if(fix_excessive_path(filename, &fixed))
+    target = fixed;
+  else
+    target = filename;
+  result = (fopen)(target, mode);
 #endif
 #endif
+
+  free(fixed);
+  return result;
 }
 }
 
 
 int curlx_win32_stat(const char *path, struct_stat *buffer)
 int curlx_win32_stat(const char *path, struct_stat *buffer)
 {
 {
-#ifdef _UNICODE
   int result = -1;
   int result = -1;
+  TCHAR *fixed = NULL;
+  const TCHAR *target = NULL;
+
+#ifdef _UNICODE
   wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
   wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
   if(path_w) {
   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
 #else
-    result = _wstati64(path_w, buffer);
+    result = _wstati64(target, buffer);
 #endif
 #endif
     curlx_unicodefree(path_w);
     curlx_unicodefree(path_w);
   }
   }
   else
   else
     errno = EINVAL;
     errno = EINVAL;
-  return result;
 #else
 #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
 #else
-  return _stati64(path, buffer);
+  result = _stati64(target, buffer);
 #endif
 #endif
 #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,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMP,                            /* defport */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMP,                       /* protocol */
   CURLPROTO_RTMP,                       /* protocol */
   CURLPROTO_RTMP,                       /* family */
   CURLPROTO_RTMP,                       /* family */
@@ -109,6 +110,7 @@ const struct Curl_handler Curl_handler_rtmpt = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMPT,                           /* defport */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPT,                      /* protocol */
   CURLPROTO_RTMPT,                      /* protocol */
   CURLPROTO_RTMPT,                      /* family */
   CURLPROTO_RTMPT,                      /* family */
@@ -133,6 +135,7 @@ const struct Curl_handler Curl_handler_rtmpe = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMP,                            /* defport */
   PORT_RTMP,                            /* defport */
   CURLPROTO_RTMPE,                      /* protocol */
   CURLPROTO_RTMPE,                      /* protocol */
   CURLPROTO_RTMPE,                      /* family */
   CURLPROTO_RTMPE,                      /* family */
@@ -157,6 +160,7 @@ const struct Curl_handler Curl_handler_rtmpte = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMPT,                           /* defport */
   PORT_RTMPT,                           /* defport */
   CURLPROTO_RTMPTE,                     /* protocol */
   CURLPROTO_RTMPTE,                     /* protocol */
   CURLPROTO_RTMPTE,                     /* family */
   CURLPROTO_RTMPTE,                     /* family */
@@ -181,6 +185,7 @@ const struct Curl_handler Curl_handler_rtmps = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMPS,                           /* defport */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPS,                      /* protocol */
   CURLPROTO_RTMPS,                      /* protocol */
   CURLPROTO_RTMP,                       /* family */
   CURLPROTO_RTMP,                       /* family */
@@ -205,6 +210,7 @@ const struct Curl_handler Curl_handler_rtmpts = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_RTMPS,                           /* defport */
   PORT_RTMPS,                           /* defport */
   CURLPROTO_RTMPTS,                     /* protocol */
   CURLPROTO_RTMPTS,                     /* protocol */
   CURLPROTO_RTMPT,                      /* family */
   CURLPROTO_RTMPT,                      /* family */

+ 101 - 95
lib/curl_setup.h

@@ -31,13 +31,6 @@
 /* Tell "curl/curl.h" not to include "curl/mprintf.h" */
 /* Tell "curl/curl.h" not to include "curl/mprintf.h" */
 #define CURL_SKIP_INCLUDE_MPRINTF
 #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 */
 /* Set default _WIN32_WINNT */
 #ifdef __MINGW32__
 #ifdef __MINGW32__
 #include <_mingw.h>
 #include <_mingw.h>
@@ -85,13 +78,17 @@
 #endif
 #endif
 #endif
 #endif
 
 
-/*
- * Disable Visual Studio warnings:
- * 4127 "conditional expression is constant"
- */
 #ifdef _MSC_VER
 #ifdef _MSC_VER
+/* Disable Visual Studio warnings: 4127 "conditional expression is constant" */
 #pragma warning(disable:4127)
 #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
+#endif /* _MSC_VER */
 
 
 #ifdef _WIN32
 #ifdef _WIN32
 /*
 /*
@@ -100,26 +97,26 @@
  * Make sure to define this macro before including any Windows headers.
  * Make sure to define this macro before including any Windows headers.
  */
  */
 #  ifndef WIN32_LEAN_AND_MEAN
 #  ifndef WIN32_LEAN_AND_MEAN
-#    define WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
 #  endif
 #  endif
 #  ifndef NOGDI
 #  ifndef NOGDI
-#    define NOGDI
+#  define NOGDI
 #  endif
 #  endif
 /* Detect Windows App environment which has a restricted access
 /* Detect Windows App environment which has a restricted access
  * to the Win32 APIs. */
  * 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
 #endif
 #endif
 
 
 /* Compatibility */
 /* Compatibility */
-#if defined(ENABLE_IPV6)
-#  define USE_IPV6 1
+#ifdef ENABLE_IPV6
+#define USE_IPV6 1
 #endif
 #endif
 
 
 /*
 /*
@@ -133,12 +130,8 @@
 
 
 #else /* HAVE_CONFIG_H */
 #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
 #endif
 
 
 #ifdef macintosh
 #ifdef macintosh
@@ -149,10 +142,6 @@
 #  include "config-riscos.h"
 #  include "config-riscos.h"
 #endif
 #endif
 
 
-#ifdef __AMIGA__
-#  include "config-amigaos.h"
-#endif
-
 #ifdef __OS400__
 #ifdef __OS400__
 #  include "config-os400.h"
 #  include "config-os400.h"
 #endif
 #endif
@@ -161,10 +150,6 @@
 #  include "config-plan9.h"
 #  include "config-plan9.h"
 #endif
 #endif
 
 
-#ifdef MSDOS
-#  include "config-dos.h"
-#endif
-
 #endif /* HAVE_CONFIG_H */
 #endif /* HAVE_CONFIG_H */
 
 
 /* ================================================================ */
 /* ================================================================ */
@@ -183,7 +168,7 @@
 
 
 #ifdef NEED_THREAD_SAFE
 #ifdef NEED_THREAD_SAFE
 #  ifndef _THREAD_SAFE
 #  ifndef _THREAD_SAFE
-#    define _THREAD_SAFE
+#  define _THREAD_SAFE
 #  endif
 #  endif
 #endif
 #endif
 
 
@@ -195,14 +180,14 @@
 
 
 #ifdef NEED_REENTRANT
 #ifdef NEED_REENTRANT
 #  ifndef _REENTRANT
 #  ifndef _REENTRANT
-#    define _REENTRANT
+#  define _REENTRANT
 #  endif
 #  endif
 #endif
 #endif
 
 
 /* Solaris needs this to get a POSIX-conformant getpwuid_r */
 /* Solaris needs this to get a POSIX-conformant getpwuid_r */
 #if defined(sun) || defined(__sun)
 #if defined(sun) || defined(__sun)
 #  ifndef _POSIX_PTHREAD_SEMANTICS
 #  ifndef _POSIX_PTHREAD_SEMANTICS
-#    define _POSIX_PTHREAD_SEMANTICS 1
+#  define _POSIX_PTHREAD_SEMANTICS 1
 #  endif
 #  endif
 #endif
 #endif
 
 
@@ -290,14 +275,6 @@
 #  define CURL_DISABLE_HTTP_AUTH 1
 #  define CURL_DISABLE_HTTP_AUTH 1
 #endif
 #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 */
 /* No system header file shall be included in this file before this */
 /* point.                                                           */
 /* point.                                                           */
@@ -393,17 +370,23 @@
 #  endif
 #  endif
 #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
 #ifdef USE_LWIPSOCK
 #  include <lwip/init.h>
 #  include <lwip/init.h>
 #  include <lwip/sockets.h>
 #  include <lwip/sockets.h>
 #  include <lwip/netdb.h>
 #  include <lwip/netdb.h>
 #endif
 #endif
 
 
-#ifdef HAVE_EXTRA_STRICMP_H
+#ifdef macintosh
 #  include <extra/stricmp.h>
 #  include <extra/stricmp.h>
-#endif
-
-#ifdef HAVE_EXTRA_STRDUP_H
 #  include <extra/strdup.h>
 #  include <extra/strdup.h>
 #endif
 #endif
 
 
@@ -456,9 +439,9 @@
 #include <assert.h>
 #include <assert.h>
 
 
 #ifdef __TANDEM /* for ns*-tandem-nsk systems */
 #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
 #endif
 
 
 #ifndef STDC_HEADERS /* no standard C headers! */
 #ifndef STDC_HEADERS /* no standard C headers! */
@@ -494,11 +477,19 @@
    FILE *curlx_win32_fopen(const char *filename, const char *mode);
    FILE *curlx_win32_fopen(const char *filename, const char *mode);
 #endif
 #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.
  * Small file (<2Gb) support using Win32 functions.
  */
  */
 
 
-#ifdef USE_WIN32_SMALL_FILES
+#if defined(_WIN32) && !defined(USE_WIN32_LARGE_FILES)
 #  include <io.h>
 #  include <io.h>
 #  include <sys/types.h>
 #  include <sys/types.h>
 #  include <sys/stat.h>
 #  include <sys/stat.h>
@@ -518,11 +509,11 @@
 #endif
 #endif
 
 
 #ifndef struct_stat
 #ifndef struct_stat
-#  define struct_stat struct stat
+#define struct_stat struct stat
 #endif
 #endif
 
 
 #ifndef LSEEK_ERROR
 #ifndef LSEEK_ERROR
-#  define LSEEK_ERROR (off_t)-1
+#define LSEEK_ERROR (off_t)-1
 #endif
 #endif
 
 
 #ifndef SIZEOF_TIME_T
 #ifndef SIZEOF_TIME_T
@@ -593,8 +584,8 @@
 #  endif
 #  endif
 #  define CURL_UINT64_SUFFIX  CURL_SUFFIX_CURL_OFF_TU
 #  define CURL_UINT64_SUFFIX  CURL_SUFFIX_CURL_OFF_TU
 #  define CURL_UINT64_C(val)  CURL_CONC_MACROS(val,CURL_UINT64_SUFFIX)
 #  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
 #endif
 
 
 #define FMT_OFF_T CURL_FORMAT_CURL_OFF_T
 #define FMT_OFF_T CURL_FORMAT_CURL_OFF_T
@@ -693,9 +684,9 @@
 /*
 /*
  * MSVC threads support requires a multi-threaded runtime library.
  * MSVC threads support requires a multi-threaded runtime library.
  * _beginthreadex() is not available in single-threaded ones.
  * _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_POSIX
 #  undef USE_THREADS_WIN32
 #  undef USE_THREADS_WIN32
 #endif
 #endif
@@ -713,15 +704,15 @@
 #  define CURLRES_IPV4
 #  define CURLRES_IPV4
 #endif
 #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_ASYNCH
 #  define CURLRES_ARES
 #  define CURLRES_ARES
 /* now undef the stock libc functions just to avoid them being used */
 /* now undef the stock libc functions just to avoid them being used */
 #  undef HAVE_GETADDRINFO
 #  undef HAVE_GETADDRINFO
 #  undef HAVE_FREEADDRINFO
 #  undef HAVE_FREEADDRINFO
-#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
-#  define CURLRES_ASYNCH
-#  define CURLRES_THREADED
 #else
 #else
 #  define CURLRES_SYNCH
 #  define CURLRES_SYNCH
 #endif
 #endif
@@ -738,14 +729,23 @@
 #error "libidn2 cannot be enabled with WinIDN or AppleIDN, choose one."
 #error "libidn2 cannot be enabled with WinIDN or AppleIDN, choose one."
 #endif
 #endif
 
 
-#define LIBIDN_REQUIRED_VERSION "0.4.1"
-
 #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
 #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_MBEDTLS) || \
   defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
   defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || defined(USE_SECTRANSP) || \
   defined(USE_BEARSSL) || defined(USE_RUSTLS)
   defined(USE_BEARSSL) || defined(USE_RUSTLS)
 #define USE_SSL    /* SSL support has been enabled */
 #define USE_SSL    /* SSL support has been enabled */
 #endif
 #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)
 #if defined(USE_WOLFSSL) && defined(USE_GNUTLS)
 /* Avoid defining unprefixed wolfSSL SHA macros colliding with nettle ones */
 /* Avoid defining unprefixed wolfSSL SHA macros colliding with nettle ones */
 #define NO_OLD_WC_NAMES
 #define NO_OLD_WC_NAMES
@@ -776,10 +776,6 @@
 #  endif
 #  endif
 #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)
 #if defined(USE_LIBSSH2) || defined(USE_LIBSSH) || defined(USE_WOLFSSH)
 #define USE_SSH
 #define USE_SSH
 #endif
 #endif
@@ -812,7 +808,7 @@
 #if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) || \
 #if (defined(__GNUC__) && (__GNUC__ >= 3)) || defined(__clang__) || \
   defined(__IAR_SYSTEMS_ICC__)
   defined(__IAR_SYSTEMS_ICC__)
 #  define CURL_NORETURN  __attribute__((__noreturn__))
 #  define CURL_NORETURN  __attribute__((__noreturn__))
-#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+#elif defined(_MSC_VER)
 #  define CURL_NORETURN  __declspec(noreturn)
 #  define CURL_NORETURN  __declspec(noreturn)
 #else
 #else
 #  define CURL_NORETURN
 #  define CURL_NORETURN
@@ -843,7 +839,7 @@
  */
  */
 
 
 #ifndef Curl_nop_stmt
 #ifndef Curl_nop_stmt
-#  define Curl_nop_stmt do { } while(0)
+#define Curl_nop_stmt do { } while(0)
 #endif
 #endif
 
 
 /*
 /*
@@ -882,6 +878,14 @@
 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
 #endif
 #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.
 /* 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
 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
 #    define CURL_SA_FAMILY_T sa_family_t
 #  elif defined(HAVE_ADDRESS_FAMILY)
 #  elif defined(HAVE_ADDRESS_FAMILY)
 #    define CURL_SA_FAMILY_T ADDRESS_FAMILY
 #    define CURL_SA_FAMILY_T ADDRESS_FAMILY
+#  elif defined(__AMIGA__)
+#    define CURL_SA_FAMILY_T unsigned char
 #  else
 #  else
 /* use a sensible default */
 /* use a sensible default */
 #    define CURL_SA_FAMILY_T unsigned short
 #    define CURL_SA_FAMILY_T unsigned short
@@ -927,8 +933,9 @@ endings either CRLF or LF so 't' is appropriate.
    as their argument */
    as their argument */
 #define STRCONST(x) x,sizeof(x)-1
 #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;
 struct passwd;
 int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
                size_t buflen, struct passwd **result);
                size_t buflen, struct passwd **result);
@@ -940,8 +947,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #define UNITTEST static
 #define UNITTEST static
 #endif
 #endif
 
 
-/* Hyper supports HTTP2 also, but Curl's integration with Hyper does not */
-#if defined(USE_NGHTTP2)
+#ifdef USE_NGHTTP2
 #define USE_HTTP2
 #define USE_HTTP2
 #endif
 #endif
 
 
@@ -950,7 +956,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
     defined(USE_QUICHE) || defined(USE_MSH3)
     defined(USE_QUICHE) || defined(USE_MSH3)
 
 
 #ifdef CURL_WITH_MULTI_SSL
 #ifdef CURL_WITH_MULTI_SSL
-#error "Multi-SSL combined with QUIC is not supported"
+#error "MultiSSL combined with QUIC is not supported"
 #endif
 #endif
 
 
 #define USE_HTTP3
 #define USE_HTTP3
@@ -970,7 +976,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #    define UNIX_PATH_MAX 108
 #    define UNIX_PATH_MAX 108
      /* !checksrc! disable TYPEDEFSTRUCT 1 */
      /* !checksrc! disable TYPEDEFSTRUCT 1 */
      typedef struct sockaddr_un {
      typedef struct sockaddr_un {
-       ADDRESS_FAMILY sun_family;
+       CURL_SA_FAMILY_T sun_family;
        char sun_path[UNIX_PATH_MAX];
        char sun_path[UNIX_PATH_MAX];
      } SOCKADDR_UN, *PSOCKADDR_UN;
      } SOCKADDR_UN, *PSOCKADDR_UN;
 #    define WIN32_SOCKADDR_UN
 #    define WIN32_SOCKADDR_UN
@@ -983,26 +989,26 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #define OPENSSL_SUPPRESS_DEPRECATED
 #define OPENSSL_SUPPRESS_DEPRECATED
 #endif
 #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)
 #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
 #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
 #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
 #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
 
 
 #endif /* HEADER_CURL_SETUP_H */
 #endif /* HEADER_CURL_SETUP_H */

+ 10 - 16
lib/curl_setup_once.h

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

+ 1 - 1
lib/curl_sha256.h

@@ -26,7 +26,7 @@
  ***************************************************************************/
  ***************************************************************************/
 
 
 #if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \
 #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/curl.h>
 #include "curl_hmac.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__
 #ifdef __GNUC__
 #  if defined(__has_attribute) && defined(__STDC_VERSION__)
 #  if defined(__has_attribute) && defined(__STDC_VERSION__)
 #    if __has_attribute(always_inline) && __STDC_VERSION__ >= 199901
 #    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
 #  endif
 #endif
 #endif
 
 
-#if !defined(MHDX_INLINE) && \
+#if !defined(CURL_FORCEINLINE) && \
   defined(_MSC_VER) && !defined(__GNUC__) && !defined(__clang__)
   defined(_MSC_VER) && !defined(__GNUC__) && !defined(__clang__)
-#  if _MSC_VER >= 1400
-#    define MHDX_INLINE __forceinline
-#  endif
+#  define CURL_FORCEINLINE __forceinline
 #endif
 #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. */
     * macro was already defined correctly. */
-#  define MHDX_INLINE inline
+#  define CURL_FORCEINLINE CURL_INLINE
 #endif
 #endif
 
 
 /* Bits manipulation macros and functions.
 /* Bits manipulation macros and functions.
    Can be moved to other headers to reuse. */
    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))[0]) << 56) | \
     ((curl_uint64_t)(((const unsigned char*)(ptr))[1]) << 48) | \
     ((curl_uint64_t)(((const unsigned char*)(ptr))[1]) << 48) | \
     ((curl_uint64_t)(((const unsigned char*)(ptr))[2]) << 40) | \
     ((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))[6]) << 8)  | \
     (curl_uint64_t)(((const unsigned char*)(ptr))[7]) )
     (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))[7]=(unsigned char)((curl_uint64_t)(val));   \
     ((unsigned char*)(ptr))[6]=(unsigned char)(((curl_uint64_t)(val)) >> 8); \
     ((unsigned char*)(ptr))[6]=(unsigned char)(((curl_uint64_t)(val)) >> 8); \
     ((unsigned char*)(ptr))[5]=(unsigned char)(((curl_uint64_t)(val)) >> 16); \
     ((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
 /* 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
  * size as each argument is used twice, so if any calculation is used
  * as an argument, the calculation could be done twice. */
  * 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;
   bits %= 64;
   if(0 == bits)
   if(0 == bits)
@@ -388,7 +386,7 @@ MHDx_rotr64(curl_uint64_t value, unsigned int bits)
 /**
 /**
  * SHA-512/256 calculation context
  * SHA-512/256 calculation context
  */
  */
-struct mhdx_sha512_256ctx
+struct Curl_sha512_256ctx
 {
 {
   /**
   /**
    * Intermediate hash value. The variable is properly aligned. Smart
    * 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
  * 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
  * @return always CURLE_OK
  */
  */
 static CURLcode
 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 */
   /* Check whether the header and this file use the same numbers */
   DEBUGASSERT(CURL_SHA512_256_DIGEST_LENGTH == CURL_SHA512_256_DIGEST_SIZE);
   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
  * @param data  the data buffer with #CURL_SHA512_256_BLOCK_SIZE bytes block
  */
  */
 static void
 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)
                           const void *data)
 {
 {
   /* Working variables,
   /* Working variables,
@@ -488,13 +486,13 @@ MHDx_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS],
   /* Four 'Sigma' macro functions.
   /* Four 'Sigma' macro functions.
      See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
      See FIPS PUB 180-4 formulae 4.10, 4.11, 4.12, 4.13. */
 #define SIG0(x)                                                         \
 #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)                                                         \
 #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)                                                 \
 #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)                                                 \
 #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) {
   if(1) {
     unsigned int t;
     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,
        Input data must be read in big-endian bytes order,
        see FIPS PUB 180-4 section 3.1.2. */
        see FIPS PUB 180-4 section 3.1.2. */
 #define SHA512_GET_W_FROM_DATA(buf,t)                                   \
 #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)
       ((const unsigned char*) (buf)) + (t) * SHA512_256_BYTES_IN_WORD)
 
 
     /* During first 16 steps, before making any calculation on each step, the
     /* 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
  * @return always CURLE_OK
  */
  */
 static CURLcode
 static CURLcode
-MHDx_sha512_256_update(void *context,
+Curl_sha512_256_update(void *context,
                        const unsigned char *data,
                        const unsigned char *data,
                        size_t length)
                        size_t length)
 {
 {
   unsigned int bytes_have; /**< Number of bytes in the context buffer */
   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 */
   /* the void pointer here is required to mute Intel compiler warning */
   void *const ctx_buf = ctx->buffer;
   void *const ctx_buf = ctx->buffer;
 
 
@@ -661,7 +659,7 @@ MHDx_sha512_256_update(void *context,
              bytes_left);
              bytes_left);
       data += bytes_left;
       data += bytes_left;
       length -= bytes_left;
       length -= bytes_left;
-      MHDx_sha512_256_transform(ctx->H, ctx->buffer);
+      Curl_sha512_256_transform(ctx->H, ctx->buffer);
       bytes_have = 0;
       bytes_have = 0;
     }
     }
   }
   }
@@ -669,7 +667,7 @@ MHDx_sha512_256_update(void *context,
   while(CURL_SHA512_256_BLOCK_SIZE <= length) {
   while(CURL_SHA512_256_BLOCK_SIZE <= length) {
     /* Process any full blocks of new data directly,
     /* Process any full blocks of new data directly,
        without copying to the buffer. */
        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;
     data += CURL_SHA512_256_BLOCK_SIZE;
     length -= 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
  * @return always CURLE_OK
  */
  */
 static CURLcode
 static CURLcode
-MHDx_sha512_256_finish(unsigned char *digest,
+Curl_sha512_256_finish(unsigned char *digest,
                        void *context)
                        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 */
   curl_uint64_t num_bits;   /**< Number of processed bits */
   unsigned int bytes_have; /**< Number of bytes in the context buffer */
   unsigned int bytes_have; /**< Number of bytes in the context buffer */
   /* the void pointer here is required to mute Intel compiler warning */
   /* 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,
       memset(((unsigned char *) ctx_buf) + bytes_have, 0,
              CURL_SHA512_256_BLOCK_SIZE - bytes_have);
              CURL_SHA512_256_BLOCK_SIZE - bytes_have);
     /* Process the full block. */
     /* Process the full block. */
-    MHDx_sha512_256_transform(ctx->H, ctx->buffer);
+    Curl_sha512_256_transform(ctx->H, ctx->buffer);
     /* Start the new block. */
     /* Start the new block. */
     bytes_have = 0;
     bytes_have = 0;
   }
   }
@@ -754,37 +752,32 @@ MHDx_sha512_256_finish(unsigned char *digest,
      part of number of bits as big-endian values.
      part of number of bits as big-endian values.
      See FIPS PUB 180-4 section 5.1.2. */
      See FIPS PUB 180-4 section 5.1.2. */
   /* Note: the target location is predefined and buffer is always aligned */
   /* 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    \
                       + CURL_SHA512_256_BLOCK_SIZE    \
                       - SHA512_256_SIZE_OF_LEN_ADD,   \
                       - SHA512_256_SIZE_OF_LEN_ADD,   \
                       ctx->count_bits_hi);
                       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        \
                       + CURL_SHA512_256_BLOCK_SIZE        \
                       - SHA512_256_SIZE_OF_LEN_ADD        \
                       - SHA512_256_SIZE_OF_LEN_ADD        \
                       + SHA512_256_BYTES_IN_WORD,         \
                       + SHA512_256_BYTES_IN_WORD,         \
                       num_bits);
                       num_bits);
   /* Process the full final block. */
   /* 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.
   /* Put in BE mode the leftmost part of the hash as the final digest.
      See FIPS PUB 180-4 section 6.7. */
      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. */
   /* Erase potentially sensitive data. */
-  memset(ctx, 0, sizeof(struct mhdx_sha512_256ctx));
+  memset(ctx, 0, sizeof(struct Curl_sha512_256ctx));
 
 
   return CURLE_OK;
   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 */
 #endif /* Local SHA-512/256 code */
 
 
 
 

+ 6 - 6
lib/curl_sspi.h

@@ -81,27 +81,27 @@ extern PSecurityFunctionTable Curl_pSecFn;
 #endif
 #endif
 
 
 #ifndef SEC_I_SIGNATURE_NEEDED
 #ifndef SEC_I_SIGNATURE_NEEDED
-# define SEC_I_SIGNATURE_NEEDED               ((HRESULT)0x0009035CL)
+#define SEC_I_SIGNATURE_NEEDED                ((HRESULT)0x0009035CL)
 #endif
 #endif
 
 
 #ifndef CRYPT_E_REVOKED
 #ifndef CRYPT_E_REVOKED
-# define CRYPT_E_REVOKED                      ((HRESULT)0x80092010L)
+#define CRYPT_E_REVOKED                       ((HRESULT)0x80092010L)
 #endif
 #endif
 
 
 #ifndef CRYPT_E_NO_REVOCATION_DLL
 #ifndef CRYPT_E_NO_REVOCATION_DLL
-# define CRYPT_E_NO_REVOCATION_DLL            ((HRESULT)0x80092011L)
+#define CRYPT_E_NO_REVOCATION_DLL             ((HRESULT)0x80092011L)
 #endif
 #endif
 
 
 #ifndef CRYPT_E_NO_REVOCATION_CHECK
 #ifndef CRYPT_E_NO_REVOCATION_CHECK
-# define CRYPT_E_NO_REVOCATION_CHECK          ((HRESULT)0x80092012L)
+#define CRYPT_E_NO_REVOCATION_CHECK           ((HRESULT)0x80092012L)
 #endif
 #endif
 
 
 #ifndef CRYPT_E_REVOCATION_OFFLINE
 #ifndef CRYPT_E_REVOCATION_OFFLINE
-# define CRYPT_E_REVOCATION_OFFLINE           ((HRESULT)0x80092013L)
+#define CRYPT_E_REVOCATION_OFFLINE            ((HRESULT)0x80092013L)
 #endif
 #endif
 
 
 #ifndef CRYPT_E_NOT_IN_REVOCATION_DATABASE
 #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
 #endif
 
 
 #ifdef UNICODE
 #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 */
 #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)
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 struct curl_trc_feat Curl_trc_feat_ws = {
 struct curl_trc_feat Curl_trc_feat_ws = {
   "WS",
   "WS",
@@ -279,6 +297,9 @@ static struct trc_feat_def trc_feats[] = {
 #ifndef CURL_DISABLE_SMTP
 #ifndef CURL_DISABLE_SMTP
   { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
   { &Curl_trc_feat_smtp,      TRC_CT_PROTOCOL },
 #endif
 #endif
+#ifdef USE_SSL
+  { &Curl_trc_feat_ssls,      TRC_CT_NETWORK },
+#endif
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
   { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
   { &Curl_trc_feat_ws,        TRC_CT_PROTOCOL },
 #endif
 #endif
@@ -319,7 +340,7 @@ static struct trc_cft_def trc_cfts[] = {
 #ifdef USE_HTTP3
 #ifdef USE_HTTP3
   { &Curl_cft_http3,          TRC_CT_PROTOCOL },
   { &Curl_cft_http3,          TRC_CT_PROTOCOL },
 #endif
 #endif
-#if !defined(CURL_DISABLE_HTTP) && !defined(USE_HYPER)
+#if !defined(CURL_DISABLE_HTTP)
   { &Curl_cft_http_connect,   TRC_CT_PROTOCOL },
   { &Curl_cft_http_connect,   TRC_CT_PROTOCOL },
 #endif
 #endif
 };
 };
@@ -427,4 +448,53 @@ CURLcode Curl_trc_init(void)
   return CURLE_OK;
   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) */
 #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
 #define CURL_HAVE_C99
 #endif
 #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, ...) \
 #define infof(data, ...) \
   do { if(Curl_trc_is_verbose(data)) \
   do { if(Curl_trc_is_verbose(data)) \
          Curl_infof(data, __VA_ARGS__); } while(0)
          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)) \
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_smtp)) \
          Curl_trc_smtp(data, __VA_ARGS__); } while(0)
          Curl_trc_smtp(data, __VA_ARGS__); } while(0)
 #endif /* !CURL_DISABLE_SMTP */
 #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)
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #define CURL_TRC_WS(data, ...)                             \
 #define CURL_TRC_WS(data, ...)                             \
   do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_ws)) \
   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
 #ifndef CURL_DISABLE_SMTP
 #define CURL_TRC_SMTP  Curl_trc_smtp
 #define CURL_TRC_SMTP  Curl_trc_smtp
 #endif
 #endif
+#ifdef USE_SSL
+#define CURL_TRC_SSLS  Curl_trc_ssls
+#endif
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP)
 #define CURL_TRC_WS    Curl_trc_ws
 #define CURL_TRC_WS    Curl_trc_ws
 #endif
 #endif
@@ -140,40 +186,6 @@ extern struct curl_trc_feat Curl_trc_feat_write;
             (Curl_trc_is_verbose(data) && \
             (Curl_trc_is_verbose(data) && \
              (ft)->log_level >= CURL_LOG_LVL_INFO)
              (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) */
 #else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */
 /* All informational messages are not compiled in for size savings */
 /* 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_cf_is_verbose(x,y)   (FALSE)
 #define Curl_trc_ft_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 /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */
 
 
 #endif /* HEADER_CURL_TRC_H */
 #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,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_DICT,                            /* defport */
   PORT_DICT,                            /* defport */
   CURLPROTO_DICT,                       /* protocol */
   CURLPROTO_DICT,                       /* protocol */
   CURLPROTO_DICT,                       /* family */
   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 doh_probes *dohp;
   struct connectdata *conn = data->conn;
   struct connectdata *conn = data->conn;
   size_t i;
   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;
   *waitp = FALSE;
   (void)hostname;
   (void)hostname;
   (void)port;
   (void)port;
@@ -462,34 +456,23 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
 #endif
 #endif
 
 
 #ifdef USE_HTTPSRR
 #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);
       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],
     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);
                            data->multi, dohp->req_hds);
-    Curl_safefree(qname);
+    free(qname);
     if(result)
     if(result)
       goto error;
       goto error;
     dohp->pending++;
     dohp->pending++;
   }
   }
-# endif
 #endif
 #endif
   *waitp = TRUE; /* this never returns synchronously */
   *waitp = TRUE; /* this never returns synchronously */
   return NULL;
   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 */
       addr = (void *)ai->ai_addr; /* storage area for this info */
       DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
       DEBUGASSERT(sizeof(struct in_addr) == sizeof(de->addr[i].ip.v4));
       memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
       memcpy(&addr->sin_addr, &de->addr[i].ip.v4, sizeof(struct in_addr));
-#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);
       addr->sin_port = htons((unsigned short)port);
       break;
       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 */
       addr6 = (void *)ai->ai_addr; /* storage area for this info */
       DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
       DEBUGASSERT(sizeof(struct in6_addr) == sizeof(de->addr[i].ip.v6));
       memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
       memcpy(&addr6->sin6_addr, &de->addr[i].ip.v6, sizeof(struct in6_addr));
-#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);
       addr6->sin6_port = htons((unsigned short)port);
       break;
       break;
 #endif
 #endif
@@ -1089,62 +1064,6 @@ static CURLcode doh_decode_rdata_name(unsigned char **buf, size_t *remaining,
   return CURLE_OK;
   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
 #ifdef DEBUGBUILD
 static CURLcode doh_test_alpn_escapes(void)
 static CURLcode doh_test_alpn_escapes(void)
 {
 {
@@ -1156,24 +1075,20 @@ static CURLcode doh_test_alpn_escapes(void)
     0x68, 0x32                                      /* value "h2" */
     0x68, 0x32                                      /* value "h2" */
   };
   };
   size_t example_len = sizeof(example);
   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;
     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_BAD_CONTENT_ENCODING;
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 #endif
 #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)
                                         struct Curl_https_rrinfo **hrr)
 {
 {
-  size_t remaining = len;
-  unsigned char *cp = rrval;
   uint16_t pcode = 0, plen = 0;
   uint16_t pcode = 0, plen = 0;
   struct Curl_https_rrinfo *lhrr = NULL;
   struct Curl_https_rrinfo *lhrr = NULL;
   char *dnsname = 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)
   if(doh_test_alpn_escapes() != CURLE_OK)
     return CURLE_OUT_OF_MEMORY;
     return CURLE_OUT_OF_MEMORY;
 #endif
 #endif
+  if(len <= 2)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
   lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
   lhrr = calloc(1, sizeof(struct Curl_https_rrinfo));
   if(!lhrr)
   if(!lhrr)
     return CURLE_OUT_OF_MEMORY;
     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;
   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;
     goto err;
   lhrr->target = dnsname;
   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;
         goto err;
-    }
-    if(pcode == HTTPS_RR_CODE_NO_DEF_ALPN)
+      break;
+    case HTTPS_RR_CODE_NO_DEF_ALPN:
       lhrr->no_def_alpn = TRUE;
       lhrr->no_def_alpn = TRUE;
-    else if(pcode == HTTPS_RR_CODE_IPV4) {
+      break;
+    case HTTPS_RR_CODE_IPV4:
       if(!plen)
       if(!plen)
         goto err;
         goto err;
       lhrr->ipv4hints = Curl_memdup(cp, plen);
       lhrr->ipv4hints = Curl_memdup(cp, plen);
       if(!lhrr->ipv4hints)
       if(!lhrr->ipv4hints)
         goto err;
         goto err;
       lhrr->ipv4hints_len = (size_t)plen;
       lhrr->ipv4hints_len = (size_t)plen;
-    }
-    else if(pcode == HTTPS_RR_CODE_ECH) {
+      break;
+    case HTTPS_RR_CODE_ECH:
       if(!plen)
       if(!plen)
         goto err;
         goto err;
       lhrr->echconfiglist = Curl_memdup(cp, plen);
       lhrr->echconfiglist = Curl_memdup(cp, plen);
       if(!lhrr->echconfiglist)
       if(!lhrr->echconfiglist)
         goto err;
         goto err;
       lhrr->echconfiglist_len = (size_t)plen;
       lhrr->echconfiglist_len = (size_t)plen;
-    }
-    else if(pcode == HTTPS_RR_CODE_IPV6) {
+      break;
+    case HTTPS_RR_CODE_IPV6:
       if(!plen)
       if(!plen)
         goto err;
         goto err;
       lhrr->ipv6hints = Curl_memdup(cp, plen);
       lhrr->ipv6hints = Curl_memdup(cp, plen);
       if(!lhrr->ipv6hints)
       if(!lhrr->ipv6hints)
         goto err;
         goto err;
       lhrr->ipv6hints_len = (size_t)plen;
       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;
       cp += plen;
-      remaining -= plen;
+      len -= plen;
     }
     }
   }
   }
-  DEBUGASSERT(!remaining);
+  DEBUGASSERT(!len);
   *hrr = lhrr;
   *hrr = lhrr;
   return CURLE_OK;
   return CURLE_OK;
 err:
 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;
   return CURLE_OUT_OF_MEMORY;
 }
 }
 
 
@@ -1260,8 +1175,9 @@ static void doh_print_httpsrr(struct Curl_easy *data,
   DEBUGASSERT(hrr);
   DEBUGASSERT(hrr);
   infof(data, "HTTPS RR: priority %d, target: %s",
   infof(data, "HTTPS RR: priority %d, target: %s",
         hrr->priority, hrr->target);
         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
   else
     infof(data, "HTTPS RR: no alpns");
     infof(data, "HTTPS RR: no alpns");
   if(hrr->no_def_alpn)
   if(hrr->no_def_alpn)

+ 1 - 13
lib/doh.h

@@ -28,6 +28,7 @@
 #include "curl_addrinfo.h"
 #include "curl_addrinfo.h"
 #ifdef USE_HTTPSRR
 #ifdef USE_HTTPSRR
 # include <stdint.h>
 # include <stdint.h>
+# include "httpsrr.h"
 #endif
 #endif
 
 
 #ifndef CURL_DISABLE_DOH
 #ifndef CURL_DISABLE_DOH
@@ -123,19 +124,6 @@ struct dohaddr {
 
 
 #ifdef USE_HTTPSRR
 #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
  * These may need escaping when found within an ALPN string
  * value.
  * value.

+ 12 - 0
lib/dynbuf.c

@@ -244,6 +244,18 @@ char *Curl_dyn_ptr(const struct dynbuf *s)
   return s->bufr;
   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.
  * 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_uptr(a) curlx_dyn_uptr(a)
 #define Curl_dyn_len(a) curlx_dyn_len(a)
 #define Curl_dyn_len(a) curlx_dyn_len(a)
 #define Curl_dyn_reset(a) curlx_dyn_reset(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_tail(a,b) curlx_dyn_tail(a,b)
 #define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b)
 #define Curl_dyn_setlen(a,b) curlx_dyn_setlen(a,b)
 #define curlx_dynbuf dynbuf /* for the struct name */
 #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 */
 /* The implementation of this function exists in mprintf.c */
 int Curl_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save);
 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 */
 /* Dynamic buffer max sizes */
 #define DYN_DOH_RESPONSE    3000
 #define DYN_DOH_RESPONSE    3000
 #define DYN_DOH_CNAME       256
 #define DYN_DOH_CNAME       256

+ 55 - 3
lib/easy.c

@@ -48,6 +48,7 @@
 #include <curl/curl.h>
 #include <curl/curl.h>
 #include "transfer.h"
 #include "transfer.h"
 #include "vtls/vtls.h"
 #include "vtls/vtls.h"
+#include "vtls/vtls_scache.h"
 #include "url.h"
 #include "url.h"
 #include "getinfo.h"
 #include "getinfo.h"
 #include "hostip.h"
 #include "hostip.h"
@@ -761,12 +762,25 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
     return CURLE_FAILED_INIT;
     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)
   if(data->multi_easy)
     multi = data->multi_easy;
     multi = data->multi_easy;
   else {
   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)
     if(!multi)
       return CURLE_OUT_OF_MEMORY;
       return CURLE_OUT_OF_MEMORY;
   }
   }
@@ -1336,3 +1350,41 @@ CURLcode curl_easy_upkeep(CURL *d)
   /* Use the common function to keep connections alive. */
   /* Use the common function to keep connections alive. */
   return Curl_cpool_upkeep(data);
   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
 #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(;;) {
   for(;;) {
     if(!atomic_exchange_explicit(lock, true, memory_order_acquire))
     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();
       __builtin_ia32_pause();
 #elif defined(__aarch64__)
 #elif defined(__aarch64__)
       __asm__ volatile("yield" ::: "memory");
       __asm__ volatile("yield" ::: "memory");
+#elif defined(_WIN32)
+      Sleep(1);
 #elif defined(HAVE_SCHED_YIELD)
 #elif defined(HAVE_SCHED_YIELD)
       sched_yield();
       sched_yield();
 #endif
 #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);
   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)
 int Curl_easyopts_check(void)
 {
 {
-  return ((CURLOPT_LASTENTRY%10000) != (326 + 1));
+  return (CURLOPT_LASTENTRY % 10000) != (326 + 1);
 }
 }
 #endif
 #endif

+ 19 - 19
lib/file.c

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

+ 1 - 1
lib/fopen.c

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

+ 19 - 4
lib/ftp.c

@@ -250,6 +250,7 @@ const struct Curl_handler Curl_handler_ftp = {
   ZERO_NULL,                       /* write_resp_hd */
   ZERO_NULL,                       /* write_resp_hd */
   ZERO_NULL,                       /* connection_check */
   ZERO_NULL,                       /* connection_check */
   ZERO_NULL,                       /* attach connection */
   ZERO_NULL,                       /* attach connection */
+  ZERO_NULL,                       /* follow */
   PORT_FTP,                        /* defport */
   PORT_FTP,                        /* defport */
   CURLPROTO_FTP,                   /* protocol */
   CURLPROTO_FTP,                   /* protocol */
   CURLPROTO_FTP,                   /* family */
   CURLPROTO_FTP,                   /* family */
@@ -282,6 +283,7 @@ const struct Curl_handler Curl_handler_ftps = {
   ZERO_NULL,                       /* write_resp_hd */
   ZERO_NULL,                       /* write_resp_hd */
   ZERO_NULL,                       /* connection_check */
   ZERO_NULL,                       /* connection_check */
   ZERO_NULL,                       /* attach connection */
   ZERO_NULL,                       /* attach connection */
+  ZERO_NULL,                       /* follow */
   PORT_FTPS,                       /* defport */
   PORT_FTPS,                       /* defport */
   CURLPROTO_FTPS,                  /* protocol */
   CURLPROTO_FTPS,                  /* protocol */
   CURLPROTO_FTP,                   /* family */
   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,
       /* 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. */
          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 &&
       if(data->req.no_body &&
          ftpc->file &&
          ftpc->file &&
          data->set.get_filetime &&
          data->set.get_filetime &&
          (data->info.filetime >= 0) ) {
          (data->info.filetime >= 0) ) {
+#if defined(__GNUC__) && (defined(__DJGPP__) || defined(__AMIGA__))
+#pragma GCC diagnostic pop
+#endif
         char headerbuf[128];
         char headerbuf[128];
         int headerbuflen;
         int headerbuflen;
         time_t filetime = data->info.filetime;
         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);
   PINGPONG_SETUP(pp, ftp_statemachine, ftp_endofresp);
 
 
-  if(conn->handler->flags & PROTOPT_SSL) {
+  if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) {
     /* BLOCKING */
     /* BLOCKING */
     result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
     result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, done);
     if(result)
     if(result)
@@ -4097,8 +4108,8 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
 }
 }
 
 
 #ifdef _MSC_VER
 #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
 #endif
 
 
 /***********************************************************************
 /***********************************************************************
@@ -4244,7 +4255,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
       else
       else
         n -= ftpc->file ? strlen(ftpc->file) : 0;
         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");
         infof(data, "Request has same path as previous transfer");
         ftpc->cwddone = TRUE;
         ftpc->cwddone = TRUE;
       }
       }
@@ -4255,6 +4266,10 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
   return CURLE_OK;
   return CURLE_OK;
 }
 }
 
 
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
 /* call this when the DO phase has completed */
 /* call this when the DO phase has completed */
 static CURLcode ftp_dophase_done(struct Curl_easy *data, bool connected)
 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); */
 /* int send(int, const char *, int, int); */
 #define SEND_TYPE_ARG1 int
 #define SEND_TYPE_ARG1 int
+#define SEND_QUAL_ARG2
 #define SEND_TYPE_ARG2 char *
 #define SEND_TYPE_ARG2 char *
 #define SEND_TYPE_ARG3 int
 #define SEND_TYPE_ARG3 int
 #define SEND_TYPE_RETV 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->request_size = 0;
   info->proxyauthavail = 0;
   info->proxyauthavail = 0;
   info->httpauthavail = 0;
   info->httpauthavail = 0;
+  info->proxyauthpicked = 0;
+  info->httpauthpicked = 0;
   info->numconnects = 0;
   info->numconnects = 0;
 
 
   free(info->contenttype);
   free(info->contenttype);
@@ -238,8 +240,10 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
   case CURLINFO_FILETIME:
   case CURLINFO_FILETIME:
     if(data->info.filetime > LONG_MAX)
     if(data->info.filetime > LONG_MAX)
       *param_longp = LONG_MAX;
       *param_longp = LONG_MAX;
+#if !defined(MSDOS) && !defined(__AMIGA__)
     else if(data->info.filetime < LONG_MIN)
     else if(data->info.filetime < LONG_MIN)
       *param_longp = LONG_MIN;
       *param_longp = LONG_MIN;
+#endif
     else
     else
       *param_longp = (long)data->info.filetime;
       *param_longp = (long)data->info.filetime;
     break;
     break;
@@ -270,6 +274,14 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
     lptr.to_long = param_longp;
     lptr.to_long = param_longp;
     *lptr.to_ulong = data->info.proxyauthavail;
     *lptr.to_ulong = data->info.proxyauthavail;
     break;
     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:
   case CURLINFO_OS_ERRNO:
     *param_longp = data->state.os_errno;
     *param_longp = data->state.os_errno;
     break;
     break;
@@ -377,6 +389,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
     case CURLINFO_APPCONNECT_TIME_T:
     case CURLINFO_APPCONNECT_TIME_T:
     case CURLINFO_PRETRANSFER_TIME_T:
     case CURLINFO_PRETRANSFER_TIME_T:
     case CURLINFO_POSTTRANSFER_TIME_T:
     case CURLINFO_POSTTRANSFER_TIME_T:
+    case CURLINFO_QUEUE_TIME_T:
     case CURLINFO_STARTTRANSFER_TIME_T:
     case CURLINFO_STARTTRANSFER_TIME_T:
     case CURLINFO_REDIRECT_TIME_T:
     case CURLINFO_REDIRECT_TIME_T:
     case CURLINFO_SPEED_DOWNLOAD_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,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_GOPHER,                          /* defport */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHER,                     /* protocol */
   CURLPROTO_GOPHER,                     /* protocol */
   CURLPROTO_GOPHER,                     /* family */
   CURLPROTO_GOPHER,                     /* family */
@@ -104,6 +105,7 @@ const struct Curl_handler Curl_handler_gophers = {
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* write_resp_hd */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* connection_check */
   ZERO_NULL,                            /* attach connection */
   ZERO_NULL,                            /* attach connection */
+  ZERO_NULL,                            /* follow */
   PORT_GOPHER,                          /* defport */
   PORT_GOPHER,                          /* defport */
   CURLPROTO_GOPHERS,                    /* protocol */
   CURLPROTO_GOPHERS,                    /* protocol */
   CURLPROTO_GOPHER,                     /* family */
   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 *h = (struct Curl_hash *) user;
   struct Curl_hash_element *e = (struct Curl_hash_element *) element;
   struct Curl_hash_element *e = (struct Curl_hash_element *) element;
+  DEBUGASSERT(h);
+  DEBUGASSERT(e);
 
 
   if(e->ptr) {
   if(e->ptr) {
     if(e->dtor)
     if(e->dtor)

+ 3 - 2
lib/hmac.c

@@ -26,8 +26,9 @@
 
 
 #include "curl_setup.h"
 #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>
 #include <curl/curl.h>
 
 

+ 8 - 14
lib/hostip.c

@@ -198,7 +198,7 @@ hostcache_entry_is_stale(void *datap, void *hc)
   if(dns->timestamp) {
   if(dns->timestamp) {
     /* age in seconds */
     /* age in seconds */
     time_t age = prune->now - dns->timestamp;
     time_t age = prune->now - dns->timestamp;
-    if(age >= prune->max_age_sec)
+    if(age >= (time_t)prune->max_age_sec)
       return TRUE;
       return TRUE;
     if(age > prune->oldest)
     if(age > prune->oldest)
       prune->oldest = age;
       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_family = AF_INET6;
   sa6.sin6_port = htons(port16);
   sa6.sin6_port = htons(port16);
   sa6.sin6_flowinfo = 0;
   sa6.sin6_flowinfo = 0;
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
   sa6.sin6_scope_id = 0;
   sa6.sin6_scope_id = 0;
+#endif
 
 
   (void)Curl_inet_pton(AF_INET6, "::1", ipv6);
   (void)Curl_inet_pton(AF_INET6, "::1", ipv6);
   memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
   memcpy(&sa6.sin6_addr, ipv6, sizeof(ipv6));
@@ -630,7 +632,7 @@ bool Curl_ipv6works(struct Curl_easy *data)
       ipv6_works = 1;
       ipv6_works = 1;
       sclose(s);
       sclose(s);
     }
     }
-    return (ipv6_works > 0);
+    return ipv6_works > 0;
   }
   }
 }
 }
 #endif /* USE_IPV6 */
 #endif /* USE_IPV6 */
@@ -1077,18 +1079,10 @@ static void hostcache_unlink_entry(void *entry)
     Curl_freeaddrinfo(dns->addr);
     Curl_freeaddrinfo(dns->addr);
 #ifdef USE_HTTPSRR
 #ifdef USE_HTTPSRR
     if(dns->hinfo) {
     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);
       free(dns->hinfo);
     }
     }
 #endif
 #endif

+ 8 - 30
lib/hostip.h

@@ -29,6 +29,7 @@
 #include "curl_addrinfo.h"
 #include "curl_addrinfo.h"
 #include "timeval.h" /* for timediff_t */
 #include "timeval.h" /* for timediff_t */
 #include "asyn.h"
 #include "asyn.h"
+#include "httpsrr.h"
 
 
 #include <setjmp.h>
 #include <setjmp.h>
 
 
@@ -53,6 +54,13 @@ struct hostent;
 struct Curl_easy;
 struct Curl_easy;
 struct connectdata;
 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.
  * 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
  * 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);
 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_dns_entry {
   struct Curl_addrinfo *addr;
   struct Curl_addrinfo *addr;
 #ifdef USE_HTTPSRR
 #ifdef USE_HTTPSRR

+ 37 - 28
lib/hsts.c

@@ -41,6 +41,7 @@
 #include "rename.h"
 #include "rename.h"
 #include "share.h"
 #include "share.h"
 #include "strdup.h"
 #include "strdup.h"
+#include "strparse.h"
 
 
 /* The last 3 #include files should be in this order */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_printf.h"
@@ -48,10 +49,8 @@
 #include "memdebug.h"
 #include "memdebug.h"
 
 
 #define MAX_HSTS_LINE 4095
 #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"
 #define UNLIMITED "unlimited"
 
 
 #if defined(DEBUGBUILD) || defined(UNITTESTS)
 #if defined(DEBUGBUILD) || defined(UNITTESTS)
@@ -109,14 +108,13 @@ void Curl_hsts_cleanup(struct hsts **hp)
 
 
 static CURLcode hsts_create(struct hsts *h,
 static CURLcode hsts_create(struct hsts *h,
                             const char *hostname,
                             const char *hostname,
+                            size_t hlen,
                             bool subdomains,
                             bool subdomains,
                             curl_off_t expires)
                             curl_off_t expires)
 {
 {
-  size_t hlen;
   DEBUGASSERT(h);
   DEBUGASSERT(h);
   DEBUGASSERT(hostname);
   DEBUGASSERT(hostname);
 
 
-  hlen = strlen(hostname);
   if(hlen && (hostname[hlen - 1] == '.'))
   if(hlen && (hostname[hlen - 1] == '.'))
     /* strip off any trailing dot */
     /* strip off any trailing dot */
     --hlen;
     --hlen;
@@ -150,6 +148,7 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
   bool subdomains = FALSE;
   bool subdomains = FALSE;
   struct stsentry *sts;
   struct stsentry *sts;
   time_t now = time(NULL);
   time_t now = time(NULL);
+  size_t hlen = strlen(hostname);
 
 
   if(Curl_host_is_ipnum(hostname))
   if(Curl_host_is_ipnum(hostname))
     /* "explicit IP address identification of all forms is excluded."
     /* "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) {
   if(!expires) {
     /* remove the entry if present verbatim (without subdomain match) */
     /* remove the entry if present verbatim (without subdomain match) */
-    sts = Curl_hsts(h, hostname, FALSE);
+    sts = Curl_hsts(h, hostname, hlen, FALSE);
     if(sts) {
     if(sts) {
       Curl_node_remove(&sts->node);
       Curl_node_remove(&sts->node);
       hsts_free(sts);
       hsts_free(sts);
@@ -233,14 +232,14 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
     expires += now;
     expires += now;
 
 
   /* check if it already exists */
   /* check if it already exists */
-  sts = Curl_hsts(h, hostname, FALSE);
+  sts = Curl_hsts(h, hostname, hlen, FALSE);
   if(sts) {
   if(sts) {
     /* just update these fields */
     /* just update these fields */
     sts->expires = expires;
     sts->expires = expires;
     sts->includeSubDomains = subdomains;
     sts->includeSubDomains = subdomains;
   }
   }
   else
   else
-    return hsts_create(h, hostname, subdomains, expires);
+    return hsts_create(h, hostname, hlen, subdomains, expires);
 
 
   return CURLE_OK;
   return CURLE_OK;
 }
 }
@@ -252,12 +251,11 @@ CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
  * attempted.
  * attempted.
  */
  */
 struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
 struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
-                           bool subdomain)
+                           size_t hlen, bool subdomain)
 {
 {
   struct stsentry *bestsub = NULL;
   struct stsentry *bestsub = NULL;
   if(h) {
   if(h) {
     time_t now = time(NULL);
     time_t now = time(NULL);
-    size_t hlen = strlen(hostname);
     struct Curl_llist_node *e;
     struct Curl_llist_node *e;
     struct Curl_llist_node *n;
     struct Curl_llist_node *n;
     size_t blen = 0;
     size_t blen = 0;
@@ -424,29 +422,40 @@ static CURLcode hsts_add(struct hsts *h, char *line)
      example.com "20191231 10:00:00"
      example.com "20191231 10:00:00"
      .example.net "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;
     CURLcode result = CURLE_OK;
-    char *p = host;
     bool subdomain = FALSE;
     bool subdomain = FALSE;
     struct stsentry *e;
     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;
       subdomain = TRUE;
     }
     }
     /* only add it if not already present */
     /* only add it if not already present */
-    e = Curl_hsts(h, p, subdomain);
+    e = Curl_hsts(h, host.str, host.len, subdomain);
     if(!e)
     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 */
       /* the same hostname, use the largest expire time */
       if(expires > e->expires)
       if(expires > e->expires)
         e->expires = 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);
           expires = Curl_getdate_capped(e.expire);
         else
         else
           expires = TIME_T_MAX; /* the end of time */
           expires = TIME_T_MAX; /* the end of time */
-        result = hsts_create(h, e.name,
+        result = hsts_create(h, e.name, strlen(e.name),
                              /* bitfield to bool conversion: */
                              /* bitfield to bool conversion: */
                              e.includeSubDomains ? TRUE : FALSE,
                              e.includeSubDomains ? TRUE : FALSE,
                              expires);
                              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,
 CURLcode Curl_hsts_parse(struct hsts *h, const char *hostname,
                          const char *sts);
                          const char *sts);
 struct stsentry *Curl_hsts(struct hsts *h, const char *hostname,
 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,
 CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
                         const char *file);
                         const char *file);
 CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
 CURLcode Curl_hsts_loadfile(struct Curl_easy *data,

ファイルの差分が大きいため隠しています
+ 430 - 137
lib/http.c


この差分においてかなりの量のファイルが変更されているため、一部のファイルを表示していません