Răsfoiți Sursa

curl 2022-04-27 (1669b17d)

Code extracted from:

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

at commit 1669b17d3a1a1fd824308544ca0ec02a2a4f50ea (curl-7_83_0).
Curl Upstream 3 ani în urmă
părinte
comite
2a9bc9ebf0
100 a modificat fișierele cu 2386 adăugiri și 2501 ștergeri
  1. 2 2
      CMake/CurlTests.c
  2. 68 0
      CMake/FindMSH3.cmake
  3. 3 3
      CMake/OtherTests.cmake
  4. 12 9
      CMakeLists.txt
  5. 1 1
      COPYING
  6. 10 22
      include/curl/curl.h
  7. 5 5
      include/curl/curlver.h
  8. 64 0
      include/curl/header.h
  9. 2 2
      include/curl/options.h
  10. 2 18
      include/curl/system.h
  11. 17 13
      lib/Makefile.inc
  12. 5 3
      lib/altsvc.c
  13. 3 2
      lib/asyn-ares.c
  14. 6 29
      lib/base64.c
  15. 14 13
      lib/c-hyper.c
  16. 26 37
      lib/conncache.c
  17. 2 3
      lib/conncache.h
  18. 24 13
      lib/connect.c
  19. 9 6
      lib/cookie.c
  20. 3 6
      lib/curl_base64.h
  21. 4 1
      lib/curl_config.h.cmake
  22. 1 4
      lib/curl_ctype.c
  23. 1 29
      lib/curl_ctype.h
  24. 8 3
      lib/curl_des.c
  25. 8 3
      lib/curl_des.h
  26. 2 2
      lib/curl_gssapi.c
  27. 6 6
      lib/curl_multibyte.c
  28. 12 34
      lib/curl_ntlm_core.c
  29. 5 26
      lib/curl_ntlm_core.h
  30. 2 2
      lib/curl_path.c
  31. 9 11
      lib/curl_sasl.c
  32. 2 2
      lib/curl_sasl.h
  33. 8 35
      lib/curl_setup.h
  34. 2 2
      lib/curl_sha256.h
  35. 5 9
      lib/dict.c
  36. 4 4
      lib/doh.c
  37. 2 2
      lib/dotdot.c
  38. 2 11
      lib/easy.c
  39. 8 29
      lib/escape.c
  40. 2 3
      lib/escape.h
  41. 2 2
      lib/file.c
  42. 8 15
      lib/formdata.c
  43. 16 12
      lib/ftp.c
  44. 2 2
      lib/gopher.c
  45. 310 0
      lib/h2h3.c
  46. 59 0
      lib/h2h3.h
  47. 324 0
      lib/headers.c
  48. 53 0
      lib/headers.h
  49. 3 3
      lib/hmac.c
  50. 7 6
      lib/hostip.c
  51. 2 2
      lib/hsts.c
  52. 153 169
      lib/http.c
  53. 56 3
      lib/http.h
  54. 72 288
      lib/http2.c
  55. 3 3
      lib/http_aws_sigv4.c
  56. 5 30
      lib/http_chunks.c
  57. 2 2
      lib/http_negotiate.c
  58. 3 5
      lib/http_ntlm.c
  59. 29 24
      lib/http_proxy.c
  60. 2 1
      lib/http_proxy.h
  61. 17 9
      lib/idn_win32.c
  62. 27 19
      lib/if2ip.c
  63. 11 3
      lib/if2ip.h
  64. 10 10
      lib/imap.c
  65. 3 9
      lib/krb5.c
  66. 12 15
      lib/ldap.c
  67. 102 56
      lib/md5.c
  68. 34 91
      lib/mime.c
  69. 5 4
      lib/mime.h
  70. 3 2
      lib/mprintf.c
  71. 24 5
      lib/mqtt.c
  72. 25 19
      lib/multi.c
  73. 0 336
      lib/non-ascii.c
  74. 0 61
      lib/non-ascii.h
  75. 2 2
      lib/nonblock.c
  76. 0 327
      lib/nwlib.c
  77. 0 88
      lib/nwos.c
  78. 338 35
      lib/openldap.c
  79. 2 13
      lib/pingpong.c
  80. 8 8
      lib/pop3.c
  81. 4 1
      lib/quic.h
  82. 2 2
      lib/rand.c
  83. 22 19
      lib/rtsp.c
  84. 4 88
      lib/select.c
  85. 3 14
      lib/select.h
  86. 23 65
      lib/sendf.c
  87. 7 3
      lib/sendf.h
  88. 15 36
      lib/setopt.c
  89. 9 3
      lib/sha256.c
  90. 11 12
      lib/smb.c
  91. 9 10
      lib/smtp.c
  92. 1 1
      lib/socks.c
  93. 2 2
      lib/socks.h
  94. 15 125
      lib/strcase.c
  95. 8 5
      lib/strcase.h
  96. 5 24
      lib/strerror.c
  97. 3 3
      lib/telnet.c
  98. 4 4
      lib/tftp.c
  99. 84 0
      lib/timediff.c
  100. 50 0
      lib/timediff.h

+ 2 - 2
CMake/CurlTests.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -56,7 +56,7 @@ return 0;
 # define PLATFORM_AIX_V3
 #endif
 /* */
-#if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3) || defined(__BEOS__)
+#if defined(PLATFORM_SUNOS4) || defined(PLATFORM_AIX_V3)
 #error "O_NONBLOCK does not work on this platform"
 #endif
 

+ 68 - 0
CMake/FindMSH3.cmake

@@ -0,0 +1,68 @@
+#***************************************************************************
+#                                  _   _ ____  _
+#  Project                     ___| | | |  _ \| |
+#                             / __| | | | |_) | |
+#                            | (__| |_| |  _ <| |___
+#                             \___|\___/|_| \_\_____|
+#
+# Copyright (C) 1998 - 2022, 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.
+#
+###########################################################################
+
+#[=======================================================================[.rst:
+FindMSH3
+----------
+
+Find the msh3 library
+
+Result Variables
+^^^^^^^^^^^^^^^^
+
+``MSH3_FOUND``
+  System has msh3
+``MSH3_INCLUDE_DIRS``
+  The msh3 include directories.
+``MSH3_LIBRARIES``
+  The libraries needed to use msh3
+#]=======================================================================]
+if(UNIX)
+  find_package(PkgConfig QUIET)
+  pkg_search_module(PC_MSH3 libmsh3)
+endif()
+
+find_path(MSH3_INCLUDE_DIR msh3.h
+  HINTS
+    ${PC_MSH3_INCLUDEDIR}
+    ${PC_MSH3_INCLUDE_DIRS}
+)
+
+find_library(MSH3_LIBRARY NAMES msh3
+  HINTS
+    ${PC_MSH3_LIBDIR}
+    ${PC_MSH3_LIBRARY_DIRS}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(MSH3
+  REQUIRED_VARS
+    MSH3_LIBRARY
+    MSH3_INCLUDE_DIR
+)
+
+if(MSH3_FOUND)
+  set(MSH3_LIBRARIES    ${MSH3_LIBRARY})
+  set(MSH3_INCLUDE_DIRS ${MSH3_INCLUDE_DIR})
+endif()
+
+mark_as_advanced(MSH3_INCLUDE_DIRS MSH3_LIBRARIES)

+ 3 - 3
CMake/OtherTests.cmake

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2022, 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
@@ -236,8 +236,8 @@ endif()
 unset(CMAKE_TRY_COMPILE_TARGET_TYPE)
 
 if(NOT DEFINED CMAKE_TOOLCHAIN_FILE)
-  if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
-  # only try this on non-macOS
+  if(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Darwin" AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "iOS")
+  # only try this on non-apple platforms
 
   # if not cross-compilation...
   include(CheckCSourceRuns)

+ 12 - 9
CMakeLists.txt

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2022, 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
@@ -109,7 +109,7 @@ option(ENABLE_CURLDEBUG "Set to ON to build with TrackMemory feature enabled" OF
 
 if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_CLANG)
   if(PICKY_COMPILER)
-    foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wfloat-equal -Wsign-compare -Wundef -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wvla -Wdouble-promotion)
+    foreach(_CCOPT -pedantic -Wall -W -Wpointer-arith -Wwrite-strings -Wunused -Wshadow -Winline -Wnested-externs -Wmissing-declarations -Wmissing-prototypes -Wfloat-equal -Wsign-compare -Wundef -Wendif-labels -Wstrict-prototypes -Wdeclaration-after-statement -Wstrict-aliasing=3 -Wcast-align -Wtype-limits -Wold-style-declaration -Wmissing-parameter-type -Wempty-body -Wclobbered -Wignored-qualifiers -Wconversion -Wvla -Wdouble-promotion -Wenum-conversion -Warith-conversion)
       # surprisingly, CHECK_C_COMPILER_FLAG needs a new variable to store each new
       # test result in.
       string(MAKE_C_IDENTIFIER "OPT${_CCOPT}" _optvarname)
@@ -334,13 +334,6 @@ check_library_exists_concat("${CMAKE_DL_LIBS}" dlopen HAVE_LIBDL)
 check_library_exists_concat("socket" connect      HAVE_LIBSOCKET)
 check_library_exists("c" gethostbyname "" NOT_NEED_LIBNSL)
 
-# Yellowtab Zeta needs different libraries than BeOS 5.
-if(BEOS)
-  set(NOT_NEED_LIBNSL 1)
-  check_library_exists_concat("bind" gethostbyname HAVE_LIBBIND)
-  check_library_exists_concat("bnetapi" closesocket HAVE_LIBBNETAPI)
-endif()
-
 if(NOT NOT_NEED_LIBNSL)
   check_library_exists_concat("nsl"    gethostbyname  HAVE_LIBNSL)
 endif()
@@ -563,6 +556,16 @@ if(USE_QUICHE)
   cmake_pop_check_state()
 endif()
 
+option(USE_MSH3 "Use msquic library for HTTP/3 support" OFF)
+if(USE_MSH3)
+  if(USE_NGTCP2 OR USE_QUICHE)
+    message(FATAL_ERROR "Only one HTTP/3 backend can be selected!")
+  endif()
+  set(USE_MSH3 ON)
+  include_directories(${MSH3_INCLUDE_DIRS})
+  list(APPEND CURL_LIBS ${MSH3_LIBRARIES})
+endif()
+
 if(NOT CURL_DISABLE_LDAP)
   if(WIN32)
     option(USE_WIN32_LDAP "Use Windows LDAP implementation" ON)

+ 1 - 1
COPYING

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

+ 10 - 22
include/curl/curl.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -73,8 +73,7 @@
     defined(ANDROID) || defined(__ANDROID__) || defined(__OpenBSD__) || \
     defined(__CYGWIN__) || defined(AMIGA) || defined(__NuttX__) || \
    (defined(__FreeBSD_version) && (__FreeBSD_version < 800000)) || \
-   (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000)) || \
-    defined(__VXWORKS__)
+   (defined(__MidnightBSD_version) && (__MidnightBSD_version < 100000))
 #include <sys/select.h>
 #endif
 
@@ -82,14 +81,10 @@
 #include <sys/socket.h>
 #endif
 
-#if !defined(CURL_WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
+#if !defined(CURL_WIN32)
 #include <sys/time.h>
 #endif
 
-#ifdef __BEOS__
-#include <support/SupportDefs.h>
-#endif
-
 /* Compatibility for non-Clang compilers */
 #ifndef __has_declspec_attribute
 #  define __has_declspec_attribute(x) 0
@@ -529,10 +524,6 @@ typedef enum {
   CURLE_UPLOAD_FAILED,           /* 25 - failed upload "command" */
   CURLE_READ_ERROR,              /* 26 - couldn't open/read from file */
   CURLE_OUT_OF_MEMORY,           /* 27 */
-  /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
-           instead of a memory allocation error if CURL_DOES_CONVERSIONS
-           is defined
-  */
   CURLE_OPERATION_TIMEDOUT,      /* 28 - the timeout time was reached */
   CURLE_OBSOLETE29,              /* 29 - NOT USED */
   CURLE_FTP_PORT_FAILED,         /* 30 - FTP PORT operation failed */
@@ -569,7 +560,7 @@ typedef enum {
   CURLE_PEER_FAILED_VERIFICATION, /* 60 - peer's certificate or fingerprint
                                      wasn't verified fine */
   CURLE_BAD_CONTENT_ENCODING,    /* 61 - Unrecognized/bad encoding */
-  CURLE_LDAP_INVALID_URL,        /* 62 - Invalid LDAP URL */
+  CURLE_OBSOLETE62,              /* 62 - NOT IN USE since 7.82.0 */
   CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
   CURLE_USE_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
   CURLE_SEND_FAIL_REWIND,        /* 65 - Sending the data requires a rewind
@@ -585,11 +576,7 @@ typedef enum {
   CURLE_REMOTE_FILE_EXISTS,      /* 73 - File already exists */
   CURLE_TFTP_NOSUCHUSER,         /* 74 - No such user */
   CURLE_CONV_FAILED,             /* 75 - conversion failed */
-  CURLE_CONV_REQD,               /* 76 - caller must register conversion
-                                    callbacks using curl_easy_setopt options
-                                    CURLOPT_CONV_FROM_NETWORK_FUNCTION,
-                                    CURLOPT_CONV_TO_NETWORK_FUNCTION, and
-                                    CURLOPT_CONV_FROM_UTF8_FUNCTION */
+  CURLE_OBSOLETE76,              /* 76 - NOT IN USE since 7.82.0 */
   CURLE_SSL_CACERT_BADFILE,      /* 77 - could not load CACERT file, missing
                                     or wrong format */
   CURLE_REMOTE_FILE_NOT_FOUND,   /* 78 - remote file not found */
@@ -683,13 +670,13 @@ typedef enum {
 /* The following were added earlier */
 
 #define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT
-
 #define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
 #define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
 #define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED
-
 #define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
 #define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+#define CURLE_LDAP_INVALID_URL CURLE_OBSOLETE62
+#define CURLE_CONV_REQD CURLE_OBSOLETE76
 
 /* This was the error code 50 in 7.7.3 and a few earlier versions, this
    is no longer used by libcurl but is instead #defined here only to not
@@ -2062,7 +2049,7 @@ typedef enum {
    * (in seconds) */
   CURLOPT(CURLOPT_MAXAGE_CONN, CURLOPTTYPE_LONG, 288),
 
-  /* SASL authorisation identity */
+  /* SASL authorization identity */
   CURLOPT(CURLOPT_SASL_AUTHZID, CURLOPTTYPE_STRINGPOINT, 289),
 
   /* allow RCPT TO command to fail for some recipients */
@@ -2832,7 +2819,7 @@ typedef enum {
   CURLCLOSEPOLICY_LAST /* last, never use this */
 } curl_closepolicy;
 
-#define CURL_GLOBAL_SSL (1<<0) /* no purpose since since 7.57.0 */
+#define CURL_GLOBAL_SSL (1<<0) /* no purpose since 7.57.0 */
 #define CURL_GLOBAL_WIN32 (1<<1)
 #define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
 #define CURL_GLOBAL_NOTHING 0
@@ -3082,6 +3069,7 @@ CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
 #include "multi.h"
 #include "urlapi.h"
 #include "options.h"
+#include "header.h"
 
 /* the typechecker doesn't work in C++ (yet) */
 #if defined(__GNUC__) && defined(__GNUC_MINOR__) && \

+ 5 - 5
include/curl/curlver.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -26,16 +26,16 @@
    a script at release-time. This was made its own header file in 7.11.2 */
 
 /* This is the global package copyright */
-#define LIBCURL_COPYRIGHT "1996 - 2021 Daniel Stenberg, <[email protected]>."
+#define LIBCURL_COPYRIGHT "1996 - 2022 Daniel Stenberg, <[email protected]>."
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.81.0-DEV"
+#define LIBCURL_VERSION "7.83.0-DEV"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 81
+#define LIBCURL_VERSION_MINOR 83
 #define LIBCURL_VERSION_PATCH 0
 
 /* This is the numeric version of the libcurl version number, meant for easier
@@ -57,7 +57,7 @@
    CURL_VERSION_BITS() macro since curl's own configure script greps for it
    and needs it to contain the full number.
 */
-#define LIBCURL_VERSION_NUM 0x075100
+#define LIBCURL_VERSION_NUM 0x075300
 
 /*
  * This is the date and time when the full source package was created. The

+ 64 - 0
include/curl/header.h

@@ -0,0 +1,64 @@
+#ifndef CURLINC_HEADER_H
+#define CURLINC_HEADER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2018 - 2022, 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.
+ *
+ ***************************************************************************/
+
+struct curl_header {
+  char *name;    /* this might not use the same case */
+  char *value;
+  size_t amount; /* number of headers using this name  */
+  size_t index;  /* ... of this instance, 0 or higher */
+  unsigned int origin; /* see bits below */
+  void *anchor; /* handle privately used by libcurl */
+};
+
+/* 'origin' bits */
+#define CURLH_HEADER    (1<<0) /* plain server header */
+#define CURLH_TRAILER   (1<<1) /* trailers */
+#define CURLH_CONNECT   (1<<2) /* CONNECT headers */
+#define CURLH_1XX       (1<<3) /* 1xx headers */
+#define CURLH_PSEUDO    (1<<4) /* pseudo headers */
+
+typedef enum {
+  CURLHE_OK,
+  CURLHE_BADINDEX,      /* header exists but not with this index */
+  CURLHE_MISSING,       /* no such header exists */
+  CURLHE_NOHEADERS,     /* no headers at all exist (yet) */
+  CURLHE_NOREQUEST,     /* no request with this number was used */
+  CURLHE_OUT_OF_MEMORY, /* out of memory while processing */
+  CURLHE_BAD_ARGUMENT,  /* a function argument was not okay */
+  CURLHE_NOT_BUILT_IN   /* if API was disabled in the build */
+} CURLHcode;
+
+CURL_EXTERN CURLHcode curl_easy_header(CURL *easy,
+                                       const char *name,
+                                       size_t index,
+                                       unsigned int origin,
+                                       int request,
+                                       struct curl_header **hout);
+
+CURL_EXTERN struct curl_header *curl_easy_nextheader(CURL *easy,
+                                                     unsigned int origin,
+                                                     int request,
+                                                     struct curl_header *prev);
+
+#endif /* CURLINC_HEADER_H */

+ 2 - 2
include/curl/options.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2022, 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
@@ -57,7 +57,7 @@ CURL_EXTERN const struct curl_easyoption *
 curl_easy_option_by_name(const char *name);
 
 CURL_EXTERN const struct curl_easyoption *
-curl_easy_option_by_id (CURLoption id);
+curl_easy_option_by_id(CURLoption id);
 
 CURL_EXTERN const struct curl_easyoption *
 curl_easy_option_next(const struct curl_easyoption *prev);

+ 2 - 18
include/curl/system.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -98,22 +98,6 @@
 #  define CURL_SUFFIX_CURL_OFF_TU    UL
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
-#elif defined(__WATCOMC__)
-#  if defined(__386__)
-#    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
-#  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(__POCC__)
 #  if (__POCC__ < 280)
 #    define CURL_TYPEOF_CURL_OFF_T     long
@@ -137,7 +121,7 @@
 #  define CURL_TYPEOF_CURL_SOCKLEN_T int
 
 #elif defined(__LCC__)
-#  if defined(__e2k__) /* MCST eLbrus C Compiler */
+#  if defined(__MCST__) /* MCST eLbrus Compiler Collection */
 #    define CURL_TYPEOF_CURL_OFF_T     long
 #    define CURL_FORMAT_CURL_OFF_T     "ld"
 #    define CURL_FORMAT_CURL_OFF_TU    "lu"

+ 17 - 13
lib/Makefile.inc

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2022, 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
@@ -44,10 +44,10 @@ LIB_VTLS_CFILES =           \
   vtls/bearssl.c            \
   vtls/gskit.c              \
   vtls/gtls.c               \
+  vtls/hostcheck.c          \
   vtls/keylog.c             \
   vtls/mbedtls.c            \
   vtls/mbedtls_threadlock.c \
-  vtls/mesalink.c           \
   vtls/nss.c                \
   vtls/openssl.c            \
   vtls/rustls.c             \
@@ -55,30 +55,34 @@ LIB_VTLS_CFILES =           \
   vtls/schannel_verify.c    \
   vtls/sectransp.c          \
   vtls/vtls.c               \
-  vtls/wolfssl.c
+  vtls/wolfssl.c            \
+  vtls/x509asn1.c
 
 LIB_VTLS_HFILES =           \
   vtls/bearssl.h            \
   vtls/gskit.h              \
   vtls/gtls.h               \
+  vtls/hostcheck.h          \
   vtls/keylog.h             \
   vtls/mbedtls.h            \
   vtls/mbedtls_threadlock.h \
-  vtls/mesalink.h           \
   vtls/nssg.h               \
   vtls/openssl.h            \
   vtls/rustls.h             \
   vtls/schannel.h           \
   vtls/sectransp.h          \
   vtls/vtls.h               \
-  vtls/wolfssl.h
+  vtls/wolfssl.h            \
+  vtls/x509asn1.h
 
 LIB_VQUIC_CFILES = \
+  vquic/msh3.c   \
   vquic/ngtcp2.c   \
   vquic/quiche.c   \
   vquic/vquic.c
 
 LIB_VQUIC_HFILES = \
+  vquic/msh3.h   \
   vquic/ngtcp2.h   \
   vquic/quiche.h   \
   vquic/vquic.h
@@ -137,10 +141,11 @@ LIB_CFILES =         \
   getenv.c           \
   getinfo.c          \
   gopher.c           \
+  h2h3.c             \
   hash.c             \
+  headers.c          \
   hmac.c             \
   hostasyn.c         \
-  hostcheck.c        \
   hostip.c           \
   hostip4.c          \
   hostip6.c          \
@@ -170,7 +175,6 @@ LIB_CFILES =         \
   mqtt.c             \
   multi.c            \
   netrc.c            \
-  non-ascii.c        \
   nonblock.c         \
   openldap.c         \
   parsedate.c        \
@@ -203,6 +207,7 @@ LIB_CFILES =         \
   system_win32.c     \
   telnet.c           \
   tftp.c             \
+  timediff.c         \
   timeval.c          \
   transfer.c         \
   url.c              \
@@ -210,8 +215,7 @@ LIB_CFILES =         \
   version.c          \
   version_win32.c    \
   warnless.c         \
-  wildcard.c         \
-  x509asn1.c
+  wildcard.c
 
 LIB_HFILES =         \
   altsvc.h           \
@@ -268,8 +272,9 @@ LIB_HFILES =         \
   ftplistparser.h    \
   getinfo.h          \
   gopher.h           \
+  h2h3.h             \
   hash.h             \
-  hostcheck.h        \
+  headers.h          \
   hostip.h           \
   hsts.h             \
   http.h             \
@@ -291,7 +296,6 @@ LIB_HFILES =         \
   multihandle.h      \
   multiif.h          \
   netrc.h            \
-  non-ascii.h        \
   nonblock.h         \
   parsedate.h        \
   pingpong.h         \
@@ -324,6 +328,7 @@ LIB_HFILES =         \
   system_win32.h     \
   telnet.h           \
   tftp.h             \
+  timediff.h         \
   timeval.h          \
   transfer.h         \
   url.h              \
@@ -331,8 +336,7 @@ LIB_HFILES =         \
   urldata.h          \
   version_win32.h    \
   warnless.h         \
-  wildcard.h         \
-  x509asn1.h
+  wildcard.h
 
 LIB_RCFILES = libcurl.rc
 

+ 5 - 3
lib/altsvc.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2019 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2019 - 2022, 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
@@ -21,7 +21,7 @@
  ***************************************************************************/
 /*
  * The Alt-Svc: header is defined in RFC 7838:
- * https://tools.ietf.org/html/rfc7838
+ * https://datatracker.ietf.org/doc/html/rfc7838
  */
 #include "curl_setup.h"
 
@@ -54,6 +54,8 @@
 #define H3VERSION "h3-29"
 #elif defined(USE_NGTCP2) && !defined(UNITTESTS)
 #define H3VERSION "h3-29"
+#elif defined(USE_MSH3) && !defined(UNITTESTS)
+#define H3VERSION "h3-29"
 #else
 #define H3VERSION "h3"
 #endif
@@ -264,7 +266,7 @@ struct altsvcinfo *Curl_altsvc_init(void)
 
   /* set default behavior */
   asi->flags = CURLALTSVC_H1
-#ifdef USE_NGHTTP2
+#ifdef USE_HTTP2
     | CURLALTSVC_H2
 #endif
 #ifdef ENABLE_QUIC

+ 3 - 2
lib/asyn-ares.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -65,6 +65,7 @@
 #include "connect.h"
 #include "select.h"
 #include "progress.h"
+#include "timediff.h"
 
 #  if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) &&   \
   defined(WIN32)
@@ -290,7 +291,7 @@ int Curl_resolver_getsock(struct Curl_easy *data,
 
   timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
                          &timebuf);
-  milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
+  milli = (long)curlx_tvtoms(timeout);
   if(milli == 0)
     milli += 10;
   Curl_expire(data, milli, EXPIRE_ASYNC_NAME);

+ 6 - 29
lib/base64.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -34,7 +34,6 @@
 #include "urldata.h" /* for the Curl_easy definition */
 #include "warnless.h"
 #include "curl_base64.h"
-#include "non-ascii.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -176,19 +175,15 @@ CURLcode Curl_base64_decode(const char *src,
 }
 
 static CURLcode base64_encode(const char *table64,
-                              struct Curl_easy *data,
                               const char *inputbuff, size_t insize,
                               char **outptr, size_t *outlen)
 {
-  CURLcode result;
   unsigned char ibuf[3];
   unsigned char obuf[4];
   int i;
   int inputparts;
   char *output;
   char *base64data;
-  char *convbuf = NULL;
-
   const char *indata = inputbuff;
 
   *outptr = NULL;
@@ -206,20 +201,6 @@ static CURLcode base64_encode(const char *table64,
   if(!output)
     return CURLE_OUT_OF_MEMORY;
 
-  /*
-   * The base64 data needs to be created using the network encoding
-   * not the host encoding.  And we can't change the actual input
-   * so we copy it to a buffer, translate it, and use that instead.
-   */
-  result = Curl_convert_clone(data, indata, insize, &convbuf);
-  if(result) {
-    free(output);
-    return result;
-  }
-
-  if(convbuf)
-    indata = (char *)convbuf;
-
   while(insize > 0) {
     for(i = inputparts = 0; i < 3; i++) {
       if(insize > 0) {
@@ -270,10 +251,8 @@ static CURLcode base64_encode(const char *table64,
   /* Return the pointer to the new data (allocated memory) */
   *outptr = base64data;
 
-  free(convbuf);
-
   /* Return the length of the new data */
-  *outlen = strlen(base64data);
+  *outlen = output - base64data;
 
   return CURLE_OK;
 }
@@ -295,11 +274,10 @@ static CURLcode base64_encode(const char *table64,
  *
  * @unittest: 1302
  */
-CURLcode Curl_base64_encode(struct Curl_easy *data,
-                            const char *inputbuff, size_t insize,
+CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
                             char **outptr, size_t *outlen)
 {
-  return base64_encode(base64, data, inputbuff, insize, outptr, outlen);
+  return base64_encode(base64, inputbuff, insize, outptr, outlen);
 }
 
 /*
@@ -319,11 +297,10 @@ CURLcode Curl_base64_encode(struct Curl_easy *data,
  *
  * @unittest: 1302
  */
-CURLcode Curl_base64url_encode(struct Curl_easy *data,
-                               const char *inputbuff, size_t insize,
+CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
                                char **outptr, size_t *outlen)
 {
-  return base64_encode(base64url, data, inputbuff, insize, outptr, outlen);
+  return base64_encode(base64url, inputbuff, insize, outptr, outlen);
 }
 
 #endif /* no users so disabled */

+ 14 - 13
lib/c-hyper.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -142,7 +142,7 @@ static int hyper_each_header(void *userdata,
       return HYPER_ITER_BREAK;
   }
   else {
-    if(Curl_dyn_add(&data->state.headerb, "\r\n"))
+    if(Curl_dyn_addn(&data->state.headerb, STRCONST("\r\n")))
       return HYPER_ITER_BREAK;
   }
   len = Curl_dyn_len(&data->state.headerb);
@@ -293,10 +293,8 @@ static CURLcode status_line(struct Curl_easy *data,
       writetype |= CLIENTWRITE_BODY;
     result = Curl_client_write(data, writetype,
                                Curl_dyn_ptr(&data->state.headerb), len);
-    if(result) {
-      data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
-      return HYPER_ITER_BREAK;
-    }
+    if(result)
+      return result;
   }
   data->info.header_size += (long)len;
   data->req.headerbytecount += (long)len;
@@ -416,7 +414,7 @@ CURLcode Curl_hyper_stream(struct Curl_easy *data,
     else if(h->endtask == task) {
       /* end of transfer */
       *done = TRUE;
-      infof(data, "hyperstream is done!");
+      infof(data, "hyperstream is done");
       if(!k->bodywrites) {
         /* hyper doesn't always call the body write callback */
         bool stilldone;
@@ -806,7 +804,7 @@ static void http1xx_cb(void *arg, struct hyper_response *resp)
   }
 
   if(data->state.hresult)
-    infof(data, "ERROR in 1xx, bail out!");
+    infof(data, "ERROR in 1xx, bail out");
 }
 
 /*
@@ -906,6 +904,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
     hyper_clientconn_options_http2(options, 1);
     h2 = TRUE;
   }
+  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);
 
@@ -1022,7 +1022,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
       goto error;
   }
 
-  p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
+  p_accept = Curl_checkheaders(data,
+                               STRCONST("Accept"))?NULL:"Accept: */*\r\n";
   if(p_accept) {
     result = Curl_hyper_header(data, headers, p_accept);
     if(result)
@@ -1036,8 +1037,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 
 #ifndef CURL_DISABLE_PROXY
   if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
-     !Curl_checkheaders(data, "Proxy-Connection") &&
-     !Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
+     !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 error;
@@ -1045,7 +1046,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 #endif
 
   Curl_safefree(data->state.aptr.ref);
-  if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
+  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;
@@ -1055,7 +1056,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
       goto error;
   }
 
-  if(!Curl_checkheaders(data, "Accept-Encoding") &&
+  if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
      data->set.str[STRING_ENCODING]) {
     Curl_safefree(data->state.aptr.accept_encoding);
     data->state.aptr.accept_encoding =

+ 26 - 37
lib/conncache.c

@@ -6,7 +6,7 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <[email protected]>
- * Copyright (C) 2012 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2022, 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
@@ -132,13 +132,11 @@ void Curl_conncache_destroy(struct conncache *connc)
 }
 
 /* creates a key to find a bundle for this connection */
-static void hashkey(struct connectdata *conn, char *buf,
-                    size_t len,  /* something like 128 is fine */
-                    const char **hostp)
+static void hashkey(struct connectdata *conn, char *buf, size_t len)
 {
   const char *hostname;
   long port = conn->remote_port;
-
+  DEBUGASSERT(len >= HASHKEY_SIZE);
 #ifndef CURL_DISABLE_PROXY
   if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
     hostname = conn->http_proxy.host.name;
@@ -151,12 +149,12 @@ static void hashkey(struct connectdata *conn, char *buf,
   else
     hostname = conn->host.name;
 
-  if(hostp)
-    /* report back which name we used */
-    *hostp = hostname;
-
-  /* put the number first so that the hostname gets cut off if too long */
-  msnprintf(buf, len, "%ld%s", port, hostname);
+  /* put the numbers first so that the hostname gets cut off if too long */
+#ifdef ENABLE_IPV6
+  msnprintf(buf, len, "%u/%ld/%s", conn->scope_id, port, hostname);
+#else
+  msnprintf(buf, len, "%ld/%s", port, hostname);
+#endif
   Curl_strntolower(buf, buf, len);
 }
 
@@ -179,27 +177,24 @@ size_t Curl_conncache_size(struct Curl_easy *data)
 struct connectbundle *
 Curl_conncache_find_bundle(struct Curl_easy *data,
                            struct connectdata *conn,
-                           struct conncache *connc,
-                           const char **hostp)
+                           struct conncache *connc)
 {
   struct connectbundle *bundle = NULL;
   CONNCACHE_LOCK(data);
   if(connc) {
     char key[HASHKEY_SIZE];
-    hashkey(conn, key, sizeof(key), hostp);
+    hashkey(conn, key, sizeof(key));
     bundle = Curl_hash_pick(&connc->hash, key, strlen(key));
   }
 
   return bundle;
 }
 
-static bool conncache_add_bundle(struct conncache *connc,
-                                 char *key,
-                                 struct connectbundle *bundle)
+static void *conncache_add_bundle(struct conncache *connc,
+                                  char *key,
+                                  struct connectbundle *bundle)
 {
-  void *p = Curl_hash_add(&connc->hash, key, strlen(key), bundle);
-
-  return p?TRUE:FALSE;
+  return Curl_hash_add(&connc->hash, key, strlen(key), bundle);
 }
 
 static void conncache_remove_bundle(struct conncache *connc,
@@ -235,10 +230,8 @@ CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
   DEBUGASSERT(conn);
 
   /* *find_bundle() locks the connection cache */
-  bundle = Curl_conncache_find_bundle(data, conn, data->state.conn_cache,
-                                      NULL);
+  bundle = Curl_conncache_find_bundle(data, conn, data->state.conn_cache);
   if(!bundle) {
-    int rc;
     char key[HASHKEY_SIZE];
 
     result = bundle_create(&bundle);
@@ -246,10 +239,9 @@ CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
       goto unlock;
     }
 
-    hashkey(conn, key, sizeof(key), NULL);
-    rc = conncache_add_bundle(data->state.conn_cache, key, bundle);
+    hashkey(conn, key, sizeof(key));
 
-    if(!rc) {
+    if(!conncache_add_bundle(data->state.conn_cache, key, bundle)) {
       bundle_destroy(bundle);
       result = CURLE_OUT_OF_MEMORY;
       goto unlock;
@@ -410,7 +402,7 @@ bool Curl_conncache_return_conn(struct Curl_easy *data,
     conn_candidate = Curl_conncache_extract_oldest(data);
     if(conn_candidate) {
       /* the winner gets the honour of being disconnected */
-      (void)Curl_disconnect(data, conn_candidate, /* dead_connection */ FALSE);
+      Curl_disconnect(data, conn_candidate, /* dead_connection */ FALSE);
     }
   }
 
@@ -535,6 +527,7 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
 {
   struct connectdata *conn;
   char buffer[READBUFFER_MIN + 1];
+  SIGPIPE_VARIABLE(pipe_st);
   if(!connc->closure_handle)
     return;
   connc->closure_handle->state.buffer = buffer;
@@ -542,27 +535,23 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
 
   conn = conncache_find_first_connection(connc);
   while(conn) {
-    SIGPIPE_VARIABLE(pipe_st);
     sigpipe_ignore(connc->closure_handle, &pipe_st);
     /* This will remove the connection from the cache */
     connclose(conn, "kill all");
     Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
-    (void)Curl_disconnect(connc->closure_handle, conn, FALSE);
+    Curl_disconnect(connc->closure_handle, conn, FALSE);
     sigpipe_restore(&pipe_st);
 
     conn = conncache_find_first_connection(connc);
   }
 
   connc->closure_handle->state.buffer = NULL;
-  if(connc->closure_handle) {
-    SIGPIPE_VARIABLE(pipe_st);
-    sigpipe_ignore(connc->closure_handle, &pipe_st);
+  sigpipe_ignore(connc->closure_handle, &pipe_st);
 
-    Curl_hostcache_clean(connc->closure_handle,
-                         connc->closure_handle->dns.hostcache);
-    Curl_close(&connc->closure_handle);
-    sigpipe_restore(&pipe_st);
-  }
+  Curl_hostcache_clean(connc->closure_handle,
+                       connc->closure_handle->dns.hostcache);
+  Curl_close(&connc->closure_handle);
+  sigpipe_restore(&pipe_st);
 }
 
 #if 0

+ 2 - 3
lib/conncache.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2015 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2015 - 2022, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2012 - 2014, Linus Nielsen Feltzing, <[email protected]>
  *
  * This software is licensed as described in the file COPYING, which
@@ -87,8 +87,7 @@ void Curl_conncache_destroy(struct conncache *connc);
 /* return the correct bundle, to a host or a proxy */
 struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data,
                                                  struct connectdata *conn,
-                                                 struct conncache *connc,
-                                                 const char **hostp);
+                                                 struct conncache *connc);
 /* returns number of connections currently held in the connection cache */
 size_t Curl_conncache_size(struct Curl_easy *data);
 

+ 24 - 13
lib/connect.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -74,6 +74,7 @@
 #include "warnless.h"
 #include "conncache.h"
 #include "multihandle.h"
+#include "share.h"
 #include "version_win32.h"
 #include "quic.h"
 #include "socks.h"
@@ -137,6 +138,14 @@ tcpkeepalive(struct Curl_easy *data,
           (void *)&optval, sizeof(optval)) < 0) {
       infof(data, "Failed to set TCP_KEEPIDLE on fd %d", sockfd);
     }
+#elif defined(TCP_KEEPALIVE)
+    /* Mac OS X style */
+    optval = curlx_sltosi(data->set.tcp_keepidle);
+    KEEPALIVE_FACTOR(optval);
+    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
+      (void *)&optval, sizeof(optval)) < 0) {
+      infof(data, "Failed to set TCP_KEEPALIVE on fd %d", sockfd);
+    }
 #endif
 #ifdef TCP_KEEPINTVL
     optval = curlx_sltosi(data->set.tcp_keepintvl);
@@ -146,15 +155,6 @@ tcpkeepalive(struct Curl_easy *data,
       infof(data, "Failed to set TCP_KEEPINTVL on fd %d", sockfd);
     }
 #endif
-#ifdef TCP_KEEPALIVE
-    /* Mac OS X style */
-    optval = curlx_sltosi(data->set.tcp_keepidle);
-    KEEPALIVE_FACTOR(optval);
-    if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
-          (void *)&optval, sizeof(optval)) < 0) {
-      infof(data, "Failed to set TCP_KEEPALIVE on fd %d", sockfd);
-    }
-#endif
 #endif
   }
 }
@@ -257,6 +257,9 @@ static CURLcode bindlocal(struct Curl_easy *data,
 #ifdef IP_BIND_ADDRESS_NO_PORT
   int on = 1;
 #endif
+#ifndef ENABLE_IPV6
+  (void)scope;
+#endif
 
   /*************************************************************
    * Select device to bind socket to
@@ -314,8 +317,11 @@ static CURLcode bindlocal(struct Curl_easy *data,
       }
 #endif
 
-      switch(Curl_if2ip(af, scope, conn->scope_id, dev,
-                        myhost, sizeof(myhost))) {
+      switch(Curl_if2ip(af,
+#ifdef ENABLE_IPV6
+                        scope, conn->scope_id,
+#endif
+                        dev, myhost, sizeof(myhost))) {
         case IF2IP_NOT_FOUND:
           if(is_interface) {
             /* Do not fall back to treating it as a host name */
@@ -617,6 +623,7 @@ void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
   data->info.conn_scheme = conn->handler->scheme;
   data->info.conn_protocol = conn->handler->protocol;
   data->info.conn_primary_port = conn->port;
+  data->info.conn_remote_port = conn->remote_port;
   data->info.conn_local_port = local_port;
 }
 
@@ -1481,7 +1488,11 @@ curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
     find.id_tofind = data->state.lastconnect_id;
     find.found = NULL;
 
-    Curl_conncache_foreach(data, data->multi_easy?
+    Curl_conncache_foreach(data,
+                           data->share && (data->share->specifier
+                           & (1<< CURL_LOCK_DATA_CONNECT))?
+                           &data->share->conn_cache:
+                           data->multi_easy?
                            &data->multi_easy->conn_cache:
                            &data->multi->conn_cache, &find, conn_is_conn);
 

+ 9 - 6
lib/cookie.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -1188,12 +1188,15 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
     fp = stdin;
     fromfile = FALSE;
   }
-  else if(file && !*file) {
-    /* points to a "" string */
+  else if(!file || !*file) {
+    /* points to an empty string or NULL */
     fp = NULL;
   }
-  else
-    fp = file?fopen(file, FOPEN_READTEXT):NULL;
+  else {
+    fp = fopen(file, FOPEN_READTEXT);
+    if(!fp)
+      infof(data, "WARNING: failed to open cookie file \"%s\"", file);
+  }
 
   c->newsession = newsession; /* new session? */
 
@@ -1227,7 +1230,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
      */
     remove_expired(c);
 
-    if(fromfile)
+    if(fromfile && fp)
       fclose(fp);
   }
 

+ 3 - 6
lib/curl_base64.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -22,13 +22,10 @@
  *
  ***************************************************************************/
 
-CURLcode Curl_base64_encode(struct Curl_easy *data,
-                            const char *inputbuff, size_t insize,
+CURLcode Curl_base64_encode(const char *inputbuff, size_t insize,
                             char **outptr, size_t *outlen);
-CURLcode Curl_base64url_encode(struct Curl_easy *data,
-                               const char *inputbuff, size_t insize,
+CURLcode Curl_base64url_encode(const char *inputbuff, size_t insize,
                                char **outptr, size_t *outlen);
-
 CURLcode Curl_base64_decode(const char *src,
                             unsigned char **outptr, size_t *outlen);
 

+ 4 - 1
lib/curl_config.h.cmake

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -949,6 +949,9 @@ ${SIZEOF_TIME_T_CODE}
 /* Define to 1 if you have the quiche_conn_set_qlog_fd function. */
 #cmakedefine HAVE_QUICHE_CONN_SET_QLOG_FD 1
 
+/* to enable msh3 */
+#cmakedefine USE_MSH3 1
+
 /* if Unix domain sockets are enabled  */
 #cmakedefine USE_UNIX_SOCKETS
 

+ 1 - 4
lib/curl_ctype.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -22,8 +22,6 @@
 
 #include "curl_setup.h"
 
-#ifndef CURL_DOES_CONVERSIONS
-
 #undef _U
 #define _U (1<<0) /* upper case */
 #undef _L
@@ -130,4 +128,3 @@ int Curl_iscntrl(int c)
   return (ascii[c] & (_C));
 }
 
-#endif /* !CURL_DOES_CONVERSIONS */

+ 1 - 29
lib/curl_ctype.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -24,32 +24,6 @@
 
 #include "curl_setup.h"
 
-#ifdef CURL_DOES_CONVERSIONS
-
-/*
- * Uppercase macro versions of ANSI/ISO is*() functions/macros which
- * avoid negative number inputs with argument byte codes > 127.
- *
- * For non-ASCII platforms the C library character classification routines
- * are used despite being locale-dependent, because this is better than
- * not to work at all.
- */
-#include <ctype.h>
-
-#define ISSPACE(x)  (isspace((int)  ((unsigned char)x)))
-#define ISDIGIT(x)  (isdigit((int)  ((unsigned char)x)))
-#define ISALNUM(x)  (isalnum((int)  ((unsigned char)x)))
-#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
-#define ISGRAPH(x)  (isgraph((int)  ((unsigned char)x)))
-#define ISALPHA(x)  (isalpha((int)  ((unsigned char)x)))
-#define ISPRINT(x)  (isprint((int)  ((unsigned char)x)))
-#define ISUPPER(x)  (isupper((int)  ((unsigned char)x)))
-#define ISLOWER(x)  (islower((int)  ((unsigned char)x)))
-#define ISCNTRL(x)  (iscntrl((int)  ((unsigned char)x)))
-#define ISASCII(x)  (isascii((int)  ((unsigned char)x)))
-
-#else
-
 int Curl_isspace(int c);
 int Curl_isdigit(int c);
 int Curl_isalnum(int c);
@@ -73,8 +47,6 @@ int Curl_iscntrl(int c);
 #define ISCNTRL(x)  (Curl_iscntrl((int)  ((unsigned char)x)))
 #define ISASCII(x)  (((x) >= 0) && ((x) <= 0x80))
 
-#endif
-
 #define ISBLANK(x)  (int)((((unsigned char)x) == ' ') ||        \
                           (((unsigned char)x) == '\t'))
 

+ 8 - 3
lib/curl_des.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2015 - 2021, Steve Holme, <[email protected]>.
+ * Copyright (C) 2015 - 2022, Steve Holme, <[email protected]>.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -22,7 +22,12 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_NTLM) && !defined(USE_OPENSSL) && !defined(USE_WOLFSSL)
+#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) && \
+    (defined(USE_GNUTLS) || \
+     defined(USE_NSS) || \
+     defined(USE_SECTRANSP) || \
+     defined(USE_OS400CRYPTO) || \
+     defined(USE_WIN32_CRYPTO))
 
 #include "curl_des.h"
 
@@ -60,4 +65,4 @@ void Curl_des_set_odd_parity(unsigned char *bytes, size_t len)
   }
 }
 
-#endif /* USE_NTLM && !USE_OPENSSL */
+#endif

+ 8 - 3
lib/curl_des.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2015 - 2020, Steve Holme, <[email protected]>.
+ * Copyright (C) 2015 - 2022, Steve Holme, <[email protected]>.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -24,11 +24,16 @@
 
 #include "curl_setup.h"
 
-#if defined(USE_NTLM) && !defined(USE_OPENSSL)
+#if defined(USE_CURL_NTLM_CORE) && !defined(USE_WOLFSSL) && \
+    (defined(USE_GNUTLS) || \
+     defined(USE_NSS) || \
+     defined(USE_SECTRANSP) || \
+     defined(USE_OS400CRYPTO) || \
+     defined(USE_WIN32_CRYPTO))
 
 /* Applies odd parity to the given byte array */
 void Curl_des_set_odd_parity(unsigned char *bytes, size_t length);
 
-#endif /* USE_NTLM && !USE_OPENSSL */
+#endif
 
 #endif /* HEADER_CURL_DES_H */

+ 2 - 2
lib/curl_gssapi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2011 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2011 - 2022, 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
@@ -60,7 +60,7 @@ OM_uint32 Curl_gss_init_sec_context(
 #ifdef GSS_C_DELEG_POLICY_FLAG
     req_flags |= GSS_C_DELEG_POLICY_FLAG;
 #else
-    infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
+    infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
         "compiled in");
 #endif
   }

+ 6 - 6
lib/curl_multibyte.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -104,7 +104,7 @@ int curlx_win32_open(const char *filename, int oflag, ...)
 #ifdef _UNICODE
   if(filename_w) {
     result = _wopen(filename_w, oflag, pmode);
-    free(filename_w);
+    curlx_unicodefree(filename_w);
   }
   else
     errno = EINVAL;
@@ -124,8 +124,8 @@ FILE *curlx_win32_fopen(const char *filename, const char *mode)
     result = _wfopen(filename_w, mode_w);
   else
     errno = EINVAL;
-  free(filename_w);
-  free(mode_w);
+  curlx_unicodefree(filename_w);
+  curlx_unicodefree(mode_w);
   return result;
 #else
   return (fopen)(filename, mode);
@@ -143,7 +143,7 @@ int curlx_win32_stat(const char *path, struct_stat *buffer)
 #else
     result = _wstati64(path_w, buffer);
 #endif
-    free(path_w);
+    curlx_unicodefree(path_w);
   }
   else
     errno = EINVAL;
@@ -164,7 +164,7 @@ int curlx_win32_access(const char *path, int mode)
   wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
   if(path_w) {
     result = _waccess(path_w, mode);
-    free(path_w);
+    curlx_unicodefree(path_w);
   }
   else
     errno = EINVAL;

+ 12 - 34
lib/curl_ntlm_core.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -108,7 +108,6 @@
 #endif
 
 #include "urldata.h"
-#include "non-ascii.h"
 #include "strcase.h"
 #include "curl_ntlm_core.h"
 #include "curl_md5.h"
@@ -402,11 +401,9 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
 /*
  * Set up lanmanager hashed password
  */
-CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
-                                   const char *password,
+CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
                                    unsigned char *lmbuffer /* 21 bytes */)
 {
-  CURLcode result;
   unsigned char pw[14];
   static const unsigned char magic[] = {
     0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
@@ -416,14 +413,6 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
   Curl_strntoupper((char *)pw, password, len);
   memset(&pw[len], 0, 14 - len);
 
-  /*
-   * The LanManager hashed password needs to be created using the
-   * password in the network encoding not the host encoding.
-   */
-  result = Curl_convert_to_network(data, (char *)pw, 14);
-  if(result)
-    return result;
-
   {
     /* Create LanManager hashed password. */
 
@@ -455,7 +444,6 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
   return CURLE_OK;
 }
 
-#ifdef USE_NTRESPONSES
 static void ascii_to_unicode_le(unsigned char *dest, const char *src,
                                 size_t srclen)
 {
@@ -466,7 +454,7 @@ static void ascii_to_unicode_le(unsigned char *dest, const char *src,
   }
 }
 
-#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
+#if !defined(USE_WINDOWS_SSPI)
 
 static void ascii_uppercase_to_unicode_le(unsigned char *dest,
                                           const char *src, size_t srclen)
@@ -478,19 +466,17 @@ static void ascii_uppercase_to_unicode_le(unsigned char *dest,
   }
 }
 
-#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */
+#endif /* !USE_WINDOWS_SSPI */
 
 /*
  * Set up nt hashed passwords
  * @unittest: 1600
  */
-CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
-                                   const char *password,
+CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
                                    unsigned char *ntbuffer /* 21 bytes */)
 {
   size_t len = strlen(password);
   unsigned char *pw;
-  CURLcode result;
   if(len > SIZE_T_MAX/2) /* avoid integer overflow */
     return CURLE_OUT_OF_MEMORY;
   pw = len ? malloc(len * 2) : (unsigned char *)strdup("");
@@ -499,22 +485,16 @@ CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
 
   ascii_to_unicode_le(pw, password, len);
 
-  /*
-   * The NT hashed password needs to be created using the password in the
-   * network encoding not the host encoding.
-   */
-  result = Curl_convert_to_network(data, (char *)pw, len * 2);
-  if(!result) {
-    /* Create NT hashed password. */
-    Curl_md4it(ntbuffer, pw, 2 * len);
-    memset(ntbuffer + 16, 0, 21 - 16);
-  }
+  /* Create NT hashed password. */
+  Curl_md4it(ntbuffer, pw, 2 * len);
+  memset(ntbuffer + 16, 0, 21 - 16);
+
   free(pw);
 
-  return result;
+  return CURLE_OK;
 }
 
-#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
+#if !defined(USE_WINDOWS_SSPI)
 
 /* Timestamp in tenths of a microsecond since January 1, 1601 00:00:00 UTC. */
 struct ms_filetime {
@@ -730,8 +710,6 @@ CURLcode  Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
   return result;
 }
 
-#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */
-
-#endif /* USE_NTRESPONSES */
+#endif /* !USE_WINDOWS_SSPI */
 
 #endif /* USE_CURL_NTLM_CORE */

+ 5 - 26
lib/curl_ntlm_core.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -42,22 +42,6 @@
 #  include <openssl/ssl.h>
 #endif
 
-/* Define USE_NTRESPONSES in order to make the type-3 message include
- * the NT response message. */
-#define USE_NTRESPONSES
-
-/* Define USE_NTLM2SESSION in order to make the type-3 message include the
-   NTLM2Session response message, requires USE_NTRESPONSES defined to 1 */
-#if defined(USE_NTRESPONSES)
-#define USE_NTLM2SESSION
-#endif
-
-/* Define USE_NTLM_V2 in order to allow the type-3 message to include the
-   LMv2 and NTLMv2 response messages, requires USE_NTRESPONSES defined to 1 */
-#if defined(USE_NTRESPONSES)
-#define USE_NTLM_V2
-#endif
-
 /* Helpers to generate function byte arguments in little endian order */
 #define SHORTPAIR(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff))
 #define LONGQUARTET(x) ((int)((x) & 0xff)), ((int)(((x) >> 8) & 0xff)), \
@@ -67,16 +51,13 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
                             const unsigned char *plaintext,
                             unsigned char *results);
 
-CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
-                                   const char *password,
+CURLcode Curl_ntlm_core_mk_lm_hash(const char *password,
                                    unsigned char *lmbuffer /* 21 bytes */);
 
-#ifdef USE_NTRESPONSES
-CURLcode Curl_ntlm_core_mk_nt_hash(struct Curl_easy *data,
-                                   const char *password,
+CURLcode Curl_ntlm_core_mk_nt_hash(const char *password,
                                    unsigned char *ntbuffer /* 21 bytes */);
 
-#if defined(USE_NTLM_V2) && !defined(USE_WINDOWS_SSPI)
+#if !defined(USE_WINDOWS_SSPI)
 
 CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen,
                        const unsigned char *data, unsigned int datalen,
@@ -98,9 +79,7 @@ CURLcode  Curl_ntlm_core_mk_lmv2_resp(unsigned char *ntlmv2hash,
                                       unsigned char *challenge_server,
                                       unsigned char *lmresp);
 
-#endif /* USE_NTLM_V2 && !USE_WINDOWS_SSPI */
-
-#endif /* USE_NTRESPONSES */
+#endif /* !USE_WINDOWS_SSPI */
 
 #endif /* USE_CURL_NTLM_CORE */
 

+ 2 - 2
lib/curl_path.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -40,7 +40,7 @@ CURLcode Curl_getworkingpath(struct Curl_easy *data,
   char *working_path;
   size_t working_path_len;
   CURLcode result =
-    Curl_urldecode(data, data->state.up.path, 0, &working_path,
+    Curl_urldecode(data->state.up.path, 0, &working_path,
                    &working_path_len, REJECT_ZERO);
   if(result)
     return result;

+ 9 - 11
lib/curl_sasl.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2022, 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
@@ -48,7 +48,6 @@
 #include "warnless.h"
 #include "strtok.h"
 #include "sendf.h"
-#include "non-ascii.h" /* included for Curl_convert_... prototypes */
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -283,8 +282,7 @@ static CURLcode get_server_message(struct SASL *sasl, struct Curl_easy *data,
 }
 
 /* Encode the outgoing SASL message. */
-static CURLcode build_message(struct SASL *sasl, struct Curl_easy *data,
-                              struct bufref *msg)
+static CURLcode build_message(struct SASL *sasl, struct bufref *msg)
 {
   CURLcode result = CURLE_OK;
 
@@ -297,7 +295,7 @@ static CURLcode build_message(struct SASL *sasl, struct Curl_easy *data,
       char *base64;
       size_t base64len;
 
-      result = Curl_base64_encode(data, (const char *) Curl_bufref_ptr(msg),
+      result = Curl_base64_encode((const char *) Curl_bufref_ptr(msg),
                                   Curl_bufref_len(msg), &base64, &base64len);
       if(!result)
         Curl_bufref_set(msg, base64, base64len, curl_free);
@@ -312,10 +310,10 @@ static CURLcode build_message(struct SASL *sasl, struct Curl_easy *data,
  *
  * Check if we have enough auth data and capabilities to authenticate.
  */
-bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
+bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data)
 {
   /* Have credentials been provided? */
-  if(conn->bits.user_passwd)
+  if(data->state.aptr.user)
     return TRUE;
 
   /* EXTERNAL can authenticate without a user name and/or password */
@@ -367,7 +365,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
     if(force_ir || data->set.sasl_ir)
       result = Curl_auth_create_external_message(conn->user, &resp);
   }
-  else if(conn->bits.user_passwd) {
+  else if(data->state.aptr.user) {
 #if defined(USE_KERBEROS5)
     if((enabledmechs & SASL_MECH_GSSAPI) && Curl_auth_is_gssapi_supported() &&
        Curl_auth_user_contains_domain(conn->user)) {
@@ -494,7 +492,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
   if(!result && mech) {
     sasl->curmech = mech;
     if(Curl_bufref_ptr(&resp))
-      result = build_message(sasl, data, &resp);
+      result = build_message(sasl, &resp);
 
     if(sasl->params->maxirlen &&
        strlen(mech) + Curl_bufref_len(&resp) > sasl->params->maxirlen)
@@ -672,7 +670,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
 #endif
 
   case SASL_OAUTH2:
-    /* Create the authorisation message */
+    /* Create the authorization message */
     if(sasl->authused == SASL_MECH_OAUTHBEARER) {
       result = Curl_auth_create_oauth_bearer_message(conn->user,
                                                      hostname,
@@ -729,7 +727,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
     newstate = SASL_CANCEL;
     break;
   case CURLE_OK:
-    result = build_message(sasl, data, &resp);
+    result = build_message(sasl, &resp);
     if(!result)
       result = sasl->params->contauth(data, sasl->curmech, &resp);
     break;

+ 2 - 2
lib/curl_sasl.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2022, 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
@@ -150,7 +150,7 @@ void Curl_sasl_init(struct SASL *sasl, struct Curl_easy *data,
                     const struct SASLproto *params);
 
 /* Check if we have enough auth data and capabilities to authenticate */
-bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
+bool Curl_sasl_can_authenticate(struct SASL *sasl, struct Curl_easy *data);
 
 /* Calculate the required login details for SASL authentication  */
 CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,

+ 8 - 35
lib/curl_setup.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -101,14 +101,6 @@
 #  include "config-os400.h"
 #endif
 
-#ifdef TPF
-#  include "config-tpf.h"
-#endif
-
-#ifdef __VXWORKS__
-#  include "config-vxworks.h"
-#endif
-
 #ifdef __PLAN9__
 #  include "config-plan9.h"
 #endif
@@ -274,22 +266,6 @@
 #  include <extra/strdup.h>
 #endif
 
-#ifdef TPF
-#  include <strings.h>    /* for bzero, strcasecmp, and strncasecmp */
-#  include <string.h>     /* for strcpy and strlen */
-#  include <stdlib.h>     /* for rand and srand */
-#  include <sys/socket.h> /* for select and ioctl*/
-#  include <netdb.h>      /* for in_addr_t definition */
-#  include <tpf/sysapi.h> /* for tpf_process_signals */
-   /* change which select is used for libcurl */
-#  define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e)
-#endif
-
-#ifdef __VXWORKS__
-#  include <sockLib.h>    /* for generic BSD socket functions */
-#  include <ioLib.h>      /* for basic I/O interface functions */
-#endif
-
 #ifdef __AMIGA__
 #  include <exec/types.h>
 #  include <exec/execbase.h>
@@ -619,14 +595,6 @@
 #  endif
 #endif
 
-#ifdef NETWARE
-int netware_init(void);
-#ifndef __NOVELL_LIBC__
-#include <sys/bsdskt.h>
-#include <sys/timeval.h>
-#endif
-#endif
-
 #if defined(HAVE_LIBIDN2) && defined(HAVE_IDN2_H) && !defined(USE_WIN32_IDN)
 /* The lib and header are present */
 #define USE_LIBIDN2
@@ -641,7 +609,7 @@ int netware_init(void);
 #if defined(USE_GNUTLS) || defined(USE_OPENSSL) || defined(USE_NSS) || \
     defined(USE_MBEDTLS) || \
     defined(USE_WOLFSSL) || defined(USE_SCHANNEL) || \
-    defined(USE_SECTRANSP) || defined(USE_GSKIT) || defined(USE_MESALINK) || \
+    defined(USE_SECTRANSP) || defined(USE_GSKIT) || \
     defined(USE_BEARSSL) || defined(USE_RUSTLS)
 #define USE_SSL    /* SSL support has been enabled */
 #endif
@@ -804,6 +772,11 @@ endings either CRLF or LF so 't' is appropriate.
 #define CURLMAX(x,y) ((x)>(y)?(x):(y))
 #define CURLMIN(x,y) ((x)<(y)?(x):(y))
 
+/* A convenience macro to provide both the string literal and the length of
+   the string literal in one go, useful for functions that take "string,len"
+   as their argument */
+#define STRCONST(x) x,sizeof(x)-1
+
 /* Some versions of the Android SDK is missing the declaration */
 #if defined(HAVE_GETPWUID_R) && defined(HAVE_DECL_GETPWUID_R_MISSING)
 struct passwd;
@@ -821,7 +794,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf,
 #define USE_HTTP2
 #endif
 
-#if defined(USE_NGTCP2) || defined(USE_QUICHE)
+#if defined(USE_NGTCP2) || defined(USE_QUICHE) || defined(USE_MSH3)
 #define ENABLE_QUIC
 #endif
 

+ 2 - 2
lib/curl_sha256.h

@@ -8,7 +8,7 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2017, Florin Petriuc, <[email protected]>
- * Copyright (C) 2018 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2022, 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
@@ -32,7 +32,7 @@ extern const struct HMAC_params Curl_HMAC_SHA256[1];
 /* SHA256_DIGEST_LENGTH is an enum value in wolfSSL. Need to import it from
  * sha.h*/
 #include <wolfssl/options.h>
-#include <openssl/sha.h>
+#include <wolfssl/openssl/sha.h>
 #else
 #define SHA256_DIGEST_LENGTH 32
 #endif

+ 5 - 9
lib/dict.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -96,13 +96,13 @@ const struct Curl_handler Curl_handler_dict = {
   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
 };
 
-static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
+static char *unescape_word(const char *inputbuff)
 {
   char *newp = NULL;
   char *dictp;
   size_t len;
 
-  CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len,
+  CURLcode result = Curl_urldecode(inputbuff, 0, &newp, &len,
                                    REJECT_NADA);
   if(!newp || result)
     return NULL;
@@ -190,10 +190,6 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
 
   *done = TRUE; /* unconditionally */
 
-  if(conn->bits.user_passwd) {
-    /* AUTH is missing */
-  }
-
   if(strncasecompare(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
      strncasecompare(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
      strncasecompare(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
@@ -226,7 +222,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
       strategy = (char *)".";
     }
 
-    eword = unescape_word(data, word);
+    eword = unescape_word(word);
     if(!eword)
       return CURLE_OUT_OF_MEMORY;
 
@@ -274,7 +270,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done)
       database = (char *)"!";
     }
 
-    eword = unescape_word(data, word);
+    eword = unescape_word(word);
     if(!eword)
       return CURLE_OUT_OF_MEMORY;
 

+ 4 - 4
lib/doh.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2022, 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
@@ -252,7 +252,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
     ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDS, p->dohbuffer);
     ERROR_CHECK_SETOPT(CURLOPT_POSTFIELDSIZE, (long)p->dohlen);
     ERROR_CHECK_SETOPT(CURLOPT_HTTPHEADER, headers);
-#ifdef USE_NGHTTP2
+#ifdef USE_HTTP2
     ERROR_CHECK_SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
 #endif
 #ifndef CURLDEBUG
@@ -530,7 +530,7 @@ static DOHcode store_cname(const unsigned char *doh,
 
     if(length) {
       if(Curl_dyn_len(c)) {
-        if(Curl_dyn_add(c, "."))
+        if(Curl_dyn_addn(c, STRCONST(".")))
           return DOH_OUT_OF_MEM;
       }
       if((index + length) > dohlen)
@@ -911,7 +911,7 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
   if(!dohp->probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
      !dohp->probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
     failf(data, "Could not DoH-resolve: %s", data->state.async.hostname);
-    return data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
+    return CONN_IS_PROXIED(data->conn)?CURLE_COULDNT_RESOLVE_PROXY:
       CURLE_COULDNT_RESOLVE_HOST;
   }
   else if(!dohp->pending) {

+ 2 - 2
lib/dotdot.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -32,7 +32,7 @@
 
 /*
  * "Remove Dot Segments"
- * https://tools.ietf.org/html/rfc3986#section-5.2.4
+ * https://datatracker.ietf.org/doc/html/rfc3986#section-5.2.4
  */
 
 /*

+ 2 - 11
lib/easy.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -68,7 +68,6 @@
 #include "slist.h"
 #include "mime.h"
 #include "amigaos.h"
-#include "non-ascii.h"
 #include "warnless.h"
 #include "multiif.h"
 #include "sigpipe.h"
@@ -168,12 +167,6 @@ static CURLcode global_init(long flags, bool memoryfuncs)
   }
 #endif
 
-#ifdef NETWARE
-  if(netware_init()) {
-    DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
-  }
-#endif
-
   if(Curl_resolver_global_init()) {
     DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
     goto fail;
@@ -933,8 +926,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
   }
 #endif /* USE_ARES */
 
-  Curl_convert_setup(outcurl);
-
   Curl_initinfo(outcurl);
 
   outcurl->magic = CURLEASY_MAGIC_NUMBER;
@@ -1111,7 +1102,7 @@ static CURLcode easy_connection(struct Curl_easy *data,
 
   /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
   if(!data->set.connect_only) {
-    failf(data, "CONNECT_ONLY is required!");
+    failf(data, "CONNECT_ONLY is required");
     return CURLE_UNSUPPORTED_PROTOCOL;
   }
 

+ 8 - 29
lib/escape.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -29,7 +29,6 @@
 
 #include "urldata.h"
 #include "warnless.h"
-#include "non-ascii.h"
 #include "escape.h"
 #include "strdup.h"
 /* The last 3 #include files should be in this order */
@@ -39,7 +38,7 @@
 
 /* Portable character check (remember EBCDIC). Do not use isalnum() because
    its behavior is altered by the current locale.
-   See https://tools.ietf.org/html/rfc3986#section-2.3
+   See https://datatracker.ietf.org/doc/html/rfc3986#section-2.3
 */
 bool Curl_isunreserved(unsigned char in)
 {
@@ -80,8 +79,8 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
                        int inlength)
 {
   size_t length;
-  CURLcode result;
   struct dynbuf d;
+  (void)data;
 
   if(inlength < 0)
     return NULL;
@@ -102,16 +101,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
     }
     else {
       /* encode it */
-      char encoded[4];
-      result = Curl_convert_to_network(data, (char *)&in, 1);
-      if(result) {
-        /* Curl_convert_to_network calls failf if unsuccessful */
-        Curl_dyn_free(&d);
-        return NULL;
-      }
-
-      msnprintf(encoded, sizeof(encoded), "%%%02X", in);
-      if(Curl_dyn_add(&d, encoded))
+      if(Curl_dyn_addf(&d, "%%%02X", in))
         return NULL;
     }
     string++;
@@ -126,8 +116,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
  * Returns a pointer to a malloced string in *ostring with length given in
  * *olen. If length == 0, the length is assumed to be strlen(string).
  *
- * 'data' can be set to NULL but then this function can't convert network
- * data to host for non-ascii.
+ * 'data' can be set to NULL
  *
  * ctrl options:
  * - REJECT_NADA: accept everything
@@ -139,8 +128,7 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
  * invokes that used TRUE/FALSE (0 and 1).
  */
 
-CURLcode Curl_urldecode(struct Curl_easy *data,
-                        const char *string, size_t length,
+CURLcode Curl_urldecode(const char *string, size_t length,
                         char **ostring, size_t *olen,
                         enum urlreject ctrl)
 {
@@ -148,7 +136,6 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
   char *ns;
   size_t strindex = 0;
   unsigned long hex;
-  CURLcode result = CURLE_OK;
 
   DEBUGASSERT(string);
   DEBUGASSERT(ctrl >= REJECT_NADA); /* crash on TRUE/FALSE */
@@ -174,15 +161,6 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
 
       in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
 
-      if(data) {
-        result = Curl_convert_from_network(data, (char *)&in, 1);
-        if(result) {
-          /* Curl_convert_from_network calls failf if unsuccessful */
-          free(ns);
-          return result;
-        }
-      }
-
       string += 2;
       alloc -= 2;
     }
@@ -218,10 +196,11 @@ char *curl_easy_unescape(struct Curl_easy *data, const char *string,
                          int length, int *olen)
 {
   char *str = NULL;
+  (void)data;
   if(length >= 0) {
     size_t inputlen = length;
     size_t outputlen;
-    CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen,
+    CURLcode res = Curl_urldecode(string, inputlen, &str, &outputlen,
                                   REJECT_NADA);
     if(res)
       return NULL;

+ 2 - 3
lib/escape.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -32,8 +32,7 @@ enum urlreject {
   REJECT_ZERO
 };
 
-CURLcode Curl_urldecode(struct Curl_easy *data,
-                        const char *string, size_t length,
+CURLcode Curl_urldecode(const char *string, size_t length,
                         char **ostring, size_t *olen,
                         enum urlreject ctrl);
 

+ 2 - 2
lib/file.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -147,7 +147,7 @@ static CURLcode file_connect(struct Curl_easy *data, bool *done)
 #endif
   size_t real_path_len;
 
-  CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &real_path,
+  CURLcode result = Curl_urldecode(data->state.up.path, 0, &real_path,
                                    &real_path_len, REJECT_ZERO);
   if(result)
     return result;

+ 8 - 15
lib/formdata.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -33,7 +33,6 @@
 
 #include "urldata.h" /* for struct Curl_easy */
 #include "mime.h"
-#include "non-ascii.h"
 #include "vtls/vtls.h"
 #include "strcase.h"
 #include "sendf.h"
@@ -77,10 +76,15 @@ AddHttpPost(char *name, size_t namelength,
             struct curl_httppost **last_post)
 {
   struct curl_httppost *post;
+  if(!namelength && name)
+    namelength = strlen(name);
+  if((bufferlength > LONG_MAX) || (namelength > LONG_MAX))
+    /* avoid overflow in typecasts below */
+    return NULL;
   post = calloc(1, sizeof(struct curl_httppost));
   if(post) {
     post->name = name;
-    post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
+    post->namelength = (long)namelength;
     post->contents = value;
     post->contentlen = contentslength;
     post->buffer = buffer;
@@ -269,14 +273,8 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
        * Set the Name property.
        */
     case CURLFORM_PTRNAME:
-#ifdef CURL_DOES_CONVERSIONS
-      /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
-       * the data in all cases so that we'll have safe memory for the eventual
-       * conversion.
-       */
-#else
       current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
-#endif
+
       /* FALLTHROUGH */
     case CURLFORM_COPYNAME:
       if(current_form->name)
@@ -901,11 +899,6 @@ CURLcode Curl_getformdata(struct Curl_easy *data,
           else
             uclen = (size_t)clen;
           result = curl_mime_data(part, post->contents, uclen);
-#ifdef CURL_DOES_CONVERSIONS
-          /* Convert textual contents now. */
-          if(!result && data && part->datasize)
-            result = Curl_convert_to_network(data, part->data, part->datasize);
-#endif
         }
       }
 

+ 16 - 12
lib/ftp.c

@@ -76,7 +76,6 @@
 #include "speedcheck.h"
 #include "warnless.h"
 #include "http_proxy.h"
-#include "non-ascii.h"
 #include "socks.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -592,7 +591,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data,
      * This response code can come at any point so having it treated
      * generically is a good idea.
      */
-    infof(data, "We got a 421 - timeout!");
+    infof(data, "We got a 421 - timeout");
     state(data, FTP_STOP);
     return CURLE_OPERATION_TIMEDOUT;
   }
@@ -1030,8 +1029,11 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
     if(*addr != '\0') {
       /* attempt to get the address of the given interface name */
       switch(Curl_if2ip(conn->ip_addr->ai_family,
+#ifdef ENABLE_IPV6
                         Curl_ipv6_scope(conn->ip_addr->ai_addr),
-                        conn->scope_id, addr, hbuf, sizeof(hbuf))) {
+                        conn->scope_id,
+#endif
+                        addr, hbuf, sizeof(hbuf))) {
         case IF2IP_NOT_FOUND:
           /* not an interface, use the given string as host name instead */
           host = addr;
@@ -1163,7 +1165,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data,
 
   /* maybe all ports were in use already*/
   if(port > port_max) {
-    failf(data, "bind() failed, we ran out of ports!");
+    failf(data, "bind() failed, we ran out of ports");
     Curl_closesocket(data, conn, portsock);
     return CURLE_FTP_PORT_FAILED;
   }
@@ -1460,7 +1462,7 @@ static CURLcode ftp_state_list(struct Curl_easy *data)
     /* url-decode before evaluation: e.g. paths starting/ending with %2f */
     const char *slashPos = NULL;
     char *rawPath = NULL;
-    result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, REJECT_CTRL);
+    result = Curl_urldecode(ftp->path, 0, &rawPath, NULL, REJECT_CTRL);
     if(result)
       return result;
 
@@ -2700,7 +2702,7 @@ static CURLcode ftp_statemachine(struct Curl_easy *data,
         Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
 
         if(Curl_sec_login(data, conn))
-          infof(data, "Logging in with password in cleartext!");
+          infof(data, "Logging in with password in cleartext");
         else
           infof(data, "Authentication successful");
       }
@@ -3247,7 +3249,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
 
   if(!result)
     /* get the url-decoded "raw" path */
-    result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen,
+    result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen,
                             REJECT_CTRL);
   if(result) {
     /* We can limp along anyway (and should try to since we may already be in
@@ -3379,7 +3381,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
        (ftp->transfer == PPTRANSFER_BODY)) {
       failf(data, "Uploaded unaligned file size (%" CURL_FORMAT_CURL_OFF_T
             " out of %" CURL_FORMAT_CURL_OFF_T " bytes)",
-            data->req.bytecount, data->state.infilesize);
+            data->req.writebytecount, data->state.infilesize);
       result = CURLE_PARTIAL_FILE;
     }
   }
@@ -3402,7 +3404,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status,
     else if(!ftpc->dont_check &&
             !data->req.bytecount &&
             (data->req.size>0)) {
-      failf(data, "No data was received!");
+      failf(data, "No data was received");
       result = CURLE_FTP_COULDNT_RETR_FILE;
     }
   }
@@ -4131,9 +4133,11 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
   ftpc->cwdfail = FALSE;
 
   /* url-decode ftp path before further evaluation */
-  result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL);
-  if(result)
+  result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL);
+  if(result) {
+    failf(data, "path contains control characters");
     return result;
+  }
 
   switch(data->set.ftp_filemethod) {
     case FTPFILE_NOCWD: /* fastest, but less standard-compliant */
@@ -4231,7 +4235,7 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data)
 
   if(data->set.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) {
     /* We need a file name when uploading. Return error! */
-    failf(data, "Uploading to a URL without a file name!");
+    failf(data, "Uploading to a URL without a file name");
     free(rawPath);
     return CURLE_URL_MALFORMAT;
   }

+ 2 - 2
lib/gopher.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -165,7 +165,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done)
     newp += 2;
 
     /* ... and finally unescape */
-    result = Curl_urldecode(data, newp, 0, &sel, &len, REJECT_ZERO);
+    result = Curl_urldecode(newp, 0, &sel, &len, REJECT_ZERO);
     free(gopherpath);
     if(result)
       return result;

+ 310 - 0
lib/h2h3.c

@@ -0,0 +1,310 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "urldata.h"
+#include "h2h3.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "strcase.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+/*
+ * Curl_pseudo_headers() creates the array with pseudo headers to be
+ * used in a HTTP/2 or HTTP/3 request.
+ */
+
+#if defined(USE_NGHTTP2) || defined(ENABLE_QUIC)
+
+/* Index where :authority header field will appear in request header
+   field list. */
+#define AUTHORITY_DST_IDX 3
+
+/* USHRT_MAX is 65535 == 0xffff */
+#define HEADER_OVERFLOW(x) \
+  (x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen)
+
+/*
+ * Check header memory for the token "trailers".
+ * Parse the tokens as separated by comma and surrounded by whitespace.
+ * Returns TRUE if found or FALSE if not.
+ */
+static bool contains_trailers(const char *p, size_t len)
+{
+  const char *end = p + len;
+  for(;;) {
+    for(; p != end && (*p == ' ' || *p == '\t'); ++p)
+      ;
+    if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
+      return FALSE;
+    if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
+      p += sizeof("trailers") - 1;
+      for(; p != end && (*p == ' ' || *p == '\t'); ++p)
+        ;
+      if(p == end || *p == ',')
+        return TRUE;
+    }
+    /* skip to next token */
+    for(; p != end && *p != ','; ++p)
+      ;
+    if(p == end)
+      return FALSE;
+    ++p;
+  }
+}
+
+typedef enum {
+  /* Send header to server */
+  HEADERINST_FORWARD,
+  /* Don't send header to server */
+  HEADERINST_IGNORE,
+  /* Discard header, and replace it with "te: trailers" */
+  HEADERINST_TE_TRAILERS
+} header_instruction;
+
+/* Decides how to treat given header field. */
+static header_instruction inspect_header(const char *name, size_t namelen,
+                                         const char *value, size_t valuelen) {
+  switch(namelen) {
+  case 2:
+    if(!strncasecompare("te", name, namelen))
+      return HEADERINST_FORWARD;
+
+    return contains_trailers(value, valuelen) ?
+           HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
+  case 7:
+    return strncasecompare("upgrade", name, namelen) ?
+           HEADERINST_IGNORE : HEADERINST_FORWARD;
+  case 10:
+    return (strncasecompare("connection", name, namelen) ||
+            strncasecompare("keep-alive", name, namelen)) ?
+           HEADERINST_IGNORE : HEADERINST_FORWARD;
+  case 16:
+    return strncasecompare("proxy-connection", name, namelen) ?
+           HEADERINST_IGNORE : HEADERINST_FORWARD;
+  case 17:
+    return strncasecompare("transfer-encoding", name, namelen) ?
+           HEADERINST_IGNORE : HEADERINST_FORWARD;
+  default:
+    return HEADERINST_FORWARD;
+  }
+}
+
+CURLcode Curl_pseudo_headers(struct Curl_easy *data,
+                             const char *mem, /* the request */
+                             const size_t len /* size of request */,
+                             struct h2h3req **hp)
+{
+  struct connectdata *conn = data->conn;
+  size_t nheader = 0;
+  size_t i;
+  size_t authority_idx;
+  char *hdbuf = (char *)mem;
+  char *end, *line_end;
+  struct h2h3pseudo *nva = NULL;
+  struct h2h3req *hreq = NULL;
+  char *vptr;
+
+  /* Calculate number of headers contained in [mem, mem + len). Assumes a
+     correctly generated HTTP header field block. */
+  for(i = 1; i < len; ++i) {
+    if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
+      ++nheader;
+      ++i;
+    }
+  }
+  if(nheader < 2) {
+    goto fail;
+  }
+  /* We counted additional 2 \r\n in the first and last line. We need 3
+     new headers: :method, :path and :scheme. Therefore we need one
+     more space. */
+  nheader += 1;
+  hreq = malloc(sizeof(struct h2h3req) +
+                sizeof(struct h2h3pseudo) * (nheader - 1));
+  if(!hreq) {
+    goto fail;
+  }
+
+  nva = &hreq->header[0];
+
+  /* Extract :method, :path from request line
+     We do line endings with CRLF so checking for CR is enough */
+  line_end = memchr(hdbuf, '\r', len);
+  if(!line_end) {
+    goto fail;
+  }
+
+  /* Method does not contain spaces */
+  end = memchr(hdbuf, ' ', line_end - hdbuf);
+  if(!end || end == hdbuf)
+    goto fail;
+  nva[0].name = H2H3_PSEUDO_METHOD;
+  nva[0].namelen = sizeof(H2H3_PSEUDO_METHOD) - 1;
+  nva[0].value = hdbuf;
+  nva[0].valuelen = (size_t)(end - hdbuf);
+
+  hdbuf = end + 1;
+
+  /* Path may contain spaces so scan backwards */
+  end = NULL;
+  for(i = (size_t)(line_end - hdbuf); i; --i) {
+    if(hdbuf[i - 1] == ' ') {
+      end = &hdbuf[i - 1];
+      break;
+    }
+  }
+  if(!end || end == hdbuf)
+    goto fail;
+  nva[1].name = H2H3_PSEUDO_PATH;
+  nva[1].namelen = sizeof(H2H3_PSEUDO_PATH) - 1;
+  nva[1].value = hdbuf;
+  nva[1].valuelen = (end - hdbuf);
+
+  nva[2].name = H2H3_PSEUDO_SCHEME;
+  nva[2].namelen = sizeof(H2H3_PSEUDO_SCHEME) - 1;
+  vptr = Curl_checkheaders(data, STRCONST(H2H3_PSEUDO_SCHEME));
+  if(vptr) {
+    vptr += sizeof(H2H3_PSEUDO_SCHEME);
+    while(*vptr && ISSPACE(*vptr))
+      vptr++;
+    nva[2].value = vptr;
+    infof(data, "set pseudo header %s to %s", H2H3_PSEUDO_SCHEME, vptr);
+  }
+  else {
+    if(conn->handler->flags & PROTOPT_SSL)
+      nva[2].value = "https";
+    else
+      nva[2].value = "http";
+  }
+  nva[2].valuelen = strlen((char *)nva[2].value);
+
+  authority_idx = 0;
+  i = 3;
+  while(i < nheader) {
+    size_t hlen;
+
+    hdbuf = line_end + 2;
+
+    /* check for next CR, but only within the piece of data left in the given
+       buffer */
+    line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
+    if(!line_end || (line_end == hdbuf))
+      goto fail;
+
+    /* header continuation lines are not supported */
+    if(*hdbuf == ' ' || *hdbuf == '\t')
+      goto fail;
+
+    for(end = hdbuf; end < line_end && *end != ':'; ++end)
+      ;
+    if(end == hdbuf || end == line_end)
+      goto fail;
+    hlen = end - hdbuf;
+
+    if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
+      authority_idx = i;
+      nva[i].name = H2H3_PSEUDO_AUTHORITY;
+      nva[i].namelen = sizeof(H2H3_PSEUDO_AUTHORITY) - 1;
+    }
+    else {
+      nva[i].namelen = (size_t)(end - hdbuf);
+      /* Lower case the header name for HTTP/3 */
+      Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
+      nva[i].name = hdbuf;
+    }
+    hdbuf = end + 1;
+    while(*hdbuf == ' ' || *hdbuf == '\t')
+      ++hdbuf;
+    end = line_end;
+
+    switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
+                          end - hdbuf)) {
+    case HEADERINST_IGNORE:
+      /* skip header fields prohibited by HTTP/2 specification. */
+      --nheader;
+      continue;
+    case HEADERINST_TE_TRAILERS:
+      nva[i].value = "trailers";
+      nva[i].valuelen = sizeof("trailers") - 1;
+      break;
+    default:
+      nva[i].value = hdbuf;
+      nva[i].valuelen = (end - hdbuf);
+    }
+
+    nva[i].value = hdbuf;
+    nva[i].valuelen = (end - hdbuf);
+
+    ++i;
+  }
+
+  /* :authority must come before non-pseudo header fields */
+  if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
+    struct h2h3pseudo authority = nva[authority_idx];
+    for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
+      nva[i] = nva[i - 1];
+    }
+    nva[i] = authority;
+  }
+
+  /* Warn stream may be rejected if cumulative length of headers is too
+     large. */
+#define MAX_ACC 60000  /* <64KB to account for some overhead */
+  {
+    size_t acc = 0;
+
+    for(i = 0; i < nheader; ++i) {
+      acc += nva[i].namelen + nva[i].valuelen;
+
+      infof(data, "h2h3 [%.*s: %.*s]",
+            (int)nva[i].namelen, nva[i].name,
+            (int)nva[i].valuelen, nva[i].value);
+    }
+
+    if(acc > MAX_ACC) {
+      infof(data, "http_request: Warning: The cumulative length of all "
+            "headers exceeds %d bytes and that could cause the "
+            "stream to be rejected.", MAX_ACC);
+    }
+  }
+
+  hreq->entries = nheader;
+  *hp = hreq;
+
+  return CURLE_OK;
+
+  fail:
+  free(hreq);
+  return CURLE_OUT_OF_MEMORY;
+}
+
+void Curl_pseudo_free(struct h2h3req *hp)
+{
+  free(hp);
+}
+
+#endif /* USE_NGHTTP2 or HTTP/3 enabled */

+ 59 - 0
lib/h2h3.h

@@ -0,0 +1,59 @@
+#ifndef HEADER_CURL_H2H3_H
+#define HEADER_CURL_H2H3_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#define H2H3_PSEUDO_METHOD ":method"
+#define H2H3_PSEUDO_SCHEME ":scheme"
+#define H2H3_PSEUDO_AUTHORITY ":authority"
+#define H2H3_PSEUDO_PATH ":path"
+#define H2H3_PSEUDO_STATUS ":status"
+
+struct h2h3pseudo {
+  const char *name;
+  size_t namelen;
+  const char *value;
+  size_t valuelen;
+};
+
+struct h2h3req {
+  size_t entries;
+  struct h2h3pseudo header[1]; /* the array is allocated to contain entries */
+};
+
+/*
+ * Curl_pseudo_headers() creates the array with pseudo headers to be
+ * used in a HTTP/2 or HTTP/3 request. Returns an allocated struct.
+ * Free it with Curl_pseudo_free().
+ */
+CURLcode Curl_pseudo_headers(struct Curl_easy *data,
+                             const char *request,
+                             const size_t len,
+                             struct h2h3req **hp);
+
+/*
+ * Curl_pseudo_free() frees a h2h3req struct.
+ */
+void Curl_pseudo_free(struct h2h3req *hp);
+
+#endif /* HEADER_CURL_H2H3_H */

+ 324 - 0
lib/headers.c

@@ -0,0 +1,324 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2022, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "strdup.h"
+#include "strcase.h"
+#include "headers.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HEADERS_API)
+
+/* Generate the curl_header struct for the user. This function MUST assign all
+   struct fields in the output struct. */
+static void copy_header_external(struct Curl_easy *data,
+                                 struct Curl_header_store *hs,
+                                 size_t index,
+                                 size_t amount,
+                                 struct Curl_llist_element *e,
+                                 struct curl_header **hout)
+{
+  struct curl_header *h = *hout = &data->state.headerout;
+  h->name = hs->name;
+  h->value = hs->value;
+  h->amount = amount;
+  h->index = index;
+  /* this will randomly OR a reserved bit for the sole purpose of making it
+     impossible for applications to do == comparisons, as that would otherwise
+     be very tempting and then lead to the reserved bits not being reserved
+     anymore. */
+  h->origin = hs->type | (1<<27);
+  h->anchor = e;
+}
+
+/* public API */
+CURLHcode curl_easy_header(CURL *easy,
+                           const char *name,
+                           size_t nameindex,
+                           unsigned int type,
+                           int request,
+                           struct curl_header **hout)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *e_pick = NULL;
+  struct Curl_easy *data = easy;
+  size_t match = 0;
+  size_t amount = 0;
+  struct Curl_header_store *hs = NULL;
+  struct Curl_header_store *pick = NULL;
+  if(!name || !hout || !data ||
+     (type > (CURLH_HEADER|CURLH_TRAILER|CURLH_CONNECT|CURLH_1XX)) ||
+     !type || (request < -1))
+    return CURLHE_BAD_ARGUMENT;
+  if(!Curl_llist_count(&data->state.httphdrs))
+    return CURLHE_NOHEADERS; /* no headers available */
+  if(request > data->state.requests)
+    return CURLHE_NOREQUEST;
+  if(request == -1)
+    request = data->state.requests;
+
+  /* we need a first round to count amount of this header */
+  for(e = data->state.httphdrs.head; e; e = e->next) {
+    hs = e->ptr;
+    if(strcasecompare(hs->name, name) &&
+       (hs->type & type) &&
+       (hs->request == request)) {
+      amount++;
+      pick = hs;
+      e_pick = e;
+    }
+  }
+  if(!amount)
+    return CURLHE_MISSING;
+  else if(nameindex >= amount)
+    return CURLHE_BADINDEX;
+
+  if(nameindex == amount - 1)
+    /* if the last or only occurrence is what's asked for, then we know it */
+    hs = pick;
+  else {
+    for(e = data->state.httphdrs.head; e; e = e->next) {
+      hs = e->ptr;
+      if(strcasecompare(hs->name, name) &&
+         (hs->type & type) &&
+         (hs->request == request) &&
+         (match++ == nameindex)) {
+        e_pick = e;
+        break;
+      }
+    }
+    if(!e) /* this shouldn't happen */
+      return CURLHE_MISSING;
+  }
+  /* this is the name we want */
+  copy_header_external(data, hs, nameindex, amount, e_pick, hout);
+  return CURLHE_OK;
+}
+
+/* public API */
+struct curl_header *curl_easy_nextheader(CURL *easy,
+                                         unsigned int type,
+                                         int request,
+                                         struct curl_header *prev)
+{
+  struct Curl_easy *data = easy;
+  struct Curl_llist_element *pick;
+  struct Curl_llist_element *e;
+  struct Curl_header_store *hs;
+  struct curl_header *hout;
+  size_t amount = 0;
+  size_t index = 0;
+
+  if(request > data->state.requests)
+    return NULL;
+  if(request == -1)
+    request = data->state.requests;
+
+  if(prev) {
+    pick = prev->anchor;
+    if(!pick)
+      /* something is wrong */
+      return NULL;
+    pick = pick->next;
+  }
+  else
+    pick = data->state.httphdrs.head;
+
+  if(pick) {
+    /* make sure it is the next header of the desired type */
+    do {
+      hs = pick->ptr;
+      if((hs->type & type) && (hs->request == request))
+        break;
+      pick = pick->next;
+    } while(pick);
+  }
+
+  if(!pick)
+    /* no more headers available */
+    return NULL;
+
+  hs = pick->ptr;
+
+  /* count number of occurrences of this name within the mask and figure out
+     the index for the currently selected entry */
+  for(e = data->state.httphdrs.head; e; e = e->next) {
+    struct Curl_header_store *check = e->ptr;
+    if(strcasecompare(hs->name, check->name) &&
+       (check->request == request) &&
+       (check->type & type))
+      amount++;
+    if(e == pick)
+      index = amount - 1;
+  }
+
+  copy_header_external(data, hs, index, amount, pick, &hout);
+  return hout;
+}
+
+static CURLcode namevalue(char *header, size_t hlen, unsigned int type,
+                           char **name, char **value)
+{
+  char *end = header + hlen - 1; /* point to the last byte */
+  DEBUGASSERT(hlen);
+  *name = header;
+
+  if(type == CURLH_PSEUDO) {
+    if(*header != ':')
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    header++;
+  }
+
+  /* Find the end of the header name */
+  while(*header && (*header != ':'))
+    ++header;
+
+  if(*header)
+    /* Skip over colon, null it */
+    *header++ = 0;
+  else
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+
+  /* skip all leading space letters */
+  while(*header && ISSPACE(*header))
+    header++;
+
+  *value = header;
+
+  /* skip all trailing space letters */
+  while((end > header) && ISSPACE(*end))
+    *end-- = 0; /* nul terminate */
+  return CURLE_OK;
+}
+
+/*
+ * Curl_headers_push() gets passed a full HTTP header to store. It gets called
+ * immediately before the header callback. The header is CRLF terminated.
+ */
+CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
+                           unsigned char type)
+{
+  char *value = NULL;
+  char *name = NULL;
+  char *end;
+  size_t hlen; /* length of the incoming header */
+  struct Curl_header_store *hs;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+
+  if((header[0] == '\r') || (header[0] == '\n'))
+    /* ignore the body separator */
+    return CURLE_OK;
+
+  end = strchr(header, '\r');
+  if(!end) {
+    end = strchr(header, '\n');
+    if(!end)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+  }
+  hlen = end - header + 1;
+
+  hs = calloc(1, sizeof(*hs) + hlen);
+  if(!hs)
+    return CURLE_OUT_OF_MEMORY;
+  memcpy(hs->buffer, header, hlen);
+  hs->buffer[hlen] = 0; /* nul terminate */
+
+  result = namevalue(hs->buffer, hlen, type, &name, &value);
+  if(result)
+    goto fail;
+
+  hs->name = name;
+  hs->value = value;
+  hs->type = type;
+  hs->request = data->state.requests;
+
+  /* insert this node into the list of headers */
+  Curl_llist_insert_next(&data->state.httphdrs, data->state.httphdrs.tail,
+                         hs, &hs->node);
+
+  return CURLE_OK;
+  fail:
+  free(hs);
+  return result;
+}
+
+/*
+ * Curl_headers_init(). Init the headers subsystem.
+ */
+static void headers_init(struct Curl_easy *data)
+{
+  Curl_llist_init(&data->state.httphdrs, NULL);
+}
+
+/*
+ * Curl_headers_cleanup(). Free all stored headers and associated memory.
+ */
+CURLcode Curl_headers_cleanup(struct Curl_easy *data)
+{
+  struct Curl_llist_element *e;
+  struct Curl_llist_element *n;
+
+  for(e = data->state.httphdrs.head; e; e = n) {
+    struct Curl_header_store *hs = e->ptr;
+    n = e->next;
+    free(hs);
+  }
+  headers_init(data);
+  return CURLE_OK;
+}
+
+#else /* HTTP-disabled builds below */
+
+CURLHcode curl_easy_header(CURL *easy,
+                           const char *name,
+                           size_t index,
+                           unsigned int origin,
+                           int request,
+                           struct curl_header **hout)
+{
+  (void)easy;
+  (void)name;
+  (void)index;
+  (void)origin;
+  (void)request;
+  (void)hout;
+  return CURLHE_NOT_BUILT_IN;
+}
+
+struct curl_header *curl_easy_nextheader(CURL *easy,
+                                         unsigned int type,
+                                         int request,
+                                         struct curl_header *prev)
+{
+  (void)easy;
+  (void)type;
+  (void)request;
+  (void)prev;
+  return NULL;
+}
+#endif

+ 53 - 0
lib/headers.h

@@ -0,0 +1,53 @@
+#ifndef HEADER_CURL_HEADER_H
+#define HEADER_CURL_HEADER_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HEADERS_API)
+
+struct Curl_header_store {
+  struct Curl_llist_element node;
+  char *name; /* points into 'buffer' */
+  char *value; /* points into 'buffer */
+  int request; /* 0 is the first request, then 1.. 2.. */
+  unsigned char type; /* CURLH_* defines */
+  char buffer[1]; /* this is the raw header blob */
+};
+
+/*
+ * Curl_headers_push() gets passed a full header to store.
+ */
+CURLcode Curl_headers_push(struct Curl_easy *data, const char *header,
+                           unsigned char type);
+
+/*
+ * Curl_headers_cleanup(). Free all stored headers and associated memory.
+ */
+CURLcode Curl_headers_cleanup(struct Curl_easy *data);
+
+#else
+#define Curl_headers_push(x,y,z) CURLE_OK
+#define Curl_headers_cleanup(x) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_HEADER_H */

+ 3 - 3
lib/hmac.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -39,8 +39,8 @@
  * Generic HMAC algorithm.
  *
  *   This module computes HMAC digests based on any hash function. Parameters
- * and computing procedures are set-up dynamically at HMAC computation
- * context initialisation.
+ * and computing procedures are set-up dynamically at HMAC computation context
+ * initialization.
  */
 
 static const unsigned char hmac_ipad = 0x36;

+ 7 - 6
lib/hostip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -945,7 +945,7 @@ clean_up:
          less than 1! */
       alarm(1);
       rc = CURLRESOLV_TIMEDOUT;
-      failf(data, "Previous alarm fired off!");
+      failf(data, "Previous alarm fired off");
     }
     else
       alarm((unsigned int)alarm_set);
@@ -1131,7 +1131,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
 
         ai = Curl_str2addr(address, port);
         if(!ai) {
-          infof(data, "Resolve address '%s' found illegal!", address);
+          infof(data, "Resolve address '%s' found illegal", address);
           goto err;
         }
 
@@ -1150,7 +1150,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       error = false;
    err:
       if(error) {
-        failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'!",
+        failf(data, "Couldn't parse CURLOPT_RESOLVE entry '%s'",
               hostp->data);
         Curl_freeaddrinfo(head);
         return CURLE_SETOPT_OPTION_SYNTAX;
@@ -1167,8 +1167,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
       if(dns) {
-        infof(data, "RESOLVE %s:%d is - old addresses discarded!",
-                hostname, port);
+        infof(data, "RESOLVE %s:%d is - old addresses discarded",
+              hostname, port);
         /* delete old entry, there are two reasons for this
          1. old entry may have different addresses.
          2. even if entry with correct addresses is already in the cache,
@@ -1220,6 +1220,7 @@ CURLcode Curl_resolv_check(struct Curl_easy *data,
                            struct Curl_dns_entry **dns)
 {
 #if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
+  (void)data;
   (void)dns;
 #endif
 #ifndef CURL_DISABLE_DOH

+ 2 - 2
lib/hsts.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2020 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2020 - 2022, 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
@@ -21,7 +21,7 @@
  ***************************************************************************/
 /*
  * The Strict-Transport-Security header is defined in RFC 6797:
- * https://tools.ietf.org/html/rfc6797
+ * https://datatracker.ietf.org/doc/html/rfc6797
  */
 #include "curl_setup.h"
 

+ 153 - 169
lib/http.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -77,7 +77,6 @@
 #include "content_encoding.h"
 #include "http_proxy.h"
 #include "warnless.h"
-#include "non-ascii.h"
 #include "http2.h"
 #include "connect.h"
 #include "strdup.h"
@@ -216,10 +215,10 @@ static CURLcode http_setup_conn(struct Curl_easy *data,
  */
 char *Curl_checkProxyheaders(struct Curl_easy *data,
                              const struct connectdata *conn,
-                             const char *thisheader)
+                             const char *thisheader,
+                             const size_t thislen)
 {
   struct curl_slist *head;
-  size_t thislen = strlen(thisheader);
 
   for(head = (conn->bits.proxy && data->set.sep_headers) ?
         data->set.proxyheaders : data->set.headers;
@@ -233,7 +232,7 @@ char *Curl_checkProxyheaders(struct Curl_easy *data,
 }
 #else
 /* disabled */
-#define Curl_checkProxyheaders(x,y,z) NULL
+#define Curl_checkProxyheaders(x,y,z,a) NULL
 #endif
 
 /*
@@ -327,7 +326,7 @@ static CURLcode http_output_basic(struct Curl_easy *data, bool proxy)
   if(!out)
     return CURLE_OUT_OF_MEMORY;
 
-  result = Curl_base64_encode(data, out, strlen(out), &authorization, &size);
+  result = Curl_base64_encode(out, strlen(out), &authorization, &size);
   if(result)
     goto fail;
 
@@ -588,7 +587,7 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data)
   if(data->state.authproblem)
     return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
 
-  if((conn->bits.user_passwd || data->set.str[STRING_BEARER]) &&
+  if((data->state.aptr.user || data->set.str[STRING_BEARER]) &&
      ((data->req.httpcode == 401) ||
       (conn->bits.authneg && data->req.httpcode < 300))) {
     pickhost = pickoneauth(&data->state.authhost, authmask);
@@ -667,6 +666,7 @@ output_auth_headers(struct Curl_easy *data,
 {
   const char *auth = NULL;
   CURLcode result = CURLE_OK;
+  (void)conn;
 
 #ifdef CURL_DISABLE_CRYPTO_AUTH
   (void)request;
@@ -725,10 +725,10 @@ output_auth_headers(struct Curl_easy *data,
     if(
 #ifndef CURL_DISABLE_PROXY
       (proxy && conn->bits.proxy_user_passwd &&
-       !Curl_checkProxyheaders(data, conn, "Proxy-authorization")) ||
+       !Curl_checkProxyheaders(data, conn, STRCONST("Proxy-authorization"))) ||
 #endif
-      (!proxy && conn->bits.user_passwd &&
-       !Curl_checkheaders(data, "Authorization"))) {
+      (!proxy && data->state.aptr.user &&
+       !Curl_checkheaders(data, STRCONST("Authorization")))) {
       auth = "Basic";
       result = http_output_basic(data, proxy);
       if(result)
@@ -742,7 +742,7 @@ output_auth_headers(struct Curl_easy *data,
   if(authstatus->picked == CURLAUTH_BEARER) {
     /* Bearer */
     if((!proxy && data->set.str[STRING_BEARER] &&
-        !Curl_checkheaders(data, "Authorization"))) {
+        !Curl_checkheaders(data, STRCONST("Authorization")))) {
       auth = "Bearer";
       result = http_output_bearer(data);
       if(result)
@@ -775,6 +775,21 @@ output_auth_headers(struct Curl_easy *data,
   return CURLE_OK;
 }
 
+/*
+ * Curl_allow_auth_to_host() tells if authentication, cookies or other
+ * "sensitive data" can (still) be sent to this host.
+ */
+bool Curl_allow_auth_to_host(struct Curl_easy *data)
+{
+  struct connectdata *conn = data->conn;
+  return (!data->state.this_is_a_follow ||
+          data->set.allow_auth_to_other_hosts ||
+          (data->state.first_host &&
+           strcasecompare(data->state.first_host, conn->host.name) &&
+           (data->state.first_remote_port == conn->remote_port) &&
+           (data->state.first_remote_protocol == conn->handler->protocol)));
+}
+
 /**
  * Curl_http_output_auth() setups the authentication headers for the
  * host/proxy and the correct authentication
@@ -811,7 +826,7 @@ Curl_http_output_auth(struct Curl_easy *data,
 #ifndef CURL_DISABLE_PROXY
     (conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
 #endif
-     conn->bits.user_passwd || data->set.str[STRING_BEARER])
+     data->state.aptr.user || data->set.str[STRING_BEARER])
     /* continue please */;
   else {
     authhost->done = TRUE;
@@ -847,17 +862,14 @@ Curl_http_output_auth(struct Curl_easy *data,
        with it */
     authproxy->done = TRUE;
 
-  /* To prevent the user+password to get sent to other than the original
-     host due to a location-follow, we do some weirdo checks here */
-  if(!data->state.this_is_a_follow ||
+  /* To prevent the user+password to get sent to other than the original host
+     due to a location-follow */
+  if(Curl_allow_auth_to_host(data)
 #ifndef CURL_DISABLE_NETRC
-     conn->bits.netrc ||
+     || conn->bits.netrc
 #endif
-     !data->state.first_host ||
-     data->set.allow_auth_to_other_hosts ||
-     strcasecompare(data->state.first_host, conn->host.name)) {
+    )
     result = output_auth_headers(data, conn, authhost, request, path, FALSE);
-  }
   else
     authhost->done = TRUE;
 
@@ -1143,7 +1155,7 @@ static bool http_should_fail(struct Curl_easy *data)
   ** Either we're not authenticating, or we're supposed to
   ** be authenticating something else.  This is an error.
   */
-  if((httpcode == 401) && !data->conn->bits.user_passwd)
+  if((httpcode == 401) && !data->state.aptr.user)
     return TRUE;
 #ifndef CURL_DISABLE_PROXY
   if((httpcode == 407) && !data->conn->bits.proxy_user_passwd)
@@ -1251,14 +1263,6 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
 
   DEBUGASSERT(size > (size_t)included_body_bytes);
 
-  result = Curl_convert_to_network(data, ptr, headersize);
-  /* Curl_convert_to_network calls failf if unsuccessful */
-  if(result) {
-    /* conversion failed, free memory and return to the caller */
-    Curl_dyn_free(in);
-    return result;
-  }
-
   if((conn->handler->flags & PROTOPT_SSL
 #ifndef CURL_DISABLE_PROXY
       || conn->http_proxy.proxytype == CURLPROXY_HTTPS
@@ -1425,18 +1429,22 @@ CURLcode Curl_buffer_send(struct dynbuf *in,
 bool
 Curl_compareheader(const char *headerline, /* line to check */
                    const char *header,  /* header keyword _with_ colon */
-                   const char *content) /* content string to find */
+                   const size_t hlen,   /* len of the keyword in bytes */
+                   const char *content, /* content string to find */
+                   const size_t clen)   /* len of the content in bytes */
 {
   /* RFC2616, section 4.2 says: "Each header field consists of a name followed
    * by a colon (":") and the field value. Field names are case-insensitive.
    * The field value MAY be preceded by any amount of LWS, though a single SP
    * is preferred." */
 
-  size_t hlen = strlen(header);
-  size_t clen;
   size_t len;
   const char *start;
   const char *end;
+  DEBUGASSERT(hlen);
+  DEBUGASSERT(clen);
+  DEBUGASSERT(header);
+  DEBUGASSERT(content);
 
   if(!strncasecompare(headerline, header, hlen))
     return FALSE; /* doesn't start with header */
@@ -1460,7 +1468,6 @@ Curl_compareheader(const char *headerline, /* line to check */
   }
 
   len = end-start; /* length of the content part of the input line */
-  clen = strlen(content); /* length of the word to find */
 
   /* find the content string in the rest of the line */
   for(; len >= clen; len--, start++) {
@@ -1546,7 +1553,7 @@ static CURLcode add_haproxy_protocol_header(struct Curl_easy *data)
 #ifdef USE_UNIX_SOCKETS
   if(data->conn->unix_domain_socket)
     /* the buffer is large enough to hold this! */
-    result = Curl_dyn_add(&req, "PROXY UNKNOWN\r\n");
+    result = Curl_dyn_addn(&req, STRCONST("PROXY UNKNOWN\r\n"));
   else {
 #endif
   /* Emit the correct prefix for IPv6 */
@@ -1713,13 +1720,13 @@ static CURLcode expect100(struct Curl_easy *data,
     /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
        Expect: 100-continue to the headers which actually speeds up post
        operations (as there is one packet coming back from the web server) */
-    const char *ptr = Curl_checkheaders(data, "Expect");
+    const char *ptr = Curl_checkheaders(data, STRCONST("Expect"));
     if(ptr) {
       data->state.expect100header =
-        Curl_compareheader(ptr, "Expect:", "100-continue");
+        Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
     }
     else {
-      result = Curl_dyn_add(req, "Expect: 100-continue\r\n");
+      result = Curl_dyn_addn(req, STRCONST("Expect: 100-continue\r\n"));
       if(!result)
         data->state.expect100header = TRUE;
     }
@@ -1772,7 +1779,7 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
         return result;
     }
     else
-      infof(handle, "Malformatted trailing header ! Skipping trailer.");
+      infof(handle, "Malformatted trailing header, skipping trailer");
     trailers = trailers->next;
   }
   result = Curl_dyn_add(b, endofline_network);
@@ -1867,7 +1874,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
           ptr = optr;
         }
       }
-      if(ptr) {
+      if(ptr && (ptr != headers->data)) {
         /* we require a colon for this to be a true header */
 
         ptr++; /* pass the colon */
@@ -1910,10 +1917,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
                    checkprefix("Cookie:", compare)) &&
                   /* be careful of sending this potentially sensitive header to
                      other hosts */
-                  (data->state.this_is_a_follow &&
-                   data->state.first_host &&
-                   !data->set.allow_auth_to_other_hosts &&
-                   !strcasecompare(data->state.first_host, conn->host.name)))
+                  !Curl_allow_auth_to_host(data))
             ;
           else {
 #ifdef USE_HYPER
@@ -1949,6 +1953,7 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
   CURLcode result;
   char datestr[80];
   const char *condp;
+  size_t len;
 
   if(data->set.timecondition == CURL_TIMECOND_NONE)
     /* no condition was asked for */
@@ -1967,16 +1972,19 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
 
   case CURL_TIMECOND_IFMODSINCE:
     condp = "If-Modified-Since";
+    len = 17;
     break;
   case CURL_TIMECOND_IFUNMODSINCE:
     condp = "If-Unmodified-Since";
+    len = 19;
     break;
   case CURL_TIMECOND_LASTMOD:
     condp = "Last-Modified";
+    len = 13;
     break;
   }
 
-  if(Curl_checkheaders(data, condp)) {
+  if(Curl_checkheaders(data, condp, len)) {
     /* A custom header was specified; it will be sent instead. */
     return CURLE_OK;
   }
@@ -2065,7 +2073,7 @@ CURLcode Curl_http_useragent(struct Curl_easy *data)
      it might have been used in the proxy connect, but if we have got a header
      with the user-agent string specified, we erase the previously made string
      here. */
-  if(Curl_checkheaders(data, "User-Agent")) {
+  if(Curl_checkheaders(data, STRCONST("User-Agent"))) {
     free(data->state.aptr.uagent);
     data->state.aptr.uagent = NULL;
   }
@@ -2085,10 +2093,11 @@ CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn)
       return CURLE_OUT_OF_MEMORY;
 
     data->state.first_remote_port = conn->remote_port;
+    data->state.first_remote_protocol = conn->handler->protocol;
   }
   Curl_safefree(data->state.aptr.host);
 
-  ptr = Curl_checkheaders(data, "Host");
+  ptr = Curl_checkheaders(data, STRCONST("Host"));
   if(ptr && (!data->state.this_is_a_follow ||
              strcasecompare(data->state.first_host, conn->host.name))) {
 #if !defined(CURL_DISABLE_COOKIES)
@@ -2305,7 +2314,7 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
 
 #ifndef CURL_DISABLE_MIME
   if(http->sendit) {
-    const char *cthdr = Curl_checkheaders(data, "Content-Type");
+    const char *cthdr = Curl_checkheaders(data, STRCONST("Content-Type"));
 
     /* Read and seek body only. */
     http->sendit->flags |= MIME_BODY_ONLY;
@@ -2330,11 +2339,12 @@ CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
   }
 #endif
 
-  ptr = Curl_checkheaders(data, "Transfer-Encoding");
+  ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding"));
   if(ptr) {
     /* Some kind of TE is requested, check if 'chunked' is chosen */
     data->req.upload_chunky =
-      Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
+      Curl_compareheader(ptr,
+                         STRCONST("Transfer-Encoding:"), STRCONST("chunked"));
   }
   else {
     if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
@@ -2394,7 +2404,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
       http->postsize = data->state.infilesize;
 
     if((http->postsize != -1) && !data->req.upload_chunky &&
-       (conn->bits.authneg || !Curl_checkheaders(data, "Content-Length"))) {
+       (conn->bits.authneg ||
+        !Curl_checkheaders(data, STRCONST("Content-Length")))) {
       /* only add Content-Length if not uploading chunked */
       result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
                              "\r\n", http->postsize);
@@ -2409,7 +2420,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
     }
 
     /* end of headers */
-    result = Curl_dyn_add(r, "\r\n");
+    result = Curl_dyn_addn(r, STRCONST("\r\n"));
     if(result)
       return result;
 
@@ -2434,7 +2445,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
     /* This is form posting using mime data. */
     if(conn->bits.authneg) {
       /* nothing to post! */
-      result = Curl_dyn_add(r, "Content-Length: 0\r\n\r\n");
+      result = Curl_dyn_addn(r, STRCONST("Content-Length: 0\r\n\r\n"));
       if(result)
         return result;
 
@@ -2454,7 +2465,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
        we don't upload data chunked, as RFC2616 forbids us to set both
        kinds of headers (Transfer-Encoding: chunked and Content-Length) */
     if(http->postsize != -1 && !data->req.upload_chunky &&
-       (conn->bits.authneg || !Curl_checkheaders(data, "Content-Length"))) {
+       (conn->bits.authneg ||
+        !Curl_checkheaders(data, STRCONST("Content-Length")))) {
       /* we allow replacing this header if not during auth negotiation,
          although it isn't very wise to actually set your own */
       result = Curl_dyn_addf(r,
@@ -2481,10 +2493,10 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
        the somewhat bigger ones we allow the app to disable it. Just make
        sure that the expect100header is always set to the preferred value
        here. */
-    ptr = Curl_checkheaders(data, "Expect");
+    ptr = Curl_checkheaders(data, STRCONST("Expect"));
     if(ptr) {
       data->state.expect100header =
-        Curl_compareheader(ptr, "Expect:", "100-continue");
+        Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
     }
     else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
       result = expect100(data, conn, r);
@@ -2495,7 +2507,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
       data->state.expect100header = FALSE;
 
     /* make the request end in a true CRLF */
-    result = Curl_dyn_add(r, "\r\n");
+    result = Curl_dyn_addn(r, STRCONST("\r\n"));
     if(result)
       return result;
 
@@ -2534,7 +2546,8 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
        we don't upload data chunked, as RFC2616 forbids us to set both
        kinds of headers (Transfer-Encoding: chunked and Content-Length) */
     if((http->postsize != -1) && !data->req.upload_chunky &&
-       (conn->bits.authneg || !Curl_checkheaders(data, "Content-Length"))) {
+       (conn->bits.authneg ||
+        !Curl_checkheaders(data, STRCONST("Content-Length")))) {
       /* we allow replacing this header if not during auth negotiation,
          although it isn't very wise to actually set your own */
       result = Curl_dyn_addf(r, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
@@ -2543,9 +2556,9 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
         return result;
     }
 
-    if(!Curl_checkheaders(data, "Content-Type")) {
-      result = Curl_dyn_add(r, "Content-Type: application/"
-                            "x-www-form-urlencoded\r\n");
+    if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
+      result = Curl_dyn_addn(r, STRCONST("Content-Type: application/"
+                                         "x-www-form-urlencoded\r\n"));
       if(result)
         return result;
     }
@@ -2554,10 +2567,10 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
        the somewhat bigger ones we allow the app to disable it. Just make
        sure that the expect100header is always set to the preferred value
        here. */
-    ptr = Curl_checkheaders(data, "Expect");
+    ptr = Curl_checkheaders(data, STRCONST("Expect"));
     if(ptr) {
       data->state.expect100header =
-        Curl_compareheader(ptr, "Expect:", "100-continue");
+        Curl_compareheader(ptr, STRCONST("Expect:"), STRCONST("100-continue"));
     }
     else if(http->postsize > EXPECT_100_THRESHOLD || http->postsize < 0) {
       result = expect100(data, conn, r);
@@ -2584,7 +2597,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
            get the data duplicated with malloc() and family. */
 
         /* end of headers! */
-        result = Curl_dyn_add(r, "\r\n");
+        result = Curl_dyn_addn(r, STRCONST("\r\n"));
         if(result)
           return result;
 
@@ -2606,12 +2619,12 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
               result = Curl_dyn_addn(r, data->set.postfields,
                                      (size_t)http->postsize);
               if(!result)
-                result = Curl_dyn_add(r, "\r\n");
+                result = Curl_dyn_addn(r, STRCONST("\r\n"));
               included_body += 2;
             }
           }
           if(!result) {
-            result = Curl_dyn_add(r, "\x30\x0d\x0a\x0d\x0a");
+            result = Curl_dyn_addn(r, STRCONST("\x30\x0d\x0a\x0d\x0a"));
             /* 0  CR  LF  CR  LF */
             included_body += 5;
           }
@@ -2634,7 +2647,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
         Curl_pgrsSetUploadSize(data, http->postsize);
 
         /* end of headers! */
-        result = Curl_dyn_add(r, "\r\n");
+        result = Curl_dyn_addn(r, STRCONST("\r\n"));
         if(result)
           return result;
       }
@@ -2643,14 +2656,14 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
 #endif
     {
        /* end of headers! */
-      result = Curl_dyn_add(r, "\r\n");
+      result = Curl_dyn_addn(r, STRCONST("\r\n"));
       if(result)
         return result;
 
       if(data->req.upload_chunky && conn->bits.authneg) {
         /* Chunky upload is selected and we're negotiating auth still, send
            end-of-data only */
-        result = Curl_dyn_add(r, (char *)"\x30\x0d\x0a\x0d\x0a");
+        result = Curl_dyn_addn(r, (char *)STRCONST("\x30\x0d\x0a\x0d\x0a"));
         /* 0  CR  LF  CR  LF */
         if(result)
           return result;
@@ -2678,7 +2691,7 @@ CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
     break;
 
   default:
-    result = Curl_dyn_add(r, "\r\n");
+    result = Curl_dyn_addn(r, STRCONST("\r\n"));
     if(result)
       return result;
 
@@ -2702,7 +2715,8 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
 {
   CURLcode result = CURLE_OK;
   char *addcookies = NULL;
-  if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, "Cookie"))
+  if(data->set.str[STRING_COOKIE] &&
+     !Curl_checkheaders(data, STRCONST("Cookie")))
     addcookies = data->set.str[STRING_COOKIE];
 
   if(data->cookies || addcookies) {
@@ -2728,7 +2742,7 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
       while(co) {
         if(co->value) {
           if(0 == count) {
-            result = Curl_dyn_add(r, "Cookie: ");
+            result = Curl_dyn_addn(r, STRCONST("Cookie: "));
             if(result)
               break;
           }
@@ -2744,14 +2758,14 @@ CURLcode Curl_http_cookies(struct Curl_easy *data,
     }
     if(addcookies && !result) {
       if(!count)
-        result = Curl_dyn_add(r, "Cookie: ");
+        result = Curl_dyn_addn(r, STRCONST("Cookie: "));
       if(!result) {
         result = Curl_dyn_addf(r, "%s%s", count?"; ":"", addcookies);
         count++;
       }
     }
     if(count && !result)
-      result = Curl_dyn_add(r, "\r\n");
+      result = Curl_dyn_addn(r, STRCONST("\r\n"));
 
     if(result)
       return result;
@@ -2770,14 +2784,14 @@ CURLcode Curl_http_range(struct Curl_easy *data,
      * ones if any such are specified.
      */
     if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
-       !Curl_checkheaders(data, "Range")) {
+       !Curl_checkheaders(data, STRCONST("Range"))) {
       /* if a line like this was already allocated, free the previous one */
       free(data->state.aptr.rangeline);
       data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
                                            data->state.range);
     }
     else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
-            !Curl_checkheaders(data, "Content-Range")) {
+            !Curl_checkheaders(data, STRCONST("Content-Range"))) {
 
       /* if a line like this was already allocated, free the previous one */
       free(data->state.aptr.rangeline);
@@ -2923,7 +2937,7 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
       /* The resume point is at the end of file, consider this fine even if it
          doesn't allow resume from here. */
       infof(data, "The entire document is already downloaded");
-      connclose(conn, "already downloaded");
+      streamclose(conn, "already downloaded");
       /* Abort download */
       k->keepon &= ~KEEP_RECV;
       *done = TRUE;
@@ -2948,10 +2962,10 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
       /* We're simulating a http 304 from server so we return
          what should have been returned from the server */
       data->info.httpcode = 304;
-      infof(data, "Simulate a HTTP 304 response!");
+      infof(data, "Simulate a HTTP 304 response");
       /* we abort the transfer before it is completed == we ruin the
          re-use ability. Close the connection */
-      connclose(conn, "Simulated 304 handling");
+      streamclose(conn, "Simulated 304 handling");
       return CURLE_OK;
     }
   } /* we have a time condition */
@@ -2962,14 +2976,14 @@ CURLcode Curl_http_firstwrite(struct Curl_easy *data,
 #ifdef HAVE_LIBZ
 CURLcode Curl_transferencode(struct Curl_easy *data)
 {
-  if(!Curl_checkheaders(data, "TE") &&
+  if(!Curl_checkheaders(data, STRCONST("TE")) &&
      data->set.http_transfer_encoding) {
     /* When we are to insert a TE: header in the request, we must also insert
        TE in a Connection: header, so we need to merge the custom provided
        Connection: header and prevent the original to get sent. Note that if
        the user has inserted his/her own TE: header we don't do this magic
        but then assume that the user will handle it all! */
-    char *cptr = Curl_checkheaders(data, "Connection");
+    char *cptr = Curl_checkheaders(data, STRCONST("Connection"));
 #define TE_HEADER "TE: gzip\r\n"
 
     Curl_safefree(data->state.aptr.te);
@@ -3089,13 +3103,13 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   }
 
   Curl_safefree(data->state.aptr.ref);
-  if(data->state.referer && !Curl_checkheaders(data, "Referer")) {
+  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)
       return CURLE_OUT_OF_MEMORY;
   }
 
-  if(!Curl_checkheaders(data, "Accept-Encoding") &&
+  if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
      data->set.str[STRING_ENCODING]) {
     Curl_safefree(data->state.aptr.accept_encoding);
     data->state.aptr.accept_encoding =
@@ -3117,7 +3131,8 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   if(result)
     return result;
 
-  p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
+  p_accept = Curl_checkheaders(data,
+                               STRCONST("Accept"))?NULL:"Accept: */*\r\n";
 
   result = Curl_http_resume(data, conn, httpreq);
   if(result)
@@ -3147,7 +3162,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
   }
 
 #ifndef CURL_DISABLE_ALTSVC
-  if(conn->bits.altused && !Curl_checkheaders(data, "Alt-Used")) {
+  if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) {
     altused = aprintf("Alt-Used: %s:%d\r\n",
                       conn->conn_to_host.name, conn->conn_to_port);
     if(!altused) {
@@ -3194,8 +3209,10 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done)
 #ifndef CURL_DISABLE_PROXY
                   (conn->bits.httpproxy &&
                    !conn->bits.tunnel_proxy &&
-                   !Curl_checkheaders(data, "Proxy-Connection") &&
-                   !Curl_checkProxyheaders(data, conn, "Proxy-Connection"))?
+                   !Curl_checkheaders(data, STRCONST("Proxy-Connection")) &&
+                   !Curl_checkProxyheaders(data,
+                                           conn,
+                                           STRCONST("Proxy-Connection")))?
                   "Proxy-Connection: Keep-Alive\r\n":"",
 #else
                   "",
@@ -3308,20 +3325,6 @@ checkhttpprefix(struct Curl_easy *data,
   struct curl_slist *head = data->set.http200aliases;
   statusline rc = STATUS_BAD;
   statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
-#ifdef CURL_DOES_CONVERSIONS
-  /* convert from the network encoding using a scratch area */
-  char *scratch = strdup(s);
-  if(!scratch) {
-    failf(data, "Failed to allocate memory for conversion!");
-    return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
-  }
-  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) {
-    /* Curl_convert_from_network calls failf if unsuccessful */
-    free(scratch);
-    return FALSE; /* can't return CURLE_foobar so return FALSE */
-  }
-  s = scratch;
-#endif /* CURL_DOES_CONVERSIONS */
 
   while(head) {
     if(checkprefixmax(head->data, s, len)) {
@@ -3334,9 +3337,6 @@ checkhttpprefix(struct Curl_easy *data,
   if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len)))
     rc = onmatch;
 
-#ifdef CURL_DOES_CONVERSIONS
-  free(scratch);
-#endif /* CURL_DOES_CONVERSIONS */
   return rc;
 }
 
@@ -3347,26 +3347,9 @@ checkrtspprefix(struct Curl_easy *data,
 {
   statusline result = STATUS_BAD;
   statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
-
-#ifdef CURL_DOES_CONVERSIONS
-  /* convert from the network encoding using a scratch area */
-  char *scratch = strdup(s);
-  if(!scratch) {
-    failf(data, "Failed to allocate memory for conversion!");
-    return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
-  }
-  if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) {
-    /* Curl_convert_from_network calls failf if unsuccessful */
-    result = FALSE; /* can't return CURLE_foobar so return FALSE */
-  }
-  else if(checkprefixmax("RTSP/", scratch, len))
-    result = onmatch;
-  free(scratch);
-#else
   (void)data; /* unused */
   if(checkprefixmax("RTSP/", s, len))
     result = onmatch;
-#endif /* CURL_DOES_CONVERSIONS */
 
   return result;
 }
@@ -3412,7 +3395,7 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
         return CURLE_FILESIZE_EXCEEDED;
       }
       streamclose(conn, "overflow content-length");
-      infof(data, "Overflow Content-Length: value!");
+      infof(data, "Overflow Content-Length: value");
     }
     else {
       /* negative or just rubbish - bad HTTP */
@@ -3436,7 +3419,9 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
 #ifndef CURL_DISABLE_PROXY
   else if((conn->httpversion == 10) &&
           conn->bits.httpproxy &&
-          Curl_compareheader(headp, "Proxy-Connection:", "keep-alive")) {
+          Curl_compareheader(headp,
+                             STRCONST("Proxy-Connection:"),
+                             STRCONST("keep-alive"))) {
     /*
      * When a HTTP/1.0 reply comes when using a proxy, the
      * 'Proxy-Connection: keep-alive' line tells us the
@@ -3444,21 +3429,25 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
      * Default action for 1.0 is to close.
      */
     connkeep(conn, "Proxy-Connection keep-alive"); /* don't close */
-    infof(data, "HTTP/1.0 proxy connection set to keep alive!");
+    infof(data, "HTTP/1.0 proxy connection set to keep alive");
   }
   else if((conn->httpversion == 11) &&
           conn->bits.httpproxy &&
-          Curl_compareheader(headp, "Proxy-Connection:", "close")) {
+          Curl_compareheader(headp,
+                             STRCONST("Proxy-Connection:"),
+                             STRCONST("close"))) {
     /*
      * We get a HTTP/1.1 response from a proxy and it says it'll
      * close down after this transfer.
      */
     connclose(conn, "Proxy-Connection: asked to close after done");
-    infof(data, "HTTP/1.1 proxy connection set close!");
+    infof(data, "HTTP/1.1 proxy connection set close");
   }
 #endif
   else if((conn->httpversion == 10) &&
-          Curl_compareheader(headp, "Connection:", "keep-alive")) {
+          Curl_compareheader(headp,
+                             STRCONST("Connection:"),
+                             STRCONST("keep-alive"))) {
     /*
      * A HTTP/1.0 reply with the 'Connection: keep-alive' line
      * tells us the connection will be kept alive for our
@@ -3466,9 +3455,10 @@ CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
      *
      * [RFC2068, section 19.7.1] */
     connkeep(conn, "Connection keep-alive");
-    infof(data, "HTTP/1.0 connection set to keep alive!");
+    infof(data, "HTTP/1.0 connection set to keep alive");
   }
-  else if(Curl_compareheader(headp, "Connection:", "close")) {
+  else if(Curl_compareheader(headp,
+                             STRCONST("Connection:"), STRCONST("close"))) {
     /*
      * [RFC 2616, section 8.1.2.1]
      * "Connection: close" is HTTP/1.1 language and means that
@@ -3795,6 +3785,29 @@ CURLcode Curl_http_size(struct Curl_easy *data)
   return CURLE_OK;
 }
 
+static CURLcode verify_header(struct Curl_easy *data)
+{
+  struct SingleRequest *k = &data->req;
+  const char *header = Curl_dyn_ptr(&data->state.headerb);
+  size_t hlen = Curl_dyn_len(&data->state.headerb);
+  char *ptr = memchr(header, 0x00, hlen);
+  if(ptr) {
+    /* this is bad, bail out */
+    failf(data, "Nul byte in header");
+    return CURLE_WEIRD_SERVER_REPLY;
+  }
+  if(k->headerline < 2)
+    /* the first "header" is the status-line and it has no colon */
+    return CURLE_OK;
+  ptr = memchr(header, ':', hlen);
+  if(!ptr) {
+    /* this is bad, bail out */
+    failf(data, "Header without colon");
+    return CURLE_WEIRD_SERVER_REPLY;
+  }
+  return CURLE_OK;
+}
+
 /*
  * Read any HTTP header lines from the server and pass them to the client app.
  */
@@ -3903,21 +3916,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
       size_t headerlen;
       /* Zero-length header line means end of headers! */
 
-#ifdef CURL_DOES_CONVERSIONS
-      if(0x0d == *headp) {
-        *headp = '\r'; /* replace with CR in host encoding */
-        headp++;       /* pass the CR byte */
-      }
-      if(0x0a == *headp) {
-        *headp = '\n'; /* replace with LF in host encoding */
-        headp++;       /* pass the LF byte */
-      }
-#else
       if('\r' == *headp)
         headp++; /* pass the \r byte */
       if('\n' == *headp)
         headp++; /* pass the \n byte */
-#endif /* CURL_DOES_CONVERSIONS */
 
       if(100 <= k->httpcode && 199 >= k->httpcode) {
         /* "A user agent MAY ignore unexpected 1xx status responses." */
@@ -4028,9 +4030,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 
       /* now, only output this if the header AND body are requested:
        */
-      writetype = CLIENTWRITE_HEADER;
-      if(data->set.include_header)
-        writetype |= CLIENTWRITE_BODY;
+      writetype = CLIENTWRITE_HEADER |
+        (data->set.include_header ? CLIENTWRITE_BODY : 0) |
+        ((k->httpcode/100 == 1) ? CLIENTWRITE_1XX : 0);
 
       headerlen = Curl_dyn_len(&data->state.headerb);
       result = Curl_client_write(data, writetype,
@@ -4127,7 +4129,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
         if(conn->bits.rewindaftersend) {
           /* We rewind after a complete send, so thus we continue
              sending now */
-          infof(data, "Keep sending data to get tossed away!");
+          infof(data, "Keep sending data to get tossed away");
           k->keepon |= KEEP_SEND;
         }
       }
@@ -4183,36 +4185,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
      * Checks for special headers coming up.
      */
 
+    writetype = CLIENTWRITE_HEADER;
     if(!k->headerline++) {
       /* This is the first header, it MUST be the error code line
          or else we consider this to be the body right away! */
       int httpversion_major;
       int rtspversion_major;
       int nc = 0;
-#ifdef CURL_DOES_CONVERSIONS
-#define HEADER1 scratch
-#define SCRATCHSIZE 21
-      CURLcode res;
-      char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */
-      /* We can't really convert this yet because we don't know if it's the
-         1st header line or the body.  So we do a partial conversion into a
-         scratch area, leaving the data at 'headp' as-is.
-      */
-      strncpy(&scratch[0], headp, SCRATCHSIZE);
-      scratch[SCRATCHSIZE] = 0; /* null terminate */
-      res = Curl_convert_from_network(data,
-                                      &scratch[0],
-                                      SCRATCHSIZE);
-      if(res)
-        /* Curl_convert_from_network calls failf if unsuccessful */
-        return res;
-#else
 #define HEADER1 headp /* no conversion needed, just use headp */
-#endif /* CURL_DOES_CONVERSIONS */
 
       if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
         /*
-         * https://tools.ietf.org/html/rfc7230#section-3.1.2
+         * https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.2
          *
          * The response code is always a three-digit number in HTTP as the spec
          * says. We allow any three-digit number here, but we cannot make
@@ -4254,10 +4238,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
           switch(httpversion) {
           case 10:
           case 11:
-#if defined(USE_NGHTTP2) || defined(USE_HYPER)
+#ifdef USE_HTTP2
           case 20:
 #endif
-#if defined(ENABLE_QUIC)
+#ifdef ENABLE_QUIC
           case 30:
 #endif
             conn->httpversion = (unsigned char)httpversion;
@@ -4326,6 +4310,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
         result = Curl_http_statusline(data, conn);
         if(result)
           return result;
+        writetype |= CLIENTWRITE_STATUS;
       }
       else {
         k->header = FALSE;   /* this is not a header line */
@@ -4333,8 +4318,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
       }
     }
 
-    result = Curl_convert_from_network(data, headp, strlen(headp));
-    /* Curl_convert_from_network calls failf if unsuccessful */
+    result = verify_header(data);
     if(result)
       return result;
 
@@ -4345,10 +4329,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
     /*
      * End of header-checks. Write them to the client.
      */
-
-    writetype = CLIENTWRITE_HEADER;
     if(data->set.include_header)
       writetype |= CLIENTWRITE_BODY;
+    if(k->httpcode/100 == 1)
+      writetype |= CLIENTWRITE_1XX;
 
     Curl_debug(data, CURLINFO_HEADER_IN, headp,
                Curl_dyn_len(&data->state.headerb));

+ 56 - 3
lib/http.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -38,6 +38,10 @@ typedef enum {
 #include <nghttp2/nghttp2.h>
 #endif
 
+#if defined(_WIN32) && defined(ENABLE_QUIC)
+#include <stdint.h>
+#endif
+
 extern const struct Curl_handler Curl_handler_http;
 
 #ifdef USE_SSL
@@ -47,13 +51,16 @@ extern const struct Curl_handler Curl_handler_https;
 /* Header specific functions */
 bool Curl_compareheader(const char *headerline,  /* line to check */
                         const char *header,   /* header keyword _with_ colon */
-                        const char *content); /* content string to find */
+                        const size_t hlen,   /* len of the keyword in bytes */
+                        const char *content, /* content string to find */
+                        const size_t clen);   /* len of the content in bytes */
 
 char *Curl_copy_header_value(const char *header);
 
 char *Curl_checkProxyheaders(struct Curl_easy *data,
                              const struct connectdata *conn,
-                             const char *thisheader);
+                             const char *thisheader,
+                             const size_t thislen);
 CURLcode Curl_buffer_send(struct dynbuf *in,
                           struct Curl_easy *data,
                           curl_off_t *bytes_written,
@@ -160,6 +167,29 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
 struct h3out; /* see ngtcp2 */
 #endif
 
+#ifdef USE_MSH3
+#ifdef _WIN32
+#define msh3_lock CRITICAL_SECTION
+#define msh3_lock_initialize(lock) InitializeCriticalSection(lock)
+#define msh3_lock_uninitialize(lock) DeleteCriticalSection(lock)
+#define msh3_lock_acquire(lock) EnterCriticalSection(lock)
+#define msh3_lock_release(lock) LeaveCriticalSection(lock)
+#else /* !_WIN32 */
+#include <pthread.h>
+#define msh3_lock pthread_mutex_t
+#define msh3_lock_initialize(lock) { \
+  pthread_mutexattr_t attr; \
+  pthread_mutexattr_init(&attr); \
+  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \
+  pthread_mutex_init(lock, &attr); \
+  pthread_mutexattr_destroy(&attr); \
+}
+#define msh3_lock_uninitialize(lock) pthread_mutex_destroy(lock)
+#define msh3_lock_acquire(lock) pthread_mutex_lock(lock)
+#define msh3_lock_release(lock) pthread_mutex_unlock(lock)
+#endif /* _WIN32 */
+#endif /* USE_MSH3 */
+
 /****************************************************************************
  * HTTP unique setup
  ***************************************************************************/
@@ -225,11 +255,13 @@ struct HTTP {
 #endif
 
 #ifdef ENABLE_QUIC
+#ifndef USE_MSH3
   /*********** for HTTP/3 we store stream-local data here *************/
   int64_t stream3_id; /* stream we are interested in */
   bool firstheader;  /* FALSE until headers arrive */
   bool firstbody;  /* FALSE until body arrives */
   bool h3req;    /* FALSE until request is issued */
+#endif
   bool upload_done;
 #endif
 #ifdef USE_NGHTTP3
@@ -237,6 +269,21 @@ struct HTTP {
   struct h3out *h3out; /* per-stream buffers for upload */
   struct dynbuf overflow; /* excess data received during a single Curl_read */
 #endif
+#ifdef USE_MSH3
+  struct MSH3_REQUEST *req;
+  msh3_lock recv_lock;
+  /* Receive Buffer (Headers and Data) */
+  uint8_t* recv_buf;
+  size_t recv_buf_alloc;
+  /* Receive Headers */
+  size_t recv_header_len;
+  bool recv_header_complete;
+  /* Receive Data */
+  size_t recv_data_len;
+  bool recv_data_complete;
+  /* General Receive Error */
+  CURLcode recv_error;
+#endif
 };
 
 #ifdef USE_NGHTTP2
@@ -317,4 +364,10 @@ Curl_http_output_auth(struct Curl_easy *data,
                       bool proxytunnel); /* TRUE if this is the request setting
                                             up the proxy tunnel */
 
+/*
+ * Curl_allow_auth_to_host() tells if authentication, cookies or other
+ * "sensitive data" can (still) be sent to this host.
+ */
+bool Curl_allow_auth_to_host(struct Curl_easy *data);
+
 #endif /* HEADER_CURL_HTTP_H */

+ 72 - 288
lib/http2.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -36,7 +36,10 @@
 #include "connect.h"
 #include "strtoofft.h"
 #include "strdup.h"
+#include "transfer.h"
 #include "dynbuf.h"
+#include "h2h3.h"
+#include "headers.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -64,7 +67,6 @@
 #define H2BUGF(x) do { } while(0)
 #endif
 
-
 static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
                           char *mem, size_t len, CURLcode *err);
 static bool http2_connisdead(struct Curl_easy *data,
@@ -200,9 +202,9 @@ static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
         nread = ((Curl_recv *)httpc->recv_underlying)(
           data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
       if(nread != -1) {
-        infof(data,
-              "%d bytes stray data read before trying h2 connection",
-              (int)nread);
+        H2BUGF(infof(data,
+                     "%d bytes stray data read before trying h2 connection",
+                     (int)nread));
         httpc->nread_inbuf = 0;
         httpc->inbuflen = nread;
         if(h2_process_pending_input(data, httpc, &result) < 0)
@@ -513,7 +515,7 @@ static int set_transfer_url(struct Curl_easy *data,
   if(!u)
     return 5;
 
-  v = curl_pushheader_byname(hp, ":scheme");
+  v = curl_pushheader_byname(hp, H2H3_PSEUDO_SCHEME);
   if(v) {
     uc = curl_url_set(u, CURLUPART_SCHEME, v, 0);
     if(uc) {
@@ -522,7 +524,7 @@ static int set_transfer_url(struct Curl_easy *data,
     }
   }
 
-  v = curl_pushheader_byname(hp, ":authority");
+  v = curl_pushheader_byname(hp, H2H3_PSEUDO_AUTHORITY);
   if(v) {
     uc = curl_url_set(u, CURLUPART_HOST, v, 0);
     if(uc) {
@@ -531,7 +533,7 @@ static int set_transfer_url(struct Curl_easy *data,
     }
   }
 
-  v = curl_pushheader_byname(hp, ":path");
+  v = curl_pushheader_byname(hp, H2H3_PSEUDO_PATH);
   if(v) {
     uc = curl_url_set(u, CURLUPART_PATH, v, 0);
     if(uc) {
@@ -560,7 +562,7 @@ static int push_promise(struct Curl_easy *data,
                         const nghttp2_push_promise *frame)
 {
   int rv; /* one of the CURL_PUSH_* defines */
-  H2BUGF(infof(data, "PUSH_PROMISE received, stream %u!",
+  H2BUGF(infof(data, "PUSH_PROMISE received, stream %u",
                frame->promised_stream_id));
   if(data->multi->push_cb) {
     struct HTTP *stream;
@@ -580,11 +582,11 @@ static int push_promise(struct Curl_easy *data,
     heads.data = data;
     heads.frame = frame;
     /* ask the application */
-    H2BUGF(infof(data, "Got PUSH_PROMISE, ask application!"));
+    H2BUGF(infof(data, "Got PUSH_PROMISE, ask application"));
 
     stream = data->req.p.http;
     if(!stream) {
-      failf(data, "Internal NULL stream!");
+      failf(data, "Internal NULL stream");
       (void)Curl_close(&newhandle);
       rv = CURL_PUSH_DENY;
       goto fail;
@@ -651,7 +653,7 @@ static int push_promise(struct Curl_easy *data,
     Curl_dyn_init(&newstream->trailer_recvbuf, DYN_H2_TRAILERS);
   }
   else {
-    H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it!"));
+    H2BUGF(infof(data, "Got PUSH_PROMISE, ignore it"));
     rv = CURL_PUSH_DENY;
   }
   fail:
@@ -757,7 +759,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
       stream->status_code = -1;
     }
 
-    result = Curl_dyn_add(&stream->header_recvbuf, "\r\n");
+    result = Curl_dyn_addn(&stream->header_recvbuf, STRCONST("\r\n"));
     if(result)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
 
@@ -800,7 +802,7 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
     }
     break;
   default:
-    H2BUGF(infof(data_s, "Got frame type %x for stream %u!",
+    H2BUGF(infof(data_s, "Got frame type %x for stream %u",
                  frame->hd.type, stream_id));
     break;
   }
@@ -823,10 +825,14 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
 
   /* get the stream from the hash based on Stream ID */
   data_s = nghttp2_session_get_stream_user_data(session, stream_id);
-  if(!data_s)
-    /* Receiving a Stream ID not in the hash should not happen, this is an
-       internal error more than anything else! */
-    return NGHTTP2_ERR_CALLBACK_FAILURE;
+  if(!data_s) {
+    /* Receiving a Stream ID not in the hash should not happen - unless
+       we have aborted a transfer artificially and there were more data
+       in the pipeline. Silently ignore. */
+    H2BUGF(fprintf(stderr, "Data for stream %u but it doesn't exist\n",
+                   stream_id));
+    return 0;
+  }
 
   stream = data_s->req.p.http;
   if(!stream)
@@ -907,15 +913,15 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
     /* remove the entry from the hash as the stream is now gone */
     rv = nghttp2_session_set_stream_user_data(session, stream_id, 0);
     if(rv) {
-      infof(data_s, "http/2: failed to clear user_data for stream %d!",
+      infof(data_s, "http/2: failed to clear user_data for stream %d",
             stream_id);
       DEBUGASSERT(0);
     }
     if(stream_id == httpc->pause_stream_id) {
-      H2BUGF(infof(data_s, "Stopped the pause stream!"));
+      H2BUGF(infof(data_s, "Stopped the pause stream"));
       httpc->pause_stream_id = 0;
     }
-    H2BUGF(infof(data_s, "Removed stream %u hash!", stream_id));
+    H2BUGF(infof(data_s, "Removed stream %u hash", stream_id));
     stream->stream_id = 0; /* cleared */
   }
   return 0;
@@ -1000,7 +1006,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
 
   stream = data_s->req.p.http;
   if(!stream) {
-    failf(data_s, "Internal NULL stream!");
+    failf(data_s, "Internal NULL stream");
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -1009,7 +1015,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
   if(frame->hd.type == NGHTTP2_PUSH_PROMISE) {
     char *h;
 
-    if(!strcmp(":authority", (const char *)name)) {
+    if(!strcmp(H2H3_PSEUDO_AUTHORITY, (const char *)name)) {
       /* pseudo headers are lower case */
       int rc = 0;
       char *check = aprintf("%s:%d", conn->host.name, conn->remote_port);
@@ -1072,22 +1078,27 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
     return 0;
   }
 
-  if(namelen == sizeof(":status") - 1 &&
-     memcmp(":status", name, namelen) == 0) {
+  if(namelen == sizeof(H2H3_PSEUDO_STATUS) - 1 &&
+     memcmp(H2H3_PSEUDO_STATUS, name, namelen) == 0) {
     /* nghttp2 guarantees :status is received first and only once, and
        value is 3 digits status code, and decode_status_code always
        succeeds. */
+    char buffer[32];
     stream->status_code = decode_status_code(value, valuelen);
     DEBUGASSERT(stream->status_code != -1);
-
-    result = Curl_dyn_add(&stream->header_recvbuf, "HTTP/2 ");
+    msnprintf(buffer, sizeof(buffer), H2H3_PSEUDO_STATUS ":%u\r",
+              stream->status_code);
+    result = Curl_headers_push(data_s, buffer, CURLH_PSEUDO);
+    if(result)
+      return NGHTTP2_ERR_CALLBACK_FAILURE;
+    result = Curl_dyn_addn(&stream->header_recvbuf, STRCONST("HTTP/2 "));
     if(result)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen);
     if(result)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     /* the space character after the status code is mandatory */
-    result = Curl_dyn_add(&stream->header_recvbuf, " \r\n");
+    result = Curl_dyn_addn(&stream->header_recvbuf, STRCONST(" \r\n"));
     if(result)
       return NGHTTP2_ERR_CALLBACK_FAILURE;
     /* if we receive data for another handle, wake that up */
@@ -1105,13 +1116,13 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
   result = Curl_dyn_addn(&stream->header_recvbuf, name, namelen);
   if(result)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
-  result = Curl_dyn_add(&stream->header_recvbuf, ": ");
+  result = Curl_dyn_addn(&stream->header_recvbuf, STRCONST(": "));
   if(result)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen);
   if(result)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
-  result = Curl_dyn_add(&stream->header_recvbuf, "\r\n");
+  result = Curl_dyn_addn(&stream->header_recvbuf, STRCONST("\r\n"));
   if(result)
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   /* if we receive data for another handle, wake that up */
@@ -1227,17 +1238,18 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
      !httpc->h2) /* not HTTP/2 ? */
     return;
 
-  if(premature) {
+  /* do this before the reset handling, as that might clear ->stream_id */
+  if(http->stream_id == httpc->pause_stream_id) {
+    H2BUGF(infof(data, "DONE the pause stream (%x)", http->stream_id));
+    httpc->pause_stream_id = 0;
+  }
+  if(premature || (!http->closed && http->stream_id)) {
     /* RST_STREAM */
     set_transfer(httpc, data); /* set the transfer */
+    H2BUGF(infof(data, "RST stream %x", http->stream_id));
     if(!nghttp2_submit_rst_stream(httpc->h2, NGHTTP2_FLAG_NONE,
                                   http->stream_id, NGHTTP2_STREAM_CLOSED))
       (void)nghttp2_session_send(httpc->h2);
-
-    if(http->stream_id == httpc->pause_stream_id) {
-      infof(data, "stopped the pause stream!");
-      httpc->pause_stream_id = 0;
-    }
   }
 
   if(data->state.drain)
@@ -1248,7 +1260,7 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
     int rv = nghttp2_session_set_stream_user_data(httpc->h2,
                                                   http->stream_id, 0);
     if(rv) {
-      infof(data, "http/2: failed to clear user_data for stream %d!",
+      infof(data, "http/2: failed to clear user_data for stream %d",
             http->stream_id);
       DEBUGASSERT(0);
     }
@@ -1273,7 +1285,7 @@ static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
     rc = nghttp2_session_callbacks_new(&callbacks);
 
     if(rc) {
-      failf(data, "Couldn't initialize nghttp2 callbacks!");
+      failf(data, "Couldn't initialize nghttp2 callbacks");
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
 
@@ -1302,7 +1314,7 @@ static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
     nghttp2_session_callbacks_del(callbacks);
 
     if(rc) {
-      failf(data, "Couldn't initialize nghttp2!");
+      failf(data, "Couldn't initialize nghttp2");
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
   }
@@ -1337,7 +1349,7 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
   }
   conn->proto.httpc.binlen = binlen;
 
-  result = Curl_base64url_encode(data, (const char *)binsettings, binlen,
+  result = Curl_base64url_encode((const char *)binsettings, binlen,
                                  &base64, &blen);
   if(result) {
     Curl_dyn_free(req);
@@ -1507,7 +1519,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
   /* Reset to FALSE to prevent infinite loop in readwrite_data function. */
   stream->closed = FALSE;
   if(stream->error == NGHTTP2_REFUSED_STREAM) {
-    H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection!",
+    H2BUGF(infof(data, "REFUSED_STREAM (%d), try again on a new connection",
                  stream->stream_id));
     connclose(conn, "REFUSED_STREAM"); /* don't use this anymore */
     data->state.refused_stream = TRUE;
@@ -1666,7 +1678,7 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
            ));
 
   if((data->state.drain) && stream->memlen) {
-    H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u!! (%p => %p)",
+    H2BUGF(infof(data, "http2_recv: DRAIN %zu bytes stream %u (%p => %p)",
                  stream->memlen, stream->stream_id,
                  stream->mem, mem));
     if(mem != stream->mem) {
@@ -1816,80 +1828,6 @@ static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
   return -1;
 }
 
-/* Index where :authority header field will appear in request header
-   field list. */
-#define AUTHORITY_DST_IDX 3
-
-/* USHRT_MAX is 65535 == 0xffff */
-#define HEADER_OVERFLOW(x) \
-  (x.namelen > 0xffff || x.valuelen > 0xffff - x.namelen)
-
-/*
- * Check header memory for the token "trailers".
- * Parse the tokens as separated by comma and surrounded by whitespace.
- * Returns TRUE if found or FALSE if not.
- */
-static bool contains_trailers(const char *p, size_t len)
-{
-  const char *end = p + len;
-  for(;;) {
-    for(; p != end && (*p == ' ' || *p == '\t'); ++p)
-      ;
-    if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
-      return FALSE;
-    if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
-      p += sizeof("trailers") - 1;
-      for(; p != end && (*p == ' ' || *p == '\t'); ++p)
-        ;
-      if(p == end || *p == ',')
-        return TRUE;
-    }
-    /* skip to next token */
-    for(; p != end && *p != ','; ++p)
-      ;
-    if(p == end)
-      return FALSE;
-    ++p;
-  }
-}
-
-typedef enum {
-  /* Send header to server */
-  HEADERINST_FORWARD,
-  /* Don't send header to server */
-  HEADERINST_IGNORE,
-  /* Discard header, and replace it with "te: trailers" */
-  HEADERINST_TE_TRAILERS
-} header_instruction;
-
-/* Decides how to treat given header field. */
-static header_instruction inspect_header(const char *name, size_t namelen,
-                                         const char *value, size_t valuelen) {
-  switch(namelen) {
-  case 2:
-    if(!strncasecompare("te", name, namelen))
-      return HEADERINST_FORWARD;
-
-    return contains_trailers(value, valuelen) ?
-           HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
-  case 7:
-    return strncasecompare("upgrade", name, namelen) ?
-           HEADERINST_IGNORE : HEADERINST_FORWARD;
-  case 10:
-    return (strncasecompare("connection", name, namelen) ||
-            strncasecompare("keep-alive", name, namelen)) ?
-           HEADERINST_IGNORE : HEADERINST_FORWARD;
-  case 16:
-    return strncasecompare("proxy-connection", name, namelen) ?
-           HEADERINST_IGNORE : HEADERINST_FORWARD;
-  case 17:
-    return strncasecompare("transfer-encoding", name, namelen) ?
-           HEADERINST_IGNORE : HEADERINST_FORWARD;
-  default:
-    return HEADERINST_FORWARD;
-  }
-}
-
 static ssize_t http2_send(struct Curl_easy *data, int sockindex,
                           const void *mem, size_t len, CURLcode *err)
 {
@@ -1904,14 +1842,12 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
   struct HTTP *stream = data->req.p.http;
   nghttp2_nv *nva = NULL;
   size_t nheader;
-  size_t i;
-  size_t authority_idx;
-  char *hdbuf = (char *)mem;
-  char *end, *line_end;
   nghttp2_data_provider data_prd;
   int32_t stream_id;
   nghttp2_session *h2 = httpc->h2;
   nghttp2_priority_spec pri_spec;
+  CURLcode result;
+  struct h2h3req *hreq;
 
   (void)sockindex;
 
@@ -1977,174 +1913,29 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
     return len;
   }
 
-  /* Calculate number of headers contained in [mem, mem + len) */
-  /* Here, we assume the curl http code generate *correct* HTTP header
-     field block */
-  nheader = 0;
-  for(i = 1; i < len; ++i) {
-    if(hdbuf[i] == '\n' && hdbuf[i - 1] == '\r') {
-      ++nheader;
-      ++i;
-    }
+  result = Curl_pseudo_headers(data, mem, len, &hreq);
+  if(result) {
+    *err = result;
+    return -1;
   }
-  if(nheader < 2)
-    goto fail;
+  nheader = hreq->entries;
 
-  /* We counted additional 2 \r\n in the first and last line. We need 3
-     new headers: :method, :path and :scheme. Therefore we need one
-     more space. */
-  nheader += 1;
   nva = malloc(sizeof(nghttp2_nv) * nheader);
   if(!nva) {
+    Curl_pseudo_free(hreq);
     *err = CURLE_OUT_OF_MEMORY;
     return -1;
   }
-
-  /* Extract :method, :path from request line
-     We do line endings with CRLF so checking for CR is enough */
-  line_end = memchr(hdbuf, '\r', len);
-  if(!line_end)
-    goto fail;
-
-  /* Method does not contain spaces */
-  end = memchr(hdbuf, ' ', line_end - hdbuf);
-  if(!end || end == hdbuf)
-    goto fail;
-  nva[0].name = (unsigned char *)":method";
-  nva[0].namelen = strlen((char *)nva[0].name);
-  nva[0].value = (unsigned char *)hdbuf;
-  nva[0].valuelen = (size_t)(end - hdbuf);
-  nva[0].flags = NGHTTP2_NV_FLAG_NONE;
-  if(HEADER_OVERFLOW(nva[0])) {
-    failf(data, "Failed sending HTTP request: Header overflow");
-    goto fail;
-  }
-
-  hdbuf = end + 1;
-
-  /* Path may contain spaces so scan backwards */
-  end = NULL;
-  for(i = (size_t)(line_end - hdbuf); i; --i) {
-    if(hdbuf[i - 1] == ' ') {
-      end = &hdbuf[i - 1];
-      break;
-    }
-  }
-  if(!end || end == hdbuf)
-    goto fail;
-  nva[1].name = (unsigned char *)":path";
-  nva[1].namelen = strlen((char *)nva[1].name);
-  nva[1].value = (unsigned char *)hdbuf;
-  nva[1].valuelen = (size_t)(end - hdbuf);
-  nva[1].flags = NGHTTP2_NV_FLAG_NONE;
-  if(HEADER_OVERFLOW(nva[1])) {
-    failf(data, "Failed sending HTTP request: Header overflow");
-    goto fail;
-  }
-
-  nva[2].name = (unsigned char *)":scheme";
-  nva[2].namelen = strlen((char *)nva[2].name);
-  if(conn->handler->flags & PROTOPT_SSL)
-    nva[2].value = (unsigned char *)"https";
-  else
-    nva[2].value = (unsigned char *)"http";
-  nva[2].valuelen = strlen((char *)nva[2].value);
-  nva[2].flags = NGHTTP2_NV_FLAG_NONE;
-  if(HEADER_OVERFLOW(nva[2])) {
-    failf(data, "Failed sending HTTP request: Header overflow");
-    goto fail;
-  }
-
-  authority_idx = 0;
-  i = 3;
-  while(i < nheader) {
-    size_t hlen;
-
-    hdbuf = line_end + 2;
-
-    /* check for next CR, but only within the piece of data left in the given
-       buffer */
-    line_end = memchr(hdbuf, '\r', len - (hdbuf - (char *)mem));
-    if(!line_end || (line_end == hdbuf))
-      goto fail;
-
-    /* header continuation lines are not supported */
-    if(*hdbuf == ' ' || *hdbuf == '\t')
-      goto fail;
-
-    for(end = hdbuf; end < line_end && *end != ':'; ++end)
-      ;
-    if(end == hdbuf || end == line_end)
-      goto fail;
-    hlen = end - hdbuf;
-
-    if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
-      authority_idx = i;
-      nva[i].name = (unsigned char *)":authority";
-      nva[i].namelen = strlen((char *)nva[i].name);
-    }
-    else {
-      nva[i].namelen = (size_t)(end - hdbuf);
-      /* Lower case the header name for HTTP/2 */
-      Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen);
-      nva[i].name = (unsigned char *)hdbuf;
-    }
-    hdbuf = end + 1;
-    while(*hdbuf == ' ' || *hdbuf == '\t')
-      ++hdbuf;
-    end = line_end;
-
-    switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
-                          end - hdbuf)) {
-    case HEADERINST_IGNORE:
-      /* skip header fields prohibited by HTTP/2 specification. */
-      --nheader;
-      continue;
-    case HEADERINST_TE_TRAILERS:
-      nva[i].value = (uint8_t*)"trailers";
-      nva[i].valuelen = sizeof("trailers") - 1;
-      break;
-    default:
-      nva[i].value = (unsigned char *)hdbuf;
-      nva[i].valuelen = (size_t)(end - hdbuf);
-    }
-
-    nva[i].flags = NGHTTP2_NV_FLAG_NONE;
-    if(HEADER_OVERFLOW(nva[i])) {
-      failf(data, "Failed sending HTTP request: Header overflow");
-      goto fail;
-    }
-    ++i;
-  }
-
-  /* :authority must come before non-pseudo header fields */
-  if(authority_idx && authority_idx != AUTHORITY_DST_IDX) {
-    nghttp2_nv authority = nva[authority_idx];
-    for(i = authority_idx; i > AUTHORITY_DST_IDX; --i) {
-      nva[i] = nva[i - 1];
-    }
-    nva[i] = authority;
-  }
-
-  /* Warn stream may be rejected if cumulative length of headers is too large.
-     It appears nghttp2 will not send a header frame larger than 64KB. */
-#define MAX_ACC 60000  /* <64KB to account for some overhead */
-  {
-    size_t acc = 0;
-
-    for(i = 0; i < nheader; ++i) {
-      acc += nva[i].namelen + nva[i].valuelen;
-
-      H2BUGF(infof(data, "h2 header: %.*s:%.*s",
-                   nva[i].namelen, nva[i].name,
-                   nva[i].valuelen, nva[i].value));
-    }
-
-    if(acc > MAX_ACC) {
-      infof(data, "http2_send: Warning: The cumulative length of all "
-            "headers exceeds %d bytes and that could cause the "
-            "stream to be rejected.", MAX_ACC);
+  else {
+    unsigned int i;
+    for(i = 0; i < nheader; i++) {
+      nva[i].name = (unsigned char *)hreq->header[i].name;
+      nva[i].namelen = hreq->header[i].namelen;
+      nva[i].value = (unsigned char *)hreq->header[i].value;
+      nva[i].valuelen = hreq->header[i].valuelen;
+      nva[i].flags = NGHTTP2_NV_FLAG_NONE;
     }
+    Curl_pseudo_free(hreq);
   }
 
   h2_pri_spec(data, &pri_spec);
@@ -2213,11 +2004,6 @@ static ssize_t http2_send(struct Curl_easy *data, int sockindex,
   nghttp2_session_resume_data(h2, stream->stream_id);
 
   return len;
-
-fail:
-  free(nva);
-  *err = CURLE_SEND_ERROR;
-  return -1;
 }
 
 CURLcode Curl_http2_setup(struct Curl_easy *data,
@@ -2271,8 +2057,6 @@ CURLcode Curl_http2_setup(struct Curl_easy *data,
   httpc->pause_stream_id = 0;
   httpc->drain_total = 0;
 
-  infof(data, "Connection state changed (HTTP/2 confirmed)");
-
   return CURLE_OK;
 }
 
@@ -2310,7 +2094,7 @@ CURLcode Curl_http2_switched(struct Curl_easy *data,
                                               stream->stream_id,
                                               data);
     if(rv) {
-      infof(data, "http/2: failed to set user_data for stream %d!",
+      infof(data, "http/2: failed to set user_data for stream %d",
             stream->stream_id);
       DEBUGASSERT(0);
     }

+ 3 - 3
lib/http_aws_sigv4.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -87,7 +87,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   struct tm tm;
   char timestamp[17];
   char date[9];
-  const char *content_type = Curl_checkheaders(data, "Content-Type");
+  const char *content_type = Curl_checkheaders(data, STRCONST("Content-Type"));
   char *canonical_headers = NULL;
   char *signed_headers = NULL;
   Curl_HttpReq httpreq;
@@ -110,7 +110,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
   DEBUGASSERT(!proxy);
   (void)proxy;
 
-  if(Curl_checkheaders(data, "Authorization")) {
+  if(Curl_checkheaders(data, STRCONST("Authorization"))) {
     /* Authorization already present, Bailing out */
     return CURLE_OK;
   }

+ 5 - 30
lib/http_chunks.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -29,7 +29,6 @@
 #include "dynbuf.h"
 #include "content_encoding.h"
 #include "http.h"
-#include "non-ascii.h" /* for Curl_convert_to_network prototype */
 #include "strtoofft.h"
 #include "warnless.h"
 
@@ -74,18 +73,7 @@
 
  */
 
-#ifdef CURL_DOES_CONVERSIONS
-/* Check for an ASCII hex digit.
-   We avoid the use of ISXDIGIT to accommodate non-ASCII hosts. */
-static bool isxdigit_ascii(char digit)
-{
-  return (digit >= 0x30 && digit <= 0x39) /* 0-9 */
-    || (digit >= 0x41 && digit <= 0x46) /* A-F */
-    || (digit >= 0x61 && digit <= 0x66); /* a-f */
-}
-#else
 #define isxdigit_ascii(x) Curl_isxdigit(x)
-#endif
 
 void Curl_httpchunk_init(struct Curl_easy *data)
 {
@@ -157,14 +145,6 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
         /* length and datap are unmodified */
         ch->hexbuffer[ch->hexindex] = 0;
 
-        /* convert to host encoding before calling strtoul */
-        result = Curl_convert_from_network(data, ch->hexbuffer, ch->hexindex);
-        if(result) {
-          /* Curl_convert_from_network calls failf if unsuccessful */
-          /* Treat it as a bad hex character */
-          return CHUNKE_ILLEGAL_HEX;
-        }
-
         if(curlx_strtoofft(ch->hexbuffer, &endptr, 16, &ch->datasize))
           return CHUNKE_ILLEGAL_HEX;
         ch->state = CHUNK_LF; /* now wait for the CRLF */
@@ -234,21 +214,16 @@ CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
 
         if(tr) {
           size_t trlen;
-          result = Curl_dyn_add(&conn->trailer, (char *)"\x0d\x0a");
+          result = Curl_dyn_addn(&conn->trailer, (char *)STRCONST("\x0d\x0a"));
           if(result)
             return CHUNKE_OUT_OF_MEMORY;
 
           tr = Curl_dyn_ptr(&conn->trailer);
           trlen = Curl_dyn_len(&conn->trailer);
-          /* Convert to host encoding before calling Curl_client_write */
-          result = Curl_convert_from_network(data, tr, trlen);
-          if(result)
-            /* Curl_convert_from_network calls failf if unsuccessful */
-            /* Treat it as a bad chunk */
-            return CHUNKE_BAD_CHUNK;
-
           if(!data->set.http_te_skip) {
-            result = Curl_client_write(data, CLIENTWRITE_HEADER, tr, trlen);
+            result = Curl_client_write(data,
+                                       CLIENTWRITE_HEADER|CLIENTWRITE_TRAILER,
+                                       tr, trlen);
             if(result) {
               *extrap = result;
               return CHUNKE_PASSTHRU_ERROR;

+ 2 - 2
lib/http_negotiate.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -161,7 +161,7 @@ CURLcode Curl_output_negotiate(struct Curl_easy *data,
         return result;
     }
 
-    result = Curl_auth_create_spnego_message(data, neg_ctx, &base64, &len);
+    result = Curl_auth_create_spnego_message(neg_ctx, &base64, &len);
     if(result)
       return result;
 

+ 3 - 5
lib/http_ntlm.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -213,8 +213,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
                                                  ntlm, &ntlmmsg);
     if(!result) {
       DEBUGASSERT(Curl_bufref_len(&ntlmmsg) != 0);
-      result = Curl_base64_encode(data,
-                                  (const char *) Curl_bufref_ptr(&ntlmmsg),
+      result = Curl_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
                                   Curl_bufref_len(&ntlmmsg), &base64, &len);
       if(!result) {
         free(*allocuserpwd);
@@ -233,8 +232,7 @@ CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
     result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
                                                  ntlm, &ntlmmsg);
     if(!result && Curl_bufref_len(&ntlmmsg)) {
-      result = Curl_base64_encode(data,
-                                  (const char *) Curl_bufref_ptr(&ntlmmsg),
+      result = Curl_base64_encode((const char *) Curl_bufref_ptr(&ntlmmsg),
                                   Curl_bufref_len(&ntlmmsg), &base64, &len);
       if(!result) {
         free(*allocuserpwd);

+ 29 - 24
lib/http_proxy.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -35,7 +35,6 @@
 #include "url.h"
 #include "select.h"
 #include "progress.h"
-#include "non-ascii.h"
 #include "connect.h"
 #include "curlx.h"
 #include "vtls/vtls.h"
@@ -173,7 +172,7 @@ static CURLcode connect_init(struct Curl_easy *data, bool reinit)
     s = calloc(1, sizeof(struct http_connect_state));
     if(!s)
       return CURLE_OUT_OF_MEMORY;
-    infof(data, "allocate connect buffer!");
+    infof(data, "allocate connect buffer");
     conn->connect_state = s;
     Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
 
@@ -221,7 +220,7 @@ void Curl_connect_done(struct Curl_easy *data)
 #ifdef USE_HYPER
     data->state.hconnect = FALSE;
 #endif
-    infof(data, "CONNECT phase completed!");
+    infof(data, "CONNECT phase completed");
   }
 }
 
@@ -245,7 +244,7 @@ static CURLcode CONNECT_host(struct Curl_easy *data,
   if(!hostheader)
     return CURLE_OUT_OF_MEMORY;
 
-  if(!Curl_checkProxyheaders(data, conn, "Host")) {
+  if(!Curl_checkProxyheaders(data, conn, STRCONST("Host"))) {
     host = aprintf("Host: %s\r\n", hostheader);
     if(!host) {
       free(hostheader);
@@ -324,25 +323,29 @@ static CURLcode CONNECT(struct Curl_easy *data,
                         data->state.aptr.proxyuserpwd?
                         data->state.aptr.proxyuserpwd:"");
 
-        if(!result && !Curl_checkProxyheaders(data, conn, "User-Agent") &&
+        if(!result && !Curl_checkProxyheaders(data,
+                                              conn, STRCONST("User-Agent")) &&
            data->set.str[STRING_USERAGENT])
           result = Curl_dyn_addf(req, "User-Agent: %s\r\n",
                                  data->set.str[STRING_USERAGENT]);
 
-        if(!result && !Curl_checkProxyheaders(data, conn, "Proxy-Connection"))
-          result = Curl_dyn_add(req, "Proxy-Connection: Keep-Alive\r\n");
+        if(!result && !Curl_checkProxyheaders(data, conn,
+                                              STRCONST("Proxy-Connection")))
+          result = Curl_dyn_addn(req,
+                                 STRCONST("Proxy-Connection: Keep-Alive\r\n"));
 
         if(!result)
           result = Curl_add_custom_headers(data, TRUE, req);
 
         if(!result)
           /* CRLF terminate the request */
-          result = Curl_dyn_add(req, "\r\n");
+          result = Curl_dyn_addn(req, STRCONST("\r\n"));
 
         if(!result) {
           /* Send the connect request to the proxy */
           result = Curl_buffer_send(req, data, &data->info.request_size, 0,
                                     sockindex);
+          s->headerlines = 0;
         }
         if(result)
           failf(data, "Failed sending CONNECT to proxy");
@@ -470,7 +473,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
         }
 
         if(Curl_dyn_addn(&s->rcvbuf, &byte, 1)) {
-          failf(data, "CONNECT response too large!");
+          failf(data, "CONNECT response too large");
           return CURLE_RECV_ERROR;
         }
 
@@ -478,23 +481,18 @@ static CURLcode CONNECT(struct Curl_easy *data,
         if(byte != 0x0a)
           continue;
 
+        s->headerlines++;
         linep = Curl_dyn_ptr(&s->rcvbuf);
         perline = Curl_dyn_len(&s->rcvbuf); /* amount of bytes in this line */
 
-        /* convert from the network encoding */
-        result = Curl_convert_from_network(data, linep, perline);
-        /* Curl_convert_from_network calls failf if unsuccessful */
-        if(result)
-          return result;
-
         /* output debug if that is requested */
         Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
 
         if(!data->set.suppress_connect_headers) {
           /* send the header to the callback */
-          int writetype = CLIENTWRITE_HEADER;
-          if(data->set.include_header)
-            writetype |= CLIENTWRITE_BODY;
+          int writetype = CLIENTWRITE_HEADER | CLIENTWRITE_CONNECT |
+            (data->set.include_header ? CLIENTWRITE_BODY : 0) |
+            (s->headerlines == 1 ? CLIENTWRITE_STATUS : 0);
 
           result = Curl_client_write(data, writetype, linep, perline);
           if(result)
@@ -596,7 +594,8 @@ static CURLcode CONNECT(struct Curl_easy *data,
                                   strlen("Content-Length:"), NULL, 10, &s->cl);
           }
         }
-        else if(Curl_compareheader(linep, "Connection:", "close"))
+        else if(Curl_compareheader(linep,
+                                   STRCONST("Connection:"), STRCONST("close")))
           s->close_connection = TRUE;
         else if(checkprefix("Transfer-Encoding:", linep)) {
           if(k->httpcode/100 == 2) {
@@ -607,14 +606,17 @@ static CURLcode CONNECT(struct Curl_easy *data,
                   "CONNECT %03d response", k->httpcode);
           }
           else if(Curl_compareheader(linep,
-                                     "Transfer-Encoding:", "chunked")) {
+                                     STRCONST("Transfer-Encoding:"),
+                                     STRCONST("chunked"))) {
             infof(data, "CONNECT responded chunked");
             s->chunked_encoding = TRUE;
             /* init our chunky engine */
             Curl_httpchunk_init(data);
           }
         }
-        else if(Curl_compareheader(linep, "Proxy-Connection:", "close"))
+        else if(Curl_compareheader(linep,
+                                   STRCONST("Proxy-Connection:"),
+                                   STRCONST("close")))
           s->close_connection = TRUE;
         else if(2 == sscanf(linep, "HTTP/1.%d %d",
                             &subversion,
@@ -765,6 +767,9 @@ static CURLcode CONNECT(struct Curl_easy *data,
       }
 
       options = hyper_clientconn_options_new();
+      hyper_clientconn_options_set_preserve_header_case(options, 1);
+      hyper_clientconn_options_set_preserve_header_order(options, 1);
+
       if(!options) {
         failf(data, "Couldn't create hyper client options");
         result = CURLE_OUT_OF_MEMORY;
@@ -877,7 +882,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
           goto error;
       }
 
-      if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
+      if(!Curl_checkProxyheaders(data, conn, STRCONST("User-Agent")) &&
          data->set.str[STRING_USERAGENT]) {
         struct dynbuf ua;
         Curl_dyn_init(&ua, DYN_HTTP_REQUEST);
@@ -891,7 +896,7 @@ static CURLcode CONNECT(struct Curl_easy *data,
         Curl_dyn_free(&ua);
       }
 
-      if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
+      if(!Curl_checkProxyheaders(data, conn, STRCONST("Proxy-Connection"))) {
         result = Curl_hyper_header(data, headers,
                                    "Proxy-Connection: Keep-Alive");
         if(result)

+ 2 - 1
lib/http_proxy.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -59,6 +59,7 @@ struct http_connect_state {
   struct dynbuf rcvbuf;
   struct dynbuf req;
   size_t nsend;
+  size_t headerlines;
   enum keeponval {
     KEEPON_DONE,
     KEEPON_CONNECT,

+ 17 - 9
lib/idn_win32.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -76,11 +76,15 @@ bool curl_win32_idn_to_ascii(const char *in, char **out)
   if(in_w) {
     wchar_t punycode[IDN_MAX_LENGTH];
     int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
-    free(in_w);
+    curlx_unicodefree(in_w);
     if(chars) {
-      *out = curlx_convert_wchar_to_UTF8(punycode);
-      if(*out)
-        success = TRUE;
+      char *mstr = curlx_convert_wchar_to_UTF8(punycode);
+      if(mstr) {
+        *out = strdup(mstr);
+        curlx_unicodefree(mstr);
+        if(*out)
+          success = TRUE;
+      }
     }
   }
 
@@ -97,11 +101,15 @@ bool curl_win32_ascii_to_idn(const char *in, char **out)
     wchar_t unicode[IDN_MAX_LENGTH];
     int chars = IdnToUnicode(0, in_w, curlx_uztosi(in_len),
                              unicode, IDN_MAX_LENGTH);
-    free(in_w);
+    curlx_unicodefree(in_w);
     if(chars) {
-      *out = curlx_convert_wchar_to_UTF8(unicode);
-      if(*out)
-        success = TRUE;
+      char *mstr = curlx_convert_wchar_to_UTF8(unicode);
+      if(mstr) {
+        *out = strdup(mstr);
+        curlx_unicodefree(mstr);
+        if(*out)
+          success = TRUE;
+      }
     }
   }
 

+ 27 - 19
lib/if2ip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -60,12 +60,10 @@
 
 /* ------------------------------------------------------------------ */
 
+#ifdef ENABLE_IPV6
 /* Return the scope of the given address. */
 unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
 {
-#ifndef ENABLE_IPV6
-  (void) sa;
-#else
   if(sa->sa_family == AF_INET6) {
     const struct sockaddr_in6 * sa6 = (const struct sockaddr_in6 *)(void *) sa;
     const unsigned char *b = sa6->sin6_addr.s6_addr;
@@ -88,27 +86,25 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
       break;
     }
   }
-#endif
-
   return IPV6_SCOPE_GLOBAL;
 }
-
+#endif
 
 #if defined(HAVE_GETIFADDRS)
 
-if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
-                          unsigned int local_scope_id, const char *interf,
+if2ip_result_t Curl_if2ip(int af,
+#ifdef ENABLE_IPV6
+                          unsigned int remote_scope,
+                          unsigned int local_scope_id,
+#endif
+                          const char *interf,
                           char *buf, int buf_size)
 {
   struct ifaddrs *iface, *head;
   if2ip_result_t res = IF2IP_NOT_FOUND;
 
-#ifndef ENABLE_IPV6
-  (void) remote_scope;
-#endif
-
-#if !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) || \
-    !defined(ENABLE_IPV6)
+#if defined(ENABLE_IPV6) && \
+    !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
   (void) local_scope_id;
 #endif
 
@@ -181,8 +177,12 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
 
 #elif defined(HAVE_IOCTL_SIOCGIFADDR)
 
-if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
-                          unsigned int local_scope_id, const char *interf,
+if2ip_result_t Curl_if2ip(int af,
+#ifdef ENABLE_IPV6
+                          unsigned int remote_scope,
+                          unsigned int local_scope_id,
+#endif
+                          const char *interf,
                           char *buf, int buf_size)
 {
   struct ifreq req;
@@ -192,8 +192,10 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
   size_t len;
   const char *r;
 
+#ifdef ENABLE_IPV6
   (void)remote_scope;
   (void)local_scope_id;
+#endif
 
   if(!interf || (af != AF_INET))
     return IF2IP_NOT_FOUND;
@@ -230,13 +232,19 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
 
 #else
 
-if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
-                          unsigned int local_scope_id, const char *interf,
+if2ip_result_t Curl_if2ip(int af,
+#ifdef ENABLE_IPV6
+                          unsigned int remote_scope,
+                          unsigned int local_scope_id,
+#endif
+                          const char *interf,
                           char *buf, int buf_size)
 {
     (void) af;
+#ifdef ENABLE_IPV6
     (void) remote_scope;
     (void) local_scope_id;
+#endif
     (void) interf;
     (void) buf;
     (void) buf_size;

+ 11 - 3
lib/if2ip.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2020, 2022, 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
@@ -30,7 +30,11 @@
 #define IPV6_SCOPE_UNIQUELOCAL  3       /* Unique local */
 #define IPV6_SCOPE_NODELOCAL    4       /* Loopback. */
 
+#ifdef ENABLE_IPV6
 unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
+#else
+#define Curl_ipv6_scope(x) 0
+#endif
 
 typedef enum {
   IF2IP_NOT_FOUND = 0, /* Interface not found */
@@ -38,8 +42,12 @@ typedef enum {
   IF2IP_FOUND = 2 /* The address has been stored in "buf" */
 } if2ip_result_t;
 
-if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
-                          unsigned int local_scope_id, const char *interf,
+if2ip_result_t Curl_if2ip(int af,
+#ifdef ENABLE_IPV6
+                          unsigned int remote_scope,
+                          unsigned int local_scope_id,
+#endif
+                          const char *interf,
                           char *buf, int buf_size);
 
 #ifdef __INTERIX

+ 10 - 10
lib/imap.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -507,7 +507,7 @@ static CURLcode imap_perform_login(struct Curl_easy *data,
 
   /* Check we have a username and password to authenticate with and end the
      connect phase if we don't */
-  if(!conn->bits.user_passwd) {
+  if(!data->state.aptr.user) {
     state(data, IMAP_STOP);
 
     return result;
@@ -608,7 +608,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
   /* Check if already authenticated OR if there is enough data to authenticate
      with and end the connect phase if we don't */
   if(imapc->preauth ||
-     !Curl_sasl_can_authenticate(&imapc->sasl, conn)) {
+     !Curl_sasl_can_authenticate(&imapc->sasl, data)) {
     state(data, IMAP_STOP);
     return result;
   }
@@ -624,7 +624,7 @@ static CURLcode imap_perform_authentication(struct Curl_easy *data,
       result = imap_perform_login(data, conn);
     else {
       /* Other mechanisms not supported */
-      infof(data, "No known authentication mechanisms supported!");
+      infof(data, "No known authentication mechanisms supported");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -777,7 +777,7 @@ static CURLcode imap_perform_append(struct Curl_easy *data)
                                        NULL, MIMESTRATEGY_MAIL);
 
     if(!result)
-      if(!Curl_checkheaders(data, "Mime-Version"))
+      if(!Curl_checkheaders(data, STRCONST("Mime-Version")))
         result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
                                       "Mime-Version: 1.0");
 
@@ -874,7 +874,7 @@ static CURLcode imap_state_servergreet_resp(struct Curl_easy *data,
     /* PREAUTH */
     struct imap_conn *imapc = &conn->proto.imapc;
     imapc->preauth = TRUE;
-    infof(data, "PREAUTH connection, already authenticated!");
+    infof(data, "PREAUTH connection, already authenticated");
   }
   else if(imapcode != IMAP_RESP_OK) {
     failf(data, "Got unexpected imap-server response");
@@ -1986,7 +1986,7 @@ static CURLcode imap_parse_url_path(struct Curl_easy *data)
     if(end > begin && end[-1] == '/')
       end--;
 
-    result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL,
+    result = Curl_urldecode(begin, end - begin, &imap->mailbox, NULL,
                             REJECT_CTRL);
     if(result)
       return result;
@@ -2009,7 +2009,7 @@ static CURLcode imap_parse_url_path(struct Curl_easy *data)
       return CURLE_URL_MALFORMAT;
 
     /* Decode the name parameter */
-    result = Curl_urldecode(data, begin, ptr - begin, &name, NULL,
+    result = Curl_urldecode(begin, ptr - begin, &name, NULL,
                             REJECT_CTRL);
     if(result)
       return result;
@@ -2020,7 +2020,7 @@ static CURLcode imap_parse_url_path(struct Curl_easy *data)
       ptr++;
 
     /* Decode the value parameter */
-    result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen,
+    result = Curl_urldecode(begin, ptr - begin, &value, &valuelen,
                             REJECT_CTRL);
     if(result) {
       free(name);
@@ -2108,7 +2108,7 @@ static CURLcode imap_parse_custom_request(struct Curl_easy *data)
 
   if(custom) {
     /* URL decode the custom request */
-    result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, REJECT_CTRL);
+    result = Curl_urldecode(custom, 0, &imap->custom, NULL, REJECT_CTRL);
 
     /* Extract the parameters if specified */
     if(!result) {

+ 3 - 9
lib/krb5.c

@@ -2,7 +2,7 @@
  *
  * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Högskolan
  * (Royal Institute of Technology, Stockholm, Sweden).
- * Copyright (c) 2004 - 2021 Daniel Stenberg
+ * Copyright (c) 2004 - 2022 Daniel Stenberg
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,6 @@
 #include "sendf.h"
 #include "curl_krb5.h"
 #include "warnless.h"
-#include "non-ascii.h"
 #include "strcase.h"
 #include "strdup.h"
 
@@ -81,11 +80,6 @@ static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
   write_len += 2;
   bytes_written = 0;
 
-  result = Curl_convert_to_network(data, s, write_len);
-  /* Curl_convert_to_network calls failf if unsuccessful */
-  if(result)
-    return result;
-
   for(;;) {
 #ifdef HAVE_GSSAPI
     conn->data_prot = PROT_CMD;
@@ -298,7 +292,7 @@ krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
       if(output_buffer.length) {
         char *cmd;
 
-        result = Curl_base64_encode(data, (char *)output_buffer.value,
+        result = Curl_base64_encode((char *)output_buffer.value,
                                     output_buffer.length, &p, &base64_sz);
         if(result) {
           infof(data, "base64-encoding: %s", curl_easy_strerror(result));
@@ -612,7 +606,7 @@ static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
     return; /* error */
 
   if(iscmd) {
-    error = Curl_base64_encode(data, buffer, curlx_sitouz(bytes),
+    error = Curl_base64_encode(buffer, curlx_sitouz(bytes),
                                &cmd_buffer, &cmd_size);
     if(error) {
       free(buffer);

+ 12 - 15
lib/ldap.c

@@ -5,7 +5,7 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -306,8 +306,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
   rc = _ldap_url_parse(data, conn, &ludp);
 #endif
   if(rc) {
-    failf(data, "LDAP local: %s", ldap_err2string(rc));
-    result = CURLE_LDAP_INVALID_URL;
+    failf(data, "Bad LDAP URL: %s", ldap_err2string(rc));
+    result = CURLE_URL_MALFORMAT;
     goto quit;
   }
 
@@ -328,7 +328,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
   host = conn->host.name;
 #endif
 
-  if(conn->bits.user_passwd) {
+  if(data->state.aptr.user) {
     user = conn->user;
     passwd = conn->passwd;
   }
@@ -361,7 +361,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
          (strcasecompare(data->set.ssl.cert_type, "DER")))
         cert_type = LDAPSSL_CERT_FILETYPE_DER;
       if(!ldap_ca) {
-        failf(data, "LDAP local: ERROR %s CA cert not set!",
+        failf(data, "LDAP local: ERROR %s CA cert not set",
               (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
         result = CURLE_SSL_CERTPROBLEM;
         goto quit;
@@ -400,12 +400,12 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
       /* OpenLDAP SDK supports BASE64 files. */
       if((data->set.ssl.cert_type) &&
          (!strcasecompare(data->set.ssl.cert_type, "PEM"))) {
-        failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!");
+        failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type");
         result = CURLE_SSL_CERTPROBLEM;
         goto quit;
       }
       if(!ldap_ca) {
-        failf(data, "LDAP local: ERROR PEM CA cert not set!");
+        failf(data, "LDAP local: ERROR PEM CA cert not set");
         result = CURLE_SSL_CERTPROBLEM;
         goto quit;
       }
@@ -636,11 +636,8 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done)
           if((attr_len > 7) &&
              (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) {
             /* Binary attribute, encode to base64. */
-            result = Curl_base64_encode(data,
-                                        vals[i]->bv_val,
-                                        vals[i]->bv_len,
-                                        &val_b64,
-                                        &val_b64_sz);
+            result = Curl_base64_encode(vals[i]->bv_val, vals[i]->bv_len,
+                                        &val_b64, &val_b64_sz);
             if(result) {
               ldap_value_free_len(vals);
               FREE_ON_WINLDAP(attr);
@@ -870,7 +867,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
     LDAP_TRACE(("DN '%s'\n", dn));
 
     /* Unescape the DN */
-    result = Curl_urldecode(data, dn, 0, &unescaped, NULL, REJECT_ZERO);
+    result = Curl_urldecode(dn, 0, &unescaped, NULL, REJECT_ZERO);
     if(result) {
       rc = LDAP_NO_MEMORY;
 
@@ -935,7 +932,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
       LDAP_TRACE(("attr[%zu] '%s'\n", i, attributes[i]));
 
       /* Unescape the attribute */
-      result = Curl_urldecode(data, attributes[i], 0, &unescaped, NULL,
+      result = Curl_urldecode(attributes[i], 0, &unescaped, NULL,
                               REJECT_ZERO);
       if(result) {
         free(attributes);
@@ -1005,7 +1002,7 @@ static int _ldap_url_parse2(struct Curl_easy *data,
     LDAP_TRACE(("filter '%s'\n", filter));
 
     /* Unescape the filter */
-    result = Curl_urldecode(data, filter, 0, &unescaped, NULL, REJECT_ZERO);
+    result = Curl_urldecode(filter, 0, &unescaped, NULL, REJECT_ZERO);
     if(result) {
       rc = LDAP_NO_MEMORY;
 

+ 102 - 56
lib/md5.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -60,22 +60,22 @@
 /* The last #include file should be: */
 #include "memdebug.h"
 
-typedef struct md5_ctx MD5_CTX;
+typedef struct md5_ctx my_md5_ctx;
 
-static CURLcode MD5_Init(MD5_CTX *ctx)
+static CURLcode my_md5_init(my_md5_ctx *ctx)
 {
   md5_init(ctx);
   return CURLE_OK;
 }
 
-static void MD5_Update(MD5_CTX *ctx,
-                       const unsigned char *input,
-                       unsigned int inputLen)
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *input,
+                          unsigned int inputLen)
 {
   md5_update(ctx, inputLen, input);
 }
 
-static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
 {
   md5_digest(ctx, 16, digest);
 }
@@ -83,11 +83,38 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
 #elif defined(USE_OPENSSL_MD5) || defined(USE_WOLFSSL_MD5)
 
 /* When OpenSSL or wolfSSL is available, we use their MD5 functions. */
+#if defined(USE_OPENSSL_MD5)
 #include <openssl/md5.h>
+#elif defined(USE_WOLFSSL_MD5)
+#include <wolfssl/openssl/md5.h>
+#endif
+
 #include "curl_memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
+typedef MD5_CTX my_md5_ctx;
+
+static CURLcode my_md5_init(my_md5_ctx *ctx)
+{
+  if(!MD5_Init(ctx))
+    return CURLE_OUT_OF_MEMORY;
+
+  return CURLE_OK;
+}
+
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *input,
+                          unsigned int len)
+{
+  (void)MD5_Update(ctx, input, len);
+}
+
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
+{
+  (void)MD5_Final(digest, ctx);
+}
+
 #elif defined(USE_MBEDTLS)
 
 #include <mbedtls/md5.h>
@@ -97,21 +124,25 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
 /* The last #include file should be: */
 #include "memdebug.h"
 
-typedef mbedtls_md5_context MD5_CTX;
+typedef mbedtls_md5_context my_md5_ctx;
 
-static CURLcode MD5_Init(MD5_CTX *ctx)
+static CURLcode my_md5_init(my_md5_ctx *ctx)
 {
-#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
-  (void) mbedtls_md5_starts(ctx);
+#if (MBEDTLS_VERSION_NUMBER >= 0x03000000)
+  if(mbedtls_md5_starts(ctx))
+    return CURLE_OUT_OF_MEMORY;
+#elif defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
+  if(mbedtls_md5_starts_ret(ctx))
+    return CURLE_OUT_OF_MEMORY;
 #else
-  (void) mbedtls_md5_starts_ret(ctx);
+  (void)mbedtls_md5_starts(ctx);
 #endif
   return CURLE_OK;
 }
 
-static void MD5_Update(MD5_CTX *ctx,
-                       const unsigned char *data,
-                       unsigned int length)
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *data,
+                          unsigned int length)
 {
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_md5_update(ctx, data, length);
@@ -120,7 +151,7 @@ static void MD5_Update(MD5_CTX *ctx,
 #endif
 }
 
-static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
 {
 #if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS)
   (void) mbedtls_md5_finish(ctx, digest);
@@ -143,25 +174,27 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
    Declaring the functions as static like this seems to be a bit more
    reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
 #  include <CommonCrypto/CommonDigest.h>
-#  define MD5_CTX CC_MD5_CTX
+#  define my_md5_ctx CC_MD5_CTX
 #include "curl_memory.h"
 /* The last #include file should be: */
 #include "memdebug.h"
 
-static CURLcode MD5_Init(MD5_CTX *ctx)
+static CURLcode my_md5_init(my_md5_ctx *ctx)
 {
-  CC_MD5_Init(ctx);
+  if(!CC_MD5_Init(ctx))
+    return CURLE_OUT_OF_MEMORY;
+
   return CURLE_OK;
 }
 
-static void MD5_Update(MD5_CTX *ctx,
-                       const unsigned char *input,
-                       unsigned int inputLen)
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *input,
+                          unsigned int inputLen)
 {
   CC_MD5_Update(ctx, input, inputLen);
 }
 
-static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
 {
   CC_MD5_Final(digest, ctx);
 }
@@ -177,25 +210,30 @@ struct md5_ctx {
   HCRYPTPROV hCryptProv;
   HCRYPTHASH hHash;
 };
-typedef struct md5_ctx MD5_CTX;
+typedef struct md5_ctx my_md5_ctx;
 
-static CURLcode MD5_Init(MD5_CTX *ctx)
+static CURLcode my_md5_init(my_md5_ctx *ctx)
 {
-  if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
-                         CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
-    CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
+  if(!CryptAcquireContext(&ctx->hCryptProv, NULL, NULL, PROV_RSA_FULL,
+                          CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+    return CURLE_OUT_OF_MEMORY;
+
+  if(!CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash)) {
+    CryptReleaseContext(ctx->hCryptProv, 0);
+    return CURLE_OUT_OF_MEMORY;
   }
+
   return CURLE_OK;
 }
 
-static void MD5_Update(MD5_CTX *ctx,
-                       const unsigned char *input,
-                       unsigned int inputLen)
+static void my_md5_update(my_md5_ctx *ctx,
+                          const unsigned char *input,
+                          unsigned int inputLen)
 {
   CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
 }
 
-static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
+static void my_md5_final(unsigned char *digest, my_md5_ctx *ctx)
 {
   unsigned long length = 0;
   CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
@@ -263,11 +301,12 @@ struct md5_ctx {
   unsigned char buffer[64];
   MD5_u32plus block[16];
 };
-typedef struct md5_ctx MD5_CTX;
+typedef struct md5_ctx my_md5_ctx;
 
-static CURLcode MD5_Init(MD5_CTX *ctx);
-static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
-static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
+static CURLcode my_md5_init(my_md5_ctx *ctx);
+static void my_md5_update(my_md5_ctx *ctx, const void *data,
+                          unsigned long size);
+static void my_md5_final(unsigned char *result, my_md5_ctx *ctx);
 
 /*
  * The basic MD5 functions.
@@ -318,7 +357,7 @@ static void MD5_Final(unsigned char *result, MD5_CTX *ctx);
  * This processes one or more 64-byte data blocks, but does NOT update
  * the bit counters.  There are no alignment requirements.
  */
-static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
+static const void *body(my_md5_ctx *ctx, const void *data, unsigned long size)
 {
   const unsigned char *ptr;
   MD5_u32plus a, b, c, d;
@@ -426,7 +465,7 @@ static const void *body(MD5_CTX *ctx, const void *data, unsigned long size)
   return ptr;
 }
 
-static CURLcode MD5_Init(MD5_CTX *ctx)
+static CURLcode my_md5_init(my_md5_ctx *ctx)
 {
   ctx->a = 0x67452301;
   ctx->b = 0xefcdab89;
@@ -439,7 +478,8 @@ static CURLcode MD5_Init(MD5_CTX *ctx)
   return CURLE_OK;
 }
 
-static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
+static void my_md5_update(my_md5_ctx *ctx, const void *data,
+                          unsigned long size)
 {
   MD5_u32plus saved_lo;
   unsigned long used;
@@ -474,7 +514,7 @@ static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size)
   memcpy(ctx->buffer, data, size);
 }
 
-static void MD5_Final(unsigned char *result, MD5_CTX *ctx)
+static void my_md5_final(unsigned char *result, my_md5_ctx *ctx)
 {
   unsigned long used, available;
 
@@ -530,13 +570,13 @@ static void MD5_Final(unsigned char *result, MD5_CTX *ctx)
 const struct HMAC_params Curl_HMAC_MD5[] = {
   {
     /* Hash initialization function. */
-    CURLX_FUNCTION_CAST(HMAC_hinit_func, MD5_Init),
+    CURLX_FUNCTION_CAST(HMAC_hinit_func, my_md5_init),
     /* Hash update function. */
-    CURLX_FUNCTION_CAST(HMAC_hupdate_func, MD5_Update),
+    CURLX_FUNCTION_CAST(HMAC_hupdate_func, my_md5_update),
     /* Hash computation end function. */
-    CURLX_FUNCTION_CAST(HMAC_hfinal_func, MD5_Final),
+    CURLX_FUNCTION_CAST(HMAC_hfinal_func, my_md5_final),
     /* Size of hash context structure. */
-    sizeof(MD5_CTX),
+    sizeof(my_md5_ctx),
     /* Maximum key length. */
     64,
     /* Result size. */
@@ -547,13 +587,13 @@ const struct HMAC_params Curl_HMAC_MD5[] = {
 const struct MD5_params Curl_DIGEST_MD5[] = {
   {
     /* Digest initialization function */
-    CURLX_FUNCTION_CAST(Curl_MD5_init_func, MD5_Init),
+    CURLX_FUNCTION_CAST(Curl_MD5_init_func, my_md5_init),
     /* Digest update function */
-    CURLX_FUNCTION_CAST(Curl_MD5_update_func, MD5_Update),
+    CURLX_FUNCTION_CAST(Curl_MD5_update_func, my_md5_update),
     /* Digest computation end function */
-    CURLX_FUNCTION_CAST(Curl_MD5_final_func, MD5_Final),
+    CURLX_FUNCTION_CAST(Curl_MD5_final_func, my_md5_final),
     /* Size of digest context struct */
-    sizeof(MD5_CTX),
+    sizeof(my_md5_ctx),
     /* Result size */
     16
   }
@@ -564,15 +604,17 @@ const struct MD5_params Curl_DIGEST_MD5[] = {
  * Returns CURLE_OK on success.
  */
 CURLcode Curl_md5it(unsigned char *outbuffer, const unsigned char *input,
-                const size_t len)
+                    const size_t len)
 {
-  MD5_CTX ctx;
+  CURLcode result;
+  my_md5_ctx ctx;
 
-  MD5_Init(&ctx);
-  MD5_Update(&ctx, input, curlx_uztoui(len));
-  MD5_Final(outbuffer, &ctx);
-
-  return CURLE_OK;
+  result = my_md5_init(&ctx);
+  if(!result) {
+    my_md5_update(&ctx, input, curlx_uztoui(len));
+    my_md5_final(outbuffer, &ctx);
+  }
+  return result;
 }
 
 struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params)
@@ -594,7 +636,11 @@ struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params)
 
   ctxt->md5_hash = md5params;
 
-  (*md5params->md5_init_func)(ctxt->md5_hashctx);
+  if((*md5params->md5_init_func)(ctxt->md5_hashctx)) {
+    free(ctxt->md5_hashctx);
+    free(ctxt);
+    return NULL;
+  }
 
   return ctxt;
 }

+ 34 - 91
lib/mime.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -25,7 +25,6 @@
 #include <curl/curl.h>
 
 #include "mime.h"
-#include "non-ascii.h"
 #include "warnless.h"
 #include "urldata.h"
 #include "sendf.h"
@@ -315,7 +314,7 @@ static char *escape_string(struct Curl_easy *data,
 
   Curl_dyn_init(&db, CURL_MAX_INPUT_LENGTH);
 
-  for(result = Curl_dyn_add(&db, ""); !result && *src; src++) {
+  for(result = Curl_dyn_addn(&db, STRCONST("")); !result && *src; src++) {
     for(p = table; *p && **p != *src; p++)
       ;
 
@@ -340,9 +339,9 @@ static char *match_header(struct curl_slist *hdr, const char *lbl, size_t len)
 }
 
 /* Get a header from an slist. */
-static char *search_header(struct curl_slist *hdrlist, const char *hdr)
+static char *search_header(struct curl_slist *hdrlist,
+                           const char *hdr, size_t len)
 {
-  size_t len = strlen(hdr);
   char *value = NULL;
 
   for(; !value && hdrlist; hdrlist = hdrlist->next)
@@ -506,15 +505,6 @@ static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
     }
   }
 
-#ifdef CURL_DOES_CONVERSIONS
-  /* This is now textual data, Convert character codes. */
-  if(part->easy && cursize) {
-    CURLcode result = Curl_convert_to_network(part->easy, buffer, cursize);
-    if(result)
-      return READ_ERROR;
-  }
-#endif
-
   return cursize;
 }
 
@@ -768,7 +758,7 @@ static void mime_file_free(void *ptr)
 static size_t readback_bytes(struct mime_state *state,
                              char *buffer, size_t bufsize,
                              const char *bytes, size_t numbytes,
-                             const char *trail)
+                             const char *trail, size_t traillen)
 {
   size_t sz;
   size_t offset = curlx_sotouz(state->offset);
@@ -778,13 +768,11 @@ static size_t readback_bytes(struct mime_state *state,
     bytes += offset;
   }
   else {
-    size_t tsz = strlen(trail);
-
     sz = offset - numbytes;
-    if(sz >= tsz)
+    if(sz >= traillen)
       return 0;
     bytes = trail + sz;
-    sz = tsz - sz;
+    sz = traillen - sz;
   }
 
   if(sz > bufsize)
@@ -925,9 +913,6 @@ static size_t readback_part(curl_mimepart *part,
                             char *buffer, size_t bufsize, bool *hasread)
 {
   size_t cursize = 0;
-#ifdef CURL_DOES_CONVERSIONS
-  char *convbuf = buffer;
-#endif
 
   /* Readback from part. */
 
@@ -956,26 +941,18 @@ static size_t readback_part(curl_mimepart *part,
         mimesetstate(&part->state, MIMESTATE_USERHEADERS, part->userheaders);
       else {
         sz = readback_bytes(&part->state, buffer, bufsize,
-                            hdr->data, strlen(hdr->data), "\r\n");
+                            hdr->data, strlen(hdr->data), STRCONST("\r\n"));
         if(!sz)
           mimesetstate(&part->state, part->state.state, hdr->next);
       }
       break;
     case MIMESTATE_EOH:
-      sz = readback_bytes(&part->state, buffer, bufsize, "\r\n", 2, "");
+      sz = readback_bytes(&part->state, buffer, bufsize, STRCONST("\r\n"),
+                          STRCONST(""));
       if(!sz)
         mimesetstate(&part->state, MIMESTATE_BODY, NULL);
       break;
     case MIMESTATE_BODY:
-#ifdef CURL_DOES_CONVERSIONS
-      if(part->easy && convbuf < buffer) {
-        CURLcode result = Curl_convert_to_network(part->easy, convbuf,
-                                                  buffer - convbuf);
-        if(result)
-          return READ_ERROR;
-        convbuf = buffer;
-      }
-#endif
       cleanup_encoder_state(&part->encstate);
       mimesetstate(&part->state, MIMESTATE_CONTENT, NULL);
       break;
@@ -1012,16 +989,6 @@ static size_t readback_part(curl_mimepart *part,
     bufsize -= sz;
   }
 
-#ifdef CURL_DOES_CONVERSIONS
-      if(part->easy && convbuf < buffer &&
-         part->state.state < MIMESTATE_BODY) {
-        CURLcode result = Curl_convert_to_network(part->easy, convbuf,
-                                                  buffer - convbuf);
-        if(result)
-          return READ_ERROR;
-      }
-#endif
-
   return cursize;
 }
 
@@ -1031,10 +998,6 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
 {
   curl_mime *mime = (curl_mime *) instream;
   size_t cursize = 0;
-#ifdef CURL_DOES_CONVERSIONS
-  char *convbuf = buffer;
-#endif
-
   (void) size;   /* Always 1. */
 
   while(nitems) {
@@ -1043,9 +1006,6 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
     switch(mime->state.state) {
     case MIMESTATE_BEGIN:
     case MIMESTATE_BODY:
-#ifdef CURL_DOES_CONVERSIONS
-      convbuf = buffer;
-#endif
       mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, mime->firstpart);
       /* The first boundary always follows the header termination empty line,
          so is always preceded by a CRLF. We can then spare 2 characters
@@ -1053,23 +1013,19 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
       mime->state.offset += 2;
       break;
     case MIMESTATE_BOUNDARY1:
-      sz = readback_bytes(&mime->state, buffer, nitems, "\r\n--", 4, "");
+      sz = readback_bytes(&mime->state, buffer, nitems, STRCONST("\r\n--"),
+                          STRCONST(""));
       if(!sz)
         mimesetstate(&mime->state, MIMESTATE_BOUNDARY2, part);
       break;
     case MIMESTATE_BOUNDARY2:
-      sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
-                          strlen(mime->boundary), part? "\r\n": "--\r\n");
+      if(part)
+        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
+                            MIME_BOUNDARY_LEN, STRCONST("\r\n"));
+      else
+        sz = readback_bytes(&mime->state, buffer, nitems, mime->boundary,
+                            MIME_BOUNDARY_LEN, STRCONST("--\r\n"));
       if(!sz) {
-#ifdef CURL_DOES_CONVERSIONS
-        if(mime->easy && convbuf < buffer) {
-          CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
-                                                    buffer - convbuf);
-          if(result)
-            return READ_ERROR;
-          convbuf = buffer;
-        }
-#endif
         mimesetstate(&mime->state, MIMESTATE_CONTENT, part);
       }
       break;
@@ -1086,9 +1042,6 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
       case STOP_FILLING:
         return cursize? cursize: sz;
       case 0:
-#ifdef CURL_DOES_CONVERSIONS
-        convbuf = buffer;
-#endif
         mimesetstate(&mime->state, MIMESTATE_BOUNDARY1, part->nextpart);
         break;
       }
@@ -1105,16 +1058,6 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems,
     nitems -= sz;
   }
 
-#ifdef CURL_DOES_CONVERSIONS
-      if(mime->easy && convbuf < buffer &&
-         mime->state.state <= MIMESTATE_CONTENT) {
-        CURLcode result = Curl_convert_to_network(mime->easy, convbuf,
-                                                  buffer - convbuf);
-        if(result)
-          return READ_ERROR;
-      }
-#endif
-
   return cursize;
 }
 
@@ -1341,8 +1284,9 @@ curl_mime *curl_mime_init(struct Curl_easy *easy)
     mime->firstpart = NULL;
     mime->lastpart = NULL;
 
-    memset(mime->boundary, '-', 24);
-    if(Curl_rand_hex(easy, (unsigned char *) &mime->boundary[24],
+    memset(mime->boundary, '-', MIME_BOUNDARY_DASHES);
+    if(Curl_rand_hex(easy,
+                     (unsigned char *) &mime->boundary[MIME_BOUNDARY_DASHES],
                      MIME_RAND_BOUNDARY_CHARS + 1)) {
       /* failed to get random separator, bail out */
       free(mime);
@@ -1619,7 +1563,7 @@ CURLcode Curl_mime_set_subparts(curl_mimepart *part,
         root = root->parent->parent;
       if(subparts == root) {
         if(part->easy)
-          failf(part->easy, "Can't add itself as a subpart!");
+          failf(part->easy, "Can't add itself as a subpart");
         return CURLE_BAD_FUNCTION_ARGUMENT;
       }
     }
@@ -1675,10 +1619,9 @@ CURLcode Curl_mime_rewind(curl_mimepart *part)
 
 /* Compute header list size. */
 static size_t slist_size(struct curl_slist *s,
-                         size_t overhead, const char *skip)
+                         size_t overhead, const char *skip, size_t skiplen)
 {
   size_t size = 0;
-  size_t skiplen = skip? strlen(skip): 0;
 
   for(; s; s = s->next)
     if(!skip || !match_header(s, skip, skiplen))
@@ -1696,7 +1639,7 @@ static curl_off_t multipart_size(curl_mime *mime)
   if(!mime)
     return 0;           /* Not present -> empty. */
 
-  boundarysize = 4 + strlen(mime->boundary) + 2;
+  boundarysize = 4 + MIME_BOUNDARY_LEN + 2;
   size = boundarysize;  /* Final boundary - CRLF after headers. */
 
   for(part = mime->firstpart; part; part = part->nextpart) {
@@ -1727,8 +1670,8 @@ curl_off_t Curl_mime_size(curl_mimepart *part)
 
   if(size >= 0 && !(part->flags & MIME_BODY_ONLY)) {
     /* Compute total part size. */
-    size += slist_size(part->curlheaders, 2, NULL);
-    size += slist_size(part->userheaders, 2, "Content-Type");
+    size += slist_size(part->curlheaders, 2, NULL, 0);
+    size += slist_size(part->userheaders, 2, STRCONST("Content-Type"));
     size += 2;    /* CRLF after headers. */
   }
   return size;
@@ -1804,10 +1747,9 @@ const char *Curl_mime_contenttype(const char *filename)
   return NULL;
 }
 
-static bool content_type_match(const char *contenttype, const char *target)
+static bool content_type_match(const char *contenttype,
+                               const char *target, size_t len)
 {
-  size_t len = strlen(target);
-
   if(contenttype && strncasecompare(contenttype, target, len))
     switch(contenttype[len]) {
     case '\0':
@@ -1843,7 +1785,7 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
   /* Check if content type is specified. */
   customct = part->mimetype;
   if(!customct)
-    customct = search_header(part->userheaders, "Content-Type");
+    customct = search_header(part->userheaders, STRCONST("Content-Type"));
   if(customct)
     contenttype = customct;
 
@@ -1872,12 +1814,12 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
       boundary = mime->boundary;
   }
   else if(contenttype && !customct &&
-          content_type_match(contenttype, "text/plain"))
+          content_type_match(contenttype, STRCONST("text/plain")))
     if(strategy == MIMESTRATEGY_MAIL || !part->filename)
       contenttype = NULL;
 
   /* Issue content-disposition header only if not already set by caller. */
-  if(!search_header(part->userheaders, "Content-Disposition")) {
+  if(!search_header(part->userheaders, STRCONST("Content-Disposition"))) {
     if(!disposition)
       if(part->filename || part->name ||
         (contenttype && !strncasecompare(contenttype, "multipart/", 10)))
@@ -1924,7 +1866,8 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
   }
 
   /* Content-Transfer-Encoding header. */
-  if(!search_header(part->userheaders, "Content-Transfer-Encoding")) {
+  if(!search_header(part->userheaders,
+                    STRCONST("Content-Transfer-Encoding"))) {
     if(part->encoder)
       cte = part->encoder->name;
     else if(contenttype && strategy == MIMESTRATEGY_MAIL &&
@@ -1948,7 +1891,7 @@ CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
     curl_mimepart *subpart;
 
     disposition = NULL;
-    if(content_type_match(contenttype, "multipart/form-data"))
+    if(content_type_match(contenttype, STRCONST("multipart/form-data")))
       disposition = "form-data";
     for(subpart = mime->firstpart; subpart; subpart = subpart->nextpart) {
       ret = Curl_mime_prepare_headers(subpart, NULL, disposition, strategy);

+ 5 - 4
lib/mime.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -24,6 +24,7 @@
 
 #include "curl_setup.h"
 
+#define MIME_BOUNDARY_DASHES            24  /* leading boundary dashes */
 #define MIME_RAND_BOUNDARY_CHARS        16  /* Nb. of random boundary chars. */
 #define MAX_ENCODED_LINE_LENGTH         76  /* Maximum encoded line length. */
 #define ENCODING_BUFFER_SIZE            256 /* Encoding temp buffers size. */
@@ -91,8 +92,8 @@ struct mime_state {
   curl_off_t offset;          /* State-dependent offset. */
 };
 
-/* minimum buffer size for the boundary string */
-#define MIME_BOUNDARY_LEN (24 + MIME_RAND_BOUNDARY_CHARS + 1)
+/* Boundary string length. */
+#define MIME_BOUNDARY_LEN (MIME_BOUNDARY_DASHES + MIME_RAND_BOUNDARY_CHARS)
 
 /* A mime multipart. */
 struct curl_mime {
@@ -100,7 +101,7 @@ struct curl_mime {
   curl_mimepart *parent;           /* Parent part. */
   curl_mimepart *firstpart;        /* First part. */
   curl_mimepart *lastpart;         /* Last part. */
-  char boundary[MIME_BOUNDARY_LEN]; /* The part boundary. */
+  char boundary[MIME_BOUNDARY_LEN + 1]; /* The part boundary. */
   struct mime_state state;         /* Current readback state. */
 };
 

+ 3 - 2
lib/mprintf.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1999 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1999 - 2022, 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
@@ -65,7 +65,6 @@
  */
 
 #if (defined(__BORLANDC__) && (__BORLANDC__ >= 0x520)) || \
-    (defined(__WATCOMC__) && defined(__386__)) || \
     (defined(__POCC__) && defined(_MSC_VER)) || \
     (defined(_WIN32_WCE)) || \
     (defined(__MINGW32__)) || \
@@ -830,6 +829,8 @@ static int dprintf_formatf(
         }
         else if(prec != -1)
           len = (size_t)prec;
+        else if(*str == '\0')
+          len = 0;
         else
           len = strlen(str);
 

+ 24 - 5
lib/mqtt.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2020 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2020 - 2022, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2019, Björn Stenberg, <[email protected]>
  *
  * This software is licensed as described in the file COPYING, which
@@ -60,6 +60,8 @@
  */
 
 static CURLcode mqtt_do(struct Curl_easy *data, bool *done);
+static CURLcode mqtt_done(struct Curl_easy *data,
+                          CURLcode status, bool premature);
 static CURLcode mqtt_doing(struct Curl_easy *data, bool *done);
 static int mqtt_getsock(struct Curl_easy *data, struct connectdata *conn,
                         curl_socket_t *sock);
@@ -74,7 +76,7 @@ const struct Curl_handler Curl_handler_mqtt = {
   "MQTT",                             /* scheme */
   mqtt_setup_conn,                    /* setup_connection */
   mqtt_do,                            /* do_it */
-  ZERO_NULL,                          /* done */
+  mqtt_done,                          /* done */
   ZERO_NULL,                          /* do_more */
   ZERO_NULL,                          /* connect_it */
   ZERO_NULL,                          /* connecting */
@@ -344,7 +346,9 @@ end:
 static CURLcode mqtt_disconnect(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
+  struct MQTT *mq = data->req.p.mqtt;
   result = mqtt_send(data, (char *)"\xe0\x00", 2);
+  Curl_safefree(mq->sendleftovers);
   return result;
 }
 
@@ -384,8 +388,7 @@ static CURLcode mqtt_get_topic(struct Curl_easy *data,
 {
   char *path = data->state.up.path;
   if(strlen(path) > 1)
-    return Curl_urldecode(data, path + 1, 0, topic, topiclen,
-                          REJECT_NADA);
+    return Curl_urldecode(path + 1, 0, topic, topiclen, REJECT_NADA);
   failf(data, "No MQTT topic found. Forgot to URL encode it?");
   return CURLE_URL_MALFORMAT;
 }
@@ -692,6 +695,16 @@ static CURLcode mqtt_do(struct Curl_easy *data, bool *done)
   return CURLE_OK;
 }
 
+static CURLcode mqtt_done(struct Curl_easy *data,
+                          CURLcode status, bool premature)
+{
+  struct MQTT *mq = data->req.p.mqtt;
+  (void)status;
+  (void)premature;
+  Curl_safefree(mq->sendleftovers);
+  return CURLE_OK;
+}
+
 static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
@@ -719,8 +732,14 @@ static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
   case MQTT_FIRST:
     /* Read the initial byte only */
     result = Curl_read(data, sockfd, (char *)&mq->firstbyte, 1, &nread);
-    if(!nread)
+    if(result)
       break;
+    else if(!nread) {
+      failf(data, "Connection disconnected");
+      *done = TRUE;
+      result = CURLE_RECV_ERROR;
+      break;
+    }
     Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
     /* remember the first byte */
     mq->npacket = 0;

+ 25 - 19
lib/multi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -687,16 +687,10 @@ static CURLcode multi_done(struct Curl_easy *data,
 #endif
      ) || conn->bits.close
        || (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
-    CURLcode res2;
     connclose(conn, "disconnecting");
     Curl_conncache_remove_conn(data, conn, FALSE);
     CONNCACHE_UNLOCK(data);
-    res2 = Curl_disconnect(data, conn, premature);
-
-    /* If we had an error already, make sure we return that one. But
-       if we got a new error, return that. */
-    if(!result && res2)
-      result = res2;
+    Curl_disconnect(data, conn, premature);
   }
   else {
     char buffer[256];
@@ -709,14 +703,15 @@ static CURLcode multi_done(struct Curl_easy *data,
       conn->bits.conn_to_host ? conn->conn_to_host.dispname :
       conn->host.dispname;
     /* create string before returning the connection */
+    long connection_id = conn->connection_id;
     msnprintf(buffer, sizeof(buffer),
               "Connection #%ld to host %s left intact",
-              conn->connection_id, host);
+              connection_id, host);
     /* the connection is no longer in use by this transfer */
     CONNCACHE_UNLOCK(data);
     if(Curl_conncache_return_conn(data, conn)) {
       /* remember the most recently used connection */
-      data->state.lastconnect_id = conn->connection_id;
+      data->state.lastconnect_id = connection_id;
       infof(data, "%s", buffer);
     }
     else
@@ -724,7 +719,6 @@ static CURLcode multi_done(struct Curl_easy *data,
   }
 
   Curl_safefree(data->state.buffer);
-  Curl_free_request_state(data);
   return result;
 }
 
@@ -1759,6 +1753,10 @@ CURLcode Curl_preconnect(struct Curl_easy *data)
   return CURLE_OK;
 }
 
+static void set_in_callback(struct Curl_multi *multi, bool value)
+{
+  multi->in_callback = value;
+}
 
 static CURLMcode multi_runsingle(struct Curl_multi *multi,
                                  struct curltime *nowp,
@@ -1795,7 +1793,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     rc = CURLM_OK;
 
     if(multi_ischanged(multi, TRUE)) {
-      DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!"));
+      DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue"));
       process_pending_handles(multi); /* multiplexed */
     }
 
@@ -2169,8 +2167,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
           Curl_posttransfer(data);
           drc = multi_done(data, result, FALSE);
 
-          /* When set to retry the connection, we must to go back to
-           * the CONNECT state */
+          /* When set to retry the connection, we must go back to the CONNECT
+           * state */
           if(newurl) {
             if(!drc || (drc == CURLE_SEND_ERROR)) {
               follow = FOLLOW_RETRY;
@@ -2382,7 +2380,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         CURLcode ret = Curl_retry_request(data, &newurl);
 
         if(!ret) {
-          infof(data, "Downgrades to HTTP/1.1!");
+          infof(data, "Downgrades to HTTP/1.1");
           streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
           data->state.httpwant = CURL_HTTP_VERSION_1_1;
           /* clear the error message bit too as we ignore the one we got */
@@ -2872,8 +2870,10 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
       continue;
 
     if(multi->socket_cb) {
+      set_in_callback(multi, TRUE);
       rc = multi->socket_cb(data, s, comboaction, multi->socket_userp,
                             entry->socketp);
+      set_in_callback(multi, FALSE);
       if(rc == -1) {
         multi->dead = TRUE;
         return CURLM_ABORTED_BY_CALLBACK;
@@ -2914,8 +2914,10 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
         entry->readers--;
       if(!entry->users) {
         if(multi->socket_cb) {
+          set_in_callback(multi, TRUE);
           rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
                                 multi->socket_userp, entry->socketp);
+          set_in_callback(multi, FALSE);
           if(rc == -1) {
             multi->dead = TRUE;
             return CURLM_ABORTED_BY_CALLBACK;
@@ -2969,9 +2971,12 @@ void Curl_multi_closed(struct Curl_easy *data, curl_socket_t s)
 
       if(entry) {
         int rc = 0;
-        if(multi->socket_cb)
+        if(multi->socket_cb) {
+          set_in_callback(multi, TRUE);
           rc = multi->socket_cb(data, s, CURL_POLL_REMOVE,
                                 multi->socket_userp, entry->socketp);
+          set_in_callback(multi, FALSE);
+        }
 
         /* now remove it from the socket hash */
         sh_delentry(entry, &multi->sockhash, s);
@@ -3343,7 +3348,9 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi)
       multi->timer_lastcall = none;
       /* there's no timeout now but there was one previously, tell the app to
          disable it */
+      set_in_callback(multi, TRUE);
       rc = multi->timer_cb(multi, -1, multi->timer_userp);
+      set_in_callback(multi, FALSE);
       if(rc == -1) {
         multi->dead = TRUE;
         return CURLM_ABORTED_BY_CALLBACK;
@@ -3362,7 +3369,9 @@ CURLMcode Curl_update_timer(struct Curl_multi *multi)
 
   multi->timer_lastcall = multi->timetree->key;
 
+  set_in_callback(multi, TRUE);
   rc = multi->timer_cb(multi, timeout_ms, multi->timer_userp);
+  set_in_callback(multi, FALSE);
   if(rc == -1) {
     multi->dead = TRUE;
     return CURLM_ABORTED_BY_CALLBACK;
@@ -3561,9 +3570,6 @@ CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
 {
   struct Curl_sh_entry *there = NULL;
 
-  if(multi->in_callback)
-    return CURLM_RECURSIVE_API_CALL;
-
   there = sh_getentry(&multi->sockhash, s);
 
   if(!there)

+ 0 - 336
lib/non-ascii.c

@@ -1,336 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#ifdef CURL_DOES_CONVERSIONS
-
-#include <curl/curl.h>
-
-#include "non-ascii.h"
-#include "formdata.h"
-#include "sendf.h"
-#include "urldata.h"
-#include "multiif.h"
-#include "strerror.h"
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-#ifdef HAVE_ICONV
-#include <iconv.h>
-/* set default codesets for iconv */
-#ifndef CURL_ICONV_CODESET_OF_NETWORK
-#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
-#endif
-#ifndef CURL_ICONV_CODESET_FOR_UTF8
-#define CURL_ICONV_CODESET_FOR_UTF8   "UTF-8"
-#endif
-#define ICONV_ERROR  (size_t)-1
-#endif /* HAVE_ICONV */
-
-/*
- * Curl_convert_clone() returns a malloced copy of the source string (if
- * returning CURLE_OK), with the data converted to network format.
- */
-CURLcode Curl_convert_clone(struct Curl_easy *data,
-                           const char *indata,
-                           size_t insize,
-                           char **outbuf)
-{
-  char *convbuf;
-  CURLcode result;
-
-  convbuf = malloc(insize);
-  if(!convbuf)
-    return CURLE_OUT_OF_MEMORY;
-
-  memcpy(convbuf, indata, insize);
-  result = Curl_convert_to_network(data, convbuf, insize);
-  if(result) {
-    free(convbuf);
-    return result;
-  }
-
-  *outbuf = convbuf; /* return the converted buffer */
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_convert_to_network() is an internal function for performing ASCII
- * conversions on non-ASCII platforms. It converts the buffer _in place_.
- */
-CURLcode Curl_convert_to_network(struct Curl_easy *data,
-                                 char *buffer, size_t length)
-{
-  if(data && data->set.convtonetwork) {
-    /* use translation callback */
-    CURLcode result;
-    Curl_set_in_callback(data, true);
-    result = data->set.convtonetwork(buffer, length);
-    Curl_set_in_callback(data, false);
-    if(result) {
-      failf(data,
-            "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
-            (int)result, curl_easy_strerror(result));
-    }
-
-    return result;
-  }
-  else {
-#ifdef HAVE_ICONV
-    /* do the translation ourselves */
-    iconv_t tmpcd = (iconv_t) -1;
-    iconv_t *cd = &tmpcd;
-    char *input_ptr, *output_ptr;
-    size_t in_bytes, out_bytes, rc;
-    char ebuffer[STRERROR_LEN];
-
-    /* open an iconv conversion descriptor if necessary */
-    if(data)
-      cd = &data->outbound_cd;
-    if(*cd == (iconv_t)-1) {
-      *cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
-                       CURL_ICONV_CODESET_OF_HOST);
-      if(*cd == (iconv_t)-1) {
-        failf(data,
-              "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
-              CURL_ICONV_CODESET_OF_NETWORK,
-              CURL_ICONV_CODESET_OF_HOST,
-              errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
-        return CURLE_CONV_FAILED;
-      }
-    }
-    /* call iconv */
-    input_ptr = output_ptr = buffer;
-    in_bytes = out_bytes = length;
-    rc = iconv(*cd, &input_ptr, &in_bytes,
-               &output_ptr, &out_bytes);
-    if(!data)
-      iconv_close(tmpcd);
-    if((rc == ICONV_ERROR) || (in_bytes)) {
-      failf(data,
-            "The Curl_convert_to_network iconv call failed with errno %i: %s",
-            errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
-      return CURLE_CONV_FAILED;
-    }
-#else
-    failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
-    return CURLE_CONV_REQD;
-#endif /* HAVE_ICONV */
-  }
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_convert_from_network() is an internal function for performing ASCII
- * conversions on non-ASCII platforms. It converts the buffer _in place_.
- */
-CURLcode Curl_convert_from_network(struct Curl_easy *data,
-                                   char *buffer, size_t length)
-{
-  if(data && data->set.convfromnetwork) {
-    /* use translation callback */
-    CURLcode result;
-    Curl_set_in_callback(data, true);
-    result = data->set.convfromnetwork(buffer, length);
-    Curl_set_in_callback(data, false);
-    if(result) {
-      failf(data,
-            "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
-            (int)result, curl_easy_strerror(result));
-    }
-
-    return result;
-  }
-  else {
-#ifdef HAVE_ICONV
-    /* do the translation ourselves */
-    iconv_t tmpcd = (iconv_t) -1;
-    iconv_t *cd = &tmpcd;
-    char *input_ptr, *output_ptr;
-    size_t in_bytes, out_bytes, rc;
-    char ebuffer[STRERROR_LEN];
-
-    /* open an iconv conversion descriptor if necessary */
-    if(data)
-      cd = &data->inbound_cd;
-    if(*cd == (iconv_t)-1) {
-      *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
-                       CURL_ICONV_CODESET_OF_NETWORK);
-      if(*cd == (iconv_t)-1) {
-        failf(data,
-              "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
-              CURL_ICONV_CODESET_OF_HOST,
-              CURL_ICONV_CODESET_OF_NETWORK,
-              errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
-        return CURLE_CONV_FAILED;
-      }
-    }
-    /* call iconv */
-    input_ptr = output_ptr = buffer;
-    in_bytes = out_bytes = length;
-    rc = iconv(*cd, &input_ptr, &in_bytes,
-               &output_ptr, &out_bytes);
-    if(!data)
-      iconv_close(tmpcd);
-    if((rc == ICONV_ERROR) || (in_bytes)) {
-      failf(data,
-            "Curl_convert_from_network iconv call failed with errno %i: %s",
-            errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
-      return CURLE_CONV_FAILED;
-    }
-#else
-    failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
-    return CURLE_CONV_REQD;
-#endif /* HAVE_ICONV */
-  }
-
-  return CURLE_OK;
-}
-
-/*
- * Curl_convert_from_utf8() is an internal function for performing UTF-8
- * conversions on non-ASCII platforms.
- */
-CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
-                                char *buffer, size_t length)
-{
-  if(data && data->set.convfromutf8) {
-    /* use translation callback */
-    CURLcode result;
-    Curl_set_in_callback(data, true);
-    result = data->set.convfromutf8(buffer, length);
-    Curl_set_in_callback(data, false);
-    if(result) {
-      failf(data,
-            "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
-            (int)result, curl_easy_strerror(result));
-    }
-
-    return result;
-  }
-  else {
-#ifdef HAVE_ICONV
-    /* do the translation ourselves */
-    iconv_t tmpcd = (iconv_t) -1;
-    iconv_t *cd = &tmpcd;
-    char *input_ptr;
-    char *output_ptr;
-    size_t in_bytes, out_bytes, rc;
-    char ebuffer[STRERROR_LEN];
-
-    /* open an iconv conversion descriptor if necessary */
-    if(data)
-      cd = &data->utf8_cd;
-    if(*cd == (iconv_t)-1) {
-      *cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
-                       CURL_ICONV_CODESET_FOR_UTF8);
-      if(*cd == (iconv_t)-1) {
-        failf(data,
-              "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
-              CURL_ICONV_CODESET_OF_HOST,
-              CURL_ICONV_CODESET_FOR_UTF8,
-              errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
-        return CURLE_CONV_FAILED;
-      }
-    }
-    /* call iconv */
-    input_ptr = output_ptr = buffer;
-    in_bytes = out_bytes = length;
-    rc = iconv(*cd, &input_ptr, &in_bytes,
-               &output_ptr, &out_bytes);
-    if(!data)
-      iconv_close(tmpcd);
-    if((rc == ICONV_ERROR) || (in_bytes)) {
-      failf(data,
-            "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
-            errno, Curl_strerror(errno, ebuffer, sizeof(ebuffer)));
-      return CURLE_CONV_FAILED;
-    }
-    if(output_ptr < input_ptr) {
-      /* null terminate the now shorter output string */
-      *output_ptr = 0x00;
-    }
-#else
-    failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
-    return CURLE_CONV_REQD;
-#endif /* HAVE_ICONV */
-  }
-
-  return CURLE_OK;
-}
-
-/*
- * Init conversion stuff for a Curl_easy
- */
-void Curl_convert_init(struct Curl_easy *data)
-{
-#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
-  /* conversion descriptors for iconv calls */
-  data->outbound_cd = (iconv_t)-1;
-  data->inbound_cd  = (iconv_t)-1;
-  data->utf8_cd     = (iconv_t)-1;
-#else
-  (void)data;
-#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
-}
-
-/*
- * Setup conversion stuff for a Curl_easy
- */
-void Curl_convert_setup(struct Curl_easy *data)
-{
-  data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
-                                CURL_ICONV_CODESET_OF_NETWORK);
-  data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
-                                 CURL_ICONV_CODESET_OF_HOST);
-  data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
-                             CURL_ICONV_CODESET_FOR_UTF8);
-}
-
-/*
- * Close conversion stuff for a Curl_easy
- */
-
-void Curl_convert_close(struct Curl_easy *data)
-{
-#ifdef HAVE_ICONV
-  /* close iconv conversion descriptors */
-  if(data->inbound_cd != (iconv_t)-1) {
-    iconv_close(data->inbound_cd);
-  }
-  if(data->outbound_cd != (iconv_t)-1) {
-    iconv_close(data->outbound_cd);
-  }
-  if(data->utf8_cd != (iconv_t)-1) {
-    iconv_close(data->utf8_cd);
-  }
-#else
-  (void)data;
-#endif /* HAVE_ICONV */
-}
-
-#endif /* CURL_DOES_CONVERSIONS */

+ 0 - 61
lib/non-ascii.h

@@ -1,61 +0,0 @@
-#ifndef HEADER_CURL_NON_ASCII_H
-#define HEADER_CURL_NON_ASCII_H
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-#include "curl_setup.h"
-
-#ifdef CURL_DOES_CONVERSIONS
-
-#include "urldata.h"
-
-/*
- * Curl_convert_clone() returns a malloced copy of the source string (if
- * returning CURLE_OK), with the data converted to network format.
- *
- * If no conversion was needed *outbuf may be NULL.
- */
-CURLcode Curl_convert_clone(struct Curl_easy *data,
-                            const char *indata,
-                            size_t insize,
-                            char **outbuf);
-
-void Curl_convert_init(struct Curl_easy *data);
-void Curl_convert_setup(struct Curl_easy *data);
-void Curl_convert_close(struct Curl_easy *data);
-
-CURLcode Curl_convert_to_network(struct Curl_easy *data,
-                                 char *buffer, size_t length);
-CURLcode Curl_convert_from_network(struct Curl_easy *data,
-                                 char *buffer, size_t length);
-CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
-                                 char *buffer, size_t length);
-#else
-#define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK)
-#define Curl_convert_init(x) Curl_nop_stmt
-#define Curl_convert_setup(x) Curl_nop_stmt
-#define Curl_convert_close(x) Curl_nop_stmt
-#define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK)
-#define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK)
-#define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK)
-#endif
-
-#endif /* HEADER_CURL_NON_ASCII_H */

+ 2 - 2
lib/nonblock.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -75,7 +75,7 @@ int curlx_nonblock(curl_socket_t sockfd,    /* operate on this */
 
 #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
 
-  /* BeOS */
+  /* Orbis OS */
   long b = nonblock ? 1L : 0L;
   return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
 

+ 0 - 327
lib/nwlib.c

@@ -1,327 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#ifdef NETWARE /* Novell NetWare */
-
-#ifdef __NOVELL_LIBC__
-/* For native LibC-based NLM we need to register as a real lib. */
-#include <library.h>
-#include <netware.h>
-#include <screen.h>
-#include <nks/thread.h>
-#include <nks/synch.h>
-
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
-
-struct libthreaddata {
-  int     _errno;
-  void    *twentybytes;
-};
-
-struct libdata {
-  int         x;
-  int         y;
-  int         z;
-  void        *tenbytes;
-  NXKey_t     perthreadkey;   /* if -1, no key obtained... */
-  NXMutex_t   *lock;
-};
-
-int         gLibId      = -1;
-void        *gLibHandle = (void *) NULL;
-rtag_t      gAllocTag   = (rtag_t) NULL;
-NXMutex_t   *gLibLock   = (NXMutex_t *) NULL;
-
-/* internal library function prototypes... */
-int  DisposeLibraryData(void *);
-void DisposeThreadData(void *);
-int  GetOrSetUpData(int id, struct libdata **data,
-                    struct libthreaddata **threaddata);
-
-
-int _NonAppStart(void        *NLMHandle,
-                 void        *errorScreen,
-                 const char  *cmdLine,
-                 const char  *loadDirPath,
-                 size_t      uninitializedDataLength,
-                 void        *NLMFileHandle,
-                 int         (*readRoutineP)(int conn,
-                                             void *fileHandle, size_t offset,
-                                             size_t nbytes,
-                                             size_t *bytesRead,
-                                             void *buffer),
-                  size_t      customDataOffset,
-                  size_t      customDataSize,
-                  int         messageCount,
-                  const char  **messages)
-{
-  NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
-
-#ifndef __GNUC__
-#pragma unused(cmdLine)
-#pragma unused(loadDirPath)
-#pragma unused(uninitializedDataLength)
-#pragma unused(NLMFileHandle)
-#pragma unused(readRoutineP)
-#pragma unused(customDataOffset)
-#pragma unused(customDataSize)
-#pragma unused(messageCount)
-#pragma unused(messages)
-#endif
-
-  /*
-   * Here we process our command line, post errors (to the error screen),
-   * perform initializations and anything else we need to do before being able
-   * to accept calls into us. If we succeed, we return non-zero and the NetWare
-   * Loader will leave us up, otherwise we fail to load and get dumped.
-   */
-  gAllocTag = AllocateResourceTag(NLMHandle,
-                                  "<library-name> memory allocations",
-                                  AllocSignature);
-
-  if(!gAllocTag) {
-    OutputToScreen(errorScreen, "Unable to allocate resource tag for "
-                   "library memory allocations.\n");
-    return -1;
-  }
-
-  gLibId = register_library(DisposeLibraryData);
-
-  if(gLibId < -1) {
-    OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
-    return -1;
-  }
-
-  gLibHandle = NLMHandle;
-
-  gLibLock = NXMutexAlloc(0, 0, &liblock);
-
-  if(!gLibLock) {
-    OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
-    return -1;
-  }
-
-  return 0;
-}
-
-/*
- * Here we clean up any resources we allocated. Resource tags is a big part
- * of what we created, but NetWare doesn't ask us to free those.
- */
-void _NonAppStop(void)
-{
-  (void) unregister_library(gLibId);
-  NXMutexFree(gLibLock);
-}
-
-/*
- * This function cannot be the first in the file for if the file is linked
- * first, then the check-unload function's offset will be nlmname.nlm+0
- * which is how to tell that there isn't one. When the check function is
- * first in the linked objects, it is ambiguous. For this reason, we will
- * put it inside this file after the stop function.
- *
- * Here we check to see if it's alright to ourselves to be unloaded. If not,
- * we return a non-zero value. Right now, there isn't any reason not to allow
- * it.
- */
-int _NonAppCheckUnload(void)
-{
-    return 0;
-}
-
-int GetOrSetUpData(int id, struct libdata **appData,
-                   struct libthreaddata **threadData)
-{
-  int                 err;
-  struct libdata      *app_data;
-  struct libthreaddata *thread_data;
-  NXKey_t             key;
-  NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
-
-  err         = 0;
-  thread_data = (struct libthreaddata_t *) NULL;
-
-  /*
-   * Attempt to get our data for the application calling us. This is where we
-   * store whatever application-specific information we need to carry in
-   * support of calling applications.
-   */
-  app_data = (struct libdata *) get_app_data(id);
-
-  if(!app_data) {
-    /*
-     * This application hasn't called us before; set up application AND
-     * per-thread data. Of course, just in case a thread from this same
-     * application is calling us simultaneously, we better lock our application
-     * data-creation mutex. We also need to recheck for data after we acquire
-     * the lock because WE might be that other thread that was too late to
-     * create the data and the first thread in will have created it.
-     */
-    NXLock(gLibLock);
-
-    app_data = (struct libdata *) get_app_data(id);
-    if(!app_data) {
-      app_data = calloc(1, sizeof(struct libdata));
-
-      if(app_data) {
-        app_data->tenbytes = malloc(10);
-        app_data->lock     = NXMutexAlloc(0, 0, &liblock);
-
-        if(!app_data->tenbytes || !app_data->lock) {
-          if(app_data->lock)
-            NXMutexFree(app_data->lock);
-          free(app_data->tenbytes);
-          free(app_data);
-          app_data = (libdata_t *) NULL;
-          err      = ENOMEM;
-        }
-
-        if(app_data) {
-          /*
-           * Here we burn in the application data that we were trying to get
-           * by calling get_app_data(). Next time we call the first function,
-           * we'll get this data we're just now setting. We also go on here to
-           * establish the per-thread data for the calling thread, something
-           * we'll have to do on each application thread the first time
-           * it calls us.
-           */
-          err = set_app_data(gLibId, app_data);
-
-          if(err) {
-            if(app_data->lock)
-              NXMutexFree(app_data->lock);
-            free(app_data->tenbytes);
-            free(app_data);
-            app_data = (libdata_t *) NULL;
-            err      = ENOMEM;
-          }
-          else {
-            /* create key for thread-specific data... */
-            err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
-
-            if(err)                /* (no more keys left?) */
-              key = -1;
-
-            app_data->perthreadkey = key;
-          }
-        }
-      }
-    }
-
-    NXUnlock(gLibLock);
-  }
-
-  if(app_data) {
-    key = app_data->perthreadkey;
-
-    if(key != -1 /* couldn't create a key? no thread data */
-        && !(err = NXKeyGetValue(key, (void **) &thread_data))
-        && !thread_data) {
-      /*
-       * Allocate the per-thread data for the calling thread. Regardless of
-       * whether there was already application data or not, this may be the
-       * first call by a new thread. The fact that we allocation 20 bytes on
-       * a pointer is not very important, this just helps to demonstrate that
-       * we can have arbitrarily complex per-thread data.
-       */
-      thread_data = malloc(sizeof(struct libthreaddata));
-
-      if(thread_data) {
-        thread_data->_errno      = 0;
-        thread_data->twentybytes = malloc(20);
-
-        if(!thread_data->twentybytes) {
-          free(thread_data);
-          thread_data = (struct libthreaddata *) NULL;
-          err         = ENOMEM;
-        }
-
-        err = NXKeySetValue(key, thread_data);
-        if(err) {
-          free(thread_data->twentybytes);
-          free(thread_data);
-          thread_data = (struct libthreaddata *) NULL;
-        }
-      }
-    }
-  }
-
-  if(appData)
-    *appData = app_data;
-
-  if(threadData)
-    *threadData = thread_data;
-
-  return err;
-}
-
-int DisposeLibraryData(void *data)
-{
-  if(data) {
-    void *tenbytes = ((libdata_t *) data)->tenbytes;
-
-    free(tenbytes);
-    free(data);
-  }
-
-  return 0;
-}
-
-void DisposeThreadData(void *data)
-{
-  if(data) {
-    void *twentybytes = ((struct libthreaddata *) data)->twentybytes;
-
-    free(twentybytes);
-    free(data);
-  }
-}
-
-#else /* __NOVELL_LIBC__ */
-/* For native CLib-based NLM seems we can do a bit more simple. */
-#include <nwthread.h>
-
-int main(void)
-{
-  /* initialize any globals here... */
-
-  /* do this if any global initializing was done
-  SynchronizeStart();
-  */
-  ExitThread(TSR_THREAD, 0);
-  return 0;
-}
-
-#endif /* __NOVELL_LIBC__ */
-
-#else /* NETWARE */
-
-#ifdef __POCC__
-#  pragma warn(disable:2024)  /* Disable warning #2024: Empty input file */
-#endif
-
-#endif /* NETWARE */

+ 0 - 88
lib/nwos.c

@@ -1,88 +0,0 @@
-/***************************************************************************
- *                                  _   _ ____  _
- *  Project                     ___| | | |  _ \| |
- *                             / __| | | | |_) | |
- *                            | (__| |_| |  _ <| |___
- *                             \___|\___/|_| \_\_____|
- *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
- *
- * This software is licensed as described in the file COPYING, which
- * you should have received as part of this distribution. The terms
- * are also available at https://curl.se/docs/copyright.html.
- *
- * You may opt to use, copy, modify, merge, publish, distribute and/or sell
- * copies of the Software, and permit persons to whom the Software is
- * furnished to do so, under the terms of the COPYING file.
- *
- * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
- * KIND, either express or implied.
- *
- ***************************************************************************/
-
-#include "curl_setup.h"
-
-#ifdef NETWARE /* Novell NetWare */
-
-#ifdef __NOVELL_LIBC__
-/* For native LibC-based NLM we need to do nothing. */
-int netware_init(void)
-{
-  return 0;
-}
-
-#else /* __NOVELL_LIBC__ */
-
-/* For native CLib-based NLM we need to initialize the LONG namespace. */
-#include <nwnspace.h>
-#include <nwthread.h>
-#include <nwadv.h>
-/* Make the CLIB Ctx stuff link */
-#include <netdb.h>
-NETDB_DEFINE_CONTEXT
-/* Make the CLIB Inet stuff link */
-#include <netinet/in.h>
-#include <arpa/inet.h>
-NETINET_DEFINE_CONTEXT
-
-int netware_init(void)
-{
-  int rc = 0;
-  unsigned int myHandle = GetNLMHandle();
-  /* import UnAugmentAsterisk dynamically for NW4.x compatibility */
-  void (*pUnAugmentAsterisk)(int) = (void(*)(int))
-          ImportSymbol(myHandle, "UnAugmentAsterisk");
-  /* import UseAccurateCaseForPaths dynamically for NW3.x compatibility */
-  void (*pUseAccurateCaseForPaths)(int) = (void(*)(int))
-          ImportSymbol(myHandle, "UseAccurateCaseForPaths");
-  if(pUnAugmentAsterisk)
-    pUnAugmentAsterisk(1);
-  if(pUseAccurateCaseForPaths)
-    pUseAccurateCaseForPaths(1);
-  UnimportSymbol(myHandle, "UnAugmentAsterisk");
-  UnimportSymbol(myHandle, "UseAccurateCaseForPaths");
-  /* set long name space */
-  if((SetCurrentNameSpace(4) == 255)) {
-    rc = 1;
-  }
-  if((SetTargetNameSpace(4) == 255)) {
-    rc = rc + 2;
-  }
-  return rc;
-}
-
-/* dummy function to satisfy newer prelude */
-int __init_environment(void)
-{
-  return 0;
-}
-
-/* dummy function to satisfy newer prelude */
-int __deinit_environment(void)
-{
-  return 0;
-}
-
-#endif /* __NOVELL_LIBC__ */
-
-#endif /* NETWARE */

+ 338 - 35
lib/openldap.c

@@ -5,7 +5,7 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2011 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2011 - 2022, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2010, Howard Chu, <[email protected]>
  *
  * This software is licensed as described in the file COPYING, which
@@ -46,6 +46,8 @@
 #include "curl_ldap.h"
 #include "curl_base64.h"
 #include "connect.h"
+#include "curl_sasl.h"
+#include "strcase.h"
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
 #include "curl_memory.h"
@@ -76,6 +78,8 @@ typedef enum {
   OLDAP_SSL,            /* Performing SSL handshake. */
   OLDAP_STARTTLS,       /* STARTTLS request sent. */
   OLDAP_TLS,            /* Performing TLS handshake. */
+  OLDAP_MECHS,          /* Get SASL authentication mechanisms. */
+  OLDAP_SASL,           /* SASL binding reply. */
   OLDAP_BIND,           /* Simple bind reply. */
   OLDAP_BINDV2,         /* Simple bind reply in protocol version 2. */
   OLDAP_LAST            /* Never used */
@@ -96,6 +100,13 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done);
 static CURLcode oldap_disconnect(struct Curl_easy *data,
                                  struct connectdata *conn, bool dead);
 
+static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
+                                   const struct bufref *initresp);
+static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
+                                    const struct bufref *resp);
+static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech);
+static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out);
+
 static Curl_recv oldap_recv;
 
 /*
@@ -154,10 +165,26 @@ const struct Curl_handler Curl_handler_ldaps = {
 };
 #endif
 
+/* SASL parameters for the ldap protocol */
+static const struct SASLproto saslldap = {
+  "ldap",                     /* The service name */
+  oldap_perform_auth,         /* Send authentication command */
+  oldap_continue_auth,        /* Send authentication continuation */
+  oldap_cancel_auth,          /* Send authentication cancellation */
+  oldap_get_message,          /* Get SASL response message */
+  0,                          /* Maximum initial response length (no max) */
+  LDAP_SASL_BIND_IN_PROGRESS, /* Code received when continuation is expected */
+  LDAP_SUCCESS,               /* Code to receive upon authentication success */
+  SASL_AUTH_NONE,             /* Default mechanisms */
+  0                           /* Configuration flags */
+};
+
 struct ldapconninfo {
+  struct SASL sasl;          /* SASL-related parameters */
   LDAP *ld;                  /* Openldap connection handle. */
   Curl_recv *recv;           /* For stacking SSL handler */
   Curl_send *send;
+  struct berval *servercred; /* SASL data from server. */
   ldapstate state;           /* Current machine state. */
   int proto;                 /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */
   int msgid;                 /* Current message id. */
@@ -184,6 +211,8 @@ static void state(struct Curl_easy *data, ldapstate newstate)
     "SSL",
     "STARTTLS",
     "TLS",
+    "MECHS",
+    "SASL",
     "BIND",
     "BINDV2",
     /* LAST */
@@ -251,6 +280,37 @@ static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
   return result;
 }
 
+/* Parse the login options. */
+static CURLcode oldap_parse_login_options(struct connectdata *conn)
+{
+  CURLcode result = CURLE_OK;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  const char *ptr = conn->options;
+
+  while(!result && ptr && *ptr) {
+    const char *key = ptr;
+    const char *value;
+
+    while(*ptr && *ptr != '=')
+        ptr++;
+
+    value = ptr + 1;
+
+    while(*ptr && *ptr != ';')
+      ptr++;
+
+    if(checkprefix("AUTH=", key))
+      result = Curl_sasl_parse_url_auth_option(&li->sasl, value, ptr - value);
+    else
+      result = CURLE_SETOPT_OPTION_SYNTAX;
+
+    if(*ptr == ';')
+      ptr++;
+  }
+
+  return result == CURLE_URL_MALFORMAT? CURLE_SETOPT_OPTION_SYNTAX: result;
+}
+
 static CURLcode oldap_setup_connection(struct Curl_easy *data,
                                        struct connectdata *conn)
 {
@@ -271,14 +331,94 @@ static CURLcode oldap_setup_connection(struct Curl_easy *data,
       conn->proto.ldapc = li;
       connkeep(conn, "OpenLDAP default");
 
+      /* Initialize the SASL storage */
+      Curl_sasl_init(&li->sasl, data, &saslldap);
+
       /* Clear the TLS upgraded flag */
       conn->bits.tls_upgraded = FALSE;
+
+      result = oldap_parse_login_options(conn);
     }
   }
 
   return result;
 }
 
+/*
+ * Get the SASL authentication challenge from the server credential buffer.
+ */
+static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out)
+{
+  struct berval *servercred = data->conn->proto.ldapc->servercred;
+
+  if(!servercred || !servercred->bv_val)
+    return CURLE_WEIRD_SERVER_REPLY;
+  Curl_bufref_set(out, servercred->bv_val, servercred->bv_len, NULL);
+  return CURLE_OK;
+}
+
+/*
+ * Sends an initial SASL bind request to the server.
+ */
+static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
+                                   const struct bufref *initresp)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  struct berval cred;
+  struct berval *pcred = &cred;
+  int rc;
+
+  cred.bv_val = (char *) Curl_bufref_ptr(initresp);
+  cred.bv_len = Curl_bufref_len(initresp);
+  if(!cred.bv_val)
+    pcred = NULL;
+  rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
+  if(rc != LDAP_SUCCESS)
+    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return result;
+}
+
+/*
+ * Sends SASL continuation.
+ */
+static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
+                                    const struct bufref *resp)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  struct berval cred;
+  struct berval *pcred = &cred;
+  int rc;
+
+  cred.bv_val = (char *) Curl_bufref_ptr(resp);
+  cred.bv_len = Curl_bufref_len(resp);
+  if(!cred.bv_val)
+    pcred = NULL;
+  rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
+  if(rc != LDAP_SUCCESS)
+    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return result;
+}
+
+/*
+ * Sends SASL bind cancellation.
+ */
+static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
+{
+  struct ldapconninfo *li = data->conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  int rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
+                          &li->msgid);
+
+  (void)mech;
+  if(rc != LDAP_SUCCESS)
+    result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
+  return result;
+}
+
 /* Starts LDAP simple bind. */
 static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
 {
@@ -292,7 +432,7 @@ static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
   passwd.bv_val = NULL;
   passwd.bv_len = 0;
 
-  if(conn->bits.user_passwd) {
+  if(data->state.aptr.user) {
     binddn = conn->user;
     passwd.bv_val = conn->passwd;
     passwd.bv_len = strlen(passwd.bv_val);
@@ -304,11 +444,45 @@ static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
     state(data, newstate);
   else
     result = oldap_map_error(rc,
-                             conn->bits.user_passwd?
+                             data->state.aptr.user?
                              CURLE_LOGIN_DENIED: CURLE_LDAP_CANNOT_BIND);
   return result;
 }
 
+/* Query the supported SASL authentication mechanisms. */
+static CURLcode oldap_perform_mechs(struct Curl_easy *data)
+{
+  CURLcode result = CURLE_OK;
+  struct ldapconninfo *li = data->conn->proto.ldapc;
+  int rc;
+  static const char * const supportedSASLMechanisms[] = {
+    "supportedSASLMechanisms",
+    NULL
+  };
+
+  rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
+                       (char **) supportedSASLMechanisms, 0,
+                       NULL, NULL, NULL, 0, &li->msgid);
+  if(rc == LDAP_SUCCESS)
+    state(data, OLDAP_MECHS);
+  else
+    result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
+  return result;
+}
+
+/* Starts SASL bind. */
+static CURLcode oldap_perform_sasl(struct Curl_easy *data)
+{
+  saslprogress progress = SASL_IDLE;
+  struct ldapconninfo *li = data->conn->proto.ldapc;
+  CURLcode result = Curl_sasl_start(&li->sasl, data, TRUE, &progress);
+
+  state(data, OLDAP_SASL);
+  if(!result && progress != SASL_INPROGRESS)
+    result = CURLE_LOGIN_DENIED;
+  return result;
+}
+
 #ifdef USE_SSL
 static Sockbuf_IO ldapsb_tls;
 
@@ -414,11 +588,106 @@ static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
   }
 #endif
 
+  if(li->sasl.prefmech != SASL_AUTH_NONE)
+    return oldap_perform_mechs(data);
+
   /* Force bind even if anonymous bind is not needed in protocol version 3
      to detect missing version 3 support. */
   return oldap_perform_bind(data, OLDAP_BIND);
 }
 
+/* Handle the supported SASL mechanisms query response */
+static CURLcode oldap_state_mechs_resp(struct Curl_easy *data,
+                                       LDAPMessage *msg, int code)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  int rc;
+  BerElement *ber = NULL;
+  CURLcode result = CURLE_OK;
+  struct berval bv, *bvals;
+
+  switch(ldap_msgtype(msg)) {
+  case LDAP_RES_SEARCH_ENTRY:
+    /* Got a list of supported SASL mechanisms. */
+    if(code != LDAP_SUCCESS && code != LDAP_NO_RESULTS_RETURNED)
+      return CURLE_LOGIN_DENIED;
+
+    rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
+    if(rc < 0)
+      return oldap_map_error(rc, CURLE_BAD_CONTENT_ENCODING);
+    for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
+        rc == LDAP_SUCCESS;
+        rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
+      int i;
+
+      if(!bv.bv_val)
+        break;
+
+      if(bvals) {
+        for(i = 0; bvals[i].bv_val; i++) {
+          size_t llen;
+          unsigned short mech = Curl_sasl_decode_mech((char *) bvals[i].bv_val,
+                                                      bvals[i].bv_len, &llen);
+          if(bvals[i].bv_len == llen)
+            li->sasl.authmechs |= mech;
+        }
+        ber_memfree(bvals);
+      }
+    }
+    ber_free(ber, 0);
+    break;
+
+  case LDAP_RES_SEARCH_RESULT:
+    switch(code) {
+    case LDAP_SIZELIMIT_EXCEEDED:
+      infof(data, "Too many authentication mechanisms\n");
+      /* FALLTHROUGH */
+    case LDAP_SUCCESS:
+    case LDAP_NO_RESULTS_RETURNED:
+      if(Curl_sasl_can_authenticate(&li->sasl, data))
+        result = oldap_perform_sasl(data);
+      else
+        result = CURLE_LOGIN_DENIED;
+      break;
+    default:
+      result = oldap_map_error(code, CURLE_LOGIN_DENIED);
+      break;
+    }
+    break;
+  default:
+    break;
+  }
+  return result;
+}
+
+/* Handle a SASL bind response. */
+static CURLcode oldap_state_sasl_resp(struct Curl_easy *data,
+                                      LDAPMessage *msg, int code)
+{
+  struct connectdata *conn = data->conn;
+  struct ldapconninfo *li = conn->proto.ldapc;
+  CURLcode result = CURLE_OK;
+  saslprogress progress;
+  int rc;
+
+  li->servercred = NULL;
+  rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0);
+  if(rc != LDAP_SUCCESS) {
+    failf(data, "LDAP local: sasl ldap_parse_result %s", ldap_err2string(rc));
+    result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
+  }
+  else {
+    result = Curl_sasl_continue(&li->sasl, data, code, &progress);
+    if(!result && progress != SASL_INPROGRESS)
+      state(data, OLDAP_STOP);
+  }
+
+  if(li->servercred)
+    ber_bvfree(li->servercred);
+  return result;
+}
+
 /* Handle a simple bind response. */
 static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
                                       int code)
@@ -459,12 +728,20 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
   if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) {
     /* Get response to last command. */
     rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg);
-    if(!rc)
-      return CURLE_OK;                    /* Timed out. */
-    if(rc < 0) {
-      failf(data, "LDAP local: connecting ldap_result %s",
-            ldap_err2string(rc));
-      return oldap_map_error(rc, CURLE_COULDNT_CONNECT);
+    switch(rc) {
+    case 0:                               /* Timed out. */
+      return CURLE_OK;
+    case LDAP_RES_SEARCH_ENTRY:
+    case LDAP_RES_SEARCH_REFERENCE:
+      break;
+    default:
+      li->msgid = 0;                      /* Nothing to abandon upon error. */
+      if(rc < 0) {
+        failf(data, "LDAP local: connecting ldap_result %s",
+              ldap_err2string(rc));
+        return oldap_map_error(rc, CURLE_COULDNT_CONNECT);
+      }
+      break;
     }
 
     /* Get error code from message. */
@@ -477,11 +754,11 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
     }
 
     /* If protocol version 3 is not supported, fallback to version 2. */
-    if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2
+    if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 &&
 #ifdef USE_SSL
-       && (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY)
+       (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) &&
 #endif
-       ) {
+       li->sasl.prefmech == SASL_AUTH_NONE) {
       static const int version = LDAP_VERSION2;
 
       ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
@@ -496,13 +773,19 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
 #ifdef USE_SSL
   case OLDAP_SSL:
     result = oldap_ssl_connect(data, OLDAP_SSL);
-    if(!result && ssl_installed(conn))
-      result = oldap_perform_bind(data, OLDAP_BIND);
+    if(!result && ssl_installed(conn)) {
+      if(li->sasl.prefmech != SASL_AUTH_NONE)
+        result = oldap_perform_mechs(data);
+      else
+        result = oldap_perform_bind(data, OLDAP_BIND);
+    }
     break;
   case OLDAP_STARTTLS:
     if(code != LDAP_SUCCESS) {
       if(data->set.use_ssl != CURLUSESSL_TRY)
         result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
+      else if(li->sasl.prefmech != SASL_AUTH_NONE)
+        result = oldap_perform_mechs(data);
       else
         result = oldap_perform_bind(data, OLDAP_BIND);
       break;
@@ -514,7 +797,9 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
       result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
     else if(ssl_installed(conn)) {
       conn->bits.tls_upgraded = TRUE;
-      if(conn->bits.user_passwd)
+      if(li->sasl.prefmech != SASL_AUTH_NONE)
+        result = oldap_perform_mechs(data);
+      else if(data->state.aptr.user)
         result = oldap_perform_bind(data, OLDAP_BIND);
       else {
         state(data, OLDAP_STOP); /* Version 3 supported: no bind required */
@@ -524,6 +809,12 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
     break;
 #endif
 
+  case OLDAP_MECHS:
+    result = oldap_state_mechs_resp(data, msg, code);
+    break;
+  case OLDAP_SASL:
+    result = oldap_state_sasl_resp(data, msg, code);
+    break;
   case OLDAP_BIND:
   case OLDAP_BINDV2:
     result = oldap_state_bind_resp(data, msg, code);
@@ -540,6 +831,10 @@ static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
   if(*done)
     conn->recv[FIRSTSOCKET] = oldap_recv;
 
+  if(result && li->msgid) {
+    ldap_abandon_ext(li->ld, li->msgid, NULL, NULL);
+    li->msgid = 0;
+  }
   return result;
 }
 
@@ -549,6 +844,9 @@ static CURLcode oldap_disconnect(struct Curl_easy *data,
 {
   struct ldapconninfo *li = conn->proto.ldapc;
   (void) dead_connection;
+#ifndef USE_SSL
+  (void)data;
+#endif
 
   if(li) {
     if(li->ld) {
@@ -562,6 +860,7 @@ static CURLcode oldap_disconnect(struct Curl_easy *data,
       ldap_unbind_ext(li->ld, NULL, NULL);
       li->ld = NULL;
     }
+    Curl_sasl_cleanup(conn, li->sasl.authused);
     conn->proto.ldapc = NULL;
     free(li);
   }
@@ -632,21 +931,21 @@ static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
   return CURLE_OK;
 }
 
-static CURLcode client_write(struct Curl_easy *data, const char *prefix,
-                             const char *value, size_t len, const char *suffix)
+static CURLcode client_write(struct Curl_easy *data,
+                             const char *prefix, size_t plen,
+                             const char *value, size_t len,
+                             const char *suffix, size_t slen)
 {
   CURLcode result = CURLE_OK;
-  size_t l;
 
   if(prefix) {
-    l = strlen(prefix);
     /* If we have a zero-length value and the prefix ends with a space
        separator, drop the latter. */
-    if(!len && l && prefix[l - 1] == ' ')
-      l--;
-    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, l);
+    if(!len && plen && prefix[plen - 1] == ' ')
+      plen--;
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, plen);
     if(!result)
-      data->req.bytecount += l;
+      data->req.bytecount += plen;
   }
   if(!result && value) {
     result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len);
@@ -654,10 +953,9 @@ static CURLcode client_write(struct Curl_easy *data, const char *prefix,
       data->req.bytecount += len;
   }
   if(!result && suffix) {
-    l = strlen(suffix);
-    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, l);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, slen);
     if(!result)
-      data->req.bytecount += l;
+      data->req.bytecount += slen;
   }
   return result;
 }
@@ -734,7 +1032,8 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
       break;
     }
 
-    result = client_write(data, "DN: ", bv.bv_val, bv.bv_len, "\n");
+    result = client_write(data, STRCONST("DN: "), bv.bv_val, bv.bv_len,
+                          STRCONST("\n"));
     if(result)
       break;
 
@@ -747,7 +1046,8 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
         break;
 
       if(!bvals) {
-        result = client_write(data, "\t", bv.bv_val, bv.bv_len, ":\n");
+        result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
+                              STRCONST(":\n"));
         if(result)
           break;
         continue;
@@ -759,7 +1059,8 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
       for(i = 0; bvals[i].bv_val != NULL; i++) {
         int binval = 0;
 
-        result = client_write(data, "\t", bv.bv_val, bv.bv_len, ":");
+        result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
+                              STRCONST(":"));
         if(result)
           break;
 
@@ -784,15 +1085,17 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
 
           /* Binary value, encode to base64. */
           if(bvals[i].bv_len)
-            result = Curl_base64_encode(data, bvals[i].bv_val, bvals[i].bv_len,
+            result = Curl_base64_encode(bvals[i].bv_val, bvals[i].bv_len,
                                         &val_b64, &val_b64_sz);
           if(!result)
-            result = client_write(data, ": ", val_b64, val_b64_sz, "\n");
+            result = client_write(data, STRCONST(": "), val_b64, val_b64_sz,
+                                  STRCONST("\n"));
           free(val_b64);
         }
         else
-          result = client_write(data, " ",
-                                bvals[i].bv_val, bvals[i].bv_len, "\n");
+          result = client_write(data, STRCONST(" "),
+                                bvals[i].bv_val, bvals[i].bv_len,
+                                STRCONST("\n"));
         if(result)
           break;
       }
@@ -800,7 +1103,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
       ber_memfree(bvals);
       bvals = NULL;
       if(!result)
-        result = client_write(data, "\n", NULL, 0, NULL);
+        result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
       if(result)
         break;
     }
@@ -808,7 +1111,7 @@ static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
     ber_free(ber, 0);
 
     if(!result)
-      result = client_write(data, "\n", NULL, 0, NULL);
+      result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
     if(!result)
       result = CURLE_AGAIN;
     break;

+ 2 - 13
lib/pingpong.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -32,7 +32,6 @@
 #include "speedcheck.h"
 #include "pingpong.h"
 #include "multiif.h"
-#include "non-ascii.h"
 #include "vtls/vtls.h"
 
 /* The last 3 #include files should be in this order */
@@ -199,11 +198,6 @@ CURLcode Curl_pp_vsendf(struct Curl_easy *data,
   s = Curl_dyn_ptr(&pp->sendbuf);
   Curl_pp_init(data, pp);
 
-  result = Curl_convert_to_network(data, s, write_len);
-  /* Curl_convert_to_network calls failf if unsuccessful */
-  if(result)
-    return result;
-
 #ifdef HAVE_GSSAPI
   conn->data_prot = PROT_CMD;
 #endif
@@ -299,7 +293,7 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
        */
       if((ptr + pp->cache_size) > (buf + data->set.buffer_size + 1)) {
         failf(data, "cached response data too big to handle");
-        return CURLE_RECV_ERROR;
+        return CURLE_WEIRD_SERVER_REPLY;
       }
       memcpy(ptr, pp->cache, pp->cache_size);
       gotbytes = (ssize_t)pp->cache_size;
@@ -324,11 +318,6 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
       if(result == CURLE_AGAIN)
         return CURLE_OK; /* return */
 
-      if(!result && (gotbytes > 0))
-        /* convert from the network encoding */
-        result = Curl_convert_from_network(data, ptr, gotbytes);
-      /* Curl_convert_from_network calls failf if unsuccessful */
-
       if(result)
         /* Set outer result variable to this error. */
         keepon = FALSE;

+ 8 - 8
lib/pop3.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -401,7 +401,7 @@ static CURLcode pop3_perform_user(struct Curl_easy *data,
 
   /* Check we have a username and password to authenticate with and end the
      connect phase if we don't */
-  if(!conn->bits.user_passwd) {
+  if(!data->state.aptr.user) {
     state(data, POP3_STOP);
 
     return result;
@@ -435,7 +435,7 @@ static CURLcode pop3_perform_apop(struct Curl_easy *data,
 
   /* Check we have a username and password to authenticate with and end the
      connect phase if we don't */
-  if(!conn->bits.user_passwd) {
+  if(!data->state.aptr.user) {
     state(data, POP3_STOP);
 
     return result;
@@ -545,7 +545,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
 
   /* Check we have enough data to authenticate with and end the
      connect phase if we don't */
-  if(!Curl_sasl_can_authenticate(&pop3c->sasl, conn)) {
+  if(!Curl_sasl_can_authenticate(&pop3c->sasl, data)) {
     state(data, POP3_STOP);
     return result;
   }
@@ -571,7 +571,7 @@ static CURLcode pop3_perform_authentication(struct Curl_easy *data,
       result = pop3_perform_user(data, conn);
     else {
       /* Other mechanisms not supported */
-      infof(data, "No known authentication mechanisms supported!");
+      infof(data, "No known authentication mechanisms supported");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -924,7 +924,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data,
 
   if(pop3code != '+') {
     state(data, POP3_STOP);
-    return CURLE_RECV_ERROR;
+    return CURLE_WEIRD_SERVER_REPLY;
   }
 
   /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
@@ -1423,7 +1423,7 @@ static CURLcode pop3_parse_url_path(struct Curl_easy *data)
   const char *path = &data->state.up.path[1]; /* skip leading path */
 
   /* URL decode the path for the message ID */
-  return Curl_urldecode(data, path, 0, &pop3->id, NULL, REJECT_CTRL);
+  return Curl_urldecode(path, 0, &pop3->id, NULL, REJECT_CTRL);
 }
 
 /***********************************************************************
@@ -1440,7 +1440,7 @@ static CURLcode pop3_parse_custom_request(struct Curl_easy *data)
 
   /* URL decode the custom request */
   if(custom)
-    result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, REJECT_CTRL);
+    result = Curl_urldecode(custom, 0, &pop3->custom, NULL, REJECT_CTRL);
 
   return result;
 }

+ 4 - 1
lib/quic.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -31,6 +31,9 @@
 #ifdef USE_QUICHE
 #include "vquic/quiche.h"
 #endif
+#ifdef USE_MSH3
+#include "vquic/msh3.h"
+#endif
 
 #include "urldata.h"
 

+ 2 - 2
lib/rand.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -87,7 +87,7 @@ static CURLcode randit(struct Curl_easy *data, unsigned int *rnd)
 
   if(!seeded) {
     struct curltime now = Curl_now();
-    infof(data, "WARNING: Using weak random seed");
+    infof(data, "WARNING: using weak random seed");
     randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
     randseed = randseed * 1103515245 + 12345;
     randseed = randseed * 1103515245 + 12345;

+ 22 - 19
lib/rtsp.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -219,7 +219,7 @@ static CURLcode rtsp_done(struct Curl_easy *data,
 
   httpStatus = Curl_http_done(data, status, premature);
 
-  if(rtsp) {
+  if(rtsp && !status && !httpStatus) {
     /* Check the sequence numbers */
     long CSeq_sent = rtsp->CSeq_sent;
     long CSeq_recv = rtsp->CSeq_recv;
@@ -340,7 +340,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
   }
 
   /* Transport Header for SETUP requests */
-  p_transport = Curl_checkheaders(data, "Transport");
+  p_transport = Curl_checkheaders(data, STRCONST("Transport"));
   if(rtspreq == RTSPREQ_SETUP && !p_transport) {
     /* New Transport: setting? */
     if(data->set.str[STRING_RTSP_TRANSPORT]) {
@@ -364,11 +364,11 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
   /* Accept Headers for DESCRIBE requests */
   if(rtspreq == RTSPREQ_DESCRIBE) {
     /* Accept Header */
-    p_accept = Curl_checkheaders(data, "Accept")?
+    p_accept = Curl_checkheaders(data, STRCONST("Accept"))?
       NULL:"Accept: application/sdp\r\n";
 
     /* Accept-Encoding header */
-    if(!Curl_checkheaders(data, "Accept-Encoding") &&
+    if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) &&
        data->set.str[STRING_ENCODING]) {
       Curl_safefree(data->state.aptr.accept_encoding);
       data->state.aptr.accept_encoding =
@@ -385,11 +385,12 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
      it might have been used in the proxy connect, but if we have got a header
      with the user-agent string specified, we erase the previously made string
      here. */
-  if(Curl_checkheaders(data, "User-Agent") && data->state.aptr.uagent) {
+  if(Curl_checkheaders(data, STRCONST("User-Agent")) &&
+     data->state.aptr.uagent) {
     Curl_safefree(data->state.aptr.uagent);
     data->state.aptr.uagent = NULL;
   }
-  else if(!Curl_checkheaders(data, "User-Agent") &&
+  else if(!Curl_checkheaders(data, STRCONST("User-Agent")) &&
           data->set.str[STRING_USERAGENT]) {
     p_uagent = data->state.aptr.uagent;
   }
@@ -405,7 +406,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
 
   /* Referrer */
   Curl_safefree(data->state.aptr.ref);
-  if(data->state.referer && !Curl_checkheaders(data, "Referer"))
+  if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer")))
     data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer);
   else
     data->state.aptr.ref = NULL;
@@ -422,7 +423,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
      (rtspreq  & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
 
     /* Check to see if there is a range set in the custom headers */
-    if(!Curl_checkheaders(data, "Range") && data->state.range) {
+    if(!Curl_checkheaders(data, STRCONST("Range")) && data->state.range) {
       Curl_safefree(data->state.aptr.rangeline);
       data->state.aptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
       p_range = data->state.aptr.rangeline;
@@ -432,11 +433,11 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
   /*
    * Sanity check the custom headers
    */
-  if(Curl_checkheaders(data, "CSeq")) {
+  if(Curl_checkheaders(data, STRCONST("CSeq"))) {
     failf(data, "CSeq cannot be set as a custom header.");
     return CURLE_RTSP_CSEQ_ERROR;
   }
-  if(Curl_checkheaders(data, "Session")) {
+  if(Curl_checkheaders(data, STRCONST("Session"))) {
     failf(data, "Session ID cannot be set as a custom header.");
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
@@ -523,7 +524,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
     if(putsize > 0 || postsize > 0) {
       /* As stated in the http comments, it is probably not wise to
        * actually set a custom Content-Length in the headers */
-      if(!Curl_checkheaders(data, "Content-Length")) {
+      if(!Curl_checkheaders(data, STRCONST("Content-Length"))) {
         result =
           Curl_dyn_addf(&req_buffer,
                         "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
@@ -534,18 +535,20 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
 
       if(rtspreq == RTSPREQ_SET_PARAMETER ||
          rtspreq == RTSPREQ_GET_PARAMETER) {
-        if(!Curl_checkheaders(data, "Content-Type")) {
-          result = Curl_dyn_addf(&req_buffer,
-                                 "Content-Type: text/parameters\r\n");
+        if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
+          result = Curl_dyn_addn(&req_buffer,
+                                 STRCONST("Content-Type: "
+                                          "text/parameters\r\n"));
           if(result)
             return result;
         }
       }
 
       if(rtspreq == RTSPREQ_ANNOUNCE) {
-        if(!Curl_checkheaders(data, "Content-Type")) {
-          result = Curl_dyn_addf(&req_buffer,
-                                 "Content-Type: application/sdp\r\n");
+        if(!Curl_checkheaders(data, STRCONST("Content-Type"))) {
+          result = Curl_dyn_addn(&req_buffer,
+                                 STRCONST("Content-Type: "
+                                          "application/sdp\r\n"));
           if(result)
             return result;
         }
@@ -563,7 +566,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
   /* RTSP never allows chunked transfer */
   data->req.forbidchunk = TRUE;
   /* Finish the request buffer */
-  result = Curl_dyn_add(&req_buffer, "\r\n");
+  result = Curl_dyn_addn(&req_buffer, STRCONST("\r\n"));
   if(result)
     return result;
 

+ 4 - 88
lib/select.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -34,25 +34,16 @@
 #error "We can't compile without select() or poll() support."
 #endif
 
-#if defined(__BEOS__) && !defined(__HAIKU__)
-/* BeOS has FD_SET defined in socket.h */
-#include <socket.h>
-#endif
-
 #ifdef MSDOS
 #include <dos.h>  /* delay() */
 #endif
 
-#ifdef __VXWORKS__
-#include <strings.h>  /* bzero() in FD_SET */
-#endif
-
 #include <curl/curl.h>
 
 #include "urldata.h"
 #include "connect.h"
 #include "select.h"
-#include "timeval.h"
+#include "timediff.h"
 #include "warnless.h"
 
 /*
@@ -102,26 +93,7 @@ int Curl_wait_ms(timediff_t timeout_ms)
 #else
   {
     struct timeval pending_tv;
-    timediff_t tv_sec = timeout_ms / 1000;
-    timediff_t tv_usec = (timeout_ms % 1000) * 1000; /* max=999999 */
-#ifdef HAVE_SUSECONDS_T
-#if TIMEDIFF_T_MAX > TIME_T_MAX
-    /* tv_sec overflow check in case time_t is signed */
-    if(tv_sec > TIME_T_MAX)
-      tv_sec = TIME_T_MAX;
-#endif
-    pending_tv.tv_sec = (time_t)tv_sec;
-    pending_tv.tv_usec = (suseconds_t)tv_usec;
-#else
-#if TIMEDIFF_T_MAX > INT_MAX
-    /* tv_sec overflow check in case time_t is signed */
-    if(tv_sec > INT_MAX)
-      tv_sec = INT_MAX;
-#endif
-    pending_tv.tv_sec = (int)tv_sec;
-    pending_tv.tv_usec = (int)tv_usec;
-#endif
-    r = select(0, NULL, NULL, NULL, &pending_tv);
+    r = select(0, NULL, NULL, NULL, curlx_mstotv(&pending_tv, timeout_ms));
   }
 #endif /* HAVE_POLL_FINE */
 #endif /* USE_WINSOCK */
@@ -161,43 +133,7 @@ static int our_select(curl_socket_t maxfd,   /* highest socket number */
   }
 #endif
 
-  ptimeout = &pending_tv;
-  if(timeout_ms < 0) {
-    ptimeout = NULL;
-  }
-  else if(timeout_ms > 0) {
-    timediff_t tv_sec = timeout_ms / 1000;
-    timediff_t tv_usec = (timeout_ms % 1000) * 1000; /* max=999999 */
-#ifdef HAVE_SUSECONDS_T
-#if TIMEDIFF_T_MAX > TIME_T_MAX
-    /* tv_sec overflow check in case time_t is signed */
-    if(tv_sec > TIME_T_MAX)
-      tv_sec = TIME_T_MAX;
-#endif
-    pending_tv.tv_sec = (time_t)tv_sec;
-    pending_tv.tv_usec = (suseconds_t)tv_usec;
-#elif defined(WIN32) /* maybe also others in the future */
-#if TIMEDIFF_T_MAX > LONG_MAX
-    /* tv_sec overflow check on Windows there we know it is long */
-    if(tv_sec > LONG_MAX)
-      tv_sec = LONG_MAX;
-#endif
-    pending_tv.tv_sec = (long)tv_sec;
-    pending_tv.tv_usec = (long)tv_usec;
-#else
-#if TIMEDIFF_T_MAX > INT_MAX
-    /* tv_sec overflow check in case time_t is signed */
-    if(tv_sec > INT_MAX)
-      tv_sec = INT_MAX;
-#endif
-    pending_tv.tv_sec = (int)tv_sec;
-    pending_tv.tv_usec = (int)tv_usec;
-#endif
-  }
-  else {
-    pending_tv.tv_sec = 0;
-    pending_tv.tv_usec = 0;
-  }
+  ptimeout = curlx_mstotv(&pending_tv, timeout_ms);
 
 #ifdef USE_WINSOCK
   /* WinSock select() must not be called with an fd_set that contains zero
@@ -450,23 +386,3 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
 
   return r;
 }
-
-#ifdef TPF
-/*
- * This is a replacement for select() on the TPF platform.
- * It is used whenever libcurl calls select().
- * The call below to tpf_process_signals() is required because
- * TPF's select calls are not signal interruptible.
- *
- * Return values are the same as select's.
- */
-int tpf_select_libcurl(int maxfds, fd_set *reads, fd_set *writes,
-                       fd_set *excepts, struct timeval *tv)
-{
-   int rc;
-
-   rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
-   tpf_process_signals();
-   return rc;
-}
-#endif /* TPF */

+ 3 - 14
lib/select.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -83,22 +83,11 @@ int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2,
 int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms);
 int Curl_wait_ms(timediff_t timeout_ms);
 
-#ifdef TPF
-int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
-                       fd_set* excepts, struct timeval *tv);
-#endif
-
-/* TPF sockets are not in range [0..FD_SETSIZE-1], which
-   unfortunately makes it impossible for us to easily check if they're valid
-
+/*
    With Winsock the valid range is [0..INVALID_SOCKET-1] according to
    https://docs.microsoft.com/en-us/windows/win32/winsock/socket-data-type-2
 */
-#if defined(TPF)
-#define VALID_SOCK(x) 1
-#define VERIFY_SOCK(x) Curl_nop_stmt
-#define FDSET_SOCK(x) 1
-#elif defined(USE_WINSOCK)
+#ifdef USE_WINSOCK
 #define VALID_SOCK(s) ((s) < INVALID_SOCKET)
 #define FDSET_SOCK(x) 1
 #define VERIFY_SOCK(x) do { \

+ 23 - 65
lib/sendf.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -41,11 +41,11 @@
 #include "vssh/ssh.h"
 #include "easyif.h"
 #include "multiif.h"
-#include "non-ascii.h"
 #include "strerror.h"
 #include "select.h"
 #include "strdup.h"
 #include "http2.h"
+#include "headers.h"
 
 /* The last 3 #include files should be in this order */
 #include "curl_printf.h"
@@ -566,7 +566,7 @@ static CURLcode chop_write(struct Curl_easy *data,
           /* Protocols that work without network cannot be paused. This is
              actually only FILE:// just now, and it can't pause since the
              transfer isn't done using the "normal" procedure. */
-          failf(data, "Write callback asked for PAUSE when not supported!");
+          failf(data, "Write callback asked for PAUSE when not supported");
           return CURLE_WRITE_ERROR;
         }
         return pausewrite(data, type, ptr, len);
@@ -581,21 +581,33 @@ static CURLcode chop_write(struct Curl_easy *data,
     len -= chunklen;
   }
 
+  /* HTTP header, but not status-line */
+  if((conn->handler->protocol & PROTO_FAMILY_HTTP) &&
+     (type & CLIENTWRITE_HEADER) && !(type & CLIENTWRITE_STATUS) ) {
+    CURLcode result =
+      Curl_headers_push(data, optr,
+                        type & CLIENTWRITE_CONNECT ? CURLH_CONNECT :
+                        (type & CLIENTWRITE_1XX ? CURLH_1XX :
+                         (type & CLIENTWRITE_TRAILER ? CURLH_TRAILER :
+                          CURLH_HEADER)));
+    if(result)
+      return result;
+  }
+
   if(writeheader) {
     size_t wrote;
-    ptr = optr;
-    len = olen;
+
     Curl_set_in_callback(data, true);
-    wrote = writeheader(ptr, 1, len, data->set.writeheader);
+    wrote = writeheader(optr, 1, olen, data->set.writeheader);
     Curl_set_in_callback(data, false);
 
     if(CURL_WRITEFUNC_PAUSE == wrote)
       /* here we pass in the HEADER bit only since if this was body as well
          then it was passed already and clearly that didn't trigger the
          pause, so this is saved for later with the HEADER bit only */
-      return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
+      return pausewrite(data, CLIENTWRITE_HEADER, optr, olen);
 
-    if(wrote != len) {
+    if(wrote != olen) {
       failf(data, "Failed writing header");
       return CURLE_WRITE_ERROR;
     }
@@ -621,26 +633,19 @@ CURLcode Curl_client_write(struct Curl_easy *data,
 {
   struct connectdata *conn = data->conn;
 
-  DEBUGASSERT(!(type & ~CLIENTWRITE_BOTH));
-
   if(!len)
     return CURLE_OK;
 
   /* FTP data may need conversion. */
   if((type & CLIENTWRITE_BODY) &&
-    (conn->handler->protocol & PROTO_FAMILY_FTP) &&
-    conn->proto.ftpc.transfertype == 'A') {
-    /* convert from the network encoding */
-    CURLcode result = Curl_convert_from_network(data, ptr, len);
-    /* Curl_convert_from_network calls failf if unsuccessful */
-    if(result)
-      return result;
+     (conn->handler->protocol & PROTO_FAMILY_FTP) &&
+     conn->proto.ftpc.transfertype == 'A') {
 
 #ifdef CURL_DO_LINEEND_CONV
     /* convert end-of-line markers */
     len = convert_lineends(data, ptr, len);
 #endif /* CURL_DO_LINEEND_CONV */
-    }
+  }
 
   return chop_write(data, type, ptr, len);
 }
@@ -716,44 +721,6 @@ int Curl_debug(struct Curl_easy *data, curl_infotype type,
   if(data->set.verbose) {
     static const char s_infotype[CURLINFO_END][3] = {
       "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
-
-#ifdef CURL_DOES_CONVERSIONS
-    char *buf = NULL;
-    size_t conv_size = 0;
-
-    switch(type) {
-    case CURLINFO_HEADER_OUT:
-      buf = Curl_memdup(ptr, size);
-      if(!buf)
-        return 1;
-      conv_size = size;
-
-      /* Special processing is needed for this block if it
-       * contains both headers and data (separated by CRLFCRLF).
-       * We want to convert just the headers, leaving the data as-is.
-       */
-      if(size > 4) {
-        size_t i;
-        for(i = 0; i < size-4; i++) {
-          if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
-            /* convert everything through this CRLFCRLF but no further */
-            conv_size = i + 4;
-            break;
-          }
-        }
-      }
-
-      Curl_convert_from_network(data, buf, conv_size);
-      /* Curl_convert_from_network calls failf if unsuccessful */
-      /* we might as well continue even if it fails...   */
-      ptr = buf; /* switch pointer to use my buffer instead */
-      break;
-    default:
-      /* leave everything else as-is */
-      break;
-    }
-#endif /* CURL_DOES_CONVERSIONS */
-
     if(data->set.fdebug) {
       Curl_set_in_callback(data, true);
       rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
@@ -766,20 +733,11 @@ int Curl_debug(struct Curl_easy *data, curl_infotype type,
       case CURLINFO_HEADER_IN:
         fwrite(s_infotype[type], 2, 1, data->set.err);
         fwrite(ptr, size, 1, data->set.err);
-#ifdef CURL_DOES_CONVERSIONS
-        if(size != conv_size) {
-          /* we had untranslated data so we need an explicit newline */
-          fwrite("\n", 1, 1, data->set.err);
-        }
-#endif
         break;
       default: /* nada */
         break;
       }
     }
-#ifdef CURL_DOES_CONVERSIONS
-    free(buf);
-#endif
   }
   return rc;
 }

+ 7 - 3
lib/sendf.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -45,8 +45,12 @@ void Curl_failf(struct Curl_easy *, const char *fmt, ...);
 
 #define failf Curl_failf
 
-#define CLIENTWRITE_BODY   (1<<0)
-#define CLIENTWRITE_HEADER (1<<1)
+#define CLIENTWRITE_BODY    (1<<0)
+#define CLIENTWRITE_HEADER  (1<<1)
+#define CLIENTWRITE_STATUS  (1<<2) /* the first "header" is the status line */
+#define CLIENTWRITE_CONNECT (1<<3) /* a CONNECT response */
+#define CLIENTWRITE_1XX     (1<<4) /* a 1xx response */
+#define CLIENTWRITE_TRAILER (1<<5) /* a trailer header */
 #define CLIENTWRITE_BOTH   (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
 
 CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,

+ 15 - 36
lib/setopt.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -62,19 +62,12 @@ CURLcode Curl_setstropt(char **charp, const char *s)
   Curl_safefree(*charp);
 
   if(s) {
-    char *str = strdup(s);
+    if(strlen(s) > CURL_MAX_INPUT_LENGTH)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
 
-    if(str) {
-      size_t len = strlen(str);
-      if(len > CURL_MAX_INPUT_LENGTH) {
-        free(str);
-        return CURLE_BAD_FUNCTION_ARGUMENT;
-      }
-    }
-    if(!str)
+    *charp = strdup(s);
+    if(!*charp)
       return CURLE_OUT_OF_MEMORY;
-
-    *charp = str;
   }
 
   return CURLE_OK;
@@ -162,7 +155,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
   char *argptr;
   CURLcode result = CURLE_OK;
   long arg;
+#ifdef ENABLE_IPV6
   unsigned long uarg;
+#endif
   curl_off_t bigsize;
 
   switch(option) {
@@ -895,7 +890,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       ;
     else
 #endif
-#if !defined(USE_NGHTTP2) && !defined(USE_HYPER)
+#ifndef USE_HTTP2
     if(arg >= CURL_HTTP_VERSION_2)
       return CURLE_UNSUPPORTED_PROTOCOL;
 #else
@@ -1650,24 +1645,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      */
     data->set.seek_client = va_arg(param, void *);
     break;
-  case CURLOPT_CONV_FROM_NETWORK_FUNCTION:
-    /*
-     * "Convert from network encoding" callback
-     */
-    data->set.convfromnetwork = va_arg(param, curl_conv_callback);
-    break;
-  case CURLOPT_CONV_TO_NETWORK_FUNCTION:
-    /*
-     * "Convert to network encoding" callback
-     */
-    data->set.convtonetwork = va_arg(param, curl_conv_callback);
-    break;
-  case CURLOPT_CONV_FROM_UTF8_FUNCTION:
-    /*
-     * "Convert from UTF-8 encoding" callback
-     */
-    data->set.convfromutf8 = va_arg(param, curl_conv_callback);
-    break;
   case CURLOPT_IOCTLFUNCTION:
     /*
      * I/O control callback. Might be NULL.
@@ -2558,6 +2535,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
 #endif
 
+#ifdef ENABLE_IPV6
   case CURLOPT_ADDRESS_SCOPE:
     /*
      * Use this scope id when using IPv6
@@ -2571,6 +2549,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 #endif
     data->set.scope_id = (unsigned int)uarg;
     break;
+#endif
 
   case CURLOPT_PROTOCOLS:
     /* set the bitmask for the protocols that are allowed to be used for the
@@ -2623,7 +2602,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 #endif
 
   case CURLOPT_SASL_AUTHZID:
-    /* Authorisation identity (identity to act as) */
+    /* Authorization identity (identity to act as) */
     result = Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID],
                             va_arg(param, char *));
     break;
@@ -2769,30 +2748,30 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype)
       data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
     break;
+#ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_TLSAUTH_USERNAME:
     result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
                             va_arg(param, char *));
-#ifndef CURL_DISABLE_PROXY
     if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
        !data->set.proxy_ssl.authtype)
       data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
-#endif
     break;
+#endif
   case CURLOPT_TLSAUTH_PASSWORD:
     result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD],
                             va_arg(param, char *));
     if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype)
       data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
     break;
+#ifndef CURL_DISABLE_PROXY
   case CURLOPT_PROXY_TLSAUTH_PASSWORD:
     result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
                             va_arg(param, char *));
-#ifndef CURL_DISABLE_PROXY
     if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
        !data->set.proxy_ssl.authtype)
       data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
-#endif
     break;
+#endif
   case CURLOPT_TLSAUTH_TYPE:
     argptr = va_arg(param, char *);
     if(!argptr ||

+ 9 - 3
lib/sha256.c

@@ -6,7 +6,7 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2017, Florin Petriuc, <[email protected]>
- * Copyright (C) 2018 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2022, 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
@@ -40,7 +40,7 @@
 
 #include <openssl/opensslv.h>
 
-#if (OPENSSL_VERSION_NUMBER >= 0x0090700fL)
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL)
 #define USE_OPENSSL_SHA256
 #endif
 
@@ -69,8 +69,14 @@
 
 #if defined(USE_OPENSSL_SHA256)
 
-/* When OpenSSL is available we use the SHA256-function from OpenSSL */
+/* When OpenSSL or wolfSSL is available is available we use their
+ * SHA256-functions.
+ */
+#if defined(USE_OPENSSL)
 #include <openssl/evp.h>
+#elif defined(USE_WOLFSSL)
+#include <wolfssl/openssl/evp.h>
+#endif
 
 #include "curl_memory.h"
 

+ 11 - 12
lib/smb.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2016 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2016 - 2022, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2014, Bill Nagel <[email protected]>, Exacq Technologies
  *
  * This software is licensed as described in the file COPYING, which
@@ -262,7 +262,7 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
   (void) done;
 
   /* Check we have a username and password to authenticate with */
-  if(!conn->bits.user_passwd)
+  if(!data->state.aptr.user)
     return CURLE_LOGIN_DENIED;
 
   /* Initialize the connection state */
@@ -299,6 +299,7 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done)
 static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
 {
   struct connectdata *conn = data->conn;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   struct smb_conn *smbc = &conn->proto.smbc;
   char *buf = smbc->recv_buf;
   ssize_t bytes_read;
@@ -307,7 +308,7 @@ static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
   size_t len = MAX_MESSAGE_SIZE - smbc->got;
   CURLcode result;
 
-  result = Curl_read(data, FIRSTSOCKET, buf + smbc->got, len, &bytes_read);
+  result = Curl_read(data, sockfd, buf + smbc->got, len, &bytes_read);
   if(result)
     return result;
 
@@ -377,11 +378,12 @@ static CURLcode smb_send(struct Curl_easy *data, ssize_t len,
                          size_t upload_size)
 {
   struct connectdata *conn = data->conn;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   struct smb_conn *smbc = &conn->proto.smbc;
   ssize_t bytes_written;
   CURLcode result;
 
-  result = Curl_write(data, FIRSTSOCKET, data->state.ulbuf,
+  result = Curl_write(data, sockfd, data->state.ulbuf,
                       len, &bytes_written);
   if(result)
     return result;
@@ -399,6 +401,7 @@ static CURLcode smb_send(struct Curl_easy *data, ssize_t len,
 static CURLcode smb_flush(struct Curl_easy *data)
 {
   struct connectdata *conn = data->conn;
+  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   struct smb_conn *smbc = &conn->proto.smbc;
   ssize_t bytes_written;
   ssize_t len = smbc->send_size - smbc->sent;
@@ -407,7 +410,7 @@ static CURLcode smb_flush(struct Curl_easy *data)
   if(!smbc->send_size)
     return CURLE_OK;
 
-  result = Curl_write(data, FIRSTSOCKET,
+  result = Curl_write(data, sockfd,
                       data->state.ulbuf + smbc->sent,
                       len, &bytes_written);
   if(result)
@@ -459,14 +462,10 @@ static CURLcode smb_send_setup(struct Curl_easy *data)
   if(byte_count > sizeof(msg.bytes))
     return CURLE_FILESIZE_EXCEEDED;
 
-  Curl_ntlm_core_mk_lm_hash(data, conn->passwd, lm_hash);
+  Curl_ntlm_core_mk_lm_hash(conn->passwd, lm_hash);
   Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm);
-#ifdef USE_NTRESPONSES
-  Curl_ntlm_core_mk_nt_hash(data, conn->passwd, nt_hash);
+  Curl_ntlm_core_mk_nt_hash(conn->passwd, nt_hash);
   Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt);
-#else
-  memset(nt, 0, sizeof(nt));
-#endif
 
   memset(&msg, 0, sizeof(msg));
   msg.word_count = SMB_WC_SETUP_ANDX;
@@ -989,7 +988,7 @@ static CURLcode smb_parse_url_path(struct Curl_easy *data,
   char *slash;
 
   /* URL decode the path */
-  CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &path, NULL,
+  CURLcode result = Curl_urldecode(data->state.up.path, 0, &path, NULL,
                                    REJECT_CTRL);
   if(result)
     return result;

+ 9 - 10
lib/smtp.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -492,7 +492,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
   /* Check we have enough data to authenticate with, and the
      server supports authentication, and end the connect phase if not */
   if(!smtpc->auth_supported ||
-     !Curl_sasl_can_authenticate(&smtpc->sasl, conn)) {
+     !Curl_sasl_can_authenticate(&smtpc->sasl, data)) {
     state(data, SMTP_STOP);
     return result;
   }
@@ -505,7 +505,7 @@ static CURLcode smtp_perform_authentication(struct Curl_easy *data)
       state(data, SMTP_AUTH);
     else {
       /* Other mechanisms not supported */
-      infof(data, "No known authentication mechanisms supported!");
+      infof(data, "No known authentication mechanisms supported");
       result = CURLE_LOGIN_DENIED;
     }
   }
@@ -698,7 +698,7 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data)
                                        NULL, MIMESTRATEGY_MAIL);
 
     if(!result)
-      if(!Curl_checkheaders(data, "Mime-Version"))
+      if(!Curl_checkheaders(data, STRCONST("Mime-Version")))
         result = Curl_mime_add_header(&data->set.mimepost.curlheaders,
                                       "Mime-Version: 1.0");
 
@@ -1037,7 +1037,7 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, int smtpcode,
   if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) ||
      (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) {
     failf(data, "Command failed: %d", smtpcode);
-    result = CURLE_RECV_ERROR;
+    result = CURLE_WEIRD_SERVER_REPLY;
   }
   else {
     /* Temporarily add the LF character back and send as body to the client */
@@ -1182,7 +1182,7 @@ static CURLcode smtp_state_postdata_resp(struct Curl_easy *data,
   (void)instate; /* no use for this yet */
 
   if(smtpcode != 250)
-    result = CURLE_RECV_ERROR;
+    result = CURLE_WEIRD_SERVER_REPLY;
 
   /* End of DONE phase */
   state(data, SMTP_STOP);
@@ -1724,8 +1724,7 @@ static CURLcode smtp_parse_url_path(struct Curl_easy *data)
   }
 
   /* URL decode the path and use it as the domain in our EHLO */
-  return Curl_urldecode(data, path, 0, &smtpc->domain, NULL,
-                        REJECT_CTRL);
+  return Curl_urldecode(path, 0, &smtpc->domain, NULL, REJECT_CTRL);
 }
 
 /***********************************************************************
@@ -1742,7 +1741,7 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data)
 
   /* URL decode the custom request */
   if(custom)
-    result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, REJECT_CTRL);
+    result = Curl_urldecode(custom, 0, &smtp->custom, NULL, REJECT_CTRL);
 
   return result;
 }
@@ -1841,7 +1840,7 @@ CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread)
 
     scratch = newscratch = malloc(2 * data->set.upload_buffer_size);
     if(!newscratch) {
-      failf(data, "Failed to alloc scratch buffer!");
+      failf(data, "Failed to alloc scratch buffer");
 
       return CURLE_OUT_OF_MEMORY;
     }

+ 1 - 1
lib/socks.c

@@ -326,7 +326,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
     if(proxy_user) {
       size_t plen = strlen(proxy_user);
       if(plen >= (size_t)data->set.buffer_size - 8) {
-        failf(data, "Too long SOCKS proxy user name, can't use!");
+        failf(data, "Too long SOCKS proxy user name, can't use");
         return CURLPX_LONG_USER;
       }
       /* copy the proxy name WITH trailing zero */

+ 2 - 2
lib/socks.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -69,7 +69,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_name,
 
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
 /*
- * This function handles the SOCKS5 GSS-API negotiation and initialisation
+ * This function handles the SOCKS5 GSS-API negotiation and initialization
  */
 CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
                                       struct Curl_easy *data);

+ 15 - 125
lib/strcase.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -28,142 +28,25 @@
 
 static char raw_tolower(char in);
 
-/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
-   its behavior is altered by the current locale. */
+/* Portable, consistent toupper. Do not use toupper() because its behavior is
+   altered by the current locale. */
 char Curl_raw_toupper(char in)
 {
-#if !defined(CURL_DOES_CONVERSIONS)
   if(in >= 'a' && in <= 'z')
     return (char)('A' + in - 'a');
-#else
-  switch(in) {
-  case 'a':
-    return 'A';
-  case 'b':
-    return 'B';
-  case 'c':
-    return 'C';
-  case 'd':
-    return 'D';
-  case 'e':
-    return 'E';
-  case 'f':
-    return 'F';
-  case 'g':
-    return 'G';
-  case 'h':
-    return 'H';
-  case 'i':
-    return 'I';
-  case 'j':
-    return 'J';
-  case 'k':
-    return 'K';
-  case 'l':
-    return 'L';
-  case 'm':
-    return 'M';
-  case 'n':
-    return 'N';
-  case 'o':
-    return 'O';
-  case 'p':
-    return 'P';
-  case 'q':
-    return 'Q';
-  case 'r':
-    return 'R';
-  case 's':
-    return 'S';
-  case 't':
-    return 'T';
-  case 'u':
-    return 'U';
-  case 'v':
-    return 'V';
-  case 'w':
-    return 'W';
-  case 'x':
-    return 'X';
-  case 'y':
-    return 'Y';
-  case 'z':
-    return 'Z';
-  }
-#endif
-
   return in;
 }
 
 
-/* Portable, consistent tolower (remember EBCDIC). Do not use tolower() because
-   its behavior is altered by the current locale. */
+/* Portable, consistent tolower. Do not use tolower() because its behavior is
+   altered by the current locale. */
 static char raw_tolower(char in)
 {
-#if !defined(CURL_DOES_CONVERSIONS)
   if(in >= 'A' && in <= 'Z')
     return (char)('a' + in - 'A');
-#else
-  switch(in) {
-  case 'A':
-    return 'a';
-  case 'B':
-    return 'b';
-  case 'C':
-    return 'c';
-  case 'D':
-    return 'd';
-  case 'E':
-    return 'e';
-  case 'F':
-    return 'f';
-  case 'G':
-    return 'g';
-  case 'H':
-    return 'h';
-  case 'I':
-    return 'i';
-  case 'J':
-    return 'j';
-  case 'K':
-    return 'k';
-  case 'L':
-    return 'l';
-  case 'M':
-    return 'm';
-  case 'N':
-    return 'n';
-  case 'O':
-    return 'o';
-  case 'P':
-    return 'p';
-  case 'Q':
-    return 'q';
-  case 'R':
-    return 'r';
-  case 'S':
-    return 's';
-  case 'T':
-    return 't';
-  case 'U':
-    return 'u';
-  case 'V':
-    return 'v';
-  case 'W':
-    return 'w';
-  case 'X':
-    return 'x';
-  case 'Y':
-    return 'y';
-  case 'Z':
-    return 'z';
-  }
-#endif
-
   return in;
 }
 
-
 /*
  * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is
  * meant to be locale independent and only compare strings we know are safe
@@ -171,9 +54,6 @@ static char raw_tolower(char in)
  * https://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for some
  * further explanation to why this function is necessary.
  *
- * The function is capable of comparing a-z case insensitively even for
- * non-ascii.
- *
  * @unittest: 1301
  */
 
@@ -251,6 +131,16 @@ void Curl_strntolower(char *dest, const char *src, size_t n)
   } while(*src++ && --n);
 }
 
+/* Compare case-sensitive NUL-terminated strings, taking care of possible
+ * null pointers. Return true if arguments match.
+ */
+bool Curl_safecmp(char *a, char *b)
+{
+  if(a && b)
+    return !strcmp(a, b);
+  return !a && !b;
+}
+
 /* --- public functions --- */
 
 int curl_strequal(const char *first, const char *second)

+ 8 - 5
lib/strcase.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -28,8 +28,9 @@
  * Only "raw" case insensitive strings. This is meant to be locale independent
  * and only compare strings we know are safe for this.
  *
- * The function is capable of comparing a-z case insensitively even for
- * non-ascii.
+ * The function is capable of comparing a-z case insensitively.
+ *
+ * Result is 1 if text matches and 0 if not.
  */
 
 #define strcasecompare(a,b) Curl_strcasecompare(a,b)
@@ -42,10 +43,12 @@ int Curl_strncasecompare(const char *first, const char *second, size_t max);
 char Curl_raw_toupper(char in);
 
 /* checkprefix() is a shorter version of the above, used when the first
-   argument is zero-byte terminated */
-#define checkprefix(a,b)    curl_strnequal(a,b,strlen(a))
+   argument is the string literal */
+#define checkprefix(a,b)    curl_strnequal(b, STRCONST(a))
 
 void Curl_strntoupper(char *dest, const char *src, size_t n);
 void Curl_strntolower(char *dest, const char *src, size_t n);
 
+bool Curl_safecmp(char *a, char *b);
+
 #endif /* HEADER_CURL_STRCASE_H */

+ 5 - 24
lib/strerror.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2004 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2004 - 2022, 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
@@ -24,12 +24,9 @@
 
 #ifdef HAVE_STRERROR_R
 #  if (!defined(HAVE_POSIX_STRERROR_R) && \
-       !defined(HAVE_GLIBC_STRERROR_R) && \
-       !defined(HAVE_VXWORKS_STRERROR_R)) || \
-      (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \
-      (defined(HAVE_GLIBC_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \
+       !defined(HAVE_GLIBC_STRERROR_R)) || \
       (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R))
-#    error "strerror_r MUST be either POSIX, glibc or vxworks-style"
+#    error "strerror_r MUST be either POSIX, glibc style"
 #  endif
 #endif
 
@@ -224,9 +221,6 @@ curl_easy_strerror(CURLcode error)
   case CURLE_BAD_CONTENT_ENCODING:
     return "Unrecognized or bad HTTP Content or Transfer-Encoding";
 
-  case CURLE_LDAP_INVALID_URL:
-    return "Invalid LDAP URL";
-
   case CURLE_FILESIZE_EXCEEDED:
     return "Maximum file size exceeded";
 
@@ -272,9 +266,6 @@ curl_easy_strerror(CURLcode error)
   case CURLE_CONV_FAILED:
     return "Conversion failed";
 
-  case CURLE_CONV_REQD:
-    return "Caller must register CURLOPT_CONV_ callback options";
-
   case CURLE_REMOTE_FILE_NOT_FOUND:
     return "Remote file not found";
 
@@ -337,6 +328,8 @@ curl_easy_strerror(CURLcode error)
   case CURLE_OBSOLETE50:
   case CURLE_OBSOLETE51:
   case CURLE_OBSOLETE57:
+  case CURLE_OBSOLETE62:
+  case CURLE_OBSOLETE76:
   case CURL_LAST:
     break;
   }
@@ -883,18 +876,6 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
     else
       msnprintf(buf, max, "Unknown error %d", err);
   }
-#elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)
- /*
-  * The vxworks-style strerror_r() does use the buffer we pass to the function.
-  * The buffer size should be at least NAME_MAX (256)
-  */
-  {
-    char buffer[256];
-    if(OK == strerror_r(err, buffer))
-      strncpy(buf, buffer, max);
-    else
-      msnprintf(buf, max, "Unknown error %d", err);
-  }
 #else
   {
     /* !checksrc! disable STRERROR 1 */

+ 3 - 3
lib/telnet.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -687,7 +687,7 @@ static void printsub(struct Curl_easy *data,
             infof(data, "%s", CURL_TELCMD(j));
           else
             infof(data, "%d", j);
-          infof(data, ", not IAC SE!) ");
+          infof(data, ", not IAC SE) ");
         }
       }
       length -= 2;
@@ -781,7 +781,7 @@ static CURLcode check_telnet_options(struct Curl_easy *data)
 
   /* Add the user name as an environment variable if it
      was given on the command line */
-  if(conn->bits.user_passwd) {
+  if(data->state.aptr.user) {
     msnprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
     beg = curl_slist_append(tn->telnet_vars, option_arg);
     if(!beg) {

+ 4 - 4
lib/tftp.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2022, 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
@@ -327,7 +327,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
 
     infof(data, "got option=(%s) value=(%s)", option, value);
 
-    if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
+    if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
       long blksize;
 
       blksize = strtol(value, NULL, 10);
@@ -359,7 +359,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
       infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
             state->blksize, "requested", state->requested_blksize);
     }
-    else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
+    else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
       long tsize = 0;
 
       tsize = strtol(value, NULL, 10);
@@ -463,7 +463,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
     /* As RFC3617 describes the separator slash is not actually part of the
        file name so we skip the always-present first letter of the path
        string. */
-    result = Curl_urldecode(data, &state->data->state.up.path[1], 0,
+    result = Curl_urldecode(&state->data->state.up.path[1], 0,
                             &filename, NULL, REJECT_ZERO);
     if(result)
       return result;

+ 84 - 0
lib/timediff.c

@@ -0,0 +1,84 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "timediff.h"
+
+/*
+ * Converts number of milliseconds into a timeval structure.
+ *
+ * Return values:
+ *    NULL IF tv is NULL or ms < 0 (eg. no timeout -> blocking select)
+ *    tv with 0 in both fields IF ms == 0 (eg. 0ms timeout -> polling select)
+ *    tv with converted fields IF ms > 0 (eg. >0ms timeout -> waiting select)
+ */
+struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms)
+{
+  if(!tv)
+    return NULL;
+
+  if(ms < 0)
+    return NULL;
+
+  if(ms > 0) {
+    timediff_t tv_sec = ms / 1000;
+    timediff_t tv_usec = (ms % 1000) * 1000; /* max=999999 */
+#ifdef HAVE_SUSECONDS_T
+#if TIMEDIFF_T_MAX > TIME_T_MAX
+    /* tv_sec overflow check in case time_t is signed */
+    if(tv_sec > TIME_T_MAX)
+      tv_sec = TIME_T_MAX;
+#endif
+    tv->tv_sec = (time_t)tv_sec;
+    tv->tv_usec = (suseconds_t)tv_usec;
+#elif defined(WIN32) /* maybe also others in the future */
+#if TIMEDIFF_T_MAX > LONG_MAX
+    /* tv_sec overflow check on Windows there we know it is long */
+    if(tv_sec > LONG_MAX)
+      tv_sec = LONG_MAX;
+#endif
+    tv->tv_sec = (long)tv_sec;
+    tv->tv_usec = (long)tv_usec;
+#else
+#if TIMEDIFF_T_MAX > INT_MAX
+    /* tv_sec overflow check in case time_t is signed */
+    if(tv_sec > INT_MAX)
+      tv_sec = INT_MAX;
+#endif
+    tv->tv_sec = (int)tv_sec;
+    tv->tv_usec = (int)tv_usec;
+#endif
+  }
+  else {
+    tv->tv_sec = 0;
+    tv->tv_usec = 0;
+  }
+
+  return tv;
+}
+
+/*
+ * Converts a timeval structure into number of milliseconds.
+ */
+timediff_t curlx_tvtoms(struct timeval *tv)
+{
+  return (tv->tv_sec*1000) + (timediff_t)(((double)tv->tv_usec)/1000.0);
+}

+ 50 - 0
lib/timediff.h

@@ -0,0 +1,50 @@
+#ifndef HEADER_CURL_TIMEDIFF_H
+#define HEADER_CURL_TIMEDIFF_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2022, Daniel Stenberg, <[email protected]>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+/* Use a larger type even for 32 bit time_t systems so that we can keep
+   microsecond accuracy in it */
+typedef curl_off_t timediff_t;
+#define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T
+
+#define TIMEDIFF_T_MAX CURL_OFF_T_MAX
+#define TIMEDIFF_T_MIN CURL_OFF_T_MIN
+
+/*
+ * Converts number of milliseconds into a timeval structure.
+ *
+ * Return values:
+ *    NULL IF tv is NULL or ms < 0 (eg. no timeout -> blocking select)
+ *    tv with 0 in both fields IF ms == 0 (eg. 0ms timeout -> polling select)
+ *    tv with converted fields IF ms > 0 (eg. >0ms timeout -> waiting select)
+ */
+struct timeval *curlx_mstotv(struct timeval *tv, timediff_t ms);
+
+/*
+ * Converts a timeval structure into number of milliseconds.
+ */
+timediff_t curlx_tvtoms(struct timeval *tv);
+
+#endif /* HEADER_CURL_TIMEDIFF_H */

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff