Pārlūkot izejas kodu

curl 2021-02-03 (2f33be81)

Code extracted from:

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

at commit 2f33be817cbce6ad7a36f27dd7ada9219f13584c (curl-7_75_0).
Curl Upstream 4 gadi atpakaļ
vecāks
revīzija
076b3219f5
100 mainītis faili ar 4948 papildinājumiem un 2646 dzēšanām
  1. 8 2
      CMakeLists.txt
  2. 1 1
      COPYING
  3. 11 3
      include/curl/curl.h
  4. 3 3
      include/curl/curlver.h
  5. 1 0
      include/curl/typecheck-gcc.h
  6. 299 52
      lib/Makefile.inc
  7. 72 72
      lib/asyn-ares.c
  8. 72 76
      lib/asyn-thread.c
  9. 7 7
      lib/asyn.h
  10. 908 0
      lib/c-hyper.c
  11. 56 0
      lib/c-hyper.h
  12. 23 20
      lib/conncache.c
  13. 27 15
      lib/conncache.h
  14. 139 97
      lib/connect.c
  15. 16 9
      lib/connect.h
  16. 84 88
      lib/content_encoding.c
  17. 7 7
      lib/content_encoding.h
  18. 9 0
      lib/cookie.c
  19. 3 3
      lib/cookie.h
  20. 2 2
      lib/curl_addrinfo.c
  21. 5 1
      lib/curl_config.h.cmake
  22. 5 1
      lib/curl_gssapi.c
  23. 4 4
      lib/curl_krb5.h
  24. 16 13
      lib/curl_ntlm_wb.c
  25. 5 3
      lib/curl_ntlm_wb.h
  26. 4 5
      lib/curl_path.c
  27. 2 2
      lib/curl_path.h
  28. 2 3
      lib/curl_range.c
  29. 2 3
      lib/curl_range.h
  30. 28 20
      lib/curl_rtmp.c
  31. 18 18
      lib/curl_sasl.c
  32. 9 5
      lib/curl_sasl.h
  33. 3 0
      lib/curl_sha256.h
  34. 9 10
      lib/dict.c
  35. 53 43
      lib/doh.c
  36. 3 3
      lib/doh.h
  37. 36 10
      lib/easy.c
  38. 3 2
      lib/easyoptions.c
  39. 49 44
      lib/file.c
  40. 5 5
      lib/formdata.h
  41. 202 181
      lib/ftp.c
  42. 7 7
      lib/ftp.h
  43. 15 15
      lib/ftplistparser.c
  44. 2 0
      lib/getinfo.c
  45. 60 9
      lib/gopher.c
  46. 3 0
      lib/gopher.h
  47. 1 1
      lib/hash.c
  48. 9 11
      lib/hostasyn.c
  49. 58 52
      lib/hostip.c
  50. 12 13
      lib/hostip.h
  51. 6 5
      lib/hostip4.c
  52. 13 17
      lib/hostip6.c
  53. 3 3
      lib/hsts.c
  54. 178 196
      lib/http.c
  55. 73 15
      lib/http.h
  56. 110 107
      lib/http2.c
  57. 8 7
      lib/http2.h
  58. 394 0
      lib/http_aws_sigv4.c
  59. 29 0
      lib/http_aws_sigv4.h
  60. 21 22
      lib/http_chunks.c
  61. 10 11
      lib/http_chunks.h
  62. 4 6
      lib/http_digest.c
  63. 4 3
      lib/http_digest.h
  64. 10 13
      lib/http_negotiate.c
  65. 5 4
      lib/http_negotiate.h
  66. 17 17
      lib/http_ntlm.c
  67. 3 3
      lib/http_ntlm.h
  68. 312 74
      lib/http_proxy.c
  69. 3 3
      lib/http_proxy.h
  70. 183 170
      lib/imap.c
  71. 55 51
      lib/krb5.c
  72. 40 38
      lib/ldap.c
  73. 2 1
      lib/mime.c
  74. 2 2
      lib/mime.h
  75. 83 70
      lib/mqtt.c
  76. 107 110
      lib/multi.c
  77. 6 2
      lib/multihandle.h
  78. 2 2
      lib/multiif.h
  79. 49 43
      lib/openldap.c
  80. 33 33
      lib/pingpong.c
  81. 26 16
      lib/pingpong.h
  82. 175 166
      lib/pop3.c
  83. 3 3
      lib/pop3.h
  84. 8 12
      lib/progress.c
  85. 3 3
      lib/progress.h
  86. 9 6
      lib/quic.h
  87. 57 50
      lib/rtsp.c
  88. 6 2
      lib/rtsp.h
  89. 10 7
      lib/select.c
  90. 1 7
      lib/select.h
  91. 48 31
      lib/sendf.c
  92. 8 7
      lib/sendf.h
  93. 32 11
      lib/setopt.c
  94. 28 5
      lib/sha256.c
  95. 7 2
      lib/share.c
  96. 5 1
      lib/share.h
  97. 143 118
      lib/smb.c
  98. 166 160
      lib/smtp.c
  99. 3 3
      lib/smtp.h
  100. 67 67
      lib/socks.c

+ 8 - 2
CMakeLists.txt

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
 #
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
@@ -337,6 +337,7 @@ if(WIN32 OR CMAKE_USE_SECTRANSP OR CMAKE_USE_SCHANNEL OR CMAKE_USE_MBEDTLS OR CM
   set(openssl_default OFF)
 endif()
 option(CMAKE_USE_OPENSSL "Use OpenSSL code. Experimental" ${openssl_default})
+option(CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG "Disable automatic loading of OpenSSL configuration" OFF)
 
 count_true(enabled_ssl_options_count
   CMAKE_USE_SCHANNEL
@@ -618,7 +619,11 @@ if(NOT CURL_DISABLE_LDAPS)
 endif()
 
 # Check for idn
-check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2)
+option(USE_LIBIDN2 "Use libidn2 for IDN support" ON)
+set(HAVE_LIBIDN2 OFF)
+if(USE_LIBIDN2)
+  check_library_exists_concat("idn2" idn2_lookup_ul HAVE_LIBIDN2)
+endif()
 
 # Check for symbol dlopen (same as HAVE_LIBDL)
 check_library_exists("${CURL_LIBS}" dlopen "" HAVE_DLOPEN)
@@ -1401,6 +1406,7 @@ _add_if("LDAPS"         NOT CURL_DISABLE_LDAPS AND
 _add_if("DICT"          NOT CURL_DISABLE_DICT)
 _add_if("TFTP"          NOT CURL_DISABLE_TFTP)
 _add_if("GOPHER"        NOT CURL_DISABLE_GOPHER)
+_add_if("GOPHERS"       NOT CURL_DISABLE_GOPHER AND SSL_ENABLED)
 _add_if("POP3"          NOT CURL_DISABLE_POP3)
 _add_if("POP3S"         NOT CURL_DISABLE_POP3 AND SSL_ENABLED)
 _add_if("IMAP"          NOT CURL_DISABLE_IMAP)

+ 1 - 1
COPYING

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

+ 11 - 3
include/curl/curl.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -787,6 +787,7 @@ typedef enum {
 #define CURLAUTH_DIGEST_IE    (((unsigned long)1)<<4)
 #define CURLAUTH_NTLM_WB      (((unsigned long)1)<<5)
 #define CURLAUTH_BEARER       (((unsigned long)1)<<6)
+#define CURLAUTH_AWS_SIGV4    (((unsigned long)1)<<7)
 #define CURLAUTH_ONLY         (((unsigned long)1)<<31)
 #define CURLAUTH_ANY          (~CURLAUTH_DIGEST_IE)
 #define CURLAUTH_ANYSAFE      (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
@@ -1015,6 +1016,7 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy,
 #define CURLPROTO_SMB    (1<<26)
 #define CURLPROTO_SMBS   (1<<27)
 #define CURLPROTO_MQTT   (1<<28)
+#define CURLPROTO_GOPHERS (1<<29)
 #define CURLPROTO_ALL    (~0) /* enable everything */
 
 /* long may be 32 or 64 bits, but we should never depend on anything else
@@ -1614,7 +1616,7 @@ typedef enum {
   CURLOPT(CURLOPT_NEW_FILE_PERMS, CURLOPTTYPE_LONG, 159),
   CURLOPT(CURLOPT_NEW_DIRECTORY_PERMS, CURLOPTTYPE_LONG, 160),
 
-  /* Set the behaviour of POST when redirecting. Values must be set to one
+  /* Set the behavior of POST when redirecting. Values must be set to one
      of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
   CURLOPT(CURLOPT_POSTREDIR, CURLOPTTYPE_VALUES, 161),
 
@@ -2073,6 +2075,9 @@ typedef enum {
   CURLOPT(CURLOPT_HSTSWRITEFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 303),
   CURLOPT(CURLOPT_HSTSWRITEDATA, CURLOPTTYPE_CBPOINT, 304),
 
+  /* Parameters for V4 signature */
+  CURLOPT(CURLOPT_AWS_SIGV4, CURLOPTTYPE_STRINGPOINT, 305),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
@@ -2849,6 +2854,7 @@ typedef enum {
   CURLVERSION_SIXTH,
   CURLVERSION_SEVENTH,
   CURLVERSION_EIGHTH,
+  CURLVERSION_NINTH,
   CURLVERSION_LAST /* never actually use this */
 } CURLversion;
 
@@ -2857,7 +2863,7 @@ typedef enum {
    meant to be a built-in version number for what kind of struct the caller
    expects. If the struct ever changes, we redefine the NOW to another enum
    from above. */
-#define CURLVERSION_NOW CURLVERSION_EIGHTH
+#define CURLVERSION_NOW CURLVERSION_NINTH
 
 struct curl_version_info_data {
   CURLversion age;          /* age of the returned struct */
@@ -2908,6 +2914,8 @@ struct curl_version_info_data {
                                   (MAJOR << 24) | (MINOR << 12) | PATCH */
   const char *zstd_version; /* human readable string. */
 
+  /* These fields were added in CURLVERSION_NINTH */
+  const char *hyper_version; /* human readable string. */
 };
 typedef struct curl_version_info_data curl_version_info_data;
 

+ 3 - 3
include/curl/curlver.h

@@ -30,12 +30,12 @@
 
 /* This is the version number of the libcurl package from which this header
    file origins: */
-#define LIBCURL_VERSION "7.74.0-DEV"
+#define LIBCURL_VERSION "7.75.0-DEV"
 
 /* The numeric version number is also available "in parts" by using these
    defines: */
 #define LIBCURL_VERSION_MAJOR 7
-#define LIBCURL_VERSION_MINOR 74
+#define LIBCURL_VERSION_MINOR 75
 #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 0x074a00
+#define LIBCURL_VERSION_NUM 0x074b00
 
 /*
  * This is the date and time when the full source package was created. The

+ 1 - 0
include/curl/typecheck-gcc.h

@@ -334,6 +334,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t,
    (option) == CURLOPT_URL ||                                                 \
    (option) == CURLOPT_USERAGENT ||                                           \
    (option) == CURLOPT_USERNAME ||                                            \
+   (option) == CURLOPT_AWS_SIGV4 ||                                           \
    (option) == CURLOPT_USERPWD ||                                             \
    (option) == CURLOPT_XOAUTH2_BEARER ||                                      \
    (option) == CURLOPT_SSL_EC_CURVES ||                                       \

+ 299 - 52
lib/Makefile.inc

@@ -5,7 +5,7 @@
 #                            | (__| |_| |  _ <| |___
 #                             \___|\___/|_| \_\_____|
 #
-# Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+# Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
 #
 # This software is licensed as described in the file COPYING, which
 # you should have received as part of this distribution. The terms
@@ -20,67 +20,314 @@
 #
 ###########################################################################
 
-LIB_VAUTH_CFILES = vauth/cleartext.c vauth/cram.c vauth/digest.c             \
-  vauth/digest_sspi.c vauth/krb5_gssapi.c vauth/krb5_sspi.c vauth/ntlm.c     \
-  vauth/ntlm_sspi.c vauth/oauth2.c vauth/spnego_gssapi.c vauth/spnego_sspi.c \
+LIB_VAUTH_CFILES =      \
+  vauth/cleartext.c     \
+  vauth/cram.c          \
+  vauth/digest.c        \
+  vauth/digest_sspi.c   \
+  vauth/krb5_gssapi.c   \
+  vauth/krb5_sspi.c     \
+  vauth/ntlm.c          \
+  vauth/ntlm_sspi.c     \
+  vauth/oauth2.c        \
+  vauth/spnego_gssapi.c \
+  vauth/spnego_sspi.c   \
   vauth/vauth.c
 
-LIB_VAUTH_HFILES = vauth/digest.h vauth/ntlm.h vauth/vauth.h
+LIB_VAUTH_HFILES =      \
+  vauth/digest.h        \
+  vauth/ntlm.h          \
+  vauth/vauth.h
 
-LIB_VTLS_CFILES = vtls/bearssl.c vtls/gskit.c vtls/gtls.c vtls/keylog.c  \
-  vtls/mbedtls.c vtls/mbedtls_threadlock.c vtls/mesalink.c vtls/nss.c    \
-  vtls/openssl.c vtls/schannel.c vtls/schannel_verify.c vtls/sectransp.c \
-  vtls/vtls.c vtls/wolfssl.c
+LIB_VTLS_CFILES =           \
+  vtls/bearssl.c            \
+  vtls/gskit.c              \
+  vtls/gtls.c               \
+  vtls/keylog.c             \
+  vtls/mbedtls.c            \
+  vtls/mbedtls_threadlock.c \
+  vtls/mesalink.c           \
+  vtls/nss.c                \
+  vtls/openssl.c            \
+  vtls/schannel.c           \
+  vtls/schannel_verify.c    \
+  vtls/sectransp.c          \
+  vtls/vtls.c               \
+  vtls/wolfssl.c
 
-LIB_VTLS_HFILES = vtls/bearssl.h vtls/gskit.h vtls/gtls.h vtls/keylog.h      \
-  vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/mesalink.h vtls/nssg.h       \
-  vtls/openssl.h vtls/schannel.h vtls/sectransp.h vtls/vtls.h vtls/wolfssl.h
+LIB_VTLS_HFILES =           \
+  vtls/bearssl.h            \
+  vtls/gskit.h              \
+  vtls/gtls.h               \
+  vtls/keylog.h             \
+  vtls/mbedtls.h            \
+  vtls/mbedtls_threadlock.h \
+  vtls/mesalink.h           \
+  vtls/nssg.h               \
+  vtls/openssl.h            \
+  vtls/schannel.h           \
+  vtls/sectransp.h          \
+  vtls/vtls.h               \
+  vtls/wolfssl.h
 
-LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c vquic/vquic.c
+LIB_VQUIC_CFILES = \
+  vquic/ngtcp2.c   \
+  vquic/quiche.c   \
+  vquic/vquic.c
 
-LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h vquic/vquic.h
+LIB_VQUIC_HFILES = \
+  vquic/ngtcp2.h   \
+  vquic/quiche.h   \
+  vquic/vquic.h
 
-LIB_VSSH_CFILES = vssh/libssh.c vssh/libssh2.c vssh/wolfssh.c
+LIB_VSSH_CFILES =  \
+  vssh/libssh.c    \
+  vssh/libssh2.c   \
+  vssh/wolfssh.c
 
-LIB_VSSH_HFILES = vssh/ssh.h
+LIB_VSSH_HFILES =  \
+  vssh/ssh.h
 
-LIB_CFILES = altsvc.c amigaos.c asyn-ares.c asyn-thread.c base64.c            \
-  conncache.c connect.c content_encoding.c cookie.c curl_addrinfo.c           \
-  curl_ctype.c curl_des.c curl_endian.c curl_fnmatch.c curl_get_line.c        \
-  curl_gethostname.c curl_gssapi.c curl_memrchr.c curl_multibyte.c            \
-  curl_ntlm_core.c curl_ntlm_wb.c curl_path.c curl_range.c curl_rtmp.c        \
-  curl_sasl.c curl_sspi.c curl_threads.c dict.c dotdot.c easy.c escape.c      \
-  file.c fileinfo.c formdata.c ftp.c url.c ftplistparser.c getenv.c getinfo.c \
-  gopher.c hash.c hmac.c hostasyn.c hostcheck.c hostip.c hostip4.c hostip6.c  \
-  hostsyn.c http.c http2.c http_chunks.c http_digest.c http_negotiate.c       \
-  http_ntlm.c http_proxy.c idn_win32.c if2ip.c imap.c inet_ntop.c inet_pton.c \
-  krb5.c ldap.c llist.c md4.c md5.c memdebug.c mime.c mprintf.c mqtt.c        \
-  multi.c netrc.c non-ascii.c nonblock.c openldap.c parsedate.c pingpong.c    \
-  pop3.c progress.c psl.c doh.c rand.c rename.c rtsp.c select.c               \
-  sendf.c setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \
-  socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c         \
-  strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c    \
-  transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c dynbuf.c     \
-  version_win32.c easyoptions.c easygetopt.c hsts.c
+LIB_CFILES =         \
+  altsvc.c           \
+  amigaos.c          \
+  asyn-ares.c        \
+  asyn-thread.c      \
+  base64.c           \
+  c-hyper.c          \
+  conncache.c        \
+  connect.c          \
+  content_encoding.c \
+  cookie.c           \
+  curl_addrinfo.c    \
+  curl_ctype.c       \
+  curl_des.c         \
+  curl_endian.c      \
+  curl_fnmatch.c     \
+  curl_get_line.c    \
+  curl_gethostname.c \
+  curl_gssapi.c      \
+  curl_memrchr.c     \
+  curl_multibyte.c   \
+  curl_ntlm_core.c   \
+  curl_ntlm_wb.c     \
+  curl_path.c        \
+  curl_range.c       \
+  curl_rtmp.c        \
+  curl_sasl.c        \
+  curl_sspi.c        \
+  curl_threads.c     \
+  dict.c             \
+  doh.c              \
+  dotdot.c           \
+  dynbuf.c           \
+  easy.c             \
+  easygetopt.c       \
+  easyoptions.c      \
+  escape.c           \
+  file.c             \
+  fileinfo.c         \
+  formdata.c         \
+  ftp.c              \
+  ftplistparser.c    \
+  getenv.c           \
+  getinfo.c          \
+  gopher.c           \
+  hash.c             \
+  hmac.c             \
+  hostasyn.c         \
+  hostcheck.c        \
+  hostip.c           \
+  hostip4.c          \
+  hostip6.c          \
+  hostsyn.c          \
+  hsts.c             \
+  http.c             \
+  http2.c            \
+  http_chunks.c      \
+  http_digest.c      \
+  http_negotiate.c   \
+  http_ntlm.c        \
+  http_proxy.c       \
+  http_aws_sigv4.c   \
+  idn_win32.c        \
+  if2ip.c            \
+  imap.c             \
+  inet_ntop.c        \
+  inet_pton.c        \
+  krb5.c             \
+  ldap.c             \
+  llist.c            \
+  md4.c              \
+  md5.c              \
+  memdebug.c         \
+  mime.c             \
+  mprintf.c          \
+  mqtt.c             \
+  multi.c            \
+  netrc.c            \
+  non-ascii.c        \
+  nonblock.c         \
+  openldap.c         \
+  parsedate.c        \
+  pingpong.c         \
+  pop3.c             \
+  progress.c         \
+  psl.c              \
+  rand.c             \
+  rename.c           \
+  rtsp.c             \
+  select.c           \
+  sendf.c            \
+  setopt.c           \
+  sha256.c           \
+  share.c            \
+  slist.c            \
+  smb.c              \
+  smtp.c             \
+  socketpair.c       \
+  socks.c            \
+  socks_gssapi.c     \
+  socks_sspi.c       \
+  speedcheck.c       \
+  splay.c            \
+  strcase.c          \
+  strdup.c           \
+  strerror.c         \
+  strtok.c           \
+  strtoofft.c        \
+  system_win32.c     \
+  telnet.c           \
+  tftp.c             \
+  timeval.c          \
+  transfer.c         \
+  url.c              \
+  urlapi.c           \
+  version.c          \
+  version_win32.c    \
+  warnless.c         \
+  wildcard.c         \
+  x509asn1.c
 
-LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h    \
-  content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h      \
-  curl_des.h curl_endian.h curl_fnmatch.h curl_get_line.h curl_gethostname.h  \
-  curl_gssapi.h curl_hmac.h curl_ldap.h curl_md4.h curl_md5.h curl_memory.h   \
-  curl_memrchr.h curl_multibyte.h curl_ntlm_core.h curl_ntlm_wb.h curl_path.h \
-  curl_printf.h curl_range.h curl_rtmp.h curl_sasl.h curl_krb5.h curl_setup.h \
-  curl_setup_once.h curl_sha256.h curl_sspi.h curl_threads.h curlx.h dict.h   \
-  dotdot.h easyif.h escape.h file.h fileinfo.h formdata.h ftp.h url.h         \
-  ftplistparser.h getinfo.h gopher.h hash.h hostcheck.h hostip.h http.h       \
-  http2.h http_chunks.h http_digest.h http_negotiate.h http_ntlm.h            \
-  http_proxy.h if2ip.h imap.h inet_ntop.h inet_pton.h llist.h memdebug.h      \
-  mime.h mqtt.h multihandle.h multiif.h netrc.h non-ascii.h nonblock.h        \
-  parsedate.h pingpong.h pop3.h progress.h psl.h doh.h quic.h rand.h rename.h \
-  rtsp.h select.h sendf.h setopt.h setup-vms.h share.h sigpipe.h slist.h      \
-  smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \
-  strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h     \
-  timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h           \
-  x509asn1.h dynbuf.h version_win32.h easyoptions.h hsts.h
+LIB_HFILES =         \
+  altsvc.h           \
+  amigaos.h          \
+  arpa_telnet.h      \
+  asyn.h             \
+  c-hyper.h          \
+  conncache.h        \
+  connect.h          \
+  content_encoding.h \
+  cookie.h           \
+  curl_addrinfo.h    \
+  curl_base64.h      \
+  curl_ctype.h       \
+  curl_des.h         \
+  curl_endian.h      \
+  curl_fnmatch.h     \
+  curl_get_line.h    \
+  curl_gethostname.h \
+  curl_gssapi.h      \
+  curl_hmac.h        \
+  curl_krb5.h        \
+  curl_ldap.h        \
+  curl_md4.h         \
+  curl_md5.h         \
+  curl_memory.h      \
+  curl_memrchr.h     \
+  curl_multibyte.h   \
+  curl_ntlm_core.h   \
+  curl_ntlm_wb.h     \
+  curl_path.h        \
+  curl_printf.h      \
+  curl_range.h       \
+  curl_rtmp.h        \
+  curl_sasl.h        \
+  curl_setup.h       \
+  curl_setup_once.h  \
+  curl_sha256.h      \
+  curl_sspi.h        \
+  curl_threads.h     \
+  curlx.h            \
+  dict.h             \
+  doh.h              \
+  dotdot.h           \
+  dynbuf.h           \
+  easyif.h           \
+  easyoptions.h      \
+  escape.h           \
+  file.h             \
+  fileinfo.h         \
+  formdata.h         \
+  ftp.h              \
+  ftplistparser.h    \
+  getinfo.h          \
+  gopher.h           \
+  hash.h             \
+  hostcheck.h        \
+  hostip.h           \
+  hsts.h             \
+  http.h             \
+  http2.h            \
+  http_chunks.h      \
+  http_digest.h      \
+  http_negotiate.h   \
+  http_ntlm.h        \
+  http_proxy.h       \
+  http_aws_sigv4.h   \
+  if2ip.h            \
+  imap.h             \
+  inet_ntop.h        \
+  inet_pton.h        \
+  llist.h            \
+  memdebug.h         \
+  mime.h             \
+  mqtt.h             \
+  multihandle.h      \
+  multiif.h          \
+  netrc.h            \
+  non-ascii.h        \
+  nonblock.h         \
+  parsedate.h        \
+  pingpong.h         \
+  pop3.h             \
+  progress.h         \
+  psl.h              \
+  quic.h             \
+  rand.h             \
+  rename.h           \
+  rtsp.h             \
+  select.h           \
+  sendf.h            \
+  setopt.h           \
+  setup-vms.h        \
+  share.h            \
+  sigpipe.h          \
+  slist.h            \
+  smb.h              \
+  smtp.h             \
+  sockaddr.h         \
+  socketpair.h       \
+  socks.h            \
+  speedcheck.h       \
+  splay.h            \
+  strcase.h          \
+  strdup.h           \
+  strerror.h         \
+  strtok.h           \
+  strtoofft.h        \
+  system_win32.h     \
+  telnet.h           \
+  tftp.h             \
+  timeval.h          \
+  transfer.h         \
+  url.h              \
+  urlapi-int.h       \
+  urldata.h          \
+  version_win32.h    \
+  warnless.h         \
+  wildcard.h         \
+  x509asn1.h
 
 LIB_RCFILES = libcurl.rc
 

+ 72 - 72
lib/asyn-ares.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -133,8 +133,8 @@ void Curl_resolver_global_cleanup(void)
 }
 
 
-static void Curl_ares_sock_state_cb(void *data, ares_socket_t socket_fd,
-                                    int readable, int writable)
+static void sock_state_cb(void *data, ares_socket_t socket_fd,
+                          int readable, int writable)
 {
   struct Curl_easy *easy = data;
   if(!readable && !writable) {
@@ -155,7 +155,7 @@ CURLcode Curl_resolver_init(struct Curl_easy *easy, void **resolver)
   int status;
   struct ares_options options;
   int optmask = ARES_OPT_SOCK_STATE_CB;
-  options.sock_state_cb = Curl_ares_sock_state_cb;
+  options.sock_state_cb = sock_state_cb;
   options.sock_state_cb_data = easy;
   status = ares_init_options((ares_channel*)resolver, &options, optmask);
   if(status != ARES_SUCCESS) {
@@ -204,22 +204,22 @@ static void destroy_async_data(struct Curl_async *async);
 /*
  * Cancel all possibly still on-going resolves for this connection.
  */
-void Curl_resolver_cancel(struct connectdata *conn)
+void Curl_resolver_cancel(struct Curl_easy *data)
 {
-  if(conn->data && conn->data->state.resolver)
-    ares_cancel((ares_channel)conn->data->state.resolver);
-  destroy_async_data(&conn->async);
+  if(data && data->state.async.resolver)
+    ares_cancel((ares_channel)data->state.async.resolver);
+  destroy_async_data(&data->state.async);
 }
 
 /*
  * We're equivalent to Curl_resolver_cancel() for the c-ares resolver.  We
  * never block.
  */
-void Curl_resolver_kill(struct connectdata *conn)
+void Curl_resolver_kill(struct Curl_easy *data)
 {
   /* We don't need to check the resolver state because we can be called safely
      at any time and we always do the same thing. */
-  Curl_resolver_cancel(conn);
+  Curl_resolver_cancel(data);
 }
 
 /*
@@ -253,25 +253,25 @@ static void destroy_async_data(struct Curl_async *async)
  * Returns: sockets-in-use-bitmap
  */
 
-int Curl_resolver_getsock(struct connectdata *conn,
+int Curl_resolver_getsock(struct Curl_easy *data,
                           curl_socket_t *socks)
 {
   struct timeval maxtime;
   struct timeval timebuf;
   struct timeval *timeout;
   long milli;
-  int max = ares_getsock((ares_channel)conn->data->state.resolver,
+  int max = ares_getsock((ares_channel)data->state.async.resolver,
                          (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
 
   maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
   maxtime.tv_usec = 0;
 
-  timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
+  timeout = ares_timeout((ares_channel)data->state.async.resolver, &maxtime,
                          &timebuf);
   milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
   if(milli == 0)
     milli += 10;
-  Curl_expire(conn->data, milli, EXPIRE_ASYNC_NAME);
+  Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
 
   return max;
 }
@@ -286,9 +286,8 @@ int Curl_resolver_getsock(struct connectdata *conn,
  * return number of sockets it worked on
  */
 
-static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
+static int waitperform(struct Curl_easy *data, timediff_t timeout_ms)
 {
-  struct Curl_easy *data = conn->data;
   int nfds;
   int bitmask;
   ares_socket_t socks[ARES_GETSOCK_MAXNUM];
@@ -296,7 +295,7 @@ static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
   int i;
   int num = 0;
 
-  bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
+  bitmask = ares_getsock((ares_channel)data->state.async.resolver, socks,
                          ARES_GETSOCK_MAXNUM);
 
   for(i = 0; i < ARES_GETSOCK_MAXNUM; i++) {
@@ -324,12 +323,12 @@ static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
   if(!nfds)
     /* Call ares_process() unconditonally here, even if we simply timed out
        above, as otherwise the ares name resolve won't timeout! */
-    ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
+    ares_process_fd((ares_channel)data->state.async.resolver, ARES_SOCKET_BAD,
                     ARES_SOCKET_BAD);
   else {
     /* move through the descriptors and ask for processing on them */
     for(i = 0; i < num; i++)
-      ares_process_fd((ares_channel)data->state.resolver,
+      ares_process_fd((ares_channel)data->state.async.resolver,
                       (pfd[i].revents & (POLLRDNORM|POLLIN))?
                       pfd[i].fd:ARES_SOCKET_BAD,
                       (pfd[i].revents & (POLLWRNORM|POLLOUT))?
@@ -345,17 +344,16 @@ static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
  *
  * Returns normal CURLcode errors.
  */
-CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
                                    struct Curl_dns_entry **dns)
 {
-  struct Curl_easy *data = conn->data;
-  struct thread_data *res = conn->async.tdata;
+  struct thread_data *res = data->state.async.tdata;
   CURLcode result = CURLE_OK;
 
   DEBUGASSERT(dns);
   *dns = NULL;
 
-  waitperform(conn, 0);
+  waitperform(data, 0);
 
   /* Now that we've checked for any last minute results above, see if there are
      any responses still pending when the EXPIRE_HAPPY_EYEBALLS_DNS timer
@@ -376,26 +374,27 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
        ARES_ECANCELLED synchronously for all pending responses.  This will
        leave us with res->num_pending == 0, which is perfect for the next
        block. */
-    ares_cancel((ares_channel)data->state.resolver);
+    ares_cancel((ares_channel)data->state.async.resolver);
     DEBUGASSERT(res->num_pending == 0);
   }
 
   if(res && !res->num_pending) {
-    (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
+    (void)Curl_addrinfo_callback(data, res->last_status, res->temp_ai);
     /* temp_ai ownership is moved to the connection, so we need not free-up
        them */
     res->temp_ai = NULL;
 
-    if(!conn->async.dns) {
+    if(!data->state.async.dns) {
       failf(data, "Could not resolve: %s (%s)",
-            conn->async.hostname, ares_strerror(conn->async.status));
-      result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
+            data->state.async.hostname,
+            ares_strerror(data->state.async.status));
+      result = data->conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
         CURLE_COULDNT_RESOLVE_HOST;
     }
     else
-      *dns = conn->async.dns;
+      *dns = data->state.async.dns;
 
-    destroy_async_data(&conn->async);
+    destroy_async_data(&data->state.async);
   }
 
   return result;
@@ -412,11 +411,10 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
  */
-CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   timediff_t timeout;
   struct curltime now = Curl_now();
 
@@ -426,7 +424,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
   timeout = Curl_timeleft(data, &now, TRUE);
   if(timeout < 0) {
     /* already expired! */
-    connclose(conn, "Timed out before name resolve started");
+    connclose(data->conn, "Timed out before name resolve started");
     return CURLE_OPERATION_TIMEDOUT;
   }
   if(!timeout)
@@ -447,7 +445,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
     store.tv_sec = itimeout/1000;
     store.tv_usec = (itimeout%1000)*1000;
 
-    tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
+    tvp = ares_timeout((ares_channel)data->state.async.resolver, &store, &tv);
 
     /* use the timeout period ares returned to us above if less than one
        second is left, otherwise just use 1000ms to make sure the progress
@@ -457,13 +455,13 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
     else
       timeout_ms = 1000;
 
-    waitperform(conn, timeout_ms);
-    result = Curl_resolver_is_resolved(conn, entry);
+    waitperform(data, timeout_ms);
+    result = Curl_resolver_is_resolved(data, entry);
 
-    if(result || conn->async.done)
+    if(result || data->state.async.done)
       break;
 
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else {
       struct curltime now2 = Curl_now();
@@ -481,17 +479,17 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
   }
   if(result)
     /* failure, so we cancel the ares operation */
-    ares_cancel((ares_channel)data->state.resolver);
+    ares_cancel((ares_channel)data->state.async.resolver);
 
   /* Operation complete, if the lookup was successful we now have the entry
      in the cache. */
   if(entry)
-    *entry = conn->async.dns;
+    *entry = data->state.async.dns;
 
   if(result)
     /* close the connection, since we can't return failure here without
        cleaning up this connection properly. */
-    connclose(conn, "c-ares resolve failed");
+    connclose(data->conn, "c-ares resolve failed");
 
   return result;
 }
@@ -525,7 +523,7 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
 #endif
                                struct hostent *hostent)
 {
-  struct connectdata *conn = (struct connectdata *)arg;
+  struct Curl_easy *data = (struct Curl_easy *)arg;
   struct thread_data *res;
 
 #ifdef HAVE_CARES_CALLBACK_TIMEOUTS
@@ -537,12 +535,12 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
        be valid so only defer it when we know the 'status' says its fine! */
     return;
 
-  res = conn->async.tdata;
+  res = data->state.async.tdata;
   if(res) {
     res->num_pending--;
 
     if(CURL_ASYNC_SUCCESS == status) {
-      struct Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
+      struct Curl_addrinfo *ai = Curl_he2ai(hostent, data->state.async.port);
       if(ai) {
         compound_results(res, ai);
       }
@@ -607,8 +605,8 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
          c-ares retry cycle each request is.
       */
       res->happy_eyeballs_dns_time = Curl_now();
-      Curl_expire(
-        conn->data, HAPPY_EYEBALLS_DNS_TIMEOUT, EXPIRE_HAPPY_EYEBALLS_DNS);
+      Curl_expire(data, HAPPY_EYEBALLS_DNS_TIMEOUT,
+                  EXPIRE_HAPPY_EYEBALLS_DNS);
     }
   }
 }
@@ -621,19 +619,18 @@ static void query_completed_cb(void *arg,  /* (struct connectdata *) */
  * memory we need to free after use. That memory *MUST* be freed with
  * Curl_freeaddrinfo(), nothing else.
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 const char *hostname,
                                                 int port,
                                                 int *waitp)
 {
   char *bufp;
-  struct Curl_easy *data = conn->data;
   int family = PF_INET;
 
   *waitp = 0; /* default to synchronous response */
 
 #ifdef ENABLE_IPV6
-  switch(conn->ip_version) {
+  switch(data->set.ipver) {
   default:
 #if ARES_VERSION >= 0x010601
     family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
@@ -653,39 +650,39 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
   bufp = strdup(hostname);
   if(bufp) {
     struct thread_data *res = NULL;
-    free(conn->async.hostname);
-    conn->async.hostname = bufp;
-    conn->async.port = port;
-    conn->async.done = FALSE;   /* not done */
-    conn->async.status = 0;     /* clear */
-    conn->async.dns = NULL;     /* clear */
+    free(data->state.async.hostname);
+    data->state.async.hostname = bufp;
+    data->state.async.port = port;
+    data->state.async.done = FALSE;   /* not done */
+    data->state.async.status = 0;     /* clear */
+    data->state.async.dns = NULL;     /* clear */
     res = calloc(sizeof(struct thread_data), 1);
     if(!res) {
-      free(conn->async.hostname);
-      conn->async.hostname = NULL;
+      free(data->state.async.hostname);
+      data->state.async.hostname = NULL;
       return NULL;
     }
-    conn->async.tdata = res;
+    data->state.async.tdata = res;
 
     /* initial status - failed */
     res->last_status = ARES_ENOTFOUND;
 #ifdef ENABLE_IPV6
     if(family == PF_UNSPEC) {
-      if(Curl_ipv6works(conn)) {
+      if(Curl_ipv6works(data)) {
         res->num_pending = 2;
 
         /* areschannel is already setup in the Curl_open() function */
-        ares_gethostbyname((ares_channel)data->state.resolver, hostname,
-                            PF_INET, query_completed_cb, conn);
-        ares_gethostbyname((ares_channel)data->state.resolver, hostname,
-                            PF_INET6, query_completed_cb, conn);
+        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                            PF_INET, query_completed_cb, data);
+        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                            PF_INET6, query_completed_cb, data);
       }
       else {
         res->num_pending = 1;
 
         /* areschannel is already setup in the Curl_open() function */
-        ares_gethostbyname((ares_channel)data->state.resolver, hostname,
-                            PF_INET, query_completed_cb, conn);
+        ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+                            PF_INET, query_completed_cb, data);
       }
     }
     else
@@ -694,8 +691,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
       res->num_pending = 1;
 
       /* areschannel is already setup in the Curl_open() function */
-      ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
-                         query_completed_cb, conn);
+      ares_gethostbyname((ares_channel)data->state.async.resolver,
+                         hostname, family,
+                         query_completed_cb, data);
     }
 
     *waitp = 1; /* expect asynchronous response */
@@ -720,9 +718,10 @@ CURLcode Curl_set_dns_servers(struct Curl_easy *data,
 
 #if (ARES_VERSION >= 0x010704)
 #if (ARES_VERSION >= 0x010b00)
-  ares_result = ares_set_servers_ports_csv(data->state.resolver, servers);
+  ares_result = ares_set_servers_ports_csv(data->state.async.resolver,
+                                           servers);
 #else
-  ares_result = ares_set_servers_csv(data->state.resolver, servers);
+  ares_result = ares_set_servers_csv(data->state.async.resolver, servers);
 #endif
   switch(ares_result) {
   case ARES_SUCCESS:
@@ -752,7 +751,7 @@ CURLcode Curl_set_dns_interface(struct Curl_easy *data,
   if(!interf)
     interf = "";
 
-  ares_set_local_dev((ares_channel)data->state.resolver, interf);
+  ares_set_local_dev((ares_channel)data->state.async.resolver, interf);
 
   return CURLE_OK;
 #else /* c-ares version too old! */
@@ -777,7 +776,8 @@ CURLcode Curl_set_dns_local_ip4(struct Curl_easy *data,
     }
   }
 
-  ares_set_local_ip4((ares_channel)data->state.resolver, ntohl(a4.s_addr));
+  ares_set_local_ip4((ares_channel)data->state.async.resolver,
+                     ntohl(a4.s_addr));
 
   return CURLE_OK;
 #else /* c-ares version too old! */
@@ -803,7 +803,7 @@ CURLcode Curl_set_dns_local_ip6(struct Curl_easy *data,
     }
   }
 
-  ares_set_local_ip6((ares_channel)data->state.resolver, a6);
+  ares_set_local_ip6((ares_channel)data->state.async.resolver, a6);
 
   return CURLE_OK;
 #else /* c-ares version too old! */

+ 72 - 76
lib/asyn-thread.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -145,13 +145,13 @@ static void destroy_async_data(struct Curl_async *);
 /*
  * Cancel all possibly still on-going resolves for this connection.
  */
-void Curl_resolver_cancel(struct connectdata *conn)
+void Curl_resolver_cancel(struct Curl_easy *data)
 {
-  destroy_async_data(&conn->async);
+  destroy_async_data(&data->state.async);
 }
 
 /* This function is used to init a threaded resolve */
-static bool init_resolve_thread(struct connectdata *conn,
+static bool init_resolve_thread(struct Curl_easy *data,
                                 const char *hostname, int port,
                                 const struct addrinfo *hints);
 
@@ -160,12 +160,11 @@ static bool init_resolve_thread(struct connectdata *conn,
 struct thread_sync_data {
   curl_mutex_t *mtx;
   int done;
-
+  int port;
   char *hostname;        /* hostname to resolve, Curl_async.hostname
                             duplicate */
-  int port;
 #ifdef USE_SOCKETPAIR
-  struct connectdata *conn;
+  struct Curl_easy *data;
   curl_socket_t sock_pair[2]; /* socket pair */
 #endif
   int sock_error;
@@ -183,9 +182,9 @@ struct thread_data {
   struct thread_sync_data tsd;
 };
 
-static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
+static struct thread_sync_data *conn_thread_sync_data(struct Curl_easy *data)
 {
-  return &(conn->async.tdata->tsd);
+  return &(data->state.async.tdata->tsd);
 }
 
 /* Destroy resolver thread synchronization data */
@@ -269,12 +268,12 @@ int init_thread_sync_data(struct thread_data *td,
   return 0;
 }
 
-static int getaddrinfo_complete(struct connectdata *conn)
+static int getaddrinfo_complete(struct Curl_easy *data)
 {
-  struct thread_sync_data *tsd = conn_thread_sync_data(conn);
+  struct thread_sync_data *tsd = conn_thread_sync_data(data);
   int rc;
 
-  rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
+  rc = Curl_addrinfo_callback(data, tsd->sock_error, tsd->res);
   /* The tsd->res structure has been copied to async.dns and perhaps the DNS
      cache.  Set our copy to NULL so destroy_thread_sync_data doesn't free it.
   */
@@ -385,7 +384,7 @@ static void destroy_async_data(struct Curl_async *async)
     int done;
 #ifdef USE_SOCKETPAIR
     curl_socket_t sock_rd = td->tsd.sock_pair[0];
-    struct connectdata *conn = td->tsd.conn;
+    struct Curl_easy *data = td->tsd.data;
 #endif
 
     /*
@@ -413,8 +412,7 @@ static void destroy_async_data(struct Curl_async *async)
      * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE
      * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL
      */
-    if(conn)
-      Curl_multi_closed(conn->data, sock_rd);
+    Curl_multi_closed(data, sock_rd);
     sclose(sock_rd);
 #endif
   }
@@ -430,32 +428,33 @@ static void destroy_async_data(struct Curl_async *async)
  *
  * Returns FALSE in case of failure, otherwise TRUE.
  */
-static bool init_resolve_thread(struct connectdata *conn,
+static bool init_resolve_thread(struct Curl_easy *data,
                                 const char *hostname, int port,
                                 const struct addrinfo *hints)
 {
   struct thread_data *td = calloc(1, sizeof(struct thread_data));
   int err = ENOMEM;
+  struct Curl_async *asp = &data->state.async;
 
-  conn->async.tdata = td;
+  data->state.async.tdata = td;
   if(!td)
     goto errno_exit;
 
-  conn->async.port = port;
-  conn->async.done = FALSE;
-  conn->async.status = 0;
-  conn->async.dns = NULL;
+  asp->port = port;
+  asp->done = FALSE;
+  asp->status = 0;
+  asp->dns = NULL;
   td->thread_hnd = curl_thread_t_null;
 
   if(!init_thread_sync_data(td, hostname, port, hints)) {
-    conn->async.tdata = NULL;
+    asp->tdata = NULL;
     free(td);
     goto errno_exit;
   }
 
-  free(conn->async.hostname);
-  conn->async.hostname = strdup(hostname);
-  if(!conn->async.hostname)
+  free(asp->hostname);
+  asp->hostname = strdup(hostname);
+  if(!asp->hostname)
     goto err_exit;
 
   /* The thread will set this to 1 when complete. */
@@ -477,7 +476,7 @@ static bool init_resolve_thread(struct connectdata *conn,
   return TRUE;
 
  err_exit:
-  destroy_async_data(&conn->async);
+  destroy_async_data(asp);
 
  errno_exit:
   errno = err;
@@ -489,12 +488,13 @@ static bool init_resolve_thread(struct connectdata *conn,
  * error
  */
 
-static CURLcode resolver_error(struct connectdata *conn)
+static CURLcode resolver_error(struct Curl_easy *data)
 {
   const char *host_or_proxy;
   CURLcode result;
 
 #ifndef CURL_DISABLE_PROXY
+  struct connectdata *conn = data->conn;
   if(conn->bits.httpproxy) {
     host_or_proxy = "proxy";
     result = CURLE_COULDNT_RESOLVE_PROXY;
@@ -506,8 +506,8 @@ static CURLcode resolver_error(struct connectdata *conn)
     result = CURLE_COULDNT_RESOLVE_HOST;
   }
 
-  failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
-        conn->async.hostname);
+  failf(data, "Could not resolve %s: %s", host_or_proxy,
+        data->state.async.hostname);
 
   return result;
 }
@@ -515,37 +515,39 @@ static CURLcode resolver_error(struct connectdata *conn)
 /*
  * 'entry' may be NULL and then no data is returned
  */
-static CURLcode thread_wait_resolv(struct connectdata *conn,
+static CURLcode thread_wait_resolv(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry,
                                    bool report)
 {
-  struct thread_data *td = conn->async.tdata;
+  struct thread_data *td;
   CURLcode result = CURLE_OK;
 
-  DEBUGASSERT(conn && td);
+  DEBUGASSERT(data);
+  td = data->state.async.tdata;
+  DEBUGASSERT(td);
   DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
 
   /* wait for the thread to resolve the name */
   if(Curl_thread_join(&td->thread_hnd)) {
     if(entry)
-      result = getaddrinfo_complete(conn);
+      result = getaddrinfo_complete(data);
   }
   else
     DEBUGASSERT(0);
 
-  conn->async.done = TRUE;
+  data->state.async.done = TRUE;
 
   if(entry)
-    *entry = conn->async.dns;
+    *entry = data->state.async.dns;
 
-  if(!conn->async.dns && report)
+  if(!data->state.async.dns && report)
     /* a name was not resolved, report error */
-    result = resolver_error(conn);
+    result = resolver_error(data);
 
-  destroy_async_data(&conn->async);
+  destroy_async_data(&data->state.async);
 
-  if(!conn->async.dns && report)
-    connclose(conn, "asynch resolve failed");
+  if(!data->state.async.dns && report)
+    connclose(data->conn, "asynch resolve failed");
 
   return result;
 }
@@ -555,17 +557,17 @@ static CURLcode thread_wait_resolv(struct connectdata *conn,
  * Until we gain a way to signal the resolver threads to stop early, we must
  * simply wait for them and ignore their results.
  */
-void Curl_resolver_kill(struct connectdata *conn)
+void Curl_resolver_kill(struct Curl_easy *data)
 {
-  struct thread_data *td = conn->async.tdata;
+  struct thread_data *td = data->state.async.tdata;
 
   /* If we're still resolving, we must wait for the threads to fully clean up,
      unfortunately.  Otherwise, we can simply cancel to clean up any resolver
      data. */
   if(td && td->thread_hnd != curl_thread_t_null)
-    (void)thread_wait_resolv(conn, NULL, FALSE);
+    (void)thread_wait_resolv(data, NULL, FALSE);
   else
-    Curl_resolver_cancel(conn);
+    Curl_resolver_cancel(data);
 }
 
 /*
@@ -581,10 +583,10 @@ void Curl_resolver_kill(struct connectdata *conn)
  *
  * This is the version for resolves-in-a-thread.
  */
-CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry)
 {
-  return thread_wait_resolv(conn, entry, TRUE);
+  return thread_wait_resolv(data, entry, TRUE);
 }
 
 /*
@@ -592,11 +594,10 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
  * name resolve request has completed. It should also make sure to time-out if
  * the operation seems to take too long.
  */
-CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
                                    struct Curl_dns_entry **entry)
 {
-  struct Curl_easy *data = conn->data;
-  struct thread_data *td = conn->async.tdata;
+  struct thread_data *td = data->state.async.tdata;
   int done = 0;
 
   DEBUGASSERT(entry);
@@ -612,15 +613,15 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
   Curl_mutex_release(td->tsd.mtx);
 
   if(done) {
-    getaddrinfo_complete(conn);
+    getaddrinfo_complete(data);
 
-    if(!conn->async.dns) {
-      CURLcode result = resolver_error(conn);
-      destroy_async_data(&conn->async);
+    if(!data->state.async.dns) {
+      CURLcode result = resolver_error(data);
+      destroy_async_data(&data->state.async);
       return result;
     }
-    destroy_async_data(&conn->async);
-    *entry = conn->async.dns;
+    destroy_async_data(&data->state.async);
+    *entry = data->state.async.dns;
   }
   else {
     /* poll for name lookup done with exponential backoff up to 250ms */
@@ -641,22 +642,20 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
       td->poll_interval = 250;
 
     td->interval_end = elapsed + td->poll_interval;
-    Curl_expire(conn->data, td->poll_interval, EXPIRE_ASYNC_NAME);
+    Curl_expire(data, td->poll_interval, EXPIRE_ASYNC_NAME);
   }
 
   return CURLE_OK;
 }
 
-int Curl_resolver_getsock(struct connectdata *conn,
-                          curl_socket_t *socks)
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *socks)
 {
   int ret_val = 0;
   timediff_t milli;
   timediff_t ms;
-  struct Curl_easy *data = conn->data;
-  struct resdata *reslv = (struct resdata *)data->state.resolver;
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
 #ifdef USE_SOCKETPAIR
-  struct thread_data *td = conn->async.tdata;
+  struct thread_data *td = data->state.async.tdata;
 #else
   (void)socks;
 #endif
@@ -665,8 +664,7 @@ int Curl_resolver_getsock(struct connectdata *conn,
   if(td) {
     /* return read fd to client for polling the DNS resolution status */
     socks[0] = td->tsd.sock_pair[0];
-    DEBUGASSERT(td->tsd.conn == conn || !td->tsd.conn);
-    td->tsd.conn = conn;
+    td->tsd.data = data;
     ret_val = GETSOCK_READSOCK(0);
   }
   else {
@@ -693,25 +691,24 @@ int Curl_resolver_getsock(struct connectdata *conn,
 /*
  * Curl_getaddrinfo() - for platforms without getaddrinfo
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 const char *hostname,
                                                 int port,
                                                 int *waitp)
 {
-  struct Curl_easy *data = conn->data;
-  struct resdata *reslv = (struct resdata *)data->state.resolver;
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
 
   *waitp = 0; /* default to synchronous response */
 
   reslv->start = Curl_now();
 
   /* fire up a new resolver thread! */
-  if(init_resolve_thread(conn, hostname, port, NULL)) {
+  if(init_resolve_thread(data, hostname, port, NULL)) {
     *waitp = 1; /* expect asynchronous response */
     return NULL;
   }
 
-  failf(conn->data, "getaddrinfo() thread failed\n");
+  failf(data, "getaddrinfo() thread failed");
 
   return NULL;
 }
@@ -721,15 +718,14 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
 /*
  * Curl_resolver_getaddrinfo() - for getaddrinfo
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 const char *hostname,
                                                 int port,
                                                 int *waitp)
 {
   struct addrinfo hints;
   int pf = PF_INET;
-  struct Curl_easy *data = conn->data;
-  struct resdata *reslv = (struct resdata *)data->state.resolver;
+  struct resdata *reslv = (struct resdata *)data->state.async.resolver;
 
   *waitp = 0; /* default to synchronous response */
 
@@ -737,7 +733,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
   /*
    * Check if a limited name resolve has been requested.
    */
-  switch(conn->ip_version) {
+  switch(data->set.ipver) {
   case CURL_IPRESOLVE_V4:
     pf = PF_INET;
     break;
@@ -749,24 +745,24 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
     break;
   }
 
-  if((pf != PF_INET) && !Curl_ipv6works(conn))
+  if((pf != PF_INET) && !Curl_ipv6works(data))
     /* The stack seems to be a non-IPv6 one */
     pf = PF_INET;
 #endif /* CURLRES_IPV6 */
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (conn->transport == TRNSPRT_TCP)?
+  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP)?
     SOCK_STREAM : SOCK_DGRAM;
 
   reslv->start = Curl_now();
   /* fire up a new resolver thread! */
-  if(init_resolve_thread(conn, hostname, port, &hints)) {
+  if(init_resolve_thread(data, hostname, port, &hints)) {
     *waitp = 1; /* expect asynchronous response */
     return NULL;
   }
 
-  failf(data, "getaddrinfo() thread failed to start\n");
+  failf(data, "getaddrinfo() thread failed to start");
   return NULL;
 
 }

+ 7 - 7
lib/asyn.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -91,7 +91,7 @@ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
  *
  * It is safe to call this when conn is in any state.
  */
-void Curl_resolver_cancel(struct connectdata *conn);
+void Curl_resolver_cancel(struct Curl_easy *data);
 
 /*
  * Curl_resolver_kill().
@@ -104,7 +104,7 @@ void Curl_resolver_cancel(struct connectdata *conn);
  *
  * It is safe to call this when conn is in any state.
  */
-void Curl_resolver_kill(struct connectdata *conn);
+void Curl_resolver_kill(struct Curl_easy *data);
 
 /* Curl_resolver_getsock()
  *
@@ -114,7 +114,7 @@ void Curl_resolver_kill(struct connectdata *conn);
  * return bitmask indicating what file descriptors (referring to array indexes
  * in the 'sock' array) to wait for, read/write.
  */
-int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock);
+int Curl_resolver_getsock(struct Curl_easy *data, curl_socket_t *sock);
 
 /*
  * Curl_resolver_is_resolved()
@@ -125,7 +125,7 @@ int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock);
  *
  * Returns normal CURLcode errors.
  */
-CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+CURLcode Curl_resolver_is_resolved(struct Curl_easy *data,
                                    struct Curl_dns_entry **dns);
 
 /*
@@ -139,7 +139,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
  * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
  * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
  */
-CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+CURLcode Curl_resolver_wait_resolv(struct Curl_easy *data,
                                    struct Curl_dns_entry **dnsentry);
 
 /*
@@ -153,7 +153,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
  * Each resolver backend must of course make sure to return data in the
  * correct format to comply with this.
  */
-struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct Curl_easy *data,
                                                 const char *hostname,
                                                 int port,
                                                 int *waitp);

+ 908 - 0
lib/c-hyper.c

@@ -0,0 +1,908 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  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.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER)
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include <hyper.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "transfer.h"
+#include "multiif.h"
+#include "progress.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+size_t Curl_hyper_recv(void *userp, hyper_context *ctx,
+                       uint8_t *buf, size_t buflen)
+{
+  struct Curl_easy *data = userp;
+  struct connectdata *conn = data->conn;
+  CURLcode result;
+  ssize_t nread;
+  DEBUGASSERT(conn);
+  (void)ctx;
+
+  result = Curl_read(data, conn->sockfd, (char *)buf, buflen, &nread);
+  if(result == CURLE_AGAIN) {
+    /* would block, register interest */
+    if(data->hyp.read_waker)
+      hyper_waker_free(data->hyp.read_waker);
+    data->hyp.read_waker = hyper_context_waker(ctx);
+    if(!data->hyp.read_waker) {
+      failf(data, "Couldn't make the read hyper_context_waker");
+      return HYPER_IO_ERROR;
+    }
+    return HYPER_IO_PENDING;
+  }
+  else if(result) {
+    failf(data, "Curl_read failed");
+    return HYPER_IO_ERROR;
+  }
+  return (size_t)nread;
+}
+
+size_t Curl_hyper_send(void *userp, hyper_context *ctx,
+                       const uint8_t *buf, size_t buflen)
+{
+  struct Curl_easy *data = userp;
+  struct connectdata *conn = data->conn;
+  CURLcode result;
+  ssize_t nwrote;
+
+  result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
+  if(result == CURLE_AGAIN) {
+    /* would block, register interest */
+    if(data->hyp.write_waker)
+      hyper_waker_free(data->hyp.write_waker);
+    data->hyp.write_waker = hyper_context_waker(ctx);
+    if(!data->hyp.write_waker) {
+      failf(data, "Couldn't make the write hyper_context_waker");
+      return HYPER_IO_ERROR;
+    }
+    return HYPER_IO_PENDING;
+  }
+  else if(result) {
+    failf(data, "Curl_write failed");
+    return HYPER_IO_ERROR;
+  }
+  return (size_t)nwrote;
+}
+
+static int hyper_each_header(void *userdata,
+                             const uint8_t *name,
+                             size_t name_len,
+                             const uint8_t *value,
+                             size_t value_len)
+{
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  size_t len;
+  char *headp;
+  CURLcode result;
+  Curl_dyn_reset(&data->state.headerb);
+  if(name_len) {
+    if(Curl_dyn_addf(&data->state.headerb, "%.*s: %.*s\r\n",
+                     (int) name_len, name, (int) value_len, value))
+      return HYPER_ITER_BREAK;
+  }
+  else {
+    if(Curl_dyn_add(&data->state.headerb, "\r\n"))
+      return HYPER_ITER_BREAK;
+  }
+  len = Curl_dyn_len(&data->state.headerb);
+  headp = Curl_dyn_ptr(&data->state.headerb);
+
+  result = Curl_http_header(data, data->conn, headp);
+  if(result) {
+    data->state.hresult = result;
+    return HYPER_ITER_BREAK;
+  }
+
+  Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
+
+  result = Curl_client_write(data, CLIENTWRITE_HEADER, headp, len);
+  if(result) {
+    data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+    return HYPER_ITER_BREAK;
+  }
+
+  data->info.header_size += (long)len;
+  data->req.headerbytecount += (long)len;
+  return HYPER_ITER_CONTINUE;
+}
+
+static int hyper_body_chunk(void *userdata, const hyper_buf *chunk)
+{
+  char *buf = (char *)hyper_buf_bytes(chunk);
+  size_t len = hyper_buf_len(chunk);
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  struct SingleRequest *k = &data->req;
+  CURLcode result;
+
+  if(0 == k->bodywrites++) {
+    bool done = FALSE;
+    result = Curl_http_firstwrite(data, data->conn, &done);
+    if(result || done) {
+      infof(data, "Return early from hyper_body_chunk\n");
+      data->state.hresult = result;
+      return HYPER_ITER_BREAK;
+    }
+  }
+  if(k->ignorebody)
+    return HYPER_ITER_CONTINUE;
+  Curl_debug(data, CURLINFO_DATA_IN, buf, len);
+  result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
+
+  if(result) {
+    data->state.hresult = result;
+    return HYPER_ITER_BREAK;
+  }
+
+  data->req.bytecount += len;
+  Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
+  return HYPER_ITER_CONTINUE;
+}
+
+/*
+ * Hyper does not consider the status line, the first line in a HTTP/1
+ * response, to be a header. The libcurl API does. This function sends the
+ * status line in the header callback. */
+static CURLcode status_line(struct Curl_easy *data,
+                            struct connectdata *conn,
+                            uint16_t http_status,
+                            int http_version,
+                            const uint8_t *reason, size_t rlen)
+{
+  CURLcode result;
+  size_t wrote;
+  size_t len;
+  const char *vstr;
+  curl_write_callback writeheader =
+    data->set.fwrite_header? data->set.fwrite_header: data->set.fwrite_func;
+  vstr = http_version == HYPER_HTTP_VERSION_1_1 ? "1.1" :
+    (http_version == HYPER_HTTP_VERSION_2 ? "2" : "1.0");
+  conn->httpversion =
+    http_version == HYPER_HTTP_VERSION_1_1 ? 11 :
+    (http_version == HYPER_HTTP_VERSION_2 ? 20 : 10);
+  data->req.httpcode = http_status;
+
+  result = Curl_http_statusline(data, conn);
+  if(result)
+    return result;
+
+  Curl_dyn_reset(&data->state.headerb);
+
+  result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n",
+                         vstr,
+                         (int)http_status,
+                         (int)rlen, reason);
+  if(result)
+    return result;
+  len = Curl_dyn_len(&data->state.headerb);
+  Curl_debug(data, CURLINFO_HEADER_IN, Curl_dyn_ptr(&data->state.headerb),
+             len);
+  Curl_set_in_callback(data, true);
+  wrote = writeheader(Curl_dyn_ptr(&data->state.headerb), 1, len,
+                      data->set.writeheader);
+  Curl_set_in_callback(data, false);
+  if(wrote != len)
+    return CURLE_WRITE_ERROR;
+
+  data->info.header_size += (long)len;
+  data->req.headerbytecount += (long)len;
+  data->req.httpcode = http_status;
+  return CURLE_OK;
+}
+
+/*
+ * Hyper does not pass on the last empty response header. The libcurl API
+ * does. This function sends an empty header in the header callback.
+ */
+static CURLcode empty_header(struct Curl_easy *data)
+{
+  return hyper_each_header(data, NULL, 0, NULL, 0) ?
+    CURLE_WRITE_ERROR : CURLE_OK;
+}
+
+CURLcode Curl_hyper_stream(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           int *didwhat,
+                           bool *done,
+                           int select_res)
+{
+  hyper_response *resp = NULL;
+  uint16_t http_status;
+  int http_version;
+  hyper_headers *headers = NULL;
+  hyper_body *resp_body = NULL;
+  struct hyptransfer *h = &data->hyp;
+  hyper_task *task;
+  hyper_task *foreach;
+  hyper_error *hypererr = NULL;
+  const uint8_t *reasonp;
+  size_t reason_len;
+  CURLcode result = CURLE_OK;
+  (void)conn;
+
+  if(select_res & CURL_CSELECT_IN) {
+    if(h->read_waker)
+      hyper_waker_wake(h->read_waker);
+    h->read_waker = NULL;
+  }
+  if(select_res & CURL_CSELECT_OUT) {
+    if(h->write_waker)
+      hyper_waker_wake(h->write_waker);
+    h->write_waker = NULL;
+  }
+
+  *done = FALSE;
+  do {
+    hyper_task_return_type t;
+    task = hyper_executor_poll(h->exec);
+    if(!task) {
+      *didwhat = KEEP_RECV;
+      break;
+    }
+    t = hyper_task_type(task);
+    switch(t) {
+    case HYPER_TASK_ERROR:
+      hypererr = hyper_task_value(task);
+      break;
+    case HYPER_TASK_RESPONSE:
+      resp = hyper_task_value(task);
+      break;
+    default:
+      break;
+    }
+    hyper_task_free(task);
+
+    if(t == HYPER_TASK_ERROR) {
+      hyper_code errnum = hyper_error_code(hypererr);
+      if(errnum == HYPERE_ABORTED_BY_CALLBACK) {
+        /* override Hyper's view, might not even be an error */
+        result = data->state.hresult;
+        infof(data, "hyperstream is done (by early callback)\n");
+      }
+      else {
+        uint8_t errbuf[256];
+        size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+        hyper_code code = hyper_error_code(hypererr);
+        failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
+        if((code == HYPERE_UNEXPECTED_EOF) && !data->req.bytecount)
+          result = CURLE_GOT_NOTHING;
+        else
+          result = CURLE_RECV_ERROR;
+      }
+      *done = TRUE;
+      hyper_error_free(hypererr);
+      break;
+    }
+    else if(h->endtask == task) {
+      /* end of transfer */
+      *done = TRUE;
+      infof(data, "hyperstream is done!\n");
+      break;
+    }
+    else if(t != HYPER_TASK_RESPONSE) {
+      *didwhat = KEEP_RECV;
+      break;
+    }
+    /* HYPER_TASK_RESPONSE */
+
+    *didwhat = KEEP_RECV;
+    if(!resp) {
+      failf(data, "hyperstream: couldn't get response");
+      return CURLE_RECV_ERROR;
+    }
+
+    http_status = hyper_response_status(resp);
+    http_version = hyper_response_version(resp);
+    reasonp = hyper_response_reason_phrase(resp);
+    reason_len = hyper_response_reason_phrase_len(resp);
+
+    result = status_line(data, conn,
+                         http_status, http_version, reasonp, reason_len);
+    if(result)
+      break;
+
+    headers = hyper_response_headers(resp);
+    if(!headers) {
+      failf(data, "hyperstream: couldn't get response headers");
+      result = CURLE_RECV_ERROR;
+      break;
+    }
+
+    /* the headers are already received */
+    hyper_headers_foreach(headers, hyper_each_header, data);
+    if(data->state.hresult) {
+      result = data->state.hresult;
+      break;
+    }
+
+    if(empty_header(data)) {
+      failf(data, "hyperstream: couldn't pass blank header");
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+
+    /* Curl_http_auth_act() checks what authentication methods that are
+     * available and decides which one (if any) to use. It will set 'newurl'
+     * if an auth method was picked. */
+    result = Curl_http_auth_act(data);
+    if(result)
+      break;
+
+    resp_body = hyper_response_body(resp);
+    if(!resp_body) {
+      failf(data, "hyperstream: couldn't get response body");
+      result = CURLE_RECV_ERROR;
+      break;
+    }
+    foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
+    if(!foreach) {
+      failf(data, "hyperstream: body foreach failed");
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    DEBUGASSERT(hyper_task_type(foreach) == HYPER_TASK_EMPTY);
+    if(HYPERE_OK != hyper_executor_push(h->exec, foreach)) {
+      failf(data, "Couldn't hyper_executor_push the body-foreach");
+      result = CURLE_OUT_OF_MEMORY;
+      break;
+    }
+    h->endtask = foreach;
+
+    hyper_response_free(resp);
+    resp = NULL;
+  } while(1);
+  if(resp)
+    hyper_response_free(resp);
+  return result;
+}
+
+static CURLcode debug_request(struct Curl_easy *data,
+                              const char *method,
+                              const char *path,
+                              bool h2)
+{
+  char *req = aprintf("%s %s HTTP/%s\r\n", method, path,
+                      h2?"2":"1.1");
+  if(!req)
+    return CURLE_OUT_OF_MEMORY;
+  Curl_debug(data, CURLINFO_HEADER_OUT, req, strlen(req));
+  free(req);
+  return CURLE_OK;
+}
+
+/*
+ * Given a full header line "name: value" (optional CRLF in the input, should
+ * be in the output), add to Hyper and send to the debug callback.
+ *
+ * Supports multiple headers.
+ */
+
+CURLcode Curl_hyper_header(struct Curl_easy *data, hyper_headers *headers,
+                           const char *line)
+{
+  const char *p;
+  const char *n;
+  size_t nlen;
+  const char *v;
+  size_t vlen;
+  bool newline = TRUE;
+  int numh = 0;
+
+  if(!line)
+    return CURLE_OK;
+  n = line;
+  do {
+    size_t linelen = 0;
+
+    p = strchr(n, ':');
+    if(!p)
+      /* this is fine if we already added at least one header */
+      return numh ? CURLE_OK : CURLE_BAD_FUNCTION_ARGUMENT;
+    nlen = p - n;
+    p++; /* move past the colon */
+    while(*p == ' ')
+      p++;
+    v = p;
+    p = strchr(v, '\r');
+    if(!p) {
+      p = strchr(v, '\n');
+      if(p)
+        linelen = 1; /* LF only */
+      else {
+        p = strchr(v, '\0');
+        newline = FALSE; /* no newline */
+      }
+    }
+    else
+      linelen = 2; /* CRLF ending */
+    linelen += (p - n);
+    if(!n)
+      return CURLE_BAD_FUNCTION_ARGUMENT;
+    vlen = p - v;
+
+    if(HYPERE_OK != hyper_headers_add(headers, (uint8_t *)n, nlen,
+                                      (uint8_t *)v, vlen)) {
+      failf(data, "hyper_headers_add host");
+      return CURLE_OUT_OF_MEMORY;
+    }
+    if(data->set.verbose) {
+      char *ptr = NULL;
+      if(!newline) {
+        ptr = aprintf("%.*s\r\n", (int)linelen, line);
+        if(!ptr)
+          return CURLE_OUT_OF_MEMORY;
+        Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
+        free(ptr);
+      }
+      else
+        Curl_debug(data, CURLINFO_HEADER_OUT, (char *)line, linelen);
+    }
+    numh++;
+    n += linelen;
+  } while(newline);
+  return CURLE_OK;
+}
+
+static CURLcode request_target(struct Curl_easy *data,
+                               struct connectdata *conn,
+                               const char *method,
+                               bool h2,
+                               hyper_request *req)
+{
+  CURLcode result;
+  struct dynbuf r;
+
+  Curl_dyn_init(&r, DYN_HTTP_REQUEST);
+
+  result = Curl_http_target(data, conn, &r);
+  if(result)
+    return result;
+
+  if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
+                           Curl_dyn_len(&r))) {
+    failf(data, "error setting path");
+    result = CURLE_OUT_OF_MEMORY;
+  }
+  else
+    result = debug_request(data, method, Curl_dyn_ptr(&r), h2);
+
+  Curl_dyn_free(&r);
+
+  return result;
+}
+
+static int uploadpostfields(void *userdata, hyper_context *ctx,
+                            hyper_buf **chunk)
+{
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  (void)ctx;
+  if(data->req.upload_done)
+    *chunk = NULL; /* nothing more to deliver */
+  else {
+    /* send everything off in a single go */
+    *chunk = hyper_buf_copy(data->set.postfields,
+                            (size_t)data->req.p.http->postsize);
+    data->req.upload_done = TRUE;
+  }
+  return HYPER_POLL_READY;
+}
+
+static int uploadstreamed(void *userdata, hyper_context *ctx,
+                          hyper_buf **chunk)
+{
+  size_t fillcount;
+  struct Curl_easy *data = (struct Curl_easy *)userdata;
+  CURLcode result =
+    Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
+  (void)ctx;
+  if(result)
+    return HYPER_POLL_ERROR;
+  if(!fillcount)
+    /* done! */
+    *chunk = NULL;
+  else
+    *chunk = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
+  return HYPER_POLL_READY;
+}
+
+/*
+ * bodysend() sets up headers in the outgoing request for a HTTP transfer that
+ * sends a body
+ */
+
+static CURLcode bodysend(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         hyper_headers *headers,
+                         hyper_request *hyperreq,
+                         Curl_HttpReq httpreq)
+{
+  CURLcode result = CURLE_OK;
+  struct dynbuf req;
+  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
+    Curl_pgrsSetUploadSize(data, 0); /* no request body */
+  else {
+    hyper_body *body;
+    Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+    result = Curl_http_bodysend(data, conn, &req, httpreq);
+
+    if(!result)
+      result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
+
+    Curl_dyn_free(&req);
+
+    body = hyper_body_new();
+    hyper_body_set_userdata(body, data);
+    if(data->set.postfields)
+      hyper_body_set_data_func(body, uploadpostfields);
+    else {
+      result = Curl_get_upload_buffer(data);
+      if(result)
+        return result;
+      /* init the "upload from here" pointer */
+      data->req.upload_fromhere = data->state.ulbuf;
+      hyper_body_set_data_func(body, uploadstreamed);
+    }
+    if(HYPERE_OK != hyper_request_set_body(hyperreq, body)) {
+      /* fail */
+      hyper_body_free(body);
+      result = CURLE_OUT_OF_MEMORY;
+    }
+  }
+  return result;
+}
+
+static CURLcode cookies(struct Curl_easy *data,
+                        struct connectdata *conn,
+                        hyper_headers *headers)
+{
+  struct dynbuf req;
+  CURLcode result;
+  Curl_dyn_init(&req, DYN_HTTP_REQUEST);
+
+  result = Curl_http_cookies(data, conn, &req);
+  if(!result)
+    result = Curl_hyper_header(data, headers, Curl_dyn_ptr(&req));
+  Curl_dyn_free(&req);
+  return result;
+}
+
+/*
+ * Curl_http() gets called from the generic multi_do() function when a HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
+CURLcode Curl_http(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  struct hyptransfer *h = &data->hyp;
+  hyper_io *io = NULL;
+  hyper_clientconn_options *options = NULL;
+  hyper_task *task = NULL; /* for the handshake */
+  hyper_task *sendtask = NULL; /* for the send */
+  hyper_clientconn *client = NULL;
+  hyper_request *req = NULL;
+  hyper_headers *headers = NULL;
+  hyper_task *handshake = NULL;
+  hyper_error *hypererr = NULL;
+  CURLcode result;
+  const char *p_accept; /* Accept: string */
+  const char *method;
+  Curl_HttpReq httpreq;
+  bool h2 = FALSE;
+  const char *te = NULL; /* transfer-encoding */
+
+  /* Always consider the DO phase done after this function call, even if there
+     may be parts of the request that is not yet sent, since we can deal with
+     the rest of the request in the PERFORM phase. */
+  *done = TRUE;
+
+  infof(data, "Time for the Hyper dance\n");
+  memset(h, 0, sizeof(struct hyptransfer));
+
+  result = Curl_http_host(data, conn);
+  if(result)
+    return result;
+
+  Curl_http_method(data, conn, &method, &httpreq);
+
+  /* setup the authentication headers */
+  {
+    char *pq = NULL;
+    if(data->state.up.query) {
+      pq = aprintf("%s?%s", data->state.up.path, data->state.up.query);
+      if(!pq)
+        return CURLE_OUT_OF_MEMORY;
+    }
+    result = Curl_http_output_auth(data, conn, method, httpreq,
+                                   (pq ? pq : data->state.up.path), FALSE);
+    free(pq);
+    if(result)
+      return result;
+  }
+
+  result = Curl_http_resume(data, conn, httpreq);
+  if(result)
+    return result;
+
+  result = Curl_http_range(data, httpreq);
+  if(result)
+    return result;
+
+  result = Curl_http_useragent(data);
+  if(result)
+    return result;
+
+  io = hyper_io_new();
+  if(!io) {
+    failf(data, "Couldn't create hyper IO");
+    goto error;
+  }
+  /* tell Hyper how to read/write network data */
+  hyper_io_set_userdata(io, data);
+  hyper_io_set_read(io, Curl_hyper_recv);
+  hyper_io_set_write(io, Curl_hyper_send);
+
+  /* create an executor to poll futures */
+  if(!h->exec) {
+    h->exec = hyper_executor_new();
+    if(!h->exec) {
+      failf(data, "Couldn't create hyper executor");
+      goto error;
+    }
+  }
+
+  options = hyper_clientconn_options_new();
+  if(!options) {
+    failf(data, "Couldn't create hyper client options");
+    goto error;
+  }
+  if(conn->negnpn == CURL_HTTP_VERSION_2) {
+    hyper_clientconn_options_http2(options, 1);
+    h2 = TRUE;
+  }
+
+  hyper_clientconn_options_exec(options, h->exec);
+
+  /* "Both the `io` and the `options` are consumed in this function call" */
+  handshake = hyper_clientconn_handshake(io, options);
+  if(!handshake) {
+    failf(data, "Couldn't create hyper client handshake");
+    goto error;
+  }
+  io = NULL;
+  options = NULL;
+
+  if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
+    failf(data, "Couldn't hyper_executor_push the handshake");
+    goto error;
+  }
+  handshake = NULL; /* ownership passed on */
+
+  task = hyper_executor_poll(h->exec);
+  if(!task) {
+    failf(data, "Couldn't hyper_executor_poll the handshake");
+    goto error;
+  }
+
+  client = hyper_task_value(task);
+  hyper_task_free(task);
+
+  req = hyper_request_new();
+  if(!req) {
+    failf(data, "Couldn't hyper_request_new");
+    goto error;
+  }
+
+  if(data->set.httpversion == CURL_HTTP_VERSION_1_0) {
+    if(HYPERE_OK != hyper_request_set_version(req,
+                                              HYPER_HTTP_VERSION_1_0)) {
+      failf(data, "error setting HTTP version");
+      goto error;
+    }
+  }
+
+  if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
+    failf(data, "error setting method");
+    goto error;
+  }
+
+  result = request_target(data, conn, method, h2, req);
+  if(result)
+    goto error;
+
+  headers = hyper_request_headers(req);
+  if(!headers) {
+    failf(data, "hyper_request_headers");
+    goto error;
+  }
+
+  result = Curl_http_body(data, conn, httpreq, &te);
+  if(result)
+    return result;
+
+  if(data->state.aptr.host &&
+     Curl_hyper_header(data, headers, data->state.aptr.host))
+    goto error;
+
+  if(data->state.aptr.proxyuserpwd &&
+     Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
+    goto error;
+
+  if(data->state.aptr.userpwd &&
+     Curl_hyper_header(data, headers, data->state.aptr.userpwd))
+    goto error;
+
+  if((data->state.use_range && data->state.aptr.rangeline) &&
+     Curl_hyper_header(data, headers, data->state.aptr.rangeline))
+    goto error;
+
+  if(data->set.str[STRING_USERAGENT] &&
+     *data->set.str[STRING_USERAGENT] &&
+     data->state.aptr.uagent &&
+     Curl_hyper_header(data, headers, data->state.aptr.uagent))
+    goto error;
+
+  p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
+  if(p_accept && Curl_hyper_header(data, headers, p_accept))
+    goto error;
+
+  if(te && Curl_hyper_header(data, headers, te))
+    goto error;
+
+#ifndef CURL_DISABLE_PROXY
+  if(conn->bits.httpproxy && !conn->bits.tunnel_proxy &&
+     !Curl_checkheaders(data, "Proxy-Connection") &&
+     !Curl_checkProxyheaders(data, conn, "Proxy-Connection")) {
+    if(Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
+      goto error;
+  }
+#endif
+
+  Curl_safefree(data->state.aptr.ref);
+  if(data->change.referer && !Curl_checkheaders(data, "Referer")) {
+    data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+    if(!data->state.aptr.ref)
+      return CURLE_OUT_OF_MEMORY;
+    if(Curl_hyper_header(data, headers, data->state.aptr.ref))
+      goto error;
+  }
+
+  result = cookies(data, conn, headers);
+  if(result)
+    return result;
+
+  result = Curl_add_timecondition(data, headers);
+  if(result)
+    return result;
+
+  result = Curl_add_custom_headers(data, FALSE, headers);
+  if(result)
+    return result;
+
+  result = bodysend(data, conn, headers, req, httpreq);
+  if(result)
+    return result;
+
+  Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"\r\n", 2);
+
+  data->req.upload_chunky = FALSE;
+  sendtask = hyper_clientconn_send(client, req);
+  if(!sendtask) {
+    failf(data, "hyper_clientconn_send");
+    goto error;
+  }
+
+  if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
+    failf(data, "Couldn't hyper_executor_push the send");
+    goto error;
+  }
+
+  hyper_clientconn_free(client);
+
+  do {
+    task = hyper_executor_poll(h->exec);
+    if(task) {
+      bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
+      if(error)
+        hypererr = hyper_task_value(task);
+      hyper_task_free(task);
+      if(error)
+        goto error;
+    }
+  } while(task);
+
+  if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) {
+    /* HTTP GET/HEAD download */
+    Curl_pgrsSetUploadSize(data, 0); /* nothing */
+    Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1);
+  }
+  conn->datastream = Curl_hyper_stream;
+
+  return CURLE_OK;
+  error:
+
+  if(io)
+    hyper_io_free(io);
+
+  if(options)
+    hyper_clientconn_options_free(options);
+
+  if(handshake)
+    hyper_task_free(handshake);
+
+  if(hypererr) {
+    uint8_t errbuf[256];
+    size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+    hyper_code code = hyper_error_code(hypererr);
+    failf(data, "Hyper: [%d] %.*s", (int)code, (int)errlen, errbuf);
+    hyper_error_free(hypererr);
+  }
+  return CURLE_OUT_OF_MEMORY;
+}
+
+void Curl_hyper_done(struct Curl_easy *data)
+{
+  struct hyptransfer *h = &data->hyp;
+  if(h->exec) {
+    hyper_executor_free(h->exec);
+    h->exec = NULL;
+  }
+  if(h->read_waker) {
+    hyper_waker_free(h->read_waker);
+    h->read_waker = NULL;
+  }
+  if(h->write_waker) {
+    hyper_waker_free(h->write_waker);
+    h->write_waker = NULL;
+  }
+}
+
+#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */

+ 56 - 0
lib/c-hyper.h

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

+ 23 - 20
lib/conncache.c

@@ -6,7 +6,7 @@
  *                             \___|\___/|_| \_\_____|
  *
  * Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <[email protected]>
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 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
@@ -179,12 +179,14 @@ size_t Curl_conncache_size(struct Curl_easy *data)
    connectdata struct is setup to use.
 
    **NOTE**: When it returns, it holds the connection cache lock! */
-struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
-                                                 struct conncache *connc,
-                                                 const char **hostp)
+struct connectbundle *
+Curl_conncache_find_bundle(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           struct conncache *connc,
+                           const char **hostp)
 {
   struct connectbundle *bundle = NULL;
-  CONNCACHE_LOCK(conn->data);
+  CONNCACHE_LOCK(data);
   if(connc) {
     char key[HASHKEY_SIZE];
     hashkey(conn, key, sizeof(key), hostp);
@@ -227,15 +229,17 @@ static void conncache_remove_bundle(struct conncache *connc,
   }
 }
 
-CURLcode Curl_conncache_add_conn(struct conncache *connc,
-                                 struct connectdata *conn)
+CURLcode Curl_conncache_add_conn(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
   struct connectbundle *bundle = NULL;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
+  struct conncache *connc = data->state.conn_cache;
+  DEBUGASSERT(conn);
 
   /* *find_bundle() locks the connection cache */
-  bundle = Curl_conncache_find_bundle(conn, data->state.conn_cache, NULL);
+  bundle = Curl_conncache_find_bundle(data, conn, data->state.conn_cache,
+                                      NULL);
   if(!bundle) {
     int rc;
     char key[HASHKEY_SIZE];
@@ -259,7 +263,7 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
   conn->connection_id = connc->next_connection_id++;
   connc->num_conn++;
 
-  DEBUGF(infof(conn->data, "Added connection %ld. "
+  DEBUGF(infof(data, "Added connection %ld. "
                "The cache now contains %zu members\n",
                conn->connection_id, connc->num_conn));
 
@@ -270,8 +274,8 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
 }
 
 /*
- * Removes the connectdata object from the connection cache, but does *not*
- * clear the conn->data association. The transfer still owns this connection.
+ * Removes the connectdata object from the connection cache, but the transfer
+ * still owns this connection.
  *
  * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
  * already holds the lock or not.
@@ -318,7 +322,8 @@ void Curl_conncache_remove_conn(struct Curl_easy *data,
 bool Curl_conncache_foreach(struct Curl_easy *data,
                             struct conncache *connc,
                             void *param,
-                            int (*func)(struct connectdata *conn, void *param))
+                            int (*func)(struct Curl_easy *data,
+                                        struct connectdata *conn, void *param))
 {
   struct Curl_hash_iterator iter;
   struct Curl_llist_element *curr;
@@ -344,7 +349,7 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
       struct connectdata *conn = curr->ptr;
       curr = curr->next;
 
-      if(1 == func(conn, param)) {
+      if(1 == func(data, conn, param)) {
         CONNCACHE_UNLOCK(data);
         return TRUE;
       }
@@ -444,7 +449,7 @@ Curl_conncache_extract_bundle(struct Curl_easy *data,
   while(curr) {
     conn = curr->ptr;
 
-    if(!CONN_INUSE(conn) && !conn->data) {
+    if(!CONN_INUSE(conn)) {
       /* Set higher score for the age passed since the connection was used */
       score = Curl_timediff(now, conn->lastused);
 
@@ -502,7 +507,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
     while(curr) {
       conn = curr->ptr;
 
-      if(!CONN_INUSE(conn) && !conn->data && !conn->bits.close &&
+      if(!CONN_INUSE(conn) && !conn->bits.close &&
          !conn->bits.connect_only) {
         /* Set higher score for the age passed since the connection was used */
         score = Curl_timediff(now, conn->lastused);
@@ -543,12 +548,10 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
   conn = conncache_find_first_connection(connc);
   while(conn) {
     SIGPIPE_VARIABLE(pipe_st);
-    conn->data = connc->closure_handle;
-
-    sigpipe_ignore(conn->data, &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(conn->data, conn, TRUE);
+    Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
     (void)Curl_disconnect(connc->closure_handle, conn, FALSE);
     sigpipe_restore(&pipe_st);
 

+ 27 - 15
lib/conncache.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2015 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2015 - 2021, 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
@@ -29,6 +29,10 @@
  * be shared.
  */
 
+#include "timeval.h"
+
+struct connectdata;
+
 struct conncache {
   struct Curl_hash hash;
   size_t num_conn;
@@ -45,17 +49,24 @@ struct conncache {
 #ifdef CURLDEBUG
 /* the debug versions of these macros make extra certain that the lock is
    never doubly locked or unlocked */
-#define CONNCACHE_LOCK(x) if((x)->share) {                              \
-    Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \
-    DEBUGASSERT(!(x)->state.conncache_lock);                            \
-    (x)->state.conncache_lock = TRUE;                                   \
-  }
+#define CONNCACHE_LOCK(x)                                               \
+  do {                                                                  \
+    if((x)->share) {                                                    \
+      Curl_share_lock((x), CURL_LOCK_DATA_CONNECT,                      \
+                      CURL_LOCK_ACCESS_SINGLE);                         \
+      DEBUGASSERT(!(x)->state.conncache_lock);                          \
+      (x)->state.conncache_lock = TRUE;                                 \
+    }                                                                   \
+  } while(0)
 
-#define CONNCACHE_UNLOCK(x) if((x)->share) {                            \
-    DEBUGASSERT((x)->state.conncache_lock);                             \
-    (x)->state.conncache_lock = FALSE;                                  \
-    Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT);                     \
-  }
+#define CONNCACHE_UNLOCK(x)                                             \
+  do {                                                                  \
+    if((x)->share) {                                                    \
+      DEBUGASSERT((x)->state.conncache_lock);                           \
+      (x)->state.conncache_lock = FALSE;                                \
+      Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT);                   \
+    }                                                                   \
+  } while(0)
 #else
 #define CONNCACHE_LOCK(x) if((x)->share)                                \
     Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
@@ -74,7 +85,8 @@ int Curl_conncache_init(struct conncache *, int size);
 void Curl_conncache_destroy(struct conncache *connc);
 
 /* return the correct bundle, to a host or a proxy */
-struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
+struct connectbundle *Curl_conncache_find_bundle(struct Curl_easy *data,
+                                                 struct connectdata *conn,
                                                  struct conncache *connc,
                                                  const char **hostp);
 /* returns number of connections currently held in the connection cache */
@@ -82,15 +94,15 @@ size_t Curl_conncache_size(struct Curl_easy *data);
 
 bool Curl_conncache_return_conn(struct Curl_easy *data,
                                 struct connectdata *conn);
-CURLcode Curl_conncache_add_conn(struct conncache *connc,
-                                 struct connectdata *conn) WARN_UNUSED_RESULT;
+CURLcode Curl_conncache_add_conn(struct Curl_easy *data) WARN_UNUSED_RESULT;
 void Curl_conncache_remove_conn(struct Curl_easy *data,
                                 struct connectdata *conn,
                                 bool lock);
 bool Curl_conncache_foreach(struct Curl_easy *data,
                             struct conncache *connc,
                             void *param,
-                            int (*func)(struct connectdata *conn,
+                            int (*func)(struct Curl_easy *data,
+                                        struct connectdata *conn,
                                         void *param));
 
 struct connectdata *

+ 139 - 97
lib/connect.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -160,7 +160,8 @@ tcpkeepalive(struct Curl_easy *data,
 }
 
 static CURLcode
-singleipconnect(struct connectdata *conn,
+singleipconnect(struct Curl_easy *data,
+                struct connectdata *conn,
                 const struct Curl_addrinfo *ai, /* start connecting to this */
                 int tempindex);          /* 0 or 1 among the temp ones */
 
@@ -236,11 +237,10 @@ timediff_t Curl_timeleft(struct Curl_easy *data,
   return timeout_ms;
 }
 
-static CURLcode bindlocal(struct connectdata *conn,
+static CURLcode bindlocal(struct Curl_easy *data,
                           curl_socket_t sockfd, int af, unsigned int scope)
 {
-  struct Curl_easy *data = conn->data;
-
+  struct connectdata *conn = data->conn;
   struct Curl_sockaddr_storage sa;
   struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
   curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
@@ -256,6 +256,9 @@ static CURLcode bindlocal(struct connectdata *conn,
   int portnum = data->set.localportrange;
   const char *dev = data->set.str[STRING_DEVICE];
   int error;
+#ifdef IP_BIND_ADDRESS_NO_PORT
+  int on = 1;
+#endif
 
   /*************************************************************
    * Select device to bind socket to
@@ -345,7 +348,7 @@ static CURLcode bindlocal(struct connectdata *conn,
        * of the connection. The resolve functions should really be changed
        * to take a type parameter instead.
        */
-      long ipver = conn->ip_version;
+      unsigned char ipver = conn->ip_version;
       int rc;
 
       if(af == AF_INET)
@@ -355,9 +358,9 @@ static CURLcode bindlocal(struct connectdata *conn,
         conn->ip_version = CURL_IPRESOLVE_V6;
 #endif
 
-      rc = Curl_resolv(conn, dev, 0, FALSE, &h);
+      rc = Curl_resolv(data, dev, 0, FALSE, &h);
       if(rc == CURLRESOLV_PENDING)
-        (void)Curl_resolver_wait_resolv(conn, &h);
+        (void)Curl_resolver_wait_resolv(data, &h);
       conn->ip_version = ipver;
 
       if(h) {
@@ -441,7 +444,9 @@ static CURLcode bindlocal(struct connectdata *conn,
       sizeof_sa = sizeof(struct sockaddr_in);
     }
   }
-
+#ifdef IP_BIND_ADDRESS_NO_PORT
+  (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
+#endif
   for(;;) {
     if(bind(sockfd, sock, sizeof_sa) >= 0) {
       /* we succeeded to bind */
@@ -568,7 +573,8 @@ static struct Curl_addrinfo *ainext(struct connectdata *conn,
 
 /* Used within the multi interface. Try next IP address, returns error if no
    more address exists or error */
-static CURLcode trynextip(struct connectdata *conn,
+static CURLcode trynextip(struct Curl_easy *data,
+                          struct connectdata *conn,
                           int sockindex,
                           int tempindex)
 {
@@ -586,7 +592,7 @@ static CURLcode trynextip(struct connectdata *conn,
 
     while(ai) {
       if(ai) {
-        result = singleipconnect(conn, ai, tempindex);
+        result = singleipconnect(data, conn, ai, tempindex);
         if(result == CURLE_COULDNT_CONNECT) {
           ai = ainext(conn, tempindex, TRUE);
           continue;
@@ -597,21 +603,25 @@ static CURLcode trynextip(struct connectdata *conn,
   }
 
   if(fd_to_close != CURL_SOCKET_BAD)
-    Curl_closesocket(conn, fd_to_close);
+    Curl_closesocket(data, conn, fd_to_close);
 
   return result;
 }
 
-/* Copies connection info into the session handle to make it available
-   when the session handle is no longer associated with a connection. */
-void Curl_persistconninfo(struct connectdata *conn)
+/* Copies connection info into the transfer handle to make it available when
+   the transfer handle is no longer associated with the connection. */
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+                          char *local_ip, long local_port)
 {
-  memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
-  memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
-  conn->data->info.conn_scheme = conn->handler->scheme;
-  conn->data->info.conn_protocol = conn->handler->protocol;
-  conn->data->info.conn_primary_port = conn->primary_port;
-  conn->data->info.conn_local_port = conn->local_port;
+  memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
+  if(local_ip && local_ip[0])
+    memcpy(data->info.conn_local_ip, local_ip, MAX_IPADR_LEN);
+  else
+    data->info.conn_local_ip[0] = 0;
+  data->info.conn_scheme = conn->handler->scheme;
+  data->info.conn_protocol = conn->handler->protocol;
+  data->info.conn_primary_port = conn->port;
+  data->info.conn_local_port = local_port;
 }
 
 /* retrieves ip address and port from a sockaddr structure.
@@ -673,27 +683,30 @@ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
 
 /* retrieves the start/end point information of a socket of an established
    connection */
-void Curl_conninfo_remote(struct connectdata *conn, curl_socket_t sockfd)
+void Curl_conninfo_remote(struct Curl_easy *data,
+                          struct connectdata *conn, curl_socket_t sockfd)
 {
 #ifdef HAVE_GETPEERNAME
   char buffer[STRERROR_LEN];
   struct Curl_sockaddr_storage ssrem;
   curl_socklen_t plen;
+  long port;
   plen = sizeof(struct Curl_sockaddr_storage);
+  memset(&ssrem, 0, sizeof(ssrem));
   if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
     int error = SOCKERRNO;
-    failf(conn->data, "getpeername() failed with errno %d: %s",
+    failf(data, "getpeername() failed with errno %d: %s",
           error, Curl_strerror(error, buffer, sizeof(buffer)));
     return;
   }
   if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
-                       conn->primary_ip, &conn->primary_port)) {
-    failf(conn->data, "ssrem inet_ntop() failed with errno %d: %s",
+                       conn->primary_ip, &port)) {
+    failf(data, "ssrem inet_ntop() failed with errno %d: %s",
           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
     return;
   }
-  memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
 #else
+  (void)data;
   (void)conn;
   (void)sockfd;
 #endif
@@ -701,7 +714,8 @@ void Curl_conninfo_remote(struct connectdata *conn, curl_socket_t sockfd)
 
 /* retrieves the start/end point information of a socket of an established
    connection */
-void Curl_conninfo_local(struct connectdata *conn, curl_socket_t sockfd)
+void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
+                         char *local_ip, long *local_port)
 {
 #ifdef HAVE_GETSOCKNAME
   char buffer[STRERROR_LEN];
@@ -711,35 +725,44 @@ void Curl_conninfo_local(struct connectdata *conn, curl_socket_t sockfd)
   memset(&ssloc, 0, sizeof(ssloc));
   if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
     int error = SOCKERRNO;
-    failf(conn->data, "getsockname() failed with errno %d: %s",
+    failf(data, "getsockname() failed with errno %d: %s",
           error, Curl_strerror(error, buffer, sizeof(buffer)));
     return;
   }
   if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
-                       conn->local_ip, &conn->local_port)) {
-    failf(conn->data, "ssloc inet_ntop() failed with errno %d: %s",
+                       local_ip, local_port)) {
+    failf(data, "ssloc inet_ntop() failed with errno %d: %s",
           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
     return;
   }
 #else
-  (void)conn;
+  (void)data;
   (void)sockfd;
+  (void)local_ip;
+  (void)local_port;
 #endif
 }
 
 /* retrieves the start/end point information of a socket of an established
    connection */
-void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
+void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
+                         curl_socket_t sockfd)
 {
+  /* 'local_ip' and 'local_port' get filled with local's numerical
+     ip address and port number whenever an outgoing connection is
+     **established** from the primary socket to a remote address. */
+  char local_ip[MAX_IPADR_LEN] = "";
+  long local_port = -1;
+
   if(conn->transport == TRNSPRT_TCP) {
     if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
-      Curl_conninfo_remote(conn, sockfd);
-      Curl_conninfo_local(conn, sockfd);
+      Curl_conninfo_remote(data, conn, sockfd);
+      Curl_conninfo_local(data, sockfd, local_ip, &local_port);
     }
   } /* end of TCP-only section */
 
   /* persist connection info in session handle */
-  Curl_persistconninfo(conn);
+  Curl_persistconninfo(data, conn, local_ip, local_port);
 }
 
 /* After a TCP connection to the proxy has been verified, this function does
@@ -749,12 +772,13 @@ void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
    Note: this function's sub-functions call failf()
 
 */
-static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
+static CURLcode connect_SOCKS(struct Curl_easy *data, int sockindex,
                               bool *done)
 {
   CURLcode result = CURLE_OK;
 #ifndef CURL_DISABLE_PROXY
   CURLproxycode pxresult = CURLPX_OK;
+  struct connectdata *conn = data->conn;
   if(conn->bits.socksproxy) {
     /* for the secondary socket (FTP), use the "connect to host"
      * but ignore the "connect to port" (use the secondary port)
@@ -775,27 +799,27 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
     case CURLPROXY_SOCKS5:
     case CURLPROXY_SOCKS5_HOSTNAME:
       pxresult = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
-                             host, port, sockindex, conn, done);
+                             host, port, sockindex, data, done);
       break;
 
     case CURLPROXY_SOCKS4:
     case CURLPROXY_SOCKS4A:
       pxresult = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
-                             conn, done);
+                             data, done);
       break;
 
     default:
-      failf(conn->data, "unknown proxytype option given");
+      failf(data, "unknown proxytype option given");
       result = CURLE_COULDNT_CONNECT;
     } /* switch proxytype */
     if(pxresult) {
       result = CURLE_PROXY;
-      conn->data->info.pxcode = pxresult;
+      data->info.pxcode = pxresult;
     }
   }
   else
 #else
-    (void)conn;
+    (void)data;
     (void)sockindex;
 #endif /* CURL_DISABLE_PROXY */
     *done = TRUE; /* no SOCKS proxy, so consider us connected */
@@ -807,7 +831,8 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
  * post_SOCKS() is called after a successful connect to the peer, which
  * *could* be a SOCKS proxy
  */
-static void post_SOCKS(struct connectdata *conn,
+static void post_SOCKS(struct Curl_easy *data,
+                       struct connectdata *conn,
                        int sockindex,
                        bool *connected)
 {
@@ -815,21 +840,21 @@ static void post_SOCKS(struct connectdata *conn,
 
   *connected = TRUE;
   if(sockindex == FIRSTSOCKET)
-    Curl_pgrsTime(conn->data, TIMER_CONNECT); /* connect done */
-  Curl_updateconninfo(conn, conn->sock[sockindex]);
-  Curl_verboseconnect(conn);
-  conn->data->info.numconnects++; /* to track the number of connections made */
+    Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
+  Curl_updateconninfo(data, conn, conn->sock[sockindex]);
+  Curl_verboseconnect(data, conn);
+  data->info.numconnects++; /* to track the number of connections made */
 }
 
 /*
  * Curl_is_connected() checks if the socket has connected.
  */
 
-CURLcode Curl_is_connected(struct connectdata *conn,
+CURLcode Curl_is_connected(struct Curl_easy *data,
+                           struct connectdata *conn,
                            int sockindex,
                            bool *connected)
 {
-  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   timediff_t allow;
   int error = 0;
@@ -860,9 +885,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
   if(SOCKS_STATE(conn->cnnct.state)) {
     /* still doing SOCKS */
-    result = connect_SOCKS(conn, sockindex, connected);
+    result = connect_SOCKS(data, sockindex, connected);
     if(!result && *connected)
-      post_SOCKS(conn, sockindex, connected);
+      post_SOCKS(data, conn, sockindex, connected);
     return result;
   }
 
@@ -873,13 +898,13 @@ CURLcode Curl_is_connected(struct connectdata *conn,
     error = 0;
 #ifdef ENABLE_QUIC
     if(conn->transport == TRNSPRT_QUIC) {
-      result = Curl_quic_is_connected(conn, i, connected);
+      result = Curl_quic_is_connected(data, conn, i, connected);
       if(!result && *connected) {
         /* use this socket from now on */
         conn->sock[sockindex] = conn->tempsock[i];
         conn->ip_addr = conn->tempaddr[i];
         conn->tempsock[i] = CURL_SOCKET_BAD;
-        post_SOCKS(conn, sockindex, connected);
+        post_SOCKS(data, conn, sockindex, connected);
         connkeep(conn, "HTTP/3 default");
         return CURLE_OK;
       }
@@ -914,7 +939,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
          (Curl_timediff(now, conn->connecttime) >=
           data->set.happy_eyeballs_timeout)) {
         conn->bits.parallel_connect = TRUE; /* starting now */
-        trynextip(conn, sockindex, 1);
+        trynextip(data, conn, sockindex, 1);
       }
     }
     else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
@@ -931,17 +956,17 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
         /* close the other socket, if open */
         if(conn->tempsock[other] != CURL_SOCKET_BAD) {
-          Curl_closesocket(conn, conn->tempsock[other]);
+          Curl_closesocket(data, conn, conn->tempsock[other]);
           conn->tempsock[other] = CURL_SOCKET_BAD;
         }
 
         /* see if we need to kick off any SOCKS proxy magic once we
            connected */
-        result = connect_SOCKS(conn, sockindex, connected);
+        result = connect_SOCKS(data, sockindex, connected);
         if(result || !*connected)
           return result;
 
-        post_SOCKS(conn, sockindex, connected);
+        post_SOCKS(data, conn, sockindex, connected);
 
         return CURLE_OK;
       }
@@ -972,7 +997,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
         conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ?
           allow : allow / 2;
         ainext(conn, i, TRUE);
-        status = trynextip(conn, sockindex, i);
+        status = trynextip(data, conn, sockindex, i);
         if((status != CURLE_COULDNT_CONNECT) ||
            conn->tempsock[other] == CURL_SOCKET_BAD)
           /* the last attempt failed and no other sockets remain open */
@@ -990,7 +1015,7 @@ CURLcode Curl_is_connected(struct connectdata *conn,
 
     /* if the first address family runs out of addresses to try before the
        happy eyeball timeout, go ahead and try the next family now */
-    result = trynextip(conn, sockindex, 1);
+    result = trynextip(data, conn, sockindex, 1);
     if(!result)
       return result;
 
@@ -1010,8 +1035,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
           hostname, conn->port,
           Curl_strerror(error, buffer, sizeof(buffer)));
 
-    Curl_quic_disconnect(conn, 0);
-    Curl_quic_disconnect(conn, 1);
+    Curl_quic_disconnect(data, conn, 0);
+    Curl_quic_disconnect(data, conn, 1);
 
 #ifdef WSAETIMEDOUT
     if(WSAETIMEDOUT == data->state.os_errno)
@@ -1027,16 +1052,15 @@ CURLcode Curl_is_connected(struct connectdata *conn,
   return result;
 }
 
-static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
+static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
 {
 #if defined(TCP_NODELAY)
   curl_socklen_t onoff = (curl_socklen_t) 1;
   int level = IPPROTO_TCP;
 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  struct Curl_easy *data = conn->data;
   char buffer[STRERROR_LEN];
 #else
-  (void) conn;
+  (void) data;
 #endif
 
   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
@@ -1044,7 +1068,7 @@ static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
     infof(data, "Could not set TCP_NODELAY: %s\n",
           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
 #else
-  (void)conn;
+  (void)data;
   (void)sockfd;
 #endif
 }
@@ -1054,10 +1078,9 @@ static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
    sending data to a dead peer (instead of relying on the 4th argument to send
    being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
    systems? */
-static void nosigpipe(struct connectdata *conn,
+static void nosigpipe(struct Curl_easy *data,
                       curl_socket_t sockfd)
 {
-  struct Curl_easy *data = conn->data;
   int onoff = 1;
   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
                 sizeof(onoff)) < 0) {
@@ -1123,7 +1146,8 @@ void Curl_sndbufset(curl_socket_t sockfd)
  * singleipconnect() connects to the given IP only, and it may return without
  * having connected.
  */
-static CURLcode singleipconnect(struct connectdata *conn,
+static CURLcode singleipconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 const struct Curl_addrinfo *ai,
                                 int tempindex)
 {
@@ -1131,7 +1155,6 @@ static CURLcode singleipconnect(struct connectdata *conn,
   int rc = -1;
   int error = 0;
   bool isconnected = FALSE;
-  struct Curl_easy *data = conn->data;
   curl_socket_t sockfd;
   CURLcode result;
   char ipaddress[MAX_IPADR_LEN];
@@ -1144,7 +1167,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
   curl_socket_t *sockp = &conn->tempsock[tempindex];
   *sockp = CURL_SOCKET_BAD;
 
-  result = Curl_socket(conn, ai, &addr, &sockfd);
+  result = Curl_socket(data, ai, &addr, &sockfd);
   if(result)
     return result;
 
@@ -1154,7 +1177,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
     /* malformed address or bug in inet_ntop, try next address */
     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
-    Curl_closesocket(conn, sockfd);
+    Curl_closesocket(data, conn, sockfd);
     return CURLE_OK;
   }
   infof(data, "  Trying %s:%ld...\n", ipaddress, port);
@@ -1166,9 +1189,9 @@ static CURLcode singleipconnect(struct connectdata *conn,
   is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
 #endif
   if(is_tcp && data->set.tcp_nodelay)
-    tcpnodelay(conn, sockfd);
+    tcpnodelay(data, sockfd);
 
-  nosigpipe(conn, sockfd);
+  nosigpipe(data, sockfd);
 
   Curl_sndbufset(sockfd);
 
@@ -1186,7 +1209,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
       isconnected = TRUE;
     else if(error) {
-      Curl_closesocket(conn, sockfd); /* close the socket and bail out */
+      Curl_closesocket(data, conn, sockfd); /* close the socket and bail out */
       return CURLE_ABORTED_BY_CALLBACK;
     }
   }
@@ -1197,10 +1220,10 @@ static CURLcode singleipconnect(struct connectdata *conn,
      || addr.family == AF_INET6
 #endif
     ) {
-    result = bindlocal(conn, sockfd, addr.family,
+    result = bindlocal(data, sockfd, addr.family,
                        Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
     if(result) {
-      Curl_closesocket(conn, sockfd); /* close socket and bail out */
+      Curl_closesocket(data, conn, sockfd); /* close socket and bail out */
       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
         /* The address family is not supported on this interface.
            We can continue trying addresses */
@@ -1268,7 +1291,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
     else if(conn->transport == TRNSPRT_QUIC) {
       /* pass in 'sockfd' separately since it hasn't been put into the
          tempsock array at this point */
-      result = Curl_quic_connect(conn, sockfd, tempindex,
+      result = Curl_quic_connect(data, conn, sockfd, tempindex,
                                  &addr.sa_addr, addr.addrlen);
       if(result)
         error = SOCKERRNO;
@@ -1303,7 +1326,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
       data->state.os_errno = error;
 
       /* connect failed */
-      Curl_closesocket(conn, sockfd);
+      Curl_closesocket(data, conn, sockfd);
       result = CURLE_COULDNT_CONNECT;
     }
   }
@@ -1320,10 +1343,10 @@ static CURLcode singleipconnect(struct connectdata *conn,
  * pointer with the connected socket.
  */
 
-CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
+CURLcode Curl_connecthost(struct Curl_easy *data,
+                          struct connectdata *conn,  /* context */
                           const struct Curl_dns_entry *remotehost)
 {
-  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_COULDNT_CONNECT;
   int i;
   timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
@@ -1361,7 +1384,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   /* get through the list in family order in case of quick failures */
   for(i = 0; (i < 2) && result; i++) {
     while(conn->tempaddr[i]) {
-      result = singleipconnect(conn, conn->tempaddr[i], i);
+      result = singleipconnect(data, conn, conn->tempaddr[i], i);
       if(!result)
         break;
       ainext(conn, i, TRUE);
@@ -1370,7 +1393,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
   if(result)
     return result;
 
-  Curl_expire(conn->data, data->set.happy_eyeballs_timeout,
+  Curl_expire(data, data->set.happy_eyeballs_timeout,
               EXPIRE_HAPPY_EYEBALLS);
 
   return CURLE_OK;
@@ -1381,9 +1404,11 @@ struct connfind {
   struct connectdata *found;
 };
 
-static int conn_is_conn(struct connectdata *conn, void *param)
+static int conn_is_conn(struct Curl_easy *data,
+                        struct connectdata *conn, void *param)
 {
   struct connfind *f = (struct connfind *)param;
+  (void)data;
   if(conn->connection_id == f->id_tofind) {
     f->found = conn;
     return 1;
@@ -1465,8 +1490,8 @@ bool Curl_connalive(struct connectdata *conn)
  *
  * 'conn' can be NULL, beware!
  */
-int Curl_closesocket(struct connectdata *conn,
-                      curl_socket_t sock)
+int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
+                     curl_socket_t sock)
 {
   if(conn && conn->fclosesocket) {
     if((sock == conn->sock[SECONDARYSOCKET]) && conn->bits.sock_accepted)
@@ -1476,17 +1501,17 @@ int Curl_closesocket(struct connectdata *conn,
       conn->bits.sock_accepted = FALSE;
     else {
       int rc;
-      Curl_multi_closed(conn->data, sock);
-      Curl_set_in_callback(conn->data, true);
+      Curl_multi_closed(data, sock);
+      Curl_set_in_callback(data, true);
       rc = conn->fclosesocket(conn->closesocket_client, sock);
-      Curl_set_in_callback(conn->data, false);
+      Curl_set_in_callback(data, false);
       return rc;
     }
   }
 
   if(conn)
     /* tell the multi-socket code about this */
-    Curl_multi_closed(conn->data, sock);
+    Curl_multi_closed(data, sock);
 
   sclose(sock);
 
@@ -1502,12 +1527,12 @@ int Curl_closesocket(struct connectdata *conn,
  * If the open socket callback is set, used that!
  *
  */
-CURLcode Curl_socket(struct connectdata *conn,
+CURLcode Curl_socket(struct Curl_easy *data,
                      const struct Curl_addrinfo *ai,
                      struct Curl_sockaddr_ex *addr,
                      curl_socket_t *sockfd)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct Curl_sockaddr_ex dummy;
 
   if(!addr)
@@ -1568,8 +1593,21 @@ CURLcode Curl_socket(struct connectdata *conn,
   }
 #endif
 
-  return CURLE_OK;
+#if defined(__linux__) && defined(IP_RECVERR)
+  if(addr->socktype == SOCK_DGRAM) {
+    int one = 1;
+    switch(addr->family) {
+    case AF_INET:
+      (void)setsockopt(*sockfd, SOL_IP, IP_RECVERR, &one, sizeof(one));
+      break;
+    case AF_INET6:
+      (void)setsockopt(*sockfd, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
+      break;
+    }
+  }
+#endif
 
+  return CURLE_OK;
 }
 
 /*
@@ -1582,16 +1620,20 @@ void Curl_conncontrol(struct connectdata *conn,
 #endif
   )
 {
-  /* close if a connection, or a stream that isn't multiplexed */
-  bool closeit = (ctrl == CONNCTRL_CONNECTION) ||
-    ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
+  /* close if a connection, or a stream that isn't multiplexed. */
+  /* This function will be called both before and after this connection is
+     associated with a transfer. */
+  bool closeit;
   DEBUGASSERT(conn);
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+  (void)reason; /* useful for debugging */
+#endif
+  closeit = (ctrl == CONNCTRL_CONNECTION) ||
+    ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
   if((ctrl == CONNCTRL_STREAM) &&
      (conn->handler->flags & PROTOPT_STREAM))
-    DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
+    ;
   else if((bit)closeit != conn->bits.close) {
-    DEBUGF(infof(conn->data, "Marked for [%s]: %s\n",
-                 closeit?"closure":"keep alive", reason));
     conn->bits.close = closeit; /* the only place in the source code that
                                    should assign this bit */
   }

+ 16 - 9
lib/connect.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -27,11 +27,13 @@
 #include "sockaddr.h"
 #include "timeval.h"
 
-CURLcode Curl_is_connected(struct connectdata *conn,
+CURLcode Curl_is_connected(struct Curl_easy *data,
+                           struct connectdata *conn,
                            int sockindex,
                            bool *connected);
 
-CURLcode Curl_connecthost(struct connectdata *conn,
+CURLcode Curl_connecthost(struct Curl_easy *data,
+                          struct connectdata *conn,
                           const struct Curl_dns_entry *host);
 
 /* generic function that returns how much time there's left to run, according
@@ -74,11 +76,16 @@ void Curl_sndbufset(curl_socket_t sockfd);
 #define Curl_sndbufset(y) Curl_nop_stmt
 #endif
 
-void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd);
-void Curl_conninfo_remote(struct connectdata *conn, curl_socket_t sockfd);
-void Curl_conninfo_local(struct connectdata *conn, curl_socket_t sockfd);
-void Curl_persistconninfo(struct connectdata *conn);
-int Curl_closesocket(struct connectdata *conn, curl_socket_t sock);
+void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
+                         curl_socket_t sockfd);
+void Curl_conninfo_remote(struct Curl_easy *data, struct connectdata *conn,
+                          curl_socket_t sockfd);
+void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
+                         char *local_ip, long *local_port);
+void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
+                          char *local_ip, long local_port);
+int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
+                     curl_socket_t sock);
 
 /*
  * The Curl_sockaddr_ex structure is basically libcurl's external API
@@ -106,7 +113,7 @@ struct Curl_sockaddr_ex {
  * socket callback is set, used that!
  *
  */
-CURLcode Curl_socket(struct connectdata *conn,
+CURLcode Curl_socket(struct Curl_easy *data,
                      const struct Curl_addrinfo *ai,
                      struct Curl_sockaddr_ex *addr,
                      curl_socket_t *sockfd);

+ 84 - 88
lib/content_encoding.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -104,9 +104,8 @@ zfree_cb(voidpf opaque, voidpf ptr)
 }
 
 static CURLcode
-process_zlib_error(struct connectdata *conn, z_stream *z)
+process_zlib_error(struct Curl_easy *data, z_stream *z)
 {
-  struct Curl_easy *data = conn->data;
   if(z->msg)
     failf(data, "Error while processing content unencoding: %s",
           z->msg);
@@ -118,7 +117,7 @@ process_zlib_error(struct connectdata *conn, z_stream *z)
 }
 
 static CURLcode
-exit_zlib(struct connectdata *conn,
+exit_zlib(struct Curl_easy *data,
           z_stream *z, zlibInitState *zlib_init, CURLcode result)
 {
   if(*zlib_init == ZLIB_GZIP_HEADER)
@@ -126,14 +125,14 @@ exit_zlib(struct connectdata *conn,
 
   if(*zlib_init != ZLIB_UNINIT) {
     if(inflateEnd(z) != Z_OK && result == CURLE_OK)
-      result = process_zlib_error(conn, z);
+      result = process_zlib_error(data, z);
     *zlib_init = ZLIB_UNINIT;
   }
 
   return result;
 }
 
-static CURLcode process_trailer(struct connectdata *conn,
+static CURLcode process_trailer(struct Curl_easy *data,
                                 struct zlib_params *zp)
 {
   z_stream *z = &zp->z;
@@ -149,7 +148,7 @@ static CURLcode process_trailer(struct connectdata *conn,
   if(z->avail_in)
     result = CURLE_WRITE_ERROR;
   if(result || !zp->trailerlen)
-    result = exit_zlib(conn, z, &zp->zlib_init, result);
+    result = exit_zlib(data, z, &zp->zlib_init, result);
   else {
     /* Only occurs for gzip with zlib < 1.2.0.4 or raw deflate. */
     zp->zlib_init = ZLIB_EXTERNAL_TRAILER;
@@ -157,7 +156,7 @@ static CURLcode process_trailer(struct connectdata *conn,
   return result;
 }
 
-static CURLcode inflate_stream(struct connectdata *conn,
+static CURLcode inflate_stream(struct Curl_easy *data,
                                struct contenc_writer *writer,
                                zlibInitState started)
 {
@@ -174,13 +173,13 @@ static CURLcode inflate_stream(struct connectdata *conn,
      zp->zlib_init != ZLIB_INFLATING &&
      zp->zlib_init != ZLIB_INIT_GZIP &&
      zp->zlib_init != ZLIB_GZIP_INFLATING)
-    return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);
+    return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
 
   /* Dynamically allocate a buffer for decompression because it's uncommonly
      large to hold on the stack */
   decomp = malloc(DSIZ);
   if(decomp == NULL)
-    return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+    return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
 
   /* because the buffer size is fixed, iteratively decompress and transfer to
      the client via downstream_write function. */
@@ -204,10 +203,10 @@ static CURLcode inflate_stream(struct connectdata *conn,
     if(z->avail_out != DSIZ) {
       if(status == Z_OK || status == Z_STREAM_END) {
         zp->zlib_init = started;      /* Data started. */
-        result = Curl_unencode_write(conn, writer->downstream, decomp,
+        result = Curl_unencode_write(data, writer->downstream, decomp,
                                      DSIZ - z->avail_out);
         if(result) {
-          exit_zlib(conn, z, &zp->zlib_init, result);
+          exit_zlib(data, z, &zp->zlib_init, result);
           break;
         }
       }
@@ -223,7 +222,7 @@ static CURLcode inflate_stream(struct connectdata *conn,
       /* No more data to flush: just exit loop. */
       break;
     case Z_STREAM_END:
-      result = process_trailer(conn, zp);
+      result = process_trailer(data, zp);
       break;
     case Z_DATA_ERROR:
       /* some servers seem to not generate zlib headers, so this is an attempt
@@ -243,7 +242,7 @@ static CURLcode inflate_stream(struct connectdata *conn,
       }
       /* FALLTHROUGH */
     default:
-      result = exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
+      result = exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
       break;
     }
   }
@@ -260,7 +259,7 @@ static CURLcode inflate_stream(struct connectdata *conn,
 
 
 /* Deflate handler. */
-static CURLcode deflate_init_writer(struct connectdata *conn,
+static CURLcode deflate_init_writer(struct Curl_easy *data,
                                     struct contenc_writer *writer)
 {
   struct zlib_params *zp = (struct zlib_params *) &writer->params;
@@ -274,12 +273,12 @@ static CURLcode deflate_init_writer(struct connectdata *conn,
   z->zfree = (free_func) zfree_cb;
 
   if(inflateInit(z) != Z_OK)
-    return process_zlib_error(conn, z);
+    return process_zlib_error(data, z);
   zp->zlib_init = ZLIB_INIT;
   return CURLE_OK;
 }
 
-static CURLcode deflate_unencode_write(struct connectdata *conn,
+static CURLcode deflate_unencode_write(struct Curl_easy *data,
                                        struct contenc_writer *writer,
                                        const char *buf, size_t nbytes)
 {
@@ -291,19 +290,19 @@ static CURLcode deflate_unencode_write(struct connectdata *conn,
   z->avail_in = (uInt) nbytes;
 
   if(zp->zlib_init == ZLIB_EXTERNAL_TRAILER)
-    return process_trailer(conn, zp);
+    return process_trailer(data, zp);
 
   /* Now uncompress the data */
-  return inflate_stream(conn, writer, ZLIB_INFLATING);
+  return inflate_stream(data, writer, ZLIB_INFLATING);
 }
 
-static void deflate_close_writer(struct connectdata *conn,
+static void deflate_close_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
   struct zlib_params *zp = (struct zlib_params *) &writer->params;
   z_stream *z = &zp->z;     /* zlib state structure */
 
-  exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
+  exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
 }
 
 static const struct content_encoding deflate_encoding = {
@@ -317,7 +316,7 @@ static const struct content_encoding deflate_encoding = {
 
 
 /* Gzip handler. */
-static CURLcode gzip_init_writer(struct connectdata *conn,
+static CURLcode gzip_init_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
   struct zlib_params *zp = (struct zlib_params *) &writer->params;
@@ -333,14 +332,14 @@ static CURLcode gzip_init_writer(struct connectdata *conn,
   if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
     /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
     if(inflateInit2(z, MAX_WBITS + 32) != Z_OK) {
-      return process_zlib_error(conn, z);
+      return process_zlib_error(data, z);
     }
     zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
   }
   else {
     /* we must parse the gzip header and trailer ourselves */
     if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
-      return process_zlib_error(conn, z);
+      return process_zlib_error(data, z);
     }
     zp->trailerlen = 8; /* A CRC-32 and a 32-bit input size (RFC 1952, 2.2) */
     zp->zlib_init = ZLIB_INIT; /* Initial call state */
@@ -433,7 +432,7 @@ static enum {
 }
 #endif
 
-static CURLcode gzip_unencode_write(struct connectdata *conn,
+static CURLcode gzip_unencode_write(struct Curl_easy *data,
                                     struct contenc_writer *writer,
                                     const char *buf, size_t nbytes)
 {
@@ -445,13 +444,13 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
     z->next_in = (Bytef *) buf;
     z->avail_in = (uInt) nbytes;
     /* Now uncompress the data */
-    return inflate_stream(conn, writer, ZLIB_INIT_GZIP);
+    return inflate_stream(data, writer, ZLIB_INIT_GZIP);
   }
 
 #ifndef OLD_ZLIB_SUPPORT
   /* Support for old zlib versions is compiled away and we are running with
      an old version, so return an error. */
-  return exit_zlib(conn, z, &zp->zlib_init, CURLE_WRITE_ERROR);
+  return exit_zlib(data, z, &zp->zlib_init, CURLE_WRITE_ERROR);
 
 #else
   /* This next mess is to get around the potential case where there isn't
@@ -489,7 +488,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
       z->avail_in = (uInt) nbytes;
       z->next_in = malloc(z->avail_in);
       if(z->next_in == NULL) {
-        return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+        return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
       }
       memcpy(z->next_in, buf, z->avail_in);
       zp->zlib_init = ZLIB_GZIP_HEADER;  /* Need more gzip header data state */
@@ -498,7 +497,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
 
     case GZIP_BAD:
     default:
-      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
+      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
     }
 
   }
@@ -511,7 +510,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
     z->avail_in += (uInt) nbytes;
     z->next_in = Curl_saferealloc(z->next_in, z->avail_in);
     if(z->next_in == NULL) {
-      return exit_zlib(conn, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
+      return exit_zlib(data, z, &zp->zlib_init, CURLE_OUT_OF_MEMORY);
     }
     /* Append the new block of data to the previous one */
     memcpy(z->next_in + z->avail_in - nbytes, buf, nbytes);
@@ -532,7 +531,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
 
     case GZIP_BAD:
     default:
-      return exit_zlib(conn, z, &zp->zlib_init, process_zlib_error(conn, z));
+      return exit_zlib(data, z, &zp->zlib_init, process_zlib_error(data, z));
     }
 
   }
@@ -541,7 +540,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
   case ZLIB_EXTERNAL_TRAILER:
     z->next_in = (Bytef *) buf;
     z->avail_in = (uInt) nbytes;
-    return process_trailer(conn, zp);
+    return process_trailer(data, zp);
 
   case ZLIB_GZIP_INFLATING:
   default:
@@ -557,17 +556,17 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
   }
 
   /* We've parsed the header, now uncompress the data */
-  return inflate_stream(conn, writer, ZLIB_GZIP_INFLATING);
+  return inflate_stream(data, writer, ZLIB_GZIP_INFLATING);
 #endif
 }
 
-static void gzip_close_writer(struct connectdata *conn,
+static void gzip_close_writer(struct Curl_easy *data,
                               struct contenc_writer *writer)
 {
   struct zlib_params *zp = (struct zlib_params *) &writer->params;
   z_stream *z = &zp->z;     /* zlib state structure */
 
-  exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
+  exit_zlib(data, z, &zp->zlib_init, CURLE_OK);
 }
 
 static const struct content_encoding gzip_encoding = {
@@ -626,11 +625,11 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
   return CURLE_WRITE_ERROR;
 }
 
-static CURLcode brotli_init_writer(struct connectdata *conn,
+static CURLcode brotli_init_writer(struct Curl_easy *data,
                                    struct contenc_writer *writer)
 {
   struct brotli_params *bp = (struct brotli_params *) &writer->params;
-  (void) conn;
+  (void) data;
 
   if(!writer->downstream)
     return CURLE_WRITE_ERROR;
@@ -639,7 +638,7 @@ static CURLcode brotli_init_writer(struct connectdata *conn,
   return bp->br? CURLE_OK: CURLE_OUT_OF_MEMORY;
 }
 
-static CURLcode brotli_unencode_write(struct connectdata *conn,
+static CURLcode brotli_unencode_write(struct Curl_easy *data,
                                       struct contenc_writer *writer,
                                       const char *buf, size_t nbytes)
 {
@@ -664,7 +663,7 @@ static CURLcode brotli_unencode_write(struct connectdata *conn,
     dstleft = DSIZ;
     r = BrotliDecoderDecompressStream(bp->br,
                                       &nbytes, &src, &dstleft, &dst, NULL);
-    result = Curl_unencode_write(conn, writer->downstream,
+    result = Curl_unencode_write(data, writer->downstream,
                                  decomp, DSIZ - dstleft);
     if(result)
       break;
@@ -687,11 +686,11 @@ static CURLcode brotli_unencode_write(struct connectdata *conn,
   return result;
 }
 
-static void brotli_close_writer(struct connectdata *conn,
+static void brotli_close_writer(struct Curl_easy *data,
                                 struct contenc_writer *writer)
 {
   struct brotli_params *bp = (struct brotli_params *) &writer->params;
-  (void) conn;
+  (void) data;
 
   if(bp->br) {
     BrotliDecoderDestroyInstance(bp->br);
@@ -717,11 +716,11 @@ struct zstd_params {
   void *decomp;
 };
 
-static CURLcode zstd_init_writer(struct connectdata *conn,
+static CURLcode zstd_init_writer(struct Curl_easy *data,
                                  struct contenc_writer *writer)
 {
   struct zstd_params *zp = (struct zstd_params *)&writer->params;
-  (void)conn;
+  (void)data;
 
   if(!writer->downstream)
     return CURLE_WRITE_ERROR;
@@ -731,9 +730,9 @@ static CURLcode zstd_init_writer(struct connectdata *conn,
   return zp->zds ? CURLE_OK : CURLE_OUT_OF_MEMORY;
 }
 
-static CURLcode zstd_unencode_write(struct connectdata *conn,
-    struct contenc_writer *writer,
-    const char *buf, size_t nbytes)
+static CURLcode zstd_unencode_write(struct Curl_easy *data,
+                                    struct contenc_writer *writer,
+                                    const char *buf, size_t nbytes)
 {
   CURLcode result = CURLE_OK;
   struct zstd_params *zp = (struct zstd_params *)&writer->params;
@@ -760,7 +759,7 @@ static CURLcode zstd_unencode_write(struct connectdata *conn,
       return CURLE_BAD_CONTENT_ENCODING;
     }
     if(out.pos > 0) {
-      result = Curl_unencode_write(conn, writer->downstream,
+      result = Curl_unencode_write(data, writer->downstream,
                                    zp->decomp, out.pos);
       if(result)
         break;
@@ -772,11 +771,11 @@ static CURLcode zstd_unencode_write(struct connectdata *conn,
   return result;
 }
 
-static void zstd_close_writer(struct connectdata *conn,
-    struct contenc_writer *writer)
+static void zstd_close_writer(struct Curl_easy *data,
+                              struct contenc_writer *writer)
 {
   struct zstd_params *zp = (struct zstd_params *)&writer->params;
-  (void)conn;
+  (void)data;
 
   if(zp->decomp) {
     free(zp->decomp);
@@ -800,24 +799,24 @@ static const struct content_encoding zstd_encoding = {
 
 
 /* Identity handler. */
-static CURLcode identity_init_writer(struct connectdata *conn,
+static CURLcode identity_init_writer(struct Curl_easy *data,
                                      struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
 }
 
-static CURLcode identity_unencode_write(struct connectdata *conn,
+static CURLcode identity_unencode_write(struct Curl_easy *data,
                                         struct contenc_writer *writer,
                                         const char *buf, size_t nbytes)
 {
-  return Curl_unencode_write(conn, writer->downstream, buf, nbytes);
+  return Curl_unencode_write(data, writer->downstream, buf, nbytes);
 }
 
-static void identity_close_writer(struct connectdata *conn,
+static void identity_close_writer(struct Curl_easy *data,
                                   struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   (void) writer;
 }
 
@@ -885,18 +884,17 @@ char *Curl_all_content_encodings(void)
 
 
 /* Real client writer: no downstream. */
-static CURLcode client_init_writer(struct connectdata *conn,
+static CURLcode client_init_writer(struct Curl_easy *data,
                                    struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
 }
 
-static CURLcode client_unencode_write(struct connectdata *conn,
+static CURLcode client_unencode_write(struct Curl_easy *data,
                                       struct contenc_writer *writer,
                                       const char *buf, size_t nbytes)
 {
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
 
   (void) writer;
@@ -904,13 +902,13 @@ static CURLcode client_unencode_write(struct connectdata *conn,
   if(!nbytes || k->ignorebody)
     return CURLE_OK;
 
-  return Curl_client_write(conn, CLIENTWRITE_BODY, (char *) buf, nbytes);
+  return Curl_client_write(data, CLIENTWRITE_BODY, (char *) buf, nbytes);
 }
 
-static void client_close_writer(struct connectdata *conn,
+static void client_close_writer(struct Curl_easy *data,
                                 struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   (void) writer;
 }
 
@@ -925,14 +923,14 @@ static const struct content_encoding client_encoding = {
 
 
 /* Deferred error dummy writer. */
-static CURLcode error_init_writer(struct connectdata *conn,
+static CURLcode error_init_writer(struct Curl_easy *data,
                                   struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
 }
 
-static CURLcode error_unencode_write(struct connectdata *conn,
+static CURLcode error_unencode_write(struct Curl_easy *data,
                                      struct contenc_writer *writer,
                                      const char *buf, size_t nbytes)
 {
@@ -944,16 +942,16 @@ static CURLcode error_unencode_write(struct connectdata *conn,
 
   if(!all)
     return CURLE_OUT_OF_MEMORY;
-  failf(conn->data, "Unrecognized content encoding type. "
-                    "libcurl understands %s content encodings.", all);
+  failf(data, "Unrecognized content encoding type. "
+        "libcurl understands %s content encodings.", all);
   free(all);
   return CURLE_BAD_CONTENT_ENCODING;
 }
 
-static void error_close_writer(struct connectdata *conn,
+static void error_close_writer(struct Curl_easy *data,
                                struct contenc_writer *writer)
 {
-  (void) conn;
+  (void) data;
   (void) writer;
 }
 
@@ -968,7 +966,7 @@ static const struct content_encoding error_encoding = {
 
 /* Create an unencoding writer stage using the given handler. */
 static struct contenc_writer *
-new_unencoding_writer(struct connectdata *conn,
+new_unencoding_writer(struct Curl_easy *data,
                       const struct content_encoding *handler,
                       struct contenc_writer *downstream)
 {
@@ -978,7 +976,7 @@ new_unencoding_writer(struct connectdata *conn,
   if(writer) {
     writer->handler = handler;
     writer->downstream = downstream;
-    if(handler->init_writer(conn, writer)) {
+    if(handler->init_writer(data, writer)) {
       free(writer);
       writer = NULL;
     }
@@ -988,25 +986,24 @@ new_unencoding_writer(struct connectdata *conn,
 }
 
 /* Write data using an unencoding writer stack. */
-CURLcode Curl_unencode_write(struct connectdata *conn,
+CURLcode Curl_unencode_write(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes)
 {
   if(!nbytes)
     return CURLE_OK;
-  return writer->handler->unencode_write(conn, writer, buf, nbytes);
+  return writer->handler->unencode_write(data, writer, buf, nbytes);
 }
 
 /* Close and clean-up the connection's writer stack. */
-void Curl_unencode_cleanup(struct connectdata *conn)
+void Curl_unencode_cleanup(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
   struct contenc_writer *writer = k->writer_stack;
 
   while(writer) {
     k->writer_stack = writer->downstream;
-    writer->handler->close_writer(conn, writer);
+    writer->handler->close_writer(data, writer);
     free(writer);
     writer = k->writer_stack;
   }
@@ -1029,10 +1026,9 @@ static const struct content_encoding *find_encoding(const char *name,
 
 /* Set-up the unencoding stack from the Content-Encoding header value.
  * See RFC 7231 section 3.1.2.2. */
-CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int maybechunked)
 {
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
 
   do {
@@ -1052,14 +1048,14 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
     /* Special case: chunked encoding is handled at the reader level. */
     if(maybechunked && namelen == 7 && strncasecompare(name, "chunked", 7)) {
       k->chunk = TRUE;             /* chunks coming our way. */
-      Curl_httpchunk_init(conn);   /* init our chunky engine. */
+      Curl_httpchunk_init(data);   /* init our chunky engine. */
     }
     else if(namelen) {
       const struct content_encoding *encoding = find_encoding(name, namelen);
       struct contenc_writer *writer;
 
       if(!k->writer_stack) {
-        k->writer_stack = new_unencoding_writer(conn, &client_encoding, NULL);
+        k->writer_stack = new_unencoding_writer(data, &client_encoding, NULL);
 
         if(!k->writer_stack)
           return CURLE_OUT_OF_MEMORY;
@@ -1069,7 +1065,7 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
         encoding = &error_encoding;  /* Defer error at stack use. */
 
       /* Stack the unencoding stage. */
-      writer = new_unencoding_writer(conn, encoding, k->writer_stack);
+      writer = new_unencoding_writer(data, encoding, k->writer_stack);
       if(!writer)
         return CURLE_OUT_OF_MEMORY;
       k->writer_stack = writer;
@@ -1081,29 +1077,29 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
 
 #else
 /* Stubs for builds without HTTP. */
-CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int maybechunked)
 {
-  (void) conn;
+  (void) data;
   (void) enclist;
   (void) maybechunked;
   return CURLE_NOT_BUILT_IN;
 }
 
-CURLcode Curl_unencode_write(struct connectdata *conn,
+CURLcode Curl_unencode_write(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes)
 {
-  (void) conn;
+  (void) data;
   (void) writer;
   (void) buf;
   (void) nbytes;
   return CURLE_NOT_BUILT_IN;
 }
 
-void Curl_unencode_cleanup(struct connectdata *conn)
+void Curl_unencode_cleanup(struct Curl_easy *data)
 {
-  (void) conn;
+  (void) data;
 }
 
 char *Curl_all_content_encodings(void)

+ 7 - 7
lib/content_encoding.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -33,23 +33,23 @@ struct contenc_writer {
 struct content_encoding {
   const char *name;        /* Encoding name. */
   const char *alias;       /* Encoding name alias. */
-  CURLcode (*init_writer)(struct connectdata *conn,
+  CURLcode (*init_writer)(struct Curl_easy *data,
                           struct contenc_writer *writer);
-  CURLcode (*unencode_write)(struct connectdata *conn,
+  CURLcode (*unencode_write)(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes);
-  void (*close_writer)(struct connectdata *conn,
+  void (*close_writer)(struct Curl_easy *data,
                        struct contenc_writer *writer);
   size_t paramsize;
 };
 
 
-CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
+CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
                                      const char *enclist, int maybechunked);
-CURLcode Curl_unencode_write(struct connectdata *conn,
+CURLcode Curl_unencode_write(struct Curl_easy *data,
                              struct contenc_writer *writer,
                              const char *buf, size_t nbytes);
-void Curl_unencode_cleanup(struct connectdata *conn);
+void Curl_unencode_cleanup(struct Curl_easy *data);
 char *Curl_all_content_encodings(void);
 
 #endif /* HEADER_CURL_CONTENT_ENCODING_H */

+ 9 - 0
lib/cookie.c

@@ -264,6 +264,11 @@ static const char *get_top_domain(const char * const domain, size_t *outlen)
   return first? first: domain;
 }
 
+/* Avoid C1001, an "internal error" with MSVC14 */
+#if defined(_MSC_VER) && (_MSC_VER == 1900)
+#pragma optimize("", off)
+#endif
+
 /*
  * A case-insensitive hash for the cookie domains.
  */
@@ -280,6 +285,10 @@ static size_t cookie_hash_domain(const char *domain, const size_t len)
   return (h % COOKIE_HASH_SIZE);
 }
 
+#if defined(_MSC_VER) && (_MSC_VER == 1900)
+#pragma optimize("", on)
+#endif
+
 /*
  * Hash this domain.
  */

+ 3 - 3
lib/cookie.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -34,12 +34,12 @@ struct Cookie {
   char *domain;      /* domain = <this> */
   curl_off_t expires;  /* expires = <this> */
   char *expirestr;   /* the plain text version */
-  bool tailmatch;    /* whether we do tail-matching of the domain name */
 
   /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
   char *version;     /* Version = <value> */
   char *maxage;      /* Max-Age = <value> */
 
+  bool tailmatch;    /* whether we do tail-matching of the domain name */
   bool secure;       /* whether the 'secure' keyword was used */
   bool livecookie;   /* updated from a server, not a stored file */
   bool httponly;     /* true if the httponly directive is present */
@@ -61,8 +61,8 @@ struct CookieInfo {
   struct Cookie *cookies[COOKIE_HASH_SIZE];
 
   char *filename;  /* file we read from/write to */
-  bool running;    /* state info, for cookie adding information */
   long numcookies; /* number of cookies in the "jar" */
+  bool running;    /* state info, for cookie adding information */
   bool newsession; /* new session, discard session cookies on load */
   int lastct;      /* last creation-time used in the jar */
 };

+ 2 - 2
lib/curl_addrinfo.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -285,7 +285,7 @@ Curl_he2ai(const struct hostent *he, int port)
 #endif
       ss_size = sizeof(struct sockaddr_in);
 
-    /* allocate memory to told the struct, the address and the name */
+    /* allocate memory to hold the struct, the address and the name */
     ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen);
     if(!ai) {
       result = CURLE_OUT_OF_MEMORY;

+ 5 - 1
lib/curl_config.h.cmake

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -1002,6 +1002,10 @@ ${SIZEOF_TIME_T_CODE}
 /* if OpenSSL is in use */
 #cmakedefine USE_OPENSSL 1
 
+/* Define to 1 if you don't want the OpenSSL configuration to be loaded
+   automatically */
+#cmakedefine CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG 1
+
 /* to enable NGHTTP2  */
 #cmakedefine USE_NGHTTP2 1
 

+ 5 - 1
lib/curl_gssapi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2011 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2011 - 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
@@ -131,6 +131,10 @@ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix,
   display_gss_error(minor, GSS_C_MECH_CODE, buf, len);
 
   infof(data, "%s%s\n", prefix, buf);
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+  (void)data;
+  (void)prefix;
+#endif
 }
 
 #endif /* HAVE_GSSAPI */

+ 4 - 4
lib/curl_krb5.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,7 +26,7 @@ struct Curl_sec_client_mech {
   const char *name;
   size_t size;
   int (*init)(void *);
-  int (*auth)(void *, struct connectdata *);
+  int (*auth)(void *, struct Curl_easy *data, struct connectdata *);
   void (*end)(void *);
   int (*check_prot)(void *, int);
   int (*overhead)(void *, int, int);
@@ -39,10 +39,10 @@ struct Curl_sec_client_mech {
 #define AUTH_ERROR      2
 
 #ifdef HAVE_GSSAPI
-int Curl_sec_read_msg(struct connectdata *conn, char *,
+int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, char *,
                       enum protection_level);
 void Curl_sec_end(struct connectdata *);
-CURLcode Curl_sec_login(struct connectdata *);
+CURLcode Curl_sec_login(struct Curl_easy *, struct connectdata *);
 int Curl_sec_request_prot(struct connectdata *conn, const char *level);
 #else
 #define Curl_sec_end(x)

+ 16 - 13
lib/curl_ntlm_wb.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -329,13 +329,16 @@ done:
   return CURLE_REMOTE_ACCESS_DENIED;
 }
 
-CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
+CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
+                            struct connectdata *conn,
                             bool proxy,
                             const char *header)
 {
   struct ntlmdata *ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
   curlntlm *state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
 
+  (void) data;  /* In case it gets unused by nop log macros. */
+
   if(!checkprefix("NTLM", header))
     return CURLE_BAD_CONTENT_ENCODING;
 
@@ -352,17 +355,17 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
   }
   else {
     if(*state == NTLMSTATE_LAST) {
-      infof(conn->data, "NTLM auth restarted\n");
+      infof(data, "NTLM auth restarted\n");
       Curl_http_auth_cleanup_ntlm_wb(conn);
     }
     else if(*state == NTLMSTATE_TYPE3) {
-      infof(conn->data, "NTLM handshake rejected\n");
+      infof(data, "NTLM handshake rejected\n");
       Curl_http_auth_cleanup_ntlm_wb(conn);
       *state = NTLMSTATE_NONE;
       return CURLE_REMOTE_ACCESS_DENIED;
     }
     else if(*state >= NTLMSTATE_TYPE1) {
-      infof(conn->data, "NTLM handshake failure (internal error)\n");
+      infof(data, "NTLM handshake failure (internal error)\n");
       return CURLE_REMOTE_ACCESS_DENIED;
     }
 
@@ -376,7 +379,8 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
  * This is for creating ntlm header output by delegating challenge/response
  * to Samba's winbind daemon helper ntlm_auth.
  */
-CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
+CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
+                             bool proxy)
 {
   /* point to the address of the pointer that holds the string to send to the
      server, which is for a plain host or for a HTTP proxy */
@@ -386,12 +390,11 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
   struct ntlmdata *ntlm;
   curlntlm *state;
   struct auth *authp;
-  struct Curl_easy *data = conn->data;
 
   CURLcode res = CURLE_OK;
 
   DEBUGASSERT(conn);
-  DEBUGASSERT(conn->data);
+  DEBUGASSERT(data);
 
   if(proxy) {
 #ifndef CURL_DISABLE_PROXY
@@ -399,7 +402,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
     userp = conn->http_proxy.user;
     ntlm = &conn->proxyntlm;
     state = &conn->proxy_ntlm_state;
-    authp = &conn->data->state.authproxy;
+    authp = &data->state.authproxy;
 #else
     return CURLE_NOT_BUILT_IN;
 #endif
@@ -409,7 +412,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
     userp = conn->user;
     ntlm = &conn->ntlm;
     state = &conn->http_ntlm_state;
-    authp = &conn->data->state.authhost;
+    authp = &data->state.authhost;
   }
   authp->done = FALSE;
 
@@ -433,10 +436,10 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
      * request handling process.
      */
     /* Create communication with ntlm_auth */
-    res = ntlm_wb_init(conn->data, ntlm, userp);
+    res = ntlm_wb_init(data, ntlm, userp);
     if(res)
       return res;
-    res = ntlm_wb_response(conn->data, ntlm, "YR\n", *state);
+    res = ntlm_wb_response(data, ntlm, "YR\n", *state);
     if(res)
       return res;
 
@@ -454,7 +457,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
     char *input = aprintf("TT %s\n", ntlm->challenge);
     if(!input)
       return CURLE_OUT_OF_MEMORY;
-    res = ntlm_wb_response(conn->data, ntlm, input, *state);
+    res = ntlm_wb_response(data, ntlm, input, *state);
     free(input);
     if(res)
       return res;

+ 5 - 3
lib/curl_ntlm_wb.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -28,11 +28,13 @@
     defined(NTLM_WB_ENABLED)
 
 /* this is for ntlm header input */
-CURLcode Curl_input_ntlm_wb(struct connectdata *conn, bool proxy,
+CURLcode Curl_input_ntlm_wb(struct Curl_easy *data,
+                            struct connectdata *conn, bool proxy,
                             const char *header);
 
 /* this is for creating ntlm header output */
-CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy);
+CURLcode Curl_output_ntlm_wb(struct Curl_easy *data, struct connectdata *conn,
+                             bool proxy);
 
 void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn);
 

+ 4 - 5
lib/curl_path.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -31,12 +31,11 @@
 #include "memdebug.h"
 
 /* figure out the path to work with in this particular request */
-CURLcode Curl_getworkingpath(struct connectdata *conn,
+CURLcode Curl_getworkingpath(struct Curl_easy *data,
                              char *homedir,  /* when SFTP is used */
                              char **path) /* returns the  allocated
                                              real path to work with */
 {
-  struct Curl_easy *data = conn->data;
   char *real_path = NULL;
   char *working_path;
   size_t working_path_len;
@@ -47,7 +46,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
     return result;
 
   /* Check for /~/, indicating relative to the user's home directory */
-  if(conn->handler->protocol & CURLPROTO_SCP) {
+  if(data->conn->handler->protocol & CURLPROTO_SCP) {
     real_path = malloc(working_path_len + 1);
     if(real_path == NULL) {
       free(working_path);
@@ -59,7 +58,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
     else
       memcpy(real_path, working_path, 1 + working_path_len);
   }
-  else if(conn->handler->protocol & CURLPROTO_SFTP) {
+  else if(data->conn->handler->protocol & CURLPROTO_SFTP) {
     if((working_path_len > 1) && (working_path[1] == '~')) {
       size_t homelen = strlen(homedir);
       real_path = malloc(homelen + working_path_len + 1);

+ 2 - 2
lib/curl_path.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -39,7 +39,7 @@
                          have their definition hidden well */
 #endif
 
-CURLcode Curl_getworkingpath(struct connectdata *conn,
+CURLcode Curl_getworkingpath(struct Curl_easy *data,
                              char *homedir,
                              char **path);
 

+ 2 - 3
lib/curl_range.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -33,12 +33,11 @@
   Check if this is a range download, and if so, set the internal variables
   properly.
  */
-CURLcode Curl_range(struct connectdata *conn)
+CURLcode Curl_range(struct Curl_easy *data)
 {
   curl_off_t from, to;
   char *ptr;
   char *ptr2;
-  struct Curl_easy *data = conn->data;
 
   if(data->state.use_range && data->state.range) {
     CURLofft from_t;

+ 2 - 3
lib/curl_range.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -25,6 +25,5 @@
 #include "curl_setup.h"
 #include "urldata.h"
 
-CURLcode Curl_range(struct connectdata *conn);
-
+CURLcode Curl_range(struct Curl_easy *data);
 #endif /* HEADER_CURL_RANGE_H */

+ 28 - 20
lib/curl_rtmp.c

@@ -5,7 +5,7 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 2021, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2010, Howard Chu, <[email protected]>
  *
  * This software is licensed as described in the file COPYING, which
@@ -48,11 +48,13 @@
 
 #define DEF_BUFTIME    (2*60*60*1000)    /* 2 hours */
 
-static CURLcode rtmp_setup_connection(struct connectdata *conn);
-static CURLcode rtmp_do(struct connectdata *conn, bool *done);
-static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature);
-static CURLcode rtmp_connect(struct connectdata *conn, bool *done);
-static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead);
+static CURLcode rtmp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode rtmp_do(struct Curl_easy *data, bool *done);
+static CURLcode rtmp_done(struct Curl_easy *data, CURLcode, bool premature);
+static CURLcode rtmp_connect(struct Curl_easy *data, bool *done);
+static CURLcode rtmp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
 
 static Curl_recv rtmp_recv;
 static Curl_send rtmp_send;
@@ -193,7 +195,8 @@ const struct Curl_handler Curl_handler_rtmpts = {
   PROTOPT_NONE                          /* flags*/
 };
 
-static CURLcode rtmp_setup_connection(struct connectdata *conn)
+static CURLcode rtmp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   RTMP *r = RTMP_Alloc();
   if(!r)
@@ -201,7 +204,7 @@ static CURLcode rtmp_setup_connection(struct connectdata *conn)
 
   RTMP_Init(r);
   RTMP_SetBufferMS(r, DEF_BUFTIME);
-  if(!RTMP_SetupURL(r, conn->data->change.url)) {
+  if(!RTMP_SetupURL(r, data->change.url)) {
     RTMP_Free(r);
     return CURLE_URL_MALFORMAT;
   }
@@ -209,8 +212,9 @@ static CURLcode rtmp_setup_connection(struct connectdata *conn)
   return CURLE_OK;
 }
 
-static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
+static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
   SET_RCVTIMEO(tv, 10);
 
@@ -219,7 +223,7 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
   /* We have to know if it's a write before we send the
    * connect request packet
    */
-  if(conn->data->set.upload)
+  if(data->set.upload)
     r->Link.protocol |= RTMP_FEATURE_WRITE;
 
   /* For plain streams, use the buffer toggle trick to keep data flowing */
@@ -243,15 +247,15 @@ static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode rtmp_do(struct connectdata *conn, bool *done)
+static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
 
   if(!RTMP_ConnectStream(r, 0))
     return CURLE_FAILED_INIT;
 
-  if(conn->data->set.upload) {
+  if(data->set.upload) {
     Curl_pgrsSetUploadSize(data, data->state.infilesize);
     Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
   }
@@ -261,20 +265,22 @@ static CURLcode rtmp_do(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode rtmp_done(struct connectdata *conn, CURLcode status,
+static CURLcode rtmp_done(struct Curl_easy *data, CURLcode status,
                           bool premature)
 {
-  (void)conn; /* unused */
+  (void)data; /* unused */
   (void)status; /* unused */
   (void)premature; /* unused */
 
   return CURLE_OK;
 }
 
-static CURLcode rtmp_disconnect(struct connectdata *conn,
+static CURLcode rtmp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 bool dead_connection)
 {
   RTMP *r = conn->proto.rtmp;
+  (void)data;
   (void)dead_connection;
   if(r) {
     conn->proto.rtmp = NULL;
@@ -284,9 +290,10 @@ static CURLcode rtmp_disconnect(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
+static ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
                          size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
   ssize_t nread;
 
@@ -295,8 +302,8 @@ static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
   nread = RTMP_Read(r, buf, curlx_uztosi(len));
   if(nread < 0) {
     if(r->m_read.status == RTMP_READ_COMPLETE ||
-        r->m_read.status == RTMP_READ_EOF) {
-      conn->data->req.size = conn->data->req.bytecount;
+       r->m_read.status == RTMP_READ_EOF) {
+      data->req.size = data->req.bytecount;
       nread = 0;
     }
     else
@@ -305,9 +312,10 @@ static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
   return nread;
 }
 
-static ssize_t rtmp_send(struct connectdata *conn, int sockindex,
+static ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
                          const void *buf, size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   RTMP *r = conn->proto.rtmp;
   ssize_t num;
 

+ 18 - 18
lib/curl_sasl.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 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
@@ -194,7 +194,7 @@ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params)
  *
  * This is the ONLY way to change SASL state!
  */
-static void state(struct SASL *sasl, struct connectdata *conn,
+static void state(struct SASL *sasl, struct Curl_easy *data,
                   saslstate newstate)
 {
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -221,10 +221,10 @@ static void state(struct SASL *sasl, struct connectdata *conn,
   };
 
   if(sasl->state != newstate)
-    infof(conn->data, "SASL %p state change from %s to %s\n",
+    infof(data, "SASL %p state change from %s to %s\n",
           (void *)sasl, names[sasl->state], names[newstate]);
 #else
-  (void) conn;
+  (void) data;
 #endif
 
   sasl->state = newstate;
@@ -253,11 +253,11 @@ bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn)
  *
  * Calculate the required login details for SASL authentication.
  */
-CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
+CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
+                         struct connectdata *conn,
                          bool force_ir, saslprogress *progress)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   unsigned int enabledmechs;
   const char *mech = NULL;
   char *resp = NULL;
@@ -398,10 +398,10 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
       resp = NULL;
     }
 
-    result = sasl->params->sendauth(conn, mech, resp);
+    result = sasl->params->sendauth(data, conn, mech, resp);
     if(!result) {
       *progress = SASL_INPROGRESS;
-      state(sasl, conn, resp ? state2 : state1);
+      state(sasl, data, resp ? state2 : state1);
     }
   }
 
@@ -415,11 +415,11 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
  *
  * Continue the authentication.
  */
-CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
+CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
+                            struct connectdata *conn,
                             int code, saslprogress *progress)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   saslstate newstate = SASL_FINAL;
   char *resp = NULL;
 #ifndef CURL_DISABLE_PROXY
@@ -450,14 +450,14 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     if(code != sasl->params->finalcode)
       result = CURLE_LOGIN_DENIED;
     *progress = SASL_DONE;
-    state(sasl, conn, SASL_STOP);
+    state(sasl, data, SASL_STOP);
     return result;
   }
 
   if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
      code != sasl->params->contcode) {
     *progress = SASL_DONE;
-    state(sasl, conn, SASL_STOP);
+    state(sasl, data, SASL_STOP);
     return CURLE_LOGIN_DENIED;
   }
 
@@ -587,7 +587,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     if(code == sasl->params->finalcode) {
       /* Final response was received so we are done */
       *progress = SASL_DONE;
-      state(sasl, conn, SASL_STOP);
+      state(sasl, data, SASL_STOP);
       return result;
     }
     else if(code == sasl->params->contcode) {
@@ -600,7 +600,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     }
     else {
       *progress = SASL_DONE;
-      state(sasl, conn, SASL_STOP);
+      state(sasl, data, SASL_STOP);
       return CURLE_LOGIN_DENIED;
     }
 
@@ -609,7 +609,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
     sasl->authmechs ^= sasl->authused;
 
     /* Start an alternative SASL authentication */
-    result = Curl_sasl_start(sasl, conn, sasl->force_ir, progress);
+    result = Curl_sasl_start(sasl, data, conn, sasl->force_ir, progress);
     newstate = sasl->state;   /* Use state from Curl_sasl_start() */
     break;
   default:
@@ -621,12 +621,12 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
   switch(result) {
   case CURLE_BAD_CONTENT_ENCODING:
     /* Cancel dialog */
-    result = sasl->params->sendcont(conn, "*");
+    result = sasl->params->sendcont(data, conn, "*");
     newstate = SASL_CANCEL;
     break;
   case CURLE_OK:
     if(resp)
-      result = sasl->params->sendcont(conn, resp);
+      result = sasl->params->sendcont(data, conn, resp);
     break;
   default:
     newstate = SASL_STOP;    /* Stop on error */
@@ -636,7 +636,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
 
   free(resp);
 
-  state(sasl, conn, newstate);
+  state(sasl, data, newstate);
 
   return result;
 }

+ 9 - 5
lib/curl_sasl.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2012 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2012 - 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
@@ -88,10 +88,12 @@ struct SASLproto {
   int contcode;            /* Code to receive when continuation is expected */
   int finalcode;           /* Code to receive upon authentication success */
   size_t maxirlen;         /* Maximum initial response length */
-  CURLcode (*sendauth)(struct connectdata *conn,
+  CURLcode (*sendauth)(struct Curl_easy *data,
+                       struct connectdata *conn,
                        const char *mech, const char *ir);
                            /* Send authentication command */
-  CURLcode (*sendcont)(struct connectdata *conn, const char *contauth);
+  CURLcode (*sendcont)(struct Curl_easy *data,
+                       struct connectdata *conn, const char *contauth);
                            /* Send authentication continuation */
   void (*getmessage)(char *buffer, char **outptr);
                            /* Get SASL response message */
@@ -133,11 +135,13 @@ void Curl_sasl_init(struct SASL *sasl, const struct SASLproto *params);
 bool Curl_sasl_can_authenticate(struct SASL *sasl, struct connectdata *conn);
 
 /* Calculate the required login details for SASL authentication  */
-CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
+CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data,
+                         struct connectdata *conn,
                          bool force_ir, saslprogress *progress);
 
 /* Continue an SASL authentication  */
-CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
+CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data,
+                            struct connectdata *conn,
                             int code, saslprogress *progress);
 
 #endif /* HEADER_CURL_SASL_H */

+ 3 - 0
lib/curl_sha256.h

@@ -24,6 +24,9 @@
  ***************************************************************************/
 
 #ifndef CURL_DISABLE_CRYPTO_AUTH
+#include "curl_hmac.h"
+
+extern const struct HMAC_params Curl_HMAC_SHA256[1];
 
 #define SHA256_DIGEST_LENGTH 32
 

+ 9 - 10
lib/dict.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -67,7 +67,7 @@
  * Forward declarations.
  */
 
-static CURLcode dict_do(struct connectdata *conn, bool *done);
+static CURLcode dict_do(struct Curl_easy *data, bool *done);
 
 /*
  * DICT protocol handler.
@@ -129,10 +129,9 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
 }
 
 /* sendf() sends formatted data to the server */
-static CURLcode sendf(curl_socket_t sockfd, struct connectdata *conn,
+static CURLcode sendf(curl_socket_t sockfd, struct Curl_easy *data,
                       const char *fmt, ...)
 {
-  struct Curl_easy *data = conn->data;
   ssize_t bytes_written;
   size_t write_len;
   CURLcode result = CURLE_OK;
@@ -151,7 +150,7 @@ static CURLcode sendf(curl_socket_t sockfd, struct connectdata *conn,
 
   for(;;) {
     /* Write the buffer to the socket */
-    result = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
+    result = Curl_write(data, sockfd, sptr, write_len, &bytes_written);
 
     if(result)
       break;
@@ -173,7 +172,7 @@ static CURLcode sendf(curl_socket_t sockfd, struct connectdata *conn,
   return result;
 }
 
-static CURLcode dict_do(struct connectdata *conn, bool *done)
+static CURLcode dict_do(struct Curl_easy *data, bool *done)
 {
   char *word;
   char *eword;
@@ -183,7 +182,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
   char *nthdef = NULL; /* This is not part of the protocol, but required
                           by RFC 2229 */
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
 
   char *path = data->state.up.path;
@@ -230,7 +229,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
     if(!eword)
       return CURLE_OUT_OF_MEMORY;
 
-    result = sendf(sockfd, conn,
+    result = sendf(sockfd, data,
                    "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
                    "MATCH "
                    "%s "    /* database */
@@ -278,7 +277,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
     if(!eword)
       return CURLE_OUT_OF_MEMORY;
 
-    result = sendf(sockfd, conn,
+    result = sendf(sockfd, data,
                    "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
                    "DEFINE "
                    "%s "     /* database */
@@ -306,7 +305,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
         if(ppath[i] == ':')
           ppath[i] = ' ';
       }
-      result = sendf(sockfd, conn,
+      result = sendf(sockfd, data,
                      "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
                      "%s\r\n"
                      "QUIT\r\n", ppath);

+ 53 - 43
lib/doh.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -187,19 +187,20 @@ doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
 }
 
 /* called from multi.c when this DOH transfer is complete */
-static int Curl_doh_done(struct Curl_easy *doh, CURLcode result)
+static int doh_done(struct Curl_easy *doh, CURLcode result)
 {
   struct Curl_easy *data = doh->set.dohfor;
+  struct dohdata *dohp = data->req.doh;
   /* so one of the DOH request done for the 'data' transfer is now complete! */
-  data->req.doh.pending--;
-  infof(data, "a DOH request is completed, %u to go\n", data->req.doh.pending);
+  dohp->pending--;
+  infof(data, "a DOH request is completed, %u to go\n", dohp->pending);
   if(result)
     infof(data, "DOH request %s\n", curl_easy_strerror(result));
 
-  if(!data->req.doh.pending) {
+  if(!dohp->pending) {
     /* DOH completed */
-    curl_slist_free_all(data->req.doh.headers);
-    data->req.doh.headers = NULL;
+    curl_slist_free_all(dohp->headers);
+    dohp->headers = NULL;
     Curl_expire(data, 0, EXPIRE_RUN_NOW);
   }
   return 0;
@@ -225,7 +226,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
   DOHcode d = doh_encode(host, dnstype, p->dohbuffer, sizeof(p->dohbuffer),
                          &p->dohlen);
   if(d) {
-    failf(data, "Failed to encode DOH packet [%d]\n", d);
+    failf(data, "Failed to encode DOH packet [%d]", d);
     return CURLE_OUT_OF_MEMORY;
   }
 
@@ -354,7 +355,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
         data->set.str[STRING_SSL_EC_CURVES]);
     }
 
-    doh->set.fmultidone = Curl_doh_done;
+    doh->set.fmultidone = doh_done;
     doh->set.dohfor = data; /* identify for which transfer this is done */
     p->easy = doh;
 
@@ -378,58 +379,64 @@ static CURLcode dohprobe(struct Curl_easy *data,
  * 'Curl_addrinfo *' with the address information.
  */
 
-struct Curl_addrinfo *Curl_doh(struct connectdata *conn,
+struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
                                const char *hostname,
                                int port,
                                int *waitp)
 {
-  struct Curl_easy *data = conn->data;
   CURLcode result = CURLE_OK;
   int slot;
+  struct dohdata *dohp;
+  struct connectdata *conn = data->conn;
   *waitp = TRUE; /* this never returns synchronously */
-  (void)conn;
   (void)hostname;
   (void)port;
 
+  DEBUGASSERT(!data->req.doh);
+  DEBUGASSERT(conn);
+
   /* start clean, consider allocating this struct on demand */
-  memset(&data->req.doh, 0, sizeof(struct dohdata));
+  dohp = data->req.doh = calloc(sizeof(struct dohdata), 1);
+  if(!dohp)
+    return NULL;
 
   conn->bits.doh = TRUE;
-  data->req.doh.host = hostname;
-  data->req.doh.port = port;
-  data->req.doh.headers =
+  dohp->host = hostname;
+  dohp->port = port;
+  dohp->headers =
     curl_slist_append(NULL,
                       "Content-Type: application/dns-message");
-  if(!data->req.doh.headers)
+  if(!dohp->headers)
     goto error;
 
   if(conn->ip_version != CURL_IPRESOLVE_V6) {
     /* create IPv4 DOH request */
-    result = dohprobe(data, &data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V4],
+    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V4],
                       DNS_TYPE_A, hostname, data->set.str[STRING_DOH],
-                      data->multi, data->req.doh.headers);
+                      data->multi, dohp->headers);
     if(result)
       goto error;
-    data->req.doh.pending++;
+    dohp->pending++;
   }
 
   if(conn->ip_version != CURL_IPRESOLVE_V4) {
     /* create IPv6 DOH request */
-    result = dohprobe(data, &data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V6],
+    result = dohprobe(data, &dohp->probe[DOH_PROBE_SLOT_IPADDR_V6],
                       DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH],
-                      data->multi, data->req.doh.headers);
+                      data->multi, dohp->headers);
     if(result)
       goto error;
-    data->req.doh.pending++;
+    dohp->pending++;
   }
   return NULL;
 
   error:
-  curl_slist_free_all(data->req.doh.headers);
-  data->req.doh.headers = NULL;
+  curl_slist_free_all(dohp->headers);
+  data->req.doh->headers = NULL;
   for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-    Curl_close(&data->req.doh.probe[slot].easy);
+    Curl_close(&dohp->probe[slot].easy);
   }
+  Curl_safefree(data->req.doh);
   return NULL;
 }
 
@@ -468,7 +475,7 @@ static unsigned int get32bit(const unsigned char *doh, int index)
       the pointer first. */
    doh += index;
 
-   /* avoid undefined behaviour by casting to unsigned before shifting
+   /* avoid undefined behavior by casting to unsigned before shifting
       24 bits, possibly into the sign bit. codegen is same, but
       ub sanitizer won't be upset */
   return ( (unsigned)doh[0] << 24) | (doh[1] << 16) |(doh[2] << 8) | doh[3];
@@ -904,20 +911,22 @@ UNITTEST void de_cleanup(struct dohentry *d)
   }
 }
 
-CURLcode Curl_doh_is_resolved(struct connectdata *conn,
+CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
                               struct Curl_dns_entry **dnsp)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
+  struct dohdata *dohp = data->req.doh;
   *dnsp = NULL; /* defaults to no response */
+  if(!dohp)
+    return CURLE_OUT_OF_MEMORY;
 
-  if(!data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V4].easy &&
-     !data->req.doh.probe[DOH_PROBE_SLOT_IPADDR_V6].easy) {
-    failf(data, "Could not DOH-resolve: %s", conn->async.hostname);
-    return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
+  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:
       CURLE_COULDNT_RESOLVE_HOST;
   }
-  else if(!data->req.doh.pending) {
+  else if(!dohp->pending) {
     DOHcode rc[DOH_PROBE_SLOTS] = {
       DOH_OK, DOH_OK
     };
@@ -925,13 +934,13 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
     int slot;
     /* remove DOH handles from multi handle and close them */
     for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-      curl_multi_remove_handle(data->multi, data->req.doh.probe[slot].easy);
-      Curl_close(&data->req.doh.probe[slot].easy);
+      curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
+      Curl_close(&dohp->probe[slot].easy);
     }
     /* parse the responses, create the struct and return it! */
     de_init(&de);
     for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
-      struct dnsprobe *p = &data->req.doh.probe[slot];
+      struct dnsprobe *p = &dohp->probe[slot];
       if(!p->dnstype)
         continue;
       rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
@@ -941,7 +950,7 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
       Curl_dyn_free(&p->serverdoh);
       if(rc[slot]) {
         infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]),
-              type2name(p->dnstype), data->req.doh.host);
+              type2name(p->dnstype), dohp->host);
       }
     } /* next slot */
 
@@ -951,10 +960,10 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
       struct Curl_dns_entry *dns;
       struct Curl_addrinfo *ai;
 
-      infof(data, "DOH Host name: %s\n", data->req.doh.host);
+      infof(data, "DOH Host name: %s\n", dohp->host);
       showdoh(data, &de);
 
-      ai = doh2ai(&de, data->req.doh.host, data->req.doh.port);
+      ai = doh2ai(&de, dohp->host, dohp->port);
       if(!ai) {
         de_cleanup(&de);
         return CURLE_OUT_OF_MEMORY;
@@ -964,7 +973,7 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
       /* we got a response, store it in the cache */
-      dns = Curl_cache_addr(data, ai, data->req.doh.host, data->req.doh.port);
+      dns = Curl_cache_addr(data, ai, dohp->host, dohp->port);
 
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
@@ -974,7 +983,7 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
         Curl_freeaddrinfo(ai);
       }
       else {
-        conn->async.dns = dns;
+        data->state.async.dns = dns;
         *dnsp = dns;
         result = CURLE_OK;      /* address resolution OK */
       }
@@ -984,9 +993,10 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
 
     /* All done */
     de_cleanup(&de);
+    Curl_safefree(data->req.doh);
     return result;
 
-  } /* !data->req.doh.pending */
+  } /* !dohp->pending */
 
   /* else wait for pending DOH transactions to complete */
   return CURLE_OK;

+ 3 - 3
lib/doh.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -32,12 +32,12 @@
  * and returns a 'Curl_addrinfo *' with the address information.
  */
 
-struct Curl_addrinfo *Curl_doh(struct connectdata *conn,
+struct Curl_addrinfo *Curl_doh(struct Curl_easy *data,
                                const char *hostname,
                                int port,
                                int *waitp);
 
-CURLcode Curl_doh_is_resolved(struct connectdata *conn,
+CURLcode Curl_doh_is_resolved(struct Curl_easy *data,
                               struct Curl_dns_entry **dns);
 
 int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks);

+ 36 - 10
lib/easy.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -124,6 +124,10 @@ curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
 #  pragma warning(default:4232) /* MSVC extension, dllimport identity */
 #endif
 
+#ifdef DEBUGBUILD
+static char *leakpointer;
+#endif
+
 /**
  * curl_global_init() globally initializes curl given a bitwise set of the
  * different features of what to initialize.
@@ -190,6 +194,12 @@ static CURLcode global_init(long flags, bool memoryfuncs)
 
   init_flags = flags;
 
+#ifdef DEBUGBUILD
+  if(getenv("CURL_GLOBAL_INIT"))
+    /* alloc data that will leak if *cleanup() is not called! */
+    leakpointer = malloc(1);
+#endif
+
   return CURLE_OK;
 
   fail:
@@ -265,6 +275,9 @@ void curl_global_cleanup(void)
 #ifdef USE_WOLFSSH
   (void)wolfSSH_Cleanup();
 #endif
+#ifdef DEBUGBUILD
+  free(leakpointer);
+#endif
 
   init_flags  = 0;
 }
@@ -895,8 +908,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
 #endif
   /* Clone the resolver handle, if present, for the new handle */
   if(Curl_resolver_duphandle(outcurl,
-                             &outcurl->state.resolver,
-                             data->state.resolver))
+                             &outcurl->state.async.resolver,
+                             data->state.async.resolver))
     goto fail;
 
 #ifdef USE_ARES
@@ -1059,7 +1072,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
         /* even if one function returns error, this loops through and frees
            all buffers */
         if(!result)
-          result = Curl_client_write(conn, writebuf[i].type,
+          result = Curl_client_write(data, writebuf[i].type,
                                      Curl_dyn_ptr(&writebuf[i].b),
                                      Curl_dyn_len(&writebuf[i].b));
         Curl_dyn_free(&writebuf[i].b);
@@ -1080,6 +1093,9 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
      (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) {
     Curl_expire(data, 0, EXPIRE_RUN_NOW); /* get this handle going again */
 
+    /* reset the too-slow time keeper */
+    data->state.keeps_speed.tv_sec = 0;
+
     if(!data->state.tempcount)
       /* if not pausing again, force a recv/send check of this connection as
          the data might've been read off the socket already */
@@ -1140,8 +1156,13 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
   if(result)
     return result;
 
+  if(!data->conn)
+    /* on first invoke, the transfer has been detached from the connection and
+       needs to be reattached */
+    Curl_attach_connnection(data, c);
+
   *n = 0;
-  result = Curl_read(c, sfd, buffer, buflen, &n1);
+  result = Curl_read(data, sfd, buffer, buflen, &n1);
 
   if(result)
     return result;
@@ -1170,8 +1191,13 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
   if(result)
     return result;
 
+  if(!data->conn)
+    /* on first invoke, the transfer has been detached from the connection and
+       needs to be reattached */
+    Curl_attach_connnection(data, c);
+
   *n = 0;
-  result = Curl_write(c, sfd, buffer, buflen, &n1);
+  result = Curl_write(data, sfd, buffer, buflen, &n1);
 
   if(n1 == -1)
     return CURLE_SEND_ERROR;
@@ -1190,16 +1216,16 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
  *
  * Returns always 0.
  */
-static int conn_upkeep(struct connectdata *conn,
+static int conn_upkeep(struct Curl_easy *data,
+                       struct connectdata *conn,
                        void *param)
 {
   /* Param is unused. */
   (void)param;
 
-  if(conn->handler->connection_check) {
+  if(conn->handler->connection_check)
     /* Do a protocol-specific keepalive check on the connection. */
-    conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE);
-  }
+    conn->handler->connection_check(data, conn, CONNCHECK_KEEPALIVE);
 
   return 0; /* continue iteration */
 }

+ 3 - 2
lib/easyoptions.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             ___|___/|_| ______|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel.se>, 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,6 +35,7 @@ struct curl_easyoption Curl_easyopts[] = {
   {"ALTSVC_CTRL", CURLOPT_ALTSVC_CTRL, CURLOT_LONG, 0},
   {"APPEND", CURLOPT_APPEND, CURLOT_LONG, 0},
   {"AUTOREFERER", CURLOPT_AUTOREFERER, CURLOT_LONG, 0},
+  {"AWS_SIGV4", CURLOPT_AWS_SIGV4, CURLOT_STRING, 0},
   {"BUFFERSIZE", CURLOPT_BUFFERSIZE, CURLOT_LONG, 0},
   {"CAINFO", CURLOPT_CAINFO, CURLOT_STRING, 0},
   {"CAPATH", CURLOPT_CAPATH, CURLOT_STRING, 0},
@@ -348,6 +349,6 @@ struct curl_easyoption Curl_easyopts[] = {
  */
 int Curl_easyopts_check(void)
 {
-  return (CURLOPT_LASTENTRY != (304 + 1));
+  return ((CURLOPT_LASTENTRY%10000) != (305 + 1));
 }
 #endif

+ 49 - 44
lib/file.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -81,13 +81,15 @@
  * Forward declarations.
  */
 
-static CURLcode file_do(struct connectdata *, bool *done);
-static CURLcode file_done(struct connectdata *conn,
+static CURLcode file_do(struct Curl_easy *data, bool *done);
+static CURLcode file_done(struct Curl_easy *data,
                           CURLcode status, bool premature);
-static CURLcode file_connect(struct connectdata *conn, bool *done);
-static CURLcode file_disconnect(struct connectdata *conn,
+static CURLcode file_connect(struct Curl_easy *data, bool *done);
+static CURLcode file_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 bool dead_connection);
-static CURLcode file_setup_connection(struct connectdata *conn);
+static CURLcode file_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
 
 /*
  * FILE scheme handler.
@@ -116,11 +118,13 @@ const struct Curl_handler Curl_handler_file = {
 };
 
 
-static CURLcode file_setup_connection(struct connectdata *conn)
+static CURLcode file_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
+  (void)conn;
   /* allocate the FILE specific struct */
-  conn->data->req.p.file = calloc(1, sizeof(struct FILEPROTO));
-  if(!conn->data->req.p.file)
+  data->req.p.file = calloc(1, sizeof(struct FILEPROTO));
+  if(!data->req.p.file)
     return CURLE_OUT_OF_MEMORY;
 
   return CURLE_OK;
@@ -131,9 +135,8 @@ static CURLcode file_setup_connection(struct connectdata *conn)
  * do protocol-specific actions at connect-time.  We emulate a
  * connect-then-transfer protocol and "connect" to the file here
  */
-static CURLcode file_connect(struct connectdata *conn, bool *done)
+static CURLcode file_connect(struct Curl_easy *data, bool *done)
 {
-  struct Curl_easy *data = conn->data;
   char *real_path;
   struct FILEPROTO *file = data->req.p.file;
   int fd;
@@ -198,7 +201,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
   file->fd = fd;
   if(!data->set.upload && (fd == -1)) {
     failf(data, "Couldn't open file %s", data->state.up.path);
-    file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
+    file_done(data, CURLE_FILE_COULDNT_READ_FILE, FALSE);
     return CURLE_FILE_COULDNT_READ_FILE;
   }
   *done = TRUE;
@@ -206,10 +209,10 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode file_done(struct connectdata *conn,
-                               CURLcode status, bool premature)
+static CURLcode file_done(struct Curl_easy *data,
+                          CURLcode status, bool premature)
 {
-  struct FILEPROTO *file = conn->data->req.p.file;
+  struct FILEPROTO *file = data->req.p.file;
   (void)status; /* not used */
   (void)premature; /* not used */
 
@@ -224,11 +227,13 @@ static CURLcode file_done(struct connectdata *conn,
   return CURLE_OK;
 }
 
-static CURLcode file_disconnect(struct connectdata *conn,
+static CURLcode file_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 bool dead_connection)
 {
   (void)dead_connection; /* not used */
-  return file_done(conn, 0, 0);
+  (void)conn;
+  return file_done(data, 0, 0);
 }
 
 #ifdef DOS_FILESYSTEM
@@ -237,14 +242,13 @@ static CURLcode file_disconnect(struct connectdata *conn,
 #define DIRSEP '/'
 #endif
 
-static CURLcode file_upload(struct connectdata *conn)
+static CURLcode file_upload(struct Curl_easy *data)
 {
-  struct FILEPROTO *file = conn->data->req.p.file;
+  struct FILEPROTO *file = data->req.p.file;
   const char *dir = strchr(file->path, DIRSEP);
   int fd;
   int mode;
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
   char *buf = data->state.buffer;
   curl_off_t bytecount = 0;
   struct_stat file_stat;
@@ -254,7 +258,7 @@ static CURLcode file_upload(struct connectdata *conn)
    * Since FILE: doesn't do the full init, we need to provide some extra
    * assignments here.
    */
-  conn->data->req.upload_fromhere = buf;
+  data->req.upload_fromhere = buf;
 
   if(!dir)
     return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
@@ -273,7 +277,7 @@ static CURLcode file_upload(struct connectdata *conn)
   else
     mode = MODE_DEFAULT|O_TRUNC;
 
-  fd = open(file->path, mode, conn->data->set.new_file_perms);
+  fd = open(file->path, mode, data->set.new_file_perms);
   if(fd < 0) {
     failf(data, "Can't open %s for writing", file->path);
     return CURLE_WRITE_ERROR;
@@ -297,7 +301,7 @@ static CURLcode file_upload(struct connectdata *conn)
     size_t nread;
     size_t nwrite;
     size_t readcount;
-    result = Curl_fillreadbuffer(conn, data->set.buffer_size, &readcount);
+    result = Curl_fillreadbuffer(data, data->set.buffer_size, &readcount);
     if(result)
       break;
 
@@ -333,12 +337,12 @@ static CURLcode file_upload(struct connectdata *conn)
 
     Curl_pgrsSetUploadCounter(data, bytecount);
 
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
       result = Curl_speedcheck(data, Curl_now());
   }
-  if(!result && Curl_pgrsUpdate(conn))
+  if(!result && Curl_pgrsUpdate(data))
     result = CURLE_ABORTED_BY_CALLBACK;
 
   close(fd);
@@ -354,7 +358,7 @@ static CURLcode file_upload(struct connectdata *conn)
  * opposed to sockets) we instead perform the whole do-operation in this
  * function.
  */
-static CURLcode file_do(struct connectdata *conn, bool *done)
+static CURLcode file_do(struct Curl_easy *data, bool *done)
 {
   /* This implementation ignores the host name in conformance with
      RFC 1738. Only local files (reachable via the standard file system)
@@ -365,10 +369,9 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
   struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
                           Windows version to have a different struct without
                           having to redefine the simple word 'stat' */
-  curl_off_t expected_size = 0;
+  curl_off_t expected_size = -1;
   bool size_known;
   bool fstated = FALSE;
-  struct Curl_easy *data = conn->data;
   char *buf = data->state.buffer;
   curl_off_t bytecount = 0;
   int fd;
@@ -379,17 +382,17 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
   Curl_pgrsStartNow(data);
 
   if(data->set.upload)
-    return file_upload(conn);
+    return file_upload(data);
 
-  file = conn->data->req.p.file;
+  file = data->req.p.file;
 
   /* get the fd from the connection phase */
   fd = file->fd;
 
   /* VMS: This only works reliable for STREAMLF files */
   if(-1 != fstat(fd, &statbuf)) {
-    /* we could stat it, then read out the size */
-    expected_size = statbuf.st_size;
+    if(!S_ISDIR(statbuf.st_mode))
+      expected_size = statbuf.st_size;
     /* and store the modification time */
     data->info.filetime = statbuf.st_mtime;
     fstated = TRUE;
@@ -407,14 +410,16 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
     struct tm buffer;
     const struct tm *tm = &buffer;
     char header[80];
-    msnprintf(header, sizeof(header),
-              "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
-              expected_size);
-    result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
-    if(result)
-      return result;
+    if(expected_size >= 0) {
+      msnprintf(header, sizeof(header),
+                "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n",
+                expected_size);
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, header, 0);
+      if(result)
+        return result;
+    }
 
-    result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+    result = Curl_client_write(data, CLIENTWRITE_HEADER,
                                (char *)"Accept-ranges: bytes\r\n", 0);
     if(result)
       return result;
@@ -435,7 +440,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
               tm->tm_min,
               tm->tm_sec,
               data->set.opt_no_body ? "": "\r\n");
-    result = Curl_client_write(conn, CLIENTWRITE_HEADER, header, 0);
+    result = Curl_client_write(data, CLIENTWRITE_HEADER, header, 0);
     if(result)
       return result;
     /* set the file size to make it available post transfer */
@@ -445,7 +450,7 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
   }
 
   /* Check whether file range has been specified */
-  result = Curl_range(conn);
+  result = Curl_range(data);
   if(result)
     return result;
 
@@ -514,18 +519,18 @@ static CURLcode file_do(struct connectdata *conn, bool *done)
     if(size_known)
       expected_size -= nread;
 
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, buf, nread);
     if(result)
       return result;
 
     Curl_pgrsSetDownloadCounter(data, bytecount);
 
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
       result = Curl_speedcheck(data, Curl_now());
   }
-  if(Curl_pgrsUpdate(conn))
+  if(Curl_pgrsUpdate(data))
     result = CURLE_ABORTED_BY_CALLBACK;
 
   return result;

+ 5 - 5
lib/formdata.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -29,22 +29,22 @@
 /* used by FormAdd for temporary storage */
 struct FormInfo {
   char *name;
-  bool name_alloc;
   size_t namelength;
   char *value;
-  bool value_alloc;
   curl_off_t contentslength;
   char *contenttype;
-  bool contenttype_alloc;
   long flags;
   char *buffer;      /* pointer to existing buffer used for file upload */
   size_t bufferlength;
   char *showfilename; /* The file name to show. If not set, the actual
                          file name will be used */
-  bool showfilename_alloc;
   char *userp;        /* pointer for the read callback */
   struct curl_slist *contentheader;
   struct FormInfo *more;
+  bool name_alloc;
+  bool value_alloc;
+  bool contenttype_alloc;
+  bool showfilename_alloc;
 };
 
 CURLcode Curl_getformdata(struct Curl_easy *data,

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 202 - 181
lib/ftp.c


+ 7 - 7
lib/ftp.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -31,7 +31,7 @@ extern const struct Curl_handler Curl_handler_ftp;
 extern const struct Curl_handler Curl_handler_ftps;
 #endif
 
-CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
+CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nread,
                              int *ftpcode);
 #endif /* CURL_DISABLE_FTP */
 
@@ -116,9 +116,9 @@ struct FTP {
 struct ftp_conn {
   struct pingpong pp;
   char *entrypath; /* the PWD reply when we logged on */
+  char *file;    /* url-decoded file name (or path) */
   char **dirs;   /* realloc()ed array for path components */
   int dirdepth;  /* number of entries used in the 'dirs' array */
-  char *file;    /* url-decoded file name (or path) */
   bool dont_check;  /* Set to TRUE to prevent the final (post-transfer)
                        file size and 226/250 status check. It should still
                        read the line, just ignore the result. */
@@ -131,6 +131,10 @@ struct ftp_conn {
   bool cwdfail;     /* set TRUE if a CWD command fails, as then we must prevent
                        caching the current directory */
   bool wait_data_conn; /* this is set TRUE if data connection is waited */
+  /* newhost is the (allocated) IP addr or host name to connect the data
+     connection to */
+  unsigned short newport;
+  char *newhost;
   char *prevpath;   /* url-decoded conn->path from the previous transfer */
   char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
                         and others (A/I or zero) */
@@ -145,10 +149,6 @@ struct ftp_conn {
   curl_off_t known_filesize; /* file size is different from -1, if wildcard
                                 LIST parsing was done and wc_statemach set
                                 it */
-  /* newhost is the (allocated) IP addr or host name to connect the data
-     connection to */
-  char *newhost;          /* this is the pair to connect the DATA... */
-  unsigned short newport; /* connection to */
 };
 
 #define DEFAULT_ACCEPT_TIMEOUT   60000 /* milliseconds == one minute */

+ 15 - 15
lib/ftplistparser.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -268,11 +268,11 @@ static int ftp_pl_get_permission(const char *str)
   return permissions;
 }
 
-static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
+static CURLcode ftp_pl_insert_finfo(struct Curl_easy *data,
                                     struct fileinfo *infop)
 {
   curl_fnmatch_callback compare;
-  struct WildcardData *wc = &conn->data->wildcard;
+  struct WildcardData *wc = &data->wildcard;
   struct ftp_wc *ftpwc = wc->protdata;
   struct Curl_llist *llist = &wc->filelist;
   struct ftp_parselist_data *parser = ftpwc->parser;
@@ -293,13 +293,13 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
                           str + parser->offsets.user : NULL;
 
   /* get correct fnmatch callback */
-  compare = conn->data->set.fnmatch;
+  compare = data->set.fnmatch;
   if(!compare)
     compare = Curl_fnmatch;
 
   /* filter pattern-corresponding filenames */
-  Curl_set_in_callback(conn->data, true);
-  if(compare(conn->data->set.fnmatch_data, wc->pattern,
+  Curl_set_in_callback(data, true);
+  if(compare(data->set.fnmatch_data, wc->pattern,
              finfo->filename) == 0) {
     /* discard symlink which is containing multiple " -> " */
     if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
@@ -310,7 +310,7 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
   else {
     add = FALSE;
   }
-  Curl_set_in_callback(conn->data, false);
+  Curl_set_in_callback(data, false);
 
   if(add) {
     Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
@@ -327,8 +327,8 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
                           void *connptr)
 {
   size_t bufflen = size*nmemb;
-  struct connectdata *conn = (struct connectdata *)connptr;
-  struct ftp_wc *ftpwc = conn->data->wildcard.protdata;
+  struct Curl_easy *data = (struct Curl_easy *)connptr;
+  struct ftp_wc *ftpwc = data->wildcard.protdata;
   struct ftp_parselist_data *parser = ftpwc->parser;
   struct fileinfo *infop;
   struct curl_fileinfo *finfo;
@@ -728,7 +728,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -740,7 +740,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.filename = parser->item_offset;
             parser->state.UNIX.main = PL_UNIX_FILETYPE;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -835,7 +835,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           else if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.symlink_target = parser->item_offset;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -847,7 +847,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
           if(c == '\n') {
             finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
             parser->offsets.symlink_target = parser->item_offset;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -967,7 +967,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
             parser->offsets.filename = parser->item_offset;
             finfo->b_data[finfo->b_used - 1] = 0;
             parser->offsets.filename = parser->item_offset;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;
@@ -979,7 +979,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
         case PL_WINNT_FILENAME_WINEOL:
           if(c == '\n') {
             parser->offsets.filename = parser->item_offset;
-            result = ftp_pl_insert_finfo(conn, infop);
+            result = ftp_pl_insert_finfo(data, infop);
             if(result) {
               parser->error = result;
               goto fail;

+ 2 - 0
lib/getinfo.c

@@ -101,6 +101,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
     if(!m) {
       if(data->set.opt_no_body)
         m = "HEAD";
+#ifndef CURL_DISABLE_HTTP
       else {
         switch(data->state.httpreq) {
         case HTTPREQ_POST:
@@ -120,6 +121,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
           break;
         }
       }
+#endif
     }
     *param_charp = m;
   }

+ 60 - 9
lib/gopher.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -33,6 +33,7 @@
 #include "gopher.h"
 #include "select.h"
 #include "strdup.h"
+#include "vtls/vtls.h"
 #include "url.h"
 #include "escape.h"
 #include "warnless.h"
@@ -45,7 +46,11 @@
  * Forward declarations.
  */
 
-static CURLcode gopher_do(struct connectdata *conn, bool *done);
+static CURLcode gopher_do(struct Curl_easy *data, bool *done);
+#ifdef USE_SSL
+static CURLcode gopher_connect(struct Curl_easy *data, bool *done);
+static CURLcode gopher_connecting(struct Curl_easy *data, bool *done);
+#endif
 
 /*
  * Gopher protocol handler.
@@ -75,10 +80,51 @@ const struct Curl_handler Curl_handler_gopher = {
   PROTOPT_NONE                          /* flags */
 };
 
-static CURLcode gopher_do(struct connectdata *conn, bool *done)
+#ifdef USE_SSL
+const struct Curl_handler Curl_handler_gophers = {
+  "GOPHERS",                            /* scheme */
+  ZERO_NULL,                            /* setup_connection */
+  gopher_do,                            /* do_it */
+  ZERO_NULL,                            /* done */
+  ZERO_NULL,                            /* do_more */
+  gopher_connect,                       /* connect_it */
+  gopher_connecting,                    /* connecting */
+  ZERO_NULL,                            /* doing */
+  ZERO_NULL,                            /* proto_getsock */
+  ZERO_NULL,                            /* doing_getsock */
+  ZERO_NULL,                            /* domore_getsock */
+  ZERO_NULL,                            /* perform_getsock */
+  ZERO_NULL,                            /* disconnect */
+  ZERO_NULL,                            /* readwrite */
+  ZERO_NULL,                            /* connection_check */
+  PORT_GOPHER,                          /* defport */
+  CURLPROTO_GOPHERS,                    /* protocol */
+  CURLPROTO_GOPHER,                     /* family */
+  PROTOPT_SSL                           /* flags */
+};
+
+static CURLcode gopher_connect(struct Curl_easy *data, bool *done)
+{
+  (void)data;
+  (void)done;
+  return CURLE_OK;
+}
+
+static CURLcode gopher_connecting(struct Curl_easy *data, bool *done)
+{
+  struct connectdata *conn = data->conn;
+  CURLcode result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
+  if(result)
+    connclose(conn, "Failed TLS connection");
+  *done = TRUE;
+  return result;
+}
+#endif
+
+static CURLcode gopher_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   char *gopherpath;
   char *path = data->state.up.path;
@@ -127,9 +173,14 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
   k = curlx_uztosz(len);
 
   for(;;) {
-    result = Curl_write(conn, sockfd, sel, k, &amount);
+    /* Break out of the loop if the selector is empty because OpenSSL and/or
+       LibreSSL fail with errno 0 if this is the case. */
+    if(strlen(sel) < 1)
+      break;
+
+    result = Curl_write(data, sockfd, sel, k, &amount);
     if(!result) { /* Which may not have written it all! */
-      result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount);
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, sel, amount);
       if(result)
         break;
 
@@ -141,7 +192,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
     else
       break;
 
-    timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
+    timeout_ms = Curl_timeleft(data, NULL, FALSE);
     if(timeout_ms < 0) {
       result = CURLE_OPERATION_TIMEDOUT;
       break;
@@ -169,12 +220,12 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
   free(sel_org);
 
   if(!result)
-    result = Curl_write(conn, sockfd, "\r\n", 2, &amount);
+    result = Curl_write(data, sockfd, "\r\n", 2, &amount);
   if(result) {
     failf(data, "Failed sending Gopher request");
     return result;
   }
-  result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
+  result = Curl_client_write(data, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
   if(result)
     return result;
 

+ 3 - 0
lib/gopher.h

@@ -24,6 +24,9 @@
 
 #ifndef CURL_DISABLE_GOPHER
 extern const struct Curl_handler Curl_handler_gopher;
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_gophers;
+#endif
 #endif
 
 #endif /* HEADER_CURL_GOPHER_H */

+ 1 - 1
lib/hash.c

@@ -175,7 +175,7 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
   return NULL;
 }
 
-#if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST)
+#if defined(DEBUGBUILD) && defined(AGGRESSIVE_TEST)
 void
 Curl_hash_apply(Curl_hash *h, void *user,
                 void (*cb)(void *user, void *ptr))

+ 9 - 11
lib/hostasyn.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -66,25 +66,23 @@
  *
  * The storage operation locks and unlocks the DNS cache.
  */
-CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
                                 int status,
                                 struct Curl_addrinfo *ai)
 {
   struct Curl_dns_entry *dns = NULL;
   CURLcode result = CURLE_OK;
 
-  conn->async.status = status;
+  data->state.async.status = status;
 
   if(CURL_ASYNC_SUCCESS == status) {
     if(ai) {
-      struct Curl_easy *data = conn->data;
-
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
       dns = Curl_cache_addr(data, ai,
-                            conn->async.hostname,
-                            conn->async.port);
+                            data->state.async.hostname,
+                            data->state.async.port);
       if(data->share)
         Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
 
@@ -99,12 +97,12 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
     }
   }
 
-  conn->async.dns = dns;
+  data->state.async.dns = dns;
 
  /* Set async.done TRUE last in this function since it may be used multi-
     threaded and once this is TRUE the other thread may read fields from the
     async struct */
-  conn->async.done = TRUE;
+  data->state.async.done = TRUE;
 
   /* IPv4: The input hostent struct will be freed by ares when we return from
      this function */
@@ -117,12 +115,12 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
  * name resolve layers (selected at build-time). They all take this same set
  * of arguments
  */
-struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
                                        const char *hostname,
                                        int port,
                                        int *waitp)
 {
-  return Curl_resolver_getaddrinfo(conn, hostname, port, waitp);
+  return Curl_resolver_getaddrinfo(data, hostname, port, waitp);
 }
 
 #endif /* CURLRES_ASYNCH */

+ 58 - 52
lib/hostip.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -253,14 +253,12 @@ sigjmp_buf curl_jmpenv;
 #endif
 
 /* lookup address, returns entry if found and not stale */
-static struct Curl_dns_entry *
-fetch_addr(struct connectdata *conn,
-                const char *hostname,
-                int port)
+static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data,
+                                         const char *hostname,
+                                         int port)
 {
   struct Curl_dns_entry *dns = NULL;
   size_t entry_len;
-  struct Curl_easy *data = conn->data;
   char entry_id[MAX_HOSTCACHE_LEN];
 
   /* Create an entry id, based upon the hostname and port */
@@ -311,17 +309,16 @@ fetch_addr(struct connectdata *conn,
  * use, or we'll leak memory!
  */
 struct Curl_dns_entry *
-Curl_fetch_addr(struct connectdata *conn,
+Curl_fetch_addr(struct Curl_easy *data,
                 const char *hostname,
                 int port)
 {
-  struct Curl_easy *data = conn->data;
   struct Curl_dns_entry *dns = NULL;
 
   if(data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-  dns = fetch_addr(conn, hostname, port);
+  dns = fetch_addr(data, hostname, port);
 
   if(dns)
     dns->inuse++; /* we use it! */
@@ -444,7 +441,7 @@ Curl_cache_addr(struct Curl_easy *data,
   dns->addr = addr; /* this is the address(es) */
   time(&dns->timestamp);
   if(dns->timestamp == 0)
-    dns->timestamp = 1;   /* zero indicates CURLOPT_RESOLVE entry */
+    dns->timestamp = 1;   /* zero indicates permanent CURLOPT_RESOLVE entry */
 
   /* Store the resolved data in our DNS cache. */
   dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len + 1,
@@ -480,16 +477,16 @@ Curl_cache_addr(struct Curl_easy *data,
  * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
  */
 
-enum resolve_t Curl_resolv(struct connectdata *conn,
+enum resolve_t Curl_resolv(struct Curl_easy *data,
                            const char *hostname,
                            int port,
                            bool allowDOH,
                            struct Curl_dns_entry **entry)
 {
   struct Curl_dns_entry *dns = NULL;
-  struct Curl_easy *data = conn->data;
   CURLcode result;
   enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
+  struct connectdata *conn = data->conn;
 
   *entry = NULL;
   conn->bits.doh = FALSE; /* default is not */
@@ -497,7 +494,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
   if(data->share)
     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-  dns = fetch_addr(conn, hostname, port);
+  dns = fetch_addr(data, hostname, port);
 
   if(dns) {
     infof(data, "Hostname %s was found in DNS cache\n", hostname);
@@ -523,7 +520,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
     if(data->set.resolver_start) {
       int st;
       Curl_set_in_callback(data, true);
-      st = data->set.resolver_start(data->state.resolver, NULL,
+      st = data->set.resolver_start(data->state.async.resolver, NULL,
                                     data->set.resolver_start_client);
       Curl_set_in_callback(data, false);
       if(st)
@@ -565,17 +562,17 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
     if(!addr) {
       /* Check what IP specifics the app has requested and if we can provide
        * it. If not, bail out. */
-      if(!Curl_ipvalid(conn))
+      if(!Curl_ipvalid(data, conn))
         return CURLRESOLV_ERROR;
 
       if(allowDOH && data->set.doh && !ipnum) {
-        addr = Curl_doh(conn, hostname, port, &respwait);
+        addr = Curl_doh(data, hostname, port, &respwait);
       }
       else {
         /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
            non-zero value indicating that we need to wait for the response to
            the resolve call */
-        addr = Curl_getaddrinfo(conn,
+        addr = Curl_getaddrinfo(data,
 #ifdef DEBUGBUILD
                                 (data->set.str[STRING_DEVICE]
                                  && !strcmp(data->set.str[STRING_DEVICE],
@@ -589,7 +586,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
         /* the response to our resolve call will come asynchronously at
            a later time, good or bad */
         /* First, check that we haven't received the info by now */
-        result = Curl_resolv_check(conn, &dns);
+        result = Curl_resolv_check(data, &dns);
         if(result) /* error detected */
           return CURLRESOLV_ERROR;
         if(dns)
@@ -658,7 +655,7 @@ RETSIGTYPE alarmfunc(int sig)
  * CURLRESOLV_PENDING  (1) = waiting for response, no pointer
  */
 
-enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
+enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
                                    const char *hostname,
                                    int port,
                                    struct Curl_dns_entry **entry,
@@ -676,7 +673,6 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
 #endif /* HAVE_SIGACTION */
   volatile long timeout;
   volatile unsigned int prev_alarm = 0;
-  struct Curl_easy *data = conn->data;
 #endif /* USE_ALARM_TIMEOUT */
   enum resolve_t rc;
 
@@ -695,7 +691,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
 
   if(!timeout)
     /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
-    return Curl_resolv(conn, hostname, port, TRUE, entry);
+    return Curl_resolv(data, hostname, port, TRUE, entry);
 
   if(timeout < 1000) {
     /* The alarm() function only provides integer second resolution, so if
@@ -728,7 +724,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
     keep_copysig = TRUE; /* yes, we have a copy */
     sigact.sa_handler = alarmfunc;
 #ifdef SA_RESTART
-    /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
+    /* HPUX doesn't have SA_RESTART but defaults to that behavior! */
     sigact.sa_flags &= ~SA_RESTART;
 #endif
     /* now set the new struct */
@@ -748,7 +744,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
 #else
 #ifndef CURLRES_ASYNCH
   if(timeoutms)
-    infof(conn->data, "timeout on name lookup is not supported\n");
+    infof(data, "timeout on name lookup is not supported\n");
 #else
   (void)timeoutms; /* timeoutms not used with an async resolver */
 #endif
@@ -757,7 +753,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
   /* Perform the actual name resolution. This might be interrupted by an
    * alarm if it takes too long.
    */
-  rc = Curl_resolv(conn, hostname, port, TRUE, entry);
+  rc = Curl_resolv(data, hostname, port, TRUE, entry);
 
 #ifdef USE_ALARM_TIMEOUT
 clean_up:
@@ -784,7 +780,7 @@ clean_up:
   if(prev_alarm) {
     /* there was an alarm() set before us, now put it back */
     timediff_t elapsed_secs = Curl_timediff(Curl_now(),
-                                            conn->created) / 1000;
+                                            data->conn->created) / 1000;
 
     /* the alarm period is counted in even number of seconds */
     unsigned long alarm_set = (unsigned long)(prev_alarm - elapsed_secs);
@@ -916,17 +912,24 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       char *addr_end;
       char *port_ptr;
       char *end_ptr;
+      bool permanent = TRUE;
+      char *host_begin;
       char *host_end;
       unsigned long tmp_port;
       bool error = true;
 
-      host_end = strchr(hostp->data, ':');
+      host_begin = hostp->data;
+      if(host_begin[0] == '+') {
+        host_begin++;
+        permanent = FALSE;
+      }
+      host_end = strchr(host_begin, ':');
       if(!host_end ||
-         ((host_end - hostp->data) >= (ptrdiff_t)sizeof(hostname)))
+         ((host_end - host_begin) >= (ptrdiff_t)sizeof(hostname)))
         goto err;
 
-      memcpy(hostname, hostp->data, host_end - hostp->data);
-      hostname[host_end - hostp->data] = '\0';
+      memcpy(hostname, host_begin, host_end - host_begin);
+      hostname[host_end - host_begin] = '\0';
 
       port_ptr = host_end + 1;
       tmp_port = strtoul(port_ptr, &end_ptr, 10);
@@ -1008,18 +1011,22 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       if(data->share)
         Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
 
-      /* See if its already in our dns cache */
+      /* See if it's already in our dns cache */
       dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
 
       if(dns) {
         infof(data, "RESOLVE %s:%d is - old addresses discarded!\n",
                 hostname, port);
-        /* delete old entry entry, there are two reasons for this
+        /* 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,
             but if it is close to expire, then by the time next http
             request is made, it can get expired and pruned because old
-            entry is not necessarily marked as added by CURLOPT_RESOLVE. */
+            entry is not necessarily marked as permanent.
+         3. when adding a non-permanent entry, we want it to remove and
+            replace an existing permanent entry.
+         4. when adding a non-permanent entry, we want it to get a "fresh"
+            timeout that starts _now_. */
 
         Curl_hash_delete(data->dns.hostcache, entry_id, entry_len + 1);
       }
@@ -1027,10 +1034,11 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
       /* put this new host in the cache */
       dns = Curl_cache_addr(data, head, hostname, port);
       if(dns) {
-        dns->timestamp = 0; /* mark as added by CURLOPT_RESOLVE */
+        if(permanent)
+          dns->timestamp = 0; /* mark as permanent */
         /* release the returned reference; the cache itself will keep the
          * entry alive: */
-            dns->inuse--;
+        dns->inuse--;
       }
 
       if(data->share)
@@ -1040,8 +1048,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
         Curl_freeaddrinfo(head);
         return CURLE_OUT_OF_MEMORY;
       }
-      infof(data, "Added %s:%d:%s to DNS cache\n",
-            hostname, port, addresses);
+      infof(data, "Added %s:%d:%s to DNS cache%s\n",
+            hostname, port, addresses, permanent ? "" : " (non-permanent)");
 
       /* Wildcard hostname */
       if(hostname[0] == '*' && hostname[1] == '\0') {
@@ -1056,29 +1064,29 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
   return CURLE_OK;
 }
 
-CURLcode Curl_resolv_check(struct connectdata *conn,
+CURLcode Curl_resolv_check(struct Curl_easy *data,
                            struct Curl_dns_entry **dns)
 {
 #if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
   (void)dns;
 #endif
 
-  if(conn->bits.doh)
-    return Curl_doh_is_resolved(conn, dns);
-  return Curl_resolver_is_resolved(conn, dns);
+  if(data->conn->bits.doh)
+    return Curl_doh_is_resolved(data, dns);
+  return Curl_resolver_is_resolved(data, dns);
 }
 
-int Curl_resolv_getsock(struct connectdata *conn,
+int Curl_resolv_getsock(struct Curl_easy *data,
                         curl_socket_t *socks)
 {
 #ifdef CURLRES_ASYNCH
-  if(conn->bits.doh)
+  if(data->conn->bits.doh)
     /* nothing to wait for during DOH resolve, those handles have their own
        sockets */
     return GETSOCK_BLANK;
-  return Curl_resolver_getsock(conn, socks);
+  return Curl_resolver_getsock(data, socks);
 #else
-  (void)conn;
+  (void)data;
   (void)socks;
   return GETSOCK_BLANK;
 #endif
@@ -1089,21 +1097,19 @@ int Curl_resolv_getsock(struct connectdata *conn,
 
    Note: this function disconnects and frees the conn data in case of
    resolve failure */
-CURLcode Curl_once_resolved(struct connectdata *conn,
-                            bool *protocol_done)
+CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_done)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
 
-  if(conn->async.dns) {
-    conn->dns_entry = conn->async.dns;
-    conn->async.dns = NULL;
+  if(data->state.async.dns) {
+    conn->dns_entry = data->state.async.dns;
+    data->state.async.dns = NULL;
   }
 
-  result = Curl_setup_conn(conn, protocol_done);
+  result = Curl_setup_conn(data, protocol_done);
 
   if(result) {
-    struct Curl_easy *data = conn->data;
-    DEBUGASSERT(data);
     Curl_detach_connnection(data);
     Curl_conncache_remove_conn(data, conn, TRUE);
     Curl_disconnect(data, conn, TRUE);

+ 12 - 13
lib/hostip.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -65,7 +65,7 @@ struct Curl_hash *Curl_global_host_cache_init(void);
 
 struct Curl_dns_entry {
   struct Curl_addrinfo *addr;
-  /* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */
+  /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (doesn't time out) */
   time_t timestamp;
   /* use-counter, use Curl_resolv_unlock to release reference */
   long inuse;
@@ -85,12 +85,12 @@ enum resolve_t {
   CURLRESOLV_RESOLVED =  0,
   CURLRESOLV_PENDING  =  1
 };
-enum resolve_t Curl_resolv(struct connectdata *conn,
+enum resolve_t Curl_resolv(struct Curl_easy *data,
                            const char *hostname,
                            int port,
                            bool allowDOH,
                            struct Curl_dns_entry **dnsentry);
-enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
+enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
                                    const char *hostname, int port,
                                    struct Curl_dns_entry **dnsentry,
                                    timediff_t timeoutms);
@@ -99,7 +99,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
 /*
  * Curl_ipv6works() returns TRUE if IPv6 seems to work.
  */
-bool Curl_ipv6works(struct connectdata *conn);
+bool Curl_ipv6works(struct Curl_easy *data);
 #else
 #define Curl_ipv6works(x) FALSE
 #endif
@@ -108,7 +108,7 @@ bool Curl_ipv6works(struct connectdata *conn);
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
  */
-bool Curl_ipvalid(struct connectdata *conn);
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn);
 
 
 /*
@@ -117,7 +117,7 @@ bool Curl_ipvalid(struct connectdata *conn);
  * name resolve layers (selected at build-time). They all take this same set
  * of arguments
  */
-struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
                                        const char *hostname,
                                        int port,
                                        int *waitp);
@@ -148,7 +148,7 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
 /* IPv4 threadsafe resolve function used for synch and asynch builds */
 struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
 
-CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect);
+CURLcode Curl_once_resolved(struct Curl_easy *data, bool *protocol_connect);
 
 /*
  * Curl_addrinfo_callback() is used when we build with any asynch specialty.
@@ -156,7 +156,7 @@ CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect);
  * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async
  * request completed whether successful or failed.
  */
-CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+CURLcode Curl_addrinfo_callback(struct Curl_easy *data,
                                 int status,
                                 struct Curl_addrinfo *ai);
 
@@ -177,7 +177,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ip,
  * use, or we'll leak memory!
  */
 struct Curl_dns_entry *
-Curl_fetch_addr(struct connectdata *conn,
+Curl_fetch_addr(struct Curl_easy *data,
                 const char *hostname,
                 int port);
 
@@ -240,10 +240,9 @@ void Curl_hostcache_clean(struct Curl_easy *data, struct Curl_hash *hash);
  * Populate the cache with specified entries from CURLOPT_RESOLVE.
  */
 CURLcode Curl_loadhostpairs(struct Curl_easy *data);
-
-CURLcode Curl_resolv_check(struct connectdata *conn,
+CURLcode Curl_resolv_check(struct Curl_easy *data,
                            struct Curl_dns_entry **dns);
-int Curl_resolv_getsock(struct connectdata *conn,
+int Curl_resolv_getsock(struct Curl_easy *data,
                         curl_socket_t *socks);
 
 #endif /* HEADER_CURL_HOSTIP_H */

+ 6 - 5
lib/hostip4.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -61,8 +61,9 @@
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
  */
-bool Curl_ipvalid(struct connectdata *conn)
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
 {
+  (void)data;
   if(conn->ip_version == CURL_IPRESOLVE_V6)
     /* An IPv6 address was requested and we can't get/use one */
     return FALSE;
@@ -88,7 +89,7 @@ bool Curl_ipvalid(struct connectdata *conn)
  * flavours have thread-safe versions of the plain gethostbyname() etc.
  *
  */
-struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
                                        const char *hostname,
                                        int port,
                                        int *waitp)
@@ -96,14 +97,14 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   struct Curl_addrinfo *ai = NULL;
 
 #ifdef CURL_DISABLE_VERBOSE_STRINGS
-  (void)conn;
+  (void)data;
 #endif
 
   *waitp = 0; /* synchronous response only */
 
   ai = Curl_ipv4_resolve_r(hostname, port);
   if(!ai)
-    infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
+    infof(data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
 
   return ai;
 }

+ 13 - 17
lib/hostip6.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -62,16 +62,15 @@
 /*
  * Curl_ipv6works() returns TRUE if IPv6 seems to work.
  */
-bool Curl_ipv6works(struct connectdata *conn)
+bool Curl_ipv6works(struct Curl_easy *data)
 {
-  if(conn) {
+  if(data) {
     /* the nature of most system is that IPv6 status doesn't come and go
        during a program's lifetime so we only probe the first time and then we
        have the info kept for fast re-use */
-    DEBUGASSERT(conn);
-    DEBUGASSERT(conn->data);
-    DEBUGASSERT(conn->data->multi);
-    return conn->data->multi->ipv6_works;
+    DEBUGASSERT(data);
+    DEBUGASSERT(data->multi);
+    return data->multi->ipv6_works;
   }
   else {
     int ipv6_works = -1;
@@ -82,7 +81,7 @@ bool Curl_ipv6works(struct connectdata *conn)
       ipv6_works = 0;
     else {
       ipv6_works = 1;
-      Curl_closesocket(NULL, s);
+      sclose(s);
     }
     return (ipv6_works>0)?TRUE:FALSE;
   }
@@ -92,10 +91,10 @@ bool Curl_ipv6works(struct connectdata *conn)
  * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
  * been set and returns TRUE if they are OK.
  */
-bool Curl_ipvalid(struct connectdata *conn)
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
 {
   if(conn->ip_version == CURL_IPRESOLVE_V6)
-    return Curl_ipv6works(conn);
+    return Curl_ipv6works(data);
 
   return TRUE;
 }
@@ -128,7 +127,7 @@ static void dump_addrinfo(struct connectdata *conn,
  * memory we need to free after use. That memory *MUST* be freed with
  * Curl_freeaddrinfo(), nothing else.
  */
-struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+struct Curl_addrinfo *Curl_getaddrinfo(struct Curl_easy *data,
                                        const char *hostname,
                                        int port,
                                        int *waitp)
@@ -142,14 +141,11 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
   char addrbuf[128];
 #endif
   int pf;
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  struct Curl_easy *data = conn->data;
-#endif
 
   *waitp = 0; /* synchronous response only */
 
   /* Check if a limited name resolve has been requested */
-  switch(conn->ip_version) {
+  switch(data->set.ipver) {
   case CURL_IPRESOLVE_V4:
     pf = PF_INET;
     break;
@@ -161,13 +157,13 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
     break;
   }
 
-  if((pf != PF_INET) && !Curl_ipv6works(conn))
+  if((pf != PF_INET) && !Curl_ipv6works(data))
     /* The stack seems to be a non-IPv6 one */
     pf = PF_INET;
 
   memset(&hints, 0, sizeof(hints));
   hints.ai_family = pf;
-  hints.ai_socktype = (conn->transport == TRNSPRT_TCP) ?
+  hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
     SOCK_STREAM : SOCK_DGRAM;
 
 #ifndef USE_RESOLVE_ON_IPS

+ 3 - 3
lib/hsts.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2020 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -325,7 +325,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
     /* no cache activated */
     return CURLE_OK;
 
-  /* if not new name is given, use the one we stored from the load */
+  /* if no new name is given, use the one we stored from the load */
   if(!file && h->filename)
     file = h->filename;
 
@@ -457,7 +457,7 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h)
  * format is documented here:
  * https://github.com/curl/curl/wiki/HSTS
  *
- * This function only returns error on major problems that prevents hsts
+ * This function only returns error on major problems that prevent hsts
  * handling to work completely. It will ignore individual syntactical errors
  * etc.
  */

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


+ 73 - 15
lib/http.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -23,6 +23,15 @@
  ***************************************************************************/
 #include "curl_setup.h"
 
+typedef enum {
+  HTTPREQ_GET,
+  HTTPREQ_POST,
+  HTTPREQ_POST_FORM, /* we make a difference internally */
+  HTTPREQ_POST_MIME, /* we make a difference internally */
+  HTTPREQ_PUT,
+  HTTPREQ_HEAD
+} Curl_HttpReq;
+
 #ifndef CURL_DISABLE_HTTP
 
 #ifdef USE_NGHTTP2
@@ -42,32 +51,78 @@ bool Curl_compareheader(const char *headerline,  /* line to check */
 
 char *Curl_copy_header_value(const char *header);
 
-char *Curl_checkProxyheaders(const struct connectdata *conn,
+char *Curl_checkProxyheaders(struct Curl_easy *data,
+                             const struct connectdata *conn,
                              const char *thisheader);
+#ifndef USE_HYPER
 CURLcode Curl_buffer_send(struct dynbuf *in,
-                          struct connectdata *conn,
+                          struct Curl_easy *data,
                           curl_off_t *bytes_written,
                           size_t included_body_bytes,
                           int socketindex);
+#else
+#define Curl_buffer_send(a,b,c,d,e) CURLE_OK
+#endif
 
-CURLcode Curl_add_timecondition(const struct connectdata *conn,
-                                struct dynbuf *buf);
-CURLcode Curl_add_custom_headers(struct connectdata *conn,
+CURLcode Curl_add_timecondition(struct Curl_easy *data,
+#ifndef USE_HYPER
+                                struct dynbuf *req
+#else
+                                void *headers
+#endif
+  );
+CURLcode Curl_add_custom_headers(struct Curl_easy *data,
                                  bool is_connect,
-                                 struct dynbuf *req_buffer);
+#ifndef USE_HYPER
+                                 struct dynbuf *req
+#else
+                                 void *headers
+#endif
+  );
 CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
                                     struct dynbuf *buf,
                                     struct Curl_easy *handle);
 
+void Curl_http_method(struct Curl_easy *data, struct connectdata *conn,
+                      const char **method, Curl_HttpReq *);
+CURLcode Curl_http_useragent(struct Curl_easy *data);
+CURLcode Curl_http_host(struct Curl_easy *data, struct connectdata *conn);
+CURLcode Curl_http_target(struct Curl_easy *data, struct connectdata *conn,
+                          struct dynbuf *req);
+CURLcode Curl_http_statusline(struct Curl_easy *data,
+                              struct connectdata *conn);
+CURLcode Curl_http_header(struct Curl_easy *data, struct connectdata *conn,
+                          char *headp);
+CURLcode Curl_http_body(struct Curl_easy *data, struct connectdata *conn,
+                        Curl_HttpReq httpreq,
+                        const char **teep);
+CURLcode Curl_http_bodysend(struct Curl_easy *data, struct connectdata *conn,
+                            struct dynbuf *r, Curl_HttpReq httpreq);
+#ifndef CURL_DISABLE_COOKIES
+CURLcode Curl_http_cookies(struct Curl_easy *data,
+                           struct connectdata *conn,
+                           struct dynbuf *r);
+#else
+#define Curl_http_cookies(a,b,c) CURLE_OK
+#endif
+CURLcode Curl_http_resume(struct Curl_easy *data,
+                          struct connectdata *conn,
+                          Curl_HttpReq httpreq);
+CURLcode Curl_http_range(struct Curl_easy *data,
+                         Curl_HttpReq httpreq);
+CURLcode Curl_http_firstwrite(struct Curl_easy *data,
+                              struct connectdata *conn,
+                              bool *done);
+
 /* protocol-specific functions set up to be called by the main engine */
-CURLcode Curl_http(struct connectdata *conn, bool *done);
-CURLcode Curl_http_done(struct connectdata *, CURLcode, bool premature);
-CURLcode Curl_http_connect(struct connectdata *conn, bool *done);
+CURLcode Curl_http(struct Curl_easy *data, bool *done);
+CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature);
+CURLcode Curl_http_connect(struct Curl_easy *data, bool *done);
 
 /* These functions are in http.c */
-CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
+CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy,
                               const char *auth);
-CURLcode Curl_http_auth_act(struct connectdata *conn);
+CURLcode Curl_http_auth_act(struct Curl_easy *data);
 
 /* If only the PICKNONE bit is set, there has been a round-trip and we
    selected to use no auth at all. Ie, we actively select no auth, as opposed
@@ -115,7 +170,6 @@ struct HTTP {
   const char *postdata;
 
   const char *p_pragma;      /* Pragma: string */
-  const char *p_accept;      /* Accept: string */
 
   /* For FORM posting */
   curl_mimepart form;
@@ -234,11 +288,13 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
 /**
  * Curl_http_output_auth() setups the authentication headers for the
  * host/proxy and the correct authentication
- * method. conn->data->state.authdone is set to TRUE when authentication is
+ * method. data->state.authdone is set to TRUE when authentication is
  * done.
  *
+ * @param data all information about the current transfer
  * @param conn all information about the current connection
  * @param request pointer to the request keyword
+ * @param httpreq is the request type
  * @param path pointer to the requested path
  * @param proxytunnel boolean if this is the request setting up a "proxy
  * tunnel"
@@ -246,8 +302,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
  * @returns CURLcode
  */
 CURLcode
-Curl_http_output_auth(struct connectdata *conn,
+Curl_http_output_auth(struct Curl_easy *data,
+                      struct connectdata *conn,
                       const char *request,
+                      Curl_HttpReq httpreq,
                       const char *path,
                       bool proxytunnel); /* TRUE if this is the request setting
                                             up the proxy tunnel */

+ 110 - 107
lib/http2.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -65,12 +65,13 @@
 #endif
 
 
-static ssize_t http2_recv(struct connectdata *conn, int sockindex,
+static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
                           char *mem, size_t len, CURLcode *err);
-static bool http2_connisdead(struct connectdata *conn);
+static bool http2_connisdead(struct Curl_easy *data,
+                             struct connectdata *conn);
 static int h2_session_send(struct Curl_easy *data,
                            nghttp2_session *h2);
-static int h2_process_pending_input(struct connectdata *conn,
+static int h2_process_pending_input(struct Curl_easy *data,
                                     struct http_conn *httpc,
                                     CURLcode *err);
 
@@ -92,18 +93,20 @@ void Curl_http2_init_userset(struct UserDefined *set)
   set->stream_weight = NGHTTP2_DEFAULT_WEIGHT;
 }
 
-static int http2_perform_getsock(const struct connectdata *conn,
-                                 curl_socket_t *sock)
+static int http2_getsock(struct Curl_easy *data,
+                         struct connectdata *conn,
+                         curl_socket_t *sock)
 {
   const struct http_conn *c = &conn->proto.httpc;
-  struct SingleRequest *k = &conn->data->req;
+  struct SingleRequest *k = &data->req;
   int bitmap = GETSOCK_BLANK;
 
   sock[0] = conn->sock[FIRSTSOCKET];
 
-  /* in a HTTP/2 connection we can basically always get a frame so we should
-     always be ready for one */
-  bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+  if(!(k->keepon & KEEP_RECV_PAUSE))
+    /* Unless paused - in a HTTP/2 connection we can basically always get a
+       frame so we should always be ready for one */
+    bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
 
   /* we're still uploading or the HTTP/2 layer wants to send data */
   if(((k->keepon & (KEEP_SEND|KEEP_SEND_PAUSE)) == KEEP_SEND) ||
@@ -113,12 +116,6 @@ static int http2_perform_getsock(const struct connectdata *conn,
   return bitmap;
 }
 
-static int http2_getsock(struct connectdata *conn,
-                         curl_socket_t *socks)
-{
-  return http2_perform_getsock(conn, socks);
-}
-
 /*
  * http2_stream_free() free HTTP2 stream related data
  */
@@ -139,18 +136,22 @@ static void http2_stream_free(struct HTTP *http)
  * connection cache and not the "main" one. Don't touch the easy handle!
  */
 
-static CURLcode http2_disconnect(struct connectdata *conn,
+static CURLcode http2_disconnect(struct Curl_easy *data,
+                                 struct connectdata *conn,
                                  bool dead_connection)
 {
   struct http_conn *c = &conn->proto.httpc;
   (void)dead_connection;
+#ifndef DEBUG_HTTP2
+  (void)data;
+#endif
 
-  H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT starts now\n"));
+  H2BUGF(infof(data, "HTTP/2 DISCONNECT starts now\n"));
 
   nghttp2_session_del(c->h2);
   Curl_safefree(c->inbuf);
 
-  H2BUGF(infof(conn->data, "HTTP/2 DISCONNECT done\n"));
+  H2BUGF(infof(data, "HTTP/2 DISCONNECT done\n"));
 
   return CURLE_OK;
 }
@@ -162,7 +163,7 @@ static CURLcode http2_disconnect(struct connectdata *conn,
  * Instead, if it is readable, run Curl_connalive() to peek at the socket
  * and distinguish between closed and data.
  */
-static bool http2_connisdead(struct connectdata *conn)
+static bool http2_connisdead(struct Curl_easy *data, struct connectdata *conn)
 {
   int sval;
   bool dead = TRUE;
@@ -192,14 +193,14 @@ static bool http2_connisdead(struct connectdata *conn)
       if(httpc->recv_underlying)
         /* if called "too early", this pointer isn't setup yet! */
         nread = ((Curl_recv *)httpc->recv_underlying)(
-          conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
+          data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, &result);
       if(nread != -1) {
-        infof(conn->data,
+        infof(data,
               "%d bytes stray data read before trying h2 connection\n",
               (int)nread);
         httpc->nread_inbuf = 0;
         httpc->inbuflen = nread;
-        (void)h2_process_pending_input(conn, httpc, &result);
+        (void)h2_process_pending_input(data, httpc, &result);
       }
       else
         /* the read failed so let's say this is dead anyway */
@@ -210,24 +211,25 @@ static bool http2_connisdead(struct connectdata *conn)
   return dead;
 }
 
-static unsigned int http2_conncheck(struct connectdata *check,
+static unsigned int http2_conncheck(struct Curl_easy *data,
+                                    struct connectdata *conn,
                                     unsigned int checks_to_perform)
 {
   unsigned int ret_val = CONNRESULT_NONE;
-  struct http_conn *c = &check->proto.httpc;
+  struct http_conn *c = &conn->proto.httpc;
   int rc;
   bool send_frames = false;
 
   if(checks_to_perform & CONNCHECK_ISDEAD) {
-    if(http2_connisdead(check))
+    if(http2_connisdead(data, conn))
       ret_val |= CONNRESULT_DEAD;
   }
 
   if(checks_to_perform & CONNCHECK_KEEPALIVE) {
     struct curltime now = Curl_now();
-    timediff_t elapsed = Curl_timediff(now, check->keepalive);
+    timediff_t elapsed = Curl_timediff(now, conn->keepalive);
 
-    if(elapsed > check->upkeep_interval_ms) {
+    if(elapsed > data->set.upkeep_interval_ms) {
       /* Perform an HTTP/2 PING */
       rc = nghttp2_submit_ping(c->h2, 0, ZERO_NULL);
       if(!rc) {
@@ -236,18 +238,18 @@ static unsigned int http2_conncheck(struct connectdata *check,
         send_frames = true;
       }
       else {
-       failf(check->data, "nghttp2_submit_ping() failed: %s(%d)",
+       failf(data, "nghttp2_submit_ping() failed: %s(%d)",
              nghttp2_strerror(rc), rc);
       }
 
-      check->keepalive = now;
+      conn->keepalive = now;
     }
   }
 
   if(send_frames) {
     rc = nghttp2_session_send(c->h2);
     if(rc)
-      failf(check->data, "nghttp2_session_send() failed: %s(%d)",
+      failf(data, "nghttp2_session_send() failed: %s(%d)",
             nghttp2_strerror(rc), rc);
   }
 
@@ -294,7 +296,7 @@ static const struct Curl_handler Curl_handler_http2 = {
   http2_getsock,                        /* proto_getsock */
   http2_getsock,                        /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  http2_perform_getsock,                /* perform_getsock */
+  http2_getsock,                        /* perform_getsock */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   http2_conncheck,                      /* connection_check */
@@ -316,7 +318,7 @@ static const struct Curl_handler Curl_handler_http2_ssl = {
   http2_getsock,                        /* proto_getsock */
   http2_getsock,                        /* doing_getsock */
   ZERO_NULL,                            /* domore_getsock */
-  http2_perform_getsock,                /* perform_getsock */
+  http2_getsock,                        /* perform_getsock */
   http2_disconnect,                     /* disconnect */
   ZERO_NULL,                            /* readwrite */
   http2_conncheck,                      /* connection_check */
@@ -342,7 +344,7 @@ int Curl_http2_ver(char *p, size_t len)
  * written. See the documentation of nghttp2_send_callback for the details.
  */
 static ssize_t send_callback(nghttp2_session *h2,
-                             const uint8_t *data, size_t length, int flags,
+                             const uint8_t *mem, size_t length, int flags,
                              void *userp)
 {
   struct connectdata *conn = (struct connectdata *)userp;
@@ -357,8 +359,8 @@ static ssize_t send_callback(nghttp2_session *h2,
     /* called before setup properly! */
     return NGHTTP2_ERR_CALLBACK_FAILURE;
 
-  written = ((Curl_send*)c->send_underlying)(conn, FIRSTSOCKET,
-                                             data, length, &result);
+  written = ((Curl_send*)c->send_underlying)(conn->data, FIRSTSOCKET,
+                                             mem, length, &result);
 
   if(result == CURLE_AGAIN) {
     return NGHTTP2_ERR_WOULDBLOCK;
@@ -541,7 +543,7 @@ static int push_promise(struct Curl_easy *data,
 
     stream = data->req.p.http;
     if(!stream) {
-      failf(data, "Internal NULL stream!\n");
+      failf(data, "Internal NULL stream!");
       (void)Curl_close(&newhandle);
       rv = CURL_PUSH_DENY;
       goto fail;
@@ -956,7 +958,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! 5\n");
+    failf(data_s, "Internal NULL stream!");
     return NGHTTP2_ERR_CALLBACK_FAILURE;
   }
 
@@ -1214,7 +1216,7 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
 /*
  * Initialize nghttp2 for a Curl connection
  */
-static CURLcode http2_init(struct connectdata *conn)
+static CURLcode http2_init(struct Curl_easy *data, struct connectdata *conn)
 {
   if(!conn->proto.httpc.h2) {
     int rc;
@@ -1227,7 +1229,7 @@ static CURLcode http2_init(struct connectdata *conn)
     rc = nghttp2_session_callbacks_new(&callbacks);
 
     if(rc) {
-      failf(conn->data, "Couldn't initialize nghttp2 callbacks!");
+      failf(data, "Couldn't initialize nghttp2 callbacks!");
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
 
@@ -1256,7 +1258,7 @@ static CURLcode http2_init(struct connectdata *conn)
     nghttp2_session_callbacks_del(callbacks);
 
     if(rc) {
-      failf(conn->data, "Couldn't initialize nghttp2!");
+      failf(data, "Couldn't initialize nghttp2!");
       return CURLE_OUT_OF_MEMORY; /* most likely at least */
     }
   }
@@ -1273,7 +1275,8 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
   ssize_t binlen;
   char *base64;
   size_t blen;
-  struct SingleRequest *k = &conn->data->req;
+  struct Curl_easy *data = conn->data;
+  struct SingleRequest *k = &data->req;
   uint8_t *binsettings = conn->proto.httpc.binsettings;
   struct http_conn *httpc = &conn->proto.httpc;
 
@@ -1284,13 +1287,13 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
                                          httpc->local_settings,
                                          httpc->local_settings_num);
   if(binlen <= 0) {
-    failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
+    failf(data, "nghttp2 unexpectedly failed on pack_settings_payload");
     Curl_dyn_free(req);
     return CURLE_FAILED_INIT;
   }
   conn->proto.httpc.binlen = binlen;
 
-  result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
+  result = Curl_base64url_encode(data, (const char *)binsettings, binlen,
                                  &base64, &blen);
   if(result) {
     Curl_dyn_free(req);
@@ -1324,14 +1327,13 @@ static int should_close_session(struct http_conn *httpc)
  * This function returns 0 if it succeeds, or -1 and error code will
  * be assigned to *err.
  */
-static int h2_process_pending_input(struct connectdata *conn,
+static int h2_process_pending_input(struct Curl_easy *data,
                                     struct http_conn *httpc,
                                     CURLcode *err)
 {
   ssize_t nread;
   char *inbuf;
   ssize_t rv;
-  struct Curl_easy *data = conn->data;
 
   nread = httpc->inbuflen - httpc->nread_inbuf;
   inbuf = httpc->inbuf + httpc->nread_inbuf;
@@ -1340,7 +1342,7 @@ static int h2_process_pending_input(struct connectdata *conn,
   if(rv < 0) {
     failf(data,
           "h2_process_pending_input: nghttp2_session_mem_recv() returned "
-          "%zd:%s\n", rv, nghttp2_strerror((int)rv));
+          "%zd:%s", rv, nghttp2_strerror((int)rv));
     *err = CURLE_RECV_ERROR;
     return -1;
   }
@@ -1371,7 +1373,7 @@ static int h2_process_pending_input(struct connectdata *conn,
        the connection may not be reused. This is set when a
        GOAWAY frame has been received or when the limit of stream
        identifiers has been reached. */
-    connclose(conn, "http/2: No new requests allowed");
+    connclose(data->conn, "http/2: No new requests allowed");
   }
 
   if(should_close_session(httpc)) {
@@ -1381,7 +1383,7 @@ static int h2_process_pending_input(struct connectdata *conn,
       *err = CURLE_HTTP2;
     else {
       /* not an error per se, but should still close the connection */
-      connclose(conn, "GOAWAY received");
+      connclose(data->conn, "GOAWAY received");
       *err = CURLE_OK;
     }
     return -1;
@@ -1392,7 +1394,8 @@ static int h2_process_pending_input(struct connectdata *conn,
 /*
  * Called from transfer.c:done_sending when we stop uploading.
  */
-CURLcode Curl_http2_done_sending(struct connectdata *conn)
+CURLcode Curl_http2_done_sending(struct Curl_easy *data,
+                                 struct connectdata *conn)
 {
   CURLcode result = CURLE_OK;
 
@@ -1400,7 +1403,7 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
      (conn->handler == &Curl_handler_http2)) {
     /* make sure this is only attempted for HTTP/2 transfers */
 
-    struct HTTP *stream = conn->data->req.p.http;
+    struct HTTP *stream = data->req.p.http;
 
     struct http_conn *httpc = &conn->proto.httpc;
     nghttp2_session *h2 = httpc->h2;
@@ -1413,13 +1416,11 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
       /* resume sending here to trigger the callback to get called again so
          that it can signal EOF to nghttp2 */
       (void)nghttp2_session_resume_data(h2, stream->stream_id);
-
-      (void)h2_process_pending_input(conn, httpc, &result);
+      (void)h2_process_pending_input(data, httpc, &result);
     }
 
     /* If nghttp2 still has pending frames unsent */
     if(nghttp2_session_want_write(h2)) {
-      struct Curl_easy *data = conn->data;
       struct SingleRequest *k = &data->req;
       int rv;
 
@@ -1450,7 +1451,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
   drained_transfer(data, httpc);
 
   if(httpc->pause_stream_id == 0) {
-    if(h2_process_pending_input(conn, httpc, err) != 0) {
+    if(h2_process_pending_input(data, httpc, err) != 0) {
       return -1;
     }
   }
@@ -1498,7 +1499,7 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
 
       Curl_debug(data, CURLINFO_HEADER_IN, trailp, len);
       /* pass the trailers one by one to the callback */
-      result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailp, len);
+      result = Curl_client_write(data, CLIENTWRITE_HEADER, trailp, len);
       if(result) {
         *err = result;
         return -1;
@@ -1562,12 +1563,12 @@ static int h2_session_send(struct Curl_easy *data,
   return nghttp2_session_send(h2);
 }
 
-static ssize_t http2_recv(struct connectdata *conn, int sockindex,
+static ssize_t http2_recv(struct Curl_easy *data, int sockindex,
                           char *mem, size_t len, CURLcode *err)
 {
   ssize_t nread;
+  struct connectdata *conn = data->conn;
   struct http_conn *httpc = &conn->proto.httpc;
-  struct Curl_easy *data = conn->data;
   struct HTTP *stream = data->req.p.http;
 
   (void)sockindex; /* we always do HTTP2 on sockindex 0 */
@@ -1631,7 +1632,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
       /* We have paused nghttp2, but we have no pause data (see
          on_data_chunk_recv). */
       httpc->pause_stream_id = 0;
-      if(h2_process_pending_input(conn, httpc, err) != 0) {
+      if(h2_process_pending_input(data, httpc, err) != 0) {
         return -1;
       }
     }
@@ -1659,7 +1660,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
          frames, then we have to call it again with 0-length data.
          Without this, on_stream_close callback will not be called,
          and stream could be hanged. */
-      if(h2_process_pending_input(conn, httpc, err) != 0) {
+      if(h2_process_pending_input(data, httpc, err) != 0) {
         return -1;
       }
     }
@@ -1693,7 +1694,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
 
     if(httpc->inbuflen == 0) {
       nread = ((Curl_recv *)httpc->recv_underlying)(
-          conn, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, err);
+        data, FIRSTSOCKET, httpc->inbuf, H2_BUFSIZE, err);
 
       if(nread == -1) {
         if(*err != CURLE_AGAIN)
@@ -1724,7 +1725,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
                    nread));
     }
 
-    if(h2_process_pending_input(conn, httpc, err) != 0)
+    if(h2_process_pending_input(data, httpc, err) != 0)
       return -1;
   }
   if(stream->memlen) {
@@ -1830,7 +1831,7 @@ static header_instruction inspect_header(const char *name, size_t namelen,
   }
 }
 
-static ssize_t http2_send(struct connectdata *conn, int sockindex,
+static ssize_t http2_send(struct Curl_easy *data, int sockindex,
                           const void *mem, size_t len, CURLcode *err)
 {
   /*
@@ -1839,8 +1840,9 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
    * request.
    */
   int rv;
+  struct connectdata *conn = data->conn;
   struct http_conn *httpc = &conn->proto.httpc;
-  struct HTTP *stream = conn->data->req.p.http;
+  struct HTTP *stream = data->req.p.http;
   nghttp2_nv *nva = NULL;
   size_t nheader;
   size_t i;
@@ -1854,16 +1856,16 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
 
   (void)sockindex;
 
-  H2BUGF(infof(conn->data, "http2_send len=%zu\n", len));
+  H2BUGF(infof(data, "http2_send len=%zu\n", len));
 
   if(stream->stream_id != -1) {
     if(stream->close_handled) {
-      infof(conn->data, "stream %d closed\n", stream->stream_id);
+      infof(data, "stream %d closed\n", stream->stream_id);
       *err = CURLE_HTTP2_STREAM;
       return -1;
     }
     else if(stream->closed) {
-      return http2_handle_stream_close(conn, conn->data, stream, err);
+      return http2_handle_stream_close(conn, data, stream, err);
     }
     /* If stream_id != -1, we have dispatched request HEADERS, and now
        are going to send or sending request body in DATA frame */
@@ -1874,7 +1876,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
       *err = CURLE_SEND_ERROR;
       return -1;
     }
-    rv = h2_session_send(conn->data, h2);
+    rv = h2_session_send(data, h2);
     if(nghttp2_is_fatal(rv)) {
       *err = CURLE_SEND_ERROR;
       return -1;
@@ -1887,7 +1889,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     stream->upload_len = 0;
 
     if(should_close_session(httpc)) {
-      H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
+      H2BUGF(infof(data, "http2_send: nothing to do in this session\n"));
       *err = CURLE_HTTP2;
       return -1;
     }
@@ -1900,7 +1902,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
       nghttp2_session_resume_data(h2, stream->stream_id);
     }
 
-    H2BUGF(infof(conn->data, "http2_send returns %zu for stream %u\n", len,
+    H2BUGF(infof(data, "http2_send returns %zu for stream %u\n", len,
                  stream->stream_id));
     return len;
   }
@@ -1944,7 +1946,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   nva[0].valuelen = (size_t)(end - hdbuf);
   nva[0].flags = NGHTTP2_NV_FLAG_NONE;
   if(HEADER_OVERFLOW(nva[0])) {
-    failf(conn->data, "Failed sending HTTP request: Header overflow");
+    failf(data, "Failed sending HTTP request: Header overflow");
     goto fail;
   }
 
@@ -1966,7 +1968,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   nva[1].valuelen = (size_t)(end - hdbuf);
   nva[1].flags = NGHTTP2_NV_FLAG_NONE;
   if(HEADER_OVERFLOW(nva[1])) {
-    failf(conn->data, "Failed sending HTTP request: Header overflow");
+    failf(data, "Failed sending HTTP request: Header overflow");
     goto fail;
   }
 
@@ -1979,7 +1981,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   nva[2].valuelen = strlen((char *)nva[2].value);
   nva[2].flags = NGHTTP2_NV_FLAG_NONE;
   if(HEADER_OVERFLOW(nva[2])) {
-    failf(conn->data, "Failed sending HTTP request: Header overflow");
+    failf(data, "Failed sending HTTP request: Header overflow");
     goto fail;
   }
 
@@ -2039,7 +2041,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
 
     nva[i].flags = NGHTTP2_NV_FLAG_NONE;
     if(HEADER_OVERFLOW(nva[i])) {
-      failf(conn->data, "Failed sending HTTP request: Header overflow");
+      failf(data, "Failed sending HTTP request: Header overflow");
       goto fail;
     }
     ++i;
@@ -2063,30 +2065,30 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     for(i = 0; i < nheader; ++i) {
       acc += nva[i].namelen + nva[i].valuelen;
 
-      H2BUGF(infof(conn->data, "h2 header: %.*s:%.*s\n",
+      H2BUGF(infof(data, "h2 header: %.*s:%.*s\n",
                    nva[i].namelen, nva[i].name,
                    nva[i].valuelen, nva[i].value));
     }
 
     if(acc > MAX_ACC) {
-      infof(conn->data, "http2_send: Warning: The cumulative length of all "
+      infof(data, "http2_send: Warning: The cumulative length of all "
             "headers exceeds %d bytes and that could cause the "
             "stream to be rejected.\n", MAX_ACC);
     }
   }
 
-  h2_pri_spec(conn->data, &pri_spec);
+  h2_pri_spec(data, &pri_spec);
 
-  H2BUGF(infof(conn->data, "http2_send request allowed %d (easy handle %p)\n",
-         nghttp2_session_check_request_allowed(h2), (void *)conn->data));
+  H2BUGF(infof(data, "http2_send request allowed %d (easy handle %p)\n",
+               nghttp2_session_check_request_allowed(h2), (void *)data));
 
-  switch(conn->data->state.httpreq) {
+  switch(data->state.httpreq) {
   case HTTPREQ_POST:
   case HTTPREQ_POST_FORM:
   case HTTPREQ_POST_MIME:
   case HTTPREQ_PUT:
-    if(conn->data->state.infilesize != -1)
-      stream->upload_left = conn->data->state.infilesize;
+    if(data->state.infilesize != -1)
+      stream->upload_left = data->state.infilesize;
     else
       /* data sending without specifying the data amount up front */
       stream->upload_left = -1; /* unknown, but not zero */
@@ -2094,32 +2096,32 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
     data_prd.read_callback = data_source_read_callback;
     data_prd.source.ptr = NULL;
     stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
-                                       &data_prd, conn->data);
+                                       &data_prd, data);
     break;
   default:
     stream_id = nghttp2_submit_request(h2, &pri_spec, nva, nheader,
-                                       NULL, conn->data);
+                                       NULL, data);
   }
 
   Curl_safefree(nva);
 
   if(stream_id < 0) {
-    H2BUGF(infof(conn->data,
+    H2BUGF(infof(data,
                  "http2_send() nghttp2_submit_request error (%s)%d\n",
                  nghttp2_strerror(stream_id), stream_id));
     *err = CURLE_SEND_ERROR;
     return -1;
   }
 
-  infof(conn->data, "Using Stream ID: %x (easy handle %p)\n",
-        stream_id, (void *)conn->data);
+  infof(data, "Using Stream ID: %x (easy handle %p)\n",
+        stream_id, (void *)data);
   stream->stream_id = stream_id;
 
   /* this does not call h2_session_send() since there can not have been any
    * priority update since the nghttp2_submit_request() call above */
   rv = nghttp2_session_send(h2);
   if(rv != 0) {
-    H2BUGF(infof(conn->data,
+    H2BUGF(infof(data,
                  "http2_send() nghttp2_session_send error (%s)%d\n",
                  nghttp2_strerror(rv), rv));
 
@@ -2128,7 +2130,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
   }
 
   if(should_close_session(httpc)) {
-    H2BUGF(infof(conn->data, "http2_send: nothing to do in this session\n"));
+    H2BUGF(infof(data, "http2_send: nothing to do in this session\n"));
     *err = CURLE_HTTP2;
     return -1;
   }
@@ -2150,13 +2152,14 @@ fail:
   return -1;
 }
 
-CURLcode Curl_http2_setup(struct connectdata *conn)
+CURLcode Curl_http2_setup(struct Curl_easy *data,
+                          struct connectdata *conn)
 {
   CURLcode result;
   struct http_conn *httpc = &conn->proto.httpc;
-  struct HTTP *stream = conn->data->req.p.http;
+  struct HTTP *stream = data->req.p.http;
 
-  DEBUGASSERT(conn->data->state.buffer);
+  DEBUGASSERT(data->state.buffer);
 
   stream->stream_id = -1;
 
@@ -2172,18 +2175,18 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
   else
     conn->handler = &Curl_handler_http2;
 
-  result = http2_init(conn);
+  result = http2_init(data, conn);
   if(result) {
     Curl_dyn_free(&stream->header_recvbuf);
     return result;
   }
 
-  infof(conn->data, "Using HTTP2, server supports multi-use\n");
+  infof(data, "Using HTTP2, server supports multi-use\n");
   stream->upload_left = 0;
   stream->upload_mem = NULL;
   stream->upload_len = 0;
-  stream->mem = conn->data->state.buffer;
-  stream->len = conn->data->set.buffer_size;
+  stream->mem = data->state.buffer;
+  stream->len = data->set.buffer_size;
 
   httpc->inbuflen = 0;
   httpc->nread_inbuf = 0;
@@ -2195,22 +2198,22 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
   conn->httpversion = 20;
   conn->bundle->multiuse = BUNDLE_MULTIPLEX;
 
-  infof(conn->data, "Connection state changed (HTTP/2 confirmed)\n");
-  multi_connchanged(conn->data->multi);
+  infof(data, "Connection state changed (HTTP/2 confirmed)\n");
+  multi_connchanged(data->multi);
 
   return CURLE_OK;
 }
 
-CURLcode Curl_http2_switched(struct connectdata *conn,
+CURLcode Curl_http2_switched(struct Curl_easy *data,
                              const char *mem, size_t nread)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   struct http_conn *httpc = &conn->proto.httpc;
   int rv;
-  struct Curl_easy *data = conn->data;
-  struct HTTP *stream = conn->data->req.p.http;
+  struct HTTP *stream = data->req.p.http;
 
-  result = Curl_http2_setup(conn);
+  result = Curl_http2_setup(data, conn);
   if(result)
     return result;
 
@@ -2219,7 +2222,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
   conn->recv[FIRSTSOCKET] = http2_recv;
   conn->send[FIRSTSOCKET] = http2_send;
 
-  if(conn->data->req.upgr101 == UPGR101_RECEIVED) {
+  if(data->req.upgr101 == UPGR101_RECEIVED) {
     /* stream 1 is opened implicitly on upgrade */
     stream->stream_id = 1;
     /* queue SETTINGS frame (again) */
@@ -2269,13 +2272,13 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
      data into stream->mem, overwriting data already there. */
   if(H2_BUFSIZE < nread) {
     failf(data, "connection buffer size is too small to store data following "
-                "HTTP Upgrade response header: buflen=%d, datalen=%zu",
+          "HTTP Upgrade response header: buflen=%d, datalen=%zu",
           H2_BUFSIZE, nread);
     return CURLE_HTTP2;
   }
 
-  infof(conn->data, "Copying HTTP/2 data in stream buffer to connection buffer"
-                    " after upgrade: len=%zu\n",
+  infof(data, "Copying HTTP/2 data in stream buffer to connection buffer"
+        " after upgrade: len=%zu\n",
         nread);
 
   if(nread)
@@ -2285,7 +2288,7 @@ CURLcode Curl_http2_switched(struct connectdata *conn,
 
   DEBUGASSERT(httpc->nread_inbuf == 0);
 
-  if(-1 == h2_process_pending_input(conn, httpc, &result))
+  if(-1 == h2_process_pending_input(data, httpc, &result))
     return CURLE_HTTP2;
 
   return CURLE_OK;

+ 8 - 7
lib/http2.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -44,14 +44,15 @@ void Curl_http2_init_state(struct UrlState *state);
 void Curl_http2_init_userset(struct UserDefined *set);
 CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
                                     struct connectdata *conn);
-CURLcode Curl_http2_setup(struct connectdata *conn);
-CURLcode Curl_http2_switched(struct connectdata *conn,
-                             const char *data, size_t nread);
+CURLcode Curl_http2_setup(struct Curl_easy *data, struct connectdata *conn);
+CURLcode Curl_http2_switched(struct Curl_easy *data,
+                             const char *ptr, size_t nread);
 /* called from http_setup_conn */
 void Curl_http2_setup_conn(struct connectdata *conn);
 void Curl_http2_setup_req(struct Curl_easy *data);
 void Curl_http2_done(struct Curl_easy *data, bool premature);
-CURLcode Curl_http2_done_sending(struct connectdata *conn);
+CURLcode Curl_http2_done_sending(struct Curl_easy *data,
+                                 struct connectdata *conn);
 CURLcode Curl_http2_add_child(struct Curl_easy *parent,
                               struct Curl_easy *child,
                               bool exclusive);
@@ -64,14 +65,14 @@ CURLcode Curl_http2_stream_pause(struct Curl_easy *data, bool pause);
 bool Curl_h2_http_1_1_error(struct connectdata *conn);
 #else /* USE_NGHTTP2 */
 #define Curl_http2_request_upgrade(x,y) CURLE_UNSUPPORTED_PROTOCOL
-#define Curl_http2_setup(x) CURLE_UNSUPPORTED_PROTOCOL
+#define Curl_http2_setup(x,y) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_switched(x,y,z) CURLE_UNSUPPORTED_PROTOCOL
 #define Curl_http2_setup_conn(x) Curl_nop_stmt
 #define Curl_http2_setup_req(x)
 #define Curl_http2_init_state(x)
 #define Curl_http2_init_userset(x)
 #define Curl_http2_done(x,y)
-#define Curl_http2_done_sending(x)
+#define Curl_http2_done_sending(x,y)
 #define Curl_http2_add_child(x, y, z)
 #define Curl_http2_remove_child(x, y)
 #define Curl_http2_cleanup_dependencies(x)

+ 394 - 0
lib/http_aws_sigv4.c

@@ -0,0 +1,394 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  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.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include "urldata.h"
+#include "strcase.h"
+#include "strdup.h"
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "http_aws_sigv4.h"
+#include "curl_sha256.h"
+#include "transfer.h"
+
+#include "strcase.h"
+#include "parsedate.h"
+#include "sendf.h"
+
+#include <time.h>
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define HMAC_SHA256(k, kl, d, dl, o)        \
+  do {                                      \
+    ret = Curl_hmacit(Curl_HMAC_SHA256,     \
+                      (unsigned char *)k,   \
+                      (unsigned int)kl,     \
+                      (unsigned char *)d,   \
+                      (unsigned int)dl, o); \
+    if(ret != CURLE_OK) {                   \
+      goto fail;                            \
+    }                                       \
+  } while(0)
+
+static void sha256_to_hex(char *dst, unsigned char *sha, size_t dst_l)
+{
+  int i;
+
+  DEBUGASSERT(dst_l >= 65);
+  for(i = 0; i < 32; ++i) {
+    curl_msnprintf(dst + (i * 2), dst_l - (i * 2), "%02x", sha[i]);
+  }
+}
+
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy)
+{
+  CURLcode ret = CURLE_OUT_OF_MEMORY;
+  struct connectdata *conn = data->conn;
+  size_t len;
+  const char *tmp0;
+  const char *tmp1;
+  char *provider0_low = NULL;
+  char *provider0_up = NULL;
+  char *provider1_low = NULL;
+  char *provider1_mid = NULL;
+  char *region = NULL;
+  char *service = NULL;
+  const char *hostname = conn->host.name;
+#ifdef DEBUGBUILD
+  char *force_timestamp;
+#endif
+  time_t clock;
+  struct tm tm;
+  char timestamp[17];
+  char date[9];
+  const char *content_type = Curl_checkheaders(data, "Content-Type");
+  char *canonical_headers = NULL;
+  char *signed_headers = NULL;
+  Curl_HttpReq httpreq;
+  const char *method;
+  const char *post_data = data->set.postfields ? data->set.postfields : "";
+  unsigned char sha_hash[32];
+  char sha_hex[65];
+  char *canonical_request = NULL;
+  char *request_type = NULL;
+  char *credential_scope = NULL;
+  char *str_to_sign = NULL;
+  const char *user = conn->user ? conn->user : "";
+  const char *passwd = conn->passwd ? conn->passwd : "";
+  char *secret = NULL;
+  unsigned char tmp_sign0[32] = {0};
+  unsigned char tmp_sign1[32] = {0};
+  char *auth_headers = NULL;
+
+  DEBUGASSERT(!proxy);
+  (void)proxy;
+
+  if(Curl_checkheaders(data, "Authorization")) {
+    /* Authorization already present, Bailing out */
+    return CURLE_OK;
+  }
+
+  /*
+   * Parameters parsing
+   * Google and Outscale use the same OSC or GOOG,
+   * but Amazon uses AWS and AMZ for header arguments.
+   * AWS is the default because most of non-amazon providers
+   * are still using aws:amz as a prefix.
+   */
+  tmp0 = data->set.str[STRING_AWS_SIGV4] ?
+    data->set.str[STRING_AWS_SIGV4] : "aws:amz";
+  tmp1 = strchr(tmp0, ':');
+  len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
+  if(len < 1) {
+    infof(data, "first provider can't be empty\n");
+    ret = CURLE_BAD_FUNCTION_ARGUMENT;
+    goto fail;
+  }
+  provider0_low = malloc(len + 1);
+  provider0_up = malloc(len + 1);
+  if(!provider0_low || !provider0_up) {
+    goto fail;
+  }
+  Curl_strntolower(provider0_low, tmp0, len);
+  provider0_low[len] = '\0';
+  Curl_strntoupper(provider0_up, tmp0, len);
+  provider0_up[len] = '\0';
+
+  if(tmp1) {
+    tmp0 = tmp1 + 1;
+    tmp1 = strchr(tmp0, ':');
+    len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
+    if(len < 1) {
+      infof(data, "second provider can't be empty\n");
+      ret = CURLE_BAD_FUNCTION_ARGUMENT;
+      goto fail;
+    }
+    provider1_low = malloc(len + 1);
+    provider1_mid = malloc(len + 1);
+    if(!provider1_low || !provider1_mid) {
+      goto fail;
+    }
+    Curl_strntolower(provider1_low, tmp0, len);
+    provider1_low[len] = '\0';
+    Curl_strntolower(provider1_mid, tmp0, len);
+    provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]);
+    provider1_mid[len] = '\0';
+
+    if(tmp1) {
+      tmp0 = tmp1 + 1;
+      tmp1 = strchr(tmp0, ':');
+      len = tmp1 ? (size_t)(tmp1 - tmp0) : strlen(tmp0);
+      if(len < 1) {
+        infof(data, "region can't be empty\n");
+        ret = CURLE_BAD_FUNCTION_ARGUMENT;
+        goto fail;
+      }
+      region = Curl_memdup(tmp0, len + 1);
+      if(!region) {
+        goto fail;
+      }
+      region[len] = '\0';
+
+      if(tmp1) {
+        tmp0 = tmp1 + 1;
+        service = strdup(tmp0);
+        if(!service) {
+          goto fail;
+        }
+        if(strlen(service) < 1) {
+          infof(data, "service can't be empty\n");
+          ret = CURLE_BAD_FUNCTION_ARGUMENT;
+          goto fail;
+        }
+      }
+    }
+  }
+  else {
+    provider1_low = Curl_memdup(provider0_low, len + 1);
+    provider1_mid = Curl_memdup(provider0_low, len + 1);
+    if(!provider1_low || !provider1_mid) {
+      goto fail;
+    }
+    provider1_mid[0] = Curl_raw_toupper(provider1_mid[0]);
+  }
+
+  if(!service) {
+    tmp0 = hostname;
+    tmp1 = strchr(tmp0, '.');
+    len = tmp1 - tmp0;
+    if(!tmp1 || len < 1) {
+      infof(data, "service missing in parameters or hostname\n");
+      ret = CURLE_URL_MALFORMAT;
+      goto fail;
+    }
+    service = Curl_memdup(tmp0, len + 1);
+    if(!service) {
+      goto fail;
+    }
+    service[len] = '\0';
+
+    if(!region) {
+      tmp0 = tmp1 + 1;
+      tmp1 = strchr(tmp0, '.');
+      len = tmp1 - tmp0;
+      if(!tmp1 || len < 1) {
+        infof(data, "region missing in parameters or hostname\n");
+        ret = CURLE_URL_MALFORMAT;
+        goto fail;
+      }
+      region = Curl_memdup(tmp0, len + 1);
+      if(!region) {
+        goto fail;
+      }
+      region[len] = '\0';
+    }
+  }
+
+#ifdef DEBUGBUILD
+  force_timestamp = getenv("CURL_FORCETIME");
+  if(force_timestamp)
+    clock = 0;
+  else
+    time(&clock);
+#else
+  time(&clock);
+#endif
+  ret = Curl_gmtime(clock, &tm);
+  if(ret != CURLE_OK) {
+    goto fail;
+  }
+  if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
+    goto fail;
+  }
+  memcpy(date, timestamp, sizeof(date));
+  date[sizeof(date) - 1] = 0;
+
+  if(content_type) {
+    content_type = strchr(content_type, ':');
+    if(!content_type) {
+      ret = CURLE_FAILED_INIT;
+      goto fail;
+    }
+    content_type++;
+    /* Skip whitespace now */
+    while(*content_type == ' ' || *content_type == '\t')
+      ++content_type;
+
+    canonical_headers = curl_maprintf("content-type:%s\n"
+                                      "host:%s\n"
+                                      "x-%s-date:%s\n",
+                                      content_type,
+                                      hostname,
+                                      provider1_low, timestamp);
+    signed_headers = curl_maprintf("content-type;host;x-%s-date",
+                                   provider1_low);
+  }
+  else {
+    canonical_headers = curl_maprintf("host:%s\n"
+                                      "x-%s-date:%s\n",
+                                      hostname,
+                                      provider1_low, timestamp);
+    signed_headers = curl_maprintf("host;x-%s-date", provider1_low);
+  }
+
+  if(!canonical_headers || !signed_headers) {
+    goto fail;
+  }
+
+  Curl_sha256it(sha_hash,
+                (const unsigned char *) post_data, strlen(post_data));
+  sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+
+  Curl_http_method(data, conn, &method, &httpreq);
+
+  canonical_request =
+    curl_maprintf("%s\n" /* HTTPRequestMethod */
+                  "%s\n" /* CanonicalURI */
+                  "%s\n" /* CanonicalQueryString */
+                  "%s\n" /* CanonicalHeaders */
+                  "%s\n" /* SignedHeaders */
+                  "%s",  /* HashedRequestPayload in hex */
+                  method,
+                  data->state.up.path,
+                  data->state.up.query ? data->state.up.query : "",
+                  canonical_headers,
+                  signed_headers,
+                  sha_hex);
+  if(!canonical_request) {
+    goto fail;
+  }
+
+  request_type = curl_maprintf("%s4_request", provider0_low);
+  if(!request_type) {
+    goto fail;
+  }
+
+  credential_scope = curl_maprintf("%s/%s/%s/%s",
+                                   date, region, service, request_type);
+  if(!credential_scope) {
+    goto fail;
+  }
+
+  Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
+                strlen(canonical_request));
+  sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+
+  /*
+   * Google allow to use rsa key instead of HMAC, so this code might change
+   * In the furure, but for now we support only HMAC version
+   */
+  str_to_sign = curl_maprintf("%s4-HMAC-SHA256\n" /* Algorithm */
+                              "%s\n" /* RequestDateTime */
+                              "%s\n" /* CredentialScope */
+                              "%s",  /* HashedCanonicalRequest in hex */
+                              provider0_up,
+                              timestamp,
+                              credential_scope,
+                              sha_hex);
+  if(!str_to_sign) {
+    goto fail;
+  }
+
+  secret = curl_maprintf("%s4%s", provider0_up, passwd);
+  if(!secret) {
+    goto fail;
+  }
+
+  HMAC_SHA256(secret, strlen(secret),
+              date, strlen(date), tmp_sign0);
+  HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0),
+              region, strlen(region), tmp_sign1);
+  HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1),
+              service, strlen(service), tmp_sign0);
+  HMAC_SHA256(tmp_sign0, sizeof(tmp_sign0),
+              request_type, strlen(request_type), tmp_sign1);
+  HMAC_SHA256(tmp_sign1, sizeof(tmp_sign1),
+              str_to_sign, strlen(str_to_sign), tmp_sign0);
+
+  sha256_to_hex(sha_hex, tmp_sign0, sizeof(sha_hex));
+
+  auth_headers = curl_maprintf("Authorization: %s4-HMAC-SHA256 "
+                               "Credential=%s/%s, "
+                               "SignedHeaders=%s, "
+                               "Signature=%s\r\n"
+                               "X-%s-Date: %s\r\n",
+                               provider0_up,
+                               user,
+                               credential_scope,
+                               signed_headers,
+                               sha_hex,
+                               provider1_mid,
+                               timestamp);
+  if(!auth_headers) {
+    goto fail;
+  }
+
+  Curl_safefree(data->state.aptr.userpwd);
+  data->state.aptr.userpwd = auth_headers;
+  data->state.authhost.done = TRUE;
+  ret = CURLE_OK;
+
+fail:
+  free(provider0_low);
+  free(provider0_up);
+  free(provider1_low);
+  free(provider1_mid);
+  free(region);
+  free(service);
+  free(canonical_headers);
+  free(signed_headers);
+  free(canonical_request);
+  free(request_type);
+  free(credential_scope);
+  free(str_to_sign);
+  free(secret);
+  return ret;
+}
+
+#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) */

+ 29 - 0
lib/http_aws_sigv4.h

@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_HTTP_AWS_SIGV4_H
+#define HEADER_CURL_HTTP_AWS_SIGV4_H
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  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.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/* this is for creating aws_sigv4 header output */
+CURLcode Curl_output_aws_sigv4(struct Curl_easy *data, bool proxy);
+
+#endif /* HEADER_CURL_HTTP_AWS_SIGV4_H */

+ 21 - 22
lib/http_chunks.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -77,21 +77,21 @@
 #ifdef CURL_DOES_CONVERSIONS
 /* Check for an ASCII hex digit.
    We avoid the use of ISXDIGIT to accommodate non-ASCII hosts. */
-static bool Curl_isxdigit_ascii(char digit)
+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 */
+    || (digit >= 0x41 && digit <= 0x46) /* A-F */
+    || (digit >= 0x61 && digit <= 0x66); /* a-f */
 }
 #else
-#define Curl_isxdigit_ascii(x) Curl_isxdigit(x)
+#define isxdigit_ascii(x) Curl_isxdigit(x)
 #endif
 
-void Curl_httpchunk_init(struct connectdata *conn)
+void Curl_httpchunk_init(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct Curl_chunker *chunk = &conn->chunk;
   chunk->hexindex = 0;      /* start at 0 */
-  chunk->dataleft = 0;      /* no data left yet! */
   chunk->state = CHUNK_HEX; /* we get hex first! */
   Curl_dyn_init(&conn->trailer, DYN_H1_TRAILER);
 }
@@ -107,14 +107,14 @@ void Curl_httpchunk_init(struct connectdata *conn)
  * This function always uses ASCII hex values to accommodate non-ASCII hosts.
  * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
  */
-CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
+CHUNKcode Curl_httpchunk_read(struct Curl_easy *data,
                               char *datap,
                               ssize_t datalen,
                               ssize_t *wrotep,
                               CURLcode *extrap)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   struct Curl_chunker *ch = &conn->chunk;
   struct SingleRequest *k = &data->req;
   size_t piece;
@@ -126,7 +126,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
   /* the original data is written to the client, but we go on with the
      chunk read process, to properly calculate the content length*/
   if(data->set.http_te_skip && !k->ignorebody) {
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, datalen);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, datap, datalen);
     if(result) {
       *extrap = result;
       return CHUNKE_PASSTHRU_ERROR;
@@ -136,8 +136,8 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
   while(length) {
     switch(ch->state) {
     case CHUNK_HEX:
-      if(Curl_isxdigit_ascii(*datap)) {
-        if(ch->hexindex < MAXNUM_SIZE) {
+      if(isxdigit_ascii(*datap)) {
+        if(ch->hexindex < CHUNK_MAXNUM_LEN) {
           ch->hexbuffer[ch->hexindex] = *datap;
           datap++;
           length--;
@@ -158,8 +158,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
         ch->hexbuffer[ch->hexindex] = 0;
 
         /* convert to host encoding before calling strtoul */
-        result = Curl_convert_from_network(conn->data, ch->hexbuffer,
-                                           ch->hexindex);
+        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 */
@@ -194,11 +193,11 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
       piece = curlx_sotouz((ch->datasize >= length)?length:ch->datasize);
 
       /* Write the data portion available */
-      if(!conn->data->set.http_te_skip && !k->ignorebody) {
-        if(!conn->data->set.http_ce_skip && k->writer_stack)
-          result = Curl_unencode_write(conn, k->writer_stack, datap, piece);
+      if(!data->set.http_te_skip && !k->ignorebody) {
+        if(!data->set.http_ce_skip && k->writer_stack)
+          result = Curl_unencode_write(data, k->writer_stack, datap, piece);
         else
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece);
+          result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece);
 
         if(result) {
           *extrap = result;
@@ -219,7 +218,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
     case CHUNK_POSTLF:
       if(*datap == 0x0a) {
         /* The last one before we go back to hex state and start all over. */
-        Curl_httpchunk_init(conn); /* sets state back to CHUNK_HEX */
+        Curl_httpchunk_init(data); /* sets state back to CHUNK_HEX */
       }
       else if(*datap != 0x0d)
         return CHUNKE_BAD_CHUNK;
@@ -242,14 +241,14 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
           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(conn->data, tr, trlen);
+          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(conn, CLIENTWRITE_HEADER, tr, trlen);
+            result = Curl_client_write(data, CLIENTWRITE_HEADER, tr, trlen);
             if(result) {
               *extrap = result;
               return CHUNKE_PASSTHRU_ERROR;
@@ -309,7 +308,7 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
 
         /* Record the length of any data left in the end of the buffer
            even if there's no more chunks to read */
-        ch->dataleft = curlx_sotouz(length);
+        ch->datasize = curlx_sotouz(length);
 
         return CHUNKE_STOP; /* return stop */
       }

+ 10 - 11
lib/http_chunks.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,10 +26,10 @@ struct connectdata;
 
 /*
  * The longest possible hexadecimal number we support in a chunked transfer.
- * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
- * to convert it, we "only" support 2^32 bytes chunk data.
+ * Neither RFC2616 nor the later HTTP specs define a maximum chunk size.
+ * For 64 bit curl_off_t we support 16 digits. For 32 bit, 8 digits.
  */
-#define MAXNUM_SIZE 16
+#define CHUNK_MAXNUM_LEN (SIZEOF_CURL_OFF_T * 2)
 
 typedef enum {
   /* await and buffer all hexadecimal digits until we get one that isn't a
@@ -48,7 +48,7 @@ typedef enum {
      big deal. */
   CHUNK_POSTLF,
 
-  /* Used to mark that we're out of the game.  NOTE: that there's a 'dataleft'
+  /* Used to mark that we're out of the game.  NOTE: that there's a 'datasize'
      field in the struct that will tell how many bytes that were not passed to
      the client in the end of the last buffer! */
   CHUNK_STOP,
@@ -83,16 +83,15 @@ typedef enum {
 const char *Curl_chunked_strerror(CHUNKcode code);
 
 struct Curl_chunker {
-  char hexbuffer[ MAXNUM_SIZE + 1];
-  int hexindex;
-  ChunkyState state;
   curl_off_t datasize;
-  size_t dataleft; /* untouched data amount at the end of the last buffer */
+  ChunkyState state;
+  unsigned char hexindex;
+  char hexbuffer[ CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */
 };
 
 /* The following functions are defined in http_chunks.c */
-void Curl_httpchunk_init(struct connectdata *conn);
-CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
+void Curl_httpchunk_init(struct Curl_easy *data);
+CHUNKcode Curl_httpchunk_read(struct Curl_easy *data, char *datap,
                               ssize_t length, ssize_t *wrote,
                               CURLcode *passthru);
 

+ 4 - 6
lib/http_digest.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -41,13 +41,11 @@ Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
 
 */
 
-CURLcode Curl_input_digest(struct connectdata *conn,
+CURLcode Curl_input_digest(struct Curl_easy *data,
                            bool proxy,
                            const char *header) /* rest of the *-authenticate:
                                                   header */
 {
-  struct Curl_easy *data = conn->data;
-
   /* Point to the correct struct with this */
   struct digestdata *digest;
 
@@ -68,13 +66,13 @@ CURLcode Curl_input_digest(struct connectdata *conn,
   return Curl_auth_decode_digest_http_message(header, digest);
 }
 
-CURLcode Curl_output_digest(struct connectdata *conn,
+CURLcode Curl_output_digest(struct Curl_easy *data,
+                            struct connectdata *conn,
                             bool proxy,
                             const unsigned char *request,
                             const unsigned char *uripath)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   unsigned char *path = NULL;
   char *tmp = NULL;
   char *response;

+ 4 - 3
lib/http_digest.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -26,11 +26,12 @@
 #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
 
 /* this is for digest header input */
-CURLcode Curl_input_digest(struct connectdata *conn,
+CURLcode Curl_input_digest(struct Curl_easy *data,
                            bool proxy, const char *header);
 
 /* this is for creating digest header output */
-CURLcode Curl_output_digest(struct connectdata *conn,
+CURLcode Curl_output_digest(struct Curl_easy *data,
+                            struct connectdata *conn,
                             bool proxy,
                             const unsigned char *request,
                             const unsigned char *uripath);

+ 10 - 13
lib/http_negotiate.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -34,11 +34,10 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
-                              const char *header)
+CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
+                              bool proxy, const char *header)
 {
   CURLcode result;
-  struct Curl_easy *data = conn->data;
   size_t len;
 
   /* Point to the username, password, service and host */
@@ -90,7 +89,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
   neg_ctx->havenegdata = len != 0;
   if(!len) {
     if(state == GSS_AUTHSUCC) {
-      infof(conn->data, "Negotiate auth restarted\n");
+      infof(data, "Negotiate auth restarted\n");
       Curl_http_auth_cleanup_negotiate(conn);
     }
     else if(state != GSS_AUTHNONE) {
@@ -116,15 +115,14 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
   return result;
 }
 
-CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
+CURLcode Curl_output_negotiate(struct Curl_easy *data,
+                               struct connectdata *conn, bool proxy)
 {
   struct negotiatedata *neg_ctx = proxy ? &conn->proxyneg :
     &conn->negotiate;
-  struct auth *authp = proxy ? &conn->data->state.authproxy :
-    &conn->data->state.authhost;
+  struct auth *authp = proxy ? &data->state.authproxy : &data->state.authhost;
   curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
     &conn->http_negotiate_state;
-  struct Curl_easy *data = conn->data;
   char *base64 = NULL;
   size_t len = 0;
   char *userp;
@@ -147,12 +145,12 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
     (*state != GSS_AUTHDONE && *state != GSS_AUTHSUCC)) {
 
     if(neg_ctx->noauthpersist && *state == GSS_AUTHSUCC) {
-      infof(conn->data, "Curl_output_negotiate, "
+      infof(data, "Curl_output_negotiate, "
        "no persistent authentication: cleanup existing context");
       Curl_http_auth_cleanup_negotiate(conn);
     }
     if(!neg_ctx->context) {
-      result = Curl_input_negotiate(conn, proxy, "Negotiate");
+      result = Curl_input_negotiate(data, conn, proxy, "Negotiate");
       if(result == CURLE_AUTH_ERROR) {
         /* negotiate auth failed, let's continue unauthenticated to stay
          * compatible with the behavior before curl-7_64_0-158-g6c6035532 */
@@ -163,8 +161,7 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
         return result;
     }
 
-    result = Curl_auth_create_spnego_message(conn->data,
-      neg_ctx, &base64, &len);
+    result = Curl_auth_create_spnego_message(data, neg_ctx, &base64, &len);
     if(result)
       return result;
 

+ 5 - 4
lib/http_negotiate.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -25,11 +25,12 @@
 #if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
 
 /* this is for Negotiate header input */
-CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
-                              const char *header);
+CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn,
+                              bool proxy, const char *header);
 
 /* this is for creating Negotiate header output */
-CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
+CURLcode Curl_output_negotiate(struct Curl_easy *data,
+                               struct connectdata *conn, bool proxy);
 
 void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
 

+ 17 - 17
lib/http_ntlm.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -59,7 +59,7 @@
 # define DEBUG_OUT(x) Curl_nop_stmt
 #endif
 
-CURLcode Curl_input_ntlm(struct connectdata *conn,
+CURLcode Curl_input_ntlm(struct Curl_easy *data,
                          bool proxy,         /* if proxy or not */
                          const char *header) /* rest of the www-authenticate:
                                                 header */
@@ -68,6 +68,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
   struct ntlmdata *ntlm;
   curlntlm *state;
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
   state = proxy ? &conn->proxy_ntlm_state : &conn->http_ntlm_state;
@@ -79,7 +80,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
       header++;
 
     if(*header) {
-      result = Curl_auth_decode_ntlm_type2_message(conn->data, header, ntlm);
+      result = Curl_auth_decode_ntlm_type2_message(data, header, ntlm);
       if(result)
         return result;
 
@@ -87,17 +88,17 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
     }
     else {
       if(*state == NTLMSTATE_LAST) {
-        infof(conn->data, "NTLM auth restarted\n");
+        infof(data, "NTLM auth restarted\n");
         Curl_http_auth_cleanup_ntlm(conn);
       }
       else if(*state == NTLMSTATE_TYPE3) {
-        infof(conn->data, "NTLM handshake rejected\n");
+        infof(data, "NTLM handshake rejected\n");
         Curl_http_auth_cleanup_ntlm(conn);
         *state = NTLMSTATE_NONE;
         return CURLE_REMOTE_ACCESS_DENIED;
       }
       else if(*state >= NTLMSTATE_TYPE1) {
-        infof(conn->data, "NTLM handshake failure (internal error)\n");
+        infof(data, "NTLM handshake failure (internal error)\n");
         return CURLE_REMOTE_ACCESS_DENIED;
       }
 
@@ -111,7 +112,7 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
 /*
  * This is for creating ntlm header output
  */
-CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
+CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy)
 {
   char *base64 = NULL;
   size_t len = 0;
@@ -131,8 +132,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   struct ntlmdata *ntlm;
   curlntlm *state;
   struct auth *authp;
-  struct Curl_easy *data = conn->data;
-
+  struct connectdata *conn = data->conn;
 
   DEBUGASSERT(conn);
   DEBUGASSERT(data);
@@ -142,12 +142,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
     allocuserpwd = &data->state.aptr.proxyuserpwd;
     userp = conn->http_proxy.user;
     passwdp = conn->http_proxy.passwd;
-    service = conn->data->set.str[STRING_PROXY_SERVICE_NAME] ?
-              conn->data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
+    service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
+              data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
     hostname = conn->http_proxy.host.name;
     ntlm = &conn->proxyntlm;
     state = &conn->proxy_ntlm_state;
-    authp = &conn->data->state.authproxy;
+    authp = &data->state.authproxy;
 #else
     return CURLE_NOT_BUILT_IN;
 #endif
@@ -156,12 +156,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
     allocuserpwd = &data->state.aptr.userpwd;
     userp = conn->user;
     passwdp = conn->passwd;
-    service = conn->data->set.str[STRING_SERVICE_NAME] ?
-              conn->data->set.str[STRING_SERVICE_NAME] : "HTTP";
+    service = data->set.str[STRING_SERVICE_NAME] ?
+              data->set.str[STRING_SERVICE_NAME] : "HTTP";
     hostname = conn->host.name;
     ntlm = &conn->ntlm;
     state = &conn->http_ntlm_state;
-    authp = &conn->data->state.authhost;
+    authp = &data->state.authhost;
   }
   authp->done = FALSE;
 
@@ -188,7 +188,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
   case NTLMSTATE_TYPE1:
   default: /* for the weird cases we (re)start here */
     /* Create a type-1 message */
-    result = Curl_auth_create_ntlm_type1_message(conn->data, userp, passwdp,
+    result = Curl_auth_create_ntlm_type1_message(data, userp, passwdp,
                                                  service, hostname,
                                                  ntlm, &base64,
                                                  &len);
@@ -210,7 +210,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
 
   case NTLMSTATE_TYPE2:
     /* We already received the type-2 message, create a type-3 message */
-    result = Curl_auth_create_ntlm_type3_message(conn->data, userp, passwdp,
+    result = Curl_auth_create_ntlm_type3_message(data, userp, passwdp,
                                                  ntlm, &base64, &len);
     if(result)
       return result;

+ 3 - 3
lib/http_ntlm.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -27,11 +27,11 @@
 #if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
 
 /* this is for ntlm header input */
-CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy,
+CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy,
                          const char *header);
 
 /* this is for creating ntlm header output */
-CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
+CURLcode Curl_output_ntlm(struct Curl_easy *data, bool proxy);
 
 void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
 

+ 312 - 74
lib/http_proxy.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -27,6 +27,9 @@
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 
 #include <curl/curl.h>
+#ifdef USE_HYPER
+#include <hyper.h>
+#endif
 #include "sendf.h"
 #include "http.h"
 #include "url.h"
@@ -47,15 +50,16 @@
  * proxy_ssl_connected connection bit when complete.  Can be
  * called multiple times.
  */
-static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex)
+static CURLcode https_proxy_connect(struct Curl_easy *data, int sockindex)
 {
 #ifdef USE_SSL
+  struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
   DEBUGASSERT(conn->http_proxy.proxytype == CURLPROXY_HTTPS);
   if(!conn->bits.proxy_ssl_connected[sockindex]) {
     /* perform SSL initialization for this socket */
     result =
-      Curl_ssl_connect_nonblocking(conn, sockindex,
+      Curl_ssl_connect_nonblocking(data, conn, sockindex,
                                    &conn->bits.proxy_ssl_connected[sockindex]);
     if(result)
       /* a failed connection is marked for closure to prevent (bad) re-use or
@@ -64,17 +68,17 @@ static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex)
   }
   return result;
 #else
-  (void) conn;
+  (void) data;
   (void) sockindex;
   return CURLE_NOT_BUILT_IN;
 #endif
 }
 
-CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
+CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
-    const CURLcode result = https_proxy_connect(conn, sockindex);
+    const CURLcode result = https_proxy_connect(data, sockindex);
     if(result)
       return result;
     if(!conn->bits.proxy_ssl_connected[sockindex])
@@ -102,9 +106,9 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
      * This function might be called several times in the multi interface case
      * if the proxy's CONNECT response is not instant.
      */
-    prot_save = conn->data->req.p.http;
+    prot_save = data->req.p.http;
     memset(&http_proxy, 0, sizeof(http_proxy));
-    conn->data->req.p.http = &http_proxy;
+    data->req.p.http = &http_proxy;
     connkeep(conn, "HTTP proxy CONNECT");
 
     /* for the secondary socket (FTP), use the "connect to host"
@@ -124,8 +128,8 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
       remote_port = conn->conn_to_port;
     else
       remote_port = conn->remote_port;
-    result = Curl_proxyCONNECT(conn, sockindex, hostname, remote_port);
-    conn->data->req.p.http = prot_save;
+    result = Curl_proxyCONNECT(data, sockindex, hostname, remote_port);
+    data->req.p.http = prot_save;
     if(CURLE_OK != result)
       return result;
     Curl_safefree(data->state.aptr.proxyuserpwd);
@@ -149,15 +153,16 @@ bool Curl_connect_ongoing(struct connectdata *conn)
     (conn->connect_state->tunnel_state != TUNNEL_COMPLETE);
 }
 
-static CURLcode connect_init(struct connectdata *conn, bool reinit)
+static CURLcode connect_init(struct Curl_easy *data, bool reinit)
 {
   struct http_connect_state *s;
+  struct connectdata *conn = data->conn;
   if(!reinit) {
     DEBUGASSERT(!conn->connect_state);
     s = calloc(1, sizeof(struct http_connect_state));
     if(!s)
       return CURLE_OUT_OF_MEMORY;
-    infof(conn->data, "allocate connect buffer!\n");
+    infof(data, "allocate connect buffer!\n");
     conn->connect_state = s;
     Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
   }
@@ -173,23 +178,57 @@ static CURLcode connect_init(struct connectdata *conn, bool reinit)
   return CURLE_OK;
 }
 
-static void connect_done(struct connectdata *conn)
+static void connect_done(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct http_connect_state *s = conn->connect_state;
   s->tunnel_state = TUNNEL_COMPLETE;
   Curl_dyn_free(&s->rcvbuf);
-  infof(conn->data, "CONNECT phase completed!\n");
+  infof(data, "CONNECT phase completed!\n");
+}
+
+static CURLcode CONNECT_host(struct Curl_easy *data,
+                             struct connectdata *conn,
+                             const char *hostname,
+                             int remote_port,
+                             char **connecthostp,
+                             char **hostp)
+{
+  char *hostheader; /* for CONNECT */
+  char *host = NULL; /* Host: */
+  bool ipv6_ip = conn->bits.ipv6_ip;
+
+  /* the hostname may be different */
+  if(hostname != conn->host.name)
+    ipv6_ip = (strchr(hostname, ':') != NULL);
+  hostheader = /* host:port with IPv6 support */
+    aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
+            remote_port);
+  if(!hostheader)
+    return CURLE_OUT_OF_MEMORY;
+
+  if(!Curl_checkProxyheaders(data, conn, "Host")) {
+    host = aprintf("Host: %s\r\n", hostheader);
+    if(!host) {
+      free(hostheader);
+      return CURLE_OUT_OF_MEMORY;
+    }
+  }
+  *connecthostp = hostheader;
+  *hostp = host;
+  return CURLE_OK;
 }
 
-static CURLcode CONNECT(struct connectdata *conn,
+static CURLcode CONNECT(struct Curl_easy *data,
                         int sockindex,
                         const char *hostname,
                         int remote_port)
+#ifndef USE_HYPER
 {
   int subversion = 0;
-  struct Curl_easy *data = conn->data;
   struct SingleRequest *k = &data->req;
   CURLcode result;
+  struct connectdata *conn = data->conn;
   curl_socket_t tunnelsocket = conn->sock[sockindex];
   struct http_connect_state *s = conn->connect_state;
   char *linep;
@@ -207,8 +246,9 @@ static CURLcode CONNECT(struct connectdata *conn,
     timediff_t check;
     if(TUNNEL_INIT == s->tunnel_state) {
       /* BEGIN CONNECT PHASE */
-      char *host_port;
       struct dynbuf req;
+      char *hostheader = NULL;
+      char *host = NULL;
 
       infof(data, "Establish HTTP proxy tunnel to %s:%d\n",
             hostname, remote_port);
@@ -219,50 +259,28 @@ static CURLcode CONNECT(struct connectdata *conn,
       free(data->req.newurl);
       data->req.newurl = NULL;
 
-      host_port = aprintf("%s:%d", hostname, remote_port);
-      if(!host_port)
-        return CURLE_OUT_OF_MEMORY;
-
       /* initialize a dynamic send-buffer */
       Curl_dyn_init(&req, DYN_HTTP_REQUEST);
 
-      /* Setup the proxy-authorization header, if any */
-      result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE);
+      result = CONNECT_host(data, conn,
+                            hostname, remote_port, &hostheader, &host);
+      if(result)
+        return result;
 
-      free(host_port);
+      /* Setup the proxy-authorization header, if any */
+      result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
+                                     hostheader, TRUE);
 
       if(!result) {
-        char *host = NULL;
         const char *proxyconn = "";
         const char *useragent = "";
         const char *httpv =
           (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1";
-        bool ipv6_ip = conn->bits.ipv6_ip;
-        char *hostheader;
-
-        /* the hostname may be different */
-        if(hostname != conn->host.name)
-          ipv6_ip = (strchr(hostname, ':') != NULL);
-        hostheader = /* host:port with IPv6 support */
-          aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
-                  remote_port);
-        if(!hostheader) {
-          Curl_dyn_free(&req);
-          return CURLE_OUT_OF_MEMORY;
-        }
 
-        if(!Curl_checkProxyheaders(conn, "Host")) {
-          host = aprintf("Host: %s\r\n", hostheader);
-          if(!host) {
-            free(hostheader);
-            Curl_dyn_free(&req);
-            return CURLE_OUT_OF_MEMORY;
-          }
-        }
-        if(!Curl_checkProxyheaders(conn, "Proxy-Connection"))
+        if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection"))
           proxyconn = "Proxy-Connection: Keep-Alive\r\n";
 
-        if(!Curl_checkProxyheaders(conn, "User-Agent") &&
+        if(!Curl_checkProxyheaders(data, conn, "User-Agent") &&
            data->set.str[STRING_USERAGENT])
           useragent = data->state.aptr.uagent;
 
@@ -281,12 +299,8 @@ static CURLcode CONNECT(struct connectdata *conn,
                         useragent,
                         proxyconn);
 
-        if(host)
-          free(host);
-        free(hostheader);
-
         if(!result)
-          result = Curl_add_custom_headers(conn, TRUE, &req);
+          result = Curl_add_custom_headers(data, TRUE, &req);
 
         if(!result)
           /* CRLF terminate the request */
@@ -295,13 +309,14 @@ static CURLcode CONNECT(struct connectdata *conn,
         if(!result) {
           /* Send the connect request to the proxy */
           /* BLOCKING */
-          result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
+          result = Curl_buffer_send(&req, data, &data->info.request_size, 0,
                                     sockindex);
         }
         if(result)
           failf(data, "Failed sending CONNECT to proxy");
       }
-
+      free(host);
+      free(hostheader);
       Curl_dyn_free(&req);
       if(result)
         return result;
@@ -330,12 +345,12 @@ static CURLcode CONNECT(struct connectdata *conn,
 
         /* Read one byte at a time to avoid a race condition. Wait at most one
            second before looping to ensure continuous pgrsUpdates. */
-        result = Curl_read(conn, tunnelsocket, &byte, 1, &gotbytes);
+        result = Curl_read(data, tunnelsocket, &byte, 1, &gotbytes);
         if(result == CURLE_AGAIN)
           /* socket buffer drained, return */
           return CURLE_OK;
 
-        if(Curl_pgrsUpdate(conn))
+        if(Curl_pgrsUpdate(data))
           return CURLE_ABORTED_BY_CALLBACK;
 
         if(result) {
@@ -379,7 +394,7 @@ static CURLcode CONNECT(struct connectdata *conn,
 
             /* now parse the chunked piece of data so that we can
                properly tell when the stream ends */
-            r = Curl_httpchunk_read(conn, &byte, 1, &tookcareof, &extra);
+            r = Curl_httpchunk_read(data, &byte, 1, &tookcareof, &extra);
             if(r == CHUNKE_STOP) {
               /* we're done reading chunks! */
               infof(data, "chunk reading DONE\n");
@@ -418,7 +433,7 @@ static CURLcode CONNECT(struct connectdata *conn,
           if(data->set.include_header)
             writetype |= CLIENTWRITE_BODY;
 
-          result = Curl_client_write(conn, writetype, linep, perline);
+          result = Curl_client_write(data, writetype, linep, perline);
           if(result)
             return result;
         }
@@ -460,7 +475,7 @@ static CURLcode CONNECT(struct connectdata *conn,
 
               /* now parse the chunked piece of data so that we can properly
                  tell when the stream ends */
-              r = Curl_httpchunk_read(conn, linep + 1, 1, &gotbytes,
+              r = Curl_httpchunk_read(data, linep + 1, 1, &gotbytes,
                                       &extra);
               if(r == CHUNKE_STOP) {
                 /* we're done reading chunks! */
@@ -479,9 +494,12 @@ static CURLcode CONNECT(struct connectdata *conn,
           }
           else
             s->keepon = KEEPON_DONE;
-          if(!s->cl)
+
+          if(s->keepon == KEEPON_DONE && !s->cl)
             /* we did the full CONNECT treatment, go to COMPLETE */
             s->tunnel_state = TUNNEL_COMPLETE;
+
+          DEBUGASSERT(s->keepon == KEEPON_IGNORE || s->keepon == KEEPON_DONE);
           continue;
         }
 
@@ -495,7 +513,7 @@ static CURLcode CONNECT(struct connectdata *conn,
           if(!auth)
             return CURLE_OUT_OF_MEMORY;
 
-          result = Curl_http_input_auth(conn, proxy, auth);
+          result = Curl_http_input_auth(data, proxy, auth);
 
           free(auth);
 
@@ -530,7 +548,7 @@ static CURLcode CONNECT(struct connectdata *conn,
             infof(data, "CONNECT responded chunked\n");
             s->chunked_encoding = TRUE;
             /* init our chunky engine */
-            Curl_httpchunk_init(conn);
+            Curl_httpchunk_init(data);
           }
         }
         else if(Curl_compareheader(linep, "Proxy-Connection:", "close"))
@@ -545,7 +563,7 @@ static CURLcode CONNECT(struct connectdata *conn,
         Curl_dyn_reset(&s->rcvbuf);
       } /* while there's buffer left and loop is requested */
 
-      if(Curl_pgrsUpdate(conn))
+      if(Curl_pgrsUpdate(data))
         return CURLE_ABORTED_BY_CALLBACK;
 
       if(error)
@@ -554,7 +572,7 @@ static CURLcode CONNECT(struct connectdata *conn,
       if(data->info.httpproxycode/100 != 2) {
         /* Deal with the possibly already received authenticate
            headers. 'newurl' is set to a new URL if we must loop. */
-        result = Curl_http_auth_act(conn);
+        result = Curl_http_auth_act(data);
         if(result)
           return result;
 
@@ -567,7 +585,7 @@ static CURLcode CONNECT(struct connectdata *conn,
 
       if(s->close_connection && data->req.newurl) {
         /* Connection closed by server. Don't use it anymore */
-        Curl_closesocket(conn, conn->sock[sockindex]);
+        Curl_closesocket(data, conn, conn->sock[sockindex]);
         conn->sock[sockindex] = CURL_SOCKET_BAD;
         break;
       }
@@ -577,7 +595,7 @@ static CURLcode CONNECT(struct connectdata *conn,
      * means the HTTP authentication is still going on so if the tunnel
      * is complete we start over in INIT state */
     if(data->req.newurl && (TUNNEL_COMPLETE == s->tunnel_state)) {
-      connect_init(conn, TRUE); /* reinit */
+      connect_init(data, TRUE); /* reinit */
     }
 
   } while(data->req.newurl);
@@ -586,14 +604,14 @@ static CURLcode CONNECT(struct connectdata *conn,
     if(s->close_connection && data->req.newurl) {
       conn->bits.proxy_connect_closed = TRUE;
       infof(data, "Connect me again please\n");
-      connect_done(conn);
+      connect_done(data);
     }
     else {
       free(data->req.newurl);
       data->req.newurl = NULL;
       /* failure, close this connection to avoid re-use */
       streamclose(conn, "proxy CONNECT failure");
-      Curl_closesocket(conn, conn->sock[sockindex]);
+      Curl_closesocket(data, conn, conn->sock[sockindex]);
       conn->sock[sockindex] = CURL_SOCKET_BAD;
     }
 
@@ -628,6 +646,225 @@ static CURLcode CONNECT(struct connectdata *conn,
   Curl_dyn_free(&s->rcvbuf);
   return CURLE_OK;
 }
+#else
+/* The Hyper version of CONNECT */
+{
+  struct connectdata *conn = data->conn;
+  struct hyptransfer *h = &data->hyp;
+  curl_socket_t tunnelsocket = conn->sock[sockindex];
+  struct http_connect_state *s = conn->connect_state;
+  CURLcode result = CURLE_OUT_OF_MEMORY;
+  hyper_io *io = NULL;
+  hyper_request *req = NULL;
+  hyper_headers *headers = NULL;
+  hyper_clientconn_options *options = NULL;
+  hyper_task *handshake = NULL;
+  hyper_task *task = NULL; /* for the handshake */
+  hyper_task *sendtask = NULL; /* for the send */
+  hyper_clientconn *client = NULL;
+  hyper_error *hypererr = NULL;
+  char *hostheader = NULL; /* for CONNECT */
+  char *host = NULL; /* Host: */
+
+  if(Curl_connect_complete(conn))
+    return CURLE_OK; /* CONNECT is already completed */
+
+  conn->bits.proxy_connect_closed = FALSE;
+
+  do {
+    switch(s->tunnel_state) {
+    case TUNNEL_INIT:
+      /* BEGIN CONNECT PHASE */
+      io = hyper_io_new();
+      if(!io) {
+        failf(data, "Couldn't create hyper IO");
+        goto error;
+      }
+      /* tell Hyper how to read/write network data */
+      hyper_io_set_userdata(io, data);
+      hyper_io_set_read(io, Curl_hyper_recv);
+      hyper_io_set_write(io, Curl_hyper_send);
+      conn->sockfd = tunnelsocket;
+
+      /* create an executor to poll futures */
+      if(!h->exec) {
+        h->exec = hyper_executor_new();
+        if(!h->exec) {
+          failf(data, "Couldn't create hyper executor");
+          goto error;
+        }
+      }
+
+      options = hyper_clientconn_options_new();
+      if(!options) {
+        failf(data, "Couldn't create hyper client options");
+        goto error;
+      }
+
+      hyper_clientconn_options_exec(options, h->exec);
+
+      /* "Both the `io` and the `options` are consumed in this function
+         call" */
+      handshake = hyper_clientconn_handshake(io, options);
+      if(!handshake) {
+        failf(data, "Couldn't create hyper client handshake");
+        goto error;
+      }
+      io = NULL;
+      options = NULL;
+
+      if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
+        failf(data, "Couldn't hyper_executor_push the handshake");
+        goto error;
+      }
+      handshake = NULL; /* ownership passed on */
+
+      task = hyper_executor_poll(h->exec);
+      if(!task) {
+        failf(data, "Couldn't hyper_executor_poll the handshake");
+        goto error;
+      }
+
+      client = hyper_task_value(task);
+      hyper_task_free(task);
+      req = hyper_request_new();
+      if(!req) {
+        failf(data, "Couldn't hyper_request_new");
+        goto error;
+      }
+      if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
+                                  strlen("CONNECT"))) {
+        failf(data, "error setting method");
+        goto error;
+      }
+
+      result = CONNECT_host(data, conn, hostname, remote_port,
+                            &hostheader, &host);
+      if(result)
+        goto error;
+
+      if(hyper_request_set_uri(req, (uint8_t *)hostheader,
+                               strlen(hostheader))) {
+        failf(data, "error setting path");
+        result = CURLE_OUT_OF_MEMORY;
+      }
+      /* Setup the proxy-authorization header, if any */
+      result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
+                                     hostheader, TRUE);
+      if(result)
+        goto error;
+      Curl_safefree(hostheader);
+
+      /* default is 1.1 */
+      if((conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) &&
+         (HYPERE_OK != hyper_request_set_version(req,
+                                                 HYPER_HTTP_VERSION_1_0))) {
+        failf(data, "error settting HTTP version");
+        goto error;
+      }
+
+      headers = hyper_request_headers(req);
+      if(!headers) {
+        failf(data, "hyper_request_headers");
+        goto error;
+      }
+      if(host && Curl_hyper_header(data, headers, host))
+        goto error;
+      Curl_safefree(host);
+
+      if(data->state.aptr.proxyuserpwd &&
+         Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
+        goto error;
+
+      if(data->set.str[STRING_USERAGENT] &&
+         *data->set.str[STRING_USERAGENT] &&
+         data->state.aptr.uagent &&
+         Curl_hyper_header(data, headers, data->state.aptr.uagent))
+        goto error;
+
+      if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") &&
+         Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
+        goto error;
+
+      sendtask = hyper_clientconn_send(client, req);
+      if(!sendtask) {
+        failf(data, "hyper_clientconn_send");
+        goto error;
+      }
+
+      if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
+        failf(data, "Couldn't hyper_executor_push the send");
+        goto error;
+      }
+
+      hyper_clientconn_free(client);
+
+      do {
+        task = hyper_executor_poll(h->exec);
+        if(task) {
+          bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
+          if(error)
+            hypererr = hyper_task_value(task);
+          hyper_task_free(task);
+          if(error)
+            goto error;
+        }
+      } while(task);
+      s->tunnel_state = TUNNEL_CONNECT;
+      /* FALLTHROUGH */
+    case TUNNEL_CONNECT: {
+      int didwhat;
+      bool done = FALSE;
+      result = Curl_hyper_stream(data, conn, &didwhat, &done,
+                                 CURL_CSELECT_IN | CURL_CSELECT_OUT);
+      if(result)
+        goto error;
+      if(!done)
+        break;
+      fprintf(stderr, "done\n");
+      s->tunnel_state = TUNNEL_COMPLETE;
+      if(h->exec) {
+        hyper_executor_free(h->exec);
+        h->exec = NULL;
+      }
+      if(h->read_waker) {
+        hyper_waker_free(h->read_waker);
+        h->read_waker = NULL;
+      }
+      if(h->write_waker) {
+        hyper_waker_free(h->write_waker);
+        h->write_waker = NULL;
+      }
+    }
+      /* FALLTHROUGH */
+    default:
+      break;
+    }
+  } while(data->req.newurl);
+
+  result = CURLE_OK;
+  error:
+  free(host);
+  free(hostheader);
+  if(io)
+    hyper_io_free(io);
+
+  if(options)
+    hyper_clientconn_options_free(options);
+
+  if(handshake)
+    hyper_task_free(handshake);
+
+  if(hypererr) {
+    uint8_t errbuf[256];
+    size_t errlen = hyper_error_print(hypererr, errbuf, sizeof(errbuf));
+    failf(data, "Hyper: %.*s", (int)errlen, errbuf);
+    hyper_error_free(hypererr);
+  }
+  return result;
+}
+
+#endif
 
 void Curl_connect_free(struct Curl_easy *data)
 {
@@ -645,21 +882,22 @@ void Curl_connect_free(struct Curl_easy *data)
  * this proxy. After that, the socket can be used just as a normal socket.
  */
 
-CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
                            int sockindex,
                            const char *hostname,
                            int remote_port)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   if(!conn->connect_state) {
-    result = connect_init(conn, FALSE);
+    result = connect_init(data, FALSE);
     if(result)
       return result;
   }
-  result = CONNECT(conn, sockindex, hostname, remote_port);
+  result = CONNECT(data, sockindex, hostname, remote_port);
 
   if(result || Curl_connect_complete(conn))
-    connect_done(conn);
+    connect_done(data);
 
   return result;
 }

+ 3 - 3
lib/http_proxy.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -27,14 +27,14 @@
 
 #if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
 /* ftp can use this as well */
-CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+CURLcode Curl_proxyCONNECT(struct Curl_easy *data,
                            int tunnelsocket,
                            const char *hostname, int remote_port);
 
 /* Default proxy timeout in milliseconds */
 #define PROXY_TIMEOUT (3600*1000)
 
-CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex);
 
 bool Curl_connect_complete(struct connectdata *conn);
 bool Curl_connect_ongoing(struct connectdata *conn);

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 183 - 170
lib/imap.c


+ 55 - 51
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 - 2020 Daniel Stenberg
+ * Copyright (c) 2004 - 2021 Daniel Stenberg
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -56,7 +56,8 @@
 #include "curl_memory.h"
 #include "memdebug.h"
 
-static CURLcode ftpsend(struct connectdata *conn, const char *cmd)
+static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
+                        const char *cmd)
 {
   ssize_t bytes_written;
 #define SBUF_SIZE 1024
@@ -80,7 +81,7 @@ static CURLcode ftpsend(struct connectdata *conn, const char *cmd)
   write_len += 2;
   bytes_written = 0;
 
-  result = Curl_convert_to_network(conn->data, s, write_len);
+  result = Curl_convert_to_network(data, s, write_len);
   /* Curl_convert_to_network calls failf if unsuccessful */
   if(result)
     return result;
@@ -89,7 +90,7 @@ static CURLcode ftpsend(struct connectdata *conn, const char *cmd)
 #ifdef HAVE_GSSAPI
     conn->data_prot = PROT_CMD;
 #endif
-    result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
+    result = Curl_write(data, conn->sock[FIRSTSOCKET], sptr, write_len,
                         &bytes_written);
 #ifdef HAVE_GSSAPI
     DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
@@ -99,7 +100,7 @@ static CURLcode ftpsend(struct connectdata *conn, const char *cmd)
     if(result)
       break;
 
-    Curl_debug(conn->data, CURLINFO_HEADER_OUT, sptr, (size_t)bytes_written);
+    Curl_debug(data, CURLINFO_HEADER_OUT, sptr, (size_t)bytes_written);
 
     if(bytes_written != (ssize_t)write_len) {
       write_len -= bytes_written;
@@ -202,14 +203,13 @@ krb5_encode(void *app_data, const void *from, int length, int level, void **to)
 }
 
 static int
-krb5_auth(void *app_data, struct connectdata *conn)
+krb5_auth(void *app_data, struct Curl_easy *data, struct connectdata *conn)
 {
   int ret = AUTH_OK;
   char *p;
   const char *host = conn->host.name;
   ssize_t nread;
   curl_socklen_t l = sizeof(conn->local_addr);
-  struct Curl_easy *data = conn->data;
   CURLcode result;
   const char *service = data->set.str[STRING_SERVICE_NAME] ?
                         data->set.str[STRING_SERVICE_NAME] :
@@ -242,11 +242,11 @@ krb5_auth(void *app_data, struct connectdata *conn)
   for(;;) {
     /* this really shouldn't be repeated here, but can't help it */
     if(service == srv_host) {
-      result = ftpsend(conn, "AUTH GSSAPI");
+      result = ftpsend(data, conn, "AUTH GSSAPI");
       if(result)
         return -2;
 
-      if(Curl_GetFTPResponse(&nread, conn, NULL))
+      if(Curl_GetFTPResponse(data, &nread, NULL))
         return -1;
 
       if(data->state.buffer[0] != '3')
@@ -319,7 +319,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
 
         cmd = aprintf("ADAT %s", p);
         if(cmd)
-          result = ftpsend(conn, cmd);
+          result = ftpsend(data, conn, cmd);
         else
           result = CURLE_OUT_OF_MEMORY;
 
@@ -331,7 +331,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
           break;
         }
 
-        if(Curl_GetFTPResponse(&nread, conn, NULL)) {
+        if(Curl_GetFTPResponse(data, &nread, NULL)) {
           ret = -1;
           break;
         }
@@ -443,7 +443,7 @@ static char level_to_char(int level)
 
 /* Send an FTP command defined by |message| and the optional arguments. The
    function returns the ftp_code. If an error occurs, -1 is returned. */
-static int ftp_send_command(struct connectdata *conn, const char *message, ...)
+static int ftp_send_command(struct Curl_easy *data, const char *message, ...)
 {
   int ftp_code;
   ssize_t nread = 0;
@@ -454,11 +454,11 @@ static int ftp_send_command(struct connectdata *conn, const char *message, ...)
   mvsnprintf(print_buffer, sizeof(print_buffer), message, args);
   va_end(args);
 
-  if(ftpsend(conn, print_buffer)) {
+  if(ftpsend(data, data->conn, print_buffer)) {
     ftp_code = -1;
   }
   else {
-    if(Curl_GetFTPResponse(&nread, conn, &ftp_code))
+    if(Curl_GetFTPResponse(data, &nread, &ftp_code))
       ftp_code = -1;
   }
 
@@ -495,7 +495,7 @@ socket_read(curl_socket_t fd, void *to, size_t len)
    CURLcode saying whether an error occurred or CURLE_OK if |len| was
    written. */
 static CURLcode
-socket_write(struct connectdata *conn, curl_socket_t fd, const void *to,
+socket_write(struct Curl_easy *data, curl_socket_t fd, const void *to,
              size_t len)
 {
   const char *to_p = to;
@@ -503,7 +503,7 @@ socket_write(struct connectdata *conn, curl_socket_t fd, const void *to,
   ssize_t written;
 
   while(len > 0) {
-    result = Curl_write_plain(conn, fd, to_p, len, &written);
+    result = Curl_write_plain(data, fd, to_p, len, &written);
     if(!result) {
       len -= written;
       to_p += written;
@@ -556,18 +556,19 @@ buffer_read(struct krb5buffer *buf, void *data, size_t len)
 }
 
 /* Matches Curl_recv signature */
-static ssize_t sec_recv(struct connectdata *conn, int sockindex,
+static ssize_t sec_recv(struct Curl_easy *data, int sockindex,
                         char *buffer, size_t len, CURLcode *err)
 {
   size_t bytes_read;
   size_t total_read = 0;
+  struct connectdata *conn = data->conn;
   curl_socket_t fd = conn->sock[sockindex];
 
   *err = CURLE_OK;
 
   /* Handle clear text response. */
   if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
-      return sread(fd, buffer, len);
+    return sread(fd, buffer, len);
 
   if(conn->in_buffer.eof_flag) {
     conn->in_buffer.eof_flag = 0;
@@ -597,8 +598,8 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex,
 
 /* Send |length| bytes from |from| to the |fd| socket taking care of encoding
    and negotiating with the server. |from| can be NULL. */
-static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
-                        const char *from, int length)
+static void do_sec_send(struct Curl_easy *data, struct connectdata *conn,
+                        curl_socket_t fd, const char *from, int length)
 {
   int bytes, htonl_bytes; /* 32-bit integers for htonl */
   char *buffer = NULL;
@@ -622,7 +623,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
     return; /* error */
 
   if(iscmd) {
-    error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes),
+    error = Curl_base64_encode(data, buffer, curlx_sitouz(bytes),
                                &cmd_buffer, &cmd_size);
     if(error) {
       free(buffer);
@@ -632,27 +633,27 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
       static const char *enc = "ENC ";
       static const char *mic = "MIC ";
       if(prot_level == PROT_PRIVATE)
-        socket_write(conn, fd, enc, 4);
+        socket_write(data, fd, enc, 4);
       else
-        socket_write(conn, fd, mic, 4);
+        socket_write(data, fd, mic, 4);
 
-      socket_write(conn, fd, cmd_buffer, cmd_size);
-      socket_write(conn, fd, "\r\n", 2);
-      infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
+      socket_write(data, fd, cmd_buffer, cmd_size);
+      socket_write(data, fd, "\r\n", 2);
+      infof(data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
             cmd_buffer);
       free(cmd_buffer);
     }
   }
   else {
     htonl_bytes = htonl(bytes);
-    socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes));
-    socket_write(conn, fd, buffer, curlx_sitouz(bytes));
+    socket_write(data, fd, &htonl_bytes, sizeof(htonl_bytes));
+    socket_write(data, fd, buffer, curlx_sitouz(bytes));
   }
   free(buffer);
 }
 
-static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd,
-                         const char *buffer, size_t length)
+static ssize_t sec_write(struct Curl_easy *data, struct connectdata *conn,
+                         curl_socket_t fd, const char *buffer, size_t length)
 {
   ssize_t tx = 0, len = conn->buffer_size;
 
@@ -664,7 +665,7 @@ static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd,
     if(length < (size_t)len)
       len = length;
 
-    do_sec_send(conn, fd, buffer, curlx_sztosi(len));
+    do_sec_send(data, conn, fd, buffer, curlx_sztosi(len));
     length -= len;
     buffer += len;
     tx += len;
@@ -673,16 +674,17 @@ static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd,
 }
 
 /* Matches Curl_send signature */
-static ssize_t sec_send(struct connectdata *conn, int sockindex,
+static ssize_t sec_send(struct Curl_easy *data, int sockindex,
                         const void *buffer, size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   curl_socket_t fd = conn->sock[sockindex];
   *err = CURLE_OK;
-  return sec_write(conn, fd, buffer, len);
+  return sec_write(data, conn, fd, buffer, len);
 }
 
-int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
-                      enum protection_level level)
+int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn,
+                      char *buffer, enum protection_level level)
 {
   /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
      int */
@@ -692,6 +694,8 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
   size_t decoded_sz = 0;
   CURLcode error;
 
+  (void) data;
+
   if(!conn->mech)
     /* not inititalized, return error */
     return -1;
@@ -717,7 +721,7 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
 
   {
     buf[decoded_len] = '\n';
-    Curl_debug(conn->data, CURLINFO_HEADER_IN, buf, decoded_len + 1);
+    Curl_debug(data, CURLINFO_HEADER_IN, buf, decoded_len + 1);
   }
 
   buf[decoded_len] = '\0';
@@ -736,16 +740,17 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
   return ret_code;
 }
 
-static int sec_set_protection_level(struct connectdata *conn)
+static int sec_set_protection_level(struct Curl_easy *data)
 {
   int code;
+  struct connectdata *conn = data->conn;
   enum protection_level level = conn->request_data_prot;
 
   DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
 
   if(!conn->sec_complete) {
-    infof(conn->data, "Trying to change the protection level after the"
-                      " completion of the data exchange.\n");
+    infof(data, "Trying to change the protection level after the"
+                " completion of the data exchange.\n");
     return -1;
   }
 
@@ -757,17 +762,17 @@ static int sec_set_protection_level(struct connectdata *conn)
     char *pbsz;
     static unsigned int buffer_size = 1 << 20; /* 1048576 */
 
-    code = ftp_send_command(conn, "PBSZ %u", buffer_size);
+    code = ftp_send_command(data, "PBSZ %u", buffer_size);
     if(code < 0)
       return -1;
 
     if(code/100 != 2) {
-      failf(conn->data, "Failed to set the protection's buffer size.");
+      failf(data, "Failed to set the protection's buffer size.");
       return -1;
     }
     conn->buffer_size = buffer_size;
 
-    pbsz = strstr(conn->data->state.buffer, "PBSZ=");
+    pbsz = strstr(data->state.buffer, "PBSZ=");
     if(pbsz) {
       /* ignore return code, use default value if it fails */
       (void)sscanf(pbsz, "PBSZ=%u", &buffer_size);
@@ -777,13 +782,13 @@ static int sec_set_protection_level(struct connectdata *conn)
   }
 
   /* Now try to negiociate the protection level. */
-  code = ftp_send_command(conn, "PROT %c", level_to_char(level));
+  code = ftp_send_command(data, "PROT %c", level_to_char(level));
 
   if(code < 0)
     return -1;
 
   if(code/100 != 2) {
-    failf(conn->data, "Failed to set the protection level.");
+    failf(data, "Failed to set the protection level.");
     return -1;
   }
 
@@ -805,10 +810,9 @@ Curl_sec_request_prot(struct connectdata *conn, const char *level)
   return 0;
 }
 
-static CURLcode choose_mech(struct connectdata *conn)
+static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
 {
   int ret;
-  struct Curl_easy *data = conn->data;
   void *tmp_allocation;
   const struct Curl_sec_client_mech *mech = &Curl_krb5_client_mech;
 
@@ -830,7 +834,7 @@ static CURLcode choose_mech(struct connectdata *conn)
   }
 
   infof(data, "Trying mechanism %s...\n", mech->name);
-  ret = ftp_send_command(conn, "AUTH %s", mech->name);
+  ret = ftp_send_command(data, "AUTH %s", mech->name);
   if(ret < 0)
     return CURLE_COULDNT_CONNECT;
 
@@ -855,7 +859,7 @@ static CURLcode choose_mech(struct connectdata *conn)
   }
 
   /* Authenticate */
-  ret = mech->auth(conn->app_data, conn);
+  ret = mech->auth(conn->app_data, data, conn);
 
   if(ret != AUTH_CONTINUE) {
     if(ret != AUTH_OK) {
@@ -873,16 +877,16 @@ static CURLcode choose_mech(struct connectdata *conn)
     conn->command_prot = PROT_SAFE;
     /* Set the requested protection level */
     /* BLOCKING */
-    (void)sec_set_protection_level(conn);
+    (void)sec_set_protection_level(data);
   }
 
   return CURLE_OK;
 }
 
 CURLcode
-Curl_sec_login(struct connectdata *conn)
+Curl_sec_login(struct Curl_easy *data, struct connectdata *conn)
 {
-  return choose_mech(conn);
+  return choose_mech(data, conn);
 }
 
 

+ 40 - 38
lib/ldap.c

@@ -5,7 +5,7 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -100,7 +100,8 @@ struct ldap_urldesc {
 #undef LDAPURLDesc
 #define LDAPURLDesc struct ldap_urldesc
 
-static int  _ldap_url_parse(const struct connectdata *conn,
+static int  _ldap_url_parse(struct Curl_easy *data,
+                            const struct connectdata *conn,
                             LDAPURLDesc **ludp);
 static void _ldap_free_urldesc(LDAPURLDesc *ludp);
 
@@ -126,7 +127,7 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp);
 #endif
 
 
-static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
+static CURLcode ldap_do(struct Curl_easy *data, bool *done);
 
 /*
  * LDAP protocol handler.
@@ -135,7 +136,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
 const struct Curl_handler Curl_handler_ldap = {
   "LDAP",                               /* scheme */
   ZERO_NULL,                            /* setup_connection */
-  Curl_ldap,                            /* do_it */
+  ldap_do,                              /* do_it */
   ZERO_NULL,                            /* done */
   ZERO_NULL,                            /* do_more */
   ZERO_NULL,                            /* connect_it */
@@ -162,7 +163,7 @@ const struct Curl_handler Curl_handler_ldap = {
 const struct Curl_handler Curl_handler_ldaps = {
   "LDAPS",                              /* scheme */
   ZERO_NULL,                            /* setup_connection */
-  Curl_ldap,                            /* do_it */
+  ldap_do,                              /* do_it */
   ZERO_NULL,                            /* done */
   ZERO_NULL,                            /* do_more */
   ZERO_NULL,                            /* connect_it */
@@ -232,7 +233,7 @@ static int ldap_win_bind_auth(LDAP *server, const char *user,
 }
 #endif /* #if defined(USE_WINDOWS_SSPI) */
 
-static int ldap_win_bind(struct connectdata *conn, LDAP *server,
+static int ldap_win_bind(struct Curl_easy *data, LDAP *server,
                          const char *user, const char *passwd)
 {
   int rc = LDAP_INVALID_CREDENTIALS;
@@ -240,7 +241,7 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
   PTCHAR inuser = NULL;
   PTCHAR inpass = NULL;
 
-  if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) {
+  if(user && passwd && (data->set.httpauth & CURLAUTH_BASIC)) {
     inuser = curlx_convert_UTF8_to_tchar((char *) user);
     inpass = curlx_convert_UTF8_to_tchar((char *) passwd);
 
@@ -251,7 +252,7 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
   }
 #if defined(USE_WINDOWS_SSPI)
   else {
-    rc = ldap_win_bind_auth(server, user, passwd, conn->data->set.httpauth);
+    rc = ldap_win_bind_auth(server, user, passwd, data->set.httpauth);
   }
 #endif
 
@@ -266,7 +267,7 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
 #endif
 
 
-static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
+static CURLcode ldap_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
   int rc = 0;
@@ -275,7 +276,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
   LDAPMessage *ldapmsg = NULL;
   LDAPMessage *entryIterator;
   int num = 0;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   int ldap_proto = LDAP_VERSION3;
   int ldap_ssl = 0;
   char *val_b64 = NULL;
@@ -300,7 +301,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
 #ifdef HAVE_LDAP_URL_PARSE
   rc = ldap_url_parse(data->change.url, &ludp);
 #else
-  rc = _ldap_url_parse(conn, &ludp);
+  rc = _ldap_url_parse(data, conn, &ludp);
 #endif
   if(rc != 0) {
     failf(data, "LDAP local: %s", ldap_err2string(rc));
@@ -472,7 +473,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
   }
 #ifdef USE_WIN32_LDAP
   ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
-  rc = ldap_win_bind(conn, server, user, passwd);
+  rc = ldap_win_bind(data, server, user, passwd);
 #else
   rc = ldap_simple_bind_s(server, user, passwd);
 #endif
@@ -480,7 +481,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
     ldap_proto = LDAP_VERSION2;
     ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
 #ifdef USE_WIN32_LDAP
-    rc = ldap_win_bind(conn, server, user, passwd);
+    rc = ldap_win_bind(data, server, user, passwd);
 #else
     rc = ldap_simple_bind_s(server, user, passwd);
 #endif
@@ -536,14 +537,14 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
 #endif
       name_len = strlen(name);
 
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
       if(result) {
         FREE_ON_WINLDAP(name);
         ldap_memfree(dn);
         goto quit;
       }
 
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name,
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) name,
                                  name_len);
       if(result) {
         FREE_ON_WINLDAP(name);
@@ -551,7 +552,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
         goto quit;
       }
 
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
       if(result) {
         FREE_ON_WINLDAP(name);
         ldap_memfree(dn);
@@ -589,7 +590,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
       vals = ldap_get_values_len(server, entryIterator, attribute);
       if(vals != NULL) {
         for(i = 0; (vals[i] != NULL); i++) {
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
           if(result) {
             ldap_value_free_len(vals);
             FREE_ON_WINLDAP(attr);
@@ -600,7 +601,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             goto quit;
           }
 
-          result = Curl_client_write(conn, CLIENTWRITE_BODY,
+          result = Curl_client_write(data, CLIENTWRITE_BODY,
                                      (char *) attr, attr_len);
           if(result) {
             ldap_value_free_len(vals);
@@ -612,7 +613,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             goto quit;
           }
 
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
           if(result) {
             ldap_value_free_len(vals);
             FREE_ON_WINLDAP(attr);
@@ -644,7 +645,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             }
 
             if(val_b64_sz > 0) {
-              result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
+              result = Curl_client_write(data, CLIENTWRITE_BODY, val_b64,
                                          val_b64_sz);
               free(val_b64);
               if(result) {
@@ -661,7 +662,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             }
           }
           else {
-            result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
+            result = Curl_client_write(data, CLIENTWRITE_BODY, vals[i]->bv_val,
                                        vals[i]->bv_len);
             if(result) {
               ldap_value_free_len(vals);
@@ -676,7 +677,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
             dlsize += vals[i]->bv_len;
           }
 
-          result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+          result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
           if(result) {
             ldap_value_free_len(vals);
             FREE_ON_WINLDAP(attr);
@@ -698,7 +699,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
       FREE_ON_WINLDAP(attr);
       ldap_memfree(attribute);
 
-      result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+      result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
       if(result)
         goto quit;
       dlsize++;
@@ -812,14 +813,15 @@ static bool split_str(char *str, char ***out, size_t *count)
  *
  * <hostname> already known from 'conn->host.name'.
  * <port>     already known from 'conn->remote_port'.
- * extract the rest from 'conn->data->state.path+1'. All fields are optional.
+ * extract the rest from 'data->state.path+1'. All fields are optional.
  * e.g.
  *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
  * yields ludp->lud_dn = "".
  *
  * Defined in RFC4516 section 2.
  */
-static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
+static int _ldap_url_parse2(struct Curl_easy *data,
+                            const struct connectdata *conn, LDAPURLDesc *ludp)
 {
   int rc = LDAP_SUCCESS;
   char *p;
@@ -828,10 +830,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
   char *query = NULL;
   size_t i;
 
-  if(!conn->data ||
-     !conn->data->state.up.path ||
-     conn->data->state.up.path[0] != '/' ||
-     !strncasecompare("LDAP", conn->data->state.up.scheme, 4))
+  if(!data ||
+     !data->state.up.path ||
+     data->state.up.path[0] != '/' ||
+     !strncasecompare("LDAP", data->state.up.scheme, 4))
     return LDAP_INVALID_SYNTAX;
 
   ludp->lud_scope = LDAP_SCOPE_BASE;
@@ -839,13 +841,13 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
   ludp->lud_host  = conn->host.name;
 
   /* Duplicate the path */
-  p = path = strdup(conn->data->state.up.path + 1);
+  p = path = strdup(data->state.up.path + 1);
   if(!path)
     return LDAP_NO_MEMORY;
 
   /* Duplicate the query if present */
-  if(conn->data->state.up.query) {
-    q = query = strdup(conn->data->state.up.query);
+  if(data->state.up.query) {
+    q = query = strdup(data->state.up.query);
     if(!query) {
       free(path);
       return LDAP_NO_MEMORY;
@@ -861,7 +863,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
     LDAP_TRACE(("DN '%s'\n", dn));
 
     /* Unescape the DN */
-    result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, REJECT_ZERO);
+    result = Curl_urldecode(data, dn, 0, &unescaped, NULL, REJECT_ZERO);
     if(result) {
       rc = LDAP_NO_MEMORY;
 
@@ -926,7 +928,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
       LDAP_TRACE(("attr[%zu] '%s'\n", i, attributes[i]));
 
       /* Unescape the attribute */
-      result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL,
+      result = Curl_urldecode(data, attributes[i], 0, &unescaped, NULL,
                               REJECT_ZERO);
       if(result) {
         free(attributes);
@@ -996,8 +998,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
     LDAP_TRACE(("filter '%s'\n", filter));
 
     /* Unescape the filter */
-    result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL,
-                            REJECT_ZERO);
+    result = Curl_urldecode(data, filter, 0, &unescaped, NULL, REJECT_ZERO);
     if(result) {
       rc = LDAP_NO_MEMORY;
 
@@ -1035,7 +1036,8 @@ quit:
   return rc;
 }
 
-static int _ldap_url_parse(const struct connectdata *conn,
+static int _ldap_url_parse(struct Curl_easy *data,
+                           const struct connectdata *conn,
                            LDAPURLDesc **ludpp)
 {
   LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
@@ -1045,7 +1047,7 @@ static int _ldap_url_parse(const struct connectdata *conn,
   if(!ludp)
      return LDAP_NO_MEMORY;
 
-  rc = _ldap_url_parse2(conn, ludp);
+  rc = _ldap_url_parse2(data, conn, ludp);
   if(rc != LDAP_SUCCESS) {
     _ldap_free_urldesc(ludp);
     ludp = NULL;

+ 2 - 1
lib/mime.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -1168,6 +1168,7 @@ static void cleanup_part_content(curl_mimepart *part)
   part->kind = MIMEKIND_NONE;
   part->flags &= ~MIME_FAST_READ;
   part->lastreadstatus = 1; /* Successful read status. */
+  part->state.state = MIMESTATE_BEGIN;
 }
 
 static void mime_subparts_free(void *ptr)

+ 2 - 2
lib/mime.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -110,6 +110,7 @@ struct curl_mimepart {
   curl_mime *parent;               /* Parent mime structure. */
   curl_mimepart *nextpart;         /* Forward linked list. */
   enum mimekind kind;              /* The part kind. */
+  unsigned int flags;              /* Flags. */
   char *data;                      /* Memory data or file name. */
   curl_read_callback readfunc;     /* Read function. */
   curl_seek_callback seekfunc;     /* Seek function. */
@@ -122,7 +123,6 @@ struct curl_mimepart {
   char *filename;                  /* Remote file name. */
   char *name;                      /* Data name. */
   curl_off_t datasize;             /* Expected data size. */
-  unsigned int flags;              /* Flags. */
   struct mime_state state;         /* Current readback state. */
   const struct mime_encoder *encoder; /* Content data encoder. */
   struct mime_encoder_state encstate; /* Data encoder state. */

+ 83 - 70
lib/mqtt.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2020 - 2021, 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
@@ -59,10 +59,12 @@
  * Forward declarations.
  */
 
-static CURLcode mqtt_do(struct connectdata *conn, bool *done);
-static CURLcode mqtt_doing(struct connectdata *conn, bool *done);
-static int mqtt_getsock(struct connectdata *conn, curl_socket_t *sock);
-static CURLcode mqtt_setup_conn(struct connectdata *conn);
+static CURLcode mqtt_do(struct Curl_easy *data, bool *done);
+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);
+static CURLcode mqtt_setup_conn(struct Curl_easy *data,
+                                struct connectdata *conn);
 
 /*
  * MQTT protocol handler.
@@ -90,12 +92,13 @@ const struct Curl_handler Curl_handler_mqtt = {
   PROTOPT_NONE                        /* flags */
 };
 
-static CURLcode mqtt_setup_conn(struct connectdata *conn)
+static CURLcode mqtt_setup_conn(struct Curl_easy *data,
+                                struct connectdata *conn)
 {
   /* allocate the HTTP-specific struct for the Curl_easy, only to survive
      during this request */
   struct MQTT *mq;
-  struct Curl_easy *data = conn->data;
+  (void)conn;
   DEBUGASSERT(data->req.p.mqtt == NULL);
 
   mq = calloc(1, sizeof(struct MQTT));
@@ -105,15 +108,15 @@ static CURLcode mqtt_setup_conn(struct connectdata *conn)
   return CURLE_OK;
 }
 
-static CURLcode mqtt_send(struct connectdata *conn,
+static CURLcode mqtt_send(struct Curl_easy *data,
                           char *buf, size_t len)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
-  struct Curl_easy *data = conn->data;
   struct MQTT *mq = data->req.p.mqtt;
   ssize_t n;
-  result = Curl_write(conn, sockfd, buf, len, &n);
+  result = Curl_write(data, sockfd, buf, len, &n);
   if(!result)
     Curl_debug(data, CURLINFO_HEADER_OUT, buf, (size_t)n);
   if(len != (size_t)n) {
@@ -130,14 +133,16 @@ static CURLcode mqtt_send(struct connectdata *conn,
 /* Generic function called by the multi interface to figure out what socket(s)
    to wait for and for what actions during the DOING and PROTOCONNECT
    states */
-static int mqtt_getsock(struct connectdata *conn,
+static int mqtt_getsock(struct Curl_easy *data,
+                        struct connectdata *conn,
                         curl_socket_t *sock)
 {
+  (void)data;
   sock[0] = conn->sock[FIRSTSOCKET];
   return GETSOCK_READSOCK(FIRSTSOCKET);
 }
 
-static CURLcode mqtt_connect(struct connectdata *conn)
+static CURLcode mqtt_connect(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
   const size_t client_id_offset = 14;
@@ -157,31 +162,31 @@ static CURLcode mqtt_connect(struct connectdata *conn)
   packet[1] = (packetlen - 2) & 0x7f;
   packet[client_id_offset - 1] = MQTT_CLIENTID_LEN;
 
-  result = Curl_rand_hex(conn->data, (unsigned char *)&client_id[clen],
+  result = Curl_rand_hex(data, (unsigned char *)&client_id[clen],
                          MQTT_CLIENTID_LEN - clen + 1);
   memcpy(&packet[client_id_offset], client_id, MQTT_CLIENTID_LEN);
-  infof(conn->data, "Using client id '%s'\n", client_id);
+  infof(data, "Using client id '%s'\n", client_id);
   if(!result)
-    result = mqtt_send(conn, packet, packetlen);
+    result = mqtt_send(data, packet, packetlen);
   return result;
 }
 
-static CURLcode mqtt_disconnect(struct connectdata *conn)
+static CURLcode mqtt_disconnect(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
-  result = mqtt_send(conn, (char *)"\xe0\x00", 2);
+  result = mqtt_send(data, (char *)"\xe0\x00", 2);
   return result;
 }
 
-static CURLcode mqtt_verify_connack(struct connectdata *conn)
+static CURLcode mqtt_verify_connack(struct Curl_easy *data)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   unsigned char readbuf[MQTT_CONNACK_LEN];
   ssize_t nread;
-  struct Curl_easy *data = conn->data;
 
-  result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread);
+  result = Curl_read(data, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread);
   if(result)
     goto fail;
 
@@ -204,18 +209,18 @@ fail:
   return result;
 }
 
-static CURLcode mqtt_get_topic(struct connectdata *conn,
+static CURLcode mqtt_get_topic(struct Curl_easy *data,
                                char **topic, size_t *topiclen)
 {
   CURLcode result = CURLE_OK;
-  char *path = conn->data->state.up.path;
+  char *path = data->state.up.path;
 
   if(strlen(path) > 1) {
-    result = Curl_urldecode(conn->data, path + 1, 0, topic, topiclen,
+    result = Curl_urldecode(data, path + 1, 0, topic, topiclen,
                             REJECT_NADA);
   }
   else {
-    failf(conn->data, "Error: No topic specified.");
+    failf(data, "Error: No topic specified.");
     result = CURLE_URL_MALFORMAT;
   }
   return result;
@@ -238,7 +243,7 @@ static int mqtt_encode_len(char *buf, size_t len)
   return i;
 }
 
-static CURLcode mqtt_subscribe(struct connectdata *conn)
+static CURLcode mqtt_subscribe(struct Curl_easy *data)
 {
   CURLcode result = CURLE_OK;
   char *topic = NULL;
@@ -247,8 +252,9 @@ static CURLcode mqtt_subscribe(struct connectdata *conn)
   size_t packetlen;
   char encodedsize[4];
   size_t n;
+  struct connectdata *conn = data->conn;
 
-  result = mqtt_get_topic(conn, &topic, &topiclen);
+  result = mqtt_get_topic(data, &topic, &topiclen);
   if(result)
     goto fail;
 
@@ -274,7 +280,7 @@ static CURLcode mqtt_subscribe(struct connectdata *conn)
   memcpy(&packet[5 + n], topic, topiclen);
   packet[5 + n + topiclen] = 0; /* QoS zero */
 
-  result = mqtt_send(conn, (char *)packet, packetlen);
+  result = mqtt_send(data, (char *)packet, packetlen);
 
 fail:
   free(topic);
@@ -285,19 +291,20 @@ fail:
 /*
  * Called when the first byte was already read.
  */
-static CURLcode mqtt_verify_suback(struct connectdata *conn)
+static CURLcode mqtt_verify_suback(struct Curl_easy *data)
 {
   CURLcode result;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   unsigned char readbuf[MQTT_SUBACK_LEN];
   ssize_t nread;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
 
-  result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_SUBACK_LEN, &nread);
+  result = Curl_read(data, sockfd, (char *)readbuf, MQTT_SUBACK_LEN, &nread);
   if(result)
     goto fail;
 
-  Curl_debug(conn->data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread);
+  Curl_debug(data, CURLINFO_HEADER_IN, (char *)readbuf, (size_t)nread);
 
   /* fixme */
   if(nread < MQTT_SUBACK_LEN) {
@@ -315,11 +322,11 @@ fail:
   return result;
 }
 
-static CURLcode mqtt_publish(struct connectdata *conn)
+static CURLcode mqtt_publish(struct Curl_easy *data)
 {
   CURLcode result;
-  char *payload = conn->data->set.postfields;
-  size_t payloadlen = (size_t)conn->data->set.postfieldsize;
+  char *payload = data->set.postfields;
+  size_t payloadlen;
   char *topic = NULL;
   size_t topiclen;
   unsigned char *pkt = NULL;
@@ -327,8 +334,16 @@ static CURLcode mqtt_publish(struct connectdata *conn)
   size_t remaininglength;
   size_t encodelen;
   char encodedbytes[4];
+  curl_off_t postfieldsize = data->set.postfieldsize;
+
+  if(!payload)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+  if(postfieldsize < 0)
+    payloadlen = strlen(payload);
+  else
+    payloadlen = (size_t)postfieldsize;
 
-  result = mqtt_get_topic(conn, &topic, &topiclen);
+  result = mqtt_get_topic(data, &topic, &topiclen);
   if(result)
     goto fail;
 
@@ -352,7 +367,7 @@ static CURLcode mqtt_publish(struct connectdata *conn)
   i += topiclen;
   memcpy(&pkt[i], payload, payloadlen);
   i += payloadlen;
-  result = mqtt_send(conn, (char *)pkt, i);
+  result = mqtt_send(data, (char *)pkt, i);
 
 fail:
   free(pkt);
@@ -395,13 +410,14 @@ static const char *statenames[]={
 #endif
 
 /* The only way to change state */
-static void mqstate(struct connectdata *conn,
+static void mqstate(struct Curl_easy *data,
                     enum mqttstate state,
                     enum mqttstate nextstate) /* used if state == FIRST */
 {
+  struct connectdata *conn = data->conn;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
 #ifdef CURLDEBUG
-  infof(conn->data, "%s (from %s) (next is %s)\n",
+  infof(data, "%s (from %s) (next is %s)\n",
         statenames[state],
         statenames[mqtt->state],
         (state == MQTT_FIRST)? statenames[nextstate] : "");
@@ -415,13 +431,12 @@ static void mqstate(struct connectdata *conn,
 /* for the publish packet */
 #define MQTT_HEADER_LEN 5    /* max 5 bytes */
 
-static CURLcode mqtt_read_publish(struct connectdata *conn,
-                                  bool *done)
+static CURLcode mqtt_read_publish(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   ssize_t nread;
-  struct Curl_easy *data = conn->data;
   unsigned char *pkt = (unsigned char *)data->state.buffer;
   size_t remlen;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
@@ -431,11 +446,11 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
   switch(mqtt->state) {
   MQTT_SUBACK_COMING:
   case MQTT_SUBACK_COMING:
-    result = mqtt_verify_suback(conn);
+    result = mqtt_verify_suback(data);
     if(result)
       break;
 
-    mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT);
+    mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
     break;
 
   case MQTT_SUBACK:
@@ -443,9 +458,9 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
     /* we are expecting PUBLISH or SUBACK */
     packet = mq->firstbyte & 0xf0;
     if(packet == MQTT_MSG_PUBLISH)
-      mqstate(conn, MQTT_PUB_REMAIN, MQTT_NOSTATE);
+      mqstate(data, MQTT_PUB_REMAIN, MQTT_NOSTATE);
     else if(packet == MQTT_MSG_SUBACK) {
-      mqstate(conn, MQTT_SUBACK_COMING, MQTT_NOSTATE);
+      mqstate(data, MQTT_SUBACK_COMING, MQTT_NOSTATE);
       goto MQTT_SUBACK_COMING;
     }
     else if(packet == MQTT_MSG_DISCONNECT) {
@@ -472,7 +487,7 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
     size_t rest = mq->npacket;
     if(rest > (size_t)data->set.buffer_size)
       rest = (size_t)data->set.buffer_size;
-    result = Curl_read(conn, sockfd, (char *)pkt, rest, &nread);
+    result = Curl_read(data, sockfd, (char *)pkt, rest, &nread);
     if(result) {
       if(CURLE_AGAIN == result) {
         infof(data, "EEEE AAAAGAIN\n");
@@ -492,13 +507,13 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
 
     /* if QoS is set, message contains packet id */
 
-    result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)pkt, nread);
+    result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)pkt, nread);
     if(result)
       goto end;
 
     if(!mq->npacket)
       /* no more PUBLISH payload, back to subscribe wait state */
-      mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT);
+      mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
     break;
   }
   default:
@@ -510,27 +525,25 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
   return result;
 }
 
-static CURLcode mqtt_do(struct connectdata *conn, bool *done)
+static CURLcode mqtt_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
-  struct Curl_easy *data = conn->data;
-
   *done = FALSE; /* unconditionally */
 
-  result = mqtt_connect(conn);
+  result = mqtt_connect(data);
   if(result) {
     failf(data, "Error %d sending MQTT CONN request", result);
     return result;
   }
-  mqstate(conn, MQTT_FIRST, MQTT_CONNACK);
+  mqstate(data, MQTT_FIRST, MQTT_CONNACK);
   return CURLE_OK;
 }
 
-static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
+static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
   struct mqtt_conn *mqtt = &conn->proto.mqtt;
-  struct Curl_easy *data = conn->data;
   struct MQTT *mq = data->req.p.mqtt;
   ssize_t nread;
   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
@@ -542,7 +555,7 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
   if(mq->nsend) {
     /* send the remainder of an outgoing packet */
     char *ptr = mq->sendleftovers;
-    result = mqtt_send(conn, mq->sendleftovers, mq->nsend);
+    result = mqtt_send(data, mq->sendleftovers, mq->nsend);
     free(ptr);
     if(result)
       return result;
@@ -552,18 +565,18 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
   switch(mqtt->state) {
   case MQTT_FIRST:
     /* Read the initial byte only */
-    result = Curl_read(conn, sockfd, (char *)&mq->firstbyte, 1, &nread);
-    if(result)
+    result = Curl_read(data, sockfd, (char *)&mq->firstbyte, 1, &nread);
+    if(!nread)
       break;
     Curl_debug(data, CURLINFO_HEADER_IN, (char *)&mq->firstbyte, 1);
     /* remember the first byte */
     mq->npacket = 0;
-    mqstate(conn, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
+    mqstate(data, MQTT_REMAINING_LENGTH, MQTT_NOSTATE);
     /* FALLTHROUGH */
   case MQTT_REMAINING_LENGTH:
     do {
-      result = Curl_read(conn, sockfd, (char *)&byte, 1, &nread);
-      if(result)
+      result = Curl_read(data, sockfd, (char *)&byte, 1, &nread);
+      if(!nread)
         break;
       Curl_debug(data, CURLINFO_HEADER_IN, (char *)&byte, 1);
       pkt[mq->npacket++] = byte;
@@ -573,10 +586,10 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
     mq->remaining_length = mqtt_decode_len(&pkt[0], mq->npacket, NULL);
     mq->npacket = 0;
     if(mq->remaining_length) {
-      mqstate(conn, mqtt->nextstate, MQTT_NOSTATE);
+      mqstate(data, mqtt->nextstate, MQTT_NOSTATE);
       break;
     }
-    mqstate(conn, MQTT_FIRST, MQTT_FIRST);
+    mqstate(data, MQTT_FIRST, MQTT_FIRST);
 
     if(mq->firstbyte == MQTT_MSG_DISCONNECT) {
       infof(data, "Got DISCONNECT\n");
@@ -584,22 +597,22 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
     }
     break;
   case MQTT_CONNACK:
-    result = mqtt_verify_connack(conn);
+    result = mqtt_verify_connack(data);
     if(result)
       break;
 
-    if(conn->data->state.httpreq == HTTPREQ_POST) {
-      result = mqtt_publish(conn);
+    if(data->state.httpreq == HTTPREQ_POST) {
+      result = mqtt_publish(data);
       if(!result) {
-        result = mqtt_disconnect(conn);
+        result = mqtt_disconnect(data);
         *done = TRUE;
       }
       mqtt->nextstate = MQTT_FIRST;
     }
     else {
-      result = mqtt_subscribe(conn);
+      result = mqtt_subscribe(data);
       if(!result) {
-        mqstate(conn, MQTT_FIRST, MQTT_SUBACK);
+        mqstate(data, MQTT_FIRST, MQTT_SUBACK);
       }
     }
     break;
@@ -607,11 +620,11 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
   case MQTT_SUBACK:
   case MQTT_PUBWAIT:
   case MQTT_PUB_REMAIN:
-    result = mqtt_read_publish(conn, done);
+    result = mqtt_read_publish(data, done);
     break;
 
   default:
-    failf(conn->data, "State not handled yet");
+    failf(data, "State not handled yet");
     *done = TRUE;
     break;
   }

+ 107 - 110
lib/multi.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -69,7 +69,7 @@
 #define CURL_MULTI_HANDLE 0x000bab1e
 
 #define GOOD_MULTI_HANDLE(x) \
-  ((x) && (x)->type == CURL_MULTI_HANDLE)
+  ((x) && (x)->magic == CURL_MULTI_HANDLE)
 
 static CURLMcode singlesocket(struct Curl_multi *multi,
                               struct Curl_easy *data);
@@ -105,7 +105,14 @@ static const char * const statename[]={
 /* function pointer called once when switching TO a state */
 typedef void (*init_multistate_func)(struct Curl_easy *data);
 
-static void Curl_init_completed(struct Curl_easy *data)
+/* called when the PERFORM state starts  */
+static void init_perform(struct Curl_easy *data)
+{
+  data->req.chunk = FALSE;
+  Curl_pgrsTime(data, TIMER_PRETRANSFER);
+}
+
+static void init_completed(struct Curl_easy *data)
 {
   /* this is a completed transfer */
 
@@ -136,10 +143,10 @@ static void mstate(struct Curl_easy *data, CURLMstate state
     NULL,              /* DOING */
     NULL,              /* DO_MORE */
     NULL,              /* DO_DONE */
-    NULL,              /* PERFORM */
+    init_perform,      /* PERFORM */
     NULL,              /* TOOFAST */
     NULL,              /* DONE */
-    Curl_init_completed, /* COMPLETED */
+    init_completed,    /* COMPLETED */
     NULL               /* MSGSENT */
   };
 
@@ -193,8 +200,8 @@ struct Curl_sh_entry {
   struct Curl_hash transfers; /* hash of transfers using this socket */
   unsigned int action;  /* what combined action READ/WRITE this socket waits
                            for */
-  void *socketp; /* settable by users with curl_multi_assign() */
   unsigned int users; /* number of transfers using this */
+  void *socketp; /* settable by users with curl_multi_assign() */
   unsigned int readers; /* this many transfers want to read */
   unsigned int writers; /* this many transfers want to write */
 };
@@ -353,7 +360,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
   if(!multi)
     return NULL;
 
-  multi->type = CURL_MULTI_HANDLE;
+  multi->magic = CURL_MULTI_HANDLE;
 
   if(Curl_mk_dnscache(&multi->hostcache))
     goto error;
@@ -558,7 +565,7 @@ static CURLcode multi_done(struct Curl_easy *data,
   conn->data = data; /* ensure the connection uses this transfer now */
 
   /* Stop the resolver and free its own resources (but not dns_entry yet). */
-  Curl_resolver_kill(conn);
+  Curl_resolver_kill(data);
 
   /* Cleanup possible redirect junk */
   Curl_safefree(data->req.newurl);
@@ -579,14 +586,14 @@ static CURLcode multi_done(struct Curl_easy *data,
 
   /* this calls the protocol-specific function pointer previously set */
   if(conn->handler->done)
-    result = conn->handler->done(conn, status, premature);
+    result = conn->handler->done(data, status, premature);
   else
     result = status;
 
   if(CURLE_ABORTED_BY_CALLBACK != result) {
     /* avoid this if we already aborted by callback to avoid this calling
        another callback */
-    CURLcode rc = Curl_pgrsDone(conn);
+    CURLcode rc = Curl_pgrsDone(data);
     if(!result && rc)
       result = CURLE_ABORTED_BY_CALLBACK;
   }
@@ -690,17 +697,13 @@ static CURLcode multi_done(struct Curl_easy *data,
   return result;
 }
 
-static int close_connect_only(struct connectdata *conn, void *param)
+static int close_connect_only(struct Curl_easy *data,
+                              struct connectdata *conn, void *param)
 {
-  struct Curl_easy *data = param;
-
+  (void)param;
   if(data->state.lastconnect_id != conn->connection_id)
     return 0;
 
-  if(conn->data != data)
-    return 1;
-  conn->data = NULL;
-
   if(!conn->bits.connect_only)
     return 1;
 
@@ -809,7 +812,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
   if(data->state.lastconnect_id != -1) {
     /* Mark any connect-only connection for closure */
     Curl_conncache_foreach(data, data->state.conn_cache,
-                           data, &close_connect_only);
+                           NULL, close_connect_only);
   }
 
 #ifdef USE_LIBPSL
@@ -938,27 +941,30 @@ static int waitproxyconnect_getsock(struct connectdata *conn,
   return GETSOCK_WRITESOCK(0);
 }
 
-static int domore_getsock(struct connectdata *conn,
+static int domore_getsock(struct Curl_easy *data,
+                          struct connectdata *conn,
                           curl_socket_t *socks)
 {
   if(conn && conn->handler->domore_getsock)
-    return conn->handler->domore_getsock(conn, socks);
+    return conn->handler->domore_getsock(data, conn, socks);
   return GETSOCK_BLANK;
 }
 
-static int doing_getsock(struct connectdata *conn,
+static int doing_getsock(struct Curl_easy *data,
+                         struct connectdata *conn,
                          curl_socket_t *socks)
 {
   if(conn && conn->handler->doing_getsock)
-    return conn->handler->doing_getsock(conn, socks);
+    return conn->handler->doing_getsock(data, conn, socks);
   return GETSOCK_BLANK;
 }
 
-static int protocol_getsock(struct connectdata *conn,
+static int protocol_getsock(struct Curl_easy *data,
+                            struct connectdata *conn,
                             curl_socket_t *socks)
 {
   if(conn->handler->proto_getsock)
-    return conn->handler->proto_getsock(conn, socks);
+    return conn->handler->proto_getsock(data, conn, socks);
   /* Backup getsock logic. Since there is a live socket in use, we must wait
      for it or it will be removed from watching when the multi_socket API is
      used. */
@@ -971,10 +977,11 @@ static int protocol_getsock(struct connectdata *conn,
 static int multi_getsock(struct Curl_easy *data,
                          curl_socket_t *socks)
 {
+  struct connectdata *conn = data->conn;
   /* The no connection case can happen when this is called from
      curl_multi_remove_handle() => singlesocket() => multi_getsock().
   */
-  if(!data->conn)
+  if(!conn)
     return 0;
 
   if(data->mstate > CURLM_STATE_CONNECT &&
@@ -988,30 +995,30 @@ static int multi_getsock(struct Curl_easy *data,
     return 0;
 
   case CURLM_STATE_WAITRESOLVE:
-    return Curl_resolv_getsock(data->conn, socks);
+    return Curl_resolv_getsock(data, socks);
 
   case CURLM_STATE_PROTOCONNECT:
   case CURLM_STATE_SENDPROTOCONNECT:
-    return protocol_getsock(data->conn, socks);
+    return protocol_getsock(data, conn, socks);
 
   case CURLM_STATE_DO:
   case CURLM_STATE_DOING:
-    return doing_getsock(data->conn, socks);
+    return doing_getsock(data, conn, socks);
 
   case CURLM_STATE_WAITPROXYCONNECT:
-    return waitproxyconnect_getsock(data->conn, socks);
+    return waitproxyconnect_getsock(conn, socks);
 
   case CURLM_STATE_WAITCONNECT:
-    return waitconnect_getsock(data->conn, socks);
+    return waitconnect_getsock(conn, socks);
 
   case CURLM_STATE_DO_MORE:
-    return domore_getsock(data->conn, socks);
+    return domore_getsock(data, conn, socks);
 
   case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
                                to waiting for the same as the *PERFORM
                                states */
   case CURLM_STATE_PERFORM:
-    return Curl_single_getsock(data->conn, socks);
+    return Curl_single_getsock(data, conn, socks);
   }
 
 }
@@ -1067,13 +1074,13 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
 
 #define NUM_POLLS_ON_STACK 10
 
-static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
-                                 struct curl_waitfd extra_fds[],
-                                 unsigned int extra_nfds,
-                                 int timeout_ms,
-                                 int *ret,
-                                 bool extrawait, /* when no socket, wait */
-                                 bool use_wakeup)
+static CURLMcode multi_wait(struct Curl_multi *multi,
+                            struct curl_waitfd extra_fds[],
+                            unsigned int extra_nfds,
+                            int timeout_ms,
+                            int *ret,
+                            bool extrawait, /* when no socket, wait */
+                            bool use_wakeup)
 {
   struct Curl_easy *data;
   curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
@@ -1281,8 +1288,8 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
                           int timeout_ms,
                           int *ret)
 {
-  return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
-                         FALSE);
+  return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, FALSE,
+                    FALSE);
 }
 
 CURLMcode curl_multi_poll(struct Curl_multi *multi,
@@ -1291,8 +1298,8 @@ CURLMcode curl_multi_poll(struct Curl_multi *multi,
                           int timeout_ms,
                           int *ret)
 {
-  return Curl_multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
-                         TRUE);
+  return multi_wait(multi, extra_fds, extra_nfds, timeout_ms, ret, TRUE,
+                    TRUE);
 }
 
 CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
@@ -1319,7 +1326,7 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
 
          The write socket is set to non-blocking, this way this function
          cannot block, making it safe to call even from the same thread
-         that will call Curl_multi_wait(). If swrite() returns that it
+         that will call curl_multi_wait(). If swrite() returns that it
          would block, it's considered successful because it means that
          previous calls to this function will wake up the poll(). */
       if(swrite(multi->wakeup_pair[1], buf, sizeof(buf)) < 0) {
@@ -1383,18 +1390,6 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
   return rc;
 }
 
-/*
- * do_complete is called when the DO actions are complete.
- *
- * We init chunking and trailer bits to their default values here immediately
- * before receiving any header data for the current request.
- */
-static void do_complete(struct connectdata *conn)
-{
-  conn->data->req.chunk = FALSE;
-  Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
-}
-
 static CURLcode multi_do(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
@@ -1404,14 +1399,10 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
   DEBUGASSERT(conn->handler);
   DEBUGASSERT(conn->data == data);
 
-  if(conn->handler->do_it) {
+  if(conn->handler->do_it)
     /* generic protocol-specific function pointer set in curl_connect() */
-    result = conn->handler->do_it(conn, done);
+    result = conn->handler->do_it(data, done);
 
-    if(!result && *done)
-      /* do_complete must be called after the protocol-specific DO function */
-      do_complete(conn);
-  }
   return result;
 }
 
@@ -1424,18 +1415,15 @@ static CURLcode multi_do(struct Curl_easy *data, bool *done)
  * DOING state there's more work to do!
  */
 
-static CURLcode multi_do_more(struct connectdata *conn, int *complete)
+static CURLcode multi_do_more(struct Curl_easy *data, int *complete)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   *complete = 0;
 
   if(conn->handler->do_more)
-    result = conn->handler->do_more(conn, complete);
-
-  if(!result && (*complete == 1))
-    /* do_complete must be called after the protocol-specific DO function */
-    do_complete(conn);
+    result = conn->handler->do_more(data, complete);
 
   return result;
 }
@@ -1446,14 +1434,14 @@ static CURLcode multi_do_more(struct connectdata *conn, int *complete)
  * protocol layer.
  */
 
-static CURLcode protocol_connecting(struct connectdata *conn,
-                                    bool *done)
+static CURLcode protocol_connecting(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   if(conn && conn->handler->connecting) {
     *done = FALSE;
-    result = conn->handler->connecting(conn, done);
+    result = conn->handler->connecting(data, done);
   }
   else
     *done = TRUE;
@@ -1466,13 +1454,14 @@ static CURLcode protocol_connecting(struct connectdata *conn,
  * until the DOING phase is done on protocol layer.
  */
 
-static CURLcode protocol_doing(struct connectdata *conn, bool *done)
+static CURLcode protocol_doing(struct Curl_easy *data, bool *done)
 {
   CURLcode result = CURLE_OK;
+  struct connectdata *conn = data->conn;
 
   if(conn && conn->handler->doing) {
     *done = FALSE;
-    result = conn->handler->doing(conn, done);
+    result = conn->handler->doing(data, done);
   }
   else
     *done = TRUE;
@@ -1485,11 +1474,11 @@ static CURLcode protocol_doing(struct connectdata *conn, bool *done)
  * proceed with some action.
  *
  */
-static CURLcode protocol_connect(struct connectdata *conn,
+static CURLcode protocol_connect(struct Curl_easy *data,
                                  bool *protocol_done)
 {
   CURLcode result = CURLE_OK;
-
+  struct connectdata *conn = data->conn;
   DEBUGASSERT(conn);
   DEBUGASSERT(protocol_done);
 
@@ -1510,7 +1499,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
 
   if(!conn->bits.protoconnstart) {
 #ifndef CURL_DISABLE_PROXY
-    result = Curl_proxy_connect(conn, FIRSTSOCKET);
+    result = Curl_proxy_connect(data, FIRSTSOCKET);
     if(result)
       return result;
 
@@ -1528,7 +1517,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
       /* is there a protocol-specific connect() procedure? */
 
       /* Call the protocol-specific connect function */
-      result = conn->handler->connect_it(conn, protocol_done);
+      result = conn->handler->connect_it(data, protocol_done);
     }
     else
       *protocol_done = TRUE;
@@ -1589,9 +1578,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       process_pending_handles(multi); /* multiplexed */
     }
 
-    if(data->conn && data->mstate > CURLM_STATE_CONNECT &&
+    if(data->mstate > CURLM_STATE_CONNECT &&
        data->mstate < CURLM_STATE_COMPLETED) {
       /* Make sure we set the connection's current owner */
+      DEBUGASSERT(data->conn);
+      if(!data->conn)
+        return CURLM_INTERNAL_ERROR;
       data->conn->data = data;
     }
 
@@ -1737,19 +1729,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         hostname = conn->host.name;
 
       /* check if we have the name resolved by now */
-      dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
+      dns = Curl_fetch_addr(data, hostname, (int)conn->port);
 
       if(dns) {
 #ifdef CURLRES_ASYNCH
-        conn->async.dns = dns;
-        conn->async.done = TRUE;
+        data->state.async.dns = dns;
+        data->state.async.done = TRUE;
 #endif
         result = CURLE_OK;
         infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
       }
 
       if(!dns)
-        result = Curl_resolv_check(data->conn, &dns);
+        result = Curl_resolv_check(data, &dns);
 
       /* Update sockets here, because the socket(s) may have been
          closed and the application thus needs to be told, even if it
@@ -1762,7 +1754,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       if(dns) {
         /* Perform the next step in the connection phase, and then move on
            to the WAITCONNECT state */
-        result = Curl_once_resolved(data->conn, &protocol_connected);
+        result = Curl_once_resolved(data, &protocol_connected);
 
         if(result)
           /* if Curl_once_resolved() returns failure, the connection struct
@@ -1796,7 +1788,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     case CURLM_STATE_WAITPROXYCONNECT:
       /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
       DEBUGASSERT(data->conn);
-      result = Curl_http_connect(data->conn, &protocol_connected);
+      result = Curl_http_connect(data, &protocol_connected);
 #ifndef CURL_DISABLE_PROXY
       if(data->conn->bits.proxy_connect_closed) {
         rc = CURLM_CALL_MULTI_PERFORM;
@@ -1827,7 +1819,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     case CURLM_STATE_WAITCONNECT:
       /* awaiting a completion of an asynch TCP connect */
       DEBUGASSERT(data->conn);
-      result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
+      result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
       if(connected && !result) {
 #ifndef CURL_DISABLE_HTTP
         if(
@@ -1860,7 +1852,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       break;
 
     case CURLM_STATE_SENDPROTOCONNECT:
-      result = protocol_connect(data->conn, &protocol_connected);
+      result = protocol_connect(data, &protocol_connected);
       if(!result && !protocol_connected)
         /* switch to waiting state */
         multistate(data, CURLM_STATE_PROTOCONNECT);
@@ -1879,7 +1871,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
 
     case CURLM_STATE_PROTOCONNECT:
       /* protocol-specific connect phase */
-      result = protocol_connecting(data->conn, &protocol_connected);
+      result = protocol_connecting(data, &protocol_connected);
       if(!result && protocol_connected) {
         /* after the connect has completed, go WAITDO or DO */
         multistate(data, CURLM_STATE_DO);
@@ -1916,7 +1908,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
               if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
                 /* skip some states if it is important */
                 multi_done(data, CURLE_OK, FALSE);
-                multistate(data, CURLM_STATE_DONE);
+
+                /* if there's no connection left, skip the DONE state */
+                multistate(data, data->conn ?
+                           CURLM_STATE_DONE : CURLM_STATE_COMPLETED);
                 rc = CURLM_CALL_MULTI_PERFORM;
                 break;
               }
@@ -1952,7 +1947,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
           followtype follow = FOLLOW_NONE;
           CURLcode drc;
 
-          drc = Curl_retry_request(data->conn, &newurl);
+          drc = Curl_retry_request(data, &newurl);
           if(drc) {
             /* a failure here pretty much implies an out of memory */
             result = drc;
@@ -2002,7 +1997,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     case CURLM_STATE_DOING:
       /* we continue DOING until the DO phase is complete */
       DEBUGASSERT(data->conn);
-      result = protocol_doing(data->conn, &dophase_done);
+      result = protocol_doing(data, &dophase_done);
       if(!result) {
         if(dophase_done) {
           /* after DO, go DO_DONE or DO_MORE */
@@ -2025,7 +2020,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
        * When we are connected, DO MORE and then go DO_DONE
        */
       DEBUGASSERT(data->conn);
-      result = multi_do_more(data->conn, &control);
+      result = multi_do_more(data, &control);
 
       if(!result) {
         if(control) {
@@ -2074,12 +2069,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
     case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
       DEBUGASSERT(data->conn);
       /* if both rates are within spec, resume transfer */
-      if(Curl_pgrsUpdate(data->conn))
+      if(Curl_pgrsUpdate(data))
         result = CURLE_ABORTED_BY_CALLBACK;
       else
         result = Curl_speedcheck(data, *nowp);
 
-      if(!result) {
+      if(result) {
+        if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
+           result != CURLE_HTTP2_STREAM)
+          streamclose(data->conn, "Transfer returned error");
+
+        Curl_posttransfer(data);
+        multi_done(data, result, TRUE);
+      }
+      else {
         send_timeout_ms = 0;
         if(data->set.max_send_speed > 0)
           send_timeout_ms =
@@ -2151,7 +2154,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
          * condition and the server closed the re-used connection exactly when
          * we wanted to use it, so figure out if that is indeed the case.
          */
-        CURLcode ret = Curl_retry_request(data->conn, &newurl);
+        CURLcode ret = Curl_retry_request(data, &newurl);
         if(!ret)
           retry = (newurl)?TRUE:FALSE;
         else if(!result)
@@ -2166,7 +2169,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       }
       else if((CURLE_HTTP2_STREAM == result) &&
               Curl_h2_http_1_1_error(data->conn)) {
-        CURLcode ret = Curl_retry_request(data->conn, &newurl);
+        CURLcode ret = Curl_retry_request(data, &newurl);
 
         if(!ret) {
           infof(data, "Downgrades to HTTP/1.1!\n");
@@ -2203,7 +2206,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         multi_done(data, result, TRUE);
       }
       else if(done) {
-        followtype follow = FOLLOW_NONE;
 
         /* call this even if the readwrite function returned error */
         Curl_posttransfer(data);
@@ -2211,6 +2213,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         /* When we follow redirects or is set to retry the connection, we must
            to go back to the CONNECT state */
         if(data->req.newurl || retry) {
+          followtype follow = FOLLOW_NONE;
           if(!retry) {
             /* if the URL is a follow-location and not just a retried request
                then figure out the URL here */
@@ -2280,14 +2283,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         /* allow a previously set error code take precedence */
         if(!result)
           result = res;
-
-        /*
-         * If there are other handles on the connection, multi_done won't set
-         * conn to NULL.  In such a case, curl_multi_remove_handle() can
-         * access free'd data, if the connection is free'd and the handle
-         * removed before we perform the processing in CURLM_STATE_COMPLETED
-         */
-        Curl_detach_connnection(data);
       }
 
 #ifndef CURL_DISABLE_FTP
@@ -2357,7 +2352,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
         rc = CURLM_CALL_MULTI_PERFORM;
       }
       /* if there's still a connection to use, call the progress function */
-      else if(data->conn && Curl_pgrsUpdate(data->conn)) {
+      else if(data->conn && Curl_pgrsUpdate(data)) {
         /* aborted due to progress callback return code must close the
            connection */
         result = CURLE_ABORTED_BY_CALLBACK;
@@ -2458,7 +2453,7 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
     if(multi->in_callback)
       return CURLM_RECURSIVE_API_CALL;
 
-    multi->type = 0; /* not good anymore */
+    multi->magic = 0; /* not good anymore */
 
     /* Firsrt remove all remaining easy handles */
     data = multi->easyp;
@@ -3329,16 +3324,18 @@ size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
  * When information about a connection has appeared, call this!
  */
 
-void Curl_multiuse_state(struct connectdata *conn,
+void Curl_multiuse_state(struct Curl_easy *data,
                          int bundlestate) /* use BUNDLE_* defines */
 {
+  struct connectdata *conn;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->multi);
+  conn = data->conn;
   DEBUGASSERT(conn);
   DEBUGASSERT(conn->bundle);
-  DEBUGASSERT(conn->data);
-  DEBUGASSERT(conn->data->multi);
 
   conn->bundle->multiuse = bundlestate;
-  process_pending_handles(conn->data->multi);
+  process_pending_handles(data->multi);
 }
 
 static void process_pending_handles(struct Curl_multi *multi)

+ 6 - 2
lib/multihandle.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -22,10 +22,14 @@
  *
  ***************************************************************************/
 
+#include "llist.h"
+#include "hash.h"
 #include "conncache.h"
 #include "psl.h"
 #include "socketpair.h"
 
+struct connectdata;
+
 struct Curl_message {
   struct Curl_llist_element list;
   /* the 'CURLMsg' is the part that is visible to the external user */
@@ -79,7 +83,7 @@ typedef enum {
 struct Curl_multi {
   /* First a simple identifier to easier detect if a user mix up
      this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
-  long type;
+  unsigned int magic;
 
   /* We have a doubly-linked list with easy handles */
   struct Curl_easy *easyp;

+ 2 - 2
lib/multiif.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -69,7 +69,7 @@ size_t Curl_multi_max_host_connections(struct Curl_multi *multi);
 /* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */
 size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
 
-void Curl_multiuse_state(struct connectdata *conn,
+void Curl_multiuse_state(struct Curl_easy *data,
                          int bundlestate); /* use BUNDLE_* defines */
 
 /*

+ 49 - 43
lib/openldap.c

@@ -5,8 +5,8 @@
  *                | (__| |_| |  _ <| |___
  *                 \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2011 - 2021, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2010, Howard Chu, <[email protected]>
- * Copyright (C) 2011 - 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
@@ -76,12 +76,14 @@ extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
                         LDAP **ld);
 #endif
 
-static CURLcode ldap_setup_connection(struct connectdata *conn);
-static CURLcode ldap_do(struct connectdata *conn, bool *done);
-static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool);
-static CURLcode ldap_connect(struct connectdata *conn, bool *done);
-static CURLcode ldap_connecting(struct connectdata *conn, bool *done);
-static CURLcode ldap_disconnect(struct connectdata *conn, bool dead);
+static CURLcode ldap_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static CURLcode ldap_do(struct Curl_easy *data, bool *done);
+static CURLcode ldap_done(struct Curl_easy *data, CURLcode, bool);
+static CURLcode ldap_connect(struct Curl_easy *data, bool *done);
+static CURLcode ldap_connecting(struct Curl_easy *data, bool *done);
+static CURLcode ldap_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
 
 static Curl_recv ldap_recv;
 
@@ -169,11 +171,11 @@ struct ldapreqinfo {
   int nument;
 };
 
-static CURLcode ldap_setup_connection(struct connectdata *conn)
+static CURLcode ldap_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   struct ldapconninfo *li;
   LDAPURLDesc *lud;
-  struct Curl_easy *data = conn->data;
   int rc, proto;
   CURLcode status;
 
@@ -186,7 +188,7 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
         status = CURLE_OUT_OF_MEMORY;
       msg = url_errs[rc];
     }
-    failf(conn->data, "LDAP local: %s", msg);
+    failf(data, "LDAP local: %s", msg);
     return status;
   }
   proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
@@ -205,10 +207,10 @@ static CURLcode ldap_setup_connection(struct connectdata *conn)
 static Sockbuf_IO ldapsb_tls;
 #endif
 
-static CURLcode ldap_connect(struct connectdata *conn, bool *done)
+static CURLcode ldap_connect(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  struct Curl_easy *data = conn->data;
   int rc, proto = LDAP_VERSION3;
   char hosturl[1024];
   char *ptr;
@@ -243,7 +245,8 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
 #ifdef USE_SSL
   if(conn->handler->flags & PROTOPT_SSL) {
     CURLcode result;
-    result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
+    result = Curl_ssl_connect_nonblocking(data, conn,
+                                          FIRSTSOCKET, &li->ssldone);
     if(result)
       return result;
   }
@@ -252,10 +255,10 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
+static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  struct Curl_easy *data = conn->data;
   LDAPMessage *msg = NULL;
   struct timeval tv = {0, 1}, *tvp;
   int rc, err;
@@ -265,7 +268,7 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
   if(conn->handler->flags & PROTOPT_SSL) {
     /* Is the SSL handshake complete yet? */
     if(!li->ssldone) {
-      CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
+      CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FIRSTSOCKET,
                                                      &li->ssldone);
       if(result || !li->ssldone)
         return result;
@@ -357,10 +360,12 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
+static CURLcode ldap_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead_connection)
 {
   struct ldapconninfo *li = conn->proto.ldapc;
   (void) dead_connection;
+  (void) data;
 
   if(li) {
     if(li->ld) {
@@ -373,15 +378,15 @@ static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
   return CURLE_OK;
 }
 
-static CURLcode ldap_do(struct connectdata *conn, bool *done)
+static CURLcode ldap_do(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
   struct ldapreqinfo *lr;
   CURLcode status = CURLE_OK;
   int rc = 0;
   LDAPURLDesc *ludp = NULL;
   int msgid;
-  struct Curl_easy *data = conn->data;
 
   connkeep(conn, "OpenLDAP do");
 
@@ -396,7 +401,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
         status = CURLE_OUT_OF_MEMORY;
       msg = url_errs[rc];
     }
-    failf(conn->data, "LDAP local: %s", msg);
+    failf(data, "LDAP local: %s", msg);
     return status;
   }
 
@@ -418,10 +423,11 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
+static CURLcode ldap_done(struct Curl_easy *data, CURLcode res,
                           bool premature)
 {
-  struct ldapreqinfo *lr = conn->data->req.p.ldap;
+  struct connectdata *conn = data->conn;
+  struct ldapreqinfo *lr = data->req.p.ldap;
 
   (void)res;
   (void)premature;
@@ -433,18 +439,18 @@ static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
       ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
       lr->msgid = 0;
     }
-    conn->data->req.p.ldap = NULL;
+    data->req.p.ldap = NULL;
     free(lr);
   }
 
   return CURLE_OK;
 }
 
-static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
+static ssize_t ldap_recv(struct Curl_easy *data, int sockindex, char *buf,
                          size_t len, CURLcode *err)
 {
+  struct connectdata *conn = data->conn;
   struct ldapconninfo *li = conn->proto.ldapc;
-  struct Curl_easy *data = conn->data;
   struct ldapreqinfo *lr = data->req.p.ldap;
   int rc, ret;
   LDAPMessage *msg = NULL;
@@ -512,20 +518,20 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
       *err = CURLE_RECV_ERROR;
       return -1;
     }
-    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
     if(writeerr) {
       *err = writeerr;
       return -1;
     }
 
-    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
                                  bv.bv_len);
     if(writeerr) {
       *err = writeerr;
       return -1;
     }
 
-    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
     if(writeerr) {
       *err = writeerr;
       return -1;
@@ -546,18 +552,18 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
         binary = 0;
 
       if(bvals == NULL) {
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
         if(writeerr) {
           *err = writeerr;
           return -1;
         }
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
                                      bv.bv_len);
         if(writeerr) {
           *err = writeerr;
           return -1;
         }
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":\n", 2);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":\n", 2);
         if(writeerr) {
           *err = writeerr;
           return -1;
@@ -568,20 +574,20 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
 
       for(i = 0; bvals[i].bv_val != NULL; i++) {
         int binval = 0;
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
         if(writeerr) {
           *err = writeerr;
           return -1;
         }
 
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
                                      bv.bv_len);
         if(writeerr) {
           *err = writeerr;
           return -1;
         }
 
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":", 1);
         if(writeerr) {
           *err = writeerr;
           return -1;
@@ -619,7 +625,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
             *err = error;
             return -1;
           }
-          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
+          writeerr = Curl_client_write(data, CLIENTWRITE_BODY,
                                        (char *)": ", 2);
           if(writeerr) {
             *err = writeerr;
@@ -628,7 +634,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
 
           data->req.bytecount += 2;
           if(val_b64_sz > 0) {
-            writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
+            writeerr = Curl_client_write(data, CLIENTWRITE_BODY, val_b64,
                                          val_b64_sz);
             if(writeerr) {
               *err = writeerr;
@@ -639,13 +645,13 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
           }
         }
         else {
-          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
+          writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)" ", 1);
           if(writeerr) {
             *err = writeerr;
             return -1;
           }
 
-          writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
+          writeerr = Curl_client_write(data, CLIENTWRITE_BODY, bvals[i].bv_val,
                                        bvals[i].bv_len);
           if(writeerr) {
             *err = writeerr;
@@ -654,7 +660,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
 
           data->req.bytecount += bvals[i].bv_len + 1;
         }
-        writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+        writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
         if(writeerr) {
           *err = writeerr;
           return -1;
@@ -663,14 +669,14 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
         data->req.bytecount++;
       }
       ber_memfree(bvals);
-      writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+      writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
       if(writeerr) {
         *err = writeerr;
         return -1;
       }
       data->req.bytecount++;
     }
-    writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+    writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0);
     if(writeerr) {
       *err = writeerr;
       return -1;
@@ -724,7 +730,7 @@ ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
   ber_slen_t ret;
   CURLcode err = CURLE_RECV_ERROR;
 
-  ret = (li->recv)(conn, FIRSTSOCKET, buf, len, &err);
+  ret = (li->recv)(conn->data, FIRSTSOCKET, buf, len, &err);
   if(ret < 0 && err == CURLE_AGAIN) {
     SET_SOCKERRNO(EWOULDBLOCK);
   }
@@ -739,7 +745,7 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
   ber_slen_t ret;
   CURLcode err = CURLE_SEND_ERROR;
 
-  ret = (li->send)(conn, FIRSTSOCKET, buf, len, &err);
+  ret = (li->send)(conn->data, FIRSTSOCKET, buf, len, &err);
   if(ret < 0 && err == CURLE_AGAIN) {
     SET_SOCKERRNO(EWOULDBLOCK);
   }

+ 33 - 33
lib/pingpong.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -44,10 +44,10 @@
 
 /* Returns timeout in ms. 0 or negative number means the timeout has already
    triggered */
-timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
+timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
+                                 struct pingpong *pp, bool disconnecting)
 {
-  struct connectdata *conn = pp->conn;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   timediff_t timeout_ms; /* in milliseconds */
   timediff_t response_time = (data->set.server_response_timeout)?
     data->set.server_response_timeout: pp->response_time;
@@ -77,15 +77,15 @@ timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
 /*
  * Curl_pp_statemach()
  */
-CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
+CURLcode Curl_pp_statemach(struct Curl_easy *data,
+                           struct pingpong *pp, bool block,
                            bool disconnecting)
 {
-  struct connectdata *conn = pp->conn;
+  struct connectdata *conn = data->conn;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
   int rc;
   timediff_t interval_ms;
-  timediff_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
-  struct Curl_easy *data = conn->data;
+  timediff_t timeout_ms = Curl_pp_state_timeout(data, pp, disconnecting);
   CURLcode result = CURLE_OK;
 
   if(timeout_ms <= 0) {
@@ -117,7 +117,7 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
 
   if(block) {
     /* if we didn't wait, we don't have to spend time on this now */
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
     else
       result = Curl_speedcheck(data, Curl_now());
@@ -131,17 +131,17 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
     result = CURLE_OUT_OF_MEMORY;
   }
   else if(rc)
-    result = pp->statemach_act(conn);
+    result = pp->statemachine(data, data->conn);
 
   return result;
 }
 
 /* initialize stuff to prepare for reading a fresh new response */
-void Curl_pp_init(struct pingpong *pp)
+void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp)
 {
-  struct connectdata *conn = pp->conn;
+  DEBUGASSERT(data);
   pp->nread_resp = 0;
-  pp->linestart_resp = conn->data->state.buffer;
+  pp->linestart_resp = data->state.buffer;
   pp->pending_resp = TRUE;
   pp->response = Curl_now(); /* start response time-out now! */
 }
@@ -162,7 +162,8 @@ void Curl_pp_setup(struct pingpong *pp)
  *
  * made to never block
  */
-CURLcode Curl_pp_vsendf(struct pingpong *pp,
+CURLcode Curl_pp_vsendf(struct Curl_easy *data,
+                        struct pingpong *pp,
                         const char *fmt,
                         va_list args)
 {
@@ -170,8 +171,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
   size_t write_len;
   char *s;
   CURLcode result;
-  struct connectdata *conn = pp->conn;
-  struct Curl_easy *data;
+  struct connectdata *conn = data->conn;
 
 #ifdef HAVE_GSSAPI
   enum protection_level data_sec;
@@ -184,7 +184,6 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
   if(!conn)
     /* can't send without a connection! */
     return CURLE_SEND_ERROR;
-  data = conn->data;
 
   Curl_dyn_reset(&pp->sendbuf);
   result = Curl_dyn_vaddf(&pp->sendbuf, fmt, args);
@@ -198,7 +197,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
 
   write_len = Curl_dyn_len(&pp->sendbuf);
   s = Curl_dyn_ptr(&pp->sendbuf);
-  Curl_pp_init(pp);
+  Curl_pp_init(data, pp);
 
   result = Curl_convert_to_network(data, s, write_len);
   /* Curl_convert_to_network calls failf if unsuccessful */
@@ -208,7 +207,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
 #ifdef HAVE_GSSAPI
   conn->data_prot = PROT_CMD;
 #endif
-  result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len,
+  result = Curl_write(data, conn->sock[FIRSTSOCKET], s, write_len,
                       &bytes_written);
   if(result)
     return result;
@@ -246,14 +245,14 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
  *
  * made to never block
  */
-CURLcode Curl_pp_sendf(struct pingpong *pp,
+CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp,
                        const char *fmt, ...)
 {
   CURLcode result;
   va_list ap;
   va_start(ap, fmt);
 
-  result = Curl_pp_vsendf(pp, fmt, ap);
+  result = Curl_pp_vsendf(data, pp, fmt, ap);
 
   va_end(ap);
 
@@ -265,7 +264,8 @@ CURLcode Curl_pp_sendf(struct pingpong *pp,
  *
  * Reads a piece of a server response.
  */
-CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+CURLcode Curl_pp_readresp(struct Curl_easy *data,
+                          curl_socket_t sockfd,
                           struct pingpong *pp,
                           int *code, /* return the server code if done */
                           size_t *size) /* size of the response */
@@ -274,8 +274,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
   bool keepon = TRUE;
   ssize_t gotbytes;
   char *ptr;
-  struct connectdata *conn = pp->conn;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   char * const buf = data->state.buffer;
   CURLcode result = CURLE_OK;
 
@@ -315,7 +314,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
 #endif
       DEBUGASSERT((ptr + data->set.buffer_size - pp->nread_resp) <=
                   (buf + data->set.buffer_size + 1));
-      result = Curl_read(conn, sockfd, ptr,
+      result = Curl_read(data, sockfd, ptr,
                          data->set.buffer_size - pp->nread_resp,
                          &gotbytes);
 #ifdef HAVE_GSSAPI
@@ -371,12 +370,12 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
            * for "headers". The response lines can be seen as a kind of
            * headers.
            */
-          result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+          result = Curl_client_write(data, CLIENTWRITE_HEADER,
                                      pp->linestart_resp, perline);
           if(result)
             return result;
 
-          if(pp->endofresp(conn, pp->linestart_resp, perline, code)) {
+          if(pp->endofresp(data, conn, pp->linestart_resp, perline, code)) {
             /* This is the end of the last line, copy the last line to the
                start of the buffer and null-terminate, for old times sake */
             size_t n = ptr - pp->linestart_resp;
@@ -456,10 +455,10 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
   return result;
 }
 
-int Curl_pp_getsock(struct pingpong *pp,
-                    curl_socket_t *socks)
+int Curl_pp_getsock(struct Curl_easy *data,
+                    struct pingpong *pp, curl_socket_t *socks)
 {
-  struct connectdata *conn = pp->conn;
+  struct connectdata *conn = data->conn;
   socks[0] = conn->sock[FIRSTSOCKET];
 
   if(pp->sendleft) {
@@ -471,13 +470,14 @@ int Curl_pp_getsock(struct pingpong *pp,
   return GETSOCK_READSOCK(0);
 }
 
-CURLcode Curl_pp_flushsend(struct pingpong *pp)
+CURLcode Curl_pp_flushsend(struct Curl_easy *data,
+                           struct pingpong *pp)
 {
   /* we have a piece of a command still left to send */
-  struct connectdata *conn = pp->conn;
+  struct connectdata *conn = data->conn;
   ssize_t written;
   curl_socket_t sock = conn->sock[FIRSTSOCKET];
-  CURLcode result = Curl_write(conn, sock, pp->sendthis + pp->sendsize -
+  CURLcode result = Curl_write(data, sock, pp->sendthis + pp->sendsize -
                                pp->sendleft, pp->sendleft, &written);
   if(result)
     return result;

+ 26 - 16
lib/pingpong.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -62,37 +62,42 @@ struct pingpong {
                                off, used to time-out response reading */
   timediff_t response_time; /* When no timeout is given, this is the amount of
                                milliseconds we await for a server response. */
-  struct connectdata *conn; /* points to the connectdata struct that this
-                               belongs to */
   struct dynbuf sendbuf;
 
   /* Function pointers the protocols MUST implement and provide for the
      pingpong layer to function */
 
-  CURLcode (*statemach_act)(struct connectdata *conn);
-
-  bool (*endofresp)(struct connectdata *conn, char *ptr, size_t len,
-                    int *code);
+  CURLcode (*statemachine)(struct Curl_easy *data, struct connectdata *conn);
+  bool (*endofresp)(struct Curl_easy *data, struct connectdata *conn,
+                    char *ptr, size_t len, int *code);
 };
 
+#define PINGPONG_SETUP(pp,s,e)                   \
+  do {                                           \
+    pp->response_time = RESP_TIMEOUT;            \
+    pp->statemachine = s;                        \
+    pp->endofresp = e;                           \
+  } while(0)
+
 /*
  * Curl_pp_statemach()
  *
  * called repeatedly until done. Set 'wait' to make it wait a while on the
  * socket if there's no traffic.
  */
-CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
-                           bool disconnecting);
+CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
+                           bool block, bool disconnecting);
 
 /* initialize stuff to prepare for reading a fresh new response */
-void Curl_pp_init(struct pingpong *pp);
+void Curl_pp_init(struct Curl_easy *data, struct pingpong *pp);
 
 /* setup for the transfer */
 void Curl_pp_setup(struct pingpong *pp);
 
 /* Returns timeout in ms. 0 or negative number means the timeout has already
    triggered */
-timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
+timediff_t Curl_pp_state_timeout(struct Curl_easy *data,
+                                 struct pingpong *pp, bool disconnecting);
 
 
 /***********************************************************************
@@ -105,7 +110,8 @@ timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
  *
  * made to never block
  */
-CURLcode Curl_pp_sendf(struct pingpong *pp,
+CURLcode Curl_pp_sendf(struct Curl_easy *data,
+                       struct pingpong *pp,
                        const char *fmt, ...);
 
 /***********************************************************************
@@ -118,7 +124,8 @@ CURLcode Curl_pp_sendf(struct pingpong *pp,
  *
  * made to never block
  */
-CURLcode Curl_pp_vsendf(struct pingpong *pp,
+CURLcode Curl_pp_vsendf(struct Curl_easy *data,
+                        struct pingpong *pp,
                         const char *fmt,
                         va_list args);
 
@@ -127,18 +134,21 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
  *
  * Reads a piece of a server response.
  */
-CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+CURLcode Curl_pp_readresp(struct Curl_easy *data,
+                          curl_socket_t sockfd,
                           struct pingpong *pp,
                           int *code, /* return the server code if done */
                           size_t *size); /* size of the response */
 
 
-CURLcode Curl_pp_flushsend(struct pingpong *pp);
+CURLcode Curl_pp_flushsend(struct Curl_easy *data,
+                           struct pingpong *pp);
 
 /* call this when a pingpong connection is disconnected */
 CURLcode Curl_pp_disconnect(struct pingpong *pp);
 
-int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks);
+int Curl_pp_getsock(struct Curl_easy *data, struct pingpong *pp,
+                    curl_socket_t *socks);
 
 
 /***********************************************************************

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 175 - 166
lib/pop3.c


+ 3 - 3
lib/pop3.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2009 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2009 - 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
@@ -61,6 +61,7 @@ struct pop3_conn {
   struct pingpong pp;
   pop3state state;        /* Always use pop3.c:state() to change state! */
   bool ssldone;           /* Is connect() over SSL done? */
+  bool tls_supported;     /* StartTLS capability supported by server */
   size_t eob;             /* Number of bytes of the EOB (End Of Body) that
                              have been received so far */
   size_t strip;           /* Number of bytes from the start to ignore as
@@ -69,7 +70,6 @@ struct pop3_conn {
   unsigned int authtypes; /* Accepted authentication types */
   unsigned int preftype;  /* Preferred authentication type */
   char *apoptimestamp;    /* APOP timestamp from the server greeting */
-  bool tls_supported;     /* StartTLS capability supported by server */
 };
 
 extern const struct Curl_handler Curl_handler_pop3;
@@ -90,6 +90,6 @@ extern const struct Curl_handler Curl_handler_pop3s;
 
 /* This function scans the body after the end-of-body and writes everything
  * until the end is found */
-CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread);
+CURLcode Curl_pop3_write(struct Curl_easy *data, char *str, size_t nread);
 
 #endif /* HEADER_CURL_POP3_H */

+ 8 - 12
lib/progress.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -137,12 +137,11 @@ static char *max5data(curl_off_t bytes, char *max5)
 
 */
 
-int Curl_pgrsDone(struct connectdata *conn)
+int Curl_pgrsDone(struct Curl_easy *data)
 {
   int rc;
-  struct Curl_easy *data = conn->data;
   data->progress.lastshow = 0;
-  rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
+  rc = Curl_pgrsUpdate(data); /* the final (forced) update */
   if(rc)
     return rc;
 
@@ -371,11 +370,10 @@ void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
 }
 
 /* returns TRUE if it's time to show the progress meter */
-static bool progress_calc(struct connectdata *conn, struct curltime now)
+static bool progress_calc(struct Curl_easy *data, struct curltime now)
 {
   curl_off_t timespent;
   curl_off_t timespent_ms; /* milliseconds */
-  struct Curl_easy *data = conn->data;
   curl_off_t dl = data->progress.downloaded;
   curl_off_t ul = data->progress.uploaded;
   bool timetoshow = FALSE;
@@ -465,9 +463,8 @@ static bool progress_calc(struct connectdata *conn, struct curltime now)
 }
 
 #ifndef CURL_DISABLE_PROGRESS_METER
-static void progress_meter(struct connectdata *conn)
+static void progress_meter(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   char max5[6][10];
   curl_off_t dlpercen = 0;
   curl_off_t ulpercen = 0;
@@ -581,11 +578,10 @@ static void progress_meter(struct connectdata *conn)
  * Curl_pgrsUpdate() returns 0 for success or the value returned by the
  * progress callback!
  */
-int Curl_pgrsUpdate(struct connectdata *conn)
+int Curl_pgrsUpdate(struct Curl_easy *data)
 {
-  struct Curl_easy *data = conn->data;
   struct curltime now = Curl_now(); /* what time is it */
-  bool showprogress = progress_calc(conn, now);
+  bool showprogress = progress_calc(data, now);
   if(!(data->progress.flags & PGRS_HIDE)) {
     if(data->set.fxferinfo) {
       int result;
@@ -621,7 +617,7 @@ int Curl_pgrsUpdate(struct connectdata *conn)
     }
 
     if(showprogress)
-      progress_meter(conn);
+      progress_meter(data);
   }
 
   return 0;

+ 3 - 3
lib/progress.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -40,14 +40,14 @@ typedef enum {
   TIMER_LAST /* must be last */
 } timerid;
 
-int Curl_pgrsDone(struct connectdata *);
+int Curl_pgrsDone(struct Curl_easy *data);
 void Curl_pgrsStartNow(struct Curl_easy *data);
 void Curl_pgrsSetDownloadSize(struct Curl_easy *data, curl_off_t size);
 void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size);
 void Curl_pgrsSetDownloadCounter(struct Curl_easy *data, curl_off_t size);
 void Curl_pgrsSetUploadCounter(struct Curl_easy *data, curl_off_t size);
 void Curl_ratelimit(struct Curl_easy *data, struct curltime now);
-int Curl_pgrsUpdate(struct connectdata *);
+int Curl_pgrsUpdate(struct Curl_easy *data);
 void Curl_pgrsResetTransferSizes(struct Curl_easy *data);
 struct curltime Curl_pgrsTime(struct Curl_easy *data, timerid timer);
 timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,

+ 9 - 6
lib/quic.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -35,25 +35,28 @@
 #include "urldata.h"
 
 /* functions provided by the specific backends */
-CURLcode Curl_quic_connect(struct connectdata *conn,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
+                           struct connectdata *conn,
                            curl_socket_t sockfd,
                            int sockindex,
                            const struct sockaddr *addr,
                            socklen_t addrlen);
-CURLcode Curl_quic_is_connected(struct connectdata *conn,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
+                                struct connectdata *conn,
                                 int sockindex,
                                 bool *connected);
 int Curl_quic_ver(char *p, size_t len);
-CURLcode Curl_quic_done_sending(struct connectdata *conn);
+CURLcode Curl_quic_done_sending(struct Curl_easy *data);
 void Curl_quic_done(struct Curl_easy *data, bool premature);
 bool Curl_quic_data_pending(const struct Curl_easy *data);
-void Curl_quic_disconnect(struct connectdata *conn, int tempindex);
+void Curl_quic_disconnect(struct Curl_easy *data,
+                          struct connectdata *conn, int tempindex);
 
 #else /* ENABLE_QUIC */
 #define Curl_quic_done_sending(x)
 #define Curl_quic_done(x,y)
 #define Curl_quic_data_pending(x)
-#define Curl_quic_disconnect(x,y)
+#define Curl_quic_disconnect(x,y,z)
 #endif /* !ENABLE_QUIC */
 
 #endif /* HEADER_CURL_QUIC_H */

+ 57 - 50
lib/rtsp.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -22,7 +22,7 @@
 
 #include "curl_setup.h"
 
-#ifndef CURL_DISABLE_RTSP
+#if !defined(CURL_DISABLE_RTSP) && !defined(USE_HYPER)
 
 #include "urldata.h"
 #include <curl/curl.h>
@@ -48,11 +48,13 @@
                              ((int)((unsigned char)((p)[3]))))
 
 /* protocol-specific functions set up to be called by the main engine */
-static CURLcode rtsp_do(struct connectdata *conn, bool *done);
-static CURLcode rtsp_done(struct connectdata *conn, CURLcode, bool premature);
-static CURLcode rtsp_connect(struct connectdata *conn, bool *done);
-static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead);
-static int rtsp_getsock_do(struct connectdata *conn, curl_socket_t *socks);
+static CURLcode rtsp_do(struct Curl_easy *data, bool *done);
+static CURLcode rtsp_done(struct Curl_easy *data, CURLcode, bool premature);
+static CURLcode rtsp_connect(struct Curl_easy *data, bool *done);
+static CURLcode rtsp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead);
+static int rtsp_getsock_do(struct Curl_easy *data,
+                           struct connectdata *conn, curl_socket_t *socks);
 
 /*
  * Parse and write out any available RTP data.
@@ -66,23 +68,26 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
                                    ssize_t *nread,
                                    bool *readmore);
 
-static CURLcode rtsp_setup_connection(struct connectdata *conn);
-static unsigned int rtsp_conncheck(struct connectdata *check,
+static CURLcode rtsp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn);
+static unsigned int rtsp_conncheck(struct Curl_easy *data,
+                                   struct connectdata *check,
                                    unsigned int checks_to_perform);
 
 /* this returns the socket to wait for in the DO and DOING state for the multi
    interface and then we're always _sending_ a request and thus we wait for
    the single socket to become writable only */
-static int rtsp_getsock_do(struct connectdata *conn,
+static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
                            curl_socket_t *socks)
 {
   /* write mode */
+  (void)data;
   socks[0] = conn->sock[FIRSTSOCKET];
   return GETSOCK_WRITESOCK(0);
 }
 
 static
-CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len);
+CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len);
 
 
 /*
@@ -111,11 +116,13 @@ const struct Curl_handler Curl_handler_rtsp = {
 };
 
 
-static CURLcode rtsp_setup_connection(struct connectdata *conn)
+static CURLcode rtsp_setup_connection(struct Curl_easy *data,
+                                      struct connectdata *conn)
 {
   struct RTSP *rtsp;
+  (void)conn;
 
-  conn->data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
+  data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
   if(!rtsp)
     return CURLE_OUT_OF_MEMORY;
 
@@ -156,13 +163,15 @@ static bool rtsp_connisdead(struct connectdata *check)
 /*
  * Function to check on various aspects of a connection.
  */
-static unsigned int rtsp_conncheck(struct connectdata *check,
+static unsigned int rtsp_conncheck(struct Curl_easy *data,
+                                   struct connectdata *conn,
                                    unsigned int checks_to_perform)
 {
   unsigned int ret_val = CONNRESULT_NONE;
+  (void)data;
 
   if(checks_to_perform & CONNCHECK_ISDEAD) {
-    if(rtsp_connisdead(check))
+    if(rtsp_connisdead(conn))
       ret_val |= CONNRESULT_DEAD;
   }
 
@@ -170,12 +179,11 @@ static unsigned int rtsp_conncheck(struct connectdata *check,
 }
 
 
-static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
+static CURLcode rtsp_connect(struct Curl_easy *data, bool *done)
 {
   CURLcode httpStatus;
-  struct Curl_easy *data = conn->data;
 
-  httpStatus = Curl_http_connect(conn, done);
+  httpStatus = Curl_http_connect(data, done);
 
   /* Initialize the CSeq if not already done */
   if(data->state.rtsp_next_client_CSeq == 0)
@@ -183,23 +191,24 @@ static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
   if(data->state.rtsp_next_server_CSeq == 0)
     data->state.rtsp_next_server_CSeq = 1;
 
-  conn->proto.rtspc.rtp_channel = -1;
+  data->conn->proto.rtspc.rtp_channel = -1;
 
   return httpStatus;
 }
 
-static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead)
+static CURLcode rtsp_disconnect(struct Curl_easy *data,
+                                struct connectdata *conn, bool dead)
 {
   (void) dead;
+  (void) data;
   Curl_safefree(conn->proto.rtspc.rtp_buf);
   return CURLE_OK;
 }
 
 
-static CURLcode rtsp_done(struct connectdata *conn,
+static CURLcode rtsp_done(struct Curl_easy *data,
                           CURLcode status, bool premature)
 {
-  struct Curl_easy *data = conn->data;
   struct RTSP *rtsp = data->req.p.rtsp;
   CURLcode httpStatus;
 
@@ -207,7 +216,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
   if(data->set.rtspreq == RTSPREQ_RECEIVE)
     premature = TRUE;
 
-  httpStatus = Curl_http_done(conn, status, premature);
+  httpStatus = Curl_http_done(data, status, premature);
 
   if(rtsp) {
     /* Check the sequence numbers */
@@ -220,7 +229,7 @@ static CURLcode rtsp_done(struct connectdata *conn,
       return CURLE_RTSP_CSEQ_ERROR;
     }
     if(data->set.rtspreq == RTSPREQ_RECEIVE &&
-            (conn->proto.rtspc.rtp_channel == -1)) {
+            (data->conn->proto.rtspc.rtp_channel == -1)) {
       infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
     }
   }
@@ -228,9 +237,9 @@ static CURLcode rtsp_done(struct connectdata *conn,
   return httpStatus;
 }
 
-static CURLcode rtsp_do(struct connectdata *conn, bool *done)
+static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   CURLcode result = CURLE_OK;
   Curl_RtspReq rtspreq = data->set.rtspreq;
   struct RTSP *rtsp = data->req.p.rtsp;
@@ -330,7 +339,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   }
 
   /* Transport Header for SETUP requests */
-  p_transport = Curl_checkheaders(conn, "Transport");
+  p_transport = Curl_checkheaders(data, "Transport");
   if(rtspreq == RTSPREQ_SETUP && !p_transport) {
     /* New Transport: setting? */
     if(data->set.str[STRING_RTSP_TRANSPORT]) {
@@ -354,11 +363,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   /* Accept Headers for DESCRIBE requests */
   if(rtspreq == RTSPREQ_DESCRIBE) {
     /* Accept Header */
-    p_accept = Curl_checkheaders(conn, "Accept")?
+    p_accept = Curl_checkheaders(data, "Accept")?
       NULL:"Accept: application/sdp\r\n";
 
     /* Accept-Encoding header */
-    if(!Curl_checkheaders(conn, "Accept-Encoding") &&
+    if(!Curl_checkheaders(data, "Accept-Encoding") &&
        data->set.str[STRING_ENCODING]) {
       Curl_safefree(data->state.aptr.accept_encoding);
       data->state.aptr.accept_encoding =
@@ -375,17 +384,18 @@ static CURLcode rtsp_do(struct connectdata *conn, 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(conn, "User-Agent") && data->state.aptr.uagent) {
+  if(Curl_checkheaders(data, "User-Agent") && data->state.aptr.uagent) {
     Curl_safefree(data->state.aptr.uagent);
     data->state.aptr.uagent = NULL;
   }
-  else if(!Curl_checkheaders(conn, "User-Agent") &&
+  else if(!Curl_checkheaders(data, "User-Agent") &&
           data->set.str[STRING_USERAGENT]) {
     p_uagent = data->state.aptr.uagent;
   }
 
   /* setup the authentication headers */
-  result = Curl_http_output_auth(conn, p_request, p_stream_uri, FALSE);
+  result = Curl_http_output_auth(data, conn, p_request, HTTPREQ_GET,
+                                 p_stream_uri, FALSE);
   if(result)
     return result;
 
@@ -394,7 +404,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 
   /* Referrer */
   Curl_safefree(data->state.aptr.ref);
-  if(data->change.referer && !Curl_checkheaders(conn, "Referer"))
+  if(data->change.referer && !Curl_checkheaders(data, "Referer"))
     data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
   else
     data->state.aptr.ref = NULL;
@@ -411,7 +421,7 @@ static CURLcode rtsp_do(struct connectdata *conn, 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(conn, "Range") && data->state.range) {
+    if(!Curl_checkheaders(data, "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;
@@ -421,11 +431,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   /*
    * Sanity check the custom headers
    */
-  if(Curl_checkheaders(conn, "CSeq")) {
+  if(Curl_checkheaders(data, "CSeq")) {
     failf(data, "CSeq cannot be set as a custom header.");
     return CURLE_RTSP_CSEQ_ERROR;
   }
-  if(Curl_checkheaders(conn, "Session")) {
+  if(Curl_checkheaders(data, "Session")) {
     failf(data, "Session ID cannot be set as a custom header.");
     return CURLE_BAD_FUNCTION_ARGUMENT;
   }
@@ -484,12 +494,12 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     return result;
 
   if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
-    result = Curl_add_timecondition(conn, &req_buffer);
+    result = Curl_add_timecondition(data, &req_buffer);
     if(result)
       return result;
   }
 
-  result = Curl_add_custom_headers(conn, FALSE, &req_buffer);
+  result = Curl_add_custom_headers(data, FALSE, &req_buffer);
   if(result)
     return result;
 
@@ -512,7 +522,7 @@ static CURLcode rtsp_do(struct connectdata *conn, 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(conn, "Content-Length")) {
+      if(!Curl_checkheaders(data, "Content-Length")) {
         result =
           Curl_dyn_addf(&req_buffer,
                         "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
@@ -523,7 +533,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
 
       if(rtspreq == RTSPREQ_SET_PARAMETER ||
          rtspreq == RTSPREQ_GET_PARAMETER) {
-        if(!Curl_checkheaders(conn, "Content-Type")) {
+        if(!Curl_checkheaders(data, "Content-Type")) {
           result = Curl_dyn_addf(&req_buffer,
                                  "Content-Type: text/parameters\r\n");
           if(result)
@@ -532,7 +542,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
       }
 
       if(rtspreq == RTSPREQ_ANNOUNCE) {
-        if(!Curl_checkheaders(conn, "Content-Type")) {
+        if(!Curl_checkheaders(data, "Content-Type")) {
           result = Curl_dyn_addf(&req_buffer,
                                  "Content-Type: application/sdp\r\n");
           if(result)
@@ -564,7 +574,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
   }
 
   /* issue the request */
-  result = Curl_buffer_send(&req_buffer, conn,
+  result = Curl_buffer_send(&req_buffer, data,
                             &data->info.request_size, 0, FIRSTSOCKET);
   if(result) {
     failf(data, "Failed sending RTSP request");
@@ -580,7 +590,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
     /* if a request-body has been sent off, we make sure this progress is
        noted properly */
     Curl_pgrsSetUploadCounter(data, data->req.writebytecount);
-    if(Curl_pgrsUpdate(conn))
+    if(Curl_pgrsUpdate(data))
       result = CURLE_ABORTED_BY_CALLBACK;
   }
 
@@ -642,7 +652,7 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
        * Write out the header including the leading '$' */
       DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n",
              rtspc->rtp_channel, rtp_length));
-      result = rtp_client_write(conn, &rtp[0], rtp_length + 4);
+      result = rtp_client_write(data, &rtp[0], rtp_length + 4);
       if(result) {
         failf(data, "Got an error writing an RTP packet");
         *readmore = FALSE;
@@ -713,9 +723,8 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
 }
 
 static
-CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
+CURLcode rtp_client_write(struct Curl_easy *data, char *ptr, size_t len)
 {
-  struct Curl_easy *data = conn->data;
   size_t wrote;
   curl_write_callback writeit;
   void *user_ptr;
@@ -755,10 +764,8 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
   return CURLE_OK;
 }
 
-CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
-                               char *header)
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
 {
-  struct Curl_easy *data = conn->data;
   long CSeq = 0;
 
   if(checkprefix("CSeq:", header)) {
@@ -826,4 +833,4 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
   return CURLE_OK;
 }
 
-#endif /* CURL_DISABLE_RTSP */
+#endif /* CURL_DISABLE_RTSP or using Hyper */

+ 6 - 2
lib/rtsp.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -21,11 +21,15 @@
  * KIND, either express or implied.
  *
  ***************************************************************************/
+#ifdef USE_HYPER
+#define CURL_DISABLE_RTSP
+#endif
+
 #ifndef CURL_DISABLE_RTSP
 
 extern const struct Curl_handler Curl_handler_rtsp;
 
-CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header);
 
 #else
 /* disabled */

+ 10 - 7
lib/select.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -130,6 +130,7 @@ int Curl_wait_ms(timediff_t timeout_ms)
   return r;
 }
 
+#ifndef HAVE_POLL_FINE
 /*
  * This is a wrapper around select() to aid in Windows compatibility.
  * A negative timeout value makes this function wait indefinitely,
@@ -141,11 +142,11 @@ int Curl_wait_ms(timediff_t timeout_ms)
  *    0 = timeout
  *    N = number of signalled file descriptors
  */
-int Curl_select(curl_socket_t maxfd,   /* highest socket number */
-                fd_set *fds_read,      /* sockets ready for reading */
-                fd_set *fds_write,     /* sockets ready for writing */
-                fd_set *fds_err,       /* sockets with errors */
-                timediff_t timeout_ms) /* milliseconds to wait */
+static int our_select(curl_socket_t maxfd,   /* highest socket number */
+                      fd_set *fds_read,      /* sockets ready for reading */
+                      fd_set *fds_write,     /* sockets ready for writing */
+                      fd_set *fds_err,       /* sockets with errors */
+                      timediff_t timeout_ms) /* milliseconds to wait */
 {
   struct timeval pending_tv;
   struct timeval *ptimeout;
@@ -220,6 +221,8 @@ int Curl_select(curl_socket_t maxfd,   /* highest socket number */
 #endif
 }
 
+#endif
+
 /*
  * Wait for read or write events on a set of file descriptors. It uses poll()
  * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
@@ -412,7 +415,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
      curl_socket_t is unsigned in such cases and thus -1 is the largest
      value).
   */
-  r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
+  r = our_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
   if(r <= 0)
     return r;
 

+ 1 - 7
lib/select.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -72,12 +72,6 @@ struct pollfd
    therefore defined here */
 #define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1)
 
-int Curl_select(curl_socket_t maxfd,
-                fd_set *fds_read,
-                fd_set *fds_write,
-                fd_set *fds_err,
-                timediff_t timeout_ms);
-
 int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2,
                       curl_socket_t writefd,
                       timediff_t timeout_ms);

+ 48 - 31
lib/sendf.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -142,7 +142,8 @@ bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
          psnd->recv_size > psnd->recv_processed;
 }
 
-static CURLcode pre_receive_plain(struct connectdata *conn, int num)
+static CURLcode pre_receive_plain(struct Curl_easy *data,
+                                  struct connectdata *conn, int num)
 {
   const curl_socket_t sockfd = conn->sock[num];
   struct postponed_data * const psnd = &(conn->postponed[num]);
@@ -161,7 +162,7 @@ static CURLcode pre_receive_plain(struct connectdata *conn, int num)
       /* Have some incoming data */
       if(!psnd->buffer) {
         /* Use buffer double default size for intermediate buffer */
-        psnd->allocated_size = 2 * conn->data->set.buffer_size;
+        psnd->allocated_size = 2 * data->set.buffer_size;
         psnd->buffer = malloc(psnd->allocated_size);
         if(!psnd->buffer)
           return CURLE_OUT_OF_MEMORY;
@@ -230,7 +231,7 @@ bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex)
   (void)sockindex;
   return false;
 }
-#define pre_receive_plain(c,n) CURLE_OK
+#define pre_receive_plain(d,c,n) CURLE_OK
 #define get_pre_recved(c,n,b,l) 0
 #endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
 
@@ -267,6 +268,7 @@ void Curl_infof(struct Curl_easy *data, const char *fmt, ...)
 
 void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
 {
+  DEBUGASSERT(!strchr(fmt, '\n'));
   if(data->set.verbose || data->set.errorbuffer) {
     va_list ap;
     size_t len;
@@ -292,7 +294,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
  * If the write would block (CURLE_AGAIN), we return CURLE_OK and
  * (*written == 0). Otherwise we return regular CURLcode value.
  */
-CURLcode Curl_write(struct connectdata *conn,
+CURLcode Curl_write(struct Curl_easy *data,
                     curl_socket_t sockfd,
                     const void *mem,
                     size_t len,
@@ -300,9 +302,14 @@ CURLcode Curl_write(struct connectdata *conn,
 {
   ssize_t bytes_written;
   CURLcode result = CURLE_OK;
-  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+  struct connectdata *conn;
+  int num;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  conn = data->conn;
+  num = (sockfd == conn->sock[SECONDARYSOCKET]);
 
-  bytes_written = conn->send[num](conn, num, mem, len, &result);
+  bytes_written = conn->send[num](data, num, mem, len, &result);
 
   *written = bytes_written;
   if(bytes_written >= 0)
@@ -325,17 +332,23 @@ CURLcode Curl_write(struct connectdata *conn,
   }
 }
 
-ssize_t Curl_send_plain(struct connectdata *conn, int num,
+ssize_t Curl_send_plain(struct Curl_easy *data, int num,
                         const void *mem, size_t len, CURLcode *code)
 {
-  curl_socket_t sockfd = conn->sock[num];
+  struct connectdata *conn;
+  curl_socket_t sockfd;
   ssize_t bytes_written;
+
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  conn = data->conn;
+  sockfd = conn->sock[num];
   /* WinSock will destroy unread received data if send() is
      failed.
      To avoid lossage of received data, recv() must be
      performed before every send() if any incoming data is
      available. */
-  if(pre_receive_plain(conn, num)) {
+  if(pre_receive_plain(data, conn, num)) {
     *code = CURLE_OUT_OF_MEMORY;
     return -1;
   }
@@ -372,9 +385,9 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
     }
     else {
       char buffer[STRERROR_LEN];
-      failf(conn->data, "Send failure: %s",
+      failf(data, "Send failure: %s",
             Curl_strerror(err, buffer, sizeof(buffer)));
-      conn->data->state.os_errno = err;
+      data->state.os_errno = err;
       *code = CURLE_SEND_ERROR;
     }
   }
@@ -386,28 +399,33 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
  * server using plain sockets only. Otherwise meant to have the exact same
  * proto as Curl_write()
  */
-CURLcode Curl_write_plain(struct connectdata *conn,
+CURLcode Curl_write_plain(struct Curl_easy *data,
                           curl_socket_t sockfd,
                           const void *mem,
                           size_t len,
                           ssize_t *written)
 {
-  ssize_t bytes_written;
   CURLcode result;
-  int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+  struct connectdata *conn = data->conn;
+  int num;
+  DEBUGASSERT(conn);
+  num = (sockfd == conn->sock[SECONDARYSOCKET]);
 
-  bytes_written = Curl_send_plain(conn, num, mem, len, &result);
-
-  *written = bytes_written;
+  *written = Curl_send_plain(data, num, mem, len, &result);
 
   return result;
 }
 
-ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
+ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
                         size_t len, CURLcode *code)
 {
-  curl_socket_t sockfd = conn->sock[num];
+  struct connectdata *conn;
+  curl_socket_t sockfd;
   ssize_t nread;
+  DEBUGASSERT(data);
+  DEBUGASSERT(data->conn);
+  conn = data->conn;
+  sockfd = conn->sock[num];
   /* Check and return data that already received and storied in internal
      intermediate buffer */
   nread = get_pre_recved(conn, num, buf, len);
@@ -438,9 +456,9 @@ ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
     }
     else {
       char buffer[STRERROR_LEN];
-      failf(conn->data, "Recv failure: %s",
+      failf(data, "Recv failure: %s",
             Curl_strerror(err, buffer, sizeof(buffer)));
-      conn->data->state.os_errno = err;
+      data->state.os_errno = err;
       *code = CURLE_RECV_ERROR;
     }
   }
@@ -499,12 +517,12 @@ static CURLcode pausewrite(struct Curl_easy *data,
  * client write callback(s) and takes care of pause requests from the
  * callbacks.
  */
-static CURLcode chop_write(struct connectdata *conn,
+static CURLcode chop_write(struct Curl_easy *data,
                            int type,
                            char *optr,
                            size_t olen)
 {
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
   curl_write_callback writeheader = NULL;
   curl_write_callback writebody = NULL;
   char *ptr = optr;
@@ -594,13 +612,12 @@ static CURLcode chop_write(struct connectdata *conn,
    local character encoding.  This is a problem and should be changed in
    the future to leave the original data alone.
  */
-CURLcode Curl_client_write(struct connectdata *conn,
+CURLcode Curl_client_write(struct Curl_easy *data,
                            int type,
                            char *ptr,
                            size_t len)
 {
-  struct Curl_easy *data = conn->data;
-
+  struct connectdata *conn = data->conn;
   if(0 == len)
     len = strlen(ptr);
 
@@ -622,7 +639,7 @@ CURLcode Curl_client_write(struct connectdata *conn,
 #endif /* CURL_DO_LINEEND_CONV */
     }
 
-  return chop_write(conn, type, ptr, len);
+  return chop_write(data, type, ptr, len);
 }
 
 CURLcode Curl_read_plain(curl_socket_t sockfd,
@@ -657,7 +674,7 @@ CURLcode Curl_read_plain(curl_socket_t sockfd,
  *
  * Returns a regular CURLcode value.
  */
-CURLcode Curl_read(struct connectdata *conn, /* connection data */
+CURLcode Curl_read(struct Curl_easy *data,   /* transfer */
                    curl_socket_t sockfd,     /* read from this socket */
                    char *buf,                /* store read data here */
                    size_t sizerequested,     /* max amount to read */
@@ -667,7 +684,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
   ssize_t nread = 0;
   size_t bytesfromsocket = 0;
   char *buffertofill = NULL;
-  struct Curl_easy *data = conn->data;
+  struct connectdata *conn = data->conn;
 
   /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
      If it is the second socket, we set num to 1. Otherwise to 0. This lets
@@ -679,7 +696,7 @@ CURLcode Curl_read(struct connectdata *conn, /* connection data */
   bytesfromsocket = CURLMIN(sizerequested, (size_t)data->set.buffer_size);
   buffertofill = buf;
 
-  nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &result);
+  nread = conn->recv[num](data, num, buffertofill, bytesfromsocket, &result);
   if(nread < 0)
     return result;
 

+ 8 - 7
lib/sendf.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -49,7 +49,7 @@ void Curl_failf(struct Curl_easy *, const char *fmt, ...);
 #define CLIENTWRITE_HEADER (1<<1)
 #define CLIENTWRITE_BOTH   (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
 
-CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
+CURLcode Curl_client_write(struct Curl_easy *data, int type, char *ptr,
                            size_t len) WARN_UNUSED_RESULT;
 
 bool Curl_recv_has_postponed_data(struct connectdata *conn, int sockindex);
@@ -60,23 +60,24 @@ CURLcode Curl_read_plain(curl_socket_t sockfd,
                          size_t bytesfromsocket,
                          ssize_t *n);
 
-ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
+ssize_t Curl_recv_plain(struct Curl_easy *data, int num, char *buf,
                         size_t len, CURLcode *code);
-ssize_t Curl_send_plain(struct connectdata *conn, int num,
+ssize_t Curl_send_plain(struct Curl_easy *data, int num,
                         const void *mem, size_t len, CURLcode *code);
 
 /* internal read-function, does plain socket, SSL and krb4 */
-CURLcode Curl_read(struct connectdata *conn, curl_socket_t sockfd,
+CURLcode Curl_read(struct Curl_easy *data, curl_socket_t sockfd,
                    char *buf, size_t buffersize,
                    ssize_t *n);
+
 /* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */
-CURLcode Curl_write(struct connectdata *conn,
+CURLcode Curl_write(struct Curl_easy *data,
                     curl_socket_t sockfd,
                     const void *mem, size_t len,
                     ssize_t *written);
 
 /* internal write-function, does plain sockets ONLY */
-CURLcode Curl_write_plain(struct connectdata *conn,
+CURLcode Curl_write_plain(struct Curl_easy *data,
                           curl_socket_t sockfd,
                           const void *mem, size_t len,
                           ssize_t *written);

+ 32 - 11
lib/setopt.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -274,11 +274,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
      * Do not include the body part in the output data stream.
      */
     data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
+#ifndef CURL_DISABLE_HTTP
     if(data->set.opt_no_body)
       /* in HTTP lingo, no body means using the HEAD request... */
       data->set.method = HTTPREQ_HEAD;
     else if(data->set.method == HTTPREQ_HEAD)
       data->set.method = HTTPREQ_GET;
+#endif
     break;
   case CURLOPT_FAILONERROR:
     /*
@@ -600,7 +602,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
 
   case CURLOPT_POSTREDIR:
     /*
-     * Set the behaviour of POST when redirecting
+     * Set the behavior of POST when redirecting
      * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
      * CURL_REDIR_POST_301 - POST is kept as POST after 301
      * CURL_REDIR_POST_302 - POST is kept as POST after 302
@@ -636,6 +638,21 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     data->set.method = HTTPREQ_POST_FORM;
     data->set.opt_no_body = FALSE; /* this is implied */
     break;
+
+  case CURLOPT_AWS_SIGV4:
+    /*
+     * String that is merged to some authentication
+     * parameters are used by the algorithm.
+     */
+    result = Curl_setstropt(&data->set.str[STRING_AWS_SIGV4],
+                            va_arg(param, char *));
+    /*
+     * Basic been set by default it need to be unset here
+     */
+    if(data->set.str[STRING_AWS_SIGV4])
+      data->set.httpauth = CURLAUTH_AWS_SIGV4;
+    break;
+
 #endif   /* CURL_DISABLE_HTTP */
 
   case CURLOPT_MIMEPOST:
@@ -865,7 +882,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       ;
     else
 #endif
-#ifndef USE_NGHTTP2
+#if !defined(USE_NGHTTP2) && !defined(USE_HYPER)
     if(arg >= CURL_HTTP_VERSION_2)
       return CURLE_UNSUPPORTED_PROTOCOL;
 #else
@@ -1444,13 +1461,16 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     break;
   case CURLOPT_RESOLVE:
     /*
-     * List of NAME:[address] names to populate the DNS cache with
-     * Prefix the NAME with dash (-) to _remove_ the name from the cache.
-     *
-     * Names added with this API will remain in the cache until explicitly
+     * List of HOST:PORT:[addresses] strings to populate the DNS cache with
+     * Entries added this way will remain in the cache until explicitly
      * removed or the handle is cleaned up.
      *
-     * This API can remove any name from the DNS cache, but only entries
+     * Prefix the HOST with plus sign (+) to have the entry expire just like
+     * automatically added entries.
+     *
+     * Prefix the HOST with dash (-) to _remove_ the entry from the cache.
+     *
+     * This API can remove any entry from the DNS cache, but only entries
      * that aren't actually in use right now will be pruned immediately.
      */
     data->set.resolve = va_arg(param, struct curl_slist *);
@@ -2150,8 +2170,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       data->share = NULL;
     }
 
-    /* use new share if it set */
-    data->share = set;
+    if(GOOD_SHARE_HANDLE(set))
+      /* use new share if it set */
+      data->share = set;
     if(data->share) {
 
       Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
@@ -2251,7 +2272,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
     arg = va_arg(param, long);
     if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6))
       return CURLE_BAD_FUNCTION_ARGUMENT;
-    data->set.ipver = arg;
+    data->set.ipver = (unsigned char) arg;
     break;
 
   case CURLOPT_MAXFILESIZE_LARGE:

+ 28 - 5
lib/sha256.c

@@ -27,6 +27,7 @@
 
 #include "warnless.h"
 #include "curl_sha256.h"
+#include "curl_hmac.h"
 
 #if defined(USE_OPENSSL)
 
@@ -343,11 +344,14 @@ static int sha256_compress(struct sha256_state *md,
   }
 
   /* Compress */
-#define RND(a,b,c,d,e,f,g,h,i)                                  \
-  unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
-  unsigned long t1 = Sigma0(a) + Maj(a, b, c);                  \
-  d += t0;                                                      \
-  h = t0 + t1;
+#define RND(a,b,c,d,e,f,g,h,i)                                          \
+  do {                                                                  \
+    unsigned long t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];       \
+    unsigned long t1 = Sigma0(a) + Maj(a, b, c);                        \
+    d += t0;                                                            \
+    h = t0 + t1;                                                        \
+  } while(0)
+
   for(i = 0; i < 64; ++i) {
     unsigned long t;
     RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
@@ -491,4 +495,23 @@ void Curl_sha256it(unsigned char *output, const unsigned char *input,
   SHA256_Final(output, &ctx);
 }
 
+
+const struct HMAC_params Curl_HMAC_SHA256[] = {
+  {
+    /* Hash initialization function. */
+    CURLX_FUNCTION_CAST(HMAC_hinit_func, SHA256_Init),
+    /* Hash update function. */
+    CURLX_FUNCTION_CAST(HMAC_hupdate_func, SHA256_Update),
+    /* Hash computation end function. */
+    CURLX_FUNCTION_CAST(HMAC_hfinal_func, SHA256_Final),
+    /* Size of hash context structure. */
+    sizeof(SHA256_CTX),
+    /* Maximum key length. */
+    64,
+    /* Result size. */
+    32
+  }
+};
+
+
 #endif /* CURL_DISABLE_CRYPTO_AUTH */

+ 7 - 2
lib/share.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -37,6 +37,7 @@ curl_share_init(void)
 {
   struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
   if(share) {
+    share->magic = CURL_GOOD_SHARE;
     share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
 
     if(Curl_mk_dnscache(&share->hostcache)) {
@@ -59,6 +60,9 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
   void *ptr;
   CURLSHcode res = CURLSHE_OK;
 
+  if(!GOOD_SHARE_HANDLE(share))
+    return CURLSHE_INVALID;
+
   if(share->dirty)
     /* don't allow setting options while one or more handles are already
        using this share */
@@ -184,7 +188,7 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
 CURLSHcode
 curl_share_cleanup(struct Curl_share *share)
 {
-  if(share == NULL)
+  if(!GOOD_SHARE_HANDLE(share))
     return CURLSHE_INVALID;
 
   if(share->lockfunc)
@@ -218,6 +222,7 @@ curl_share_cleanup(struct Curl_share *share)
 
   if(share->unlockfunc)
     share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+  share->magic = 0;
   free(share);
 
   return CURLSHE_OK;

+ 5 - 1
lib/share.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -37,8 +37,12 @@
 #define CURL_VOLATILE volatile
 #endif
 
+#define CURL_GOOD_SHARE 0x7e117a1e
+#define GOOD_SHARE_HANDLE(x) ((x) && (x)->magic == CURL_GOOD_SHARE)
+
 /* this struct is libcurl-private, don't export details */
 struct Curl_share {
+  unsigned int magic; /* CURL_GOOD_SHARE */
   unsigned int specifier;
   CURL_VOLATILE unsigned int dirty;
 

+ 143 - 118
lib/smb.c

@@ -5,8 +5,8 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
+ * Copyright (C) 2016 - 2021, Daniel Stenberg, <[email protected]>, et al.
  * Copyright (C) 2014, Bill Nagel <[email protected]>, Exacq Technologies
- * Copyright (C) 2016-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
@@ -54,16 +54,20 @@
 #include "memdebug.h"
 
 /* Local API functions */
-static CURLcode smb_setup_connection(struct connectdata *conn);
-static CURLcode smb_connect(struct connectdata *conn, bool *done);
-static CURLcode smb_connection_state(struct connectdata *conn, bool *done);
-static CURLcode smb_do(struct connectdata *conn, bool *done);
-static CURLcode smb_request_state(struct connectdata *conn, bool *done);
-static CURLcode smb_done(struct connectdata *conn, CURLcode status,
+static CURLcode smb_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn);
+static CURLcode smb_connect(struct Curl_easy *data, bool *done);
+static CURLcode smb_connection_state(struct Curl_easy *data, bool *done);
+static CURLcode smb_do(struct Curl_easy *data, bool *done);
+static CURLcode smb_request_state(struct Curl_easy *data, bool *done);
+static CURLcode smb_done(struct Curl_easy *data, CURLcode status,
                          bool premature);
-static CURLcode smb_disconnect(struct connectdata *conn, bool dead);
-static int smb_getsock(struct connectdata *conn, curl_socket_t *socks);
-static CURLcode smb_parse_url_path(struct connectdata *conn);
+static CURLcode smb_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead);
+static int smb_getsock(struct Curl_easy *data, struct connectdata *conn,
+                       curl_socket_t *socks);
+static CURLcode smb_parse_url_path(struct Curl_easy *data,
+                                   struct connectdata *conn);
 
 /*
  * SMB handler interface
@@ -124,13 +128,17 @@ const struct Curl_handler Curl_handler_smbs = {
 
 /* Append a string to an SMB message */
 #define MSGCAT(str)                             \
-  strcpy(p, (str));                             \
-  p += strlen(str);
+  do {                                          \
+    strcpy(p, (str));                           \
+    p += strlen(str);                           \
+  } while(0)
 
 /* Append a null-terminated string to an SMB message */
 #define MSGCATNULL(str)                         \
-  strcpy(p, (str));                             \
-  p += strlen(str) + 1;
+  do {                                          \
+    strcpy(p, (str));                           \
+    p += strlen(str) + 1;                       \
+  } while(0)
 
 /* SMB is mostly little endian */
 #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
@@ -179,9 +187,9 @@ struct smb_request {
   CURLcode result;
 };
 
-static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
+static void conn_state(struct Curl_easy *data, enum smb_conn_state newstate)
 {
-  struct smb_conn *smbc = &conn->proto.smbc;
+  struct smb_conn *smbc = &data->conn->proto.smbc;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* For debug purposes */
   static const char * const names[] = {
@@ -194,17 +202,17 @@ static void conn_state(struct connectdata *conn, enum smb_conn_state newstate)
   };
 
   if(smbc->state != newstate)
-    infof(conn->data, "SMB conn %p state change from %s to %s\n",
+    infof(data, "SMB conn %p state change from %s to %s\n",
           (void *)smbc, names[smbc->state], names[newstate]);
 #endif
 
   smbc->state = newstate;
 }
 
-static void request_state(struct connectdata *conn,
+static void request_state(struct Curl_easy *data,
                           enum smb_req_state newstate)
 {
-  struct smb_request *req = conn->data->req.p.smb;
+  struct smb_request *req = data->req.p.smb;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* For debug purposes */
   static const char * const names[] = {
@@ -220,7 +228,7 @@ static void request_state(struct connectdata *conn,
   };
 
   if(req->state != newstate)
-    infof(conn->data, "SMB request %p state change from %s to %s\n",
+    infof(data, "SMB request %p state change from %s to %s\n",
           (void *)req, names[req->state], names[newstate]);
 #endif
 
@@ -229,21 +237,23 @@ static void request_state(struct connectdata *conn,
 
 /* this should setup things in the connection, not in the easy
    handle */
-static CURLcode smb_setup_connection(struct connectdata *conn)
+static CURLcode smb_setup_connection(struct Curl_easy *data,
+                                     struct connectdata *conn)
 {
   struct smb_request *req;
 
   /* Initialize the request state */
-  conn->data->req.p.smb = req = calloc(1, sizeof(struct smb_request));
+  data->req.p.smb = req = calloc(1, sizeof(struct smb_request));
   if(!req)
     return CURLE_OUT_OF_MEMORY;
 
   /* Parse the URL path */
-  return smb_parse_url_path(conn);
+  return smb_parse_url_path(data, conn);
 }
 
-static CURLcode smb_connect(struct connectdata *conn, bool *done)
+static CURLcode smb_connect(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   char *slash;
 
@@ -284,8 +294,9 @@ static CURLcode smb_connect(struct connectdata *conn, bool *done)
   return CURLE_OK;
 }
 
-static CURLcode smb_recv_message(struct connectdata *conn, void **msg)
+static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   char *buf = smbc->recv_buf;
   ssize_t bytes_read;
@@ -294,7 +305,7 @@ static CURLcode smb_recv_message(struct connectdata *conn, void **msg)
   size_t len = MAX_MESSAGE_SIZE - smbc->got;
   CURLcode result;
 
-  result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read);
+  result = Curl_read(data, FIRSTSOCKET, buf + smbc->got, len, &bytes_read);
   if(result)
     return result;
 
@@ -338,11 +349,12 @@ static void smb_pop_message(struct connectdata *conn)
   smbc->got = 0;
 }
 
-static void smb_format_message(struct connectdata *conn, struct smb_header *h,
+static void smb_format_message(struct Curl_easy *data, struct smb_header *h,
                                unsigned char cmd, size_t len)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
-  struct smb_request *req = conn->data->req.p.smb;
+  struct smb_request *req = data->req.p.smb;
   unsigned int pid;
 
   memset(h, 0, sizeof(*h));
@@ -359,14 +371,15 @@ static void smb_format_message(struct connectdata *conn, struct smb_header *h,
   h->pid = smb_swap16((unsigned short) pid);
 }
 
-static CURLcode smb_send(struct connectdata *conn, ssize_t len,
+static CURLcode smb_send(struct Curl_easy *data, ssize_t len,
                          size_t upload_size)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   ssize_t bytes_written;
   CURLcode result;
 
-  result = Curl_write(conn, FIRSTSOCKET, conn->data->state.ulbuf,
+  result = Curl_write(data, FIRSTSOCKET, data->state.ulbuf,
                       len, &bytes_written);
   if(result)
     return result;
@@ -381,8 +394,9 @@ static CURLcode smb_send(struct connectdata *conn, ssize_t len,
   return CURLE_OK;
 }
 
-static CURLcode smb_flush(struct connectdata *conn)
+static CURLcode smb_flush(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   ssize_t bytes_written;
   ssize_t len = smbc->send_size - smbc->sent;
@@ -391,8 +405,8 @@ static CURLcode smb_flush(struct connectdata *conn)
   if(!smbc->send_size)
     return CURLE_OK;
 
-  result = Curl_write(conn, FIRSTSOCKET,
-                      conn->data->state.ulbuf + smbc->sent,
+  result = Curl_write(data, FIRSTSOCKET,
+                      data->state.ulbuf + smbc->sent,
                       len, &bytes_written);
   if(result)
     return result;
@@ -405,29 +419,30 @@ static CURLcode smb_flush(struct connectdata *conn)
   return CURLE_OK;
 }
 
-static CURLcode smb_send_message(struct connectdata *conn, unsigned char cmd,
+static CURLcode smb_send_message(struct Curl_easy *data, unsigned char cmd,
                                  const void *msg, size_t msg_len)
 {
-  CURLcode result = Curl_get_upload_buffer(conn->data);
+  CURLcode result = Curl_get_upload_buffer(data);
   if(result)
     return result;
-  smb_format_message(conn, (struct smb_header *)conn->data->state.ulbuf,
+  smb_format_message(data, (struct smb_header *)data->state.ulbuf,
                      cmd, msg_len);
-  memcpy(conn->data->state.ulbuf + sizeof(struct smb_header),
+  memcpy(data->state.ulbuf + sizeof(struct smb_header),
          msg, msg_len);
 
-  return smb_send(conn, sizeof(struct smb_header) + msg_len, 0);
+  return smb_send(data, sizeof(struct smb_header) + msg_len, 0);
 }
 
-static CURLcode smb_send_negotiate(struct connectdata *conn)
+static CURLcode smb_send_negotiate(struct Curl_easy *data)
 {
   const char *msg = "\x00\x0c\x00\x02NT LM 0.12";
 
-  return smb_send_message(conn, SMB_COM_NEGOTIATE, msg, 15);
+  return smb_send_message(data, SMB_COM_NEGOTIATE, msg, 15);
 }
 
-static CURLcode smb_send_setup(struct connectdata *conn)
+static CURLcode smb_send_setup(struct Curl_easy *data)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   struct smb_setup msg;
   char *p = msg.bytes;
@@ -442,10 +457,10 @@ static CURLcode smb_send_setup(struct connectdata *conn)
   if(byte_count > sizeof(msg.bytes))
     return CURLE_FILESIZE_EXCEEDED;
 
-  Curl_ntlm_core_mk_lm_hash(conn->data, conn->passwd, lm_hash);
+  Curl_ntlm_core_mk_lm_hash(data, conn->passwd, lm_hash);
   Curl_ntlm_core_lm_resp(lm_hash, smbc->challenge, lm);
 #ifdef USE_NTRESPONSES
-  Curl_ntlm_core_mk_nt_hash(conn->data, conn->passwd, nt_hash);
+  Curl_ntlm_core_mk_nt_hash(data, conn->passwd, nt_hash);
   Curl_ntlm_core_lm_resp(nt_hash, smbc->challenge, nt);
 #else
   memset(nt, 0, sizeof(nt));
@@ -472,13 +487,14 @@ static CURLcode smb_send_setup(struct connectdata *conn)
   byte_count = p - msg.bytes;
   msg.byte_count = smb_swap16((unsigned short)byte_count);
 
-  return smb_send_message(conn, SMB_COM_SETUP_ANDX, &msg,
+  return smb_send_message(data, SMB_COM_SETUP_ANDX, &msg,
                           sizeof(msg) - sizeof(msg.bytes) + byte_count);
 }
 
-static CURLcode smb_send_tree_connect(struct connectdata *conn)
+static CURLcode smb_send_tree_connect(struct Curl_easy *data)
 {
   struct smb_tree_connect msg;
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   char *p = msg.bytes;
 
@@ -499,13 +515,13 @@ static CURLcode smb_send_tree_connect(struct connectdata *conn)
   byte_count = p - msg.bytes;
   msg.byte_count = smb_swap16((unsigned short)byte_count);
 
-  return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg,
+  return smb_send_message(data, SMB_COM_TREE_CONNECT_ANDX, &msg,
                           sizeof(msg) - sizeof(msg.bytes) + byte_count);
 }
 
-static CURLcode smb_send_open(struct connectdata *conn)
+static CURLcode smb_send_open(struct Curl_easy *data)
 {
-  struct smb_request *req = conn->data->req.p.smb;
+  struct smb_request *req = data->req.p.smb;
   struct smb_nt_create msg;
   size_t byte_count;
 
@@ -518,7 +534,7 @@ static CURLcode smb_send_open(struct connectdata *conn)
   byte_count = strlen(req->path);
   msg.name_length = smb_swap16((unsigned short)byte_count);
   msg.share_access = smb_swap32(SMB_FILE_SHARE_ALL);
-  if(conn->data->set.upload) {
+  if(data->set.upload) {
     msg.access = smb_swap32(SMB_GENERIC_READ | SMB_GENERIC_WRITE);
     msg.create_disposition = smb_swap32(SMB_FILE_OVERWRITE_IF);
   }
@@ -529,35 +545,35 @@ static CURLcode smb_send_open(struct connectdata *conn)
   msg.byte_count = smb_swap16((unsigned short) ++byte_count);
   strcpy(msg.bytes, req->path);
 
-  return smb_send_message(conn, SMB_COM_NT_CREATE_ANDX, &msg,
+  return smb_send_message(data, SMB_COM_NT_CREATE_ANDX, &msg,
                           sizeof(msg) - sizeof(msg.bytes) + byte_count);
 }
 
-static CURLcode smb_send_close(struct connectdata *conn)
+static CURLcode smb_send_close(struct Curl_easy *data)
 {
-  struct smb_request *req = conn->data->req.p.smb;
+  struct smb_request *req = data->req.p.smb;
   struct smb_close msg;
 
   memset(&msg, 0, sizeof(msg));
   msg.word_count = SMB_WC_CLOSE;
   msg.fid = smb_swap16(req->fid);
 
-  return smb_send_message(conn, SMB_COM_CLOSE, &msg, sizeof(msg));
+  return smb_send_message(data, SMB_COM_CLOSE, &msg, sizeof(msg));
 }
 
-static CURLcode smb_send_tree_disconnect(struct connectdata *conn)
+static CURLcode smb_send_tree_disconnect(struct Curl_easy *data)
 {
   struct smb_tree_disconnect msg;
 
   memset(&msg, 0, sizeof(msg));
 
-  return smb_send_message(conn, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg));
+  return smb_send_message(data, SMB_COM_TREE_DISCONNECT, &msg, sizeof(msg));
 }
 
-static CURLcode smb_send_read(struct connectdata *conn)
+static CURLcode smb_send_read(struct Curl_easy *data)
 {
-  struct smb_request *req = conn->data->req.p.smb;
-  curl_off_t offset = conn->data->req.offset;
+  struct smb_request *req = data->req.p.smb;
+  curl_off_t offset = data->req.offset;
   struct smb_read msg;
 
   memset(&msg, 0, sizeof(msg));
@@ -569,19 +585,19 @@ static CURLcode smb_send_read(struct connectdata *conn)
   msg.min_bytes = smb_swap16(MAX_PAYLOAD_SIZE);
   msg.max_bytes = smb_swap16(MAX_PAYLOAD_SIZE);
 
-  return smb_send_message(conn, SMB_COM_READ_ANDX, &msg, sizeof(msg));
+  return smb_send_message(data, SMB_COM_READ_ANDX, &msg, sizeof(msg));
 }
 
-static CURLcode smb_send_write(struct connectdata *conn)
+static CURLcode smb_send_write(struct Curl_easy *data)
 {
   struct smb_write *msg;
-  struct smb_request *req = conn->data->req.p.smb;
-  curl_off_t offset = conn->data->req.offset;
-  curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount;
-  CURLcode result = Curl_get_upload_buffer(conn->data);
+  struct smb_request *req = data->req.p.smb;
+  curl_off_t offset = data->req.offset;
+  curl_off_t upload_size = data->req.size - data->req.bytecount;
+  CURLcode result = Curl_get_upload_buffer(data);
   if(result)
     return result;
-  msg = (struct smb_write *)conn->data->state.ulbuf;
+  msg = (struct smb_write *)data->state.ulbuf;
 
   if(upload_size >= MAX_PAYLOAD_SIZE - 1) /* There is one byte of padding */
     upload_size = MAX_PAYLOAD_SIZE - 1;
@@ -596,25 +612,26 @@ static CURLcode smb_send_write(struct connectdata *conn)
   msg->data_offset = smb_swap16(sizeof(*msg) - sizeof(unsigned int));
   msg->byte_count = smb_swap16((unsigned short) (upload_size + 1));
 
-  smb_format_message(conn, &msg->h, SMB_COM_WRITE_ANDX,
+  smb_format_message(data, &msg->h, SMB_COM_WRITE_ANDX,
                      sizeof(*msg) - sizeof(msg->h) + (size_t) upload_size);
 
-  return smb_send(conn, sizeof(*msg), (size_t) upload_size);
+  return smb_send(data, sizeof(*msg), (size_t) upload_size);
 }
 
-static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
+static CURLcode smb_send_and_recv(struct Curl_easy *data, void **msg)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   CURLcode result;
   *msg = NULL; /* if it returns early */
 
   /* Check if there is data in the transfer buffer */
   if(!smbc->send_size && smbc->upload_size) {
-    size_t nread = smbc->upload_size > conn->data->set.upload_buffer_size ?
-      conn->data->set.upload_buffer_size :
+    size_t nread = smbc->upload_size > data->set.upload_buffer_size ?
+      data->set.upload_buffer_size :
       smbc->upload_size;
-    conn->data->req.upload_fromhere = conn->data->state.ulbuf;
-    result = Curl_fillreadbuffer(conn, nread, &nread);
+    data->req.upload_fromhere = data->state.ulbuf;
+    result = Curl_fillreadbuffer(data, nread, &nread);
     if(result && result != CURLE_AGAIN)
       return result;
     if(!nread)
@@ -627,7 +644,7 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
 
   /* Check if there is data to send */
   if(smbc->send_size) {
-    result = smb_flush(conn);
+    result = smb_flush(data);
     if(result)
       return result;
   }
@@ -636,11 +653,12 @@ static CURLcode smb_send_and_recv(struct connectdata *conn, void **msg)
   if(smbc->send_size || smbc->upload_size)
     return CURLE_AGAIN;
 
-  return smb_recv_message(conn, msg);
+  return smb_recv_message(data, msg);
 }
 
-static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
+static CURLcode smb_connection_state(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
   struct smb_negotiate_response *nrsp;
   struct smb_header *h;
@@ -651,7 +669,8 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
 #ifdef USE_SSL
     if((conn->handler->flags & PROTOPT_SSL)) {
       bool ssl_done = FALSE;
-      result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done);
+      result = Curl_ssl_connect_nonblocking(data, conn,
+                                            FIRSTSOCKET, &ssl_done);
       if(result && result != CURLE_AGAIN)
         return result;
       if(!ssl_done)
@@ -659,17 +678,17 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
     }
 #endif
 
-    result = smb_send_negotiate(conn);
+    result = smb_send_negotiate(data);
     if(result) {
       connclose(conn, "SMB: failed to send negotiate message");
       return result;
     }
 
-    conn_state(conn, SMB_NEGOTIATE);
+    conn_state(data, SMB_NEGOTIATE);
   }
 
   /* Send the previous message and check for a response */
-  result = smb_send_and_recv(conn, &msg);
+  result = smb_send_and_recv(data, &msg);
   if(result && result != CURLE_AGAIN) {
     connclose(conn, "SMB: failed to communicate");
     return result;
@@ -690,12 +709,12 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
     nrsp = msg;
     memcpy(smbc->challenge, nrsp->bytes, sizeof(smbc->challenge));
     smbc->session_key = smb_swap32(nrsp->session_key);
-    result = smb_send_setup(conn);
+    result = smb_send_setup(data);
     if(result) {
       connclose(conn, "SMB: failed to send setup message");
       return result;
     }
-    conn_state(conn, SMB_SETUP);
+    conn_state(data, SMB_SETUP);
     break;
 
   case SMB_SETUP:
@@ -704,7 +723,7 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
       return CURLE_LOGIN_DENIED;
     }
     smbc->uid = smb_swap16(h->uid);
-    conn_state(conn, SMB_CONNECTED);
+    conn_state(data, SMB_CONNECTED);
     *done = true;
     break;
 
@@ -736,9 +755,10 @@ static void get_posix_time(time_t *out, curl_off_t timestamp)
     *out = (time_t) timestamp;
 }
 
-static CURLcode smb_request_state(struct connectdata *conn, bool *done)
+static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
 {
-  struct smb_request *req = conn->data->req.p.smb;
+  struct connectdata *conn = data->conn;
+  struct smb_request *req = data->req.p.smb;
   struct smb_header *h;
   struct smb_conn *smbc = &conn->proto.smbc;
   enum smb_req_state next_state = SMB_DONE;
@@ -750,17 +770,17 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
 
   /* Start the request */
   if(req->state == SMB_REQUESTING) {
-    result = smb_send_tree_connect(conn);
+    result = smb_send_tree_connect(data);
     if(result) {
       connclose(conn, "SMB: failed to send tree connect message");
       return result;
     }
 
-    request_state(conn, SMB_TREE_CONNECT);
+    request_state(data, SMB_TREE_CONNECT);
   }
 
   /* Send the previous message and check for a response */
-  result = smb_send_and_recv(conn, &msg);
+  result = smb_send_and_recv(data, &msg);
   if(result && result != CURLE_AGAIN) {
     connclose(conn, "SMB: failed to communicate");
     return result;
@@ -793,23 +813,23 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
     }
     smb_m = (const struct smb_nt_create_response*) msg;
     req->fid = smb_swap16(smb_m->fid);
-    conn->data->req.offset = 0;
-    if(conn->data->set.upload) {
-      conn->data->req.size = conn->data->state.infilesize;
-      Curl_pgrsSetUploadSize(conn->data, conn->data->req.size);
+    data->req.offset = 0;
+    if(data->set.upload) {
+      data->req.size = data->state.infilesize;
+      Curl_pgrsSetUploadSize(data, data->req.size);
       next_state = SMB_UPLOAD;
     }
     else {
       smb_m = (const struct smb_nt_create_response*) msg;
-      conn->data->req.size = smb_swap64(smb_m->end_of_file);
-      if(conn->data->req.size < 0) {
+      data->req.size = smb_swap64(smb_m->end_of_file);
+      if(data->req.size < 0) {
         req->result = CURLE_WEIRD_SERVER_REPLY;
         next_state = SMB_CLOSE;
       }
       else {
-        Curl_pgrsSetDownloadSize(conn->data, conn->data->req.size);
-        if(conn->data->set.get_filetime)
-          get_posix_time(&conn->data->info.filetime, smb_m->last_change_time);
+        Curl_pgrsSetDownloadSize(data, data->req.size);
+        if(data->set.get_filetime)
+          get_posix_time(&data->info.filetime, smb_m->last_change_time);
         next_state = SMB_DOWNLOAD;
       }
     }
@@ -827,11 +847,11 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
                          sizeof(struct smb_header) + 13);
     if(len > 0) {
       if(off + sizeof(unsigned int) + len > smbc->got) {
-        failf(conn->data, "Invalid input packet");
+        failf(data, "Invalid input packet");
         result = CURLE_RECV_ERROR;
       }
       else
-        result = Curl_client_write(conn, CLIENTWRITE_BODY,
+        result = Curl_client_write(data, CLIENTWRITE_BODY,
                                    (char *)msg + off + sizeof(unsigned int),
                                    len);
       if(result) {
@@ -840,9 +860,9 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
         break;
       }
     }
-    conn->data->req.bytecount += len;
-    conn->data->req.offset += len;
-    Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount);
+    data->req.bytecount += len;
+    data->req.offset += len;
+    Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
     next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD;
     break;
 
@@ -854,10 +874,10 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
     }
     len = Curl_read16_le(((const unsigned char *) msg) +
                          sizeof(struct smb_header) + 5);
-    conn->data->req.bytecount += len;
-    conn->data->req.offset += len;
-    Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount);
-    if(conn->data->req.bytecount >= conn->data->req.size)
+    data->req.bytecount += len;
+    data->req.offset += len;
+    Curl_pgrsSetUploadCounter(data, data->req.bytecount);
+    if(data->req.bytecount >= data->req.size)
       next_state = SMB_CLOSE;
     else
       next_state = SMB_UPLOAD;
@@ -881,23 +901,23 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
 
   switch(next_state) {
   case SMB_OPEN:
-    result = smb_send_open(conn);
+    result = smb_send_open(data);
     break;
 
   case SMB_DOWNLOAD:
-    result = smb_send_read(conn);
+    result = smb_send_read(data);
     break;
 
   case SMB_UPLOAD:
-    result = smb_send_write(conn);
+    result = smb_send_write(data);
     break;
 
   case SMB_CLOSE:
-    result = smb_send_close(conn);
+    result = smb_send_close(data);
     break;
 
   case SMB_TREE_DISCONNECT:
-    result = smb_send_tree_disconnect(conn);
+    result = smb_send_tree_disconnect(data);
     break;
 
   case SMB_DONE:
@@ -914,37 +934,42 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
     return result;
   }
 
-  request_state(conn, next_state);
+  request_state(data, next_state);
 
   return CURLE_OK;
 }
 
-static CURLcode smb_done(struct connectdata *conn, CURLcode status,
+static CURLcode smb_done(struct Curl_easy *data, CURLcode status,
                          bool premature)
 {
   (void) premature;
-  Curl_safefree(conn->data->req.p.smb);
+  Curl_safefree(data->req.p.smb);
   return status;
 }
 
-static CURLcode smb_disconnect(struct connectdata *conn, bool dead)
+static CURLcode smb_disconnect(struct Curl_easy *data,
+                               struct connectdata *conn, bool dead)
 {
   struct smb_conn *smbc = &conn->proto.smbc;
   (void) dead;
+  (void) data;
   Curl_safefree(smbc->share);
   Curl_safefree(smbc->domain);
   Curl_safefree(smbc->recv_buf);
   return CURLE_OK;
 }
 
-static int smb_getsock(struct connectdata *conn, curl_socket_t *socks)
+static int smb_getsock(struct Curl_easy *data,
+                       struct connectdata *conn, curl_socket_t *socks)
 {
+  (void)data;
   socks[0] = conn->sock[FIRSTSOCKET];
   return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0);
 }
 
-static CURLcode smb_do(struct connectdata *conn, bool *done)
+static CURLcode smb_do(struct Curl_easy *data, bool *done)
 {
+  struct connectdata *conn = data->conn;
   struct smb_conn *smbc = &conn->proto.smbc;
 
   *done = FALSE;
@@ -954,9 +979,9 @@ static CURLcode smb_do(struct connectdata *conn, bool *done)
   return CURLE_URL_MALFORMAT;
 }
 
-static CURLcode smb_parse_url_path(struct connectdata *conn)
+static CURLcode smb_parse_url_path(struct Curl_easy *data,
+                                   struct connectdata *conn)
 {
-  struct Curl_easy *data = conn->data;
   struct smb_request *req = data->req.p.smb;
   struct smb_conn *smbc = &conn->proto.smbc;
   char *path;

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 166 - 160
lib/smtp.c


+ 3 - 3
lib/smtp.h

@@ -7,7 +7,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 2009 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2009 - 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
@@ -57,10 +57,10 @@ struct SMTP {
   struct curl_slist *rcpt; /* Recipient list */
   bool rcpt_had_ok;        /* Whether any of RCPT TO commands (depends on
                               total number of recipients) succeeded so far */
+  bool trailing_crlf;      /* Specifies if the trailing CRLF is present */
   int rcpt_last_error;     /* The last error received for RCPT TO command */
   size_t eob;              /* Number of bytes of the EOB (End Of Body) that
                               have been received so far */
-  bool trailing_crlf;      /* Specifies if the tailing CRLF is present */
 };
 
 /* smtp_conn is used for struct connection-oriented data in the connectdata
@@ -91,6 +91,6 @@ extern const struct Curl_handler Curl_handler_smtps;
 #define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
 #define SMTP_EOB_REPL_LEN 4
 
-CURLcode Curl_smtp_escape_eob(struct connectdata *conn, const ssize_t nread);
+CURLcode Curl_smtp_escape_eob(struct Curl_easy *data, const ssize_t nread);
 
 #endif /* HEADER_CURL_SMTP_H */

+ 67 - 67
lib/socks.c

@@ -5,7 +5,7 @@
  *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <[email protected]>, et al.
  *
  * This software is licensed as described in the file COPYING, which
  * you should have received as part of this distribution. The terms
@@ -51,7 +51,7 @@
  *
  * This is STUPID BLOCKING behavior. Only used by the SOCKS GSSAPI functions.
  */
-int Curl_blockread_all(struct connectdata *conn, /* connection data */
+int Curl_blockread_all(struct Curl_easy *data,   /* transfer */
                        curl_socket_t sockfd,     /* read from this socket */
                        char *buf,                /* store read data here */
                        ssize_t buffersize,       /* max amount to read */
@@ -62,7 +62,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
   int result;
   *n = 0;
   for(;;) {
-    timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, TRUE);
+    timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
     if(timeout_ms < 0) {
       /* we already got the timeout */
       result = CURLE_OPERATION_TIMEDOUT;
@@ -107,13 +107,14 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
 
 
 /* always use this function to change state, to make debugging easier */
-static void socksstate(struct connectdata *conn,
+static void socksstate(struct Curl_easy *data,
                        enum connect_t state
 #ifdef DEBUGBUILD
                        , int lineno
 #endif
 )
 {
+  struct connectdata *conn = data->conn;
   enum connect_t oldstate = conn->cnnct.state;
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
   /* synced with the state list in urldata.h */
@@ -146,7 +147,7 @@ static void socksstate(struct connectdata *conn,
   conn->cnnct.state = state;
 
 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
-  infof(conn->data,
+  infof(data,
         "SXSTATE: %s => %s conn %p; line %d\n",
         statename[oldstate], statename[conn->cnnct.state], conn,
         lineno);
@@ -188,29 +189,32 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
                           const char *hostname,
                           int remote_port,
                           int sockindex,
-                          struct connectdata *conn,
+                          struct Curl_easy *data,
                           bool *done)
 {
+  struct connectdata *conn = data->conn;
   const bool protocol4a =
     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS4A) ? TRUE : FALSE;
-  unsigned char *socksreq = &conn->cnnct.socksreq[0];
+  unsigned char *socksreq = (unsigned char *)data->state.buffer;
   CURLcode result;
   curl_socket_t sockfd = conn->sock[sockindex];
-  struct Curl_easy *data = conn->data;
   struct connstate *sx = &conn->cnnct;
   struct Curl_dns_entry *dns = NULL;
   ssize_t actualread;
   ssize_t written;
 
+  /* make sure that the buffer is at least 600 bytes */
+  DEBUGASSERT(READBUFFER_MIN >= 600);
+
   if(!SOCKS_STATE(sx->state) && !*done)
-    sxstate(conn, CONNECT_SOCKS_INIT);
+    sxstate(data, CONNECT_SOCKS_INIT);
 
   switch(sx->state) {
   case CONNECT_SOCKS_INIT:
     /* SOCKS4 can only do IPv4, insist! */
     conn->ip_version = CURL_IPRESOLVE_V4;
     if(conn->bits.httpproxy)
-      infof(conn->data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
+      infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d\n",
             protocol4a ? "a" : "", hostname, remote_port);
 
     infof(data, "SOCKS4 communication to %s:%d\n", hostname, remote_port);
@@ -234,37 +238,37 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
     /* DNS resolve only for SOCKS4, not SOCKS4a */
     if(!protocol4a) {
       enum resolve_t rc =
-        Curl_resolv(conn, hostname, remote_port, FALSE, &dns);
+        Curl_resolv(data, hostname, remote_port, FALSE, &dns);
 
       if(rc == CURLRESOLV_ERROR)
         return CURLPX_RESOLVE_HOST;
       else if(rc == CURLRESOLV_PENDING) {
-        sxstate(conn, CONNECT_RESOLVING);
+        sxstate(data, CONNECT_RESOLVING);
         infof(data, "SOCKS4 non-blocking resolve of %s\n", hostname);
         return CURLPX_OK;
       }
-      sxstate(conn, CONNECT_RESOLVED);
+      sxstate(data, CONNECT_RESOLVED);
       goto CONNECT_RESOLVED;
     }
 
     /* socks4a doesn't resolve anything locally */
-    sxstate(conn, CONNECT_REQ_INIT);
+    sxstate(data, CONNECT_REQ_INIT);
     goto CONNECT_REQ_INIT;
 
   case CONNECT_RESOLVING:
     /* check if we have the name resolved by now */
-    dns = Curl_fetch_addr(conn, hostname, (int)conn->port);
+    dns = Curl_fetch_addr(data, hostname, (int)conn->port);
 
     if(dns) {
 #ifdef CURLRES_ASYNCH
-      conn->async.dns = dns;
-      conn->async.done = TRUE;
+      data->state.async.dns = dns;
+      data->state.async.done = TRUE;
 #endif
       infof(data, "Hostname '%s' was found\n", hostname);
-      sxstate(conn, CONNECT_RESOLVED);
+      sxstate(data, CONNECT_RESOLVED);
     }
     else {
-      result = Curl_resolv_check(data->conn, &dns);
+      result = Curl_resolv_check(data, &dns);
       if(!dns) {
         if(result)
           return CURLPX_RESOLVE_HOST;
@@ -298,7 +302,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
       }
       else {
         hp = NULL; /* fail! */
-        failf(data, "SOCKS4 connection to %s not supported\n", buf);
+        failf(data, "SOCKS4 connection to %s not supported", buf);
       }
 
       Curl_resolv_unlock(data, dns); /* not used anymore from now on */
@@ -318,8 +322,8 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
     socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
     if(proxy_user) {
       size_t plen = strlen(proxy_user);
-      if(plen >= sizeof(sx->socksreq) - 8) {
-        failf(data, "Too long SOCKS proxy user name, can't use!\n");
+      if(plen >= (size_t)data->set.buffer_size - 8) {
+        failf(data, "Too long SOCKS proxy user name, can't use!");
         return CURLPX_LONG_USER;
       }
       /* copy the proxy name WITH trailing zero */
@@ -352,12 +356,12 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
       }
       sx->outp = socksreq;
       sx->outstanding = packetsize;
-      sxstate(conn, CONNECT_REQ_SENDING);
+      sxstate(data, CONNECT_REQ_SENDING);
     }
     /* FALLTHROUGH */
   case CONNECT_REQ_SENDING:
     /* Send request */
-    result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
+    result = Curl_write_plain(data, sockfd, (char *)sx->outp,
                               sx->outstanding, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Failed to send SOCKS4 connect request.");
@@ -373,7 +377,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
     /* done sending! */
     sx->outstanding = 8; /* receive data size */
     sx->outp = socksreq;
-    sxstate(conn, CONNECT_SOCKS_READ);
+    sxstate(data, CONNECT_SOCKS_READ);
 
     /* FALLTHROUGH */
   case CONNECT_SOCKS_READ:
@@ -396,7 +400,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
       sx->outp += actualread;
       return CURLPX_OK;
     }
-    sxstate(conn, CONNECT_DONE);
+    sxstate(data, CONNECT_DONE);
     break;
   default: /* lots of unused states in SOCKS4 */
     break;
@@ -437,8 +441,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
     failf(data,
           "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
           ", request rejected or failed.",
-          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
-          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
           (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
           (unsigned char)socksreq[1]);
     return CURLPX_REQUEST_FAILED;
@@ -447,8 +450,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
           "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
           ", request rejected because SOCKS server cannot connect to "
           "identd on the client.",
-          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
-          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
           (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
           (unsigned char)socksreq[1]);
     return CURLPX_IDENTD;
@@ -457,8 +459,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
           "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
           ", request rejected because the client program and identd "
           "report different user-ids.",
-          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
-          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
           (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
           (unsigned char)socksreq[1]);
     return CURLPX_IDENTD_DIFFER;
@@ -466,8 +467,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
     failf(data,
           "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
           ", Unknown.",
-          (unsigned char)socksreq[4], (unsigned char)socksreq[5],
-          (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+          socksreq[4], socksreq[5], socksreq[6], socksreq[7],
           (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]),
           (unsigned char)socksreq[1]);
     return CURLPX_UNKNOWN_FAIL;
@@ -486,7 +486,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
                           const char *hostname,
                           int remote_port,
                           int sockindex,
-                          struct connectdata *conn,
+                          struct Curl_easy *data,
                           bool *done)
 {
   /*
@@ -505,14 +505,14 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
     o  REP    Reply field:
     o  X'00' succeeded
   */
-  unsigned char *socksreq = &conn->cnnct.socksreq[0];
+  struct connectdata *conn = data->conn;
+  unsigned char *socksreq = (unsigned char *)data->state.buffer;
   char dest[256] = "unknown";  /* printable hostname:port */
   int idx;
   ssize_t actualread;
   ssize_t written;
   CURLcode result;
   curl_socket_t sockfd = conn->sock[sockindex];
-  struct Curl_easy *data = conn->data;
   bool socks5_resolve_local =
     (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5) ? TRUE : FALSE;
   const size_t hostname_len = strlen(hostname);
@@ -523,23 +523,23 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
   struct Curl_dns_entry *dns = NULL;
 
   if(!SOCKS_STATE(sx->state) && !*done)
-    sxstate(conn, CONNECT_SOCKS_INIT);
+    sxstate(data, CONNECT_SOCKS_INIT);
 
   switch(sx->state) {
   case CONNECT_SOCKS_INIT:
     if(conn->bits.httpproxy)
-      infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
+      infof(data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
             hostname, remote_port);
 
     /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
     if(!socks5_resolve_local && hostname_len > 255) {
-      infof(conn->data, "SOCKS5: server resolving disabled for hostnames of "
+      infof(data, "SOCKS5: server resolving disabled for hostnames of "
             "length > 255 [actual len=%zu]\n", hostname_len);
       socks5_resolve_local = TRUE;
     }
 
     if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI))
-      infof(conn->data,
+      infof(data,
             "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %lu\n",
             auth);
     if(!(auth & CURLAUTH_BASIC))
@@ -561,21 +561,21 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
     /* write the number of authentication methods */
     socksreq[1] = (unsigned char) (idx - 2);
 
-    result = Curl_write_plain(conn, sockfd, (char *)socksreq, idx, &written);
+    result = Curl_write_plain(data, sockfd, (char *)socksreq, idx, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Unable to send initial SOCKS5 request.");
       return CURLPX_SEND_CONNECT;
     }
     if(written != idx) {
-      sxstate(conn, CONNECT_SOCKS_SEND);
+      sxstate(data, CONNECT_SOCKS_SEND);
       sx->outstanding = idx - written;
       sx->outp = &socksreq[written];
       return CURLPX_OK;
     }
-    sxstate(conn, CONNECT_SOCKS_READ);
+    sxstate(data, CONNECT_SOCKS_READ);
     goto CONNECT_SOCKS_READ_INIT;
   case CONNECT_SOCKS_SEND:
-    result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
+    result = Curl_write_plain(data, sockfd, (char *)sx->outp,
                               sx->outstanding, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Unable to send initial SOCKS5 request.");
@@ -617,18 +617,18 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
     }
     else if(socksreq[1] == 0) {
       /* DONE! No authentication needed. Send request. */
-      sxstate(conn, CONNECT_REQ_INIT);
+      sxstate(data, CONNECT_REQ_INIT);
       goto CONNECT_REQ_INIT;
     }
     else if(socksreq[1] == 2) {
       /* regular name + password authentication */
-      sxstate(conn, CONNECT_AUTH_INIT);
+      sxstate(data, CONNECT_AUTH_INIT);
       goto CONNECT_AUTH_INIT;
     }
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
     else if(allow_gssapi && (socksreq[1] == 1)) {
-      sxstate(conn, CONNECT_GSSAPI_INIT);
-      result = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
+      sxstate(data, CONNECT_GSSAPI_INIT);
+      result = Curl_SOCKS5_gssapi_negotiate(sockindex, data);
       if(result) {
         failf(data, "Unable to negotiate SOCKS5 GSS-API context.");
         return CURLPX_GSSAPI;
@@ -701,13 +701,13 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
       memcpy(socksreq + len, proxy_password, proxy_password_len);
     }
     len += proxy_password_len;
-    sxstate(conn, CONNECT_AUTH_SEND);
+    sxstate(data, CONNECT_AUTH_SEND);
     sx->outstanding = len;
     sx->outp = socksreq;
   }
     /* FALLTHROUGH */
   case CONNECT_AUTH_SEND:
-    result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
+    result = Curl_write_plain(data, sockfd, (char *)sx->outp,
                               sx->outstanding, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Failed to send SOCKS5 sub-negotiation request.");
@@ -721,7 +721,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
     }
     sx->outp = socksreq;
     sx->outstanding = 2;
-    sxstate(conn, CONNECT_AUTH_READ);
+    sxstate(data, CONNECT_AUTH_READ);
     /* FALLTHROUGH */
   case CONNECT_AUTH_READ:
     result = Curl_read_plain(sockfd, (char *)sx->outp,
@@ -749,40 +749,40 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
     }
 
     /* Everything is good so far, user was authenticated! */
-    sxstate(conn, CONNECT_REQ_INIT);
+    sxstate(data, CONNECT_REQ_INIT);
     /* FALLTHROUGH */
   CONNECT_REQ_INIT:
   case CONNECT_REQ_INIT:
     if(socks5_resolve_local) {
-      enum resolve_t rc = Curl_resolv(conn, hostname, remote_port,
+      enum resolve_t rc = Curl_resolv(data, hostname, remote_port,
                                       FALSE, &dns);
 
       if(rc == CURLRESOLV_ERROR)
         return CURLPX_RESOLVE_HOST;
 
       if(rc == CURLRESOLV_PENDING) {
-        sxstate(conn, CONNECT_RESOLVING);
+        sxstate(data, CONNECT_RESOLVING);
         return CURLPX_OK;
       }
-      sxstate(conn, CONNECT_RESOLVED);
+      sxstate(data, CONNECT_RESOLVED);
       goto CONNECT_RESOLVED;
     }
     goto CONNECT_RESOLVE_REMOTE;
 
   case CONNECT_RESOLVING:
     /* check if we have the name resolved by now */
-    dns = Curl_fetch_addr(conn, hostname, remote_port);
+    dns = Curl_fetch_addr(data, hostname, remote_port);
 
     if(dns) {
 #ifdef CURLRES_ASYNCH
-      conn->async.dns = dns;
-      conn->async.done = TRUE;
+      data->state.async.dns = dns;
+      data->state.async.done = TRUE;
 #endif
       infof(data, "SOCKS5: hostname '%s' found\n", hostname);
     }
 
     if(!dns) {
-      result = Curl_resolv_check(data->conn, &dns);
+      result = Curl_resolv_check(data, &dns);
       if(!dns) {
         if(result)
           return CURLPX_RESOLVE_HOST;
@@ -839,7 +839,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
 #endif
     else {
       hp = NULL; /* fail! */
-      failf(data, "SOCKS5 connection to %s not supported\n", dest);
+      failf(data, "SOCKS5 connection to %s not supported", dest);
     }
 
     Curl_resolv_unlock(data, dns); /* not used anymore from now on */
@@ -878,10 +878,10 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
 #endif
     sx->outp = socksreq;
     sx->outstanding = len;
-    sxstate(conn, CONNECT_REQ_SENDING);
+    sxstate(data, CONNECT_REQ_SENDING);
     /* FALLTHROUGH */
   case CONNECT_REQ_SENDING:
-    result = Curl_write_plain(conn, sockfd, (char *)sx->outp,
+    result = Curl_write_plain(data, sockfd, (char *)sx->outp,
                               sx->outstanding, &written);
     if(result && (CURLE_AGAIN != result)) {
       failf(data, "Failed to send SOCKS5 connect request.");
@@ -901,7 +901,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
 #endif
     sx->outstanding = 10; /* minimum packet size is 10 */
     sx->outp = socksreq;
-    sxstate(conn, CONNECT_REQ_READ);
+    sxstate(data, CONNECT_REQ_READ);
     /* FALLTHROUGH */
   case CONNECT_REQ_READ:
     result = Curl_read_plain(sockfd, (char *)sx->outp,
@@ -992,10 +992,10 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
       if(len > 10) {
         sx->outstanding = len - 10; /* get the rest */
         sx->outp = &socksreq[10];
-        sxstate(conn, CONNECT_REQ_READ_MORE);
+        sxstate(data, CONNECT_REQ_READ_MORE);
       }
       else {
-        sxstate(conn, CONNECT_DONE);
+        sxstate(data, CONNECT_DONE);
         break;
       }
 #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
@@ -1020,7 +1020,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
       sx->outp += actualread;
       return CURLPX_OK;
     }
-    sxstate(conn, CONNECT_DONE);
+    sxstate(data, CONNECT_DONE);
   }
   infof(data, "SOCKS5 request granted.\n");
 

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