Code extracted from: https://github.com/curl/curl.git at commit 2f33be817cbce6ad7a36f27dd7ada9219f13584c (curl-7_75_0).
@@ -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)
# 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,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.
@@ -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;
@@ -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
@@ -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 || \
@@ -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
@@ -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 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);
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;
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)
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,
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;
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 */
/* 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;
/* 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");
@@ -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;
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) {
- conn->async.hostname = NULL;
+ data->state.async.hostname = NULL;
return NULL;
- conn->async.tdata = res;
+ data->state.async.tdata = res;
/* initial status - failed */
res->last_status = ARES_ENOTFOUND;
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);
- PF_INET6, query_completed_cb, conn);
+ ares_gethostbyname((ares_channel)data->state.async.resolver, hostname,
+ PF_INET, query_completed_cb, data);
+ PF_INET6, query_completed_cb, data);
res->num_pending = 1;
@@ -694,8 +691,9 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
- 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);
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));
@@ -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);
@@ -145,13 +145,13 @@ static void destroy_async_data(struct Curl_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 */
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)
curl_socket_t sock_rd = td->tsd.sock_pair[0];
- struct connectdata *conn = td->tsd.conn;
+ struct Curl_easy *data = td->tsd.data;
@@ -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);
@@ -430,32 +428,33 @@ static void destroy_async_data(struct Curl_async *async)
* Returns FALSE in case of failure, otherwise TRUE.
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.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);
- 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(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);
@@ -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;
- 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)) {
- result = getaddrinfo_complete(conn);
+ result = getaddrinfo_complete(data);
DEBUGASSERT(0);
- conn->async.done = TRUE;
+ data->state.async.done = TRUE;
- 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);
- connclose(conn, "asynch resolve failed");
+ connclose(data->conn, "asynch resolve failed");
@@ -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.
+ 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);
@@ -581,10 +583,10 @@ void Curl_resolver_kill(struct connectdata *conn)
* This is the version for resolves-in-a-thread.
- 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.
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);
- CURLcode result = resolver_error(conn);
+ CURLcode result = resolver_error(data);
/* 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);
- 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 resdata *reslv = (struct resdata *)data->state.resolver;
+ struct resdata *reslv = (struct resdata *)data->state.async.resolver;
(void)socks;
@@ -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);
@@ -693,25 +691,24 @@ int Curl_resolver_getsock(struct connectdata *conn,
* Curl_getaddrinfo() - for platforms without getaddrinfo
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)) {
- failf(conn->data, "getaddrinfo() thread failed\n");
+ failf(data, "getaddrinfo() thread failed");
@@ -721,15 +718,14 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
* Curl_resolver_getaddrinfo() - for getaddrinfo
struct addrinfo hints;
int pf = PF_INET;
@@ -737,7 +733,7 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
* Check if a limited name resolve has been requested.
case CURL_IPRESOLVE_V4:
pf = PF_INET;
@@ -749,24 +745,24 @@ struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
- if((pf != PF_INET) && !Curl_ipv6works(conn))
+ if((pf != PF_INET) && !Curl_ipv6works(data))
/* The stack seems to be a non-IPv6 one */
#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;
- if(init_resolve_thread(conn, hostname, port, &hints)) {
+ if(init_resolve_thread(data, hostname, port, &hints)) {
- failf(data, "getaddrinfo() thread failed to start\n");
+ failf(data, "getaddrinfo() thread failed to start");
@@ -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);
-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);
struct Curl_dns_entry **dns);
@@ -139,7 +139,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
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.
int *waitp);
@@ -0,0 +1,908 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * 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>
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#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;
+ 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 (size_t)nread;
+}
+size_t Curl_hyper_send(void *userp, hyper_context *ctx,
+ const uint8_t *buf, size_t buflen)
+ ssize_t nwrote;
+ result = Curl_write(data, conn->sockfd, (void *)buf, buflen, &nwrote);
+ 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");
+ failf(data, "Curl_write failed");
+ 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;
+ 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"))
+ 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;
+ Curl_debug(data, CURLINFO_HEADER_IN, headp, len);
+ result = Curl_client_write(data, CLIENTWRITE_HEADER, headp, len);
+ data->state.hresult = CURLE_ABORTED_BY_CALLBACK;
+ 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 SingleRequest *k = &data->req;
+ 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");
+ if(k->ignorebody)
+ Curl_debug(data, CURLINFO_DATA_IN, buf, len);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, buf, len);
+ data->req.bytecount += len;
+ Curl_pgrsSetDownloadCounter(data, data->req.bytecount);
+/*
+ * 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)
+ size_t wrote;
+ 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;
+ result = Curl_dyn_addf(&data->state.headerb, "HTTP/%s %03d %.*s\r\n",
+ vstr,
+ (int)http_status,
+ (int)rlen, reason);
+ 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;
+ 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,
+ 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);
+ case HYPER_TASK_RESPONSE:
+ resp = hyper_task_value(task);
+ default:
+ 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");
+ 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);
+ else if(h->endtask == task) {
+ /* end of transfer */
+ infof(data, "hyperstream is done!\n");
+ else if(t != HYPER_TASK_RESPONSE) {
+ /* HYPER_TASK_RESPONSE */
+ 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);
+ headers = hyper_response_headers(resp);
+ if(!headers) {
+ failf(data, "hyperstream: couldn't get response headers");
+ /* the headers are already received */
+ hyper_headers_foreach(headers, hyper_each_header, data);
+ if(data->state.hresult) {
+ if(empty_header(data)) {
+ failf(data, "hyperstream: couldn't pass blank header");
+ result = CURLE_OUT_OF_MEMORY;
+ /* 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);
+ resp_body = hyper_response_body(resp);
+ if(!resp_body) {
+ failf(data, "hyperstream: couldn't get response body");
+ foreach = hyper_body_foreach(resp_body, hyper_body_chunk, data);
+ if(!foreach) {
+ failf(data, "hyperstream: body foreach failed");
+ 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");
+ h->endtask = foreach;
+ hyper_response_free(resp);
+ resp = NULL;
+ } while(1);
+ if(resp)
+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);
+ * 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)
+ n = line;
+ 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 */
+ p = strchr(v, '\0');
+ newline = FALSE; /* no newline */
+ 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");
+ if(data->set.verbose) {
+ char *ptr = NULL;
+ if(!newline) {
+ ptr = aprintf("%.*s\r\n", (int)linelen, line);
+ if(!ptr)
+ Curl_debug(data, CURLINFO_HEADER_OUT, ptr, linelen + 2);
+ free(ptr);
+ Curl_debug(data, CURLINFO_HEADER_OUT, (char *)line, linelen);
+ numh++;
+ n += linelen;
+ } while(newline);
+static CURLcode request_target(struct Curl_easy *data,
+ bool h2,
+ hyper_request *req)
+ struct dynbuf r;
+ Curl_dyn_init(&r, DYN_HTTP_REQUEST);
+ result = Curl_http_target(data, conn, &r);
+ if(hyper_request_set_uri(req, (uint8_t *)Curl_dyn_uptr(&r),
+ Curl_dyn_len(&r))) {
+ failf(data, "error setting path");
+ result = debug_request(data, method, Curl_dyn_ptr(&r), h2);
+ Curl_dyn_free(&r);
+static int uploadpostfields(void *userdata, hyper_context *ctx,
+ hyper_buf **chunk)
+ if(data->req.upload_done)
+ *chunk = NULL; /* nothing more to deliver */
+ /* 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,
+ size_t fillcount;
+ CURLcode result =
+ Curl_fillreadbuffer(data, data->set.upload_buffer_size, &fillcount);
+ return HYPER_POLL_ERROR;
+ if(!fillcount)
+ /* done! */
+ *chunk = NULL;
+ *chunk = hyper_buf_copy((uint8_t *)data->state.ulbuf, fillcount);
+ * bodysend() sets up headers in the outgoing request for a HTTP transfer that
+ * sends a body
+static CURLcode bodysend(struct Curl_easy *data,
+ hyper_headers *headers,
+ hyper_request *hyperreq,
+ Curl_HttpReq httpreq)
+ struct dynbuf req;
+ if((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD))
+ Curl_pgrsSetUploadSize(data, 0); /* no request body */
+ 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);
+ result = Curl_get_upload_buffer(data);
+ /* 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);
+static CURLcode cookies(struct Curl_easy *data,
+ hyper_headers *headers)
+ result = Curl_http_cookies(data, conn, &req);
+ * 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)
+ 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_task *handshake = NULL;
+ 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. */
+ infof(data, "Time for the Hyper dance\n");
+ memset(h, 0, sizeof(struct hyptransfer));
+ result = Curl_http_host(data, conn);
+ 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)
+ result = Curl_http_output_auth(data, conn, method, httpreq,
+ (pq ? pq : data->state.up.path), FALSE);
+ free(pq);
+ result = Curl_http_resume(data, conn, httpreq);
+ result = Curl_http_range(data, httpreq);
+ result = Curl_http_useragent(data);
+ 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();
+ failf(data, "Couldn't create hyper executor");
+ options = hyper_clientconn_options_new();
+ if(!options) {
+ failf(data, "Couldn't create hyper client options");
+ 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");
+ io = NULL;
+ options = NULL;
+ if(HYPERE_OK != hyper_executor_push(h->exec, handshake)) {
+ failf(data, "Couldn't hyper_executor_push the handshake");
+ handshake = NULL; /* ownership passed on */
+ failf(data, "Couldn't hyper_executor_poll the handshake");
+ client = hyper_task_value(task);
+ req = hyper_request_new();
+ if(!req) {
+ failf(data, "Couldn't hyper_request_new");
+ 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");
+ if(hyper_request_set_method(req, (uint8_t *)method, strlen(method))) {
+ failf(data, "error setting method");
+ result = request_target(data, conn, method, h2, req);
+ headers = hyper_request_headers(req);
+ failf(data, "hyper_request_headers");
+ result = Curl_http_body(data, conn, httpreq, &te);
+ if(data->state.aptr.host &&
+ Curl_hyper_header(data, headers, data->state.aptr.host))
+ if(data->state.aptr.proxyuserpwd &&
+ Curl_hyper_header(data, headers, data->state.aptr.proxyuserpwd))
+ if(data->state.aptr.userpwd &&
+ Curl_hyper_header(data, headers, data->state.aptr.userpwd))
+ if((data->state.use_range && data->state.aptr.rangeline) &&
+ Curl_hyper_header(data, headers, data->state.aptr.rangeline))
+ if(data->set.str[STRING_USERAGENT] &&
+ *data->set.str[STRING_USERAGENT] &&
+ data->state.aptr.uagent &&
+ Curl_hyper_header(data, headers, data->state.aptr.uagent))
+ p_accept = Curl_checkheaders(data, "Accept")?NULL:"Accept: */*\r\n";
+ if(p_accept && Curl_hyper_header(data, headers, p_accept))
+ if(te && Curl_hyper_header(data, headers, te))
+#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"))
+ 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)
+ if(Curl_hyper_header(data, headers, data->state.aptr.ref))
+ result = cookies(data, conn, headers);
+ result = Curl_add_timecondition(data, headers);
+ result = Curl_add_custom_headers(data, FALSE, headers);
+ result = bodysend(data, conn, headers, req, httpreq);
+ 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");
+ if(HYPERE_OK != hyper_executor_push(h->exec, sendtask)) {
+ failf(data, "Couldn't hyper_executor_push the send");
+ hyper_clientconn_free(client);
+ if(task) {
+ bool error = hyper_task_type(task) == HYPER_TASK_ERROR;
+ if(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;
+ error:
+ if(io)
+ hyper_io_free(io);
+ if(options)
+ hyper_clientconn_options_free(options);
+ if(handshake)
+ hyper_task_free(handshake);
+ if(hypererr) {
+void Curl_hyper_done(struct Curl_easy *data)
+ if(h->exec) {
+ hyper_executor_free(h->exec);
+ h->exec = NULL;
+ if(h->read_waker) {
+ hyper_waker_free(h->read_waker);
+ if(h->write_waker) {
+ hyper_waker_free(h->write_waker);
+#endif /* !defined(CURL_DISABLE_HTTP) && defined(USE_HYPER) */
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_HYPER_H
+#define HEADER_CURL_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;
+};
+ uint8_t *buf, size_t buflen);
+ const uint8_t *buf, size_t buflen);
+ int select_res);
+ const char *line);
+void Curl_hyper_done(struct Curl_easy *);
+#else
+#define Curl_hyper_done(x)
+#endif /* HEADER_CURL_HYPER_H */
@@ -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.
@@ -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 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)
+ struct conncache *connc = data->state.conn_cache;
/* *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) {
@@ -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);
@@ -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)
- if(!CONN_INUSE(conn) && !conn->data && !conn->bits.close &&
+ if(!CONN_INUSE(conn) && !conn->bits.close &&
!conn->bits.connect_only) {
@@ -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);
- * 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]>
@@ -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) \
+ DEBUGASSERT((x)->state.conncache_lock); \
+ (x)->state.conncache_lock = FALSE; \
+ Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \
#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 Curl_easy *data,
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);
- 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);
- int (*func)(struct connectdata *conn,
void *param));
struct connectdata *
@@ -160,7 +160,8 @@ tcpkeepalive(struct Curl_easy *data,
static CURLcode
-singleipconnect(struct connectdata *conn,
+singleipconnect(struct Curl_easy *data,
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_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;
/*************************************************************
* 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;
if(af == AF_INET)
@@ -355,9 +358,9 @@ static CURLcode bindlocal(struct connectdata *conn,
conn->ip_version = CURL_IPRESOLVE_V6;
- 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);
+ (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
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,
int sockindex,
int tempindex)
@@ -586,7 +592,7 @@ static CURLcode trynextip(struct connectdata *conn,
while(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);
-/* 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);
+ 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)));
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)));
- memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
+ (void)data;
(void)conn;
(void)sockfd;
@@ -701,7 +714,8 @@ void Curl_conninfo_remote(struct connectdata *conn, curl_socket_t sockfd)
-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
@@ -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)) {
- failf(conn->data, "getsockname() failed with errno %d: %s",
+ failf(data, "getsockname() failed with errno %d: %s",
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",
- (void)conn;
+ (void)local_ip;
+ (void)local_port;
-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)
CURLproxycode pxresult = CURLPX_OK;
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);
case CURLPROXY_SOCKS4:
case CURLPROXY_SOCKS4A:
pxresult = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
- conn, done);
+ data, done);
- 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;
(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,
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,
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);
@@ -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;
connkeep(conn, "HTTP/3 default");
@@ -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 */
if(result || !*connected)
@@ -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)
@@ -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,
-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)
- (void) conn;
+ (void) data;
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)));
@@ -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)
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,
const struct Curl_addrinfo *ai,
@@ -1131,7 +1155,6 @@ static CURLcode singleipconnect(struct connectdata *conn,
int rc = -1;
bool isconnected = FALSE;
curl_socket_t sockfd;
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);
@@ -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",
- Curl_closesocket(conn, sockfd);
+ Curl_closesocket(data, conn, sockfd);
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;
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
) {
- 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);
error = SOCKERRNO;
@@ -1303,7 +1326,7 @@ static CURLcode singleipconnect(struct connectdata *conn,
data->state.os_errno = error;
/* connect failed */
@@ -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)
CURLcode result = CURLE_COULDNT_CONNECT;
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);
@@ -1370,7 +1393,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
- Curl_expire(conn->data, data->set.happy_eyeballs_timeout,
+ Curl_expire(data, data->set.happy_eyeballs_timeout,
EXPIRE_HAPPY_EYEBALLS);
@@ -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;
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;
- Curl_multi_closed(conn->data, sock);
- Curl_set_in_callback(conn->data, true);
+ Curl_multi_closed(data, sock);
rc = conn->fclosesocket(conn->closesocket_client, sock);
- Curl_set_in_callback(conn->data, false);
return rc;
if(conn)
/* tell the multi-socket code about this */
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,
struct Curl_sockaddr_ex *addr,
curl_socket_t *sockfd)
struct Curl_sockaddr_ex dummy;
if(!addr)
@@ -1568,8 +1593,21 @@ CURLcode Curl_socket(struct connectdata *conn,
- 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));
+ case AF_INET6:
+ (void)setsockopt(*sockfd, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
@@ -1582,16 +1620,20 @@ void Curl_conncontrol(struct connectdata *conn,
)
- /* 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 */
+ 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 */
@@ -27,11 +27,13 @@
#include "sockaddr.h"
#include "timeval.h"
bool *connected);
-CURLcode Curl_connecthost(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
-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);
+ curl_socket_t sockfd);
+void Curl_conninfo_remote(struct Curl_easy *data, struct connectdata *conn,
+ char *local_ip, long *local_port);
+ char *local_ip, long local_port);
+ 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!
curl_socket_t *sockfd);
@@ -104,9 +104,8 @@ zfree_cb(voidpf opaque, voidpf ptr)
-process_zlib_error(struct connectdata *conn, z_stream *z)
+process_zlib_error(struct Curl_easy *data, z_stream *z)
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)
-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;
-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);
/* 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,
-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);
- exit_zlib(conn, z, &zp->zlib_init, result);
+ exit_zlib(data, z, &zp->zlib_init, result);
@@ -223,7 +222,7 @@ static CURLcode inflate_stream(struct connectdata *conn,
/* No more data to flush: just exit loop. */
case Z_STREAM_END:
- result = process_trailer(conn, zp);
+ result = process_trailer(data, zp);
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 */
- 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));
@@ -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;
-static CURLcode deflate_unencode_write(struct connectdata *conn,
+static CURLcode deflate_unencode_write(struct Curl_easy *data,
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,
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,
@@ -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) {
zp->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
/* we must parse the gzip header and trailer ourselves */
if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
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 {
-static CURLcode gzip_unencode_write(struct connectdata *conn,
+static CURLcode gzip_unencode_write(struct Curl_easy *data,
@@ -445,13 +444,13 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
z->next_in = (Bytef *) buf;
- 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. */
/* 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->next_in = malloc(z->avail_in);
if(z->next_in == NULL) {
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:
- 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);
/* 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,
@@ -541,7 +540,7 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
case ZLIB_EXTERNAL_TRAILER:
case ZLIB_GZIP_INFLATING:
@@ -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);
-static void gzip_close_writer(struct connectdata *conn,
+static void gzip_close_writer(struct Curl_easy *data,
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 brotli_params *bp = (struct brotli_params *) &writer->params;
if(!writer->downstream)
@@ -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,
@@ -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);
@@ -687,11 +686,11 @@ static CURLcode brotli_unencode_write(struct connectdata *conn,
-static void brotli_close_writer(struct connectdata *conn,
+static void brotli_close_writer(struct Curl_easy *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 zstd_params *zp = (struct zstd_params *)&writer->params;
@@ -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)
@@ -760,7 +759,7 @@ static CURLcode zstd_unencode_write(struct connectdata *conn,
return CURLE_BAD_CONTENT_ENCODING;
if(out.pos > 0) {
zp->decomp, out.pos);
@@ -772,11 +771,11 @@ static CURLcode zstd_unencode_write(struct connectdata *conn,
-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)
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,
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,
- 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,
(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,
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 SingleRequest *k = &data->req;
@@ -904,13 +902,13 @@ static CURLcode client_unencode_write(struct connectdata *conn,
if(!nbytes || k->ignorebody)
- 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,
@@ -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,
-static CURLcode error_unencode_write(struct connectdata *conn,
+static CURLcode error_unencode_write(struct Curl_easy *data,
@@ -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);
-static void error_close_writer(struct connectdata *conn,
+static void error_close_writer(struct Curl_easy *data,
@@ -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,
if(!nbytes)
- 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 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);
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)
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)
@@ -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)
k->writer_stack = writer;
@@ -1081,29 +1077,29 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
/* Stubs for builds without HTTP. */
(void) enclist;
(void) maybechunked;
return CURLE_NOT_BUILT_IN;
(void) buf;
(void) nbytes;
char *Curl_all_content_encodings(void)
@@ -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,
const char *buf, size_t nbytes);
- void (*close_writer)(struct connectdata *conn,
+ void (*close_writer)(struct Curl_easy *data,
size_t paramsize;
const char *enclist, int maybechunked);
-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 */
@@ -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)
* 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);
+#pragma optimize("", on)
* Hash this domain.
@@ -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 */
@@ -285,7 +285,7 @@ Curl_he2ai(const struct hostent *he, int port)
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;
@@ -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
- * Copyright (C) 2011 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2011 - 2021, Daniel Stenberg, <[email protected]>, et al.
@@ -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)prefix;
#endif /* HAVE_GSSAPI */
@@ -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);
#define Curl_sec_end(x)
@@ -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,
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))
@@ -352,17 +355,17 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
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");
*state = NTLMSTATE_NONE;
else if(*state >= NTLMSTATE_TYPE1) {
- infof(conn->data, "NTLM handshake failure (internal error)\n");
+ infof(data, "NTLM handshake failure (internal error)\n");
@@ -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;
CURLcode res = CURLE_OK;
- DEBUGASSERT(conn->data);
if(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;
@@ -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);
@@ -454,7 +457,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
char *input = aprintf("TT %s\n", ntlm->challenge);
if(!input)
- res = ntlm_wb_response(conn->data, ntlm, input, *state);
+ res = ntlm_wb_response(data, ntlm, input, *state);
free(input);
@@ -28,11 +28,13 @@
defined(NTLM_WB_ENABLED)
/* this is for ntlm header input */
-CURLcode Curl_input_ntlm_wb(struct connectdata *conn, bool proxy,
+ 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);
+ bool proxy);
void Curl_http_auth_cleanup_ntlm_wb(struct connectdata *conn);
@@ -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 */
char *real_path = NULL;
char *working_path;
size_t working_path_len;
@@ -47,7 +46,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
/* 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,
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);
@@ -39,7 +39,7 @@
have their definition hidden well */
char *homedir,
char **path);
@@ -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;
if(data->state.use_range && data->state.range) {
CURLofft from_t;
@@ -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 */
* Copyright (C) 2010, Howard Chu, <[email protected]>
@@ -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)
+ 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)
-static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
+static CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
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)
-static CURLcode rtmp_do(struct connectdata *conn, bool *done)
+static CURLcode rtmp_do(struct Curl_easy *data, bool *done)
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)
-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 */
-static CURLcode rtmp_disconnect(struct connectdata *conn,
bool dead_connection)
(void)dead_connection;
if(r) {
conn->proto.rtmp = NULL;
@@ -284,9 +290,10 @@ static CURLcode rtmp_disconnect(struct connectdata *conn,
-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)
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;
@@ -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)
ssize_t num;
@@ -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]);
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,
bool force_ir, saslprogress *progress)
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,
int code, saslprogress *progress)
saslstate newstate = SASL_FINAL;
@@ -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);
if(sasl->state != SASL_CANCEL && sasl->state != SASL_OAUTH2_RESP &&
code != sasl->params->contcode) {
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 */
else if(code == sasl->params->contcode) {
@@ -600,7 +600,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
@@ -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() */
@@ -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;
case CURLE_OK:
if(resp)
- result = sasl->params->sendcont(conn, resp);
+ result = sasl->params->sendcont(data, conn, resp);
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);
@@ -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,
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 */
bool force_ir, saslprogress *progress);
/* Continue an SASL authentication */
int code, saslprogress *progress);
#endif /* HEADER_CURL_SASL_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
@@ -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, ...)
ssize_t bytes_written;
size_t write_len;
@@ -151,7 +150,7 @@ static CURLcode sendf(curl_socket_t sockfd, struct connectdata *conn,
/* 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);
@@ -173,7 +172,7 @@ static CURLcode sendf(curl_socket_t sockfd, struct connectdata *conn,
-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 */
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)
- 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)
"DEFINE "
@@ -306,7 +305,7 @@ static CURLcode dict_do(struct connectdata *conn, bool *done)
if(ppath[i] == ':')
ppath[i] = ' ';
"%s\r\n"
"QUIT\r\n", ppath);
- * Copyright (C) 2018 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2018 - 2021, Daniel Stenberg, <[email protected]>, et al.
@@ -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);
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);
@@ -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);
@@ -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,
int slot;
+ struct dohdata *dohp;
*waitp = TRUE; /* this never returns synchronously */
(void)hostname;
(void)port;
+ DEBUGASSERT(!data->req.doh);
/* 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);
- 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],
error:
+ 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);
@@ -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)
*dnsp = NULL; /* defaults to no response */
- 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:
- 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,
/* remove DOH handles from multi handle and close them */
- curl_multi_remove_handle(data->multi, data->req.doh.probe[slot].easy);
+ curl_multi_remove_handle(data->multi, dohp->probe[slot].easy);
/* parse the responses, create the struct and return it! */
de_init(&de);
- struct dnsprobe *p = &data->req.doh.probe[slot];
+ struct dnsprobe *p = &dohp->probe[slot];
if(!p->dnstype)
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);
de_cleanup(&de);
@@ -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);
- 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 */
- } /* !data->req.doh.pending */
+ } /* !dohp->pending */
/* else wait for pending DOH transactions to complete */
@@ -32,12 +32,12 @@
* and returns a 'Curl_addrinfo *' with the address information.
int Curl_doh_getsock(struct connectdata *conn, curl_socket_t *socks);
@@ -124,6 +124,10 @@ curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
# pragma warning(default:4232) /* MSVC extension, dllimport identity */
+#ifdef DEBUGBUILD
+static char *leakpointer;
/**
* 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;
+ if(getenv("CURL_GLOBAL_INIT"))
+ /* alloc data that will leak if *cleanup() is not called! */
+ leakpointer = malloc(1);
fail:
@@ -265,6 +275,9 @@ void curl_global_cleanup(void)
#ifdef USE_WOLFSSH
(void)wolfSSH_Cleanup();
+ free(leakpointer);
init_flags = 0;
@@ -895,8 +908,8 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
/* 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 */
- 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(!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);
@@ -1170,8 +1191,13 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
- 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,
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 */
* ___|___/|_| ______|
- * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel.se>, et al.
+ * Copyright (C) 1998 - 2021, Daniel Stenberg, <daniel.se>, et al.
@@ -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));
@@ -81,13 +81,15 @@
-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,
bool dead_connection);
-static CURLcode file_setup_connection(struct connectdata *conn);
+static CURLcode file_setup_connection(struct Curl_easy *data,
* FILE scheme handler.
@@ -116,11 +118,13 @@ const struct Curl_handler Curl_handler_file = {
-static CURLcode file_setup_connection(struct connectdata *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)
@@ -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)
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)
- CURLcode status, bool premature)
+ 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,
(void)dead_connection; /* not used */
- return file_done(conn, 0, 0);
+ return file_done(data, 0, 0);
#ifdef DOS_FILESYSTEM
@@ -237,14 +242,13 @@ static CURLcode file_disconnect(struct connectdata *conn,
#define DIRSEP '/'
-static CURLcode file_upload(struct connectdata *conn)
+static CURLcode file_upload(struct Curl_easy *data)
const char *dir = strchr(file->path, DIRSEP);
int mode;
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)
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);
@@ -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);
@@ -333,12 +337,12 @@ static CURLcode file_upload(struct connectdata *conn)
Curl_pgrsSetUploadCounter(data, bytecount);
result = Curl_speedcheck(data, Curl_now());
- if(!result && Curl_pgrsUpdate(conn))
+ if(!result && Curl_pgrsUpdate(data))
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;
@@ -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);
- result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+ result = Curl_client_write(data, CLIENTWRITE_HEADER,
(char *)"Accept-ranges: bytes\r\n", 0);
@@ -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");
/* 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);
@@ -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);
Curl_pgrsSetDownloadCounter(data, bytecount);
@@ -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,
@@ -31,7 +31,7 @@ extern const struct Curl_handler Curl_handler_ftp;
extern const struct Curl_handler Curl_handler_ftps;
-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 */
@@ -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 */
- if(compare(conn->data->set.fnmatch_data, wc->pattern,
+ 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,
add = 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 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);
parser->error = result;
@@ -740,7 +740,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
@@ -835,7 +835,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
else if(c == '\n') {
parser->offsets.symlink_target = parser->item_offset;
@@ -847,7 +847,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
if(c == '\n') {
@@ -967,7 +967,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
finfo->b_data[finfo->b_used - 1] = 0;
@@ -979,7 +979,7 @@ size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
case PL_WINNT_FILENAME_WINEOL:
@@ -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
switch(data->state.httpreq) {
case HTTPREQ_POST:
@@ -120,6 +121,7 @@ static CURLcode getinfo_char(struct Curl_easy *data, CURLINFO info,
*param_charp = m;
@@ -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 @@
-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);
* 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)
+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)done;
+static CURLcode gopher_connecting(struct Curl_easy *data, bool *done)
+ CURLcode result = Curl_ssl_connect(data, conn, FIRSTSOCKET);
+ connclose(conn, "Failed TLS connection");
+static CURLcode gopher_do(struct Curl_easy *data, bool *done)
char *gopherpath;
@@ -127,9 +173,14 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
k = curlx_uztosz(len);
- 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)
+ 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);
@@ -141,7 +192,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
- timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
+ timeout_ms = Curl_timeleft(data, NULL, FALSE);
if(timeout_ms < 0) {
result = CURLE_OPERATION_TIMEDOUT;
@@ -169,12 +220,12 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
free(sel_org);
- result = Curl_write(conn, sockfd, "\r\n", 2, &amount);
+ result = Curl_write(data, sockfd, "\r\n", 2, &amount);
failf(data, "Failed sending Gopher request");
- result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
+ result = Curl_client_write(data, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
#ifndef CURL_DISABLE_GOPHER
extern const struct Curl_handler Curl_handler_gopher;
+extern const struct Curl_handler Curl_handler_gophers;
#endif /* HEADER_CURL_GOPHER_H */
@@ -175,7 +175,7 @@ Curl_hash_pick(struct Curl_hash *h, void *key, size_t key_len)
-#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))
@@ -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;
- conn->async.status = status;
+ data->state.async.status = status;
dns = Curl_cache_addr(data, ai,
- conn->async.hostname,
- conn->async.port);
+ data->state.async.port);
@@ -99,12 +97,12 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
/* 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 */
/* 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,
- return Curl_resolver_getaddrinfo(conn, hostname, port, waitp);
+ return Curl_resolver_getaddrinfo(data, hostname, port, waitp);
#endif /* CURLRES_ASYNCH */
@@ -253,14 +253,12 @@ sigjmp_buf curl_jmpenv;
/* 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)
size_t entry_len;
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,
int port)
- 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,
bool allowDOH,
enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
*entry = NULL;
conn->bits.doh = FALSE; /* default is not */
@@ -497,7 +494,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
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);
/* 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 */
@@ -658,7 +655,7 @@ RETSIGTYPE alarmfunc(int sig)
-enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
+enum resolve_t Curl_resolv_timeout(struct Curl_easy *data,
@@ -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;
#endif /* USE_ALARM_TIMEOUT */
enum resolve_t rc;
@@ -695,7 +691,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
/* 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;
/* now set the new struct */
@@ -748,7 +744,7 @@ enum resolve_t Curl_resolv_timeout(struct connectdata *conn,
#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");
(void)timeoutms; /* timeoutms not used with an async resolver */
@@ -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)
- /* 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);
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);
- 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--;
@@ -1040,8 +1048,8 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
Curl_freeaddrinfo(head);
- 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)
-CURLcode Curl_resolv_check(struct connectdata *conn,
+CURLcode Curl_resolv_check(struct Curl_easy *data,
#if defined(CURL_DISABLE_DOH) && !defined(CURLRES_ASYNCH)
(void)dns;
- 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,
#ifdef CURLRES_ASYNCH
/* 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);
@@ -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)
- if(conn->async.dns) {
- conn->dns_entry = conn->async.dns;
+ 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);
- DEBUGASSERT(data);
Curl_detach_connnection(data);
Curl_conncache_remove_conn(data, conn, TRUE);
Curl_disconnect(data, conn, TRUE);
@@ -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
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);
#define Curl_ipv6works(x) FALSE
@@ -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);
@@ -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.
struct Curl_addrinfo *ai);
@@ -177,7 +177,7 @@ void Curl_printable_address(const struct Curl_addrinfo *ip,
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);
curl_socket_t *socks);
#endif /* HEADER_CURL_HOSTIP_H */
@@ -61,8 +61,9 @@
-bool Curl_ipvalid(struct connectdata *conn)
+bool Curl_ipvalid(struct Curl_easy *data, struct connectdata *conn)
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.
@@ -96,14 +97,14 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
struct Curl_addrinfo *ai = NULL;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
*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;
@@ -62,16 +62,15 @@
-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->multi);
- return conn->data->multi->ipv6_works;
+ DEBUGASSERT(data->multi);
+ return data->multi->ipv6_works;
int ipv6_works = -1;
@@ -82,7 +81,7 @@ bool Curl_ipv6works(struct connectdata *conn)
ipv6_works = 0;
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)
- return Curl_ipv6works(conn);
+ return Curl_ipv6works(data);
@@ -128,7 +127,7 @@ static void dump_addrinfo(struct connectdata *conn,
@@ -142,14 +141,11 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
char addrbuf[128];
int pf;
-#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
-#endif
/* Check if a limited name resolve has been requested */
@@ -161,13 +157,13 @@ struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- hints.ai_socktype = (conn->transport == TRNSPRT_TCP) ?
+ hints.ai_socktype = (data->conn->transport == TRNSPRT_TCP) ?
#ifndef USE_RESOLVE_ON_IPS
- * Copyright (C) 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2020 - 2021, Daniel Stenberg, <[email protected]>, et al.
@@ -325,7 +325,7 @@ CURLcode Curl_hsts_save(struct Curl_easy *data, struct hsts *h,
/* no cache activated */
- /* 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.
@@ -23,6 +23,15 @@
+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);
+#define Curl_buffer_send(a,b,c,d,e) CURLE_OK
-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,
+ struct dynbuf *req
+ void *headers
+ );
+CURLcode Curl_add_custom_headers(struct Curl_easy *data,
bool is_connect,
- struct dynbuf *req_buffer);
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,
+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 dynbuf *r);
+#define Curl_http_cookies(a,b,c) CURLE_OK
+CURLcode Curl_http_resume(struct Curl_easy *data,
+ Curl_HttpReq httpreq);
+CURLcode Curl_http_range(struct Curl_easy *data,
+CURLcode Curl_http_firstwrite(struct Curl_easy *data,
+ 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,
const char *request,
const char *path,
bool proxytunnel); /* TRUE if this is the request setting
up the proxy tunnel */
@@ -65,12 +65,13 @@
-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,
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,
+ curl_socket_t *sock)
const struct http_conn *c = &conn->proto.httpc;
- struct SingleRequest *k = &conn->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,
-{
- 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 http_conn *c = &conn->proto.httpc;
+#ifndef DEBUG_HTTP2
- 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"));
@@ -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);
/* 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,
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;
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) {
- 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;
- 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)",
@@ -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 = {
@@ -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;
@@ -956,7 +958,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
stream = data_s->req.p.http;
- failf(data_s, "Internal NULL stream! 5\n");
+ failf(data_s, "Internal NULL stream!");
@@ -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) {
@@ -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);
- failf(conn->data, "Couldn't initialize nghttp2!");
+ failf(data, "Couldn't initialize nghttp2!");
@@ -1273,7 +1275,8 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
ssize_t binlen;
char *base64;
size_t blen;
+ struct Curl_easy *data = conn->data;
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);
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);
@@ -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.
CURLcode *err)
char *inbuf;
ssize_t rv;
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;
/* not an error per se, but should still close the connection */
- connclose(conn, "GOAWAY received");
+ connclose(data->conn, "GOAWAY received");
*err = CURLE_OK;
@@ -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,
@@ -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;
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);
/* If nghttp2 still has pending frames unsent */
if(nghttp2_session_want_write(h2)) {
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) {
@@ -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);
*err = result;
@@ -1562,12 +1563,12 @@ static int h2_session_send(struct Curl_easy *data,
return nghttp2_session_send(h2);
char *mem, size_t len, CURLcode *err)
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;
@@ -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. */
@@ -1693,7 +1694,7 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
if(httpc->inbuflen == 0) {
- 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)
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.
nghttp2_nv *nva = NULL;
size_t nheader;
size_t i;
@@ -1854,16 +1856,16 @@ static ssize_t http2_send(struct connectdata *conn, int 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;
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;
- rv = h2_session_send(conn->data, h2);
+ rv = h2_session_send(data, h2);
if(nghttp2_is_fatal(rv)) {
@@ -1887,7 +1889,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
stream->upload_len = 0;
- 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"));
@@ -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");
@@ -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])) {
@@ -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])) {
@@ -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])) {
++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_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;
/* 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);
- 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));
- 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) {
"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,
@@ -2150,13 +2152,14 @@ fail:
-CURLcode Curl_http2_setup(struct connectdata *conn)
+CURLcode Curl_http2_setup(struct Curl_easy *data,
- DEBUGASSERT(conn->data->state.buffer);
+ DEBUGASSERT(data->state.buffer);
stream->stream_id = -1;
@@ -2172,18 +2175,18 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
conn->handler = &Curl_handler_http2;
- result = http2_init(conn);
+ result = http2_init(data, conn);
Curl_dyn_free(&stream->header_recvbuf);
- 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->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;
@@ -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);
-CURLcode Curl_http2_switched(struct connectdata *conn,
+CURLcode Curl_http2_switched(struct Curl_easy *data,
const char *mem, size_t nread)
- result = Curl_http2_setup(conn);
+ result = Curl_http2_setup(data, conn);
@@ -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))
@@ -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,
-CURLcode Curl_http2_setup(struct connectdata *conn);
- const char *data, size_t nread);
+CURLcode Curl_http2_setup(struct Curl_easy *data, struct connectdata *conn);
+ 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_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)
@@ -0,0 +1,394 @@
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+#include "strcase.h"
+#include "strdup.h"
+#include "vauth/vauth.h"
+#include "vauth/digest.h"
+#include "http_aws_sigv4.h"
+#include "curl_sha256.h"
+#include "parsedate.h"
+#include <time.h>
+#define HMAC_SHA256(k, kl, d, dl, o) \
+ 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; \
+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;
+ 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;
+ char *force_timestamp;
+ 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;
+ 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 */
+ /*
+ * 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) {
+ 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;
+ infof(data, "second provider can't be empty\n");
+ provider1_low = malloc(len + 1);
+ provider1_mid = malloc(len + 1);
+ if(!provider1_low || !provider1_mid) {
+ 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';
+ infof(data, "region can't be empty\n");
+ region = Curl_memdup(tmp0, len + 1);
+ if(!region) {
+ region[len] = '\0';
+ service = strdup(tmp0);
+ if(!service) {
+ if(strlen(service) < 1) {
+ infof(data, "service can't be empty\n");
+ provider1_low = Curl_memdup(provider0_low, len + 1);
+ provider1_mid = Curl_memdup(provider0_low, len + 1);
+ 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;
+ service = Curl_memdup(tmp0, len + 1);
+ service[len] = '\0';
+ infof(data, "region missing in parameters or hostname\n");
+ force_timestamp = getenv("CURL_FORCETIME");
+ if(force_timestamp)
+ clock = 0;
+ time(&clock);
+ ret = Curl_gmtime(clock, &tm);
+ if(ret != CURLE_OK) {
+ if(!strftime(timestamp, sizeof(timestamp), "%Y%m%dT%H%M%SZ", &tm)) {
+ 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;
+ 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);
+ canonical_headers = curl_maprintf("host:%s\n"
+ signed_headers = curl_maprintf("host;x-%s-date", provider1_low);
+ if(!canonical_headers || !signed_headers) {
+ Curl_sha256it(sha_hash,
+ (const unsigned char *) post_data, strlen(post_data));
+ sha256_to_hex(sha_hex, sha_hash, sizeof(sha_hex));
+ 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) {
+ request_type = curl_maprintf("%s4_request", provider0_low);
+ if(!request_type) {
+ credential_scope = curl_maprintf("%s/%s/%s/%s",
+ date, region, service, request_type);
+ if(!credential_scope) {
+ Curl_sha256it(sha_hash, (unsigned char *) canonical_request,
+ strlen(canonical_request));
+ * 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,
+ if(!str_to_sign) {
+ secret = curl_maprintf("%s4%s", provider0_up, passwd);
+ if(!secret) {
+ 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);
+ request_type, strlen(request_type), 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",
+ user,
+ sha_hex,
+ provider1_mid,
+ timestamp);
+ if(!auth_headers) {
+ 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) */
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_HTTP_AWS_SIGV4_H
+#define HEADER_CURL_HTTP_AWS_SIGV4_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 */
@@ -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 */
-#define Curl_isxdigit_ascii(x) Curl_isxdigit(x)
+#define isxdigit_ascii(x) Curl_isxdigit(x)
-void Curl_httpchunk_init(struct connectdata *conn)
+void Curl_httpchunk_init(struct Curl_easy *data)
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)
struct Curl_chunker *ch = &conn->chunk;
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);
*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);
/* 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);
- result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, piece);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, datap, piece);
@@ -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);
/* Treat it as a 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);
@@ -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 */
@@ -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);
@@ -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,
const char *header) /* rest of the *-authenticate:
header */
/* 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,
const unsigned char *request,
const unsigned char *uripath)
unsigned char *path = NULL;
char *tmp = NULL;
char *response;
@@ -26,11 +26,12 @@
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
/* this is for digest header input */
bool proxy, const char *header);
/* this is for creating digest header output */
const unsigned char *uripath);
@@ -34,11 +34,10 @@
#include "curl_memory.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)
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,
-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;
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");
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)
- result = Curl_auth_create_spnego_message(conn->data,
- neg_ctx, &base64, &len);
+ result = Curl_auth_create_spnego_message(data, neg_ctx, &base64, &len);
@@ -25,11 +25,12 @@
#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
/* this is for Negotiate header input */
- const char *header);
+ bool proxy, const char *header);
/* this is for creating Negotiate header output */
-CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
+ struct connectdata *conn, bool proxy);
void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
@@ -59,7 +59,7 @@
# define DEBUG_OUT(x) Curl_nop_stmt
-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:
@@ -68,6 +68,7 @@ CURLcode Curl_input_ntlm(struct connectdata *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);
@@ -87,17 +88,17 @@ CURLcode Curl_input_ntlm(struct connectdata *conn,
Curl_http_auth_cleanup_ntlm(conn);
@@ -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)
@@ -131,8 +132,7 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
DEBUGASSERT(data);
@@ -142,12 +142,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
allocuserpwd = &data->state.aptr.proxyuserpwd;
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;
@@ -156,12 +156,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
allocuserpwd = &data->state.aptr.userpwd;
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;
@@ -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);
@@ -27,11 +27,11 @@
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
-CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy,
+CURLcode Curl_input_ntlm(struct Curl_easy *data, bool proxy,
-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);
@@ -27,6 +27,9 @@
#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
#include <curl/curl.h>
+#ifdef USE_HYPER
#include "sendf.h"
#include "http.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
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]);
/* 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)
(void) sockindex;
-CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
+CURLcode Curl_proxy_connect(struct Curl_easy *data, int sockindex)
if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
- const CURLcode result = https_proxy_connect(conn, sockindex);
+ const CURLcode result = https_proxy_connect(data, sockindex);
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");
@@ -124,8 +128,8 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
remote_port = conn->conn_to_port;
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)
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;
if(!reinit) {
DEBUGASSERT(!conn->connect_state);
s = calloc(1, sizeof(struct http_connect_state));
if(!s)
- 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)
-static void connect_done(struct connectdata *conn)
+static void connect_done(struct Curl_easy *data)
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,
+ 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)
+ if(!Curl_checkProxyheaders(data, conn, "Host")) {
+ host = aprintf("Host: %s\r\n", hostheader);
+ if(!host) {
+ free(hostheader);
+ *connecthostp = hostheader;
+ *hostp = host;
-static CURLcode CONNECT(struct connectdata *conn,
+static CURLcode CONNECT(struct Curl_easy *data,
int remote_port)
int subversion = 0;
curl_socket_t tunnelsocket = conn->sock[sockindex];
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);
- free(host_port);
+ /* Setup the proxy-authorization header, if any */
+ result = Curl_http_output_auth(data, conn, "CONNECT", HTTPREQ_GET,
+ hostheader, TRUE);
- 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);
- if(!Curl_checkProxyheaders(conn, "Host")) {
- host = aprintf("Host: %s\r\n", hostheader);
- if(!host) {
- free(hostheader);
- 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);
- result = Curl_add_custom_headers(conn, TRUE, &req);
+ result = Curl_add_custom_headers(data, TRUE, &req);
/* CRLF terminate the request */
@@ -295,13 +309,14 @@ static CURLcode CONNECT(struct connectdata *conn,
/* 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);
failf(data, "Failed sending CONNECT to proxy");
+ free(host);
Curl_dyn_free(&req);
@@ -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 */
@@ -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);
@@ -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);
@@ -479,9 +494,12 @@ static CURLcode CONNECT(struct connectdata *conn,
s->keepon = KEEPON_DONE;
- if(!s->cl)
+ if(s->keepon == KEEPON_DONE && !s->cl)
/* we did the full CONNECT treatment, go to COMPLETE */
+ DEBUGASSERT(s->keepon == KEEPON_IGNORE || s->keepon == KEEPON_DONE);
@@ -495,7 +513,7 @@ static CURLcode CONNECT(struct connectdata *conn,
if(!auth)
- 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(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);
@@ -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;
@@ -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,
conn->bits.proxy_connect_closed = TRUE;
infof(data, "Connect me again please\n");
- connect_done(conn);
+ connect_done(data);
/* failure, close this connection to avoid re-use */
streamclose(conn, "proxy CONNECT failure");
@@ -628,6 +646,225 @@ static CURLcode CONNECT(struct connectdata *conn,
+/* The Hyper version of CONNECT */
+ curl_socket_t tunnelsocket = conn->sock[sockindex];
+ struct http_connect_state *s = conn->connect_state;
+ CURLcode result = CURLE_OUT_OF_MEMORY;
+ char *hostheader = NULL; /* for CONNECT */
+ if(Curl_connect_complete(conn))
+ return CURLE_OK; /* CONNECT is already completed */
+ conn->bits.proxy_connect_closed = FALSE;
+ switch(s->tunnel_state) {
+ case TUNNEL_INIT:
+ /* BEGIN CONNECT PHASE */
+ conn->sockfd = tunnelsocket;
+ /* "Both the `io` and the `options` are consumed in this function
+ call" */
+ if(hyper_request_set_method(req, (uint8_t *)"CONNECT",
+ strlen("CONNECT"))) {
+ result = CONNECT_host(data, conn, hostname, remote_port,
+ &hostheader, &host);
+ if(hyper_request_set_uri(req, (uint8_t *)hostheader,
+ strlen(hostheader))) {
+ 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");
+ if(host && Curl_hyper_header(data, headers, host))
+ Curl_safefree(host);
+ if(!Curl_checkProxyheaders(data, conn, "Proxy-Connection") &&
+ Curl_hyper_header(data, headers, "Proxy-Connection: Keep-Alive"))
+ s->tunnel_state = TUNNEL_CONNECT;
+ /* FALLTHROUGH */
+ case TUNNEL_CONNECT: {
+ int didwhat;
+ result = Curl_hyper_stream(data, conn, &didwhat, &done,
+ CURL_CSELECT_IN | CURL_CSELECT_OUT);
+ if(!done)
+ fprintf(stderr, "done\n");
+ s->tunnel_state = TUNNEL_COMPLETE;
+ } while(data->req.newurl);
+ result = CURLE_OK;
+ failf(data, "Hyper: %.*s", (int)errlen, errbuf);
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,
if(!conn->connect_state) {
- result = connect_init(conn, FALSE);
+ result = connect_init(data, FALSE);
- result = CONNECT(conn, sockindex, hostname, remote_port);
+ result = CONNECT(data, sockindex, hostname, remote_port);
if(result || Curl_connect_complete(conn))
@@ -27,14 +27,14 @@
/* ftp can use this as well */
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);
@@ -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 @@
-static CURLcode ftpsend(struct connectdata *conn, const char *cmd)
+static CURLcode ftpsend(struct Curl_easy *data, struct connectdata *conn,
+ const char *cmd)
#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 */
@@ -89,7 +90,7 @@ static CURLcode ftpsend(struct connectdata *conn, const char *cmd)
conn->data_prot = PROT_CMD;
- result = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
+ result = Curl_write(data, conn->sock[FIRSTSOCKET], sptr, write_len,
&bytes_written);
DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
@@ -99,7 +100,7 @@ static CURLcode ftpsend(struct connectdata *conn, const char *cmd)
- 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;
curl_socklen_t l = sizeof(conn->local_addr);
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)
/* 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");
return -2;
- if(Curl_GetFTPResponse(&nread, conn, NULL))
+ if(Curl_GetFTPResponse(data, &nread, NULL))
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);
@@ -331,7 +331,7 @@ krb5_auth(void *app_data, struct connectdata *conn)
- if(Curl_GetFTPResponse(&nread, conn, NULL)) {
+ if(Curl_GetFTPResponse(data, &nread, NULL)) {
ret = -1;
@@ -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;
- if(Curl_GetFTPResponse(&nread, conn, &ftp_code))
+ if(Curl_GetFTPResponse(data, &nread, &ftp_code))
@@ -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. */
-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);
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;
curl_socket_t fd = conn->sock[sockindex];
/* 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);
- 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);
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));
-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)
- 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;
if(!conn->mech)
/* not inititalized, return error */
@@ -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;
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");
@@ -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)
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.");
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));
- failf(conn->data, "Failed to set the protection level.");
+ failf(data, "Failed to set the protection level.");
@@ -805,10 +810,9 @@ Curl_sec_request_prot(struct connectdata *conn, const char *level)
-static CURLcode choose_mech(struct connectdata *conn)
+static CURLcode choose_mech(struct Curl_easy *data, struct connectdata *conn)
int ret;
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 */
- (void)sec_set_protection_level(conn);
+ (void)sec_set_protection_level(data);
-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);
@@ -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,
LDAPURLDesc **ludp);
static void _ldap_free_urldesc(LDAPURLDesc *ludp);
@@ -126,7 +127,7 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp);
-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 */
@@ -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)
- rc = ldap_win_bind_auth(server, user, passwd, conn->data->set.httpauth);
+ rc = ldap_win_bind_auth(server, user, passwd, data->set.httpauth);
@@ -266,7 +267,7 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
-static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
+static CURLcode ldap_do(struct Curl_easy *data, bool *done)
int rc = 0;
@@ -275,7 +276,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
LDAPMessage *ldapmsg = NULL;
LDAPMessage *entryIterator;
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);
- rc = _ldap_url_parse(conn, &ludp);
+ rc = _ldap_url_parse(data, conn, &ludp);
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);
rc = ldap_simple_bind_s(server, user, passwd);
@@ -480,7 +481,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
ldap_proto = LDAP_VERSION2;
@@ -536,14 +537,14 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
name_len = strlen(name);
- result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
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);
@@ -551,7 +552,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
- result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
@@ -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);
ldap_value_free_len(vals);
FREE_ON_WINLDAP(attr);
@@ -600,7 +601,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
- result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ result = Curl_client_write(data, CLIENTWRITE_BODY,
(char *) attr, attr_len);
@@ -612,7 +613,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
- result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
+ result = Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2);
@@ -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);
@@ -661,7 +662,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
- 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);
@@ -676,7 +677,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
dlsize += vals[i]->bv_len;
@@ -698,7 +699,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
ldap_memfree(attribute);
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;
@@ -828,10 +830,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
char *query = NULL;
- 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);
+ q = query = strdup(data->state.up.query);
if(!query) {
free(path);
@@ -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);
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);
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);
@@ -1035,7 +1036,8 @@ quit:
LDAPURLDesc **ludpp)
LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
@@ -1045,7 +1047,7 @@ static int _ldap_url_parse(const struct connectdata *conn,
if(!ludp)
- rc = _ldap_url_parse2(conn, ludp);
+ rc = _ldap_url_parse2(data, conn, ludp);
if(rc != LDAP_SUCCESS) {
_ldap_free_urldesc(ludp);
ludp = NULL;
@@ -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)
@@ -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. */
* Copyright (C) 2019, Björn Stenberg, <[email protected]>
@@ -59,10 +59,12 @@
-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,
* MQTT protocol handler.
@@ -90,12 +92,13 @@ const struct Curl_handler Curl_handler_mqtt = {
-static CURLcode mqtt_setup_conn(struct connectdata *conn)
/* allocate the HTTP-specific struct for the Curl_easy, only to survive
during this request */
struct MQTT *mq;
DEBUGASSERT(data->req.p.mqtt == NULL);
mq = calloc(1, sizeof(struct MQTT));
@@ -105,15 +108,15 @@ static CURLcode mqtt_setup_conn(struct connectdata *conn)
-static CURLcode mqtt_send(struct connectdata *conn,
+static CURLcode mqtt_send(struct Curl_easy *data,
char *buf, size_t len)
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);
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,
curl_socket_t *sock)
return GETSOCK_READSOCK(FIRSTSOCKET);
-static CURLcode mqtt_connect(struct connectdata *conn)
+static CURLcode mqtt_connect(struct Curl_easy *data)
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);
- result = mqtt_send(conn, packet, packetlen);
+ result = mqtt_send(data, packet, packetlen);
-static CURLcode mqtt_disconnect(struct connectdata *conn)
+static CURLcode mqtt_disconnect(struct Curl_easy *data)
- result = mqtt_send(conn, (char *)"\xe0\x00", 2);
+ result = mqtt_send(data, (char *)"\xe0\x00", 2);
-static CURLcode mqtt_verify_connack(struct connectdata *conn)
+static CURLcode mqtt_verify_connack(struct Curl_easy *data)
unsigned char readbuf[MQTT_CONNACK_LEN];
- result = Curl_read(conn, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread);
+ result = Curl_read(data, sockfd, (char *)readbuf, MQTT_CONNACK_LEN, &nread);
@@ -204,18 +209,18 @@ fail:
-static CURLcode mqtt_get_topic(struct connectdata *conn,
+static CURLcode mqtt_get_topic(struct Curl_easy *data,
char **topic, size_t *topiclen)
- 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);
- failf(conn->data, "Error: No topic specified.");
+ failf(data, "Error: No topic specified.");
result = CURLE_URL_MALFORMAT;
@@ -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)
char *topic = NULL;
@@ -247,8 +252,9 @@ static CURLcode mqtt_subscribe(struct connectdata *conn)
size_t packetlen;
char encodedsize[4];
size_t n;
- result = mqtt_get_topic(conn, &topic, &topiclen);
+ result = mqtt_get_topic(data, &topic, &topiclen);
@@ -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);
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)
unsigned char readbuf[MQTT_SUBACK_LEN];
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);
- 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:
-static CURLcode mqtt_publish(struct connectdata *conn)
+static CURLcode mqtt_publish(struct Curl_easy *data)
- char *payload = conn->data->set.postfields;
- size_t payloadlen = (size_t)conn->data->set.postfieldsize;
+ char *payload = data->set.postfields;
+ size_t payloadlen;
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)
+ if(postfieldsize < 0)
+ payloadlen = strlen(payload);
+ payloadlen = (size_t)postfieldsize;
@@ -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);
free(pkt);
@@ -395,13 +410,14 @@ static const char *statenames[]={
/* 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 */
- 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)
unsigned char *pkt = (unsigned char *)data->state.buffer;
size_t remlen;
@@ -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);
- mqstate(conn, MQTT_FIRST, MQTT_PUBWAIT);
+ mqstate(data, MQTT_FIRST, MQTT_PUBWAIT);
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(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);
goto end;
if(!mq->npacket)
/* no more PUBLISH payload, back to subscribe wait state */
@@ -510,27 +525,25 @@ static CURLcode mqtt_read_publish(struct connectdata *conn,
-static CURLcode mqtt_do(struct connectdata *conn, bool *done)
+static CURLcode mqtt_do(struct Curl_easy *data, bool *done)
*done = FALSE; /* unconditionally */
- result = mqtt_connect(conn);
+ result = mqtt_connect(data);
failf(data, "Error %d sending MQTT CONN request", result);
- mqstate(conn, MQTT_FIRST, MQTT_CONNACK);
+ mqstate(data, MQTT_FIRST, MQTT_CONNACK);
-static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
+static CURLcode mqtt_doing(struct Curl_easy *data, bool *done)
@@ -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);
@@ -552,18 +565,18 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
case MQTT_FIRST:
/* Read the initial byte only */
- result = Curl_read(conn, sockfd, (char *)&mq->firstbyte, 1, &nread);
+ result = Curl_read(data, sockfd, (char *)&mq->firstbyte, 1, &nread);
+ if(!nread)
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);
case MQTT_REMAINING_LENGTH:
- result = Curl_read(conn, sockfd, (char *)&byte, 1, &nread);
+ result = Curl_read(data, sockfd, (char *)&byte, 1, &nread);
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);
if(mq->remaining_length) {
- mqstate(conn, mqtt->nextstate, MQTT_NOSTATE);
+ mqstate(data, mqtt->nextstate, MQTT_NOSTATE);
- 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)
case MQTT_CONNACK:
- result = mqtt_verify_connack(conn);
+ result = mqtt_verify_connack(data);
- if(conn->data->state.httpreq == HTTPREQ_POST) {
- result = mqtt_publish(conn);
+ if(data->state.httpreq == HTTPREQ_POST) {
+ result = mqtt_publish(data);
- result = mqtt_disconnect(conn);
+ result = mqtt_disconnect(data);
mqtt->nextstate = MQTT_FIRST;
- result = mqtt_subscribe(conn);
+ result = mqtt_subscribe(data);
- mqstate(conn, MQTT_FIRST, MQTT_SUBACK);
+ mqstate(data, MQTT_FIRST, MQTT_SUBACK);
@@ -607,11 +620,11 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
case MQTT_PUBWAIT:
case MQTT_PUB_REMAIN:
- result = mqtt_read_publish(conn, done);
+ result = mqtt_read_publish(data, done);
- failf(conn->data, "State not handled yet");
+ failf(data, "State not handled yet");
@@ -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)
- multi->type = CURL_MULTI_HANDLE;
+ multi->magic = CURL_MULTI_HANDLE;
if(Curl_mk_dnscache(&multi->hostcache))
@@ -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);
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)
@@ -690,17 +697,13 @@ static CURLcode multi_done(struct Curl_easy *data,
-static int close_connect_only(struct connectdata *conn, void *param)
+static int close_connect_only(struct Curl_easy *data,
- struct Curl_easy *data = param;
+ (void)param;
if(data->state.lastconnect_id != conn->connection_id)
- if(conn->data != data)
- return 1;
- conn->data = NULL;
if(!conn->bits.connect_only)
@@ -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,
if(conn && conn->handler->domore_getsock)
- return conn->handler->domore_getsock(conn, socks);
+ return conn->handler->domore_getsock(data, conn, socks);
-static int doing_getsock(struct connectdata *conn,
+static int doing_getsock(struct Curl_easy *data,
if(conn && conn->handler->doing_getsock)
- return conn->handler->doing_getsock(conn, socks);
+ return conn->handler->doing_getsock(data, conn, socks);
-static int protocol_getsock(struct connectdata *conn,
+static int protocol_getsock(struct Curl_easy *data,
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,
/* The no connection case can happen when this is called from
curl_multi_remove_handle() => singlesocket() => multi_getsock().
- if(!data->conn)
+ if(!conn)
if(data->mstate > CURLM_STATE_CONNECT &&
@@ -988,30 +995,30 @@ static int multi_getsock(struct Curl_easy *data,
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
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,
- 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,
-/*
- * 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)
@@ -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);
@@ -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)
*complete = 0;
if(conn->handler->do_more)
- result = conn->handler->do_more(conn, complete);
- if(!result && (*complete == 1))
+ result = conn->handler->do_more(data, complete);
@@ -1446,14 +1434,14 @@ static CURLcode multi_do_more(struct connectdata *conn, int *complete)
* protocol layer.
-static CURLcode protocol_connecting(struct connectdata *conn,
+static CURLcode protocol_connecting(struct Curl_easy *data, bool *done)
if(conn && conn->handler->connecting) {
*done = FALSE;
- result = conn->handler->connecting(conn, done);
+ result = conn->handler->connecting(data, done);
@@ -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)
if(conn && conn->handler->doing) {
- result = conn->handler->doing(conn, done);
+ result = conn->handler->doing(data, done);
@@ -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)
DEBUGASSERT(protocol_done);
@@ -1510,7 +1499,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
if(!conn->bits.protoconnstart) {
- result = Curl_proxy_connect(conn, FIRSTSOCKET);
+ result = Curl_proxy_connect(data, FIRSTSOCKET);
@@ -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);
*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);
+ return CURLM_INTERNAL_ERROR;
data->conn->data = data;
@@ -1737,19 +1729,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* 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);
result = CURLE_OK;
infof(data, "Hostname '%s' was found in DNS cache\n", hostname);
if(!dns)
- result = Curl_resolv_check(data->conn, &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,
/* 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 Curl_once_resolved() returns failure, the connection struct
@@ -1796,7 +1788,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* 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);
if(data->conn->bits.proxy_connect_closed) {
rc = CURLM_CALL_MULTI_PERFORM;
@@ -1827,7 +1819,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* awaiting a completion of an asynch TCP connect */
- result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
+ result = Curl_is_connected(data, data->conn, FIRSTSOCKET, &connected);
if(connected && !result) {
if(
@@ -1860,7 +1852,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
- 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,
/* 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);
@@ -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,
/* we continue DOING until the DO phase is complete */
- result = protocol_doing(data->conn, &dophase_done);
+ result = protocol_doing(data, &dophase_done);
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
- result = multi_do_more(data->conn, &control);
+ result = multi_do_more(data, &control);
if(control) {
@@ -2074,12 +2069,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
/* if both rates are within spec, resume transfer */
- if(Curl_pgrsUpdate(data->conn))
result = Curl_speedcheck(data, *nowp);
- 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);
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)) {
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 */
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,
/* 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
@@ -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;
+ conn = data->conn;
DEBUGASSERT(conn->bundle);
conn->bundle->multiuse = bundlestate;
- process_pending_handles(conn->data->multi);
+ process_pending_handles(data->multi);
static void process_pending_handles(struct Curl_multi *multi)
@@ -22,10 +22,14 @@
+#include "llist.h"
+#include "hash.h"
#include "conncache.h"
#include "psl.h"
#include "socketpair.h"
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;
@@ -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);
int bundlestate); /* use BUNDLE_* defines */
@@ -5,8 +5,8 @@
@@ -76,12 +76,14 @@ extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
LDAP **ld);
-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,
+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,
static Curl_recv ldap_recv;
@@ -169,11 +171,11 @@ struct ldapreqinfo {
int nument;
-static CURLcode ldap_setup_connection(struct connectdata *conn)
struct ldapconninfo *li;
LDAPURLDesc *lud;
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;
-static CURLcode ldap_connect(struct connectdata *conn, bool *done)
+static CURLcode ldap_connect(struct Curl_easy *data, bool *done)
struct ldapconninfo *li = conn->proto.ldapc;
int rc, proto = LDAP_VERSION3;
char hosturl[1024];
@@ -243,7 +245,8 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
if(conn->handler->flags & PROTOPT_SSL) {
- result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
+ result = Curl_ssl_connect_nonblocking(data, conn,
+ FIRSTSOCKET, &li->ssldone);
@@ -252,10 +255,10 @@ static CURLcode ldap_connect(struct connectdata *conn, bool *done)
-static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
+static CURLcode ldap_connecting(struct Curl_easy *data, bool *done)
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)
/* 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)
@@ -357,10 +360,12 @@ static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
-static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
+ struct connectdata *conn, bool dead_connection)
(void) dead_connection;
if(li) {
if(li->ld) {
@@ -373,15 +378,15 @@ static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
-static CURLcode ldap_do(struct connectdata *conn, bool *done)
struct ldapreqinfo *lr;
CURLcode status = CURLE_OK;
LDAPURLDesc *ludp = NULL;
int msgid;
connkeep(conn, "OpenLDAP do");
@@ -396,7 +401,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
@@ -418,10 +423,11 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
-static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
+static CURLcode ldap_done(struct Curl_easy *data, CURLcode res,
- struct ldapreqinfo *lr = conn->data->req.p.ldap;
+ 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);
-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,
struct ldapreqinfo *lr = data->req.p.ldap;
int rc, ret;
@@ -512,20 +518,20 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
- writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
if(writeerr) {
*err = writeerr;
- 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);
- writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 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);
- writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":\n", 2);
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":\n", 2);
@@ -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 *)":", 1);
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":", 1);
@@ -619,7 +625,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
*err = error;
- writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY,
(char *)": ", 2);
@@ -628,7 +634,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
data->req.bytecount += 2;
- writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, val_b64,
@@ -639,13 +645,13 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
- writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
+ writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)" ", 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);
@@ -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);
@@ -663,14 +669,14 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
data->req.bytecount++;
ber_memfree(bvals);
@@ -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)
CURLcode err = CURLE_SEND_ERROR;
- ret = (li->send)(conn, FIRSTSOCKET, buf, len, &err);
+ ret = (li->send)(conn->data, FIRSTSOCKET, buf, len, &err);
@@ -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;
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)
curl_socket_t sock = conn->sock[FIRSTSOCKET];
timediff_t interval_ms;
- timediff_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
+ timediff_t timeout_ms = Curl_pp_state_timeout(data, pp, disconnecting);
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 */
@@ -131,17 +131,17 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
else if(rc)
- result = pp->statemach_act(conn);
+ result = pp->statemachine(data, data->conn);
/* 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)
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,
char *s;
- struct Curl_easy *data;
enum protection_level data_sec;
@@ -184,7 +184,6 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
if(!conn)
/* can't send without a connection! */
- 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);
@@ -208,7 +207,7 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
- result = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len,
+ result = Curl_write(data, conn->sock[FIRSTSOCKET], s, write_len,
@@ -246,14 +245,14 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
-CURLcode Curl_pp_sendf(struct pingpong *pp,
+CURLcode Curl_pp_sendf(struct Curl_easy *data, struct pingpong *pp,
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 * const buf = data->state.buffer;
@@ -315,7 +314,7 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
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);
@@ -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.
pp->linestart_resp, perline);
- 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,
-int Curl_pp_getsock(struct pingpong *pp,
+int Curl_pp_getsock(struct Curl_easy *data,
+ struct pingpong *pp, curl_socket_t *socks)
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 */
- 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);
@@ -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) \
+ pp->response_time = RESP_TIMEOUT; \
+ pp->statemachine = s; \
+ pp->endofresp = e; \
* called repeatedly until done. Set 'wait' to make it wait a while on the
* socket if there's no traffic.
- bool disconnecting);
+CURLcode Curl_pp_statemach(struct Curl_easy *data, struct pingpong *pp,
+ bool block, bool disconnecting);
-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);
-timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
+ struct pingpong *pp, bool disconnecting);
/***********************************************************************
@@ -105,7 +110,8 @@ timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
+CURLcode Curl_pp_sendf(struct Curl_easy *data,
const char *fmt, ...);
@@ -118,7 +124,8 @@ CURLcode Curl_pp_sendf(struct pingpong *pp,
va_list args);
@@ -127,18 +134,21 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp,
size_t *size); /* size of the response */
-CURLcode Curl_pp_flushsend(struct pingpong *pp);
+ 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);
- * Copyright (C) 2009 - 2020, Daniel Stenberg, <[email protected]>, et al.
+ * Copyright (C) 2009 - 2021, Daniel Stenberg, <[email protected]>, et al.
@@ -61,6 +61,7 @@ struct pop3_conn {
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 */
@@ -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)
data->progress.lastshow = 0;
- rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
+ rc = Curl_pgrsUpdate(data); /* the final (forced) update */
@@ -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 */
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)
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 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);
@@ -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,
@@ -35,25 +35,28 @@
/* functions provided by the specific backends */
-CURLcode Curl_quic_connect(struct connectdata *conn,
+CURLcode Curl_quic_connect(struct Curl_easy *data,
curl_socket_t sockfd,
const struct sockaddr *addr,
socklen_t addrlen);
-CURLcode Curl_quic_is_connected(struct connectdata *conn,
+CURLcode Curl_quic_is_connected(struct Curl_easy *data,
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 */
@@ -22,7 +22,7 @@
-#ifndef CURL_DISABLE_RTSP
+#if !defined(CURL_DISABLE_RTSP) && !defined(USE_HYPER)
((int)((unsigned char)((p)[3]))))
-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,
+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,
+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,
/* write mode */
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)
struct RTSP *rtsp;
- conn->data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
+ data->req.p.rtsp = rtsp = calloc(1, sizeof(struct RTSP));
if(!rtsp)
@@ -156,13 +163,15 @@ static bool rtsp_connisdead(struct connectdata *check)
* Function to check on various aspects of a connection.
- if(rtsp_connisdead(check))
+ if(rtsp_connisdead(conn))
@@ -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;
- 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)
+ struct connectdata *conn, bool dead)
(void) dead;
Curl_safefree(conn->proto.rtspc.rtp_buf);
-static CURLcode rtsp_done(struct connectdata *conn,
+static CURLcode rtsp_done(struct Curl_easy *data,
CURLcode status, bool premature)
struct RTSP *rtsp = data->req.p.rtsp;
@@ -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,
-static CURLcode rtsp_do(struct connectdata *conn, bool *done)
+static CURLcode rtsp_do(struct Curl_easy *data, bool *done)
Curl_RtspReq rtspreq = data->set.rtspreq;
@@ -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);
@@ -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);
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.");
- 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)
if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
- result = Curl_add_timecondition(conn, &req_buffer);
+ result = Curl_add_timecondition(data, &req_buffer);
- result = Curl_add_custom_headers(conn, FALSE, &req_buffer);
+ result = Curl_add_custom_headers(data, FALSE, &req_buffer);
@@ -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")) {
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");
@@ -532,7 +542,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_ANNOUNCE) {
"Content-Type: application/sdp\r\n");
@@ -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);
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);
@@ -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);
failf(data, "Got an error writing an RTP packet");
*readmore = FALSE;
@@ -713,9 +723,8 @@ static CURLcode rtsp_rtp_readwrite(struct Curl_easy *data,
-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)
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)
-CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
- char *header)
+CURLcode Curl_rtsp_parseheader(struct Curl_easy *data, char *header)
long CSeq = 0;
if(checkprefix("CSeq:", header)) {
@@ -826,4 +833,4 @@ CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
-#endif /* CURL_DISABLE_RTSP */
+#endif /* CURL_DISABLE_RTSP or using Hyper */
@@ -21,11 +21,15 @@
* KIND, either express or implied.
+#define CURL_DISABLE_RTSP
#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);
/* disabled */
@@ -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 */
* 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)
@@ -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);
@@ -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)
@@ -230,7 +231,7 @@ bool Curl_recv_has_postponed_data(struct connectdata *conn, int 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) {
@@ -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,
const void *mem,
size_t len,
@@ -300,9 +302,14 @@ CURLcode Curl_write(struct connectdata *conn,
- int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+ int num;
+ 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];
+ curl_socket_t sockfd;
+ 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;
@@ -372,9 +385,9 @@ ssize_t Curl_send_plain(struct connectdata *conn, int num,
- 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,
ssize_t *written)
- ssize_t bytes_written;
- bytes_written = Curl_send_plain(conn, num, mem, len, &result);
- *written = bytes_written;
+ *written = Curl_send_plain(data, num, mem, len, &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)
/* 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,
- failf(conn->data, "Recv failure: %s",
+ failf(data, "Recv failure: %s",
*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)
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,
char *ptr,
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 */
size_t bytesfromsocket = 0;
char *buffertofill = NULL;
/* 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)
@@ -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);
size_t len, CURLcode *code);
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,
/* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */
const void *mem, size_t len,
ssize_t *written);
/* internal write-function, does plain sockets ONLY */
@@ -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;
/* 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;
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 */
+ 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;
#endif /* CURL_DISABLE_HTTP */
case CURLOPT_MIMEPOST:
@@ -865,7 +882,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
;
-#ifndef USE_NGHTTP2
+#if !defined(USE_NGHTTP2) && !defined(USE_HYPER)
if(arg >= CURL_HTTP_VERSION_2)
return CURLE_UNSUPPORTED_PROTOCOL;
@@ -1444,13 +1461,16 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
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))
- data->set.ipver = arg;
+ data->set.ipver = (unsigned char) arg;
case CURLOPT_MAXFILESIZE_LARGE:
@@ -27,6 +27,7 @@
#include "curl_sha256.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) \
+ 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; \
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 */
@@ -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)
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;
@@ -37,8 +37,12 @@
#define CURL_VOLATILE volatile
+#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;
+ * 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.
@@ -54,16 +54,20 @@
/* 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,
+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,
+static int smb_getsock(struct Curl_easy *data, struct connectdata *conn,
+static CURLcode smb_parse_url_path(struct Curl_easy *data,
* 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);
+ strcpy(p, (str)); \
+ p += strlen(str); \
/* Append a null-terminated string to an SMB message */
#define MSGCATNULL(str) \
- p += strlen(str) + 1;
+ p += strlen(str) + 1; \
/* SMB is mostly little endian */
#if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \
@@ -179,9 +187,9 @@ struct smb_request {
-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;
/* 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]);
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;
@@ -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]);
@@ -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)
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)
/* 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 smb_conn *smbc = &conn->proto.smbc;
char *slash;
@@ -284,8 +294,9 @@ static CURLcode smb_connect(struct connectdata *conn, bool *done)
-static CURLcode smb_recv_message(struct connectdata *conn, void **msg)
+static CURLcode smb_recv_message(struct Curl_easy *data, void **msg)
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;
- result = Curl_read(conn, FIRSTSOCKET, buf + smbc->got, len, &bytes_read);
+ result = Curl_read(data, FIRSTSOCKET, buf + smbc->got, len, &bytes_read);
@@ -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)
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)
- result = Curl_write(conn, FIRSTSOCKET, conn->data->state.ulbuf,
+ result = Curl_write(data, FIRSTSOCKET, data->state.ulbuf,
len, &bytes_written);
@@ -381,8 +394,9 @@ static CURLcode smb_send(struct connectdata *conn, ssize_t len,
-static CURLcode smb_flush(struct connectdata *conn)
+static CURLcode smb_flush(struct Curl_easy *data)
ssize_t len = smbc->send_size - smbc->sent;
@@ -391,8 +405,8 @@ static CURLcode smb_flush(struct connectdata *conn)
if(!smbc->send_size)
- result = Curl_write(conn, FIRSTSOCKET,
- conn->data->state.ulbuf + smbc->sent,
+ result = Curl_write(data, FIRSTSOCKET,
+ data->state.ulbuf + smbc->sent,
@@ -405,29 +419,30 @@ static CURLcode smb_flush(struct connectdata *conn)
-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);
- 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 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);
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;
@@ -499,13 +515,13 @@ static CURLcode smb_send_tree_connect(struct connectdata *conn)
- return smb_send_message(conn, SMB_COM_TREE_CONNECT_ANDX, &msg,
+ return smb_send_message(data, SMB_COM_TREE_CONNECT_ANDX, &msg,
-static CURLcode smb_send_open(struct connectdata *conn)
+static CURLcode smb_send_open(struct Curl_easy *data)
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);
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,
-static CURLcode smb_send_close(struct connectdata *conn)
+static CURLcode smb_send_close(struct Curl_easy *data)
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;
- 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)
- curl_off_t offset = conn->data->req.offset;
+ curl_off_t offset = data->req.offset;
struct smb_read 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;
- curl_off_t upload_size = conn->data->req.size - conn->data->req.bytecount;
+ curl_off_t upload_size = data->req.size - data->req.bytecount;
- 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)
*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);
+ result = Curl_fillreadbuffer(data, nread, &nread);
if(result && result != CURLE_AGAIN)
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);
@@ -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 smb_negotiate_response *nrsp;
struct smb_header *h;
@@ -651,7 +669,8 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
if((conn->handler->flags & PROTOPT_SSL)) {
bool ssl_done = FALSE;
- result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &ssl_done);
+ FIRSTSOCKET, &ssl_done);
if(!ssl_done)
@@ -659,17 +678,17 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
- result = smb_send_negotiate(conn);
+ result = smb_send_negotiate(data);
connclose(conn, "SMB: failed to send negotiate message");
- 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");
@@ -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);
connclose(conn, "SMB: failed to send setup message");
- conn_state(conn, SMB_SETUP);
+ conn_state(data, SMB_SETUP);
case SMB_SETUP:
@@ -704,7 +723,7 @@ static CURLcode smb_connection_state(struct connectdata *conn, bool *done)
smbc->uid = smb_swap16(h->uid);
- conn_state(conn, SMB_CONNECTED);
+ conn_state(data, SMB_CONNECTED);
*done = true;
@@ -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)
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);
connclose(conn, "SMB: failed to send tree connect message");
- request_state(conn, SMB_TREE_CONNECT);
+ request_state(data, SMB_TREE_CONNECT);
@@ -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;
- conn->data->req.size = conn->data->state.infilesize;
- Curl_pgrsSetUploadSize(conn->data, conn->data->req.size);
+ data->req.offset = 0;
+ data->req.size = data->state.infilesize;
+ Curl_pgrsSetUploadSize(data, data->req.size);
next_state = SMB_UPLOAD;
- 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;
- 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;
(char *)msg + off + sizeof(unsigned int),
len);
@@ -840,9 +860,9 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
- conn->data->req.bytecount += len;
- conn->data->req.offset += len;
- Curl_pgrsSetDownloadCounter(conn->data, conn->data->req.bytecount);
+ data->req.offset += len;
next_state = (len < MAX_PAYLOAD_SIZE) ? SMB_CLOSE : SMB_DOWNLOAD;
@@ -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);
- Curl_pgrsSetUploadCounter(conn->data, conn->data->req.bytecount);
- if(conn->data->req.bytecount >= conn->data->req.size)
+ Curl_pgrsSetUploadCounter(data, data->req.bytecount);
+ if(data->req.bytecount >= data->req.size)
@@ -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);
case SMB_DOWNLOAD:
- result = smb_send_read(conn);
+ result = smb_send_read(data);
case SMB_UPLOAD:
- result = smb_send_write(conn);
+ result = smb_send_write(data);
case SMB_CLOSE:
- result = smb_send_close(conn);
+ result = smb_send_close(data);
case SMB_TREE_DISCONNECT:
- result = smb_send_tree_disconnect(conn);
+ result = smb_send_tree_disconnect(data);
case SMB_DONE:
@@ -914,37 +934,42 @@ static CURLcode smb_request_state(struct connectdata *conn, bool *done)
- request_state(conn, next_state);
+ request_state(data, next_state);
(void) premature;
- Curl_safefree(conn->data->req.p.smb);
+ Curl_safefree(data->req.p.smb);
-static CURLcode smb_disconnect(struct connectdata *conn, bool dead)
Curl_safefree(smbc->share);
Curl_safefree(smbc->domain);
Curl_safefree(smbc->recv_buf);
-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)
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)
@@ -954,9 +979,9 @@ static CURLcode smb_do(struct connectdata *conn, bool *done)
-static CURLcode smb_parse_url_path(struct connectdata *conn)
struct smb_request *req = data->req.p.smb;
char *path;
@@ -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 */
- 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 */
@@ -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 */
ssize_t buffersize, /* max amount to read */
@@ -62,7 +62,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
- timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, TRUE);
+ timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
/* we already got the timeout */
@@ -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
, int lineno
enum connect_t oldstate = conn->cnnct.state;
/* synced with the state list in urldata.h */
@@ -146,7 +147,7 @@ static void socksstate(struct connectdata *conn,
conn->cnnct.state = state;
"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,
int remote_port,
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;
curl_socket_t sockfd = conn->sock[sockindex];
struct connstate *sx = &conn->cnnct;
ssize_t actualread;
+ /* 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:
infof(data, "Hostname '%s' was found\n", hostname);
if(!dns) {
@@ -298,7 +302,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
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);
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 */
- sxstate(conn, CONNECT_SOCKS_READ);
+ sxstate(data, CONNECT_SOCKS_READ);
case CONNECT_SOCKS_READ:
@@ -396,7 +400,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
sx->outp += actualread;
- sxstate(conn, CONNECT_DONE);
+ sxstate(data, CONNECT_DONE);
default: /* lots of unused states in SOCKS4 */
@@ -437,8 +441,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
"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,
", request rejected because SOCKS server cannot connect to "
"identd on the client.",
return CURLPX_IDENTD;
@@ -457,8 +459,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
", request rejected because the client program and identd "
"report different user-ids.",
return CURLPX_IDENTD_DIFFER;
@@ -466,8 +467,7 @@ CURLproxycode Curl_SOCKS4(const char *proxy_user,
", Unknown.",
return CURLPX_UNKNOWN_FAIL;
@@ -486,7 +486,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
@@ -505,14 +505,14 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
o REP Reply field:
o X'00' succeeded
char dest[256] = "unknown"; /* printable hostname:port */
int idx;
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,
- infof(conn->data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
+ infof(data, "SOCKS5: connecting to HTTP proxy %s port %d\n",
/* 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))
"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);
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];
goto CONNECT_SOCKS_READ_INIT;
case CONNECT_SOCKS_SEND:
@@ -617,18 +617,18 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
else if(socksreq[1] == 0) {
/* DONE! No authentication needed. Send request. */
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);
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;
case CONNECT_AUTH_SEND:
failf(data, "Failed to send SOCKS5 sub-negotiation request.");
@@ -721,7 +721,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
sx->outstanding = 2;
- sxstate(conn, CONNECT_AUTH_READ);
+ sxstate(data, CONNECT_AUTH_READ);
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! */
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_PENDING) {
goto CONNECT_RESOLVE_REMOTE;
- dns = Curl_fetch_addr(conn, hostname, remote_port);
+ dns = Curl_fetch_addr(data, hostname, remote_port);
infof(data, "SOCKS5: hostname '%s' found\n", hostname);
@@ -839,7 +839,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
- failf(data, "SOCKS5 connection to %s not supported\n", dest);
+ failf(data, "SOCKS5 connection to %s not supported", dest);
@@ -878,10 +878,10 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
failf(data, "Failed to send SOCKS5 connect request.");
@@ -901,7 +901,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
sx->outstanding = 10; /* minimum packet size is 10 */
- sxstate(conn, CONNECT_REQ_READ);
+ sxstate(data, CONNECT_REQ_READ);
case CONNECT_REQ_READ:
@@ -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);
@@ -1020,7 +1020,7 @@ CURLproxycode Curl_SOCKS5(const char *proxy_user,
infof(data, "SOCKS5 request granted.\n");