From 858bae65a9113518b1117e9885f5adff274c3991 Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Mon, 22 Sep 2025 11:29:49 +0200 Subject: [PATCH] deps: update libcurl to 8.16.0 --- deps/curl/.editorconfig | 18 + deps/curl/include/Makefile.in | 1 + deps/curl/include/curl/Makefile.in | 1 + deps/curl/include/curl/curl.h | 218 ++- deps/curl/include/curl/curlver.h | 9 +- deps/curl/include/curl/easy.h | 4 +- deps/curl/include/curl/header.h | 2 +- deps/curl/include/curl/mprintf.h | 6 +- deps/curl/include/curl/multi.h | 46 +- deps/curl/include/curl/options.h | 2 +- deps/curl/include/curl/system.h | 32 +- deps/curl/include/curl/typecheck-gcc.h | 100 +- deps/curl/include/curl/urlapi.h | 2 +- deps/curl/include/curl/websockets.h | 21 +- deps/curl/lib/CMakeLists.txt | 13 +- deps/curl/lib/Makefile.am | 6 +- deps/curl/lib/Makefile.in | 354 ++-- deps/curl/lib/Makefile.inc | 5 +- deps/curl/lib/altsvc.c | 8 +- deps/curl/lib/asyn-ares.c | 111 +- deps/curl/lib/asyn-base.c | 44 +- deps/curl/lib/asyn-thrdd.c | 392 ++-- deps/curl/lib/asyn.h | 20 +- deps/curl/lib/bufq.c | 18 +- deps/curl/lib/cf-h1-proxy.c | 14 +- deps/curl/lib/cf-h2-proxy.c | 38 +- deps/curl/lib/cf-h2-proxy.h | 3 +- deps/curl/lib/cf-haproxy.c | 15 +- deps/curl/lib/cf-haproxy.h | 2 +- deps/curl/lib/cf-https-connect.c | 43 +- deps/curl/lib/cf-https-connect.h | 10 +- deps/curl/lib/cf-ip-happy.c | 951 +++++++++ deps/curl/lib/cf-ip-happy.h | 59 + deps/curl/lib/cf-socket.c | 63 +- deps/curl/lib/cf-socket.h | 8 - deps/curl/lib/cfilters.c | 370 ++-- deps/curl/lib/cfilters.h | 95 +- deps/curl/lib/config-os400.h | 4 - deps/curl/lib/config-win32.h | 8 +- deps/curl/lib/conncache.c | 39 +- deps/curl/lib/conncache.h | 4 + deps/curl/lib/connect.c | 918 +-------- deps/curl/lib/connect.h | 23 - deps/curl/lib/content_encoding.c | 24 +- deps/curl/lib/cookie.c | 90 +- deps/curl/lib/cookie.h | 10 +- deps/curl/lib/cshutdn.c | 39 +- deps/curl/lib/curl_addrinfo.c | 16 +- deps/curl/lib/curl_config.h.cmake | 6 - deps/curl/lib/curl_config.h.in | 11 +- deps/curl/lib/curl_fnmatch.c | 7 +- deps/curl/lib/curl_gethostname.c | 4 +- deps/curl/lib/curl_gssapi.c | 2 +- deps/curl/lib/curl_hmac.h | 2 +- deps/curl/lib/curl_md4.h | 4 +- deps/curl/lib/curl_md5.h | 4 +- .../{vquic/curl_msh3.h => curl_mem_undef.h} | 53 +- deps/curl/lib/curl_memory.h | 68 - deps/curl/lib/curl_ntlm_core.c | 41 +- deps/curl/lib/curl_ntlm_core.h | 4 +- deps/curl/lib/curl_rtmp.c | 64 +- deps/curl/lib/curl_sasl.c | 10 +- deps/curl/lib/curl_setup.h | 196 +- deps/curl/lib/curl_setup_once.h | 6 - deps/curl/lib/curl_sha256.h | 4 +- deps/curl/lib/curl_sha512_256.c | 118 +- deps/curl/lib/curl_sspi.c | 8 +- deps/curl/lib/curl_sspi.h | 38 +- deps/curl/lib/curl_threads.c | 57 +- deps/curl/lib/curl_threads.h | 37 +- deps/curl/lib/curl_trc.c | 66 +- deps/curl/lib/curl_trc.h | 18 +- deps/curl/lib/curlx/base64.c | 9 - deps/curl/lib/curlx/dynbuf.c | 13 +- deps/curl/lib/curlx/dynbuf.h | 2 +- deps/curl/lib/curlx/inet_ntop.c | 2 +- deps/curl/lib/curlx/inet_ntop.h | 6 +- deps/curl/lib/curlx/inet_pton.h | 6 +- deps/curl/lib/curlx/multibyte.h | 8 +- deps/curl/lib/curlx/nonblock.c | 2 +- deps/curl/lib/curlx/strparse.c | 2 +- deps/curl/lib/curlx/timeval.c | 10 +- deps/curl/lib/curlx/wait.c | 2 +- deps/curl/lib/curlx/warnless.c | 6 +- deps/curl/lib/cw-out.c | 109 +- deps/curl/lib/dict.c | 14 +- deps/curl/lib/dllmain.c | 6 +- deps/curl/lib/doh.c | 49 +- deps/curl/lib/doh.h | 12 +- deps/curl/lib/easy.c | 95 +- deps/curl/lib/easy_lock.h | 8 +- deps/curl/lib/easygetopt.c | 2 +- deps/curl/lib/file.c | 20 +- deps/curl/lib/fileinfo.c | 3 + deps/curl/lib/fopen.c | 2 +- deps/curl/lib/formdata.c | 26 +- deps/curl/lib/ftp.c | 1153 +++++------ deps/curl/lib/ftp.h | 10 +- deps/curl/lib/gopher.c | 18 +- deps/curl/lib/hmac.c | 8 +- deps/curl/lib/hostip.c | 169 +- deps/curl/lib/hostip.h | 18 +- deps/curl/lib/hostip4.c | 12 +- deps/curl/lib/hostip6.c | 6 +- deps/curl/lib/hsts.c | 12 +- deps/curl/lib/http.c | 759 ++++---- deps/curl/lib/http.h | 12 +- deps/curl/lib/http2.c | 47 +- deps/curl/lib/http_aws_sigv4.c | 4 +- deps/curl/lib/http_chunks.c | 9 +- deps/curl/lib/http_digest.c | 4 +- deps/curl/lib/http_ntlm.c | 2 +- deps/curl/lib/http_proxy.c | 51 +- deps/curl/lib/httpsrr.h | 2 +- deps/curl/lib/idn.c | 14 +- deps/curl/lib/if2ip.c | 16 +- deps/curl/lib/imap.c | 57 +- deps/curl/lib/krb5.c | 11 +- deps/curl/lib/ldap.c | 78 +- deps/curl/lib/libcurl.def | 2 + deps/curl/lib/md4.c | 68 +- deps/curl/lib/md5.c | 33 +- deps/curl/lib/memdebug.c | 4 +- deps/curl/lib/memdebug.h | 122 +- deps/curl/lib/mime.c | 165 +- deps/curl/lib/mqtt.c | 21 +- deps/curl/lib/multi.c | 568 +++--- deps/curl/lib/multi_ev.c | 88 +- deps/curl/lib/multihandle.h | 9 +- deps/curl/lib/multiif.h | 22 +- deps/curl/lib/netrc.c | 64 +- deps/curl/lib/netrc.h | 3 +- deps/curl/lib/noproxy.c | 10 +- deps/curl/lib/openldap.c | 49 +- deps/curl/lib/optiontable.pl | 30 +- deps/curl/lib/parsedate.c | 27 +- deps/curl/lib/parsedate.h | 4 +- deps/curl/lib/pingpong.c | 18 +- deps/curl/lib/pingpong.h | 5 +- deps/curl/lib/pop3.c | 49 +- deps/curl/lib/progress.c | 51 +- deps/curl/lib/rand.c | 9 +- deps/curl/lib/request.c | 16 +- deps/curl/lib/request.h | 1 - deps/curl/lib/rtsp.c | 194 +- deps/curl/lib/select.c | 235 ++- deps/curl/lib/select.h | 84 + deps/curl/lib/sendf.c | 90 +- deps/curl/lib/sendf.h | 21 +- deps/curl/lib/setopt.c | 1723 ++++++++--------- deps/curl/lib/setopt.h | 7 + deps/curl/lib/sha256.c | 36 +- deps/curl/lib/smb.c | 34 +- deps/curl/lib/smb.h | 5 +- deps/curl/lib/smtp.c | 111 +- deps/curl/lib/socketpair.c | 4 +- deps/curl/lib/socketpair.h | 5 +- deps/curl/lib/socks.c | 357 ++-- deps/curl/lib/socks_gssapi.c | 6 +- deps/curl/lib/socks_sspi.c | 292 ++- deps/curl/lib/splay.c | 26 +- deps/curl/lib/strdup.c | 2 +- deps/curl/lib/strequal.c | 2 +- deps/curl/lib/strerror.c | 2 +- deps/curl/lib/telnet.c | 12 +- deps/curl/lib/tftp.c | 31 +- deps/curl/lib/transfer.c | 183 +- deps/curl/lib/transfer.h | 53 +- deps/curl/lib/uint-bset.c | 4 +- deps/curl/lib/url.c | 107 +- deps/curl/lib/url.h | 9 +- deps/curl/lib/urlapi.c | 21 +- deps/curl/lib/urldata.h | 102 +- deps/curl/lib/vauth/cleartext.c | 4 +- deps/curl/lib/vauth/digest_sspi.c | 10 +- deps/curl/lib/vauth/krb5_gssapi.c | 4 +- deps/curl/lib/vauth/krb5_sspi.c | 4 +- deps/curl/lib/vauth/ntlm.c | 8 +- deps/curl/lib/vauth/ntlm_sspi.c | 12 +- deps/curl/lib/vauth/spnego_gssapi.c | 4 +- deps/curl/lib/vauth/spnego_sspi.c | 4 +- deps/curl/lib/vauth/vauth.c | 4 +- deps/curl/lib/vauth/vauth.h | 14 +- deps/curl/lib/version.c | 30 +- deps/curl/lib/vquic/curl_msh3.c | 1095 ----------- deps/curl/lib/vquic/curl_ngtcp2.c | 57 +- deps/curl/lib/vquic/curl_ngtcp2.h | 2 +- deps/curl/lib/vquic/curl_osslq.c | 89 +- deps/curl/lib/vquic/curl_osslq.h | 3 +- deps/curl/lib/vquic/curl_quiche.c | 37 +- deps/curl/lib/vquic/curl_quiche.h | 2 +- deps/curl/lib/vquic/vquic-tls.c | 4 +- deps/curl/lib/vquic/vquic.c | 80 +- deps/curl/lib/vquic/vquic.h | 4 +- deps/curl/lib/vquic/vquic_int.h | 9 + deps/curl/lib/vssh/curl_path.c | 2 +- deps/curl/lib/vssh/libssh.c | 153 +- deps/curl/lib/vssh/libssh2.c | 87 +- deps/curl/lib/vssh/ssh.h | 13 +- deps/curl/lib/vssh/wolfssh.c | 339 ++-- deps/curl/lib/vtls/cipher_suite.c | 16 +- deps/curl/lib/vtls/gtls.c | 496 ++--- deps/curl/lib/vtls/hostcheck.c | 3 +- deps/curl/lib/vtls/hostcheck.h | 4 + deps/curl/lib/vtls/mbedtls.c | 186 +- deps/curl/lib/vtls/openssl.c | 1231 ++++++------ deps/curl/lib/vtls/openssl.h | 26 +- deps/curl/lib/vtls/rustls.c | 17 +- deps/curl/lib/vtls/schannel.c | 483 +++-- deps/curl/lib/vtls/schannel.h | 4 +- deps/curl/lib/vtls/schannel_int.h | 43 +- deps/curl/lib/vtls/schannel_verify.c | 31 +- deps/curl/lib/vtls/vtls.c | 163 +- deps/curl/lib/vtls/vtls_int.h | 9 +- deps/curl/lib/vtls/vtls_spack.c | 4 +- deps/curl/lib/vtls/vtls_spack.h | 4 +- deps/curl/lib/vtls/wolfssl.c | 342 ++-- deps/curl/lib/vtls/wolfssl.h | 2 +- deps/curl/lib/ws.c | 933 ++++++--- 219 files changed, 9750 insertions(+), 9510 deletions(-) create mode 100644 deps/curl/.editorconfig create mode 100644 deps/curl/lib/cf-ip-happy.c create mode 100644 deps/curl/lib/cf-ip-happy.h rename deps/curl/lib/{vquic/curl_msh3.h => curl_mem_undef.h} (62%) delete mode 100644 deps/curl/lib/vquic/curl_msh3.c diff --git a/deps/curl/.editorconfig b/deps/curl/.editorconfig new file mode 100644 index 00000000000..edcc4629fba --- /dev/null +++ b/deps/curl/.editorconfig @@ -0,0 +1,18 @@ +# Copyright (C) Daniel Stenberg, , et al. +# +# SPDX-License-Identifier: curl + +root = true + +[*] +charset = utf-8 +insert_final_newline = true +indent_style = space +trim_trailing_whitespace = true + +[*.{c,h}] +indent_size = 2 +max_line_length = 79 + +[*.{pl,pm}] +indent_size = 4 diff --git a/deps/curl/include/Makefile.in b/deps/curl/include/Makefile.in index 3bfa56e75a8..2169d15a23b 100644 --- a/deps/curl/include/Makefile.in +++ b/deps/curl/include/Makefile.in @@ -232,6 +232,7 @@ CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX = @CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX@ CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME = @CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME@ CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ CYGPATH_W = @CYGPATH_W@ +DANTED = @DANTED@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ diff --git a/deps/curl/include/curl/Makefile.in b/deps/curl/include/curl/Makefile.in index aa203e458e7..2d3e435a940 100644 --- a/deps/curl/include/curl/Makefile.in +++ b/deps/curl/include/curl/Makefile.in @@ -219,6 +219,7 @@ CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX = @CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX@ CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME = @CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME@ CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ CYGPATH_W = @CYGPATH_W@ +DANTED = @DANTED@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ diff --git a/deps/curl/include/curl/curl.h b/deps/curl/include/curl/curl.h index 7ef5b993498..6f4aa90f134 100644 --- a/deps/curl/include/curl/curl.h +++ b/deps/curl/include/curl/curl.h @@ -102,7 +102,7 @@ #include #endif -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -124,7 +124,7 @@ typedef void CURLSH; #elif defined(_WIN32) || \ (CURL_HAS_DECLSPEC_ATTRIBUTE(dllexport) && \ CURL_HAS_DECLSPEC_ATTRIBUTE(dllimport)) -# if defined(BUILDING_LIBCURL) +# ifdef BUILDING_LIBCURL # define CURL_EXTERN __declspec(dllexport) # else # define CURL_EXTERN __declspec(dllimport) @@ -788,20 +788,24 @@ typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */ mbedtls_ssl_config */ void *userptr); +#define CURLPROXY_HTTP 0L /* added in 7.10, new in 7.19.4 default is + to use CONNECT HTTP/1.1 */ +#define CURLPROXY_HTTP_1_0 1L /* force to use CONNECT HTTP/1.0 + added in 7.19.4 */ +#define CURLPROXY_HTTPS 2L /* HTTPS but stick to HTTP/1 + added in 7.52.0 */ +#define CURLPROXY_HTTPS2 3L /* HTTPS and attempt HTTP/2 + added in 8.2.0 */ +#define CURLPROXY_SOCKS4 4L /* support added in 7.15.2, enum existed + already in 7.10 */ +#define CURLPROXY_SOCKS5 5L /* added in 7.10 */ +#define CURLPROXY_SOCKS4A 6L /* added in 7.18.0 */ +#define CURLPROXY_SOCKS5_HOSTNAME 7L /* Use the SOCKS5 protocol but pass along + the hostname rather than the IP + address. added in 7.18.0 */ + typedef enum { - CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use - CONNECT HTTP/1.1 */ - CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT - HTTP/1.0 */ - CURLPROXY_HTTPS = 2, /* HTTPS but stick to HTTP/1 added in 7.52.0 */ - CURLPROXY_HTTPS2 = 3, /* HTTPS and attempt HTTP/2 added in 8.2.0 */ - CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already - in 7.10 */ - CURLPROXY_SOCKS5 = 5, /* added in 7.10 */ - CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */ - CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the - hostname rather than the IP address. added - in 7.18.0 */ + CURLPROXY_LAST = 8 /* never use */ } curl_proxytype; /* this enum was added in 7.10 */ /* @@ -842,19 +846,19 @@ typedef enum { #define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE) #define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE)) -#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */ -#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */ -#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */ -#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */ -#define CURLSSH_AUTH_HOST (1<<2) /* host key files */ -#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ -#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */ -#define CURLSSH_AUTH_GSSAPI (1<<5) /* gssapi (kerberos, ...) */ +#define CURLSSH_AUTH_ANY ~0L /* all types supported by the server */ +#define CURLSSH_AUTH_NONE 0L /* none allowed, silly but complete */ +#define CURLSSH_AUTH_PUBLICKEY (1L<<0) /* public/private key files */ +#define CURLSSH_AUTH_PASSWORD (1L<<1) /* password */ +#define CURLSSH_AUTH_HOST (1L<<2) /* host key files */ +#define CURLSSH_AUTH_KEYBOARD (1L<<3) /* keyboard interactive */ +#define CURLSSH_AUTH_AGENT (1L<<4) /* agent (ssh-agent, pageant...) */ +#define CURLSSH_AUTH_GSSAPI (1L<<5) /* gssapi (kerberos, ...) */ #define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY -#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */ -#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */ -#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */ +#define CURLGSSAPI_DELEGATION_NONE 0L /* no delegation (default) */ +#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1L<<0) /* if permitted by policy */ +#define CURLGSSAPI_DELEGATION_FLAG (1L<<1) /* delegate always */ #define CURL_ERROR_SIZE 256 @@ -979,50 +983,55 @@ typedef enum { #endif /* !CURL_NO_OLDIES */ /* parameter for the CURLOPT_FTP_SSL_CCC option */ +#define CURLFTPSSL_CCC_NONE 0L /* do not send CCC */ +#define CURLFTPSSL_CCC_PASSIVE 1L /* Let the server initiate the shutdown */ +#define CURLFTPSSL_CCC_ACTIVE 2L /* Initiate the shutdown */ + typedef enum { - CURLFTPSSL_CCC_NONE, /* do not send CCC */ - CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */ - CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */ - CURLFTPSSL_CCC_LAST /* not an option, never use */ + CURLFTPSSL_CCC_LAST = 3 /* not an option, never use */ } curl_ftpccc; /* parameter for the CURLOPT_FTPSSLAUTH option */ +#define CURLFTPAUTH_DEFAULT 0L /* let libcurl decide */ +#define CURLFTPAUTH_SSL 1L /* use "AUTH SSL" */ +#define CURLFTPAUTH_TLS 2L /* use "AUTH TLS" */ + typedef enum { - CURLFTPAUTH_DEFAULT, /* let libcurl decide */ - CURLFTPAUTH_SSL, /* use "AUTH SSL" */ - CURLFTPAUTH_TLS, /* use "AUTH TLS" */ - CURLFTPAUTH_LAST /* not an option, never use */ + CURLFTPAUTH_LAST = 3 /* not an option, never use */ } curl_ftpauth; /* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */ +#define CURLFTP_CREATE_DIR_NONE 0L /* do NOT create missing dirs! */ +#define CURLFTP_CREATE_DIR 1L /* (FTP/SFTP) if CWD fails, try MKD and + then CWD again if MKD succeeded, for + SFTP this does similar magic */ +#define CURLFTP_CREATE_DIR_RETRY 2L /* (FTP only) if CWD fails, try MKD and + then CWD again even if MKD failed! */ + typedef enum { - CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */ - CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD - again if MKD succeeded, for SFTP this does - similar magic */ - CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD - again even if MKD failed! */ - CURLFTP_CREATE_DIR_LAST /* not an option, never use */ + CURLFTP_CREATE_DIR_LAST = 3 /* not an option, never use */ } curl_ftpcreatedir; /* parameter for the CURLOPT_FTP_FILEMETHOD option */ +#define CURLFTPMETHOD_DEFAULT 0L /* let libcurl pick */ +#define CURLFTPMETHOD_MULTICWD 1L /* single CWD operation for each path + part */ +#define CURLFTPMETHOD_NOCWD 2L /* no CWD at all */ +#define CURLFTPMETHOD_SINGLECWD 3L /* one CWD to full dir, then work on file */ + typedef enum { - CURLFTPMETHOD_DEFAULT, /* let libcurl pick */ - CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */ - CURLFTPMETHOD_NOCWD, /* no CWD at all */ - CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */ - CURLFTPMETHOD_LAST /* not an option, never use */ + CURLFTPMETHOD_LAST = 4 /* not an option, never use */ } curl_ftpmethod; /* bitmask defines for CURLOPT_HEADEROPT */ -#define CURLHEADER_UNIFIED 0 -#define CURLHEADER_SEPARATE (1<<0) +#define CURLHEADER_UNIFIED 0L +#define CURLHEADER_SEPARATE (1L<<0) /* CURLALTSVC_* are bits for the CURLOPT_ALTSVC_CTRL option */ -#define CURLALTSVC_READONLYFILE (1<<2) -#define CURLALTSVC_H1 (1<<3) -#define CURLALTSVC_H2 (1<<4) -#define CURLALTSVC_H3 (1<<5) +#define CURLALTSVC_READONLYFILE (1L<<2) +#define CURLALTSVC_H1 (1L<<3) +#define CURLALTSVC_H2 (1L<<4) +#define CURLALTSVC_H3 (1L<<5) /* bitmask values for CURLOPT_UPLOAD_FLAGS */ #define CURLULFLAG_ANSWERED (1L<<0) @@ -1058,42 +1067,42 @@ typedef CURLSTScode (*curl_hstswrite_callback)(CURL *easy, void *userp); /* CURLHSTS_* are bits for the CURLOPT_HSTS option */ -#define CURLHSTS_ENABLE (long)(1<<0) -#define CURLHSTS_READONLYFILE (long)(1<<1) +#define CURLHSTS_ENABLE (1L<<0) +#define CURLHSTS_READONLYFILE (1L<<1) /* The CURLPROTO_ defines below are for the **deprecated** CURLOPT_*PROTOCOLS options. Do not use. */ -#define CURLPROTO_HTTP (1<<0) -#define CURLPROTO_HTTPS (1<<1) -#define CURLPROTO_FTP (1<<2) -#define CURLPROTO_FTPS (1<<3) -#define CURLPROTO_SCP (1<<4) -#define CURLPROTO_SFTP (1<<5) -#define CURLPROTO_TELNET (1<<6) -#define CURLPROTO_LDAP (1<<7) -#define CURLPROTO_LDAPS (1<<8) -#define CURLPROTO_DICT (1<<9) -#define CURLPROTO_FILE (1<<10) -#define CURLPROTO_TFTP (1<<11) -#define CURLPROTO_IMAP (1<<12) -#define CURLPROTO_IMAPS (1<<13) -#define CURLPROTO_POP3 (1<<14) -#define CURLPROTO_POP3S (1<<15) -#define CURLPROTO_SMTP (1<<16) -#define CURLPROTO_SMTPS (1<<17) -#define CURLPROTO_RTSP (1<<18) -#define CURLPROTO_RTMP (1<<19) -#define CURLPROTO_RTMPT (1<<20) -#define CURLPROTO_RTMPE (1<<21) -#define CURLPROTO_RTMPTE (1<<22) -#define CURLPROTO_RTMPS (1<<23) -#define CURLPROTO_RTMPTS (1<<24) -#define CURLPROTO_GOPHER (1<<25) -#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 */ +#define CURLPROTO_HTTP (1L<<0) +#define CURLPROTO_HTTPS (1L<<1) +#define CURLPROTO_FTP (1L<<2) +#define CURLPROTO_FTPS (1L<<3) +#define CURLPROTO_SCP (1L<<4) +#define CURLPROTO_SFTP (1L<<5) +#define CURLPROTO_TELNET (1L<<6) +#define CURLPROTO_LDAP (1L<<7) +#define CURLPROTO_LDAPS (1L<<8) +#define CURLPROTO_DICT (1L<<9) +#define CURLPROTO_FILE (1L<<10) +#define CURLPROTO_TFTP (1L<<11) +#define CURLPROTO_IMAP (1L<<12) +#define CURLPROTO_IMAPS (1L<<13) +#define CURLPROTO_POP3 (1L<<14) +#define CURLPROTO_POP3S (1L<<15) +#define CURLPROTO_SMTP (1L<<16) +#define CURLPROTO_SMTPS (1L<<17) +#define CURLPROTO_RTSP (1L<<18) +#define CURLPROTO_RTMP (1L<<19) +#define CURLPROTO_RTMPT (1L<<20) +#define CURLPROTO_RTMPE (1L<<21) +#define CURLPROTO_RTMPTE (1L<<22) +#define CURLPROTO_RTMPS (1L<<23) +#define CURLPROTO_RTMPTS (1L<<24) +#define CURLPROTO_GOPHER (1L<<25) +#define CURLPROTO_SMB (1L<<26) +#define CURLPROTO_SMBS (1L<<27) +#define CURLPROTO_MQTT (1L<<28) +#define CURLPROTO_GOPHERS (1L<<29) +#define CURLPROTO_ALL (~0L) /* enable everything */ /* long may be 32 or 64 bits, but we should never depend on anything else but 32 */ @@ -2354,18 +2363,18 @@ enum CURL_NETRC_OPTION { CURL_NETRC_LAST = 3 }; -#define CURL_SSLVERSION_DEFAULT 0 -#define CURL_SSLVERSION_TLSv1 1 /* TLS 1.x */ -#define CURL_SSLVERSION_SSLv2 2 -#define CURL_SSLVERSION_SSLv3 3 -#define CURL_SSLVERSION_TLSv1_0 4 -#define CURL_SSLVERSION_TLSv1_1 5 -#define CURL_SSLVERSION_TLSv1_2 6 -#define CURL_SSLVERSION_TLSv1_3 7 +#define CURL_SSLVERSION_DEFAULT 0L +#define CURL_SSLVERSION_TLSv1 1L /* TLS 1.x */ +#define CURL_SSLVERSION_SSLv2 2L +#define CURL_SSLVERSION_SSLv3 3L +#define CURL_SSLVERSION_TLSv1_0 4L +#define CURL_SSLVERSION_TLSv1_1 5L +#define CURL_SSLVERSION_TLSv1_2 6L +#define CURL_SSLVERSION_TLSv1_3 7L -#define CURL_SSLVERSION_LAST 8 /* never use, keep last */ +#define CURL_SSLVERSION_LAST 8L /* never use, keep last */ -#define CURL_SSLVERSION_MAX_NONE 0 +#define CURL_SSLVERSION_MAX_NONE 0L #define CURL_SSLVERSION_MAX_DEFAULT (CURL_SSLVERSION_TLSv1 << 16) #define CURL_SSLVERSION_MAX_TLSv1_0 (CURL_SSLVERSION_TLSv1_0 << 16) #define CURL_SSLVERSION_MAX_TLSv1_1 (CURL_SSLVERSION_TLSv1_1 << 16) @@ -2389,10 +2398,10 @@ enum CURL_TLSAUTH { can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302 | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */ -#define CURL_REDIR_GET_ALL 0 -#define CURL_REDIR_POST_301 1 -#define CURL_REDIR_POST_302 2 -#define CURL_REDIR_POST_303 4 +#define CURL_REDIR_GET_ALL 0L +#define CURL_REDIR_POST_301 1L +#define CURL_REDIR_POST_302 2L +#define CURL_REDIR_POST_303 4L #define CURL_REDIR_POST_ALL \ (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303) @@ -2421,7 +2430,7 @@ typedef struct curl_mime curl_mime; /* Mime context. */ typedef struct curl_mimepart curl_mimepart; /* Mime part context. */ /* CURLMIMEOPT_ defines are for the CURLOPT_MIME_OPTIONS option. */ -#define CURLMIMEOPT_FORMESCAPE (1<<0) /* Use backslash-escaping for forms. */ +#define CURLMIMEOPT_FORMESCAPE (1L<<0) /* Use backslash-escaping for forms. */ /* * NAME curl_mime_init() @@ -2750,7 +2759,7 @@ CURL_EXTERN CURLcode curl_global_init(long flags); * for each application that uses libcurl. This function can be used to * initialize libcurl and set user defined memory management callback * functions. Users can implement memory management routines to check for - * memory leaks, check for mis-use of the curl library etc. User registered + * memory leaks, check for misuse of the curl library etc. User registered * callback routines will be invoked by this library instead of the system * memory management routines like malloc, free etc. */ @@ -3302,7 +3311,7 @@ CURL_EXTERN CURLcode curl_easy_ssls_export(CURL *handle, void *userptr); -#ifdef __cplusplus +#ifdef __cplusplus } /* end of extern "C" */ #endif @@ -3317,8 +3326,9 @@ CURL_EXTERN CURLcode curl_easy_ssls_export(CURL *handle, #include "mprintf.h" /* the typechecker does not work in C++ (yet) */ -#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \ - ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \ +#if ((defined(__GNUC__) && defined(__GNUC_MINOR__) && \ + ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) || \ + (defined(__clang__) && __clang_major__ >= 14)) && \ !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK) #include "typecheck-gcc.h" #else diff --git a/deps/curl/include/curl/curlver.h b/deps/curl/include/curl/curlver.h index 31b01b99755..3c7a919415e 100644 --- a/deps/curl/include/curl/curlver.h +++ b/deps/curl/include/curl/curlver.h @@ -32,14 +32,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "8.15.0" +#define LIBCURL_VERSION "8.16.0" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 8 -#define LIBCURL_VERSION_MINOR 15 +#define LIBCURL_VERSION_MINOR 16 #define LIBCURL_VERSION_PATCH 0 - /* This is the numeric version of the libcurl version number, meant for easier parsing and comparisons by programs. The LIBCURL_VERSION_NUM define will always follow this syntax: @@ -59,7 +58,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 0x080f00 +#define LIBCURL_VERSION_NUM 0x081000 /* * This is the date and time when the full source package was created. The @@ -70,7 +69,7 @@ * * "2007-11-23" */ -#define LIBCURL_TIMESTAMP "2025-07-16" +#define LIBCURL_TIMESTAMP "2025-09-10" #define CURL_VERSION_BITS(x,y,z) ((x)<<16|(y)<<8|(z)) #define CURL_AT_LEAST_VERSION(x,y,z) \ diff --git a/deps/curl/include/curl/easy.h b/deps/curl/include/curl/easy.h index 56f8060e045..fa135649379 100644 --- a/deps/curl/include/curl/easy.h +++ b/deps/curl/include/curl/easy.h @@ -23,7 +23,7 @@ * SPDX-License-Identifier: curl * ***************************************************************************/ -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -118,7 +118,7 @@ CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer, */ CURL_EXTERN CURLcode curl_easy_upkeep(CURL *curl); -#ifdef __cplusplus +#ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/deps/curl/include/curl/header.h b/deps/curl/include/curl/header.h index 8df11e1e424..7465274b9c4 100644 --- a/deps/curl/include/curl/header.h +++ b/deps/curl/include/curl/header.h @@ -24,7 +24,7 @@ * ***************************************************************************/ -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif diff --git a/deps/curl/include/curl/mprintf.h b/deps/curl/include/curl/mprintf.h index 88059c851fb..9272e748919 100644 --- a/deps/curl/include/curl/mprintf.h +++ b/deps/curl/include/curl/mprintf.h @@ -28,7 +28,7 @@ #include /* needed for FILE */ #include "curl.h" /* for CURL_EXTERN */ -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -38,7 +38,7 @@ extern "C" { defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ !defined(CURL_NO_FMT_CHECKS) #if defined(__MINGW32__) && !defined(__clang__) -#if defined(__MINGW_PRINTF_FORMAT) /* mingw-w64 3.0.0+. Needs stdio.h. */ +#ifdef __MINGW_PRINTF_FORMAT /* mingw-w64 3.0.0+. Needs stdio.h. */ #define CURL_TEMP_PRINTF(fmt, arg) \ __attribute__((format(__MINGW_PRINTF_FORMAT, fmt, arg))) #else @@ -78,7 +78,7 @@ CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args) #undef CURL_TEMP_PRINTF -#ifdef __cplusplus +#ifdef __cplusplus } /* end of extern "C" */ #endif diff --git a/deps/curl/include/curl/multi.h b/deps/curl/include/curl/multi.h index 42469bb5657..782541f1abb 100644 --- a/deps/curl/include/curl/multi.h +++ b/deps/curl/include/curl/multi.h @@ -50,7 +50,7 @@ */ #include "curl.h" -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -395,9 +395,23 @@ typedef enum { /* maximum number of concurrent streams to support on a connection */ CURLOPT(CURLMOPT_MAX_CONCURRENT_STREAMS, CURLOPTTYPE_LONG, 16), + /* network has changed, adjust caches/connection reuse */ + CURLOPT(CURLMOPT_NETWORK_CHANGED, CURLOPTTYPE_LONG, 17), + CURLMOPT_LASTENTRY /* the last unused */ } CURLMoption; +/* Definition of bits for the CURLMOPT_NETWORK_CHANGED argument: */ + +/* - CURLMNWC_CLEAR_CONNS tells libcurl to prevent further reuse of existing + connections. Connections that are idle will be closed. Ongoing transfers + will continue with the connection they have. */ +#define CURLMNWC_CLEAR_CONNS (1L<<0) + +/* - CURLMNWC_CLEAR_DNS tells libcurl to prevent further reuse of existing + connections. Connections that are idle will be closed. Ongoing transfers + will continue with the connection they have. */ +#define CURLMNWC_CLEAR_DNS (1L<<0) /* * Name: curl_multi_setopt() @@ -434,6 +448,36 @@ CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle, */ CURL_EXTERN CURL **curl_multi_get_handles(CURLM *multi_handle); + +typedef enum { + CURLMINFO_NONE, /* first, never use this */ + /* The number of easy handles currently managed by the multi handle, + * e.g. have been added but not yet removed. */ + CURLMINFO_XFERS_CURRENT = 1, + /* The number of easy handles running, e.g. not done and not queueing. */ + CURLMINFO_XFERS_RUNNING = 2, + /* The number of easy handles waiting to start, e.g. for a connection + * to become available due to limits on parallelism, max connections + * or other factors. */ + CURLMINFO_XFERS_PENDING = 3, + /* The number of easy handles finished, waiting for their results to + * be read via `curl_multi_info_read()`. */ + CURLMINFO_XFERS_DONE = 4, + /* The total number of easy handles added to the multi handle, ever. */ + CURLMINFO_XFERS_ADDED = 5 +} CURLMinfo_offt; + +/* + * Name: curl_multi_get_offt() + * + * Desc: Retrieves a numeric value for the `CURLMINFO_*` enums. + * + * Returns: CULRM_OK or error when value could not be obtained. + */ +CURL_EXTERN CURLMcode curl_multi_get_offt(CURLM *multi_handle, + CURLMinfo_offt info, + curl_off_t *pvalue); + /* * Name: curl_push_callback * diff --git a/deps/curl/include/curl/options.h b/deps/curl/include/curl/options.h index 1ed76a95c68..77cab7768f2 100644 --- a/deps/curl/include/curl/options.h +++ b/deps/curl/include/curl/options.h @@ -24,7 +24,7 @@ * ***************************************************************************/ -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif diff --git a/deps/curl/include/curl/system.h b/deps/curl/include/curl/system.h index ebcdc5e4fd0..62ed2b0f43a 100644 --- a/deps/curl/include/curl/system.h +++ b/deps/curl/include/curl/system.h @@ -66,7 +66,7 @@ # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__POCC__) -# if defined(_MSC_VER) +# ifdef _MSC_VER # define CURL_TYPEOF_CURL_OFF_T __int64 # define CURL_FORMAT_CURL_OFF_T "I64d" # define CURL_FORMAT_CURL_OFF_TU "I64u" @@ -82,7 +82,7 @@ # define CURL_TYPEOF_CURL_SOCKLEN_T int #elif defined(__LCC__) -# if defined(__MCST__) /* MCST eLbrus Compiler Collection */ +# ifdef __MCST__ /* MCST eLbrus Compiler Collection */ # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" @@ -118,7 +118,7 @@ # define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int #elif defined(__TANDEM) -# if !defined(__LP64) +# ifndef __LP64 # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" @@ -135,7 +135,7 @@ # endif #elif defined(UNDER_CE) -# if defined(__MINGW32CE__) +# ifdef __MINGW32CE__ # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" @@ -162,7 +162,7 @@ # define CURL_PULL_SYS_TYPES_H 1 #elif defined(__VMS) -# if defined(__VAX) +# ifdef __VAX # define CURL_TYPEOF_CURL_OFF_T long # define CURL_FORMAT_CURL_OFF_T "ld" # define CURL_FORMAT_CURL_OFF_TU "lu" @@ -188,7 +188,7 @@ # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__MVS__) -# if defined(_LONG_LONG) +# ifdef _LONG_LONG # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" @@ -207,7 +207,7 @@ #elif defined(__370__) # if defined(__IBMC__) || defined(__IBMCPP__) -# if defined(_LONG_LONG) +# ifdef _LONG_LONG # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" @@ -266,7 +266,7 @@ # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__xlc__) /* IBM xlc compiler */ -# if !defined(_LP64) +# ifndef _LP64 # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" @@ -284,7 +284,7 @@ # define CURL_PULL_SYS_SOCKET_H 1 #elif defined(__hpux) /* HP aCC compiler */ -# if !defined(_LP64) +# ifndef _LP64 # define CURL_TYPEOF_CURL_OFF_T long long # define CURL_FORMAT_CURL_OFF_T "lld" # define CURL_FORMAT_CURL_OFF_TU "llu" @@ -336,8 +336,11 @@ # define CURL_FORMAT_CURL_OFF_TU "llu" # define CURL_SUFFIX_CURL_OFF_T LL # define CURL_SUFFIX_CURL_OFF_TU ULL -# define CURL_POPCOUNT64(x) __builtin_popcountll(x) -# define CURL_CTZ64(x) __builtin_ctzll(x) +# if (__GNUC__ >= 4) || \ + ((__GNUC__ == 3) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 4)) +# define CURL_POPCOUNT64(x) __builtin_popcountll(x) +# define CURL_CTZ64(x) __builtin_ctzll(x) +# endif # elif defined(__LP64__) || \ defined(__x86_64__) || defined(__ppc64__) || defined(__sparc64__) || \ defined(__e2k__) || \ @@ -348,8 +351,11 @@ # define CURL_FORMAT_CURL_OFF_TU "lu" # define CURL_SUFFIX_CURL_OFF_T L # define CURL_SUFFIX_CURL_OFF_TU UL -# define CURL_POPCOUNT64(x) __builtin_popcountl(x) -# define CURL_CTZ64(x) __builtin_ctzl(x) +# if (__GNUC__ >= 4) || \ + ((__GNUC__ == 3) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 4)) +# define CURL_POPCOUNT64(x) __builtin_popcountl(x) +# define CURL_CTZ64(x) __builtin_ctzl(x) +# endif # endif # define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t # define CURL_PULL_SYS_TYPES_H 1 diff --git a/deps/curl/include/curl/typecheck-gcc.h b/deps/curl/include/curl/typecheck-gcc.h index ca0c0ef9d69..a0b41aeb247 100644 --- a/deps/curl/include/curl/typecheck-gcc.h +++ b/deps/curl/include/curl/typecheck-gcc.h @@ -135,7 +135,7 @@ _curl_easy_setopt_err_error_buffer(); \ if((option) == CURLOPT_CURLU) \ if(!curlcheck_ptr((value), CURLU)) \ - _curl_easy_setopt_err_curlu(); \ + _curl_easy_setopt_err_curlu(); \ if((option) == CURLOPT_STDERR) \ if(!curlcheck_FILE(value)) \ _curl_easy_setopt_err_FILE(); \ @@ -178,7 +178,7 @@ _curl_easy_getinfo_err_curl_slist(); \ if(curlcheck_tlssessioninfo_info(info)) \ if(!curlcheck_arr((arg), struct curl_tlssessioninfo *)) \ - _curl_easy_getinfo_err_curl_tlssessioninfo(); \ + _curl_easy_getinfo_err_curl_tlssessioninfo(); \ if(curlcheck_certinfo_info(info)) \ if(!curlcheck_arr((arg), struct curl_certinfo *)) \ _curl_easy_getinfo_err_curl_certinfo(); \ @@ -193,11 +193,68 @@ curl_easy_getinfo(handle, info, arg); \ }) +#define curl_multi_setopt(handle, option, value) \ + __extension__({ \ + if(__builtin_constant_p(option)) { \ + if(curlcheck_long_option(option)) \ + if(!curlcheck_long(value)) \ + _curl_multi_setopt_err_long(); \ + if(curlcheck_off_t_option(option)) \ + if(!curlcheck_off_t(value)) \ + _curl_multi_setopt_err_curl_off_t(); \ + if(curlcheck_multicb_data_option(option)) \ + if(!curlcheck_cb_data(value)) \ + _curl_multi_setopt_err_cb_data(); \ + if(curlcheck_charpp_option(option)) \ + if(!curlcheck_ptrptr(value, char)) \ + _curl_multi_setopt_err_charpp(); \ + if((option) == CURLMOPT_PUSHFUNCTION) \ + if(!curlcheck_multipush_cb(value)) \ + _curl_multi_setopt_err_pushcb(); \ + if((option) == CURLMOPT_SOCKETFUNCTION) \ + if(!curlcheck_multisocket_cb(value)) \ + _curl_multi_setopt_err_socketcb(); \ + if((option) == CURLMOPT_TIMERFUNCTION) \ + if(!curlcheck_multitimer_cb(value)) \ + _curl_multi_setopt_err_timercb(); \ + } \ + curl_multi_setopt(handle, option, value); \ + }) + +/* evaluates to true if the option takes a data argument to pass to a + callback */ +#define curlcheck_multicb_data_option(option) \ + ((option) == CURLMOPT_PUSHDATA || \ + (option) == CURLMOPT_SOCKETDATA || \ + (option) == CURLMOPT_TIMERDATA || \ + 0) + +/* evaluates to true if the option takes a char ** argument */ +#define curlcheck_charpp_option(option) \ + ((option) == CURLMOPT_PIPELINING_SERVER_BL || \ + (option) == CURLMOPT_PIPELINING_SITE_BL || \ + 0) + +/* evaluates to true if expr is of type curl_multi_timer_callback */ +#define curlcheck_multitimer_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_multi_timer_callback)) + +/* evaluates to true if expr is of type curl_socket_callback */ +#define curlcheck_multisocket_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_socket_callback)) + +/* evaluates to true if expr is of type curl_push_callback */ +#define curlcheck_multipush_cb(expr) \ + (curlcheck_NULL(expr) || \ + curlcheck_cb_compatible((expr), curl_push_callback)) + /* * For now, just make sure that the functions are called with three arguments */ #define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param) -#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param) + /* the actual warnings, triggered by calling the _curl_easy_setopt_err* * functions */ @@ -208,6 +265,21 @@ __attribute__((__unused__)) __attribute__((__noinline__)) \ id(void) { __asm__(""); } +CURLWARNING(_curl_multi_setopt_err_long, + "curl_multi_setopt expects a long argument") +CURLWARNING(_curl_multi_setopt_err_curl_off_t, + "curl_multi_setopt expects a curl_off_t argument") +CURLWARNING(_curl_multi_setopt_err_cb_data, + "curl_multi_setopt expects a 'void *' argument") +CURLWARNING(_curl_multi_setopt_err_charpp, + "curl_multi_setopt expects a 'char **' argument") +CURLWARNING(_curl_multi_setopt_err_pushcb, + "curl_multi_setopt expects a curl_push_callback argument") +CURLWARNING(_curl_multi_setopt_err_socketcb, + "curl_multi_setopt expects a curl_socket_callback argument") +CURLWARNING(_curl_multi_setopt_err_timercb, + "curl_multi_setopt expects a curl_multi_timer_callback argument") + CURLWARNING(_curl_easy_setopt_err_long, "curl_easy_setopt expects a long argument") CURLWARNING(_curl_easy_setopt_err_curl_off_t, @@ -534,6 +606,14 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, __builtin_types_compatible_p(__typeof__(expr), type *) || \ __builtin_types_compatible_p(__typeof__(expr), const type *)) +/* evaluates to true if expr is type**, const type** or NULL */ +#define curlcheck_ptrptr(expr, type) \ + (curlcheck_NULL(expr) || \ + __builtin_types_compatible_p(__typeof__(expr), type **) || \ + __builtin_types_compatible_p(__typeof__(expr), type *[]) || \ + __builtin_types_compatible_p(__typeof__(expr), const type *[]) || \ + __builtin_types_compatible_p(__typeof__(expr), const type **)) + /* evaluates to true if expr is one of type[], type*, NULL or const type* */ #define curlcheck_arr(expr, type) \ (curlcheck_ptr((expr), type) || \ @@ -546,7 +626,7 @@ CURLWARNING(_curl_easy_getinfo_err_curl_off_t, curlcheck_arr((expr), unsigned char)) /* evaluates to true if expr is a CURL * */ -#define curlcheck_curl(expr) \ +#define curlcheck_curl(expr) \ (curlcheck_NULL(expr) || \ __builtin_types_compatible_p(__typeof__(expr), CURL *)) @@ -840,8 +920,8 @@ typedef long (*_curl_chunk_bgn_callback2)(void *, void *, int); curlcheck_cb_compatible((expr), curl_sshhostkeycallback)) /* evaluates to true if expr is of type curl_sshkeycallback */ -#define curlcheck_ssh_key_cb(expr) \ - (curlcheck_NULL(expr) || \ +#define curlcheck_ssh_key_cb(expr) \ + (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_sshkeycallback)) /* evaluates to true if expr is of type curl_interleave_callback */ @@ -855,13 +935,13 @@ typedef size_t (*_curl_interleave_callback2)(char *p, size_t s, size_t n, void *u); /* evaluates to true if expr is of type curl_prereq_callback */ -#define curlcheck_prereq_cb(expr) \ - (curlcheck_NULL(expr) || \ +#define curlcheck_prereq_cb(expr) \ + (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_prereq_callback)) /* evaluates to true if expr is of type curl_trailer_callback */ -#define curlcheck_trailer_cb(expr) \ - (curlcheck_NULL(expr) || \ +#define curlcheck_trailer_cb(expr) \ + (curlcheck_NULL(expr) || \ curlcheck_cb_compatible((expr), curl_trailer_callback)) #endif /* CURLINC_TYPECHECK_GCC_H */ diff --git a/deps/curl/include/curl/urlapi.h b/deps/curl/include/curl/urlapi.h index b4a6e5d5670..34c11a6bb7f 100644 --- a/deps/curl/include/curl/urlapi.h +++ b/deps/curl/include/curl/urlapi.h @@ -26,7 +26,7 @@ #include "curl.h" -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif diff --git a/deps/curl/include/curl/websockets.h b/deps/curl/include/curl/websockets.h index afb86b4ebcf..df8590f399d 100644 --- a/deps/curl/include/curl/websockets.h +++ b/deps/curl/include/curl/websockets.h @@ -24,7 +24,7 @@ * ***************************************************************************/ -#ifdef __cplusplus +#ifdef __cplusplus extern "C" { #endif @@ -72,13 +72,26 @@ CURL_EXTERN CURLcode curl_ws_send(CURL *curl, const void *buffer, curl_off_t fragsize, unsigned int flags); +/* + * NAME curl_ws_start_frame() + * + * DESCRIPTION + * + * Buffers a websocket frame header with the given flags and length. + * Errors when a previous frame is not complete, e.g. not all its + * payload has been added. + */ +CURL_EXTERN CURLcode curl_ws_start_frame(CURL *curl, + unsigned int flags, + curl_off_t frame_len); + /* bits for the CURLOPT_WS_OPTIONS bitmask: */ -#define CURLWS_RAW_MODE (1<<0) -#define CURLWS_NOAUTOPONG (1<<1) +#define CURLWS_RAW_MODE (1L<<0) +#define CURLWS_NOAUTOPONG (1L<<1) CURL_EXTERN const struct curl_ws_frame *curl_ws_meta(CURL *curl); -#ifdef __cplusplus +#ifdef __cplusplus } #endif diff --git a/deps/curl/lib/CMakeLists.txt b/deps/curl/lib/CMakeLists.txt index 9b0fda54092..3476d55b096 100644 --- a/deps/curl/lib/CMakeLists.txt +++ b/deps/curl/lib/CMakeLists.txt @@ -24,8 +24,7 @@ set(LIBCURL_OUTPUT_NAME "${LIB_NAME}" CACHE STRING "Basename of the curl library") -set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "BUILDING_LIBCURL") -set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS "${CURL_DEBUG_MACROS}") +set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS ${CURL_DEBUG_MACROS} "BUILDING_LIBCURL") configure_file("curl_config.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/curl_config.h") @@ -56,7 +55,7 @@ if(CURL_BUILD_TESTING) ${CSOURCES} > "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h" DEPENDS "${PROJECT_SOURCE_DIR}/scripts/extract-unit-protos" ${CSOURCES} VERBATIM) - add_custom_target(curlu-unitprotos ALL DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h") + add_custom_target(curlu-unitprotos DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/unitprotos.h") endif() ## Library definition @@ -156,11 +155,11 @@ if(BUILD_STATIC_LIBS) endif() if(CURL_HAS_LTO) if(CMAKE_CONFIGURATION_TYPES) - set_target_properties(${LIB_OBJECT} PROPERTIES + set_target_properties(${LIB_STATIC} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) else() - set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) + set_target_properties(${LIB_STATIC} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() @@ -192,11 +191,11 @@ if(BUILD_SHARED_LIBS) endif() if(CURL_HAS_LTO) if(CMAKE_CONFIGURATION_TYPES) - set_target_properties(${LIB_OBJECT} PROPERTIES + set_target_properties(${LIB_SHARED} PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO TRUE) else() - set_target_properties(${LIB_OBJECT} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) + set_target_properties(${LIB_SHARED} PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE) endif() endif() diff --git a/deps/curl/lib/Makefile.am b/deps/curl/lib/Makefile.am index 75fbbdf4b93..973876f5010 100644 --- a/deps/curl/lib/Makefile.am +++ b/deps/curl/lib/Makefile.am @@ -66,7 +66,6 @@ AM_CPPFLAGS = -I$(top_srcdir)/include \ # Prevent LIBS from being used for all link targets LIBS = $(BLANK_AT_MAKETIME) -AM_CPPFLAGS += -DBUILDING_LIBCURL AM_LDFLAGS = AM_CFLAGS = if DEBUGBUILD @@ -75,6 +74,7 @@ endif if CURLDEBUG AM_CPPFLAGS += -DCURLDEBUG endif +AM_CPPFLAGS += -DBUILDING_LIBCURL if DOING_NATIVE_WINDOWS CSOURCES += dllmain.c @@ -162,7 +162,7 @@ CHECKSOURCES = checksrc endif endif -all-local: $(CHECKSOURCES) $(UNITPROTOS) +all-local: $(CHECKSOURCES) UNIT_V = $(UNITV_$(V)) UNITV_0 = @echo " UNITPR " $@; @@ -174,7 +174,7 @@ $(UNITPROTOS): $(CSOURCES) $(UNIT_V)(cd $(srcdir) && @PERL@ ../scripts/extract-unit-protos $(CSOURCES) > $(top_builddir)/lib/$(UNITPROTOS)) # disable the tests that are mostly causing false positives -TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -quiet +TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling -quiet if CURL_WERROR TIDYFLAGS += --warnings-as-errors=* endif diff --git a/deps/curl/lib/Makefile.in b/deps/curl/lib/Makefile.in index 1ac27c85f10..a7f8065d96b 100644 --- a/deps/curl/lib/Makefile.in +++ b/deps/curl/lib/Makefile.in @@ -218,29 +218,29 @@ LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) libcurl_la_LIBADD = am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \ asyn-base.c asyn-thrdd.c bufq.c bufref.c cf-h1-proxy.c \ - cf-h2-proxy.c cf-haproxy.c cf-https-connect.c cf-socket.c \ - cfilters.c conncache.c connect.c content_encoding.c cookie.c \ - cshutdn.c curl_addrinfo.c curl_des.c curl_endian.c \ - curl_fnmatch.c curl_get_line.c curl_gethostname.c \ - curl_gssapi.c curl_memrchr.c curl_ntlm_core.c curl_range.c \ - curl_rtmp.c curl_sasl.c curl_sha512_256.c curl_sspi.c \ - curl_threads.c curl_trc.c cw-out.c cw-pause.c dict.c doh.c \ - dynhds.c easy.c easygetopt.c easyoptions.c escape.c \ - fake_addrinfo.c file.c fileinfo.c fopen.c formdata.c ftp.c \ - ftplistparser.c getenv.c getinfo.c gopher.c hash.c headers.c \ - hmac.c hostip.c hostip4.c hostip6.c hsts.c http.c http1.c \ - http2.c http_aws_sigv4.c http_chunks.c http_digest.c \ - http_negotiate.c http_ntlm.c http_proxy.c httpsrr.c idn.c \ - if2ip.c imap.c krb5.c ldap.c llist.c macos.c md4.c md5.c \ - memdebug.c mime.c mprintf.c mqtt.c multi.c multi_ev.c netrc.c \ - noproxy.c openldap.c parsedate.c pingpong.c pop3.c progress.c \ - psl.c rand.c rename.c request.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 strequal.c strerror.c system_win32.c \ - telnet.c tftp.c transfer.c uint-bset.c uint-hash.c \ - uint-spbset.c uint-table.c url.c urlapi.c version.c ws.c \ - vauth/cleartext.c vauth/cram.c vauth/digest.c \ + cf-h2-proxy.c cf-haproxy.c cf-https-connect.c cf-ip-happy.c \ + cf-socket.c cfilters.c conncache.c connect.c \ + content_encoding.c cookie.c cshutdn.c curl_addrinfo.c \ + curl_des.c curl_endian.c curl_fnmatch.c curl_get_line.c \ + curl_gethostname.c curl_gssapi.c curl_memrchr.c \ + curl_ntlm_core.c curl_range.c curl_rtmp.c curl_sasl.c \ + curl_sha512_256.c curl_sspi.c curl_threads.c curl_trc.c \ + cw-out.c cw-pause.c dict.c doh.c dynhds.c easy.c easygetopt.c \ + easyoptions.c escape.c fake_addrinfo.c file.c fileinfo.c \ + fopen.c formdata.c ftp.c ftplistparser.c getenv.c getinfo.c \ + gopher.c hash.c headers.c hmac.c hostip.c hostip4.c hostip6.c \ + hsts.c http.c http1.c http2.c http_aws_sigv4.c http_chunks.c \ + http_digest.c http_negotiate.c http_ntlm.c http_proxy.c \ + httpsrr.c idn.c if2ip.c imap.c krb5.c ldap.c llist.c macos.c \ + md4.c md5.c memdebug.c mime.c mprintf.c mqtt.c multi.c \ + multi_ev.c netrc.c noproxy.c openldap.c parsedate.c pingpong.c \ + pop3.c progress.c psl.c rand.c rename.c request.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 strequal.c strerror.c \ + system_win32.c telnet.c tftp.c transfer.c uint-bset.c \ + uint-hash.c uint-spbset.c uint-table.c url.c urlapi.c \ + version.c ws.c vauth/cleartext.c vauth/cram.c vauth/digest.c \ vauth/digest_sspi.c vauth/gsasl.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 \ @@ -249,27 +249,27 @@ am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \ vtls/openssl.c vtls/rustls.c vtls/schannel.c \ vtls/schannel_verify.c vtls/vtls.c vtls/vtls_scache.c \ vtls/vtls_spack.c vtls/wolfssl.c vtls/x509asn1.c \ - vquic/curl_msh3.c vquic/curl_ngtcp2.c vquic/curl_osslq.c \ - vquic/curl_quiche.c vquic/vquic.c vquic/vquic-tls.c \ - vssh/libssh.c vssh/libssh2.c vssh/curl_path.c vssh/wolfssh.c \ - curlx/base64.c curlx/dynbuf.c curlx/inet_ntop.c \ - curlx/inet_pton.c curlx/multibyte.c curlx/nonblock.c \ - curlx/strparse.c curlx/timediff.c curlx/timeval.c \ - curlx/version_win32.c curlx/wait.c curlx/warnless.c \ - curlx/winapi.c dllmain.c altsvc.h amigaos.h arpa_telnet.h \ - asyn.h bufq.h bufref.h cf-h1-proxy.h cf-h2-proxy.h \ - cf-haproxy.h cf-https-connect.h cf-socket.h cfilters.h \ - conncache.h cshutdn.h connect.h content_encoding.h cookie.h \ - curl_addrinfo.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_ntlm_core.h \ - curl_printf.h curl_range.h curl_rtmp.h curl_sasl.h \ - curl_setup.h curl_setup_once.h curl_sha256.h curl_sha512_256.h \ - curl_sspi.h curl_threads.h curl_trc.h cw-out.h cw-pause.h \ - dict.h doh.h dynhds.h easy_lock.h easyif.h easyoptions.h \ - escape.h fake_addrinfo.h file.h fileinfo.h fopen.h formdata.h \ - ftp.h ftplistparser.h functypes.h getinfo.h gopher.h hash.h \ + vquic/curl_ngtcp2.c vquic/curl_osslq.c vquic/curl_quiche.c \ + vquic/vquic.c vquic/vquic-tls.c vssh/libssh.c vssh/libssh2.c \ + vssh/curl_path.c vssh/wolfssh.c curlx/base64.c curlx/dynbuf.c \ + curlx/inet_ntop.c curlx/inet_pton.c curlx/multibyte.c \ + curlx/nonblock.c curlx/strparse.c curlx/timediff.c \ + curlx/timeval.c curlx/version_win32.c curlx/wait.c \ + curlx/warnless.c curlx/winapi.c dllmain.c altsvc.h amigaos.h \ + arpa_telnet.h asyn.h bufq.h bufref.h cf-h1-proxy.h \ + cf-h2-proxy.h cf-haproxy.h cf-https-connect.h cf-ip-happy.h \ + cf-socket.h cfilters.h conncache.h cshutdn.h connect.h \ + content_encoding.h cookie.h curl_addrinfo.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_mem_undef.h \ + curl_memory.h curl_memrchr.h curl_ntlm_core.h curl_printf.h \ + curl_range.h curl_rtmp.h curl_sasl.h curl_setup.h \ + curl_setup_once.h curl_sha256.h curl_sha512_256.h curl_sspi.h \ + curl_threads.h curl_trc.h cw-out.h cw-pause.h dict.h doh.h \ + dynhds.h easy_lock.h easyif.h easyoptions.h escape.h \ + fake_addrinfo.h file.h fileinfo.h fopen.h formdata.h ftp.h \ + ftplistparser.h functypes.h getinfo.h gopher.h hash.h \ headers.h hostip.h hsts.h http.h http1.h http2.h \ http_aws_sigv4.h http_chunks.h http_digest.h http_negotiate.h \ http_ntlm.h http_proxy.h httpsrr.h idn.h if2ip.h imap.h \ @@ -286,34 +286,34 @@ am__libcurl_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \ vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/openssl.h \ vtls/rustls.h vtls/schannel.h vtls/schannel_int.h vtls/vtls.h \ vtls/vtls_int.h vtls/vtls_scache.h vtls/vtls_spack.h \ - vtls/wolfssl.h vtls/x509asn1.h vquic/curl_msh3.h \ - vquic/curl_ngtcp2.h vquic/curl_osslq.h vquic/curl_quiche.h \ - vquic/vquic.h vquic/vquic_int.h vquic/vquic-tls.h \ - vssh/curl_path.h vssh/ssh.h curlx/binmode.h curlx/base64.h \ - curlx/curlx.h curlx/dynbuf.h curlx/inet_ntop.h \ - curlx/inet_pton.h curlx/multibyte.h curlx/nonblock.h \ - curlx/strparse.h curlx/timediff.h curlx/timeval.h \ - curlx/version_win32.h curlx/wait.h curlx/warnless.h \ - curlx/winapi.h libcurl.rc + vtls/wolfssl.h vtls/x509asn1.h vquic/curl_ngtcp2.h \ + vquic/curl_osslq.h vquic/curl_quiche.h vquic/vquic.h \ + vquic/vquic_int.h vquic/vquic-tls.h vssh/curl_path.h \ + vssh/ssh.h curlx/binmode.h curlx/base64.h curlx/curlx.h \ + curlx/dynbuf.h curlx/inet_ntop.h curlx/inet_pton.h \ + curlx/multibyte.h curlx/nonblock.h curlx/strparse.h \ + curlx/timediff.h curlx/timeval.h curlx/version_win32.h \ + curlx/wait.h curlx/warnless.h curlx/winapi.h libcurl.rc am__objects_1 = libcurl_la-altsvc.lo libcurl_la-amigaos.lo \ libcurl_la-asyn-ares.lo libcurl_la-asyn-base.lo \ libcurl_la-asyn-thrdd.lo libcurl_la-bufq.lo \ libcurl_la-bufref.lo libcurl_la-cf-h1-proxy.lo \ libcurl_la-cf-h2-proxy.lo libcurl_la-cf-haproxy.lo \ - libcurl_la-cf-https-connect.lo libcurl_la-cf-socket.lo \ - libcurl_la-cfilters.lo libcurl_la-conncache.lo \ - libcurl_la-connect.lo libcurl_la-content_encoding.lo \ - libcurl_la-cookie.lo libcurl_la-cshutdn.lo \ - libcurl_la-curl_addrinfo.lo libcurl_la-curl_des.lo \ - libcurl_la-curl_endian.lo libcurl_la-curl_fnmatch.lo \ - libcurl_la-curl_get_line.lo libcurl_la-curl_gethostname.lo \ - libcurl_la-curl_gssapi.lo libcurl_la-curl_memrchr.lo \ - libcurl_la-curl_ntlm_core.lo libcurl_la-curl_range.lo \ - libcurl_la-curl_rtmp.lo libcurl_la-curl_sasl.lo \ - libcurl_la-curl_sha512_256.lo libcurl_la-curl_sspi.lo \ - libcurl_la-curl_threads.lo libcurl_la-curl_trc.lo \ - libcurl_la-cw-out.lo libcurl_la-cw-pause.lo libcurl_la-dict.lo \ - libcurl_la-doh.lo libcurl_la-dynhds.lo libcurl_la-easy.lo \ + libcurl_la-cf-https-connect.lo libcurl_la-cf-ip-happy.lo \ + libcurl_la-cf-socket.lo libcurl_la-cfilters.lo \ + libcurl_la-conncache.lo libcurl_la-connect.lo \ + libcurl_la-content_encoding.lo libcurl_la-cookie.lo \ + libcurl_la-cshutdn.lo libcurl_la-curl_addrinfo.lo \ + libcurl_la-curl_des.lo libcurl_la-curl_endian.lo \ + libcurl_la-curl_fnmatch.lo libcurl_la-curl_get_line.lo \ + libcurl_la-curl_gethostname.lo libcurl_la-curl_gssapi.lo \ + libcurl_la-curl_memrchr.lo libcurl_la-curl_ntlm_core.lo \ + libcurl_la-curl_range.lo libcurl_la-curl_rtmp.lo \ + libcurl_la-curl_sasl.lo libcurl_la-curl_sha512_256.lo \ + libcurl_la-curl_sspi.lo libcurl_la-curl_threads.lo \ + libcurl_la-curl_trc.lo libcurl_la-cw-out.lo \ + libcurl_la-cw-pause.lo libcurl_la-dict.lo libcurl_la-doh.lo \ + libcurl_la-dynhds.lo libcurl_la-easy.lo \ libcurl_la-easygetopt.lo libcurl_la-easyoptions.lo \ libcurl_la-escape.lo libcurl_la-fake_addrinfo.lo \ libcurl_la-file.lo libcurl_la-fileinfo.lo libcurl_la-fopen.lo \ @@ -367,10 +367,9 @@ am__objects_3 = vtls/libcurl_la-cipher_suite.lo \ vtls/libcurl_la-vtls.lo vtls/libcurl_la-vtls_scache.lo \ vtls/libcurl_la-vtls_spack.lo vtls/libcurl_la-wolfssl.lo \ vtls/libcurl_la-x509asn1.lo -am__objects_4 = vquic/libcurl_la-curl_msh3.lo \ - vquic/libcurl_la-curl_ngtcp2.lo vquic/libcurl_la-curl_osslq.lo \ - vquic/libcurl_la-curl_quiche.lo vquic/libcurl_la-vquic.lo \ - vquic/libcurl_la-vquic-tls.lo +am__objects_4 = vquic/libcurl_la-curl_ngtcp2.lo \ + vquic/libcurl_la-curl_osslq.lo vquic/libcurl_la-curl_quiche.lo \ + vquic/libcurl_la-vquic.lo vquic/libcurl_la-vquic-tls.lo am__objects_5 = vssh/libcurl_la-libssh.lo vssh/libcurl_la-libssh2.lo \ vssh/libcurl_la-curl_path.lo vssh/libcurl_la-wolfssh.lo am__objects_6 = curlx/libcurl_la-base64.lo curlx/libcurl_la-dynbuf.lo \ @@ -406,29 +405,29 @@ libcurl_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ libcurlu_la_LIBADD = am__libcurlu_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \ asyn-base.c asyn-thrdd.c bufq.c bufref.c cf-h1-proxy.c \ - cf-h2-proxy.c cf-haproxy.c cf-https-connect.c cf-socket.c \ - cfilters.c conncache.c connect.c content_encoding.c cookie.c \ - cshutdn.c curl_addrinfo.c curl_des.c curl_endian.c \ - curl_fnmatch.c curl_get_line.c curl_gethostname.c \ - curl_gssapi.c curl_memrchr.c curl_ntlm_core.c curl_range.c \ - curl_rtmp.c curl_sasl.c curl_sha512_256.c curl_sspi.c \ - curl_threads.c curl_trc.c cw-out.c cw-pause.c dict.c doh.c \ - dynhds.c easy.c easygetopt.c easyoptions.c escape.c \ - fake_addrinfo.c file.c fileinfo.c fopen.c formdata.c ftp.c \ - ftplistparser.c getenv.c getinfo.c gopher.c hash.c headers.c \ - hmac.c hostip.c hostip4.c hostip6.c hsts.c http.c http1.c \ - http2.c http_aws_sigv4.c http_chunks.c http_digest.c \ - http_negotiate.c http_ntlm.c http_proxy.c httpsrr.c idn.c \ - if2ip.c imap.c krb5.c ldap.c llist.c macos.c md4.c md5.c \ - memdebug.c mime.c mprintf.c mqtt.c multi.c multi_ev.c netrc.c \ - noproxy.c openldap.c parsedate.c pingpong.c pop3.c progress.c \ - psl.c rand.c rename.c request.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 strequal.c strerror.c system_win32.c \ - telnet.c tftp.c transfer.c uint-bset.c uint-hash.c \ - uint-spbset.c uint-table.c url.c urlapi.c version.c ws.c \ - vauth/cleartext.c vauth/cram.c vauth/digest.c \ + cf-h2-proxy.c cf-haproxy.c cf-https-connect.c cf-ip-happy.c \ + cf-socket.c cfilters.c conncache.c connect.c \ + content_encoding.c cookie.c cshutdn.c curl_addrinfo.c \ + curl_des.c curl_endian.c curl_fnmatch.c curl_get_line.c \ + curl_gethostname.c curl_gssapi.c curl_memrchr.c \ + curl_ntlm_core.c curl_range.c curl_rtmp.c curl_sasl.c \ + curl_sha512_256.c curl_sspi.c curl_threads.c curl_trc.c \ + cw-out.c cw-pause.c dict.c doh.c dynhds.c easy.c easygetopt.c \ + easyoptions.c escape.c fake_addrinfo.c file.c fileinfo.c \ + fopen.c formdata.c ftp.c ftplistparser.c getenv.c getinfo.c \ + gopher.c hash.c headers.c hmac.c hostip.c hostip4.c hostip6.c \ + hsts.c http.c http1.c http2.c http_aws_sigv4.c http_chunks.c \ + http_digest.c http_negotiate.c http_ntlm.c http_proxy.c \ + httpsrr.c idn.c if2ip.c imap.c krb5.c ldap.c llist.c macos.c \ + md4.c md5.c memdebug.c mime.c mprintf.c mqtt.c multi.c \ + multi_ev.c netrc.c noproxy.c openldap.c parsedate.c pingpong.c \ + pop3.c progress.c psl.c rand.c rename.c request.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 strequal.c strerror.c \ + system_win32.c telnet.c tftp.c transfer.c uint-bset.c \ + uint-hash.c uint-spbset.c uint-table.c url.c urlapi.c \ + version.c ws.c vauth/cleartext.c vauth/cram.c vauth/digest.c \ vauth/digest_sspi.c vauth/gsasl.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 \ @@ -437,27 +436,27 @@ am__libcurlu_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \ vtls/openssl.c vtls/rustls.c vtls/schannel.c \ vtls/schannel_verify.c vtls/vtls.c vtls/vtls_scache.c \ vtls/vtls_spack.c vtls/wolfssl.c vtls/x509asn1.c \ - vquic/curl_msh3.c vquic/curl_ngtcp2.c vquic/curl_osslq.c \ - vquic/curl_quiche.c vquic/vquic.c vquic/vquic-tls.c \ - vssh/libssh.c vssh/libssh2.c vssh/curl_path.c vssh/wolfssh.c \ - curlx/base64.c curlx/dynbuf.c curlx/inet_ntop.c \ - curlx/inet_pton.c curlx/multibyte.c curlx/nonblock.c \ - curlx/strparse.c curlx/timediff.c curlx/timeval.c \ - curlx/version_win32.c curlx/wait.c curlx/warnless.c \ - curlx/winapi.c dllmain.c altsvc.h amigaos.h arpa_telnet.h \ - asyn.h bufq.h bufref.h cf-h1-proxy.h cf-h2-proxy.h \ - cf-haproxy.h cf-https-connect.h cf-socket.h cfilters.h \ - conncache.h cshutdn.h connect.h content_encoding.h cookie.h \ - curl_addrinfo.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_ntlm_core.h \ - curl_printf.h curl_range.h curl_rtmp.h curl_sasl.h \ - curl_setup.h curl_setup_once.h curl_sha256.h curl_sha512_256.h \ - curl_sspi.h curl_threads.h curl_trc.h cw-out.h cw-pause.h \ - dict.h doh.h dynhds.h easy_lock.h easyif.h easyoptions.h \ - escape.h fake_addrinfo.h file.h fileinfo.h fopen.h formdata.h \ - ftp.h ftplistparser.h functypes.h getinfo.h gopher.h hash.h \ + vquic/curl_ngtcp2.c vquic/curl_osslq.c vquic/curl_quiche.c \ + vquic/vquic.c vquic/vquic-tls.c vssh/libssh.c vssh/libssh2.c \ + vssh/curl_path.c vssh/wolfssh.c curlx/base64.c curlx/dynbuf.c \ + curlx/inet_ntop.c curlx/inet_pton.c curlx/multibyte.c \ + curlx/nonblock.c curlx/strparse.c curlx/timediff.c \ + curlx/timeval.c curlx/version_win32.c curlx/wait.c \ + curlx/warnless.c curlx/winapi.c dllmain.c altsvc.h amigaos.h \ + arpa_telnet.h asyn.h bufq.h bufref.h cf-h1-proxy.h \ + cf-h2-proxy.h cf-haproxy.h cf-https-connect.h cf-ip-happy.h \ + cf-socket.h cfilters.h conncache.h cshutdn.h connect.h \ + content_encoding.h cookie.h curl_addrinfo.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_mem_undef.h \ + curl_memory.h curl_memrchr.h curl_ntlm_core.h curl_printf.h \ + curl_range.h curl_rtmp.h curl_sasl.h curl_setup.h \ + curl_setup_once.h curl_sha256.h curl_sha512_256.h curl_sspi.h \ + curl_threads.h curl_trc.h cw-out.h cw-pause.h dict.h doh.h \ + dynhds.h easy_lock.h easyif.h easyoptions.h escape.h \ + fake_addrinfo.h file.h fileinfo.h fopen.h formdata.h ftp.h \ + ftplistparser.h functypes.h getinfo.h gopher.h hash.h \ headers.h hostip.h hsts.h http.h http1.h http2.h \ http_aws_sigv4.h http_chunks.h http_digest.h http_negotiate.h \ http_ntlm.h http_proxy.h httpsrr.h idn.h if2ip.h imap.h \ @@ -474,42 +473,42 @@ am__libcurlu_la_SOURCES_DIST = altsvc.c amigaos.c asyn-ares.c \ vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/openssl.h \ vtls/rustls.h vtls/schannel.h vtls/schannel_int.h vtls/vtls.h \ vtls/vtls_int.h vtls/vtls_scache.h vtls/vtls_spack.h \ - vtls/wolfssl.h vtls/x509asn1.h vquic/curl_msh3.h \ - vquic/curl_ngtcp2.h vquic/curl_osslq.h vquic/curl_quiche.h \ - vquic/vquic.h vquic/vquic_int.h vquic/vquic-tls.h \ - vssh/curl_path.h vssh/ssh.h curlx/binmode.h curlx/base64.h \ - curlx/curlx.h curlx/dynbuf.h curlx/inet_ntop.h \ - curlx/inet_pton.h curlx/multibyte.h curlx/nonblock.h \ - curlx/strparse.h curlx/timediff.h curlx/timeval.h \ - curlx/version_win32.h curlx/wait.h curlx/warnless.h \ - curlx/winapi.h + vtls/wolfssl.h vtls/x509asn1.h vquic/curl_ngtcp2.h \ + vquic/curl_osslq.h vquic/curl_quiche.h vquic/vquic.h \ + vquic/vquic_int.h vquic/vquic-tls.h vssh/curl_path.h \ + vssh/ssh.h curlx/binmode.h curlx/base64.h curlx/curlx.h \ + curlx/dynbuf.h curlx/inet_ntop.h curlx/inet_pton.h \ + curlx/multibyte.h curlx/nonblock.h curlx/strparse.h \ + curlx/timediff.h curlx/timeval.h curlx/version_win32.h \ + curlx/wait.h curlx/warnless.h curlx/winapi.h am__objects_13 = libcurlu_la-altsvc.lo libcurlu_la-amigaos.lo \ libcurlu_la-asyn-ares.lo libcurlu_la-asyn-base.lo \ libcurlu_la-asyn-thrdd.lo libcurlu_la-bufq.lo \ libcurlu_la-bufref.lo libcurlu_la-cf-h1-proxy.lo \ libcurlu_la-cf-h2-proxy.lo libcurlu_la-cf-haproxy.lo \ - libcurlu_la-cf-https-connect.lo libcurlu_la-cf-socket.lo \ - libcurlu_la-cfilters.lo libcurlu_la-conncache.lo \ - libcurlu_la-connect.lo libcurlu_la-content_encoding.lo \ - libcurlu_la-cookie.lo libcurlu_la-cshutdn.lo \ - libcurlu_la-curl_addrinfo.lo libcurlu_la-curl_des.lo \ - libcurlu_la-curl_endian.lo libcurlu_la-curl_fnmatch.lo \ - libcurlu_la-curl_get_line.lo libcurlu_la-curl_gethostname.lo \ - libcurlu_la-curl_gssapi.lo libcurlu_la-curl_memrchr.lo \ - libcurlu_la-curl_ntlm_core.lo libcurlu_la-curl_range.lo \ - libcurlu_la-curl_rtmp.lo libcurlu_la-curl_sasl.lo \ - libcurlu_la-curl_sha512_256.lo libcurlu_la-curl_sspi.lo \ - libcurlu_la-curl_threads.lo libcurlu_la-curl_trc.lo \ - libcurlu_la-cw-out.lo libcurlu_la-cw-pause.lo \ - libcurlu_la-dict.lo libcurlu_la-doh.lo libcurlu_la-dynhds.lo \ - libcurlu_la-easy.lo libcurlu_la-easygetopt.lo \ - libcurlu_la-easyoptions.lo libcurlu_la-escape.lo \ - libcurlu_la-fake_addrinfo.lo libcurlu_la-file.lo \ - libcurlu_la-fileinfo.lo libcurlu_la-fopen.lo \ - libcurlu_la-formdata.lo libcurlu_la-ftp.lo \ - libcurlu_la-ftplistparser.lo libcurlu_la-getenv.lo \ - libcurlu_la-getinfo.lo libcurlu_la-gopher.lo \ - libcurlu_la-hash.lo libcurlu_la-headers.lo libcurlu_la-hmac.lo \ + libcurlu_la-cf-https-connect.lo libcurlu_la-cf-ip-happy.lo \ + libcurlu_la-cf-socket.lo libcurlu_la-cfilters.lo \ + libcurlu_la-conncache.lo libcurlu_la-connect.lo \ + libcurlu_la-content_encoding.lo libcurlu_la-cookie.lo \ + libcurlu_la-cshutdn.lo libcurlu_la-curl_addrinfo.lo \ + libcurlu_la-curl_des.lo libcurlu_la-curl_endian.lo \ + libcurlu_la-curl_fnmatch.lo libcurlu_la-curl_get_line.lo \ + libcurlu_la-curl_gethostname.lo libcurlu_la-curl_gssapi.lo \ + libcurlu_la-curl_memrchr.lo libcurlu_la-curl_ntlm_core.lo \ + libcurlu_la-curl_range.lo libcurlu_la-curl_rtmp.lo \ + libcurlu_la-curl_sasl.lo libcurlu_la-curl_sha512_256.lo \ + libcurlu_la-curl_sspi.lo libcurlu_la-curl_threads.lo \ + libcurlu_la-curl_trc.lo libcurlu_la-cw-out.lo \ + libcurlu_la-cw-pause.lo libcurlu_la-dict.lo libcurlu_la-doh.lo \ + libcurlu_la-dynhds.lo libcurlu_la-easy.lo \ + libcurlu_la-easygetopt.lo libcurlu_la-easyoptions.lo \ + libcurlu_la-escape.lo libcurlu_la-fake_addrinfo.lo \ + libcurlu_la-file.lo libcurlu_la-fileinfo.lo \ + libcurlu_la-fopen.lo libcurlu_la-formdata.lo \ + libcurlu_la-ftp.lo libcurlu_la-ftplistparser.lo \ + libcurlu_la-getenv.lo libcurlu_la-getinfo.lo \ + libcurlu_la-gopher.lo libcurlu_la-hash.lo \ + libcurlu_la-headers.lo libcurlu_la-hmac.lo \ libcurlu_la-hostip.lo libcurlu_la-hostip4.lo \ libcurlu_la-hostip6.lo libcurlu_la-hsts.lo libcurlu_la-http.lo \ libcurlu_la-http1.lo libcurlu_la-http2.lo \ @@ -558,8 +557,7 @@ am__objects_15 = vtls/libcurlu_la-cipher_suite.lo \ vtls/libcurlu_la-schannel_verify.lo vtls/libcurlu_la-vtls.lo \ vtls/libcurlu_la-vtls_scache.lo vtls/libcurlu_la-vtls_spack.lo \ vtls/libcurlu_la-wolfssl.lo vtls/libcurlu_la-x509asn1.lo -am__objects_16 = vquic/libcurlu_la-curl_msh3.lo \ - vquic/libcurlu_la-curl_ngtcp2.lo \ +am__objects_16 = vquic/libcurlu_la-curl_ngtcp2.lo \ vquic/libcurlu_la-curl_osslq.lo \ vquic/libcurlu_la-curl_quiche.lo vquic/libcurlu_la-vquic.lo \ vquic/libcurlu_la-vquic-tls.lo @@ -613,6 +611,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ ./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo \ ./$(DEPDIR)/libcurl_la-cf-haproxy.Plo \ ./$(DEPDIR)/libcurl_la-cf-https-connect.Plo \ + ./$(DEPDIR)/libcurl_la-cf-ip-happy.Plo \ ./$(DEPDIR)/libcurl_la-cf-socket.Plo \ ./$(DEPDIR)/libcurl_la-cfilters.Plo \ ./$(DEPDIR)/libcurl_la-conncache.Plo \ @@ -739,6 +738,7 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ ./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo \ ./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo \ ./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo \ + ./$(DEPDIR)/libcurlu_la-cf-ip-happy.Plo \ ./$(DEPDIR)/libcurlu_la-cf-socket.Plo \ ./$(DEPDIR)/libcurlu_la-cfilters.Plo \ ./$(DEPDIR)/libcurlu_la-conncache.Plo \ @@ -909,13 +909,11 @@ am__depfiles_remade = ./$(DEPDIR)/libcurl_la-altsvc.Plo \ vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo \ vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo \ vauth/$(DEPDIR)/libcurlu_la-vauth.Plo \ - vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo \ vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo \ vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo \ vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo \ vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo \ vquic/$(DEPDIR)/libcurl_la-vquic.Plo \ - vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo \ vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo \ vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo \ vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo \ @@ -1042,6 +1040,7 @@ CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX = @CURL_LIBCURL_VERSIONED_SYMBOLS_PREFIX@ CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME = @CURL_LIBCURL_VERSIONED_SYMBOLS_SONAME@ CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@ CYGPATH_W = @CYGPATH_W@ +DANTED = @DANTED@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ DLLTOOL = @DLLTOOL@ @@ -1288,7 +1287,6 @@ LIB_VTLS_HFILES = \ vtls/x509asn1.h LIB_VQUIC_CFILES = \ - vquic/curl_msh3.c \ vquic/curl_ngtcp2.c \ vquic/curl_osslq.c \ vquic/curl_quiche.c \ @@ -1296,7 +1294,6 @@ LIB_VQUIC_CFILES = \ vquic/vquic-tls.c LIB_VQUIC_HFILES = \ - vquic/curl_msh3.h \ vquic/curl_ngtcp2.h \ vquic/curl_osslq.h \ vquic/curl_quiche.h \ @@ -1326,6 +1323,7 @@ LIB_CFILES = \ cf-h2-proxy.c \ cf-haproxy.c \ cf-https-connect.c \ + cf-ip-happy.c \ cf-socket.c \ cfilters.c \ conncache.c \ @@ -1454,6 +1452,7 @@ LIB_HFILES = \ cf-h2-proxy.h \ cf-haproxy.h \ cf-https-connect.h \ + cf-ip-happy.h \ cf-socket.h \ cfilters.h \ conncache.h \ @@ -1474,6 +1473,7 @@ LIB_HFILES = \ curl_ldap.h \ curl_md4.h \ curl_md5.h \ + curl_mem_undef.h \ curl_memory.h \ curl_memrchr.h \ curl_ntlm_core.h \ @@ -1608,7 +1608,7 @@ lib_LTLIBRARIES = libcurl.la # $(top_builddir)/lib is for libcurl's generated lib/curl_config.h file # $(srcdir) for the generated unity source to find included sources AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_builddir)/lib \ - -I$(srcdir) -DBUILDING_LIBCURL $(am__append_1) $(am__append_2) + -I$(srcdir) $(am__append_1) $(am__append_2) -DBUILDING_LIBCURL AM_LDFLAGS = AM_CFLAGS = @USE_UNITY_TRUE@nodist_libcurl_la_SOURCES = libcurl_unity.c @@ -1651,7 +1651,7 @@ UNITV_1 = UNITV_ = $(UNITV_0) # disable the tests that are mostly causing false positives -TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling \ +TIDYFLAGS := -checks=-clang-analyzer-security.insecureAPI.bzero,-clang-analyzer-security.insecureAPI.strcpy,-clang-analyzer-optin.performance.Padding,-clang-analyzer-security.ArrayBound,-clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling \ -quiet $(am__append_13) TIDY := clang-tidy all: curl_config.h @@ -1826,8 +1826,6 @@ vquic/$(am__dirstamp): vquic/$(DEPDIR)/$(am__dirstamp): @$(MKDIR_P) vquic/$(DEPDIR) @: > vquic/$(DEPDIR)/$(am__dirstamp) -vquic/libcurl_la-curl_msh3.lo: vquic/$(am__dirstamp) \ - vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurl_la-curl_ngtcp2.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurl_la-curl_osslq.lo: vquic/$(am__dirstamp) \ @@ -1943,8 +1941,6 @@ vtls/libcurlu_la-wolfssl.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) vtls/libcurlu_la-x509asn1.lo: vtls/$(am__dirstamp) \ vtls/$(DEPDIR)/$(am__dirstamp) -vquic/libcurlu_la-curl_msh3.lo: vquic/$(am__dirstamp) \ - vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurlu_la-curl_ngtcp2.lo: vquic/$(am__dirstamp) \ vquic/$(DEPDIR)/$(am__dirstamp) vquic/libcurlu_la-curl_osslq.lo: vquic/$(am__dirstamp) \ @@ -2020,6 +2016,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-haproxy.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-https-connect.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-ip-happy.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cf-socket.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-cfilters.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurl_la-conncache.Plo@am__quote@ # am--include-marker @@ -2149,6 +2146,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-ip-happy.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cf-socket.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-cfilters.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcurlu_la-conncache.Plo@am__quote@ # am--include-marker @@ -2319,13 +2317,11 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vauth/$(DEPDIR)/libcurlu_la-vauth.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurl_la-vquic.Plo@am__quote@ # am--include-marker -@AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo@am__quote@ # am--include-marker @AMDEP_TRUE@@am__include@ @am__quote@vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo@am__quote@ # am--include-marker @@ -2477,6 +2473,13 @@ libcurl_la-cf-https-connect.lo: cf-https-connect.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c +libcurl_la-cf-ip-happy.lo: cf-ip-happy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-ip-happy.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-ip-happy.Tpo -c -o libcurl_la-cf-ip-happy.lo `test -f 'cf-ip-happy.c' || echo '$(srcdir)/'`cf-ip-happy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-ip-happy.Tpo $(DEPDIR)/libcurl_la-cf-ip-happy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-ip-happy.c' object='libcurl_la-cf-ip-happy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o libcurl_la-cf-ip-happy.lo `test -f 'cf-ip-happy.c' || echo '$(srcdir)/'`cf-ip-happy.c + libcurl_la-cf-socket.lo: cf-socket.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT libcurl_la-cf-socket.lo -MD -MP -MF $(DEPDIR)/libcurl_la-cf-socket.Tpo -c -o libcurl_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurl_la-cf-socket.Tpo $(DEPDIR)/libcurl_la-cf-socket.Plo @@ -3485,13 +3488,6 @@ vtls/libcurl_la-x509asn1.lo: vtls/x509asn1.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurl_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c -vquic/libcurl_la-curl_msh3.lo: vquic/curl_msh3.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_msh3.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_msh3.Tpo -c -o vquic/libcurl_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_msh3.Tpo vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_msh3.c' object='vquic/libcurl_la-curl_msh3.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurl_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c - vquic/libcurl_la-curl_ngtcp2.lo: vquic/curl_ngtcp2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurl_la_CPPFLAGS) $(CPPFLAGS) $(libcurl_la_CFLAGS) $(CFLAGS) -MT vquic/libcurl_la-curl_ngtcp2.lo -MD -MP -MF vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Tpo -c -o vquic/libcurl_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Tpo vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo @@ -3737,6 +3733,13 @@ libcurlu_la-cf-https-connect.lo: cf-https-connect.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-https-connect.lo `test -f 'cf-https-connect.c' || echo '$(srcdir)/'`cf-https-connect.c +libcurlu_la-cf-ip-happy.lo: cf-ip-happy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-ip-happy.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-ip-happy.Tpo -c -o libcurlu_la-cf-ip-happy.lo `test -f 'cf-ip-happy.c' || echo '$(srcdir)/'`cf-ip-happy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-ip-happy.Tpo $(DEPDIR)/libcurlu_la-cf-ip-happy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cf-ip-happy.c' object='libcurlu_la-cf-ip-happy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o libcurlu_la-cf-ip-happy.lo `test -f 'cf-ip-happy.c' || echo '$(srcdir)/'`cf-ip-happy.c + libcurlu_la-cf-socket.lo: cf-socket.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT libcurlu_la-cf-socket.lo -MD -MP -MF $(DEPDIR)/libcurlu_la-cf-socket.Tpo -c -o libcurlu_la-cf-socket.lo `test -f 'cf-socket.c' || echo '$(srcdir)/'`cf-socket.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcurlu_la-cf-socket.Tpo $(DEPDIR)/libcurlu_la-cf-socket.Plo @@ -4745,13 +4748,6 @@ vtls/libcurlu_la-x509asn1.lo: vtls/x509asn1.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vtls/libcurlu_la-x509asn1.lo `test -f 'vtls/x509asn1.c' || echo '$(srcdir)/'`vtls/x509asn1.c -vquic/libcurlu_la-curl_msh3.lo: vquic/curl_msh3.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_msh3.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Tpo -c -o vquic/libcurlu_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='vquic/curl_msh3.c' object='vquic/libcurlu_la-curl_msh3.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -c -o vquic/libcurlu_la-curl_msh3.lo `test -f 'vquic/curl_msh3.c' || echo '$(srcdir)/'`vquic/curl_msh3.c - vquic/libcurlu_la-curl_ngtcp2.lo: vquic/curl_ngtcp2.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcurlu_la_CPPFLAGS) $(CPPFLAGS) $(libcurlu_la_CFLAGS) $(CFLAGS) -MT vquic/libcurlu_la-curl_ngtcp2.lo -MD -MP -MF vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Tpo -c -o vquic/libcurlu_la-curl_ngtcp2.lo `test -f 'vquic/curl_ngtcp2.c' || echo '$(srcdir)/'`vquic/curl_ngtcp2.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Tpo vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo @@ -5080,6 +5076,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo -rm -f ./$(DEPDIR)/libcurl_la-cf-haproxy.Plo -rm -f ./$(DEPDIR)/libcurl_la-cf-https-connect.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-ip-happy.Plo -rm -f ./$(DEPDIR)/libcurl_la-cf-socket.Plo -rm -f ./$(DEPDIR)/libcurl_la-cfilters.Plo -rm -f ./$(DEPDIR)/libcurl_la-conncache.Plo @@ -5209,6 +5206,7 @@ distclean: distclean-am -rm -f ./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo -rm -f ./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo -rm -f ./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-ip-happy.Plo -rm -f ./$(DEPDIR)/libcurlu_la-cf-socket.Plo -rm -f ./$(DEPDIR)/libcurlu_la-cfilters.Plo -rm -f ./$(DEPDIR)/libcurlu_la-conncache.Plo @@ -5379,13 +5377,11 @@ distclean: distclean-am -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo -rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo - -rm -f vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-vquic.Plo - -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo @@ -5485,6 +5481,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libcurl_la-cf-h2-proxy.Plo -rm -f ./$(DEPDIR)/libcurl_la-cf-haproxy.Plo -rm -f ./$(DEPDIR)/libcurl_la-cf-https-connect.Plo + -rm -f ./$(DEPDIR)/libcurl_la-cf-ip-happy.Plo -rm -f ./$(DEPDIR)/libcurl_la-cf-socket.Plo -rm -f ./$(DEPDIR)/libcurl_la-cfilters.Plo -rm -f ./$(DEPDIR)/libcurl_la-conncache.Plo @@ -5614,6 +5611,7 @@ maintainer-clean: maintainer-clean-am -rm -f ./$(DEPDIR)/libcurlu_la-cf-h2-proxy.Plo -rm -f ./$(DEPDIR)/libcurlu_la-cf-haproxy.Plo -rm -f ./$(DEPDIR)/libcurlu_la-cf-https-connect.Plo + -rm -f ./$(DEPDIR)/libcurlu_la-cf-ip-happy.Plo -rm -f ./$(DEPDIR)/libcurlu_la-cf-socket.Plo -rm -f ./$(DEPDIR)/libcurlu_la-cfilters.Plo -rm -f ./$(DEPDIR)/libcurlu_la-conncache.Plo @@ -5784,13 +5782,11 @@ maintainer-clean: maintainer-clean-am -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_gssapi.Plo -rm -f vauth/$(DEPDIR)/libcurlu_la-spnego_sspi.Plo -rm -f vauth/$(DEPDIR)/libcurlu_la-vauth.Plo - -rm -f vquic/$(DEPDIR)/libcurl_la-curl_msh3.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_ngtcp2.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_osslq.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-curl_quiche.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-vquic-tls.Plo -rm -f vquic/$(DEPDIR)/libcurl_la-vquic.Plo - -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_msh3.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_ngtcp2.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_osslq.Plo -rm -f vquic/$(DEPDIR)/libcurlu_la-curl_quiche.Plo @@ -5893,7 +5889,7 @@ checksrc: $(CHECKSRC)(@PERL@ $(top_srcdir)/scripts/checksrc.pl -D$(srcdir) \ $(CSOURCES) $(HHEADERS)) -all-local: $(CHECKSOURCES) $(UNITPROTOS) +all-local: $(CHECKSOURCES) # UNITPROTOS depends on every C file in the lib/ dir $(UNITPROTOS): $(CSOURCES) diff --git a/deps/curl/lib/Makefile.inc b/deps/curl/lib/Makefile.inc index 257e104de94..524fdcc53d5 100644 --- a/deps/curl/lib/Makefile.inc +++ b/deps/curl/lib/Makefile.inc @@ -110,7 +110,6 @@ LIB_VTLS_HFILES = \ vtls/x509asn1.h LIB_VQUIC_CFILES = \ - vquic/curl_msh3.c \ vquic/curl_ngtcp2.c \ vquic/curl_osslq.c \ vquic/curl_quiche.c \ @@ -118,7 +117,6 @@ LIB_VQUIC_CFILES = \ vquic/vquic-tls.c LIB_VQUIC_HFILES = \ - vquic/curl_msh3.h \ vquic/curl_ngtcp2.h \ vquic/curl_osslq.h \ vquic/curl_quiche.h \ @@ -148,6 +146,7 @@ LIB_CFILES = \ cf-h2-proxy.c \ cf-haproxy.c \ cf-https-connect.c \ + cf-ip-happy.c \ cf-socket.c \ cfilters.c \ conncache.c \ @@ -276,6 +275,7 @@ LIB_HFILES = \ cf-h2-proxy.h \ cf-haproxy.h \ cf-https-connect.h \ + cf-ip-happy.h \ cf-socket.h \ cfilters.h \ conncache.h \ @@ -296,6 +296,7 @@ LIB_HFILES = \ curl_ldap.h \ curl_md4.h \ curl_md5.h \ + curl_mem_undef.h \ curl_memory.h \ curl_memrchr.h \ curl_ntlm_core.h \ diff --git a/deps/curl/lib/altsvc.c b/deps/curl/lib/altsvc.c index 59476d7325a..c7448692fb5 100644 --- a/deps/curl/lib/altsvc.c +++ b/deps/curl/lib/altsvc.c @@ -187,13 +187,13 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, const char *line) else { struct altsvc *as; char dbuf[MAX_ALTSVC_DATELEN + 1]; - time_t expires; + time_t expires = 0; /* The date parser works on a null-terminated string. The maximum length is upheld by curlx_str_quotedword(). */ memcpy(dbuf, curlx_str(&date), curlx_strlen(&date)); dbuf[curlx_strlen(&date)] = 0; - expires = Curl_getdate_capped(dbuf); + Curl_getdate_capped(dbuf, &expires); as = altsvc_create(&srchost, &dsthost, &srcalpn, &dstalpn, (size_t)srcport, (size_t)dstport); if(as) { @@ -260,11 +260,11 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp) #ifdef USE_IPV6 else { char ipv6_unused[16]; - if(1 == curlx_inet_pton(AF_INET6, as->dst.host, ipv6_unused)) { + if(curlx_inet_pton(AF_INET6, as->dst.host, ipv6_unused) == 1) { dst6_pre = "["; dst6_post = "]"; } - if(1 == curlx_inet_pton(AF_INET6, as->src.host, ipv6_unused)) { + if(curlx_inet_pton(AF_INET6, as->src.host, ipv6_unused) == 1) { src6_pre = "["; src6_post = "]"; } diff --git a/deps/curl/lib/asyn-ares.c b/deps/curl/lib/asyn-ares.c index 007f1d7123c..e955990878a 100644 --- a/deps/curl/lib/asyn-ares.c +++ b/deps/curl/lib/asyn-ares.c @@ -237,26 +237,6 @@ CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl) return result; } -static void async_ares_cleanup(struct Curl_easy *data); - -void Curl_async_ares_shutdown(struct Curl_easy *data) -{ - struct async_ares_ctx *ares = &data->state.async.ares; - if(ares->channel) - ares_cancel(ares->channel); - async_ares_cleanup(data); -} - -void Curl_async_ares_destroy(struct Curl_easy *data) -{ - struct async_ares_ctx *ares = &data->state.async.ares; - Curl_async_ares_shutdown(data); - if(ares->channel) { - ares_destroy(ares->channel); - ares->channel = NULL; - } -} - /* * async_ares_cleanup() cleans up async resolver data. */ @@ -272,16 +252,37 @@ static void async_ares_cleanup(struct Curl_easy *data) #endif } +void Curl_async_ares_shutdown(struct Curl_easy *data) +{ + /* c-ares has a method to "cancel" operations on a channel, but + * as reported in #18216, this does not totally reset the channel + * and ares may get stuck. + * We need to destroy the channel and on demand create a new + * one to avoid that. */ + Curl_async_ares_destroy(data); +} + +void Curl_async_ares_destroy(struct Curl_easy *data) +{ + struct async_ares_ctx *ares = &data->state.async.ares; + if(ares->channel) { + ares_destroy(ares->channel); + ares->channel = NULL; + } + async_ares_cleanup(data); +} + /* - * Curl_async_getsock() is called when someone from the outside world + * Curl_async_pollset() is called when someone from the outside world * (using curl_multi_fdset()) wants to get our fd_set setup. */ -int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks) +CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps) { struct async_ares_ctx *ares = &data->state.async.ares; - DEBUGASSERT(ares->channel); - return Curl_ares_getsock(data, ares->channel, socks); + if(ares->channel) + return Curl_ares_pollset(data, ares->channel, ps); + return CURLE_OK; } /* @@ -337,28 +338,33 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, Curl_resolv_unlink(data, &data->state.async.dns); data->state.async.done = TRUE; result = ares->result; - if(ares->last_status == CURL_ASYNC_SUCCESS && !result) { + if(ares->ares_status == ARES_SUCCESS && !result) { data->state.async.dns = Curl_dnscache_mk_entry(data, ares->temp_ai, data->state.async.hostname, 0, data->state.async.port, FALSE); ares->temp_ai = NULL; /* temp_ai now owned by entry */ #ifdef HTTPSRR_WORKS - if(data->state.async.dns) { - struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&ares->hinfo); - if(!lhrr) - result = CURLE_OUT_OF_MEMORY; - else - data->state.async.dns->hinfo = lhrr; - } + if(data->state.async.dns) { + struct Curl_https_rrinfo *lhrr = Curl_httpsrr_dup_move(&ares->hinfo); + if(!lhrr) + result = CURLE_OUT_OF_MEMORY; + else + data->state.async.dns->hinfo = lhrr; + } #endif if(!result && data->state.async.dns) result = Curl_dnscache_add(data, data->state.async.dns); } /* if we have not found anything, report the proper * CURLE_COULDNT_RESOLVE_* code */ - if(!result && !data->state.async.dns) - result = Curl_resolver_error(data); + if(!result && !data->state.async.dns) { + const char *msg = NULL; + if(ares->ares_status != ARES_SUCCESS) + msg = ares_strerror(ares->ares_status); + result = Curl_resolver_error(data, msg); + } + if(result) Curl_resolv_unlink(data, &data->state.async.dns); *dns = data->state.async.dns; @@ -511,14 +517,14 @@ static void async_ares_hostbyname_cb(void *user_data, be valid so only defer it when we know the 'status' says its fine! */ return; - if(CURL_ASYNC_SUCCESS == status) { - ares->last_status = status; /* one success overrules any error */ + if(ARES_SUCCESS == status) { + ares->ares_status = status; /* one success overrules any error */ async_addr_concat(&ares->temp_ai, Curl_he2ai(hostent, data->state.async.port)); } - else if(ares->last_status != ARES_SUCCESS) { - /* no success so far, remember error */ - ares->last_status = status; + else if(ares->ares_status != ARES_SUCCESS) { + /* no success so far, remember last error */ + ares->ares_status = status; } ares->num_pending--; @@ -666,21 +672,22 @@ async_ares_node2addr(struct ares_addrinfo_node *node) } static void async_ares_addrinfo_cb(void *user_data, int status, int timeouts, - struct ares_addrinfo *result) + struct ares_addrinfo *ares_ai) { struct Curl_easy *data = (struct Curl_easy *)user_data; struct async_ares_ctx *ares = &data->state.async.ares; (void)timeouts; - CURL_TRC_DNS(data, "asyn-ares: addrinfo callback, status=%d", status); - if(ARES_SUCCESS == status) { - ares->temp_ai = async_ares_node2addr(result->nodes); - ares->last_status = CURL_ASYNC_SUCCESS; - ares_freeaddrinfo(result); + if(ares->ares_status != ARES_SUCCESS) /* do not overwrite success */ + ares->ares_status = status; + if(status == ARES_SUCCESS) { + ares->temp_ai = async_ares_node2addr(ares_ai->nodes); + ares_freeaddrinfo(ares_ai); } ares->num_pending--; - CURL_TRC_DNS(data, "ares: addrinfo done, status=%d, pending=%d, " - "addr=%sfound", - status, ares->num_pending, ares->temp_ai ? "" : "not "); + CURL_TRC_DNS(data, "ares: addrinfo done, query status=%d, " + "overall status=%d, pending=%d, addr=%sfound", + status, ares->ares_status, ares->num_pending, + ares->temp_ai ? "" : "not "); } #endif @@ -736,7 +743,13 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, return NULL; /* initial status - failed */ - ares->last_status = ARES_ENOTFOUND; + ares->ares_status = ARES_ENOTFOUND; + ares->result = CURLE_OK; + +#if ARES_VERSION >= 0x011800 /* >= v1.24.0 */ + CURL_TRC_DNS(data, "asyn-ares: servers=%s", + ares_get_servers_csv(ares->channel)); +#endif #ifdef HAVE_CARES_GETADDRINFO { diff --git a/deps/curl/lib/asyn-base.c b/deps/curl/lib/asyn-base.c index ea89fba15c3..eb2240b816c 100644 --- a/deps/curl/lib/asyn-base.c +++ b/deps/curl/lib/asyn-base.c @@ -70,7 +70,7 @@ #endif /* - * Curl_ares_getsock() is called when the outside world (using + * Curl_ares_pollset() is called when the outside world (using * curl_multi_fdset()) wants to get our fd_set setup and we are talking with * ares. The caller must make sure that this function is only called when we * have a working ares channel. @@ -78,18 +78,44 @@ * Returns: sockets-in-use-bitmap */ -int Curl_ares_getsock(struct Curl_easy *data, - ares_channel channel, - curl_socket_t *socks) + +CURLcode Curl_ares_pollset(struct Curl_easy *data, + ares_channel channel, + struct easy_pollset *ps) { struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 }; struct timeval timebuf; - int max = ares_getsock(channel, - (ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE); - struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf); - timediff_t milli = curlx_tvtoms(timeout); + curl_socket_t sockets[16]; /* ARES documented limit */ + unsigned int bitmap, i; + struct timeval *timeout; + timediff_t milli; + CURLcode result = CURLE_OK; + + DEBUGASSERT(channel); + if(!channel) + return CURLE_FAILED_INIT; + + bitmap = ares_getsock(channel, (ares_socket_t *)sockets, + CURL_ARRAYSIZE(sockets)); + for(i = 0; i < CURL_ARRAYSIZE(sockets); ++i) { + int flags = 0; + if(ARES_GETSOCK_READABLE(bitmap, i)) + flags |= CURL_POLL_IN; + if(ARES_GETSOCK_WRITABLE(bitmap, i)) + flags |= CURL_POLL_OUT; + if(!flags) + break; + result = Curl_pollset_change(data, ps, sockets[i], flags, 0); + if(result) + return result; + } + + timeout = ares_timeout(channel, &maxtime, &timebuf); + if(!timeout) + timeout = &maxtime; + milli = curlx_tvtoms(timeout); Curl_expire(data, milli, EXPIRE_ASYNC_NAME); - return max; + return result; } /* diff --git a/deps/curl/lib/asyn-thrdd.c b/deps/curl/lib/asyn-thrdd.c index 1ede8688206..ca6830a0bee 100644 --- a/deps/curl/lib/asyn-thrdd.c +++ b/deps/curl/lib/asyn-thrdd.c @@ -63,6 +63,7 @@ #include "url.h" #include "multiif.h" #include "curl_threads.h" +#include "select.h" #include "strdup.h" #ifdef USE_ARES @@ -106,6 +107,7 @@ void Curl_async_global_cleanup(void) } static void async_thrdd_destroy(struct Curl_easy *); +static void async_thrdd_shutdown(struct Curl_easy *); CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl) { @@ -114,33 +116,46 @@ CURLcode Curl_async_get_impl(struct Curl_easy *data, void **impl) return CURLE_OK; } -/* Destroy context of threaded resolver */ -static void addr_ctx_destroy(struct async_thrdd_addr_ctx *addr_ctx) +/* Give up reference to add_ctx */ +static void addr_ctx_unlink(struct async_thrdd_addr_ctx **paddr_ctx, + struct Curl_easy *data) { - if(addr_ctx) { - DEBUGASSERT(!addr_ctx->ref_count); + struct async_thrdd_addr_ctx *addr_ctx = *paddr_ctx; + bool destroy; + + (void)data; + if(!addr_ctx) + return; + + Curl_mutex_acquire(&addr_ctx->mutx); + if(!data) /* called by resolving thread */ + addr_ctx->thrd_done = TRUE; + + DEBUGASSERT(addr_ctx->ref_count); + --addr_ctx->ref_count; + destroy = !addr_ctx->ref_count; + Curl_mutex_release(&addr_ctx->mutx); + + if(destroy) { Curl_mutex_destroy(&addr_ctx->mutx); free(addr_ctx->hostname); if(addr_ctx->res) Curl_freeaddrinfo(addr_ctx->res); #ifndef CURL_DISABLE_SOCKETPAIR - /* - * close one end of the socket pair (may be done in resolver thread); - * the other end (for reading) is always closed in the parent thread. - */ #ifndef USE_EVENTFD - if(addr_ctx->sock_pair[1] != CURL_SOCKET_BAD) { wakeup_close(addr_ctx->sock_pair[1]); - } #endif + wakeup_close(addr_ctx->sock_pair[0]); #endif free(addr_ctx); } + *paddr_ctx = NULL; } /* Initialize context for threaded resolver */ static struct async_thrdd_addr_ctx * -addr_ctx_create(const char *hostname, int port, +addr_ctx_create(struct Curl_easy *data, + const char *hostname, int port, const struct addrinfo *hints) { struct async_thrdd_addr_ctx *addr_ctx = calloc(1, sizeof(*addr_ctx)); @@ -149,17 +164,13 @@ addr_ctx_create(const char *hostname, int port, addr_ctx->thread_hnd = curl_thread_t_null; addr_ctx->port = port; -#ifndef CURL_DISABLE_SOCKETPAIR - addr_ctx->sock_pair[0] = CURL_SOCKET_BAD; - addr_ctx->sock_pair[1] = CURL_SOCKET_BAD; -#endif - addr_ctx->ref_count = 0; + addr_ctx->ref_count = 1; #ifdef HAVE_GETADDRINFO DEBUGASSERT(hints); addr_ctx->hints = *hints; #else - (void) hints; + (void)hints; #endif Curl_mutex_init(&addr_ctx->mutx); @@ -172,7 +183,7 @@ addr_ctx_create(const char *hostname, int port, goto err_exit; } #endif - addr_ctx->sock_error = CURL_ASYNC_SUCCESS; + addr_ctx->sock_error = 0; /* Copying hostname string because original can be destroyed by parent * thread during gethostbyname execution. @@ -181,20 +192,21 @@ addr_ctx_create(const char *hostname, int port, if(!addr_ctx->hostname) goto err_exit; - addr_ctx->ref_count = 1; return addr_ctx; err_exit: -#ifndef CURL_DISABLE_SOCKETPAIR - if(addr_ctx->sock_pair[0] != CURL_SOCKET_BAD) { - wakeup_close(addr_ctx->sock_pair[0]); - addr_ctx->sock_pair[0] = CURL_SOCKET_BAD; - } -#endif - addr_ctx_destroy(addr_ctx); + addr_ctx_unlink(&addr_ctx, data); return NULL; } +static void async_thrd_cleanup(void *arg) +{ + struct async_thrdd_addr_ctx *addr_ctx = arg; + + Curl_thread_disable_cancel(); + addr_ctx_unlink(&addr_ctx, NULL); +} + #ifdef HAVE_GETADDRINFO /* @@ -203,58 +215,71 @@ addr_ctx_create(const char *hostname, int port, * For builds without ARES, but with USE_IPV6, create a resolver thread * and wait on it. */ -static -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) -DWORD -#else -unsigned int -#endif -CURL_STDCALL getaddrinfo_thread(void *arg) +static CURL_THREAD_RETURN_T CURL_STDCALL getaddrinfo_thread(void *arg) { struct async_thrdd_addr_ctx *addr_ctx = arg; - char service[12]; - int rc; - bool all_gone; + bool do_abort; - msnprintf(service, sizeof(service), "%d", addr_ctx->port); +/* clang complains about empty statements and the pthread_cleanup* macros + * are pretty ill defined. */ +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif - rc = Curl_getaddrinfo_ex(addr_ctx->hostname, service, - &addr_ctx->hints, &addr_ctx->res); - - if(rc) { - addr_ctx->sock_error = SOCKERRNO ? SOCKERRNO : rc; - if(addr_ctx->sock_error == 0) - addr_ctx->sock_error = RESOLVER_ENOMEM; - } - else { - Curl_addrinfo_set_port(addr_ctx->res, addr_ctx->port); - } + Curl_thread_push_cleanup(async_thrd_cleanup, addr_ctx); Curl_mutex_acquire(&addr_ctx->mutx); - if(addr_ctx->ref_count > 1) { - /* Someone still waiting on our results. */ + do_abort = addr_ctx->do_abort; + Curl_mutex_release(&addr_ctx->mutx); + + if(!do_abort) { + char service[12]; + int rc; + +#ifdef DEBUGBUILD + Curl_resolve_test_delay(); +#endif + msnprintf(service, sizeof(service), "%d", addr_ctx->port); + + rc = Curl_getaddrinfo_ex(addr_ctx->hostname, service, + &addr_ctx->hints, &addr_ctx->res); + + if(rc) { + addr_ctx->sock_error = SOCKERRNO ? SOCKERRNO : rc; + if(addr_ctx->sock_error == 0) + addr_ctx->sock_error = RESOLVER_ENOMEM; + } + else { + Curl_addrinfo_set_port(addr_ctx->res, addr_ctx->port); + } + + Curl_mutex_acquire(&addr_ctx->mutx); + do_abort = addr_ctx->do_abort; + Curl_mutex_release(&addr_ctx->mutx); #ifndef CURL_DISABLE_SOCKETPAIR - if(addr_ctx->sock_pair[1] != CURL_SOCKET_BAD) { + if(!do_abort) { #ifdef USE_EVENTFD const uint64_t buf[1] = { 1 }; #else const char buf[1] = { 1 }; #endif - /* DNS has been resolved, signal client task */ + /* Thread is done, notify transfer */ if(wakeup_write(addr_ctx->sock_pair[1], buf, sizeof(buf)) < 0) { - /* update sock_erro to errno */ + /* update sock_error to errno */ addr_ctx->sock_error = SOCKERRNO; } } #endif + } - /* thread gives up its reference to the shared data now. */ - --addr_ctx->ref_count; - all_gone = !addr_ctx->ref_count; - Curl_mutex_release(&addr_ctx->mutx); - if(all_gone) - addr_ctx_destroy(addr_ctx); + Curl_thread_pop_cleanup(); +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + + addr_ctx_unlink(&addr_ctx, NULL); return 0; } @@ -263,33 +288,61 @@ CURL_STDCALL getaddrinfo_thread(void *arg) /* * gethostbyname_thread() resolves a name and then exits. */ -static -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) -DWORD -#else -unsigned int -#endif -CURL_STDCALL gethostbyname_thread(void *arg) +static CURL_THREAD_RETURN_T CURL_STDCALL gethostbyname_thread(void *arg) { struct async_thrdd_addr_ctx *addr_ctx = arg; - bool all_gone; + bool do_abort; - addr_ctx->res = Curl_ipv4_resolve_r(addr_ctx->hostname, addr_ctx->port); +/* clang complains about empty statements and the pthread_cleanup* macros + * are pretty ill defined. */ +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wextra-semi-stmt" +#endif - if(!addr_ctx->res) { - addr_ctx->sock_error = SOCKERRNO; - if(addr_ctx->sock_error == 0) - addr_ctx->sock_error = RESOLVER_ENOMEM; - } + Curl_thread_push_cleanup(async_thrd_cleanup, addr_ctx); Curl_mutex_acquire(&addr_ctx->mutx); - /* thread gives up its reference to the shared data now. */ - --addr_ctx->ref_count; - all_gone = !addr_ctx->ref_count;; + do_abort = addr_ctx->do_abort; Curl_mutex_release(&addr_ctx->mutx); - if(all_gone) - addr_ctx_destroy(addr_ctx); + if(!do_abort) { +#ifdef DEBUGBUILD + Curl_resolve_test_delay(); +#endif + + addr_ctx->res = Curl_ipv4_resolve_r(addr_ctx->hostname, addr_ctx->port); + if(!addr_ctx->res) { + addr_ctx->sock_error = SOCKERRNO; + if(addr_ctx->sock_error == 0) + addr_ctx->sock_error = RESOLVER_ENOMEM; + } + + Curl_mutex_acquire(&addr_ctx->mutx); + do_abort = addr_ctx->do_abort; + Curl_mutex_release(&addr_ctx->mutx); +#ifndef CURL_DISABLE_SOCKETPAIR + if(!do_abort) { +#ifdef USE_EVENTFD + const uint64_t buf[1] = { 1 }; +#else + const char buf[1] = { 1 }; +#endif + /* Thread is done, notify transfer */ + if(wakeup_write(addr_ctx->sock_pair[1], buf, sizeof(buf)) < 0) { + /* update sock_error to errno */ + addr_ctx->sock_error = SOCKERRNO; + } + } +#endif + } + + Curl_thread_pop_cleanup(); +#if defined(__clang__) +#pragma clang diagnostic pop +#endif + + async_thrd_cleanup(addr_ctx); return 0; } @@ -302,6 +355,7 @@ static void async_thrdd_destroy(struct Curl_easy *data) { struct async_thrdd_ctx *thrdd = &data->state.async.thrdd; struct async_thrdd_addr_ctx *addr = thrdd->addr; + #ifdef USE_HTTPSRR_ARES if(thrdd->rr.channel) { ares_destroy(thrdd->rr.channel); @@ -310,46 +364,30 @@ static void async_thrdd_destroy(struct Curl_easy *data) Curl_httpsrr_cleanup(&thrdd->rr.hinfo); #endif - if(addr) { -#ifndef CURL_DISABLE_SOCKETPAIR - curl_socket_t sock_rd = addr->sock_pair[0]; -#endif + if(thrdd->addr && (thrdd->addr->thread_hnd != curl_thread_t_null)) { bool done; - /* Release our reference to the data shared with the thread. */ Curl_mutex_acquire(&addr->mutx); - --addr->ref_count; - CURL_TRC_DNS(data, "resolve, destroy async data, shared ref=%d", - addr->ref_count); - done = !addr->ref_count; - /* we give up our reference to `addr`, so NULL our pointer. - * coverity analyses this as being a potential unsynched write, - * assuming two calls to this function could be invoked concurrently. - * Which they never are, as the transfer's side runs single-threaded. */ - thrdd->addr = NULL; - if(!done) { - /* thread is still running. Detach the thread while mutexed, it will - * trigger the cleanup when it releases its reference. */ - Curl_thread_destroy(&addr->thread_hnd); - } +#ifndef CURL_DISABLE_SOCKETPAIR + if(!addr->do_abort) + Curl_multi_will_close(data, addr->sock_pair[0]); +#endif + addr->do_abort = TRUE; + done = addr->thrd_done; Curl_mutex_release(&addr->mutx); if(done) { - /* thread has released its reference, join it and - * release the memory we shared with it. */ - if(addr->thread_hnd != curl_thread_t_null) - Curl_thread_join(&addr->thread_hnd); - addr_ctx_destroy(addr); + Curl_thread_join(&addr->thread_hnd); + CURL_TRC_DNS(data, "async_thrdd_destroy, thread joined"); + } + else { + /* thread is still running. Detach the thread while mutexed, it will + * trigger the cleanup when it releases its reference. */ + Curl_thread_destroy(&addr->thread_hnd); + CURL_TRC_DNS(data, "async_thrdd_destroy, thread detached"); } -#ifndef CURL_DISABLE_SOCKETPAIR - /* - * ensure CURLMOPT_SOCKETFUNCTION fires CURL_POLL_REMOVE - * before the FD is invalidated to avoid EBADF on EPOLL_CTL_DEL - */ - Curl_multi_will_close(data, sock_rd); - wakeup_close(sock_rd); -#endif } + addr_ctx_unlink(&thrdd->addr, data); } #ifdef USE_HTTPSRR_ARES @@ -379,6 +417,14 @@ static CURLcode async_rr_start(struct Curl_easy *data) thrdd->rr.channel = NULL; return CURLE_FAILED_INIT; } +#ifdef CURLDEBUG + if(getenv("CURL_DNS_SERVER")) { + const char *servers = getenv("CURL_DNS_SERVER"); + status = ares_set_servers_ports_csv(thrdd->rr.channel, servers); + if(status) + return CURLE_FAILED_INIT; + } +#endif memset(&thrdd->rr.hinfo, 0, sizeof(thrdd->rr.hinfo)); thrdd->rr.hinfo.port = -1; @@ -386,6 +432,7 @@ static CURLcode async_rr_start(struct Curl_easy *data) data->conn->host.name, ARES_CLASS_IN, ARES_REC_TYPE_HTTPS, async_thrdd_rr_done, data, NULL); + CURL_TRC_DNS(data, "Issued HTTPS-RR request for %s", data->conn->host.name); return CURLE_OK; } #endif @@ -428,29 +475,28 @@ static bool async_thrdd_init(struct Curl_easy *data, if(!data->state.async.hostname) goto err_exit; - addr_ctx = addr_ctx_create(hostname, port, hints); + addr_ctx = addr_ctx_create(data, hostname, port, hints); if(!addr_ctx) goto err_exit; thrdd->addr = addr_ctx; - Curl_mutex_acquire(&addr_ctx->mutx); - DEBUGASSERT(addr_ctx->ref_count == 1); /* passing addr_ctx to the thread adds a reference */ + addr_ctx->ref_count = 2; addr_ctx->start = curlx_now(); - ++addr_ctx->ref_count; + #ifdef HAVE_GETADDRINFO addr_ctx->thread_hnd = Curl_thread_create(getaddrinfo_thread, addr_ctx); #else addr_ctx->thread_hnd = Curl_thread_create(gethostbyname_thread, addr_ctx); #endif + if(addr_ctx->thread_hnd == curl_thread_t_null) { - /* The thread never started, remove its reference that never happened. */ - --addr_ctx->ref_count; + /* The thread never started */ + addr_ctx->ref_count = 1; + addr_ctx->thrd_done = TRUE; err = errno; - Curl_mutex_release(&addr_ctx->mutx); goto err_exit; } - Curl_mutex_release(&addr_ctx->mutx); #ifdef USE_HTTPSRR_ARES if(async_rr_start(data)) @@ -466,6 +512,33 @@ static bool async_thrdd_init(struct Curl_easy *data, return FALSE; } +static void async_thrdd_shutdown(struct Curl_easy *data) +{ + struct async_thrdd_ctx *thrdd = &data->state.async.thrdd; + struct async_thrdd_addr_ctx *addr_ctx = thrdd->addr; + bool done; + + if(!addr_ctx) + return; + if(addr_ctx->thread_hnd == curl_thread_t_null) + return; + + Curl_mutex_acquire(&addr_ctx->mutx); +#ifndef CURL_DISABLE_SOCKETPAIR + if(!addr_ctx->do_abort) + Curl_multi_will_close(data, addr_ctx->sock_pair[0]); +#endif + addr_ctx->do_abort = TRUE; + done = addr_ctx->thrd_done; + Curl_mutex_release(&addr_ctx->mutx); + + DEBUGASSERT(addr_ctx->thread_hnd != curl_thread_t_null); + if(!done && (addr_ctx->thread_hnd != curl_thread_t_null)) { + CURL_TRC_DNS(data, "cancelling resolve thread"); + (void)Curl_thread_cancel(&addr_ctx->thread_hnd); + } +} + /* * 'entry' may be NULL and then no data is returned */ @@ -475,47 +548,44 @@ static CURLcode asyn_thrdd_await(struct Curl_easy *data, { CURLcode result = CURLE_OK; - DEBUGASSERT(addr_ctx->thread_hnd != curl_thread_t_null); + if(addr_ctx->thread_hnd != curl_thread_t_null) { + /* not interested in result? cancel, if still running... */ + if(!entry) + async_thrdd_shutdown(data); + + CURL_TRC_DNS(data, "resolve, wait for thread to finish"); + if(!Curl_thread_join(&addr_ctx->thread_hnd)) { + DEBUGASSERT(0); + } - CURL_TRC_DNS(data, "resolve, wait for thread to finish"); - /* wait for the thread to resolve the name */ - if(Curl_thread_join(&addr_ctx->thread_hnd)) { if(entry) result = Curl_async_is_resolved(data, entry); } - else - DEBUGASSERT(0); data->state.async.done = TRUE; if(entry) *entry = data->state.async.dns; - async_thrdd_destroy(data); return result; } - /* * Until we gain a way to signal the resolver threads to stop early, we must * simply wait for them and ignore their results. */ void Curl_async_thrdd_shutdown(struct Curl_easy *data) { - struct async_thrdd_ctx *thrdd = &data->state.async.thrdd; - - /* If we are 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(thrdd->addr && (thrdd->addr->thread_hnd != curl_thread_t_null) && - !data->set.quick_exit) - (void)asyn_thrdd_await(data, thrdd->addr, NULL); - else - async_thrdd_destroy(data); + async_thrdd_shutdown(data); } void Curl_async_thrdd_destroy(struct Curl_easy *data) { - Curl_async_thrdd_shutdown(data); + struct async_thrdd_ctx *thrdd = &data->state.async.thrdd; + + if(thrdd->addr && !data->set.quick_exit) { + (void)asyn_thrdd_await(data, thrdd->addr, NULL); + } + async_thrdd_destroy(data); } /* @@ -572,7 +642,7 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, return CURLE_FAILED_INIT; Curl_mutex_acquire(&thrdd->addr->mutx); - done = (thrdd->addr->ref_count == 1); + done = thrdd->addr->thrd_done; Curl_mutex_release(&thrdd->addr->mutx); if(done) { @@ -608,13 +678,13 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, } if(!result && !data->state.async.dns) - result = Curl_resolver_error(data); + result = Curl_resolver_error(data, NULL); if(result) Curl_resolv_unlink(data, &data->state.async.dns); *dns = data->state.async.dns; CURL_TRC_DNS(data, "is_resolved() result=%d, dns=%sfound", result, *dns ? "" : "not "); - async_thrdd_destroy(data); + async_thrdd_shutdown(data); return result; } else { @@ -641,37 +711,35 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data, } } -int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks) +CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps) { struct async_thrdd_ctx *thrdd = &data->state.async.thrdd; - int ret_val = 0; -#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES) - int socketi = 0; -#else - (void)socks; + CURLcode result = CURLE_OK; + bool thrd_done; + +#if !defined(USE_HTTPSRR_ARES) && defined(CURL_DISABLE_SOCKETPAIR) + (void)ps; #endif #ifdef USE_HTTPSRR_ARES if(thrdd->rr.channel) { - ret_val = Curl_ares_getsock(data, thrdd->rr.channel, socks); - for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++) - if(!ARES_GETSOCK_READABLE(ret_val, socketi) && - !ARES_GETSOCK_WRITABLE(ret_val, socketi)) - break; + result = Curl_ares_pollset(data, thrdd->rr.channel, ps); + if(result) + return result; } #endif if(!thrdd->addr) - return ret_val; + return result; + Curl_mutex_acquire(&thrdd->addr->mutx); + thrd_done = thrdd->addr->thrd_done; + Curl_mutex_release(&thrdd->addr->mutx); + + if(!thrd_done) { #ifndef CURL_DISABLE_SOCKETPAIR - if(thrdd->addr) { - /* return read fd to client for polling the DNS resolution status */ - socks[socketi] = thrdd->addr->sock_pair[0]; - ret_val |= GETSOCK_READSOCK(socketi); - } - else -#endif - { + /* return read fd to client for polling the DNS resolution status */ + result = Curl_pollset_add_in(data, ps, thrdd->addr->sock_pair[0]); +#else timediff_t milli; timediff_t ms = curlx_timediff(curlx_now(), thrdd->addr->start); if(ms < 3) @@ -683,9 +751,9 @@ int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks) else milli = 200; Curl_expire(data, milli, EXPIRE_ASYNC_NAME); +#endif } - - return ret_val; + return result; } #ifndef HAVE_GETADDRINFO diff --git a/deps/curl/lib/asyn.h b/deps/curl/lib/asyn.h index 1cc7175bebc..7863042bbe3 100644 --- a/deps/curl/lib/asyn.h +++ b/deps/curl/lib/asyn.h @@ -37,6 +37,7 @@ struct Curl_dns_entry; struct addrinfo; struct hostent; struct connectdata; +struct easy_pollset; #if defined(CURLRES_ARES) && defined(CURLRES_THREADED) #error cannot have both CURLRES_ARES and CURLRES_THREADED defined @@ -70,15 +71,15 @@ void Curl_async_global_cleanup(void); */ CURLcode Curl_async_get_impl(struct Curl_easy *easy, void **impl); -/* Curl_async_getsock() +/* Curl_async_pollset() * - * This function is called from the Curl_multi_getsock() function. 'sock' is a + * This function is called from the Curl_multi_pollset() function. 'sock' is a * pointer to an array to hold the file descriptors, with 'numsock' being the * size of that array (in number of entries). This function is supposed to * return bitmask indicating what file descriptors (referring to array indexes * in the 'sock' array) to wait for, read/write. */ -int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *sock); +CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps); /* * Curl_async_is_resolved() @@ -127,9 +128,10 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data, /* common functions for c-ares and threaded resolver with HTTPSRR */ #include -int Curl_ares_getsock(struct Curl_easy *data, - ares_channel channel, - curl_socket_t *socks); +CURLcode Curl_ares_pollset(struct Curl_easy *data, + ares_channel channel, + struct easy_pollset *ps); + int Curl_ares_perform(ares_channel channel, timediff_t timeout_ms); #endif @@ -141,7 +143,7 @@ struct async_ares_ctx { int num_pending; /* number of outstanding c-ares requests */ struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */ - int last_status; + int ares_status; /* ARES_SUCCESS, ARES_ENOTFOUND, etc. */ CURLcode result; /* CURLE_OK or error handling response */ #ifndef HAVE_CARES_GETADDRINFO struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */ @@ -191,6 +193,8 @@ struct async_thrdd_addr_ctx { int port; int sock_error; int ref_count; + BIT(thrd_done); + BIT(do_abort); }; /* Context for threaded resolver */ @@ -236,7 +240,7 @@ struct doh_probes; #ifdef USE_CURL_ASYNC struct Curl_async { -#ifdef CURLRES_ARES /* */ +#ifdef CURLRES_ARES struct async_ares_ctx ares; #elif defined(CURLRES_THREADED) struct async_thrdd_ctx thrdd; diff --git a/deps/curl/lib/bufq.c b/deps/curl/lib/bufq.c index 8783619eed0..5cfd7520f2e 100644 --- a/deps/curl/lib/bufq.c +++ b/deps/curl/lib/bufq.c @@ -149,7 +149,6 @@ static void chunk_list_free(struct buf_chunk **anchor) } - void Curl_bufcp_init(struct bufc_pool *pool, size_t chunk_size, size_t spare_max) { @@ -174,6 +173,12 @@ static CURLcode bufcp_take(struct bufc_pool *pool, return CURLE_OK; } + /* Check for integer overflow before allocation */ + if(pool->chunk_size > SIZE_MAX - sizeof(*chunk)) { + *pchunk = NULL; + return CURLE_OUT_OF_MEMORY; + } + chunk = calloc(1, sizeof(*chunk) + pool->chunk_size); if(!chunk) { *pchunk = NULL; @@ -302,6 +307,11 @@ static struct buf_chunk *get_spare(struct bufq *q) return chunk; } else { + /* Check for integer overflow before allocation */ + if(q->chunk_size > SIZE_MAX - sizeof(*chunk)) { + return NULL; + } + chunk = calloc(1, sizeof(*chunk) + q->chunk_size); if(!chunk) return NULL; @@ -526,7 +536,8 @@ CURLcode Curl_bufq_write_pass(struct bufq *q, if(result != CURLE_AGAIN) /* real error, fail */ return result; - if((result == CURLE_AGAIN) && *pwritten) + /* result == CURLE_AGAIN */ + if(*pwritten) /* we did write successfully before */ result = CURLE_OK; return result; @@ -590,8 +601,7 @@ static CURLcode bufq_slurpn(struct bufq *q, size_t max_len, break; } else if(n == 0) { - /* eof */ - result = CURLE_OK; + /* eof, result remains CURLE_OK */ break; } *pnread += n; diff --git a/deps/curl/lib/cf-h1-proxy.c b/deps/curl/lib/cf-h1-proxy.c index 4aac877fc18..798d6e9f668 100644 --- a/deps/curl/lib/cf-h1-proxy.c +++ b/deps/curl/lib/cf-h1-proxy.c @@ -682,11 +682,12 @@ static CURLcode cf_h1_proxy_connect(struct Curl_cfilter *cf, return result; } -static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct h1_tunnel_state *ts = cf->ctx; + CURLcode result = CURLE_OK; if(!cf->connected) { /* If we are not connected, but the filter "below" is @@ -698,13 +699,14 @@ static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf, response headers or if we are still sending the request, wait for write. */ if(tunnel_want_send(ts)) - Curl_pollset_set_out_only(data, ps, sock); + result = Curl_pollset_set_out_only(data, ps, sock); else - Curl_pollset_set_in_only(data, ps, sock); + result = Curl_pollset_set_in_only(data, ps, sock); } else - Curl_pollset_set_out_only(data, ps, sock); + result = Curl_pollset_set_out_only(data, ps, sock); } + return result; } static void cf_h1_proxy_destroy(struct Curl_cfilter *cf, diff --git a/deps/curl/lib/cf-h2-proxy.c b/deps/curl/lib/cf-h2-proxy.c index 8a853f6b1d2..d67bbd55adf 100644 --- a/deps/curl/lib/cf-h2-proxy.c +++ b/deps/curl/lib/cf-h2-proxy.c @@ -24,7 +24,8 @@ #include "curl_setup.h" -#if defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_PROXY) && \ + defined(USE_NGHTTP2) #include #include "urldata.h" @@ -40,6 +41,7 @@ #include "http_proxy.h" #include "multiif.h" #include "sendf.h" +#include "select.h" #include "cf-h2-proxy.h" /* The last 3 #include files should be in this order */ @@ -472,7 +474,7 @@ static CURLcode proxy_h2_progress_ingress(struct Curl_cfilter *cf, Curl_bufq_len(&ctx->inbufq), result, nread); if(result) { if(result != CURLE_AGAIN) { - failf(data, "Failed receiving HTTP2 data"); + failf(data, "Failed receiving HTTP2 proxy data"); return result; } break; @@ -539,7 +541,7 @@ static ssize_t on_session_send(nghttp2_session *h2, if(!nwritten) return NGHTTP2_ERR_WOULDBLOCK; - return (nwritten > SSIZE_T_MAX) ? + return (nwritten > SSIZE_MAX) ? NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten; } @@ -815,7 +817,7 @@ static ssize_t tunnel_send_callback(nghttp2_session *session, CURL_TRC_CF(data, cf, "[%d] tunnel_send_callback -> %zd", ts->stream_id, nread); - return (nread > SSIZE_T_MAX) ? + return (nread > SSIZE_MAX) ? NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nread; } @@ -1201,14 +1203,15 @@ static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf, return cf->next ? cf->next->cft->has_data_pending(cf->next, data) : FALSE; } -static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_h2_proxy_ctx *ctx = cf->ctx; struct cf_call_data save; curl_socket_t sock = Curl_conn_cf_get_socket(cf, data); bool want_recv, want_send; + CURLcode result = CURLE_OK; if(!cf->connected && ctx->h2) { want_send = nghttp2_session_want_write(ctx->h2) || @@ -1233,9 +1236,9 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf, !Curl_bufq_is_empty(&ctx->outbufq) || !Curl_bufq_is_empty(&ctx->tunnel.sendbuf); - Curl_pollset_set(data, ps, sock, want_recv, want_send); - CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d", - want_recv, want_send); + result = Curl_pollset_set(data, ps, sock, want_recv, want_send); + CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d -> %d", + want_recv, want_send, result); CF_DATA_RESTORE(cf, save); } else if(ctx->sent_goaway && !cf->shutdown) { @@ -1245,11 +1248,12 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf, !Curl_bufq_is_empty(&ctx->outbufq) || !Curl_bufq_is_empty(&ctx->tunnel.sendbuf); want_recv = nghttp2_session_want_read(ctx->h2); - Curl_pollset_set(data, ps, sock, want_recv, want_send); - CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d", - want_recv, want_send); + result = Curl_pollset_set(data, ps, sock, want_recv, want_send); + CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d -> %d", + want_recv, want_send, result); CF_DATA_RESTORE(cf, save); } + return result; } static CURLcode h2_handle_tunnel_close(struct Curl_cfilter *cf, @@ -1533,6 +1537,12 @@ static CURLcode cf_h2_proxy_query(struct Curl_cfilter *cf, } break; } + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = NULL; + return CURLE_OK; + } default: break; } @@ -1606,4 +1616,4 @@ CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf, return result; } -#endif /* defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) */ +#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_PROXY && USE_NGHTTP2 */ diff --git a/deps/curl/lib/cf-h2-proxy.h b/deps/curl/lib/cf-h2-proxy.h index c01bf62133b..1b3f85aaaff 100644 --- a/deps/curl/lib/cf-h2-proxy.h +++ b/deps/curl/lib/cf-h2-proxy.h @@ -33,7 +33,6 @@ CURLcode Curl_cf_h2_proxy_insert_after(struct Curl_cfilter *cf, extern struct Curl_cftype Curl_cft_h2_proxy; - -#endif /* defined(USE_NGHTTP2) && !defined(CURL_DISABLE_PROXY) */ +#endif /* USE_NGHTTP2 && !CURL_DISABLE_PROXY */ #endif /* HEADER_CURL_H2_PROXY_H */ diff --git a/deps/curl/lib/cf-haproxy.c b/deps/curl/lib/cf-haproxy.c index 6183ca2c13a..2d66efea904 100644 --- a/deps/curl/lib/cf-haproxy.c +++ b/deps/curl/lib/cf-haproxy.c @@ -24,7 +24,7 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_PROXY) +#ifndef CURL_DISABLE_PROXY #include #include "urldata.h" @@ -32,6 +32,7 @@ #include "cf-haproxy.h" #include "curl_trc.h" #include "multiif.h" +#include "select.h" /* The last 3 #include files should be in this order */ #include "curl_printf.h" @@ -72,7 +73,7 @@ static CURLcode cf_haproxy_date_out_set(struct Curl_cfilter*cf, CURLcode result; const char *client_ip; struct ip_quadruple ipquad; - int is_ipv6; + bool is_ipv6; DEBUGASSERT(ctx); DEBUGASSERT(ctx->state == HAPROXY_INIT); @@ -178,15 +179,17 @@ static void cf_haproxy_close(struct Curl_cfilter *cf, cf->next->cft->do_close(cf->next, data); } -static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_haproxy_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { if(cf->next->connected && !cf->connected) { /* If we are not connected, but the filter "below" is * and not waiting on something, we are sending. */ - Curl_pollset_set_out_only(data, ps, Curl_conn_cf_get_socket(cf, data)); + return Curl_pollset_set_out_only( + data, ps, Curl_conn_cf_get_socket(cf, data)); } + return CURLE_OK; } struct Curl_cftype Curl_cft_haproxy = { diff --git a/deps/curl/lib/cf-haproxy.h b/deps/curl/lib/cf-haproxy.h index d02c323e7b7..9190dd5b578 100644 --- a/deps/curl/lib/cf-haproxy.h +++ b/deps/curl/lib/cf-haproxy.h @@ -27,7 +27,7 @@ #include "curl_setup.h" #include "urldata.h" -#if !defined(CURL_DISABLE_PROXY) +#ifndef CURL_DISABLE_PROXY CURLcode Curl_cf_haproxy_insert_after(struct Curl_cfilter *cf_at, struct Curl_easy *data); diff --git a/deps/curl/lib/cf-https-connect.c b/deps/curl/lib/cf-https-connect.c index b89ed80e553..b4a46052950 100644 --- a/deps/curl/lib/cf-https-connect.c +++ b/deps/curl/lib/cf-https-connect.c @@ -24,7 +24,7 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_HTTP) +#ifndef CURL_DISABLE_HTTP #include "urldata.h" #include @@ -35,6 +35,7 @@ #include "multiif.h" #include "cf-https-connect.h" #include "http2.h" +#include "select.h" #include "vquic/vquic.h" /* The last 3 #include files should be in this order */ @@ -226,24 +227,22 @@ static CURLcode baller_connected(struct Curl_cfilter *cf, cf->next = winner->cf; winner->cf = NULL; - switch(cf->conn->alpn) { - case CURL_HTTP_VERSION_3: - break; - case CURL_HTTP_VERSION_2: #ifdef USE_NGHTTP2 + { /* Using nghttp2, we add the filter "below" us, so when the conn * closes, we tear it down for a fresh reconnect */ - result = Curl_http2_switch_at(cf, data); - if(result) { - ctx->state = CF_HC_FAILURE; - ctx->result = result; - return result; + const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data); + if(alpn && !strcmp("h2", alpn)) { + result = Curl_http2_switch_at(cf, data); + if(result) { + ctx->state = CF_HC_FAILURE; + ctx->result = result; + return result; + } } -#endif - break; - default: - break; } +#endif + ctx->state = CF_HC_SUCCESS; cf->connected = TRUE; return result; @@ -428,22 +427,24 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf, return result; } -static void cf_hc_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_hc_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { + CURLcode result = CURLE_OK; if(!cf->connected) { struct cf_hc_ctx *ctx = cf->ctx; size_t i; - for(i = 0; i < ctx->baller_count; i++) { + for(i = 0; (i < ctx->baller_count) && !result; i++) { struct cf_hc_baller *b = &ctx->ballers[i]; if(!cf_hc_baller_is_active(b)) continue; - Curl_conn_cf_adjust_pollset(b->cf, data, ps); + result = Curl_conn_cf_adjust_pollset(b->cf, data, ps); } - CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num); + CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %d socks", result, ps->n); } + return result; } static bool cf_hc_data_pending(struct Curl_cfilter *cf, @@ -749,4 +750,4 @@ CURLcode Curl_cf_https_setup(struct Curl_easy *data, return result; } -#endif /* !defined(CURL_DISABLE_HTTP) */ +#endif /* !CURL_DISABLE_HTTP */ diff --git a/deps/curl/lib/cf-https-connect.h b/deps/curl/lib/cf-https-connect.h index c36726f0a22..df51b62479d 100644 --- a/deps/curl/lib/cf-https-connect.h +++ b/deps/curl/lib/cf-https-connect.h @@ -25,7 +25,7 @@ ***************************************************************************/ #include "curl_setup.h" -#if !defined(CURL_DISABLE_HTTP) +#ifndef CURL_DISABLE_HTTP struct Curl_cfilter; struct Curl_easy; @@ -40,16 +40,10 @@ CURLcode Curl_cf_http_connect_add(struct Curl_easy *data, int sockindex, bool try_h3, bool try_h21); -CURLcode -Curl_cf_http_connect_insert_after(struct Curl_cfilter *cf_at, - struct Curl_easy *data, - bool try_h3, bool try_h21); - - CURLcode Curl_cf_https_setup(struct Curl_easy *data, struct connectdata *conn, int sockindex); -#endif /* !defined(CURL_DISABLE_HTTP) */ +#endif /* !CURL_DISABLE_HTTP */ #endif /* HEADER_CURL_CF_HTTP_H */ diff --git a/deps/curl/lib/cf-ip-happy.c b/deps/curl/lib/cf-ip-happy.c new file mode 100644 index 00000000000..5e4c20444e7 --- /dev/null +++ b/deps/curl/lib/cf-ip-happy.c @@ -0,0 +1,951 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ + +#include "curl_setup.h" + +#ifdef HAVE_NETINET_IN_H +#include /* may need it */ +#endif +#ifdef HAVE_SYS_UN_H +#include /* for sockaddr_un */ +#endif +#ifdef HAVE_LINUX_TCP_H +#include +#elif defined(HAVE_NETINET_TCP_H) +#include +#endif +#ifdef HAVE_SYS_IOCTL_H +#include +#endif +#ifdef HAVE_NETDB_H +#include +#endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef __VMS +#include +#include +#endif + +#include "urldata.h" +#include "connect.h" +#include "cfilters.h" +#include "cf-ip-happy.h" +#include "curl_trc.h" +#include "multiif.h" +#include "progress.h" +#include "select.h" +#include "vquic/vquic.h" /* for quic cfilters */ + +/* The last 3 #include files should be in this order */ +#include "curl_printf.h" +#include "curl_memory.h" +#include "memdebug.h" + + +struct transport_provider { + int transport; + cf_ip_connect_create *cf_create; +}; + +static +#ifndef UNITTESTS +const +#endif +struct transport_provider transport_providers[] = { + { TRNSPRT_TCP, Curl_cf_tcp_create }, +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) + { TRNSPRT_QUIC, Curl_cf_quic_create }, +#endif +#ifndef CURL_DISABLE_TFTP + { TRNSPRT_UDP, Curl_cf_udp_create }, +#endif +#ifdef USE_UNIX_SOCKETS + { TRNSPRT_UNIX, Curl_cf_unix_create }, +#endif +}; + +static cf_ip_connect_create *get_cf_create(int transport) +{ + size_t i; + for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) { + if(transport == transport_providers[i].transport) + return transport_providers[i].cf_create; + } + return NULL; +} + +#ifdef UNITTESTS +/* used by unit2600.c */ +void Curl_debug_set_transport_provider(int transport, + cf_ip_connect_create *cf_create) +{ + size_t i; + for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) { + if(transport == transport_providers[i].transport) { + transport_providers[i].cf_create = cf_create; + return; + } + } +} +#endif /* UNITTESTS */ + + +struct cf_ai_iter { + const struct Curl_addrinfo *head; + const struct Curl_addrinfo *last; + int ai_family; + int n; +}; + +static void cf_ai_iter_init(struct cf_ai_iter *iter, + const struct Curl_addrinfo *list, + int ai_family) +{ + iter->head = list; + iter->ai_family = ai_family; + iter->last = NULL; + iter->n = -1; +} + +static const struct Curl_addrinfo *cf_ai_iter_next(struct cf_ai_iter *iter) +{ + const struct Curl_addrinfo *addr; + if(iter->n < 0) { + iter->n++; + for(addr = iter->head; addr; addr = addr->ai_next) { + if(addr->ai_family == iter->ai_family) + break; + } + iter->last = addr; + } + else if(iter->last) { + iter->n++; + for(addr = iter->last->ai_next; addr; addr = addr->ai_next) { + if(addr->ai_family == iter->ai_family) + break; + } + iter->last = addr; + } + return iter->last; +} + +#ifdef USE_IPV6 +static bool cf_ai_iter_done(struct cf_ai_iter *iter) +{ + return (iter->n >= 0) && !iter->last; +} +#endif + +struct cf_ip_attempt { + struct cf_ip_attempt *next; + const struct Curl_addrinfo *addr; /* List of addresses to try, not owned */ + struct Curl_cfilter *cf; /* current sub-cfilter connecting */ + cf_ip_connect_create *cf_create; + struct curltime started; /* start of current attempt */ + CURLcode result; + int ai_family; + int transport; + int error; + BIT(connected); /* cf has connected */ + BIT(shutdown); /* cf has shutdown */ + BIT(inconclusive); /* connect was not a hard failure, we + * might talk to a restarting server */ +}; + +static void cf_ip_attempt_free(struct cf_ip_attempt *a, + struct Curl_easy *data) +{ + if(a) { + if(a->cf) + Curl_conn_cf_discard_chain(&a->cf, data); + free(a); + } +} + +static CURLcode cf_ip_attempt_new(struct cf_ip_attempt **pa, + struct Curl_cfilter *cf, + struct Curl_easy *data, + const struct Curl_addrinfo *addr, + int ai_family, + int transport, + cf_ip_connect_create *cf_create) +{ + struct Curl_cfilter *wcf; + struct cf_ip_attempt *a; + CURLcode result = CURLE_OK; + + *pa = NULL; + a = calloc(1, sizeof(*a)); + if(!a) + return CURLE_OUT_OF_MEMORY; + + a->addr = addr; + a->ai_family = ai_family; + a->transport = transport; + a->result = CURLE_OK; + a->cf_create = cf_create; + *pa = a; + + result = a->cf_create(&a->cf, data, cf->conn, a->addr, transport); + if(result) + goto out; + + /* the new filter might have sub-filters */ + for(wcf = a->cf; wcf; wcf = wcf->next) { + wcf->conn = cf->conn; + wcf->sockindex = cf->sockindex; + } + +out: + if(result) { + cf_ip_attempt_free(a, data); + *pa = NULL; + } + return result; +} + +static CURLcode cf_ip_attempt_connect(struct cf_ip_attempt *a, + struct Curl_easy *data, + bool *connected) +{ + *connected = a->connected; + if(!a->result && !*connected) { + /* evaluate again */ + a->result = Curl_conn_cf_connect(a->cf, data, connected); + + if(!a->result) { + if(*connected) { + a->connected = TRUE; + } + } + else if(a->result == CURLE_WEIRD_SERVER_REPLY) + a->inconclusive = TRUE; + } + return a->result; +} + +struct cf_ip_ballers { + struct cf_ip_attempt *running; + struct cf_ip_attempt *winner; + struct cf_ai_iter addr_iter; +#ifdef USE_IPV6 + struct cf_ai_iter ipv6_iter; +#endif + cf_ip_connect_create *cf_create; /* for creating cf */ + struct curltime started; + struct curltime last_attempt_started; + timediff_t attempt_delay_ms; + int last_attempt_ai_family; + int transport; +}; + +static CURLcode cf_ip_attempt_restart(struct cf_ip_attempt *a, + struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct Curl_cfilter *cf_prev = a->cf; + struct Curl_cfilter *wcf; + CURLcode result; + + /* When restarting, we tear down and existing filter *after* we + * started up the new one. This gives us a new socket number and + * probably a new local port. Which may prevent confusion. */ + a->result = CURLE_OK; + a->connected = FALSE; + a->inconclusive = FALSE; + a->cf = NULL; + + result = a->cf_create(&a->cf, data, cf->conn, a->addr, a->transport); + if(!result) { + bool dummy; + /* the new filter might have sub-filters */ + for(wcf = a->cf; wcf; wcf = wcf->next) { + wcf->conn = cf->conn; + wcf->sockindex = cf->sockindex; + } + a->result = cf_ip_attempt_connect(a, data, &dummy); + } + if(cf_prev) + Curl_conn_cf_discard_chain(&cf_prev, data); + return result; +} + +static void cf_ip_ballers_clear(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct cf_ip_ballers *bs) +{ + (void)cf; + while(bs->running) { + struct cf_ip_attempt *a = bs->running; + bs->running = a->next; + cf_ip_attempt_free(a, data); + } + cf_ip_attempt_free(bs->winner, data); + bs->winner = NULL; +} + +static CURLcode cf_ip_ballers_init(struct cf_ip_ballers *bs, int ip_version, + const struct Curl_addrinfo *addr_list, + cf_ip_connect_create *cf_create, + int transport, + timediff_t attempt_delay_ms) +{ + memset(bs, 0, sizeof(*bs)); + bs->cf_create = cf_create; + bs->transport = transport; + bs->attempt_delay_ms = attempt_delay_ms; + bs->last_attempt_ai_family = AF_INET; /* so AF_INET6 is next */ + + if(transport == TRNSPRT_UNIX) { +#ifdef USE_UNIX_SOCKETS + cf_ai_iter_init(&bs->addr_iter, addr_list, AF_UNIX); +#else + return CURLE_UNSUPPORTED_PROTOCOL; +#endif + } + else { /* TCP/UDP/QUIC */ +#ifdef USE_IPV6 + if(ip_version == CURL_IPRESOLVE_V6) + cf_ai_iter_init(&bs->addr_iter, NULL, AF_INET); + else + cf_ai_iter_init(&bs->addr_iter, addr_list, AF_INET); + + if(ip_version == CURL_IPRESOLVE_V4) + cf_ai_iter_init(&bs->ipv6_iter, NULL, AF_INET6); + else + cf_ai_iter_init(&bs->ipv6_iter, addr_list, AF_INET6); +#else + (void)ip_version; + cf_ai_iter_init(&bs->addr_iter, addr_list, AF_INET); +#endif + } + return CURLE_OK; +} + +static CURLcode cf_ip_ballers_run(struct cf_ip_ballers *bs, + struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *connected) +{ + CURLcode result = CURLE_OK; + struct cf_ip_attempt *a = NULL, **panchor; + bool do_more, more_possible; + struct curltime now; + timediff_t next_expire_ms; + int i, inconclusive, ongoing; + + if(bs->winner) + return CURLE_OK; + +evaluate: + now = curlx_now(); + ongoing = inconclusive = 0; + more_possible = TRUE; + + /* check if a running baller connects now */ + i = -1; + for(panchor = &bs->running; *panchor; panchor = &((*panchor)->next)) { + ++i; + a = *panchor; + a->result = cf_ip_attempt_connect(a, data, connected); + if(!a->result) { + if(*connected) { + /* connected, declare the winner, remove from running, + * clear remaining running list. */ + CURL_TRC_CF(data, cf, "connect attempt #%d successful", i); + bs->winner = a; + *panchor = a->next; + a->next = NULL; + while(bs->running) { + a = bs->running; + bs->running = a->next; + cf_ip_attempt_free(a, data); + } + return CURLE_OK; + } + /* still running */ + ++ongoing; + } + else if(a->inconclusive) /* failed, but inconclusive */ + ++inconclusive; + } + if(bs->running) + CURL_TRC_CF(data, cf, "checked connect attempts: " + "%d ongoing, %d inconclusive", ongoing, inconclusive); + + /* no attempt connected yet, start another one? */ + if(!ongoing) { + if(!bs->started.tv_sec && !bs->started.tv_usec) + bs->started = now; + do_more = TRUE; + } + else { + do_more = (curlx_timediff(now, bs->last_attempt_started) >= + bs->attempt_delay_ms); + if(do_more) + CURL_TRC_CF(data, cf, "happy eyeballs timeout expired, " + "start next attempt"); + } + + if(do_more) { + /* start the next attempt if there is another ip address to try. + * Alternate between address families when possible. */ + const struct Curl_addrinfo *addr = NULL; + int ai_family = 0; +#ifdef USE_IPV6 + if((bs->last_attempt_ai_family == AF_INET) || + cf_ai_iter_done(&bs->addr_iter)) { + addr = cf_ai_iter_next(&bs->ipv6_iter); + ai_family = bs->ipv6_iter.ai_family; + } +#endif + if(!addr) { + addr = cf_ai_iter_next(&bs->addr_iter); + ai_family = bs->addr_iter.ai_family; + } + + if(addr) { /* try another address */ + result = cf_ip_attempt_new(&a, cf, data, addr, ai_family, + bs->transport, bs->cf_create); + CURL_TRC_CF(data, cf, "starting %s attempt for ipv%s -> %d", + bs->running ? "next" : "first", + (ai_family == AF_INET) ? "4" : "6", result); + if(result) + goto out; + DEBUGASSERT(a); + + /* append to running list */ + panchor = &bs->running; + while(*panchor) + panchor = &((*panchor)->next); + *panchor = a; + bs->last_attempt_started = now; + bs->last_attempt_ai_family = ai_family; + /* and run everything again */ + goto evaluate; + } + else if(inconclusive) { + /* tried all addresses, no success but some where inconclusive. + * Let's restart the inconclusive ones. */ + if(curlx_timediff(now, bs->last_attempt_started) >= + bs->attempt_delay_ms) { + CURL_TRC_CF(data, cf, "tried all addresses with inconclusive results" + ", restarting one"); + i = -1; + for(a = bs->running; a; a = a->next) { + ++i; + if(!a->inconclusive) + continue; + result = cf_ip_attempt_restart(a, cf, data); + CURL_TRC_CF(data, cf, "restarted baller %d -> %d", i, result); + if(result) /* serious failure */ + goto out; + bs->last_attempt_started = now; + goto evaluate; + } + DEBUGASSERT(0); /* should not come here */ + } + /* attempt timeout for restart has not expired yet */ + goto out; + } + else if(ongoing) { + /* no more addresses, no inconclusive attempts */ + more_possible = FALSE; + } + else { + CURL_TRC_CF(data, cf, "no more attempts to try"); + result = CURLE_COULDNT_CONNECT; + i = 0; + for(a = bs->running; a; a = a->next) { + CURL_TRC_CF(data, cf, "baller %d: result=%d", i, a->result); + if(a->result) + result = a->result; + } + } + } + +out: + if(!result) { + /* when do we need to be called again? */ + next_expire_ms = Curl_timeleft(data, &now, TRUE); + if(more_possible) { + timediff_t expire_ms, elapsed_ms; + elapsed_ms = curlx_timediff(now, bs->last_attempt_started); + expire_ms = CURLMAX(bs->attempt_delay_ms - elapsed_ms, 0); + next_expire_ms = CURLMIN(next_expire_ms, expire_ms); + } + + if(next_expire_ms <= 0) { + failf(data, "Connection timeout after %" FMT_OFF_T " ms", + curlx_timediff(now, data->progress.t_startsingle)); + return CURLE_OPERATION_TIMEDOUT; + } + Curl_expire(data, next_expire_ms, EXPIRE_HAPPY_EYEBALLS); + } + return result; +} + +static CURLcode cf_ip_ballers_shutdown(struct cf_ip_ballers *bs, + struct Curl_easy *data, + bool *done) +{ + struct cf_ip_attempt *a; + + /* shutdown all ballers that have not done so already. If one fails, + * continue shutting down others until all are shutdown. */ + *done = TRUE; + for(a = bs->running; a; a = a->next) { + bool bdone = FALSE; + if(a->shutdown) + continue; + a->result = a->cf->cft->do_shutdown(a->cf, data, &bdone); + if(a->result || bdone) + a->shutdown = TRUE; /* treat a failed shutdown as done */ + else + *done = FALSE; + } + return CURLE_OK; +} + +static CURLcode cf_ip_ballers_pollset(struct cf_ip_ballers *bs, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_ip_attempt *a; + CURLcode result = CURLE_OK; + for(a = bs->running; a && !result; a = a->next) { + if(a->result) + continue; + result = Curl_conn_cf_adjust_pollset(a->cf, data, ps); + } + return result; +} + +static bool cf_ip_ballers_pending(struct cf_ip_ballers *bs, + const struct Curl_easy *data) +{ + struct cf_ip_attempt *a; + + for(a = bs->running; a; a = a->next) { + if(a->result) + continue; + if(a->cf->cft->has_data_pending(a->cf, data)) + return TRUE; + } + return FALSE; +} + +static struct curltime cf_ip_ballers_max_time(struct cf_ip_ballers *bs, + struct Curl_easy *data, + int query) +{ + struct curltime t, tmax; + struct cf_ip_attempt *a; + + memset(&tmax, 0, sizeof(tmax)); + for(a = bs->running; a; a = a->next) { + memset(&t, 0, sizeof(t)); + if(!a->cf->cft->query(a->cf, data, query, NULL, &t)) { + if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0) + tmax = t; + } + } + return tmax; +} + +static int cf_ip_ballers_min_reply_ms(struct cf_ip_ballers *bs, + struct Curl_easy *data) +{ + int reply_ms = -1, breply_ms; + struct cf_ip_attempt *a; + + for(a = bs->running; a; a = a->next) { + if(!a->cf->cft->query(a->cf, data, CF_QUERY_CONNECT_REPLY_MS, + &breply_ms, NULL)) { + if(breply_ms >= 0 && (reply_ms < 0 || breply_ms < reply_ms)) + reply_ms = breply_ms; + } + } + return reply_ms; +} + + +typedef enum { + SCFST_INIT, + SCFST_WAITING, + SCFST_DONE +} cf_connect_state; + +struct cf_ip_happy_ctx { + int transport; + cf_ip_connect_create *cf_create; + cf_connect_state state; + struct cf_ip_ballers ballers; + struct curltime started; +}; + + +static CURLcode is_connected(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *connected) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + struct connectdata *conn = cf->conn; + CURLcode result; + + result = cf_ip_ballers_run(&ctx->ballers, cf, data, connected); + + if(!result) + return CURLE_OK; + + { + const char *hostname, *proxy_name = NULL; + int port; +#ifndef CURL_DISABLE_PROXY + if(conn->bits.socksproxy) + proxy_name = conn->socks_proxy.host.name; + else if(conn->bits.httpproxy) + proxy_name = conn->http_proxy.host.name; +#endif + hostname = conn->bits.conn_to_host ? + conn->conn_to_host.name : conn->host.name; + + if(cf->sockindex == SECONDARYSOCKET) + port = conn->secondary_port; + else if(cf->conn->bits.conn_to_port) + port = conn->conn_to_port; + else + port = conn->remote_port; + + failf(data, "Failed to connect to %s port %u %s%s%safter " + "%" FMT_TIMEDIFF_T " ms: %s", + hostname, port, + proxy_name ? "via " : "", + proxy_name ? proxy_name : "", + proxy_name ? " " : "", + curlx_timediff(curlx_now(), data->progress.t_startsingle), + curl_easy_strerror(result)); + } + +#ifdef SOCKETIMEDOUT + if(SOCKETIMEDOUT == data->state.os_errno) + result = CURLE_OPERATION_TIMEDOUT; +#endif + + return result; +} + +/* + * Connect to the given host with timeout, proxy or remote does not matter. + * There might be more than one IP address to try out. + */ +static CURLcode start_connect(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + struct Curl_dns_entry *dns = data->state.dns[cf->sockindex]; + + if(!dns) + return CURLE_FAILED_INIT; + + if(Curl_timeleft(data, NULL, TRUE) < 0) { + /* a precaution, no need to continue if time already is up */ + failf(data, "Connection time-out"); + return CURLE_OPERATION_TIMEDOUT; + } + + CURL_TRC_CF(data, cf, "init ip ballers for transport %d", ctx->transport); + ctx->started = curlx_now(); + return cf_ip_ballers_init(&ctx->ballers, cf->conn->ip_version, + dns->addr, ctx->cf_create, ctx->transport, + data->set.happy_eyeballs_timeout); +} + +static void cf_ip_happy_ctx_clear(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + + DEBUGASSERT(ctx); + DEBUGASSERT(data); + cf_ip_ballers_clear(cf, data, &ctx->ballers); +} + +static CURLcode cf_ip_happy_shutdown(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + DEBUGASSERT(data); + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + result = cf_ip_ballers_shutdown(&ctx->ballers, data, done); + CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done); + return result; +} + +static CURLcode cf_ip_happy_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(!cf->connected) { + result = cf_ip_ballers_pollset(&ctx->ballers, data, ps); + CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %d socks", result, ps->n); + } + return result; +} + +static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf, + struct Curl_easy *data, + bool *done) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; + + if(cf->connected) { + *done = TRUE; + return CURLE_OK; + } + + DEBUGASSERT(ctx); + *done = FALSE; + + switch(ctx->state) { + case SCFST_INIT: + DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data)); + DEBUGASSERT(!cf->connected); + result = start_connect(cf, data); + if(result) + return result; + ctx->state = SCFST_WAITING; + FALLTHROUGH(); + case SCFST_WAITING: + result = is_connected(cf, data, done); + if(!result && *done) { + DEBUGASSERT(ctx->ballers.winner); + DEBUGASSERT(ctx->ballers.winner->cf); + DEBUGASSERT(ctx->ballers.winner->cf->connected); + /* we have a winner. Install and activate it. + * close/free all others. */ + ctx->state = SCFST_DONE; + cf->connected = TRUE; + cf->next = ctx->ballers.winner->cf; + ctx->ballers.winner->cf = NULL; + cf_ip_happy_ctx_clear(cf, data); + Curl_expire_done(data, EXPIRE_HAPPY_EYEBALLS); + + if(cf->conn->handler->protocol & PROTO_FAMILY_SSH) + Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_cf_is_verbose(cf, data)) { + struct ip_quadruple ipquad; + bool is_ipv6; + if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) { + const char *host; + int port; + Curl_conn_get_current_host(data, cf->sockindex, &host, &port); + CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u", + host, ipquad.remote_ip, ipquad.remote_port); + } + } +#endif + data->info.numconnects++; /* to track the # of connections made */ + } + break; + case SCFST_DONE: + *done = TRUE; + break; + } + return result; +} + +static void cf_ip_happy_close(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + + CURL_TRC_CF(data, cf, "close"); + cf_ip_happy_ctx_clear(cf, data); + cf->connected = FALSE; + ctx->state = SCFST_INIT; + + if(cf->next) { + cf->next->cft->do_close(cf->next, data); + Curl_conn_cf_discard_chain(&cf->next, data); + } +} + +static bool cf_ip_happy_data_pending(struct Curl_cfilter *cf, + const struct Curl_easy *data) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + + if(!cf->connected) { + return cf_ip_ballers_pending(&ctx->ballers, data); + } + return cf->next->cft->has_data_pending(cf->next, data); +} + +static CURLcode cf_ip_happy_query(struct Curl_cfilter *cf, + struct Curl_easy *data, + int query, int *pres1, void *pres2) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + + if(!cf->connected) { + switch(query) { + case CF_QUERY_CONNECT_REPLY_MS: { + *pres1 = cf_ip_ballers_min_reply_ms(&ctx->ballers, data); + CURL_TRC_CF(data, cf, "query connect reply: %dms", *pres1); + return CURLE_OK; + } + case CF_QUERY_TIMER_CONNECT: { + struct curltime *when = pres2; + *when = cf_ip_ballers_max_time(&ctx->ballers, data, + CF_QUERY_TIMER_CONNECT); + return CURLE_OK; + } + case CF_QUERY_TIMER_APPCONNECT: { + struct curltime *when = pres2; + *when = cf_ip_ballers_max_time(&ctx->ballers, data, + CF_QUERY_TIMER_APPCONNECT); + return CURLE_OK; + } + default: + break; + } + } + + return cf->next ? + cf->next->cft->query(cf->next, data, query, pres1, pres2) : + CURLE_UNKNOWN_OPTION; +} + +static void cf_ip_happy_destroy(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + struct cf_ip_happy_ctx *ctx = cf->ctx; + + CURL_TRC_CF(data, cf, "destroy"); + if(ctx) { + cf_ip_happy_ctx_clear(cf, data); + } + /* release any resources held in state */ + Curl_safefree(ctx); +} + +struct Curl_cftype Curl_cft_ip_happy = { + "HAPPY-EYEBALLS", + 0, + CURL_LOG_LVL_NONE, + cf_ip_happy_destroy, + cf_ip_happy_connect, + cf_ip_happy_close, + cf_ip_happy_shutdown, + cf_ip_happy_adjust_pollset, + cf_ip_happy_data_pending, + Curl_cf_def_send, + Curl_cf_def_recv, + Curl_cf_def_cntrl, + Curl_cf_def_conn_is_alive, + Curl_cf_def_conn_keep_alive, + cf_ip_happy_query, +}; + +/** + * Create an IP happy eyeball connection filter that uses the, once resolved, + * address information to connect on ip families based on connection + * configuration. + * @param pcf output, the created cfilter + * @param data easy handle used in creation + * @param conn connection the filter is created for + * @param cf_create method to create the sub-filters performing the + * actual connects. + */ +static CURLcode cf_ip_happy_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + cf_ip_connect_create *cf_create, + int transport) +{ + struct cf_ip_happy_ctx *ctx = NULL; + CURLcode result; + + (void)data; + (void)conn; + *pcf = NULL; + ctx = calloc(1, sizeof(*ctx)); + if(!ctx) { + result = CURLE_OUT_OF_MEMORY; + goto out; + } + ctx->transport = transport; + ctx->cf_create = cf_create; + + result = Curl_cf_create(pcf, &Curl_cft_ip_happy, ctx); + +out: + if(result) { + Curl_safefree(*pcf); + free(ctx); + } + return result; +} + +CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data, + int transport) +{ + cf_ip_connect_create *cf_create; + struct Curl_cfilter *cf; + CURLcode result; + + /* Need to be first */ + DEBUGASSERT(cf_at); + cf_create = get_cf_create(transport); + if(!cf_create) { + CURL_TRC_CF(data, cf_at, "unsupported transport type %d", transport); + return CURLE_UNSUPPORTED_PROTOCOL; + } + result = cf_ip_happy_create(&cf, data, cf_at->conn, cf_create, transport); + if(result) + return result; + + Curl_conn_cf_insert_after(cf_at, cf); + return CURLE_OK; +} diff --git a/deps/curl/lib/cf-ip-happy.h b/deps/curl/lib/cf-ip-happy.h new file mode 100644 index 00000000000..96e619ae430 --- /dev/null +++ b/deps/curl/lib/cf-ip-happy.h @@ -0,0 +1,59 @@ +#ifndef HEADER_CURL_IP_HAPPY_H +#define HEADER_CURL_IP_HAPPY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at https://curl.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + * SPDX-License-Identifier: curl + * + ***************************************************************************/ +#include "curl_setup.h" + +#include "curlx/nonblock.h" /* for curlx_nonblock() */ +#include "sockaddr.h" + +/** + * Create a cfilter for making an "ip" connection to the + * given address, using parameters from `conn`. The "ip" connection + * can be a TCP socket, a UDP socket or even a QUIC connection. + * + * It MUST use only the supplied `ai` for its connection attempt. + * + * Such a filter may be used in "happy eyeball" scenarios, and its + * `connect` implementation needs to support non-blocking. Once connected, + * it MAY be installed in the connection filter chain to serve transfers. + */ +typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf, + struct Curl_easy *data, + struct connectdata *conn, + const struct Curl_addrinfo *ai, + int transport); + +CURLcode cf_ip_happy_insert_after(struct Curl_cfilter *cf_at, + struct Curl_easy *data, + int transport); + +extern struct Curl_cftype Curl_cft_ip_happy; + +#ifdef UNITTESTS +void Curl_debug_set_transport_provider(int transport, + cf_ip_connect_create *cf_create); +#endif + +#endif /* HEADER_CURL_IP_HAPPY_H */ diff --git a/deps/curl/lib/cf-socket.c b/deps/curl/lib/cf-socket.c index 273258feaf2..f449ca36caf 100644 --- a/deps/curl/lib/cf-socket.c +++ b/deps/curl/lib/cf-socket.c @@ -109,7 +109,7 @@ static void set_ipv6_v6only(curl_socket_t sockfd, int on) static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd) { -#if defined(TCP_NODELAY) +#if defined(TCP_NODELAY) && defined(CURL_TCP_NODELAY_SUPPORTED) curl_socklen_t onoff = (curl_socklen_t) 1; int level = IPPROTO_TCP; char buffer[STRERROR_LEN]; @@ -136,7 +136,7 @@ static void nosigpipe(struct Curl_easy *data, (void)data; if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff, sizeof(onoff)) < 0) { -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS char buffer[STRERROR_LEN]; infof(data, "Could not set SO_NOSIGPIPE: %s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer))); @@ -164,6 +164,7 @@ static void nosigpipe(struct Curl_easy *data, #define KEEPALIVE_FACTOR(x) #endif +/* Offered by mingw-w64 and MS SDK. Latter only when targeting Win7+. */ #if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS) #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4) @@ -188,9 +189,9 @@ tcpkeepalive(struct Curl_easy *data, sockfd, SOCKERRNO); } else { -#if defined(SIO_KEEPALIVE_VALS) /* Windows */ +#ifdef SIO_KEEPALIVE_VALS /* Windows */ /* Windows 10, version 1709 (10.0.16299) and later versions */ -#if defined(CURL_WINSOCK_KEEP_SSO) +#ifdef CURL_WINSOCK_KEEP_SSO optval = curlx_sltosi(data->set.tcp_keepidle); KEEPALIVE_FACTOR(optval); if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, @@ -307,9 +308,9 @@ tcpkeepalive(struct Curl_easy *data, * Assign the address `ai` to the Curl_sockaddr_ex `dest` and * set the transport used. */ -CURLcode Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest, - const struct Curl_addrinfo *ai, - int transport) +static CURLcode sock_assign_addr(struct Curl_sockaddr_ex *dest, + const struct Curl_addrinfo *ai, + int transport) { /* * The Curl_sockaddr_ex structure is basically libcurl's external API @@ -406,7 +407,7 @@ CURLcode Curl_socket_open(struct Curl_easy *data, /* if the caller does not want info back, use a local temp copy */ addr = &dummy; - result = Curl_sock_assign_addr(addr, ai, transport); + result = sock_assign_addr(addr, ai, transport); if(result) return result; @@ -844,7 +845,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) #endif - if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize)) + if(getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize)) err = SOCKERRNO; #ifdef UNDER_CE /* Old Windows CE versions do not support SO_ERROR */ @@ -860,7 +861,7 @@ static bool verifyconnect(curl_socket_t sockfd, int *error) err = 0; } #endif - if((0 == err) || (SOCKEISCONN == err)) + if((err == 0) || (SOCKEISCONN == err)) /* we are connected, awesome! */ rc = TRUE; else @@ -885,7 +886,7 @@ static CURLcode socket_connect_result(struct Curl_easy *data, switch(error) { case SOCKEINPROGRESS: case SOCKEWOULDBLOCK: -#if defined(EAGAIN) +#ifdef EAGAIN #if (EAGAIN) != (SOCKEWOULDBLOCK) /* On some platforms EAGAIN and EWOULDBLOCK are the * same value, and on others they are different, hence @@ -949,7 +950,7 @@ static CURLcode cf_socket_ctx_init(struct cf_socket_ctx *ctx, ctx->sock = CURL_SOCKET_BAD; ctx->transport = transport; - result = Curl_sock_assign_addr(&ctx->addr, ai, transport); + result = sock_assign_addr(&ctx->addr, ai, transport); if(result) return result; @@ -1237,8 +1238,8 @@ static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data, (void)data; if(is_tcp_fastopen) { -#if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */ -# if defined(HAVE_BUILTIN_AVAILABLE) +#ifdef CONNECT_DATA_IDEMPOTENT /* Darwin */ +# ifdef HAVE_BUILTIN_AVAILABLE /* while connectx function is available since macOS 10.11 / iOS 9, it did not have the interface declared correctly until Xcode 9 / macOS SDK 10.13 */ @@ -1375,11 +1376,12 @@ static CURLcode cf_tcp_connect(struct Curl_cfilter *cf, return result; } -static void cf_socket_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_socket_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_socket_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; if(ctx->sock != CURL_SOCKET_BAD) { /* A listening socket filter needs to be connected before the accept @@ -1387,25 +1389,27 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf, * FTP no longer does the socket checks and accept calls and delegates * all that to the filter. */ if(ctx->listening) { - Curl_pollset_set_in_only(data, ps, ctx->sock); + result = Curl_pollset_set_in_only(data, ps, ctx->sock); CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%" FMT_SOCKET_T, ctx->sock); } else if(!cf->connected) { - Curl_pollset_set_out_only(data, ps, ctx->sock); + result = Curl_pollset_set_out_only(data, ps, ctx->sock); CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%" FMT_SOCKET_T, ctx->sock); } else if(!ctx->active) { - Curl_pollset_add_in(data, ps, ctx->sock); + result = Curl_pollset_add_in(data, ps, ctx->sock); CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%" FMT_SOCKET_T, ctx->sock); } } + return result; } #ifdef USE_WINSOCK +/* Offered by mingw-w64 v13+. MS SDK 7.0A+. */ #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B #endif @@ -1440,7 +1444,7 @@ static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, size_t orig_len = len; CURLcode result = CURLE_OK; - (void)eos; /* unused */ + (void)eos; *pnwritten = 0; fdsave = cf->conn->sock[cf->sockindex]; cf->conn->sock[cf->sockindex] = ctx->sock; @@ -1505,7 +1509,7 @@ static CURLcode cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data, else *pnwritten = (size_t)nwritten; -#if defined(USE_WINSOCK) +#ifdef USE_WINSOCK if(!result) win_update_sndbuf_size(ctx); #endif @@ -1600,15 +1604,10 @@ static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data) /* use this socket from now on */ cf->conn->sock[cf->sockindex] = ctx->sock; set_local_ip(cf, data); - if(cf->sockindex == FIRSTSOCKET) { - cf->conn->primary = ctx->ip; - #ifdef USE_IPV6 +#ifdef USE_IPV6 + if(cf->sockindex == FIRSTSOCKET) cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6); - #endif - } - else { - cf->conn->secondary = ctx->ip; - } +#endif ctx->active = TRUE; } @@ -2111,13 +2110,13 @@ static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf, return CURLE_OK; } - if(0 == getsockname(ctx->sock, (struct sockaddr *) &add, &size)) { + if(!getsockname(ctx->sock, (struct sockaddr *) &add, &size)) { size = sizeof(add); #ifdef HAVE_ACCEPT4 s_accepted = accept4(ctx->sock, (struct sockaddr *) &add, &size, SOCK_NONBLOCK | SOCK_CLOEXEC); #else - s_accepted = accept(ctx->sock, (struct sockaddr *) &add, &size); + s_accepted = CURL_ACCEPT(ctx->sock, (struct sockaddr *) &add, &size); #endif } diff --git a/deps/curl/lib/cf-socket.h b/deps/curl/lib/cf-socket.h index 90daf079a01..88c08fe7c0c 100644 --- a/deps/curl/lib/cf-socket.h +++ b/deps/curl/lib/cf-socket.h @@ -91,14 +91,6 @@ void Curl_sndbuf_init(curl_socket_t sockfd); #define Curl_sndbuf_init(y) Curl_nop_stmt #endif -/** - * Assign the address `ai` to the Curl_sockaddr_ex `dest` and - * set the transport used. - */ -CURLcode Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest, - const struct Curl_addrinfo *ai, - int transport); - /** * Creates a cfilter that opens a TCP socket to the given address * when calling its `connect` implementation. diff --git a/deps/curl/lib/cfilters.c b/deps/curl/lib/cfilters.c index 01f1e282183..efd2ac6f63d 100644 --- a/deps/curl/lib/cfilters.c +++ b/deps/curl/lib/cfilters.c @@ -67,14 +67,15 @@ CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf, static void conn_report_connect_stats(struct Curl_easy *data, struct connectdata *conn); -void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +CURLcode Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { /* NOP */ (void)cf; (void)data; (void)ps; + return CURLE_OK; } bool Curl_cf_def_data_pending(struct Curl_cfilter *cf, @@ -176,6 +177,10 @@ CURLcode Curl_conn_shutdown(struct Curl_easy *data, int sockindex, bool *done) struct curltime now; DEBUGASSERT(data->conn); + + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; + /* Get the first connected filter that is not shut down already. */ cf = data->conn->cfilter[sockindex]; while(cf && (!cf->connected || cf->shutdown)) @@ -439,6 +444,29 @@ CURLcode Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data, return CURLE_RECV_ERROR; } +#ifndef CURL_DISABLE_VERBOSE_STRINGS +static CURLcode cf_verboseconnect(struct Curl_easy *data, + struct Curl_cfilter *cf) +{ + if(Curl_trc_is_verbose(data)) { + struct ip_quadruple ipquad; + bool is_ipv6; + CURLcode result; + + result = Curl_conn_cf_get_ip_info(cf, data, &is_ipv6, &ipquad); + if(result) + return result; + + infof(data, "Established %sconnection to %s (%s port %u) from %s port %u ", + (cf->sockindex == SECONDARYSOCKET) ? "2nd " : "", + CURL_CONN_HOST_DISPNAME(data->conn), + ipquad.remote_ip, ipquad.remote_port, + ipquad.local_ip, ipquad.local_port); + } + return CURLE_OK; +} +#endif + CURLcode Curl_conn_connect(struct Curl_easy *data, int sockindex, bool blocking, @@ -446,12 +474,15 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, { #define CF_CONN_NUM_POLLS_ON_STACK 5 struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK]; + struct easy_pollset ps; struct curl_pollfds cpfds; struct Curl_cfilter *cf; CURLcode result = CURLE_OK; DEBUGASSERT(data); DEBUGASSERT(data->conn); + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; cf = data->conn->cfilter[sockindex]; if(!cf) { @@ -463,6 +494,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, if(*done) return CURLE_OK; + Curl_pollset_init(&ps); Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK); while(!*done) { if(Curl_conn_needs_flush(data, sockindex)) { @@ -482,7 +514,9 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, cf_cntrl_update_info(data, data->conn); conn_report_connect_stats(data, data->conn); data->conn->keepalive = curlx_now(); - Curl_verboseconnect(data, data->conn, sockindex); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + result = cf_verboseconnect(data, cf); +#endif goto out; } else if(result) { @@ -498,7 +532,6 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, /* check allowed time left */ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data); - struct easy_pollset ps; int rc; if(timeout_ms < 0) { @@ -509,12 +542,14 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, } CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll"); + Curl_pollset_reset(&ps); Curl_pollfds_reset(&cpfds); - memset(&ps, 0, sizeof(ps)); /* In general, we want to send after connect, wait on that. */ if(sockfd != CURL_SOCKET_BAD) Curl_pollset_set_out_only(data, &ps, sockfd); - Curl_conn_adjust_pollset(data, data->conn, &ps); + result = Curl_conn_adjust_pollset(data, data->conn, &ps); + if(result) + goto out; result = Curl_pollfds_add_ps(&cpfds, &ps); if(result) goto out; @@ -532,12 +567,15 @@ CURLcode Curl_conn_connect(struct Curl_easy *data, } out: + Curl_pollset_cleanup(&ps); Curl_pollfds_cleanup(&cpfds); return result; } bool Curl_conn_is_setup(struct connectdata *conn, int sockindex) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; return (conn->cfilter[sockindex] != NULL); } @@ -545,6 +583,8 @@ bool Curl_conn_is_connected(struct connectdata *conn, int sockindex) { struct Curl_cfilter *cf; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; cf = conn->cfilter[sockindex]; return cf && cf->connected; } @@ -553,6 +593,8 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex) { struct Curl_cfilter *cf; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; cf = data->conn->cfilter[sockindex]; while(cf) { if(cf->connected) @@ -564,7 +606,7 @@ bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex) return FALSE; } -bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf) +static bool cf_is_ssl(struct Curl_cfilter *cf) { for(; cf; cf = cf->next) { if(cf->cft->flags & CF_TYPE_SSL) @@ -577,13 +619,17 @@ bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf) bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex) { - return conn ? Curl_conn_cf_is_ssl(conn->cfilter[sockindex]) : FALSE; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; + return conn ? cf_is_ssl(conn->cfilter[sockindex]) : FALSE; } bool Curl_conn_get_ssl_info(struct Curl_easy *data, struct connectdata *conn, int sockindex, struct curl_tlssessioninfo *info) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; if(Curl_conn_is_ssl(conn, sockindex)) { struct Curl_cfilter *cf = conn->cfilter[sockindex]; CURLcode result = cf ? cf->cft->query(cf, data, CF_QUERY_SSL_INFO, @@ -593,9 +639,24 @@ bool Curl_conn_get_ssl_info(struct Curl_easy *data, return FALSE; } +CURLcode Curl_conn_get_ip_info(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + bool *is_ipv6, struct ip_quadruple *ipquad) +{ + struct Curl_cfilter *cf; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; + cf = conn ? conn->cfilter[sockindex] : NULL; + return Curl_conn_cf_get_ip_info(cf, data, is_ipv6, ipquad); +} + bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex) { - struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; + struct Curl_cfilter *cf; + + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; + cf = conn ? conn->cfilter[sockindex] : NULL; for(; cf; cf = cf->next) { if(cf->cft->flags & CF_TYPE_MULTIPLEX) @@ -613,6 +674,13 @@ unsigned char Curl_conn_get_transport(struct Curl_easy *data, return Curl_conn_cf_get_transport(cf, data); } +const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data, + struct connectdata *conn) +{ + struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET]; + return Curl_conn_cf_get_alpn_negotiated(cf, data); +} + unsigned char Curl_conn_http_version(struct Curl_easy *data, struct connectdata *conn) { @@ -644,6 +712,8 @@ bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex) (void)data; DEBUGASSERT(data); DEBUGASSERT(data->conn); + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; cf = data->conn->cfilter[sockindex]; while(cf && !cf->connected) { @@ -667,13 +737,16 @@ bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf, bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return FALSE; return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data); } -void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +CURLcode Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { + CURLcode result = CURLE_OK; /* Get the lowest not-connected filter, if there are any */ while(cf && !cf->connected && cf->next && !cf->next->connected) cf = cf->next; @@ -682,23 +755,26 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, cf = cf->next; /* From there on, give all filters a chance to adjust the pollset. * Lower filters are called later, so they may override */ - while(cf) { - cf->cft->adjust_pollset(cf, data, ps); + while(cf && !result) { + result = cf->cft->adjust_pollset(cf, data, ps); cf = cf->next; } + return result; } -void Curl_conn_adjust_pollset(struct Curl_easy *data, - struct connectdata *conn, - struct easy_pollset *ps) +CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data, + struct connectdata *conn, + struct easy_pollset *ps) { + CURLcode result = CURLE_OK; int i; DEBUGASSERT(data); DEBUGASSERT(conn); - for(i = 0; i < 2; ++i) { - Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps); + for(i = 0; (i < 2) && !result; ++i) { + result = Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps); } + return result; } int Curl_conn_cf_poll(struct Curl_cfilter *cf, @@ -706,35 +782,18 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf, timediff_t timeout_ms) { struct easy_pollset ps; - struct pollfd pfds[MAX_SOCKSPEREASYHANDLE]; - unsigned int i, npfds = 0; + int result; DEBUGASSERT(cf); DEBUGASSERT(data); DEBUGASSERT(data->conn); - memset(&ps, 0, sizeof(ps)); - memset(pfds, 0, sizeof(pfds)); - - Curl_conn_cf_adjust_pollset(cf, data, &ps); - DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE); - for(i = 0; i < ps.num; ++i) { - short events = 0; - if(ps.actions[i] & CURL_POLL_IN) { - events |= POLLIN; - } - if(ps.actions[i] & CURL_POLL_OUT) { - events |= POLLOUT; - } - if(events) { - pfds[npfds].fd = ps.sockets[i]; - pfds[npfds].events = events; - ++npfds; - } - } + Curl_pollset_init(&ps); - if(!npfds) - DEBUGF(infof(data, "no sockets to poll!")); - return Curl_poll(pfds, npfds, timeout_ms); + result = Curl_conn_cf_adjust_pollset(cf, data, &ps); + if(!result) + result = Curl_pollset_poll(data, &ps, timeout_ms); + Curl_pollset_cleanup(&ps); + return result; } void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex, @@ -742,8 +801,14 @@ void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex, { struct Curl_cfilter *cf, *cf_proxy = NULL; - DEBUGASSERT(data->conn); - cf = data->conn->cfilter[sockindex]; + if(!data->conn) { + DEBUGASSERT(0); + *phost = ""; + *pport = -1; + return; + } + + cf = CONN_SOCK_IDX_VALID(sockindex) ? data->conn->cfilter[sockindex] : NULL; /* Find the "lowest" tunneling proxy filter that has not connected yet. */ while(cf && !cf->connected) { if((cf->cft->flags & (CF_TYPE_IP_CONNECT|CF_TYPE_PROXY)) == @@ -810,6 +875,17 @@ unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf, return (unsigned char)(data->conn ? data->conn->transport_wanted : 0); } +const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf, + struct Curl_easy *data) +{ + const char *alpn = NULL; + CURL_TRC_CF(data, cf, "query ALPN"); + if(cf && !cf->cft->query(cf, data, CF_QUERY_ALPN_NEGOTIATED, NULL, + CURL_UNCONST(&alpn))) + return alpn; + return NULL; +} + static const struct Curl_sockaddr_ex * cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data) { @@ -823,36 +899,44 @@ cf_get_remote_addr(struct Curl_cfilter *cf, struct Curl_easy *data) CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf, struct Curl_easy *data, - int *is_ipv6, struct ip_quadruple *ipquad) + bool *is_ipv6, struct ip_quadruple *ipquad) { - if(cf) - return cf->cft->query(cf, data, CF_QUERY_IP_INFO, is_ipv6, ipquad); - return CURLE_UNKNOWN_OPTION; + CURLcode result = CURLE_UNKNOWN_OPTION; + if(cf) { + int ipv6 = 0; + result = cf->cft->query(cf, data, CF_QUERY_IP_INFO, &ipv6, ipquad); + *is_ipv6 = !!ipv6; + } + return result; } -curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex) +curl_socket_t Curl_conn_get_first_socket(struct Curl_easy *data) { struct Curl_cfilter *cf; - cf = data->conn ? data->conn->cfilter[sockindex] : NULL; + if(!data->conn) + return CURL_SOCKET_BAD; + + cf = data->conn->cfilter[FIRSTSOCKET]; /* if the top filter has not connected, ask it (and its sub-filters) - * for the socket. Otherwise conn->sock[sockindex] should have it. - */ + * for the socket. Otherwise conn->sock[sockindex] should have it. */ if(cf && !cf->connected) return Curl_conn_cf_get_socket(cf, data); - return data->conn ? data->conn->sock[sockindex] : CURL_SOCKET_BAD; + return data->conn->sock[FIRSTSOCKET]; } const struct Curl_sockaddr_ex * Curl_conn_get_remote_addr(struct Curl_easy *data, int sockindex) { - struct Curl_cfilter *cf = data->conn ? data->conn->cfilter[sockindex] : NULL; + struct Curl_cfilter *cf = + (data->conn && CONN_SOCK_IDX_VALID(sockindex)) ? + data->conn->cfilter[sockindex] : NULL; return cf ? cf_get_remote_addr(cf, data) : NULL; } void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex) { - if(data->conn) { + if(data->conn && CONN_SOCK_IDX_VALID(sockindex)) { struct Curl_cfilter *cf = data->conn->cfilter[sockindex]; if(cf) (void)Curl_conn_cf_cntrl(cf, data, TRUE, @@ -894,6 +978,8 @@ CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data) CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex) { + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; return Curl_conn_cf_cntrl(data->conn->cfilter[sockindex], data, FALSE, CF_CTRL_FLUSH, 0, NULL); } @@ -963,7 +1049,11 @@ CURLcode Curl_conn_keep_alive(struct Curl_easy *data, struct connectdata *conn, int sockindex) { - struct Curl_cfilter *cf = conn->cfilter[sockindex]; + struct Curl_cfilter *cf; + + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; + cf = conn->cfilter[sockindex]; return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK; } @@ -971,23 +1061,34 @@ size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, struct connectdata *conn, int sockindex) { + struct Curl_cfilter *cf; CURLcode result; - int n = 0; + int n = -1; - struct Curl_cfilter *cf = conn->cfilter[sockindex]; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return 0; + + cf = conn->cfilter[sockindex]; result = cf ? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT, &n, NULL) : CURLE_UNKNOWN_OPTION; - return (result || n <= 0) ? 1 : (size_t)n; + /* If no filter answered the query, the default is a non-multiplexed + * connection with limit 1. Otherwise, the the query may return 0 + * for connections that are in shutdown, e.g. server HTTP/2 GOAWAY. */ + return (result || n < 0) ? 1 : (size_t)n; } int Curl_conn_get_stream_error(struct Curl_easy *data, struct connectdata *conn, int sockindex) { + struct Curl_cfilter *cf; CURLcode result; int n = 0; - struct Curl_cfilter *cf = conn->cfilter[sockindex]; + if(!CONN_SOCK_IDX_VALID(sockindex)) + return 0; + + cf = conn->cfilter[sockindex]; result = cf ? cf->cft->query(cf, data, CF_QUERY_STREAM_ERROR, &n, NULL) : CURLE_UNKNOWN_OPTION; return (result || n < 0) ? 0 : n; @@ -1006,6 +1107,8 @@ CURLcode Curl_conn_recv(struct Curl_easy *data, int sockindex, { DEBUGASSERT(data); DEBUGASSERT(data->conn); + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; if(data && data->conn && data->conn->recv[sockindex]) return data->conn->recv[sockindex](data, sockindex, buf, blen, pnread); *pnread = 0; @@ -1020,7 +1123,9 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, DEBUGASSERT(data); DEBUGASSERT(data->conn); - DEBUGASSERT(sockindex >= 0 && sockindex < 2); + DEBUGASSERT(CONN_SOCK_IDX_VALID(sockindex)); + if(!CONN_SOCK_IDX_VALID(sockindex)) + return CURLE_BAD_FUNCTION_ARGUMENT; #ifdef DEBUGBUILD if(write_len) { /* Allow debug builds to override this logic to force short sends @@ -1041,142 +1146,3 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, *pnwritten = 0; return CURLE_FAILED_INIT; } - -void Curl_pollset_reset(struct Curl_easy *data, - struct easy_pollset *ps) -{ - size_t i; - (void)data; - memset(ps, 0, sizeof(*ps)); - for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) - ps->sockets[i] = CURL_SOCKET_BAD; -} - -/** - * - */ -void Curl_pollset_change(struct Curl_easy *data, - struct easy_pollset *ps, curl_socket_t sock, - int add_flags, int remove_flags) -{ - unsigned int i; - - (void)data; - DEBUGASSERT(VALID_SOCK(sock)); - if(!VALID_SOCK(sock)) - return; - - DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT)); - DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT)); - DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */ - for(i = 0; i < ps->num; ++i) { - if(ps->sockets[i] == sock) { - ps->actions[i] &= (unsigned char)(~remove_flags); - ps->actions[i] |= (unsigned char)add_flags; - /* all gone? remove socket */ - if(!ps->actions[i]) { - if((i + 1) < ps->num) { - memmove(&ps->sockets[i], &ps->sockets[i + 1], - (ps->num - (i + 1)) * sizeof(ps->sockets[0])); - memmove(&ps->actions[i], &ps->actions[i + 1], - (ps->num - (i + 1)) * sizeof(ps->actions[0])); - } - --ps->num; - } - return; - } - } - /* not present */ - if(add_flags) { - /* Having more SOCKETS per easy handle than what is defined - * is a programming error. This indicates that we need - * to raise this limit, making easy_pollset larger. - * Since we use this in tight loops, we do not want to make - * the pollset dynamic unnecessarily. - * The current maximum in practise is HTTP/3 eyeballing where - * we have up to 4 sockets involved in connection setup. - */ - DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE); - if(i < MAX_SOCKSPEREASYHANDLE) { - ps->sockets[i] = sock; - ps->actions[i] = (unsigned char)add_flags; - ps->num = i + 1; - } - } -} - -void Curl_pollset_set(struct Curl_easy *data, - struct easy_pollset *ps, curl_socket_t sock, - bool do_in, bool do_out) -{ - Curl_pollset_change(data, ps, sock, - (do_in ? CURL_POLL_IN : 0)| - (do_out ? CURL_POLL_OUT : 0), - (!do_in ? CURL_POLL_IN : 0)| - (!do_out ? CURL_POLL_OUT : 0)); -} - -static void ps_add(struct Curl_easy *data, struct easy_pollset *ps, - int bitmap, curl_socket_t *socks) -{ - if(bitmap) { - int i; - for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) { - if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) { - break; - } - if(bitmap & GETSOCK_READSOCK(i)) { - if(bitmap & GETSOCK_WRITESOCK(i)) - Curl_pollset_add_inout(data, ps, socks[i]); - else - /* is READ, since we checked MASK_RW above */ - Curl_pollset_add_in(data, ps, socks[i]); - } - else - Curl_pollset_add_out(data, ps, socks[i]); - } - } -} - -void Curl_pollset_add_socks(struct Curl_easy *data, - struct easy_pollset *ps, - int (*get_socks_cb)(struct Curl_easy *data, - curl_socket_t *socks)) -{ - curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; - int bitmap; - - bitmap = get_socks_cb(data, socks); - ps_add(data, ps, bitmap, socks); -} - -void Curl_pollset_check(struct Curl_easy *data, - struct easy_pollset *ps, curl_socket_t sock, - bool *pwant_read, bool *pwant_write) -{ - unsigned int i; - - (void)data; - DEBUGASSERT(VALID_SOCK(sock)); - for(i = 0; i < ps->num; ++i) { - if(ps->sockets[i] == sock) { - *pwant_read = !!(ps->actions[i] & CURL_POLL_IN); - *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT); - return; - } - } - *pwant_read = *pwant_write = FALSE; -} - -bool Curl_pollset_want_read(struct Curl_easy *data, - struct easy_pollset *ps, - curl_socket_t sock) -{ - unsigned int i; - (void)data; - for(i = 0; i < ps->num; ++i) { - if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN)) - return TRUE; - } - return FALSE; -} diff --git a/deps/curl/lib/cfilters.h b/deps/curl/lib/cfilters.h index 39d906d673b..815b72a6e80 100644 --- a/deps/curl/lib/cfilters.h +++ b/deps/curl/lib/cfilters.h @@ -80,7 +80,7 @@ struct easy_pollset; * @param data the easy handle the pollset is about * @param ps the pollset (inout) for the easy handle */ -typedef void Curl_cft_adjust_pollset(struct Curl_cfilter *cf, +typedef CURLcode Curl_cft_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, struct easy_pollset *ps); @@ -158,6 +158,10 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, * - CF_QUERY_SSL_CTX_INFO: same as CF_QUERY_SSL_INFO, but give the SSL_CTX * when available, or the same internal pointer * when the TLS stack does not differentiate. + * - CF_QUERY_ALPN_NEGOTIATED: The ALPN selected by the server as + null-terminated string or NULL if none + selected/handshake not done. Implemented by filter + types CF_TYPE_SSL or CF_TYPE_IP_CONNECT. */ /* query res1 res2 */ #define CF_QUERY_MAX_CONCURRENT 1 /* number - */ @@ -176,6 +180,7 @@ typedef CURLcode Curl_cft_cntrl(struct Curl_cfilter *cf, #define CF_QUERY_SSL_INFO 12 /* - struct curl_tlssessioninfo * */ #define CF_QUERY_SSL_CTX_INFO 13 /* - struct curl_tlssessioninfo * */ #define CF_QUERY_TRANSPORT 14 /* TRNSPRT_* - * */ +#define CF_QUERY_ALPN_NEGOTIATED 15 /* - const char * */ /** * Query the cfilter for properties. Filters ignorant of a query will @@ -239,7 +244,7 @@ void Curl_cf_def_destroy_this(struct Curl_cfilter *cf, /* Default implementations for the type functions, implementing pass-through * the filter chain. */ -void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, +CURLcode Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, struct easy_pollset *ps); bool Curl_cf_def_data_pending(struct Curl_cfilter *cf, @@ -331,12 +336,6 @@ CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf, bool ignore_result, int event, int arg1, void *arg2); -/** - * Determine if the connection filter chain is using SSL to the remote host - * (or will be once connected). - */ -bool Curl_conn_cf_is_ssl(struct Curl_cfilter *cf); - /** * Get the socket used by the filter chain starting at `cf`. * Returns CURL_SOCKET_BAD if not available. @@ -346,7 +345,7 @@ curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf, CURLcode Curl_conn_cf_get_ip_info(struct Curl_cfilter *cf, struct Curl_easy *data, - int *is_ipv6, struct ip_quadruple *ipquad); + bool *is_ipv6, struct ip_quadruple *ipquad); bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf, struct Curl_easy *data); @@ -354,6 +353,9 @@ bool Curl_conn_cf_needs_flush(struct Curl_cfilter *cf, unsigned char Curl_conn_cf_get_transport(struct Curl_cfilter *cf, struct Curl_easy *data); +const char *Curl_conn_cf_get_alpn_negotiated(struct Curl_cfilter *cf, + struct Curl_easy *data); + #define CURL_CF_SSL_DEFAULT -1 #define CURL_CF_SSL_DISABLE 0 #define CURL_CF_SSL_ENABLE 1 @@ -402,6 +404,10 @@ bool Curl_conn_get_ssl_info(struct Curl_easy *data, struct connectdata *conn, int sockindex, struct curl_tlssessioninfo *info); +CURLcode Curl_conn_get_ip_info(struct Curl_easy *data, + struct connectdata *conn, int sockindex, + bool *is_ipv6, struct ip_quadruple *ipquad); + /** * Connection provides multiplexing of easy handles at `socketindex`. */ @@ -418,6 +424,10 @@ unsigned char Curl_conn_http_version(struct Curl_easy *data, unsigned char Curl_conn_get_transport(struct Curl_easy *data, struct connectdata *conn); +/* Get the negotiated ALPN protocol or NULL if none in play */ +const char *Curl_conn_get_alpn_negotiated(struct Curl_easy *data, + struct connectdata *conn); + /** * Close the filter chain at `sockindex` for connection `data->conn`. * Filters remain in place and may be connected again afterwards. @@ -450,10 +460,11 @@ bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex); CURLcode Curl_conn_flush(struct Curl_easy *data, int sockindex); /** - * Return the socket used on data's connection for the index. + * Return the socket used on data's connection for FIRSTSOCKET, + * querying filters if the whole chain has not connected yet. * Returns CURL_SOCKET_BAD if not available. */ -curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex); +curl_socket_t Curl_conn_get_first_socket(struct Curl_easy *data); /* Return a pointer to the connected socket address or NULL. */ const struct Curl_sockaddr_ex * @@ -467,16 +478,16 @@ void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex); /** * Adjust the pollset for the filter chain starting at `cf`. */ -void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps); +CURLcode Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps); /** * Adjust pollset from filters installed at transfer's connection. */ -void Curl_conn_adjust_pollset(struct Curl_easy *data, - struct connectdata *conn, - struct easy_pollset *ps); +CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data, + struct connectdata *conn, + struct easy_pollset *ps); /** * Curl_poll() the filter chain at `cf` with timeout `timeout_ms`. @@ -622,56 +633,6 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex, size_t *pnwritten); -void Curl_pollset_reset(struct Curl_easy *data, - struct easy_pollset *ps); - -/* Change the poll flags (CURL_POLL_IN/CURL_POLL_OUT) to the poll set for - * socket `sock`. If the socket is not already part of the poll set, it - * will be added. - * If the socket is present and all poll flags are cleared, it will be removed. - */ -void Curl_pollset_change(struct Curl_easy *data, - struct easy_pollset *ps, curl_socket_t sock, - int add_flags, int remove_flags); - -void Curl_pollset_set(struct Curl_easy *data, - struct easy_pollset *ps, curl_socket_t sock, - bool do_in, bool do_out); - -#define Curl_pollset_add_in(data, ps, sock) \ - Curl_pollset_change((data), (ps), (sock), CURL_POLL_IN, 0) -#define Curl_pollset_add_out(data, ps, sock) \ - Curl_pollset_change((data), (ps), (sock), CURL_POLL_OUT, 0) -#define Curl_pollset_add_inout(data, ps, sock) \ - Curl_pollset_change((data), (ps), (sock), \ - CURL_POLL_IN|CURL_POLL_OUT, 0) -#define Curl_pollset_set_in_only(data, ps, sock) \ - Curl_pollset_change((data), (ps), (sock), \ - CURL_POLL_IN, CURL_POLL_OUT) -#define Curl_pollset_set_out_only(data, ps, sock) \ - Curl_pollset_change((data), (ps), (sock), \ - CURL_POLL_OUT, CURL_POLL_IN) - -void Curl_pollset_add_socks(struct Curl_easy *data, - struct easy_pollset *ps, - int (*get_socks_cb)(struct Curl_easy *data, - curl_socket_t *socks)); - -/** - * Check if the pollset, as is, wants to read and/or write regarding - * the given socket. - */ -void Curl_pollset_check(struct Curl_easy *data, - struct easy_pollset *ps, curl_socket_t sock, - bool *pwant_read, bool *pwant_write); - -/** - * Return TRUE if the pollset contains socket with CURL_POLL_IN. - */ -bool Curl_pollset_want_read(struct Curl_easy *data, - struct easy_pollset *ps, - curl_socket_t sock); - /** * Types and macros used to keep the current easy handle in filter calls, * allowing for nested invocations. See #10336. diff --git a/deps/curl/lib/config-os400.h b/deps/curl/lib/config-os400.h index 064338ed2ab..bccdb4a8974 100644 --- a/deps/curl/lib/config-os400.h +++ b/deps/curl/lib/config-os400.h @@ -203,10 +203,6 @@ /* Define if you have the ANSI C header files. */ #define STDC_HEADERS -/* Define to enable HTTP3 support (experimental, requires NGTCP2, quiche or - MSH3) */ -#undef USE_HTTP3 - /* Version number of package */ #undef VERSION diff --git a/deps/curl/lib/config-win32.h b/deps/curl/lib/config-win32.h index 68377025db3..b7f83927a43 100644 --- a/deps/curl/lib/config-win32.h +++ b/deps/curl/lib/config-win32.h @@ -264,13 +264,11 @@ #define HAVE_SNPRINTF 1 #endif -/* Vista */ -#if (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600) && !defined(UNDER_CE) +/* Must always use local implementations on Windows. */ /* Define to 1 if you have an IPv6 capable working inet_ntop function. */ -#define HAVE_INET_NTOP 1 +/* #undef HAVE_INET_NTOP */ /* Define to 1 if you have an IPv6 capable working inet_pton function. */ -#define HAVE_INET_PTON 1 -#endif +/* #undef HAVE_INET_PTON */ /* Define to 1 if you have the `basename' function. */ #ifdef __MINGW32__ diff --git a/deps/curl/lib/conncache.c b/deps/curl/lib/conncache.c index fd6776e34c6..1393bb565be 100644 --- a/deps/curl/lib/conncache.c +++ b/deps/curl/lib/conncache.c @@ -515,7 +515,7 @@ static bool cpool_foreach(struct Curl_easy *data, struct connectdata *conn = Curl_node_elem(curr); curr = Curl_node_next(curr); - if(1 == func(data, conn, param)) { + if(func(data, conn, param) == 1) { return TRUE; } } @@ -709,7 +709,8 @@ static int cpool_reap_dead_cb(struct Curl_easy *data, struct connectdata *conn, void *param) { struct cpool_reaper_ctx *rctx = param; - if(Curl_conn_seems_dead(conn, data, &rctx->now)) { + if((!CONN_INUSE(conn) && conn->bits.no_reuse) || + Curl_conn_seems_dead(conn, data, &rctx->now)) { /* stop the iteration here, pass back the connection that was pruned */ Curl_conn_terminate(data, conn, FALSE); return 1; @@ -849,6 +850,40 @@ void Curl_cpool_do_locked(struct Curl_easy *data, cb(conn, data, cbdata); } +static int cpool_mark_stale(struct Curl_easy *data, + struct connectdata *conn, void *param) +{ + (void)data; + (void)param; + conn->bits.no_reuse = TRUE; + return 0; +} + +static int cpool_reap_no_reuse(struct Curl_easy *data, + struct connectdata *conn, void *param) +{ + (void)data; + (void)param; + if(!CONN_INUSE(conn) && conn->bits.no_reuse) { + Curl_conn_terminate(data, conn, FALSE); + return 1; + } + return 0; /* continue iteration */ +} + +void Curl_cpool_nw_changed(struct Curl_easy *data) +{ + struct cpool *cpool = cpool_get_instance(data); + + if(cpool) { + CPOOL_LOCK(cpool, data); + cpool_foreach(data, cpool, NULL, cpool_mark_stale); + while(cpool_foreach(data, cpool, NULL, cpool_reap_no_reuse)) + ; + CPOOL_UNLOCK(cpool, data); + } +} + #if 0 /* Useful for debugging the connection pool */ void Curl_cpool_print(struct cpool *cpool) diff --git a/deps/curl/lib/conncache.h b/deps/curl/lib/conncache.h index ac07111a7d7..a5f133344fd 100644 --- a/deps/curl/lib/conncache.h +++ b/deps/curl/lib/conncache.h @@ -163,4 +163,8 @@ void Curl_cpool_do_locked(struct Curl_easy *data, struct connectdata *conn, Curl_cpool_conn_do_cb *cb, void *cbdata); +/* Close all unused connections, prevent reuse of existing ones. */ +void Curl_cpool_nw_changed(struct Curl_easy *data); + + #endif /* HEADER_CURL_CONNCACHE_H */ diff --git a/deps/curl/lib/connect.c b/deps/curl/lib/connect.c index ac16c3399b3..f0628d6206e 100644 --- a/deps/curl/lib/connect.c +++ b/deps/curl/lib/connect.c @@ -61,6 +61,7 @@ #include "connect.h" #include "cf-haproxy.h" #include "cf-https-connect.h" +#include "cf-ip-happy.h" #include "cf-socket.h" #include "select.h" #include "url.h" /* for Curl_safefree() */ @@ -74,8 +75,6 @@ #include "conncache.h" #include "multihandle.h" #include "share.h" -#include "curlx/version_win32.h" -#include "vquic/vquic.h" /* for quic cfilters */ #include "http_proxy.h" #include "socks.h" @@ -232,28 +231,6 @@ bool Curl_shutdown_started(struct Curl_easy *data, int sockindex) return (pt->tv_sec > 0) || (pt->tv_usec > 0); } -static const struct Curl_addrinfo * -addr_first_match(const struct Curl_addrinfo *addr, int family) -{ - while(addr) { - if(addr->ai_family == family) - return addr; - addr = addr->ai_next; - } - return NULL; -} - -static const struct Curl_addrinfo * -addr_next_match(const struct Curl_addrinfo *addr, int family) -{ - while(addr && addr->ai_next) { - addr = addr->ai_next; - if(addr->ai_family == family) - return addr; - } - return NULL; -} - /* retrieves ip address and port from a sockaddr structure. note it calls curlx_inet_ntop which sets errno on fail, not SOCKERRNO. */ bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen, @@ -372,874 +349,6 @@ void Curl_conncontrol(struct connectdata *conn, } } -/** - * job walking the matching addr infos, creating a sub-cfilter with the - * provided method `cf_create` and running setup/connect on it. - */ -struct eyeballer { - const char *name; - const struct Curl_addrinfo *first; /* complete address list, not owned */ - const struct Curl_addrinfo *addr; /* List of addresses to try, not owned */ - int ai_family; /* matching address family only */ - cf_ip_connect_create *cf_create; /* for creating cf */ - struct Curl_cfilter *cf; /* current sub-cfilter connecting */ - struct eyeballer *primary; /* eyeballer this one is backup for */ - timediff_t delay_ms; /* delay until start */ - struct curltime started; /* start of current attempt */ - timediff_t timeoutms; /* timeout for current attempt */ - expire_id timeout_id; /* ID for Curl_expire() */ - CURLcode result; - int error; - BIT(has_started); /* attempts have started */ - BIT(is_done); /* out of addresses/time */ - BIT(connected); /* cf has connected */ - BIT(shutdown); /* cf has shutdown */ - BIT(inconclusive); /* connect was not a hard failure, we - * might talk to a restarting server */ -}; - - -typedef enum { - SCFST_INIT, - SCFST_WAITING, - SCFST_DONE -} cf_connect_state; - -struct cf_he_ctx { - int transport; - cf_ip_connect_create *cf_create; - cf_connect_state state; - struct eyeballer *baller[2]; - struct eyeballer *winner; - struct curltime started; -}; - -/* when there are more than one IP address left to use, this macro returns how - much of the given timeout to spend on *this* attempt */ -#define TIMEOUT_LARGE 600 -#define USETIME(ms) ((ms > TIMEOUT_LARGE) ? (ms / 2) : ms) - -static CURLcode eyeballer_new(struct eyeballer **pballer, - cf_ip_connect_create *cf_create, - const struct Curl_addrinfo *addr, - int ai_family, - struct eyeballer *primary, - timediff_t delay_ms, - timediff_t timeout_ms, - expire_id timeout_id) -{ - struct eyeballer *baller; - - *pballer = NULL; - baller = calloc(1, sizeof(*baller)); - if(!baller) - return CURLE_OUT_OF_MEMORY; - - baller->name = ((ai_family == AF_INET) ? "ipv4" : ( -#ifdef USE_IPV6 - (ai_family == AF_INET6) ? "ipv6" : -#endif - "ip")); - baller->cf_create = cf_create; - baller->first = baller->addr = addr; - baller->ai_family = ai_family; - baller->primary = primary; - baller->delay_ms = delay_ms; - baller->timeoutms = addr_next_match(baller->addr, baller->ai_family) ? - USETIME(timeout_ms) : timeout_ms; - baller->timeout_id = timeout_id; - baller->result = CURLE_COULDNT_CONNECT; - - *pballer = baller; - return CURLE_OK; -} - -static void baller_close(struct eyeballer *baller, - struct Curl_easy *data) -{ - if(baller && baller->cf) { - Curl_conn_cf_discard_chain(&baller->cf, data); - } -} - -static void baller_free(struct eyeballer *baller, - struct Curl_easy *data) -{ - if(baller) { - baller_close(baller, data); - free(baller); - } -} - -static void baller_rewind(struct eyeballer *baller) -{ - baller->addr = baller->first; - baller->inconclusive = FALSE; -} - -static void baller_next_addr(struct eyeballer *baller) -{ - baller->addr = addr_next_match(baller->addr, baller->ai_family); -} - -/* - * Initiate a connect attempt walk. - * - * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to - * CURL_SOCKET_BAD. Other errors will however return proper errors. - */ -static void baller_initiate(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct eyeballer *baller) -{ - struct cf_he_ctx *ctx = cf->ctx; - struct Curl_cfilter *cf_prev = baller->cf; - struct Curl_cfilter *wcf; - CURLcode result; - - - /* Do not close a previous cfilter yet to ensure that the next IP's - socket gets a different file descriptor, which can prevent bugs when - the curl_multi_socket_action interface is used with certain select() - replacements such as kqueue. */ - result = baller->cf_create(&baller->cf, data, cf->conn, baller->addr, - ctx->transport); - if(result) - goto out; - - /* the new filter might have sub-filters */ - for(wcf = baller->cf; wcf; wcf = wcf->next) { - wcf->conn = cf->conn; - wcf->sockindex = cf->sockindex; - } - - if(addr_next_match(baller->addr, baller->ai_family)) { - Curl_expire(data, baller->timeoutms, baller->timeout_id); - } - -out: - if(result) { - CURL_TRC_CF(data, cf, "%s failed", baller->name); - baller_close(baller, data); - } - if(cf_prev) - Curl_conn_cf_discard_chain(&cf_prev, data); - baller->result = result; -} - -/** - * Start a connection attempt on the current baller address. - * Will return CURLE_OK on the first address where a socket - * could be created and the non-blocking connect started. - * Returns error when all remaining addresses have been tried. - */ -static CURLcode baller_start(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct eyeballer *baller, - timediff_t timeoutms) -{ - baller->error = 0; - baller->connected = FALSE; - baller->has_started = TRUE; - - while(baller->addr) { - baller->started = curlx_now(); - baller->timeoutms = addr_next_match(baller->addr, baller->ai_family) ? - USETIME(timeoutms) : timeoutms; - baller_initiate(cf, data, baller); - if(!baller->result) - break; - baller_next_addr(baller); - } - if(!baller->addr) { - baller->is_done = TRUE; - } - return baller->result; -} - - -/* Used within the multi interface. Try next IP address, returns error if no - more address exists or error */ -static CURLcode baller_start_next(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct eyeballer *baller, - timediff_t timeoutms) -{ - if(cf->sockindex == FIRSTSOCKET) { - baller_next_addr(baller); - /* If we get inconclusive answers from the server(s), we start - * again until this whole thing times out. This allows us to - * connect to servers that are gracefully restarting and the - * packet routing to the new instance has not happened yet (e.g. QUIC). */ - if(!baller->addr && baller->inconclusive) - baller_rewind(baller); - baller_start(cf, data, baller, timeoutms); - } - else { - baller->error = 0; - baller->connected = FALSE; - baller->has_started = TRUE; - baller->is_done = TRUE; - baller->result = CURLE_COULDNT_CONNECT; - } - return baller->result; -} - -static CURLcode baller_connect(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct eyeballer *baller, - struct curltime *now, - bool *connected) -{ - (void)cf; - *connected = baller->connected; - if(!baller->result && !*connected) { - /* evaluate again */ - baller->result = Curl_conn_cf_connect(baller->cf, data, connected); - - if(!baller->result) { - if(*connected) { - baller->connected = TRUE; - baller->is_done = TRUE; - } - else if(curlx_timediff(*now, baller->started) >= baller->timeoutms) { - infof(data, "%s connect timeout after %" FMT_TIMEDIFF_T - "ms, move on!", baller->name, baller->timeoutms); -#ifdef SOCKETIMEDOUT - baller->error = SOCKETIMEDOUT; -#endif - baller->result = CURLE_OPERATION_TIMEDOUT; - } - } - else if(baller->result == CURLE_WEIRD_SERVER_REPLY) - baller->inconclusive = TRUE; - } - return baller->result; -} - -/* - * is_connected() checks if the socket has connected. - */ -static CURLcode is_connected(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *connected) -{ - struct cf_he_ctx *ctx = cf->ctx; - struct connectdata *conn = cf->conn; - CURLcode result; - struct curltime now; - size_t i; - int ongoing, not_started; - const char *hostname; - - /* Check if any of the conn->tempsock we use for establishing connections - * succeeded and, if so, close any ongoing other ones. - * Transfer the successful conn->tempsock to conn->sock[sockindex] - * and set conn->tempsock to CURL_SOCKET_BAD. - * If transport is QUIC, we need to shutdown the ongoing 'other' - * cot ballers in a QUIC appropriate way. */ -evaluate: - *connected = FALSE; /* a negative world view is best */ - now = curlx_now(); - ongoing = not_started = 0; - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - struct eyeballer *baller = ctx->baller[i]; - - if(!baller || baller->is_done) - continue; - - if(!baller->has_started) { - ++not_started; - continue; - } - baller->result = baller_connect(cf, data, baller, &now, connected); - CURL_TRC_CF(data, cf, "%s connect -> %d, connected=%d", - baller->name, baller->result, *connected); - - if(!baller->result) { - if(*connected) { - /* connected, declare the winner */ - ctx->winner = baller; - ctx->baller[i] = NULL; - break; - } - else { /* still waiting */ - ++ongoing; - } - } - else if(!baller->is_done) { - /* The baller failed to connect, start its next attempt */ - if(baller->error) { - data->state.os_errno = baller->error; - SET_SOCKERRNO(baller->error); - } - baller_start_next(cf, data, baller, Curl_timeleft(data, &now, TRUE)); - if(baller->is_done) { - CURL_TRC_CF(data, cf, "%s done", baller->name); - } - else { - /* next attempt was started */ - CURL_TRC_CF(data, cf, "%s trying next", baller->name); - ++ongoing; - Curl_multi_mark_dirty(data); - } - } - } - - if(ctx->winner) { - *connected = TRUE; - return CURLE_OK; - } - - /* Nothing connected, check the time before we might - * start new ballers or return ok. */ - if((ongoing || not_started) && Curl_timeleft(data, &now, TRUE) < 0) { - failf(data, "Connection timeout after %" FMT_OFF_T " ms", - curlx_timediff(now, data->progress.t_startsingle)); - return CURLE_OPERATION_TIMEDOUT; - } - - /* Check if we have any waiting ballers to start now. */ - if(not_started > 0) { - int added = 0; - - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - struct eyeballer *baller = ctx->baller[i]; - - if(!baller || baller->has_started) - continue; - /* We start its primary baller has failed to connect or if - * its start delay_ms have expired */ - if((baller->primary && baller->primary->is_done) || - curlx_timediff(now, ctx->started) >= baller->delay_ms) { - baller_start(cf, data, baller, Curl_timeleft(data, &now, TRUE)); - if(baller->is_done) { - CURL_TRC_CF(data, cf, "%s done", baller->name); - } - else { - CURL_TRC_CF(data, cf, "%s starting (timeout=%" FMT_TIMEDIFF_T "ms)", - baller->name, baller->timeoutms); - ++ongoing; - ++added; - } - } - } - if(added > 0) - goto evaluate; - } - - if(ongoing > 0) { - /* We are still trying, return for more waiting */ - *connected = FALSE; - return CURLE_OK; - } - - /* all ballers have failed to connect. */ - CURL_TRC_CF(data, cf, "all eyeballers failed"); - result = CURLE_COULDNT_CONNECT; - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - struct eyeballer *baller = ctx->baller[i]; - if(!baller) - continue; - CURL_TRC_CF(data, cf, "%s assess started=%d, result=%d", - baller->name, baller->has_started, baller->result); - if(baller->has_started && baller->result) { - result = baller->result; - break; - } - } - -#ifndef CURL_DISABLE_PROXY - if(conn->bits.socksproxy) - hostname = conn->socks_proxy.host.name; - else if(conn->bits.httpproxy) - hostname = conn->http_proxy.host.name; - else -#endif - if(conn->bits.conn_to_host) - hostname = conn->conn_to_host.name; - else - hostname = conn->host.name; - - failf(data, "Failed to connect to %s port %u after " - "%" FMT_TIMEDIFF_T " ms: %s", - hostname, conn->primary.remote_port, - curlx_timediff(now, data->progress.t_startsingle), - curl_easy_strerror(result)); - -#ifdef SOCKETIMEDOUT - if(SOCKETIMEDOUT == data->state.os_errno) - result = CURLE_OPERATION_TIMEDOUT; -#endif - - return result; -} - -/* - * Connect to the given host with timeout, proxy or remote does not matter. - * There might be more than one IP address to try out. - */ -static CURLcode start_connect(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_he_ctx *ctx = cf->ctx; - struct connectdata *conn = cf->conn; - CURLcode result = CURLE_COULDNT_CONNECT; - int ai_family0 = 0, ai_family1 = 0; - timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); - const struct Curl_addrinfo *addr0 = NULL, *addr1 = NULL; - struct Curl_dns_entry *dns = data->state.dns[cf->sockindex]; - - if(!dns) - return CURLE_FAILED_INIT; - - if(timeout_ms < 0) { - /* a precaution, no need to continue if time already is up */ - failf(data, "Connection time-out"); - return CURLE_OPERATION_TIMEDOUT; - } - - ctx->started = curlx_now(); - - /* dns->addr is the list of addresses from the resolver, each - * with an address family. The list has at least one entry, possibly - * many more. - * We try at most 2 at a time, until we either get a connection or - * run out of addresses to try. Since likelihood of success is tied - * to the address family (e.g. IPV6 might not work at all ), we want - * the 2 connect attempt ballers to try different families, if possible. - * - */ - if(conn->ip_version == CURL_IPRESOLVE_V6) { -#ifdef USE_IPV6 - ai_family0 = AF_INET6; - addr0 = addr_first_match(dns->addr, ai_family0); -#endif - } - else if(conn->ip_version == CURL_IPRESOLVE_V4) { - ai_family0 = AF_INET; - addr0 = addr_first_match(dns->addr, ai_family0); - } - else { - /* no user preference, we try ipv6 always first when available */ -#ifdef USE_IPV6 - ai_family0 = AF_INET6; - addr0 = addr_first_match(dns->addr, ai_family0); -#endif - /* next candidate is ipv4 */ - ai_family1 = AF_INET; - addr1 = addr_first_match(dns->addr, ai_family1); - /* no ip address families, probably AF_UNIX or something, use the - * address family given to us */ - if(!addr1 && !addr0 && dns->addr) { - ai_family0 = dns->addr->ai_family; - addr0 = addr_first_match(dns->addr, ai_family0); - } - } - - if(!addr0 && addr1) { - /* switch around, so a single baller always uses addr0 */ - addr0 = addr1; - ai_family0 = ai_family1; - addr1 = NULL; - } - - /* We found no address that matches our criteria, we cannot connect */ - if(!addr0) { - return CURLE_COULDNT_CONNECT; - } - - memset(ctx->baller, 0, sizeof(ctx->baller)); - result = eyeballer_new(&ctx->baller[0], ctx->cf_create, addr0, ai_family0, - NULL, 0, /* no primary/delay, start now */ - timeout_ms, EXPIRE_DNS_PER_NAME); - if(result) - return result; - CURL_TRC_CF(data, cf, "created %s (timeout %" FMT_TIMEDIFF_T "ms)", - ctx->baller[0]->name, ctx->baller[0]->timeoutms); - if(addr1) { - /* second one gets a delayed start */ - result = eyeballer_new(&ctx->baller[1], ctx->cf_create, addr1, ai_family1, - ctx->baller[0], /* wait on that to fail */ - /* or start this delayed */ - data->set.happy_eyeballs_timeout, - timeout_ms, EXPIRE_DNS_PER_NAME2); - if(result) - return result; - CURL_TRC_CF(data, cf, "created %s (timeout %" FMT_TIMEDIFF_T "ms)", - ctx->baller[1]->name, ctx->baller[1]->timeoutms); - Curl_expire(data, data->set.happy_eyeballs_timeout, - EXPIRE_HAPPY_EYEBALLS); - } - - return CURLE_OK; -} - -static void cf_he_ctx_clear(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct cf_he_ctx *ctx = cf->ctx; - size_t i; - - DEBUGASSERT(ctx); - DEBUGASSERT(data); - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - baller_free(ctx->baller[i], data); - ctx->baller[i] = NULL; - } - baller_free(ctx->winner, data); - ctx->winner = NULL; -} - -static CURLcode cf_he_shutdown(struct Curl_cfilter *cf, - struct Curl_easy *data, bool *done) -{ - struct cf_he_ctx *ctx = cf->ctx; - size_t i; - CURLcode result = CURLE_OK; - - DEBUGASSERT(data); - if(cf->connected) { - *done = TRUE; - return CURLE_OK; - } - - /* shutdown all ballers that have not done so already. If one fails, - * continue shutting down others until all are shutdown. */ - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - struct eyeballer *baller = ctx->baller[i]; - bool bdone = FALSE; - if(!baller || !baller->cf || baller->shutdown) - continue; - baller->result = baller->cf->cft->do_shutdown(baller->cf, data, &bdone); - if(baller->result || bdone) - baller->shutdown = TRUE; /* treat a failed shutdown as done */ - } - - *done = TRUE; - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - if(ctx->baller[i] && !ctx->baller[i]->shutdown) - *done = FALSE; - } - if(*done) { - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - if(ctx->baller[i] && ctx->baller[i]->result) - result = ctx->baller[i]->result; - } - } - CURL_TRC_CF(data, cf, "shutdown -> %d, done=%d", result, *done); - return result; -} - -static void cf_he_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) -{ - struct cf_he_ctx *ctx = cf->ctx; - size_t i; - - if(!cf->connected) { - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - struct eyeballer *baller = ctx->baller[i]; - if(!baller || !baller->cf) - continue; - Curl_conn_cf_adjust_pollset(baller->cf, data, ps); - } - CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num); - } -} - -static CURLcode cf_he_connect(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - struct cf_he_ctx *ctx = cf->ctx; - CURLcode result = CURLE_OK; - - if(cf->connected) { - *done = TRUE; - return CURLE_OK; - } - - DEBUGASSERT(ctx); - *done = FALSE; - - switch(ctx->state) { - case SCFST_INIT: - DEBUGASSERT(CURL_SOCKET_BAD == Curl_conn_cf_get_socket(cf, data)); - DEBUGASSERT(!cf->connected); - result = start_connect(cf, data); - if(result) - return result; - ctx->state = SCFST_WAITING; - FALLTHROUGH(); - case SCFST_WAITING: - result = is_connected(cf, data, done); - if(!result && *done) { - DEBUGASSERT(ctx->winner); - DEBUGASSERT(ctx->winner->cf); - DEBUGASSERT(ctx->winner->cf->connected); - /* we have a winner. Install and activate it. - * close/free all others. */ - ctx->state = SCFST_DONE; - cf->connected = TRUE; - cf->next = ctx->winner->cf; - ctx->winner->cf = NULL; - cf_he_ctx_clear(cf, data); - - if(cf->conn->handler->protocol & PROTO_FAMILY_SSH) - Curl_pgrsTime(data, TIMER_APPCONNECT); /* we are connected already */ - if(Curl_trc_cf_is_verbose(cf, data)) { - struct ip_quadruple ipquad; - int is_ipv6; - if(!Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad)) { - const char *host; - int port; - Curl_conn_get_current_host(data, cf->sockindex, &host, &port); - CURL_TRC_CF(data, cf, "Connected to %s (%s) port %u", - host, ipquad.remote_ip, ipquad.remote_port); - } - } - data->info.numconnects++; /* to track the # of connections made */ - } - break; - case SCFST_DONE: - *done = TRUE; - break; - } - return result; -} - -static void cf_he_close(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_he_ctx *ctx = cf->ctx; - - CURL_TRC_CF(data, cf, "close"); - cf_he_ctx_clear(cf, data); - cf->connected = FALSE; - ctx->state = SCFST_INIT; - - if(cf->next) { - cf->next->cft->do_close(cf->next, data); - Curl_conn_cf_discard_chain(&cf->next, data); - } -} - -static bool cf_he_data_pending(struct Curl_cfilter *cf, - const struct Curl_easy *data) -{ - struct cf_he_ctx *ctx = cf->ctx; - size_t i; - - if(cf->connected) - return cf->next->cft->has_data_pending(cf->next, data); - - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - struct eyeballer *baller = ctx->baller[i]; - if(!baller || !baller->cf) - continue; - if(baller->cf->cft->has_data_pending(baller->cf, data)) - return TRUE; - } - return FALSE; -} - -static struct curltime get_max_baller_time(struct Curl_cfilter *cf, - struct Curl_easy *data, - int query) -{ - struct cf_he_ctx *ctx = cf->ctx; - struct curltime t, tmax; - size_t i; - - memset(&tmax, 0, sizeof(tmax)); - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - struct eyeballer *baller = ctx->baller[i]; - - memset(&t, 0, sizeof(t)); - if(baller && baller->cf && - !baller->cf->cft->query(baller->cf, data, query, NULL, &t)) { - if((t.tv_sec || t.tv_usec) && curlx_timediff_us(t, tmax) > 0) - tmax = t; - } - } - return tmax; -} - -static CURLcode cf_he_query(struct Curl_cfilter *cf, - struct Curl_easy *data, - int query, int *pres1, void *pres2) -{ - struct cf_he_ctx *ctx = cf->ctx; - - if(!cf->connected) { - switch(query) { - case CF_QUERY_CONNECT_REPLY_MS: { - int reply_ms = -1; - size_t i; - - for(i = 0; i < CURL_ARRAYSIZE(ctx->baller); i++) { - struct eyeballer *baller = ctx->baller[i]; - int breply_ms; - - if(baller && baller->cf && - !baller->cf->cft->query(baller->cf, data, query, - &breply_ms, NULL)) { - if(breply_ms >= 0 && (reply_ms < 0 || breply_ms < reply_ms)) - reply_ms = breply_ms; - } - } - *pres1 = reply_ms; - CURL_TRC_CF(data, cf, "query connect reply: %dms", *pres1); - return CURLE_OK; - } - case CF_QUERY_TIMER_CONNECT: { - struct curltime *when = pres2; - *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_CONNECT); - return CURLE_OK; - } - case CF_QUERY_TIMER_APPCONNECT: { - struct curltime *when = pres2; - *when = get_max_baller_time(cf, data, CF_QUERY_TIMER_APPCONNECT); - return CURLE_OK; - } - default: - break; - } - } - - return cf->next ? - cf->next->cft->query(cf->next, data, query, pres1, pres2) : - CURLE_UNKNOWN_OPTION; -} - -static void cf_he_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct cf_he_ctx *ctx = cf->ctx; - - CURL_TRC_CF(data, cf, "destroy"); - if(ctx) { - cf_he_ctx_clear(cf, data); - } - /* release any resources held in state */ - Curl_safefree(ctx); -} - -struct Curl_cftype Curl_cft_happy_eyeballs = { - "HAPPY-EYEBALLS", - 0, - CURL_LOG_LVL_NONE, - cf_he_destroy, - cf_he_connect, - cf_he_close, - cf_he_shutdown, - cf_he_adjust_pollset, - cf_he_data_pending, - Curl_cf_def_send, - Curl_cf_def_recv, - Curl_cf_def_cntrl, - Curl_cf_def_conn_is_alive, - Curl_cf_def_conn_keep_alive, - cf_he_query, -}; - -/** - * Create a happy eyeball connection filter that uses the, once resolved, - * address information to connect on ip families based on connection - * configuration. - * @param pcf output, the created cfilter - * @param data easy handle used in creation - * @param conn connection the filter is created for - * @param cf_create method to create the sub-filters performing the - * actual connects. - */ -static CURLcode -cf_happy_eyeballs_create(struct Curl_cfilter **pcf, - struct Curl_easy *data, - struct connectdata *conn, - cf_ip_connect_create *cf_create, - int transport) -{ - struct cf_he_ctx *ctx = NULL; - CURLcode result; - - (void)data; - (void)conn; - *pcf = NULL; - ctx = calloc(1, sizeof(*ctx)); - if(!ctx) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - ctx->transport = transport; - ctx->cf_create = cf_create; - - result = Curl_cf_create(pcf, &Curl_cft_happy_eyeballs, ctx); - -out: - if(result) { - Curl_safefree(*pcf); - free(ctx); - } - return result; -} - -struct transport_provider { - int transport; - cf_ip_connect_create *cf_create; -}; - -static -#ifndef UNITTESTS -const -#endif -struct transport_provider transport_providers[] = { - { TRNSPRT_TCP, Curl_cf_tcp_create }, -#ifdef USE_HTTP3 - { TRNSPRT_QUIC, Curl_cf_quic_create }, -#endif -#ifndef CURL_DISABLE_TFTP - { TRNSPRT_UDP, Curl_cf_udp_create }, -#endif -#ifdef USE_UNIX_SOCKETS - { TRNSPRT_UNIX, Curl_cf_unix_create }, -#endif -}; - -static cf_ip_connect_create *get_cf_create(int transport) -{ - size_t i; - for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) { - if(transport == transport_providers[i].transport) - return transport_providers[i].cf_create; - } - return NULL; -} - -static CURLcode cf_he_insert_after(struct Curl_cfilter *cf_at, - struct Curl_easy *data, - int transport) -{ - cf_ip_connect_create *cf_create; - struct Curl_cfilter *cf; - CURLcode result; - - /* Need to be first */ - DEBUGASSERT(cf_at); - cf_create = get_cf_create(transport); - if(!cf_create) { - CURL_TRC_CF(data, cf_at, "unsupported transport type %d", transport); - return CURLE_UNSUPPORTED_PROTOCOL; - } - result = cf_happy_eyeballs_create(&cf, data, cf_at->conn, - cf_create, transport); - if(result) - return result; - - Curl_conn_cf_insert_after(cf_at, cf); - return CURLE_OK; -} - typedef enum { CF_SETUP_INIT, CF_SETUP_CNNCT_EYEBALLS, @@ -1281,7 +390,7 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf, } if(ctx->state < CF_SETUP_CNNCT_EYEBALLS) { - result = cf_he_insert_after(cf, data, ctx->transport); + result = cf_ip_happy_insert_after(cf, data, ctx->transport); if(result) return result; ctx->state = CF_SETUP_CNNCT_EYEBALLS; @@ -1310,7 +419,7 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf, } #endif /* USE_SSL */ -#if !defined(CURL_DISABLE_HTTP) +#ifndef CURL_DISABLE_HTTP if(cf->conn->bits.tunnel_proxy) { result = Curl_cf_http_proxy_insert_after(cf, data); if(result) @@ -1324,7 +433,7 @@ static CURLcode cf_setup_connect(struct Curl_cfilter *cf, #endif /* !CURL_DISABLE_PROXY */ if(ctx->state < CF_SETUP_CNNCT_HAPROXY) { -#if !defined(CURL_DISABLE_PROXY) +#ifndef CURL_DISABLE_PROXY if(data->set.haproxyprotocol) { if(Curl_conn_is_ssl(cf->conn, cf->sockindex)) { failf(data, "haproxy protocol not support with SSL " @@ -1456,21 +565,6 @@ static CURLcode cf_setup_add(struct Curl_easy *data, return result; } -#ifdef UNITTESTS -/* used by unit2600.c */ -void Curl_debug_set_transport_provider(int transport, - cf_ip_connect_create *cf_create) -{ - size_t i; - for(i = 0; i < CURL_ARRAYSIZE(transport_providers); ++i) { - if(transport == transport_providers[i].transport) { - transport_providers[i].cf_create = cf_create; - return; - } - } -} -#endif /* UNITTESTS */ - CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at, struct Curl_easy *data, int transport, @@ -1503,7 +597,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data, Curl_resolv_unlink(data, &data->state.dns[sockindex]); data->state.dns[sockindex] = dns; -#if !defined(CURL_DISABLE_HTTP) +#ifndef CURL_DISABLE_HTTP if(!conn->cfilter[sockindex] && conn->handler->protocol == CURLPROTO_HTTPS) { DEBUGASSERT(ssl_mode != CURL_CF_SSL_DISABLE); @@ -1511,7 +605,7 @@ CURLcode Curl_conn_setup(struct Curl_easy *data, if(result) goto out; } -#endif /* !defined(CURL_DISABLE_HTTP) */ +#endif /* !CURL_DISABLE_HTTP */ /* Still no cfilter set, apply default. */ if(!conn->cfilter[sockindex]) { diff --git a/deps/curl/lib/connect.h b/deps/curl/lib/connect.h index 120338eb99f..6a2487ff538 100644 --- a/deps/curl/lib/connect.h +++ b/deps/curl/lib/connect.h @@ -107,23 +107,6 @@ void Curl_conncontrol(struct connectdata *conn, #define connkeep(x,y) Curl_conncontrol(x, CONNCTRL_KEEP) #endif -/** - * Create a cfilter for making an "ip" connection to the - * given address, using parameters from `conn`. The "ip" connection - * can be a TCP socket, a UDP socket or even a QUIC connection. - * - * It MUST use only the supplied `ai` for its connection attempt. - * - * Such a filter may be used in "happy eyeball" scenarios, and its - * `connect` implementation needs to support non-blocking. Once connected, - * it MAY be installed in the connection filter chain to serve transfers. - */ -typedef CURLcode cf_ip_connect_create(struct Curl_cfilter **pcf, - struct Curl_easy *data, - struct connectdata *conn, - const struct Curl_addrinfo *ai, - int transport); - CURLcode Curl_cf_setup_insert_after(struct Curl_cfilter *cf_at, struct Curl_easy *data, int transport, @@ -140,12 +123,6 @@ CURLcode Curl_conn_setup(struct Curl_easy *data, struct Curl_dns_entry *dns, int ssl_mode); -extern struct Curl_cftype Curl_cft_happy_eyeballs; extern struct Curl_cftype Curl_cft_setup; -#ifdef UNITTESTS -void Curl_debug_set_transport_provider(int transport, - cf_ip_connect_create *cf_create); -#endif - #endif /* HEADER_CURL_CONNECT_H */ diff --git a/deps/curl/lib/content_encoding.c b/deps/curl/lib/content_encoding.c index 9ea4a047c88..3a0549c4b1a 100644 --- a/deps/curl/lib/content_encoding.c +++ b/deps/curl/lib/content_encoding.c @@ -96,7 +96,7 @@ struct zlib_writer { static voidpf zalloc_cb(voidpf opaque, unsigned int items, unsigned int size) { - (void) opaque; + (void)opaque; /* not a typo, keep it calloc() */ return (voidpf) calloc(items, size); } @@ -104,7 +104,7 @@ zalloc_cb(voidpf opaque, unsigned int items, unsigned int size) static void zfree_cb(voidpf opaque, voidpf ptr) { - (void) opaque; + (void)opaque; free(ptr); } @@ -411,7 +411,7 @@ static CURLcode brotli_do_init(struct Curl_easy *data, struct Curl_cwriter *writer) { struct brotli_writer *bp = (struct brotli_writer *) writer; - (void) data; + (void)data; bp->br = BrotliDecoderCreateInstance(NULL, NULL, NULL); return bp->br ? CURLE_OK : CURLE_OUT_OF_MEMORY; @@ -466,7 +466,7 @@ static void brotli_do_close(struct Curl_easy *data, struct Curl_cwriter *writer) { struct brotli_writer *bp = (struct brotli_writer *) writer; - (void) data; + (void)data; if(bp->br) { BrotliDecoderDestroyInstance(bp->br); @@ -671,9 +671,9 @@ static CURLcode error_do_write(struct Curl_easy *data, struct Curl_cwriter *writer, int type, const char *buf, size_t nbytes) { - (void) writer; - (void) buf; - (void) nbytes; + (void)writer; + (void)buf; + (void)nbytes; if(!(type & CLIENTWRITE_BODY) || !nbytes) return Curl_cwriter_write(data, writer->next, type, buf, nbytes); @@ -689,8 +689,8 @@ static CURLcode error_do_write(struct Curl_easy *data, static void error_do_close(struct Curl_easy *data, struct Curl_cwriter *writer) { - (void) data; - (void) writer; + (void)data; + (void)writer; } static const struct Curl_cwtype error_writer = { @@ -843,9 +843,9 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, CURLcode Curl_build_unencoding_stack(struct Curl_easy *data, const char *enclist, int is_transfer) { - (void) data; - (void) enclist; - (void) is_transfer; + (void)data; + (void)enclist; + (void)is_transfer; return CURLE_NOT_BUILT_IN; } diff --git a/deps/curl/lib/cookie.c b/deps/curl/lib/cookie.c index 9221871e4b4..35d33268f96 100644 --- a/deps/curl/lib/cookie.c +++ b/deps/curl/lib/cookie.c @@ -107,7 +107,7 @@ static void strstore(char **str, const char *newstr, size_t len); */ static void cap_expires(time_t now, struct Cookie *co) { - if((TIME_T_MAX - COOKIES_MAXAGE - 30) > now) { + if(co->expires && (TIME_T_MAX - COOKIES_MAXAGE - 30) > now) { timediff_t cap = now + COOKIES_MAXAGE; if(co->expires > cap) { cap += 30; @@ -167,13 +167,13 @@ static bool pathmatch(const char *cookie_path, const char *uri_path) /* cookie_path must not have last '/' separator. ex: /sample */ cookie_path_len = strlen(cookie_path); - if(1 == cookie_path_len) { + if(cookie_path_len == 1) { /* cookie_path must be '/' */ return TRUE; } /* #-fragments are already cut off! */ - if(0 == strlen(uri_path) || uri_path[0] != '/') + if(strlen(uri_path) == 0 || uri_path[0] != '/') uri_path = "/"; /* @@ -296,9 +296,9 @@ static char *sanitize_cookie_path(const char *cookie_path) /* Let cookie-path be the default-path. */ return strdup("/"); - /* remove trailing slash */ + /* remove trailing slash when path is non-empty */ /* convert /hoge/ to /hoge */ - if(len && cookie_path[len - 1] == '/') + if(len > 1 && cookie_path[len - 1] == '/') len--; return Curl_memdup0(cookie_path, len); @@ -388,17 +388,17 @@ static void remove_expired(struct CookieInfo *ci) for(n = Curl_llist_head(&ci->cookielist[i]); n; n = e) { co = Curl_node_elem(n); e = Curl_node_next(n); - if(co->expires && co->expires < now) { - Curl_node_remove(n); - freecookie(co); - ci->numcookies--; - } - else { - /* - * If this cookie has an expiration timestamp earlier than what we - * have seen so far then record it for the next round of expirations. - */ - if(co->expires && co->expires < ci->next_expiration) + if(co->expires) { + if(co->expires < now) { + Curl_node_remove(n); + freecookie(co); + ci->numcookies--; + } + else if(co->expires < ci->next_expiration) + /* + * If this cookie has an expiration timestamp earlier than what we + * have seen so far then record it for the next round of expirations. + */ ci->next_expiration = co->expires; } } @@ -666,7 +666,6 @@ parse_cookie_header(struct Curl_easy *data, if(*maxage == '\"') maxage++; rc = curlx_str_number(&maxage, &co->expires, CURL_OFF_T_MAX); - switch(rc) { case STRE_OVERFLOW: /* overflow, used max value */ @@ -678,8 +677,7 @@ parse_cookie_header(struct Curl_easy *data, break; case STRE_OK: if(!co->expires) - /* already expired */ - co->expires = 1; + co->expires = 1; /* expire now */ else if(CURL_OFF_T_MAX - now < co->expires) /* would overflow */ co->expires = CURL_OFF_T_MAX; @@ -698,18 +696,15 @@ parse_cookie_header(struct Curl_easy *data, * will be treated as a session cookie */ char dbuf[MAX_DATE_LENGTH + 1]; + time_t date = 0; memcpy(dbuf, curlx_str(&val), curlx_strlen(&val)); dbuf[curlx_strlen(&val)] = 0; - co->expires = Curl_getdate_capped(dbuf); - - /* - * Session cookies have expires set to 0 so if we get that back - * from the date parser let's add a second to make it a - * non-session cookie - */ - if(co->expires == 0) - co->expires = 1; - else if(co->expires < 0) + if(!Curl_getdate_capped(dbuf, &date)) { + if(!date) + date++; + co->expires = (curl_off_t)date; + } + else co->expires = 0; cap_expires(now, co); } @@ -872,7 +867,7 @@ parse_netscape(struct Cookie *co, break; } } - if(6 == fields) { + if(fields == 6) { /* we got a cookie with blank contents, fix it */ co->value = strdup(""); if(!co->value) @@ -881,7 +876,7 @@ parse_netscape(struct Cookie *co, fields++; } - if(7 != fields) + if(fields != 7) /* we did not find the sufficient number of fields */ return CERR_FIELDS; @@ -965,7 +960,7 @@ replace_existing(struct Curl_easy *data, clist->spath && co->spath && /* both have paths */ clist->secure && !co->secure && !secure) { size_t cllen; - const char *sep; + const char *sep = NULL; /* * A non-secure cookie may not overlay an existing secure cookie. @@ -974,8 +969,9 @@ replace_existing(struct Curl_easy *data, * "/loginhelper" is ok. */ - sep = strchr(clist->spath + 1, '/'); - + DEBUGASSERT(clist->spath[0]); + if(clist->spath[0]) + sep = strchr(clist->spath + 1, '/'); if(sep) cllen = sep - clist->spath; else @@ -1102,7 +1098,7 @@ Curl_cookie_add(struct Curl_easy *data, if(!ci->running && /* read from a file */ ci->newsession && /* clean session cookies */ - !co->expires) /* this is a session cookie since it does not expire */ + !co->expires) /* this is a session cookie */ goto fail; co->livecookie = ci->running; @@ -1293,6 +1289,14 @@ static int cookie_sort_ct(const void *p1, const void *p2) return (c2->creationtime > c1->creationtime) ? 1 : -1; } +bool Curl_secure_context(struct connectdata *conn, const char *host) +{ + return conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || + curl_strequal("localhost", host) || + !strcmp(host, "127.0.0.1") || + !strcmp(host, "::1"); +} + /* * Curl_cookie_getlist * @@ -1305,15 +1309,17 @@ static int cookie_sort_ct(const void *p1, const void *p2) * Returns 0 when there is a list returned. Otherwise non-zero. */ int Curl_cookie_getlist(struct Curl_easy *data, - struct CookieInfo *ci, - const char *host, const char *path, - bool secure, + struct connectdata *conn, + const char *host, struct Curl_llist *list) { size_t matches = 0; - bool is_ip; + const bool is_ip = Curl_host_is_ipnum(host); const size_t myhash = cookiehash(host); struct Curl_llist_node *n; + const bool secure = Curl_secure_context(conn, host); + struct CookieInfo *ci = data->cookies; + const char *path = data->state.up.path; Curl_llist_init(list, NULL); @@ -1323,9 +1329,6 @@ int Curl_cookie_getlist(struct Curl_easy *data, /* at first, remove expired cookies */ remove_expired(ci); - /* check if host is an IP(v4|v6) address */ - is_ip = Curl_host_is_ipnum(host); - for(n = Curl_llist_head(&ci->cookielist[myhash]); n; n = Curl_node_next(n)) { struct Cookie *co = Curl_node_elem(n); @@ -1614,6 +1617,9 @@ static struct curl_slist *cookie_list(struct Curl_easy *data) if(!data->cookies || (data->cookies->numcookies == 0)) return NULL; + /* at first, remove expired cookies */ + remove_expired(data->cookies); + for(i = 0; i < COOKIE_HASH_SIZE; i++) { for(n = Curl_llist_head(&data->cookies->cookielist[i]); n; n = Curl_node_next(n)) { diff --git a/deps/curl/lib/cookie.h b/deps/curl/lib/cookie.h index 7af65073cd9..99aa20af7c4 100644 --- a/deps/curl/lib/cookie.h +++ b/deps/curl/lib/cookie.h @@ -105,21 +105,21 @@ struct CookieInfo { #define MAX_COOKIE_SEND_AMOUNT 150 struct Curl_easy; +struct connectdata; + /* * Add a cookie to the internal list of cookies. The domain and path arguments * are only used if the header boolean is TRUE. */ +bool Curl_secure_context(struct connectdata *conn, const char *host); struct Cookie *Curl_cookie_add(struct Curl_easy *data, struct CookieInfo *c, bool header, bool noexpiry, const char *lineptr, const char *domain, const char *path, bool secure); - -int Curl_cookie_getlist(struct Curl_easy *data, - struct CookieInfo *c, const char *host, - const char *path, bool secure, - struct Curl_llist *list); +int Curl_cookie_getlist(struct Curl_easy *data, struct connectdata *conn, + const char *host, struct Curl_llist *list); void Curl_cookie_clearall(struct CookieInfo *cookies); void Curl_cookie_clearsess(struct CookieInfo *cookies); diff --git a/deps/curl/lib/cshutdn.c b/deps/curl/lib/cshutdn.c index c8b40dc3218..1c144c6025f 100644 --- a/deps/curl/lib/cshutdn.c +++ b/deps/curl/lib/cshutdn.c @@ -486,19 +486,25 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn, { if(Curl_llist_head(&cshutdn->list)) { struct Curl_llist_node *e; + struct easy_pollset ps; + Curl_pollset_init(&ps); for(e = Curl_llist_head(&cshutdn->list); e; e = Curl_node_next(e)) { - struct easy_pollset ps; unsigned int i; struct connectdata *conn = Curl_node_elem(e); - memset(&ps, 0, sizeof(ps)); + CURLcode result; + + Curl_pollset_reset(&ps); Curl_attach_connection(data, conn); - Curl_conn_adjust_pollset(data, conn, &ps); + result = Curl_conn_adjust_pollset(data, conn, &ps); Curl_detach_connection(data); - for(i = 0; i < ps.num; i++) { -#if defined(__DJGPP__) + if(result) + continue; + + for(i = 0; i < ps.n; i++) { +#ifdef __DJGPP__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warith-conversion" #endif @@ -506,7 +512,7 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn, FD_SET(ps.sockets[i], read_fd_set); if(ps.actions[i] & CURL_POLL_OUT) FD_SET(ps.sockets[i], write_fd_set); -#if defined(__DJGPP__) +#ifdef __DJGPP__ #pragma GCC diagnostic pop #endif if((ps.actions[i] & (CURL_POLL_OUT | CURL_POLL_IN)) && @@ -514,6 +520,7 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn, *maxfd = (int)ps.sockets[i]; } } + Curl_pollset_cleanup(&ps); } } @@ -528,17 +535,21 @@ unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn, struct Curl_llist_node *e; struct easy_pollset ps; struct connectdata *conn; + CURLcode result; + Curl_pollset_init(&ps); for(e = Curl_llist_head(&cshutdn->list); e; e = Curl_node_next(e)) { conn = Curl_node_elem(e); - memset(&ps, 0, sizeof(ps)); + Curl_pollset_reset(&ps); Curl_attach_connection(data, conn); - Curl_conn_adjust_pollset(data, conn, &ps); + result = Curl_conn_adjust_pollset(data, conn, &ps); Curl_detach_connection(data); - need += Curl_waitfds_add_ps(cwfds, &ps); + if(!result) + need += Curl_waitfds_add_ps(cwfds, &ps); } + Curl_pollset_cleanup(&ps); } return need; } @@ -554,20 +565,24 @@ CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn, struct easy_pollset ps; struct connectdata *conn; + Curl_pollset_init(&ps); for(e = Curl_llist_head(&cshutdn->list); e; e = Curl_node_next(e)) { conn = Curl_node_elem(e); - memset(&ps, 0, sizeof(ps)); + Curl_pollset_reset(&ps); Curl_attach_connection(data, conn); - Curl_conn_adjust_pollset(data, conn, &ps); + result = Curl_conn_adjust_pollset(data, conn, &ps); Curl_detach_connection(data); - result = Curl_pollfds_add_ps(cpfds, &ps); + if(!result) + result = Curl_pollfds_add_ps(cpfds, &ps); if(result) { + Curl_pollset_cleanup(&ps); Curl_pollfds_cleanup(cpfds); goto out; } } + Curl_pollset_cleanup(&ps); } out: return result; diff --git a/deps/curl/lib/curl_addrinfo.c b/deps/curl/lib/curl_addrinfo.c index b131c747b10..22212ac86f8 100644 --- a/deps/curl/lib/curl_addrinfo.c +++ b/deps/curl/lib/curl_addrinfo.c @@ -68,7 +68,7 @@ */ #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \ - defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) + defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__) /* workaround icc 9.1 optimizer issue */ # define vqualifier volatile #else @@ -398,11 +398,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) addr = (void *)ai->ai_addr; /* storage area for this info */ memcpy(&addr->sin_addr, inaddr, sizeof(struct in_addr)); -#ifdef __MINGW32__ - addr->sin_family = (short)af; -#else addr->sin_family = (CURL_SA_FAMILY_T)af; -#endif addr->sin_port = htons((unsigned short)port); break; @@ -411,11 +407,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port) addr6 = (void *)ai->ai_addr; /* storage area for this info */ memcpy(&addr6->sin6_addr, inaddr, sizeof(struct in6_addr)); -#ifdef __MINGW32__ - addr6->sin6_family = (short)af; -#else addr6->sin6_family = (CURL_SA_FAMILY_T)af; -#endif addr6->sin6_port = htons((unsigned short)port); break; #endif @@ -521,7 +513,7 @@ curl_dbg_freeaddrinfo(struct addrinfo *freethis, freeaddrinfo(freethis); #endif } -#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */ +#endif /* CURLDEBUG && HAVE_FREEADDRINFO */ #if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) @@ -552,7 +544,7 @@ curl_dbg_getaddrinfo(const char *hostname, #else int res = getaddrinfo(hostname, service, hints, result); #endif - if(0 == res) + if(res == 0) /* success */ curl_dbg_log("ADDR %s:%d getaddrinfo() = %p\n", source, line, (void *)*result); @@ -561,7 +553,7 @@ curl_dbg_getaddrinfo(const char *hostname, source, line); return res; } -#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */ +#endif /* CURLDEBUG && HAVE_GETADDRINFO */ #if defined(HAVE_GETADDRINFO) && defined(USE_RESOLVE_ON_IPS) /* diff --git a/deps/curl/lib/curl_config.h.cmake b/deps/curl/lib/curl_config.h.cmake index 0838ddccfba..ca516710e42 100644 --- a/deps/curl/lib/curl_config.h.cmake +++ b/deps/curl/lib/curl_config.h.cmake @@ -336,9 +336,6 @@ /* Define to 1 if symbol `sa_family_t' exists */ #cmakedefine HAVE_SA_FAMILY_T 1 -/* Define to 1 if symbol `ADDRESS_FAMILY' exists */ -#cmakedefine HAVE_ADDRESS_FAMILY 1 - /* Define to 1 if you have the ioctlsocket function. */ #cmakedefine HAVE_IOCTLSOCKET 1 @@ -761,9 +758,6 @@ ${SIZEOF_TIME_T_CODE} /* Define to 1 if you have the quiche_conn_set_qlog_fd function. */ #cmakedefine HAVE_QUICHE_CONN_SET_QLOG_FD 1 -/* to enable msh3 */ -#cmakedefine USE_MSH3 1 - /* if Unix domain sockets are enabled */ #cmakedefine USE_UNIX_SOCKETS 1 diff --git a/deps/curl/lib/curl_config.h.in b/deps/curl/lib/curl_config.h.in index a525e96b231..397384733fb 100644 --- a/deps/curl/lib/curl_config.h.in +++ b/deps/curl/lib/curl_config.h.in @@ -5,7 +5,7 @@ /* Location of default ca bundle */ #undef CURL_CA_BUNDLE -/* define "1" to use built-in CA store of SSL library */ +/* define "1" to use OpenSSL's built-in CA store */ #undef CURL_CA_FALLBACK /* Location of default ca path */ @@ -167,9 +167,6 @@ /* Define to 1 if you have the `accept4' function. */ #undef HAVE_ACCEPT4 -/* Define to 1 if symbol `ADDRESS_FAMILY' exists */ -#undef HAVE_ADDRESS_FAMILY - /* Define to 1 if you have the alarm function. */ #undef HAVE_ALARM @@ -436,9 +433,6 @@ /* Define to 1 if you have the MSG_NOSIGNAL flag. */ #undef HAVE_MSG_NOSIGNAL -/* Define to 1 if you have the header file. */ -#undef HAVE_MSH3_H - /* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H @@ -856,9 +850,6 @@ /* if mbedTLS is enabled */ #undef USE_MBEDTLS -/* if msh3 is in use */ -#undef USE_MSH3 - /* if nghttp2 is in use */ #undef USE_NGHTTP2 diff --git a/deps/curl/lib/curl_fnmatch.c b/deps/curl/lib/curl_fnmatch.c index 21eca4ceda5..66b9739f3c0 100644 --- a/deps/curl/lib/curl_fnmatch.c +++ b/deps/curl/lib/curl_fnmatch.c @@ -74,14 +74,13 @@ typedef enum { static int parsekeyword(const unsigned char **pattern, unsigned char *charset) { parsekey_state state = CURLFNM_PKW_INIT; -#define KEYLEN 10 - char keyword[KEYLEN] = { 0 }; - int i; + char keyword[10] = { 0 }; + size_t i; const unsigned char *p = *pattern; bool found = FALSE; for(i = 0; !found; i++) { char c = (char)*p++; - if(i >= KEYLEN) + if(i >= sizeof(keyword)) return SETCHARSET_FAIL; switch(state) { case CURLFNM_PKW_INIT: diff --git a/deps/curl/lib/curl_gethostname.c b/deps/curl/lib/curl_gethostname.c index fb418b400d8..c3fa864effc 100644 --- a/deps/curl/lib/curl_gethostname.c +++ b/deps/curl/lib/curl_gethostname.c @@ -46,8 +46,8 @@ int Curl_gethostname(char * const name, GETHOSTNAME_TYPE_ARG2 namelen) #ifndef HAVE_GETHOSTNAME /* Allow compilation and return failure when unavailable */ - (void) name; - (void) namelen; + (void)name; + (void)namelen; return -1; #else diff --git a/deps/curl/lib/curl_gssapi.c b/deps/curl/lib/curl_gssapi.c index 4690218050c..92b867f7753 100644 --- a/deps/curl/lib/curl_gssapi.c +++ b/deps/curl/lib/curl_gssapi.c @@ -34,7 +34,7 @@ #include "curl_memory.h" #include "memdebug.h" -#if defined(__GNUC__) +#ifdef __GNUC__ #define CURL_ALIGN8 __attribute__((aligned(8))) #else #define CURL_ALIGN8 diff --git a/deps/curl/lib/curl_hmac.h b/deps/curl/lib/curl_hmac.h index f54edeb49ed..9675c6c5425 100644 --- a/deps/curl/lib/curl_hmac.h +++ b/deps/curl/lib/curl_hmac.h @@ -26,7 +26,7 @@ #if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) || \ !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \ - defined(USE_SSL) + defined(USE_LIBSSH2) || defined(USE_SSL) #include diff --git a/deps/curl/lib/curl_md4.h b/deps/curl/lib/curl_md4.h index 4706e49578b..f103d38b41b 100644 --- a/deps/curl/lib/curl_md4.h +++ b/deps/curl/lib/curl_md4.h @@ -27,13 +27,13 @@ #include "curl_setup.h" #include -#if defined(USE_CURL_NTLM_CORE) +#ifdef USE_CURL_NTLM_CORE #define MD4_DIGEST_LENGTH 16 CURLcode Curl_md4it(unsigned char *output, const unsigned char *input, const size_t len); -#endif /* defined(USE_CURL_NTLM_CORE) */ +#endif /* USE_CURL_NTLM_CORE */ #endif /* HEADER_CURL_MD4_H */ diff --git a/deps/curl/lib/curl_md5.h b/deps/curl/lib/curl_md5.h index ec27503b144..16272c75910 100644 --- a/deps/curl/lib/curl_md5.h +++ b/deps/curl/lib/curl_md5.h @@ -24,8 +24,8 @@ * ***************************************************************************/ -#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ - || !defined(CURL_DISABLE_DIGEST_AUTH) +#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) || \ + !defined(CURL_DISABLE_DIGEST_AUTH) #include "curl_hmac.h" diff --git a/deps/curl/lib/vquic/curl_msh3.h b/deps/curl/lib/curl_mem_undef.h similarity index 62% rename from deps/curl/lib/vquic/curl_msh3.h rename to deps/curl/lib/curl_mem_undef.h index d2862c2d896..b72e529ddeb 100644 --- a/deps/curl/lib/vquic/curl_msh3.h +++ b/deps/curl/lib/curl_mem_undef.h @@ -1,5 +1,3 @@ -#ifndef HEADER_CURL_VQUIC_CURL_MSH3_H -#define HEADER_CURL_VQUIC_CURL_MSH3_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -24,23 +22,34 @@ * ***************************************************************************/ -#include "../curl_setup.h" - -#ifdef USE_MSH3 - -#include - -void Curl_msh3_ver(char *p, size_t len); - -CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf, - struct Curl_easy *data, - struct connectdata *conn, - const struct Curl_addrinfo *ai); - -bool Curl_conn_is_msh3(const struct Curl_easy *data, - const struct connectdata *conn, - int sockindex); - -#endif /* USE_MSQUIC */ - -#endif /* HEADER_CURL_VQUIC_CURL_MSH3_H */ +/* Unset redefined system symbols. */ + +#undef strdup +#undef malloc +#undef calloc +#undef realloc +#undef free +#undef send +#undef recv + +#ifdef _WIN32 +#undef _tcsdup +#endif + +#undef socket +#ifdef HAVE_ACCEPT4 +#undef accept4 +#endif +#ifdef HAVE_SOCKETPAIR +#undef socketpair +#endif + +#undef fopen +#ifdef CURL_FOPEN +#define fopen(fname, mode) CURL_FOPEN(fname, mode) +#endif +#undef fdopen +#undef fclose + +#undef HEADER_CURL_MEMORY_H +#undef HEADER_CURL_MEMDEBUG_H diff --git a/deps/curl/lib/curl_memory.h b/deps/curl/lib/curl_memory.h index b4536c1b3f8..07ef111ce78 100644 --- a/deps/curl/lib/curl_memory.h +++ b/deps/curl/lib/curl_memory.h @@ -54,74 +54,6 @@ * */ -#ifdef HEADER_CURL_MEMDEBUG_H -/* cleanup after memdebug.h */ - -#ifdef CURLDEBUG - -#undef strdup -#undef malloc -#undef calloc -#undef realloc -#undef free -#undef send -#undef recv - -#ifdef _WIN32 -#undef _tcsdup -#endif - -#undef socket -#undef accept -#ifdef HAVE_ACCEPT4 -#undef accept4 -#endif -#ifdef HAVE_SOCKETPAIR -#undef socketpair -#endif - -/* sclose is probably already defined, redefine it! */ -#undef sclose -#define sclose(x) CURL_SCLOSE(x) -#undef fopen -#ifdef CURL_FOPEN -#define fopen(fname, mode) CURL_FOPEN(fname, mode) -#endif -#undef fdopen -#undef fclose - -#endif /* CURLDEBUG */ - -#undef HEADER_CURL_MEMDEBUG_H -#endif /* HEADER_CURL_MEMDEBUG_H */ - -/* -** Following section applies even when CURLDEBUG is not defined. -*/ - -#undef fake_sclose - -#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ -/* - * The following memory function replacement typedef's are COPIED from - * curl/curl.h and MUST match the originals. We copy them to avoid having to - * include curl/curl.h here. We avoid that include since it includes stdio.h - * and other headers that may get messed up with defines done here. - */ -typedef void *(*curl_malloc_callback)(size_t size); -typedef void (*curl_free_callback)(void *ptr); -typedef void *(*curl_realloc_callback)(void *ptr, size_t size); -typedef char *(*curl_strdup_callback)(const char *str); -typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); -#define CURL_DID_MEMORY_FUNC_TYPEDEFS -#endif - -extern curl_malloc_callback Curl_cmalloc; -extern curl_free_callback Curl_cfree; -extern curl_realloc_callback Curl_crealloc; -extern curl_strdup_callback Curl_cstrdup; -extern curl_calloc_callback Curl_ccalloc; - #ifndef CURLDEBUG /* diff --git a/deps/curl/lib/curl_ntlm_core.c b/deps/curl/lib/curl_ntlm_core.c index c35953177c9..e040db2ab65 100644 --- a/deps/curl/lib/curl_ntlm_core.c +++ b/deps/curl/lib/curl_ntlm_core.c @@ -24,7 +24,7 @@ #include "curl_setup.h" -#if defined(USE_CURL_NTLM_CORE) +#ifdef USE_CURL_NTLM_CORE /* * NTLM details: @@ -51,39 +51,35 @@ in NTLM type-3 messages. */ -#if defined(USE_OPENSSL) +#ifdef USE_OPENSSL #include #if !defined(OPENSSL_NO_DES) && !defined(OPENSSL_NO_DEPRECATED_3_0) #define USE_OPENSSL_DES #endif #elif defined(USE_WOLFSSL) #include - #if !defined(NO_DES3) + #ifndef NO_DES3 #define USE_OPENSSL_DES #endif #endif -#if defined(USE_OPENSSL_DES) +#ifdef USE_OPENSSL_DES -#if defined(USE_OPENSSL) +#ifdef USE_OPENSSL # include # include # include # include -# if defined(OPENSSL_IS_AWSLC) +# ifdef OPENSSL_IS_AWSLC /* for versions 1.2.0 to 1.30.1 */ # define DES_set_key_unchecked (void)DES_set_key -# define DESKEYARG(x) *x -# define DESKEY(x) &x -# else -# define DESKEYARG(x) *x -# define DESKEY(x) &x # endif +# define DESKEY(x) &x #else # include # include # include # include -# if defined(OPENSSL_COEXIST) +# ifdef OPENSSL_COEXIST # define DES_key_schedule WOLFSSL_DES_key_schedule # define DES_cblock WOLFSSL_DES_cblock # define DES_set_odd_parity wolfSSL_DES_set_odd_parity @@ -91,12 +87,11 @@ # define DES_set_key_unchecked wolfSSL_DES_set_key_unchecked # define DES_ecb_encrypt wolfSSL_DES_ecb_encrypt # define DESKEY(x) ((WOLFSSL_DES_key_schedule *)(x)) -# define DESKEYARG(x) *x # else -# define DESKEYARG(x) *x # define DESKEY(x) &x # endif #endif +#define DESKEYARG(x) *x #elif defined(USE_GNUTLS) @@ -129,7 +124,7 @@ #include "curl_memory.h" #include "memdebug.h" -#if !defined(CURL_NTLM_NOT_SUPPORTED) +#ifndef CURL_NTLM_NOT_SUPPORTED /* * Turns a 56-bit key into being 64-bit wide. */ @@ -146,7 +141,7 @@ static void extend_key_56_to_64(const unsigned char *key_56, char *key) } #endif -#if defined(USE_OPENSSL_DES) +#ifdef USE_OPENSSL_DES /* * Turns a 56-bit key into a 64-bit, odd parity key and sets the key. The * key schedule ks is also set. @@ -277,7 +272,7 @@ static bool encrypt_des(const unsigned char *in, unsigned char *out, return TRUE; } -#endif /* defined(USE_WIN32_CRYPTO) */ +#endif /* USE_WIN32_CRYPTO */ /* * takes a 21 byte array and treats it as 3 56-bit DES keys. The @@ -288,7 +283,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys, const unsigned char *plaintext, unsigned char *results) { -#if defined(USE_OPENSSL_DES) +#ifdef USE_OPENSSL_DES DES_key_schedule ks; setup_des_key(keys, DESKEY(ks)); @@ -329,7 +324,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password, unsigned char *lmbuffer /* 21 bytes */) { unsigned char pw[14]; -#if !defined(CURL_NTLM_NOT_SUPPORTED) +#ifndef CURL_NTLM_NOT_SUPPORTED static const unsigned char magic[] = { 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ }; @@ -342,7 +337,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password, { /* Create LanManager hashed password. */ -#if defined(USE_OPENSSL_DES) +#ifdef USE_OPENSSL_DES DES_key_schedule ks; setup_des_key(pw, DESKEY(ks)); @@ -380,7 +375,7 @@ static void ascii_to_unicode_le(unsigned char *dest, const char *src, } } -#if !defined(USE_WINDOWS_SSPI) +#ifndef USE_WINDOWS_SSPI static void ascii_uppercase_to_unicode_le(unsigned char *dest, const char *src, size_t srclen) @@ -404,7 +399,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(const char *password, size_t len = strlen(password); unsigned char *pw; CURLcode result; - if(len > SIZE_T_MAX/2) /* avoid integer overflow */ + if(len > SIZE_MAX/2) /* avoid integer overflow */ return CURLE_OUT_OF_MEMORY; pw = len ? malloc(len * 2) : (unsigned char *)strdup(""); if(!pw) @@ -422,7 +417,7 @@ CURLcode Curl_ntlm_core_mk_nt_hash(const char *password, return result; } -#if !defined(USE_WINDOWS_SSPI) +#ifndef USE_WINDOWS_SSPI #define NTLMv2_BLOB_SIGNATURE "\x01\x01\x00\x00" #define NTLMv2_BLOB_LEN (44 -16 + ntlm->target_info_len + 4) diff --git a/deps/curl/lib/curl_ntlm_core.h b/deps/curl/lib/curl_ntlm_core.h index 7571ad5432f..584f4a17d50 100644 --- a/deps/curl/lib/curl_ntlm_core.h +++ b/deps/curl/lib/curl_ntlm_core.h @@ -26,7 +26,7 @@ #include "curl_setup.h" -#if defined(USE_CURL_NTLM_CORE) +#ifdef USE_CURL_NTLM_CORE #include "vauth/vauth.h" @@ -47,7 +47,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(const char *password, CURLcode Curl_ntlm_core_mk_nt_hash(const char *password, unsigned char *ntbuffer /* 21 bytes */); -#if !defined(USE_WINDOWS_SSPI) +#ifndef USE_WINDOWS_SSPI CURLcode Curl_hmac_md5(const unsigned char *key, unsigned int keylen, const unsigned char *data, unsigned int datalen, diff --git a/deps/curl/lib/curl_rtmp.c b/deps/curl/lib/curl_rtmp.c index 0be1f7c7681..baee79fbeec 100644 --- a/deps/curl/lib/curl_rtmp.c +++ b/deps/curl/lib/curl_rtmp.c @@ -81,10 +81,10 @@ const struct Curl_handler Curl_handler_rtmp = { rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -106,10 +106,10 @@ const struct Curl_handler Curl_handler_rtmpt = { rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -131,10 +131,10 @@ const struct Curl_handler Curl_handler_rtmpe = { rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -156,10 +156,10 @@ const struct Curl_handler Curl_handler_rtmpte = { rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -181,10 +181,10 @@ const struct Curl_handler Curl_handler_rtmps = { rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -206,10 +206,10 @@ const struct Curl_handler Curl_handler_rtmpts = { rtmp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -296,10 +296,10 @@ static CURLcode rtmp_do(struct Curl_easy *data, bool *done) if(data->state.upload) { Curl_pgrsSetUploadSize(data, data->state.infilesize); - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); } else - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); *done = TRUE; return CURLE_OK; } @@ -307,9 +307,9 @@ static CURLcode rtmp_do(struct Curl_easy *data, bool *done) static CURLcode rtmp_done(struct Curl_easy *data, CURLcode status, bool premature) { - (void)data; /* unused */ - (void)status; /* unused */ - (void)premature; /* unused */ + (void)data; + (void)status; + (void)premature; return CURLE_OK; } @@ -334,7 +334,7 @@ static CURLcode rtmp_recv(struct Curl_easy *data, int sockindex, char *buf, CURLcode result = CURLE_OK; ssize_t nread; - (void)sockindex; /* unused */ + (void)sockindex; *pnread = 0; if(!r) return CURLE_FAILED_INIT; @@ -362,8 +362,8 @@ static CURLcode rtmp_send(struct Curl_easy *data, int sockindex, RTMP *r = Curl_conn_meta_get(conn, CURL_META_RTMP_CONN); ssize_t nwritten; - (void)sockindex; /* unused */ - (void)eos; /* unused */ + (void)sockindex; + (void)eos; *pnwritten = 0; if(!r) return CURLE_FAILED_INIT; diff --git a/deps/curl/lib/curl_sasl.c b/deps/curl/lib/curl_sasl.c index 766de44b85c..8eb63fb9495 100644 --- a/deps/curl/lib/curl_sasl.c +++ b/deps/curl/lib/curl_sasl.c @@ -222,7 +222,7 @@ static void sasl_state(struct SASL *sasl, struct Curl_easy *data, infof(data, "SASL %p state change from %s to %s", (void *)sasl, names[sasl->state], names[newstate]); #else - (void) data; + (void)data; #endif sasl->state = newstate; @@ -557,7 +557,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct Curl_easy *data, /* Calculate the supported authentication mechanism, by decreasing order of security, as well as the initial response where appropriate */ if(sasl_choose_external(data, &sctx) || -#if defined(USE_KERBEROS5) +#ifdef USE_KERBEROS5 sasl_choose_krb5(data, &sctx) || #endif #ifdef USE_GSASL @@ -615,8 +615,8 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, struct bufref resp; const char *hostname; int port; -#if defined(USE_KERBEROS5) || defined(USE_NTLM) \ - || !defined(CURL_DISABLE_DIGEST_AUTH) +#if defined(USE_KERBEROS5) || defined(USE_NTLM) || \ + !defined(CURL_DISABLE_DIGEST_AUTH) const char *service = data->set.str[STRING_SERVICE_NAME] ? data->set.str[STRING_SERVICE_NAME] : sasl->params->service; @@ -722,7 +722,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct Curl_easy *data, } #endif -#if defined(USE_KERBEROS5) +#ifdef USE_KERBEROS5 case SASL_GSSAPI: { struct kerberos5data *krb5 = Curl_auth_krb5_get(conn); result = !krb5 ? CURLE_OUT_OF_MEMORY : diff --git a/deps/curl/lib/curl_setup.h b/deps/curl/lib/curl_setup.h index 4dc46f7a73a..72c118affcc 100644 --- a/deps/curl/lib/curl_setup.h +++ b/deps/curl/lib/curl_setup.h @@ -75,6 +75,11 @@ #endif #endif +#if defined(__MINGW32__) && !defined(__MINGW32CE__) && \ + (!defined(__MINGW64_VERSION_MAJOR) || (__MINGW64_VERSION_MAJOR < 3)) +#error "Building curl requires mingw-w64 3.0 or later" +#endif + /* Visual Studio 2008 is the minimum Visual Studio version we support. Workarounds for older versions of Visual Studio have been removed. */ #if defined(_MSC_VER) && (_MSC_VER < 1500) @@ -331,10 +336,10 @@ #define CURL_CONC_MACROS(A,B) CURL_CONC_MACROS_(A,B) /* curl uses its own printf() function internally. It understands the GNU - * format. Use this format, so that is matches the GNU format attribute we + * format. Use this format, so that it matches the GNU format attribute we * use with the MinGW compiler, allowing it to verify them at compile-time. */ -#ifdef __MINGW32__ +#ifdef __MINGW32__ # undef CURL_FORMAT_CURL_OFF_T # undef CURL_FORMAT_CURL_OFF_TU # define CURL_FORMAT_CURL_OFF_T "lld" @@ -380,7 +385,7 @@ * performing this task will result in a synthesized IPv6 address. */ #if defined(__APPLE__) && !defined(USE_ARES) -#define USE_RESOLVE_ON_IPS 1 +# define USE_RESOLVE_ON_IPS 1 # if TARGET_OS_MAC && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) && \ defined(USE_IPV6) # define CURL_MACOS_CALL_COPYPROXIES 1 @@ -470,6 +475,12 @@ #include #endif +#if defined(HAVE_STDINT_H) || defined(USE_WOLFSSL) +#include +#endif + +#include + #ifdef _WIN32 # ifdef HAVE_IO_H # include @@ -549,11 +560,11 @@ #ifndef SIZEOF_OFF_T # if defined(__VMS) && !defined(__VAX) -# if defined(_LARGEFILE) +# ifdef _LARGEFILE # define SIZEOF_OFF_T 8 # endif # elif defined(__OS400__) && defined(__ILEC400__) -# if defined(_LARGE_FILES) +# ifdef _LARGE_FILES # define SIZEOF_OFF_T 8 # endif # elif defined(__MVS__) && defined(__IBMC__) @@ -613,21 +624,21 @@ # endif #endif -#ifndef SIZE_T_MAX +#ifndef SIZE_MAX /* some limits.h headers have this defined, some do not */ #if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4) -#define SIZE_T_MAX 18446744073709551615U +#define SIZE_MAX 18446744073709551615U #else -#define SIZE_T_MAX 4294967295U +#define SIZE_MAX 4294967295U #endif #endif -#ifndef SSIZE_T_MAX +#ifndef SSIZE_MAX /* some limits.h headers have this defined, some do not */ #if defined(SIZEOF_SIZE_T) && (SIZEOF_SIZE_T > 4) -#define SSIZE_T_MAX 9223372036854775807 +#define SSIZE_MAX 9223372036854775807 #else -#define SSIZE_T_MAX 2147483647 +#define SSIZE_MAX 2147483647 #endif #endif @@ -774,20 +785,12 @@ * Parameters should of course normally not be unused, but for example when * we have multiple implementations of the same interface it may happen. */ - #if defined(__GNUC__) && ((__GNUC__ >= 3) || \ ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7))) -# define UNUSED_PARAM __attribute__((__unused__)) # define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -#elif defined(__IAR_SYSTEMS_ICC__) -# define UNUSED_PARAM __attribute__((__unused__)) -# if (__VER__ >= 9040001) -# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) -# else -# define WARN_UNUSED_RESULT -# endif +#elif defined(__IAR_SYSTEMS_ICC__) && (__VER__ >= 9040001) +# define WARN_UNUSED_RESULT __attribute__((warn_unused_result)) #else -# define UNUSED_PARAM /* NOTHING */ # define WARN_UNUSED_RESULT #endif @@ -932,10 +935,10 @@ endings either CRLF or LF so 't' is appropriate. /* for systems that do not detect this in configure */ #ifndef CURL_SA_FAMILY_T -# if defined(HAVE_SA_FAMILY_T) -# define CURL_SA_FAMILY_T sa_family_t -# elif defined(HAVE_ADDRESS_FAMILY) +# if defined(_WIN32) && !defined(UNDER_CE) # define CURL_SA_FAMILY_T ADDRESS_FAMILY +# elif defined(HAVE_SA_FAMILY_T) +# define CURL_SA_FAMILY_T sa_family_t # elif defined(__AMIGA__) # define CURL_SA_FAMILY_T unsigned char # else @@ -956,15 +959,145 @@ endings either CRLF or LF so 't' is appropriate. #define CURL_ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0])) +#ifndef CURL_DID_MEMORY_FUNC_TYPEDEFS /* only if not already done */ +/* + * The following memory function replacement typedef's are COPIED from + * curl/curl.h and MUST match the originals. We copy them to avoid having to + * include curl/curl.h here. We avoid that include since it includes stdio.h + * and other headers that may get messed up with defines done here. + */ +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); +#define CURL_DID_MEMORY_FUNC_TYPEDEFS +#endif + +extern curl_malloc_callback Curl_cmalloc; +extern curl_free_callback Curl_cfree; +extern curl_realloc_callback Curl_crealloc; +extern curl_strdup_callback Curl_cstrdup; +extern curl_calloc_callback Curl_ccalloc; + +/* + * Curl_safefree defined as a macro to allow MemoryTracking feature + * to log free() calls at same location where Curl_safefree is used. + * This macro also assigns NULL to given pointer when free'd. + */ +#define Curl_safefree(ptr) \ + do { free((ptr)); (ptr) = NULL;} while(0) + #ifdef CURLDEBUG +#ifdef __clang__ +# define ALLOC_FUNC __attribute__((__malloc__)) +# if __clang_major__ >= 4 +# define ALLOC_SIZE(s) __attribute__((__alloc_size__(s))) +# define ALLOC_SIZE2(n, s) __attribute__((__alloc_size__(n, s))) +# else +# define ALLOC_SIZE(s) +# define ALLOC_SIZE2(n, s) +# endif +#elif defined(__GNUC__) && __GNUC__ >= 3 +# define ALLOC_FUNC __attribute__((__malloc__)) +# define ALLOC_SIZE(s) __attribute__((__alloc_size__(s))) +# define ALLOC_SIZE2(n, s) __attribute__((__alloc_size__(n, s))) +#elif defined(_MSC_VER) +# define ALLOC_FUNC __declspec(restrict) +# define ALLOC_SIZE(s) +# define ALLOC_SIZE2(n, s) +#else +# define ALLOC_FUNC +# define ALLOC_SIZE(s) +# define ALLOC_SIZE2(n, s) +#endif + +#include /* for CURL_EXTERN */ + +extern FILE *curl_dbg_logfile; + +/* memory functions */ +CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source); +CURL_EXTERN ALLOC_FUNC ALLOC_SIZE(1) + void *curl_dbg_malloc(size_t size, int line, const char *source); +CURL_EXTERN ALLOC_FUNC ALLOC_SIZE2(1, 2) + void *curl_dbg_calloc(size_t n, size_t size, int line, const char *source); +CURL_EXTERN ALLOC_SIZE(2) + void *curl_dbg_realloc(void *ptr, size_t size, int line, const char *source); +CURL_EXTERN ALLOC_FUNC + char *curl_dbg_strdup(const char *str, int line, const char *src); +#if defined(_WIN32) && defined(UNICODE) +CURL_EXTERN ALLOC_FUNC + wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source); +#endif + +CURL_EXTERN void curl_dbg_memdebug(const char *logname); +CURL_EXTERN void curl_dbg_memlimit(long limit); +CURL_EXTERN void curl_dbg_log(const char *format, ...) CURL_PRINTF(1, 2); + +/* file descriptor manipulators */ +CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol, + int line, const char *source); +CURL_EXTERN void curl_dbg_mark_sclose(curl_socket_t sockfd, + int line, const char *source); +CURL_EXTERN int curl_dbg_sclose(curl_socket_t sockfd, + int line, const char *source); +CURL_EXTERN curl_socket_t curl_dbg_accept(curl_socket_t s, void *a, void *alen, + int line, const char *source); +#ifdef HAVE_ACCEPT4 +CURL_EXTERN curl_socket_t curl_dbg_accept4(curl_socket_t s, void *saddr, + void *saddrlen, int flags, + int line, const char *source); +#endif +#ifdef HAVE_SOCKETPAIR +CURL_EXTERN int curl_dbg_socketpair(int domain, int type, int protocol, + curl_socket_t socket_vector[2], + int line, const char *source); +#endif + +/* send/receive sockets */ +CURL_EXTERN SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, + SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, + SEND_TYPE_ARG3 len, + SEND_TYPE_ARG4 flags, int line, + const char *source); +CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, + RECV_TYPE_ARG2 buf, + RECV_TYPE_ARG3 len, + RECV_TYPE_ARG4 flags, int line, + const char *source); + +/* FILE functions */ +CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source); +CURL_EXTERN ALLOC_FUNC + FILE *curl_dbg_fopen(const char *file, const char *mode, + int line, const char *source); +CURL_EXTERN ALLOC_FUNC + FILE *curl_dbg_fdopen(int filedes, const char *mode, + int line, const char *source); + +#define sclose(sockfd) curl_dbg_sclose(sockfd,__LINE__,__FILE__) +#define fake_sclose(sockfd) curl_dbg_mark_sclose(sockfd,__LINE__,__FILE__) + #define CURL_GETADDRINFO(host,serv,hint,res) \ curl_dbg_getaddrinfo(host, serv, hint, res, __LINE__, __FILE__) #define CURL_FREEADDRINFO(data) \ curl_dbg_freeaddrinfo(data, __LINE__, __FILE__) -#else + +#define CURL_ACCEPT(sock,addr,len) \ + curl_dbg_accept(sock, addr, len, __LINE__, __FILE__) + +#else /* !CURLDEBUG */ + +#define sclose(x) CURL_SCLOSE(x) +#define fake_sclose(x) Curl_nop_stmt + #define CURL_GETADDRINFO getaddrinfo #define CURL_FREEADDRINFO freeaddrinfo -#endif + +#define CURL_ACCEPT accept + +#endif /* CURLDEBUG */ /* Some versions of the Android NDK is missing the declaration */ #if defined(HAVE_GETPWUID_R) && \ @@ -986,7 +1119,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, #if (defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || \ (defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3)) || \ - defined(USE_QUICHE) || defined(USE_MSH3) + defined(USE_QUICHE) #ifdef CURL_WITH_MULTI_SSL #error "MultiSSL combined with QUIC is not supported" @@ -995,6 +1128,11 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, #define USE_HTTP3 #endif +/* WebAssembly builds have TCP_NODELAY, but runtime support is missing. */ +#ifndef __EMSCRIPTEN__ +#define CURL_TCP_NODELAY_SUPPORTED +#endif + /* Certain Windows implementations are not aligned with what curl expects, so always use the local one on this platform. E.g. the mingw-w64 implementation can return wrong results for non-ASCII inputs. */ @@ -1003,7 +1141,7 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, #endif #if defined(USE_UNIX_SOCKETS) && defined(_WIN32) -# if !defined(UNIX_PATH_MAX) +# ifndef UNIX_PATH_MAX /* Replicating logic present in afunix.h (distributed with newer Windows 10 SDK versions only) */ # define UNIX_PATH_MAX 108 @@ -1051,3 +1189,5 @@ int getpwuid_r(uid_t uid, struct passwd *pwd, char *buf, #endif #endif /* HEADER_CURL_SETUP_H */ + +#include "curl_mem_undef.h" diff --git a/deps/curl/lib/curl_setup_once.h b/deps/curl/lib/curl_setup_once.h index bec45de8888..7a54760e161 100644 --- a/deps/curl/lib/curl_setup_once.h +++ b/deps/curl/lib/curl_setup_once.h @@ -63,10 +63,6 @@ #include #endif -#if defined(HAVE_STDINT_H) || defined(USE_WOLFSSL) -#include -#endif - /* Macro to strip 'const' without triggering a compiler warning. Use it for APIs that do not or cannot support the const qualifier. */ #ifdef HAVE_STDINT_H @@ -206,8 +202,6 @@ struct timeval { # define CURL_SCLOSE(x) close((x)) #endif -#define sclose(x) CURL_SCLOSE(x) - /* * Stack-independent version of fcntl() on sockets: */ diff --git a/deps/curl/lib/curl_sha256.h b/deps/curl/lib/curl_sha256.h index f532939d056..caa5080b3f0 100644 --- a/deps/curl/lib/curl_sha256.h +++ b/deps/curl/lib/curl_sha256.h @@ -25,8 +25,8 @@ * ***************************************************************************/ -#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \ - || defined(USE_LIBSSH2) || defined(USE_SSL) +#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \ + defined(USE_LIBSSH2) || defined(USE_SSL) #include #include "curl_hmac.h" diff --git a/deps/curl/lib/curl_sha512_256.c b/deps/curl/lib/curl_sha512_256.c index 81bfddc711a..7e9b223387e 100644 --- a/deps/curl/lib/curl_sha512_256.c +++ b/deps/curl/lib/curl_sha512_256.c @@ -38,13 +38,12 @@ * * Rustls * Skip the backend if it does not support the required algorithm */ -#if defined(USE_OPENSSL) +#ifdef USE_OPENSSL # include # if (!defined(LIBRESSL_VERSION_NUMBER) && \ - defined(OPENSSL_VERSION_NUMBER) && \ - (OPENSSL_VERSION_NUMBER >= 0x10101000L)) || \ + OPENSSL_VERSION_NUMBER >= 0x10101000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && \ - (LIBRESSL_VERSION_NUMBER >= 0x3080000fL)) + LIBRESSL_VERSION_NUMBER >= 0x3080000fL) # include # if !defined(OPENSSL_NO_SHA) && !defined(OPENSSL_NO_SHA512) # include @@ -78,12 +77,12 @@ #if !defined(HAS_SHA512_256_IMPLEMENTATION) && defined(USE_GNUTLS) # include -# if defined(SHA512_256_DIGEST_SIZE) +# ifdef SHA512_256_DIGEST_SIZE # define USE_GNUTLS_SHA512_256 1 # endif #endif /* ! HAS_SHA512_256_IMPLEMENTATION && USE_GNUTLS */ -#if defined(USE_OPENSSL_SHA512_256) +#ifdef USE_OPENSSL_SHA512_256 /* OpenSSL does not provide macros for SHA-512/256 sizes */ @@ -110,8 +109,7 @@ typedef EVP_MD_CTX *Curl_sha512_256_ctx; * @return CURLE_OK if succeed, * error code otherwise */ -static CURLcode -Curl_sha512_256_init(void *context) +static CURLcode Curl_sha512_256_init(void *context) { Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context; @@ -142,10 +140,9 @@ Curl_sha512_256_init(void *context) * @return CURLE_OK if succeed, * error code otherwise */ -static CURLcode -Curl_sha512_256_update(void *context, - const unsigned char *data, - size_t length) +static CURLcode Curl_sha512_256_update(void *context, + const unsigned char *data, + size_t length) { Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context; @@ -165,9 +162,7 @@ Curl_sha512_256_update(void *context, * @return CURLE_OK if succeed, * error code otherwise */ -static CURLcode -Curl_sha512_256_finish(unsigned char *digest, - void *context) +static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context) { CURLcode ret; Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context; @@ -207,8 +202,7 @@ typedef struct sha512_256_ctx Curl_sha512_256_ctx; * @param context the calculation context * @return always CURLE_OK */ -static CURLcode -Curl_sha512_256_init(void *context) +static CURLcode Curl_sha512_256_init(void *context) { Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context; @@ -229,10 +223,9 @@ Curl_sha512_256_init(void *context) * @param length number of bytes in @a data * @return always CURLE_OK */ -static CURLcode -Curl_sha512_256_update(void *context, - const unsigned char *data, - size_t length) +static CURLcode Curl_sha512_256_update(void *context, + const unsigned char *data, + size_t length) { Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context; @@ -252,9 +245,8 @@ Curl_sha512_256_update(void *context, # bytes * @return always CURLE_OK */ -static CURLcode -Curl_sha512_256_finish(unsigned char *digest, - void *context) +static CURLcode Curl_sha512_256_finish(unsigned char *digest, + void *context) { Curl_sha512_256_ctx *const ctx = (Curl_sha512_256_ctx *)context; @@ -284,13 +276,13 @@ Curl_sha512_256_finish(unsigned char *digest, #if !defined(CURL_FORCEINLINE) && \ defined(_MSC_VER) && !defined(__GNUC__) && !defined(__clang__) -# define CURL_FORCEINLINE __forceinline +#define CURL_FORCEINLINE __forceinline #endif -#if !defined(CURL_FORCEINLINE) - /* Assume that 'CURL_INLINE' keyword works or the - * macro was already defined correctly. */ -# define CURL_FORCEINLINE CURL_INLINE +/* Assume that 'CURL_INLINE' keyword works or the + * macro was already defined correctly. */ +#ifndef CURL_FORCEINLINE +#define CURL_FORCEINLINE CURL_INLINE #endif /* Bits manipulation macros and functions. @@ -320,11 +312,11 @@ Curl_sha512_256_finish(unsigned char *digest, /* Defined as a function. The macro version may duplicate the binary code * size as each argument is used twice, so if any calculation is used * as an argument, the calculation could be done twice. */ -static CURL_FORCEINLINE curl_uint64_t -Curl_rotr64(curl_uint64_t value, unsigned int bits) +static CURL_FORCEINLINE curl_uint64_t Curl_rotr64(curl_uint64_t value, + unsigned int bits) { bits %= 64; - if(0 == bits) + if(bits == 0) return value; /* Defined in a form which modern compiler could optimize. */ return (value >> bits) | (value << (64 - bits)); @@ -380,8 +372,7 @@ Curl_rotr64(curl_uint64_t value, unsigned int bits) /** * SHA-512/256 calculation context */ -struct Curl_sha512_256ctx -{ +struct Curl_sha512_256ctx { /** * Intermediate hash value. The variable is properly aligned. Smart * compilers may automatically use fast load/store instruction for big @@ -417,8 +408,7 @@ typedef struct Curl_sha512_256ctx Curl_sha512_256_ctx; * @param context the calculation context * @return always CURLE_OK */ -static CURLcode -Curl_sha512_256_init(void *context) +static CURLcode Curl_sha512_256_init(void *context) { struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context; @@ -453,9 +443,9 @@ Curl_sha512_256_init(void *context) * @param H hash values * @param data the data buffer with #CURL_SHA512_256_BLOCK_SIZE bytes block */ -static void -Curl_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS], - const void *data) +static +void Curl_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS], + const void *data) { /* Working variables, see FIPS PUB 180-4 section 6.7, 6.4. */ @@ -619,10 +609,9 @@ Curl_sha512_256_transform(curl_uint64_t H[SHA512_256_HASH_SIZE_WORDS], * @param length number of bytes in @a data * @return always CURLE_OK */ -static CURLcode -Curl_sha512_256_update(void *context, - const unsigned char *data, - size_t length) +static CURLcode Curl_sha512_256_update(void *context, + const unsigned char *data, + size_t length) { unsigned int bytes_have; /**< Number of bytes in the context buffer */ struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context; @@ -631,7 +620,7 @@ Curl_sha512_256_update(void *context, DEBUGASSERT((data != NULL) || (length == 0)); - if(0 == length) + if(length == 0) return CURLE_OK; /* Shortcut, do nothing */ /* Note: (count & (CURL_SHA512_256_BLOCK_SIZE-1)) @@ -643,7 +632,7 @@ Curl_sha512_256_update(void *context, ctx->count_bits_hi += ctx->count >> 61; ctx->count &= CURL_UINT64_C(0x1FFFFFFFFFFFFFFF); - if(0 != bytes_have) { + if(bytes_have) { unsigned int bytes_left = CURL_SHA512_256_BLOCK_SIZE - bytes_have; if(length >= bytes_left) { /* Combine new data with data in the buffer and process the full @@ -666,7 +655,7 @@ Curl_sha512_256_update(void *context, length -= CURL_SHA512_256_BLOCK_SIZE; } - if(0 != length) { + if(length) { /* Copy incomplete block of new data (if any) to the buffer. */ memcpy(((unsigned char *) ctx_buf) + bytes_have, data, length); @@ -676,7 +665,6 @@ Curl_sha512_256_update(void *context, } - /** * Size of "length" insertion in bits. * See FIPS PUB 180-4 section 5.1.2. @@ -696,9 +684,7 @@ Curl_sha512_256_update(void *context, # bytes * @return always CURLE_OK */ -static CURLcode -Curl_sha512_256_finish(unsigned char *digest, - void *context) +static CURLcode Curl_sha512_256_finish(unsigned char *digest, void *context) { struct Curl_sha512_256ctx *const ctx = (struct Curl_sha512_256ctx *)context; curl_uint64_t num_bits; /**< Number of processed bits */ @@ -746,14 +732,14 @@ Curl_sha512_256_finish(unsigned char *digest, part of number of bits as big-endian values. See FIPS PUB 180-4 section 5.1.2. */ /* Note: the target location is predefined and buffer is always aligned */ - CURL_PUT_64BIT_BE(((unsigned char *) ctx_buf) \ + CURL_PUT_64BIT_BE(((unsigned char *) ctx_buf) \ + CURL_SHA512_256_BLOCK_SIZE \ - SHA512_256_SIZE_OF_LEN_ADD, \ ctx->count_bits_hi); - CURL_PUT_64BIT_BE(((unsigned char *) ctx_buf) \ - + CURL_SHA512_256_BLOCK_SIZE \ - - SHA512_256_SIZE_OF_LEN_ADD \ - + SHA512_256_BYTES_IN_WORD, \ + CURL_PUT_64BIT_BE(((unsigned char *) ctx_buf) \ + + CURL_SHA512_256_BLOCK_SIZE \ + - SHA512_256_SIZE_OF_LEN_ADD \ + + SHA512_256_BYTES_IN_WORD, \ num_bits); /* Process the full final block. */ Curl_sha512_256_transform(ctx->H, ctx->buffer); @@ -782,9 +768,8 @@ Curl_sha512_256_finish(unsigned char *digest, * @param input_size the size of the data pointed by @a input * @return always #CURLE_OK */ -CURLcode -Curl_sha512_256it(unsigned char *output, const unsigned char *input, - size_t input_size) +CURLcode Curl_sha512_256it(unsigned char *output, const unsigned char *input, + size_t input_size) { Curl_sha512_256_ctx ctx; CURLcode res; @@ -796,7 +781,7 @@ Curl_sha512_256it(unsigned char *output, const unsigned char *input, res = Curl_sha512_256_update(&ctx, (const void *) input, input_size); if(res != CURLE_OK) { - (void) Curl_sha512_256_finish(output, &ctx); + (void)Curl_sha512_256_finish(output, &ctx); return res; } @@ -804,22 +789,19 @@ Curl_sha512_256it(unsigned char *output, const unsigned char *input, } /* Wrapper function, takes 'unsigned int' as length type, returns void */ -static void -Curl_sha512_256_update_i(void *context, - const unsigned char *data, - unsigned int length) +static void Curl_sha512_256_update_i(void *context, + const unsigned char *data, + unsigned int length) { /* Hypothetically the function may fail, but assume it does not */ - (void) Curl_sha512_256_update(context, data, length); + (void)Curl_sha512_256_update(context, data, length); } /* Wrapper function, returns void */ -static void -Curl_sha512_256_finish_v(unsigned char *result, - void *context) +static void Curl_sha512_256_finish_v(unsigned char *result, void *context) { /* Hypothetically the function may fail, but assume it does not */ - (void) Curl_sha512_256_finish(result, context); + (void)Curl_sha512_256_finish(result, context); } /* Wrapper function, takes 'unsigned int' as length type, returns void */ diff --git a/deps/curl/lib/curl_sspi.c b/deps/curl/lib/curl_sspi.c index 5f19e960b9b..635f560b68a 100644 --- a/deps/curl/lib/curl_sspi.c +++ b/deps/curl/lib/curl_sspi.c @@ -31,7 +31,6 @@ #include "strdup.h" #include "curlx/multibyte.h" #include "system_win32.h" -#include "curlx/version_win32.h" #include "curlx/warnless.h" /* The last #include files should be: */ @@ -178,7 +177,12 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, curlx_unicodefree(passwd.tchar_ptr); /* Setup the identity's flags */ - identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY; + identity->Flags = (unsigned long) +#ifdef UNICODE + SEC_WINNT_AUTH_IDENTITY_UNICODE; +#else + SEC_WINNT_AUTH_IDENTITY_ANSI; +#endif return CURLE_OK; } diff --git a/deps/curl/lib/curl_sspi.h b/deps/curl/lib/curl_sspi.h index 540cdfd19cc..8ecd81fdea1 100644 --- a/deps/curl/lib/curl_sspi.h +++ b/deps/curl/lib/curl_sspi.h @@ -65,6 +65,7 @@ extern PSecurityFunctionTable Curl_pSecFn; #define SP_NAME_NEGOTIATE "Negotiate" #define SP_NAME_KERBEROS "Kerberos" +/* Offered by mingw-w64 v9+. MS SDK 7.0A+. */ #ifndef ISC_REQ_USE_HTTP_STYLE #define ISC_REQ_USE_HTTP_STYLE 0x01000000 #endif @@ -288,14 +289,17 @@ extern PSecurityFunctionTable Curl_pSecFn; #define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL) #endif #endif /* __MINGW32CE__ */ +/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */ #ifndef SEC_E_INVALID_PARAMETER -# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) +#define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL) #endif +/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */ #ifndef SEC_E_DELEGATION_POLICY -# define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL) +#define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL) #endif +/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */ #ifndef SEC_E_POLICY_NLTM_ONLY -# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) +#define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL) #endif #ifdef __MINGW32CE__ @@ -324,37 +328,17 @@ extern PSecurityFunctionTable Curl_pSecFn; #define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L) #endif #endif /* __MINGW32CE__ */ + +/* Offered by mingw-w64 v8+. MS SDK 6.0A+. */ #ifndef SEC_I_SIGNATURE_NEEDED #define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL) #endif -#ifndef CRYPT_E_REVOKED -#define CRYPT_E_REVOKED ((HRESULT)0x80092010L) -#endif - -#ifndef CRYPT_E_NO_REVOCATION_DLL -#define CRYPT_E_NO_REVOCATION_DLL ((HRESULT)0x80092011L) -#endif - -#ifndef CRYPT_E_NO_REVOCATION_CHECK -#define CRYPT_E_NO_REVOCATION_CHECK ((HRESULT)0x80092012L) -#endif - -#ifndef CRYPT_E_REVOCATION_OFFLINE -#define CRYPT_E_REVOCATION_OFFLINE ((HRESULT)0x80092013L) -#endif - +#ifdef __MINGW32CE__ #ifndef CRYPT_E_NOT_IN_REVOCATION_DATABASE #define CRYPT_E_NOT_IN_REVOCATION_DATABASE ((HRESULT)0x80092014L) #endif - -#ifdef UNICODE -# define SECFLAG_WINNT_AUTH_IDENTITY \ - (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE -#else -# define SECFLAG_WINNT_AUTH_IDENTITY \ - (unsigned long)SEC_WINNT_AUTH_IDENTITY_ANSI -#endif +#endif /* __MINGW32CE__ */ /* * Definitions required from ntsecapi.h are directly provided below this point diff --git a/deps/curl/lib/curl_threads.c b/deps/curl/lib/curl_threads.c index eae75440161..2750f5ad9f7 100644 --- a/deps/curl/lib/curl_threads.c +++ b/deps/curl/lib/curl_threads.c @@ -26,7 +26,7 @@ #include -#if defined(USE_THREADS_POSIX) +#ifdef USE_THREADS_POSIX # ifdef HAVE_PTHREAD_H # include # endif @@ -36,10 +36,10 @@ #include "curl_threads.h" #include "curl_memory.h" -/* The last #include file should be: */ +/* The last #include FILE should be: */ #include "memdebug.h" -#if defined(USE_THREADS_POSIX) +#ifdef USE_THREADS_POSIX struct Curl_actual_call { unsigned int (*func)(void *); @@ -59,7 +59,8 @@ static void *curl_thread_create_thunk(void *arg) return 0; } -curl_thread_t Curl_thread_create(unsigned int (*func) (void *), void *arg) +curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T + (CURL_STDCALL *func) (void *), void *arg) { curl_thread_t t = malloc(sizeof(pthread_t)); struct Curl_actual_call *ac = malloc(sizeof(struct Curl_actual_call)); @@ -99,16 +100,38 @@ int Curl_thread_join(curl_thread_t *hnd) return ret; } -#elif defined(USE_THREADS_WIN32) +/* do not use pthread_cancel if: + * - pthread_cancel seems to be absent + * - on FreeBSD, as we see hangers in CI testing + * - this is a -fsanitize=thread build + * (clang sanitizer reports false positive when functions to not return) + */ +#if defined(PTHREAD_CANCEL_ENABLE) && !defined(__FreeBSD__) +#if defined(__has_feature) +# if !__has_feature(thread_sanitizer) +#define USE_PTHREAD_CANCEL +# endif +#else /* __has_feature */ +#define USE_PTHREAD_CANCEL +#endif /* !__has_feature */ +#endif /* PTHREAD_CANCEL_ENABLE && !__FreeBSD__ */ -curl_thread_t Curl_thread_create( -#if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) - DWORD +int Curl_thread_cancel(curl_thread_t *hnd) +{ + (void)hnd; + if(*hnd != curl_thread_t_null) +#ifdef USE_PTHREAD_CANCEL + return pthread_cancel(**hnd); #else - unsigned int + return 1; /* not supported */ #endif - (CURL_STDCALL *func) (void *), - void *arg) + return 0; +} + +#elif defined(USE_THREADS_WIN32) + +curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T + (CURL_STDCALL *func) (void *), void *arg) { #if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) typedef HANDLE curl_win_thread_handle_t; @@ -147,8 +170,7 @@ void Curl_thread_destroy(curl_thread_t *hnd) int Curl_thread_join(curl_thread_t *hnd) { -#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ - (_WIN32_WINNT < _WIN32_WINNT_VISTA) +#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < _WIN32_WINNT_VISTA) int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0); #else int ret = (WaitForSingleObjectEx(*hnd, INFINITE, FALSE) == WAIT_OBJECT_0); @@ -156,7 +178,16 @@ int Curl_thread_join(curl_thread_t *hnd) Curl_thread_destroy(hnd); + return ret; } +int Curl_thread_cancel(curl_thread_t *hnd) +{ + if(*hnd != curl_thread_t_null) { + return 1; /* not supported */ + } + return 0; +} + #endif /* USE_THREADS_* */ diff --git a/deps/curl/lib/curl_threads.h b/deps/curl/lib/curl_threads.h index b060d4acd3e..115277c00ea 100644 --- a/deps/curl/lib/curl_threads.h +++ b/deps/curl/lib/curl_threads.h @@ -25,7 +25,7 @@ ***************************************************************************/ #include "curl_setup.h" -#if defined(USE_THREADS_POSIX) +#ifdef USE_THREADS_POSIX # define CURL_STDCALL # define curl_mutex_t pthread_mutex_t # define curl_thread_t pthread_t * @@ -39,8 +39,7 @@ # define curl_mutex_t CRITICAL_SECTION # define curl_thread_t HANDLE # define curl_thread_t_null (HANDLE)0 -# if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \ - (_WIN32_WINNT < _WIN32_WINNT_VISTA) +# if !defined(_WIN32_WINNT) || (_WIN32_WINNT < _WIN32_WINNT_VISTA) # define Curl_mutex_init(m) InitializeCriticalSection(m) # else # define Curl_mutex_init(m) InitializeCriticalSectionEx(m, 0, 1) @@ -48,23 +47,41 @@ # define Curl_mutex_acquire(m) EnterCriticalSection(m) # define Curl_mutex_release(m) LeaveCriticalSection(m) # define Curl_mutex_destroy(m) DeleteCriticalSection(m) +#else +# define CURL_STDCALL #endif -#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) - -curl_thread_t Curl_thread_create( #if defined(CURL_WINDOWS_UWP) || defined(UNDER_CE) - DWORD +#define CURL_THREAD_RETURN_T DWORD #else - unsigned int +#define CURL_THREAD_RETURN_T unsigned int #endif - (CURL_STDCALL *func) (void *), - void *arg); + +#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32) + +curl_thread_t Curl_thread_create(CURL_THREAD_RETURN_T + (CURL_STDCALL *func) (void *), void *arg); void Curl_thread_destroy(curl_thread_t *hnd); int Curl_thread_join(curl_thread_t *hnd); +int Curl_thread_cancel(curl_thread_t *hnd); + +#if defined(USE_THREADS_POSIX) && defined(PTHREAD_CANCEL_ENABLE) +#define Curl_thread_push_cleanup(a,b) pthread_cleanup_push(a,b) +#define Curl_thread_pop_cleanup() pthread_cleanup_pop(0) +#define Curl_thread_enable_cancel() \ + pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) +#define Curl_thread_disable_cancel() \ + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL) +#else +#define Curl_thread_push_cleanup(a,b) ((void)a,(void)b) +#define Curl_thread_pop_cleanup() Curl_nop_stmt +#define Curl_thread_enable_cancel() Curl_nop_stmt +#define Curl_thread_disable_cancel() Curl_nop_stmt +#endif + #endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */ #endif /* HEADER_CURL_THREADS_H */ diff --git a/deps/curl/lib/curl_trc.c b/deps/curl/lib/curl_trc.c index 334b6e2a1db..52671f4eaeb 100644 --- a/deps/curl/lib/curl_trc.c +++ b/deps/curl/lib/curl_trc.c @@ -41,6 +41,7 @@ #include "cf-h2-proxy.h" #include "cf-haproxy.h" #include "cf-https-connect.h" +#include "cf-ip-happy.h" #include "socks.h" #include "curlx/strparse.h" #include "vtls/vtls.h" @@ -161,10 +162,12 @@ void Curl_debug(struct Curl_easy *data, curl_infotype type, case CURLINFO_TEXT: case CURLINFO_HEADER_OUT: case CURLINFO_HEADER_IN: +#ifndef CURL_DISABLE_VERBOSE_STRINGS if(CURL_TRC_IDS(data)) { len = trc_print_ids(data, buf, TRC_LINE_MAX); fwrite(buf, len, 1, data->set.err); } +#endif fwrite(s_infotype[type], 2, 1, data->set.err); fwrite(ptr, size, 1, data->set.err); break; @@ -199,8 +202,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...) } } -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) - +#ifndef CURL_DISABLE_VERBOSE_STRINGS static void trc_infof(struct Curl_easy *data, struct curl_trc_feat *feat, @@ -271,6 +273,45 @@ struct curl_trc_feat Curl_trc_feat_dns = { CURL_LOG_LVL_NONE, }; +static const char * const Curl_trc_timer_names[]={ + "100_TIMEOUT", + "ASYNC_NAME", + "CONNECTTIMEOUT", + "DNS_PER_NAME", + "DNS_PER_NAME2", + "HAPPY_EYEBALLS_DNS", + "HAPPY_EYEBALLS", + "MULTI_PENDING", + "SPEEDCHECK", + "TIMEOUT", + "TOOFAST", + "QUIC", + "FTP_ACCEPT", + "ALPN_EYEBALLS", + "SHUTDOWN", +}; + +const char *Curl_trc_timer_name(int tid) +{ + if((tid >= 0) && ((size_t)tid < CURL_ARRAYSIZE(Curl_trc_timer_names))) + return Curl_trc_timer_names[(size_t)tid]; + return "UNKNOWN?"; +} + +void Curl_trc_multi_timeouts(struct Curl_easy *data) +{ + struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); + if(e) { + struct curltime now = curlx_now(); + while(e) { + struct time_node *n = Curl_node_elem(e); + e = Curl_node_next(e); + CURL_TRC_M(data, "[TIMEOUT] %s expires in %" FMT_TIMEDIFF_T "ns", + CURL_TIMER_NAME(n->eid), + curlx_timediff_us(n->time, now)); + } + } +} static const char * const Curl_trc_mstate_names[]={ "INIT", @@ -461,9 +502,9 @@ static struct trc_cft_def trc_cfts[] = { { &Curl_cft_udp, TRC_CT_NETWORK }, { &Curl_cft_unix, TRC_CT_NETWORK }, { &Curl_cft_tcp_accept, TRC_CT_NETWORK }, - { &Curl_cft_happy_eyeballs, TRC_CT_NETWORK }, + { &Curl_cft_ip_happy, TRC_CT_NETWORK }, { &Curl_cft_setup, TRC_CT_PROTOCOL }, -#ifdef USE_NGHTTP2 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2) { &Curl_cft_nghttp2, TRC_CT_PROTOCOL }, #endif #ifdef USE_SSL @@ -472,8 +513,8 @@ static struct trc_cft_def trc_cfts[] = { { &Curl_cft_ssl_proxy, TRC_CT_PROXY }, #endif #endif -#if !defined(CURL_DISABLE_PROXY) -#if !defined(CURL_DISABLE_HTTP) +#ifndef CURL_DISABLE_PROXY +#ifndef CURL_DISABLE_HTTP { &Curl_cft_h1_proxy, TRC_CT_PROXY }, #ifdef USE_NGHTTP2 { &Curl_cft_h2_proxy, TRC_CT_PROXY }, @@ -483,10 +524,10 @@ static struct trc_cft_def trc_cfts[] = { { &Curl_cft_haproxy, TRC_CT_PROXY }, { &Curl_cft_socks_proxy, TRC_CT_PROXY }, #endif /* !CURL_DISABLE_PROXY */ -#ifdef USE_HTTP3 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) { &Curl_cft_http3, TRC_CT_PROTOCOL }, #endif -#if !defined(CURL_DISABLE_HTTP) +#ifndef CURL_DISABLE_HTTP { &Curl_cft_http_connect, TRC_CT_PROTOCOL }, #endif }; @@ -581,7 +622,7 @@ CURLcode Curl_trc_init(void) #endif } -#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */ +#else /* CURL_DISABLE_VERBOSE_STRINGS */ CURLcode Curl_trc_init(void) { @@ -633,17 +674,18 @@ void Curl_trc_smtp(struct Curl_easy *data, const char *fmt, ...) (void)data; (void)fmt; } #endif -#if !defined(CURL_DISABLE_WEBSOCKETS) || !defined(CURL_DISABLE_HTTP) +#if !defined(CURL_DISABLE_WEBSOCKETS) && !defined(CURL_DISABLE_HTTP) void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...) { (void)data; (void)fmt; } #endif - +#ifdef USE_SSL void Curl_trc_ssls(struct Curl_easy *data, const char *fmt, ...) { (void)data; (void)fmt; } +#endif -#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */ +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ diff --git a/deps/curl/lib/curl_trc.h b/deps/curl/lib/curl_trc.h index ed7e5d89f00..fa0999250fb 100644 --- a/deps/curl/lib/curl_trc.h +++ b/deps/curl/lib/curl_trc.h @@ -85,6 +85,9 @@ void Curl_trc_cf_infof(struct Curl_easy *data, const struct Curl_cfilter *cf, void Curl_trc_multi(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); const char *Curl_trc_mstate_name(int state); +const char *Curl_trc_timer_name(int tid); +void Curl_trc_multi_timeouts(struct Curl_easy *data); + void Curl_trc_write(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); void Curl_trc_read(struct Curl_easy *data, @@ -113,12 +116,15 @@ void Curl_trc_ws(struct Curl_easy *data, const char *fmt, ...) CURL_PRINTF(2, 3); #endif +#define CURL_TRC_M_is_verbose(data) \ + Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi) + #if defined(CURL_HAVE_C99) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #define infof(data, ...) \ do { if(Curl_trc_is_verbose(data)) \ Curl_infof(data, __VA_ARGS__); } while(0) #define CURL_TRC_M(data, ...) \ - do { if(Curl_trc_ft_is_verbose(data, &Curl_trc_feat_multi)) \ + do { if(CURL_TRC_M_is_verbose(data)) \ Curl_trc_multi(data, __VA_ARGS__); } while(0) #define CURL_TRC_CF(data, cf, ...) \ do { if(Curl_trc_cf_is_verbose(cf, data)) \ @@ -202,15 +208,21 @@ extern struct curl_trc_feat Curl_trc_feat_dns; (Curl_trc_is_verbose(data) && \ (ft)->log_level >= CURL_LOG_LVL_INFO) #define CURL_MSTATE_NAME(s) Curl_trc_mstate_name((int)(s)) +#define CURL_TIMER_NAME(t) Curl_trc_timer_name((int)(t)) +#define CURL_TRC_M_TIMEOUTS(data) \ + do { if(CURL_TRC_M_is_verbose(data)) \ + Curl_trc_multi_timeouts(data); } while(0) -#else /* defined(CURL_DISABLE_VERBOSE_STRINGS) */ +#else /* CURL_DISABLE_VERBOSE_STRINGS */ /* All informational messages are not compiled in for size savings */ #define Curl_trc_is_verbose(d) (FALSE) #define Curl_trc_cf_is_verbose(x,y) (FALSE) #define Curl_trc_ft_is_verbose(x,y) (FALSE) #define CURL_MSTATE_NAME(x) ((void)(x), "-") +#define CURL_TIMER_NAME(x) ((void)(x), "-") +#define CURL_TRC_M_TIMEOUTS(x) Curl_nop_stmt -#endif /* !defined(CURL_DISABLE_VERBOSE_STRINGS) */ +#endif /* !CURL_DISABLE_VERBOSE_STRINGS */ #endif /* HEADER_CURL_TRC_H */ diff --git a/deps/curl/lib/curlx/base64.c b/deps/curl/lib/curlx/base64.c index 92ebc57e1e6..dc6e9c001ce 100644 --- a/deps/curl/lib/curlx/base64.c +++ b/deps/curl/lib/curlx/base64.c @@ -26,13 +26,6 @@ #include "../curl_setup.h" -#if !defined(CURL_DISABLE_HTTP_AUTH) || defined(USE_SSH) || \ - !defined(CURL_DISABLE_LDAP) || \ - !defined(CURL_DISABLE_SMTP) || \ - !defined(CURL_DISABLE_POP3) || \ - !defined(CURL_DISABLE_IMAP) || \ - !defined(CURL_DISABLE_DIGEST_AUTH) || \ - !defined(CURL_DISABLE_DOH) || defined(USE_SSL) || !defined(BUILDING_LIBCURL) #include #include "warnless.h" #include "base64.h" @@ -281,5 +274,3 @@ CURLcode curlx_base64url_encode(const char *inputbuff, size_t insize, { return base64_encode(base64url, 0, inputbuff, insize, outptr, outlen); } - -#endif /* no users so disabled */ diff --git a/deps/curl/lib/curlx/dynbuf.c b/deps/curl/lib/curlx/dynbuf.c index 0b8dfe8e34f..447203e42a8 100644 --- a/deps/curl/lib/curlx/dynbuf.c +++ b/deps/curl/lib/curlx/dynbuf.c @@ -71,14 +71,14 @@ void curlx_dyn_free(struct dynbuf *s) static CURLcode dyn_nappend(struct dynbuf *s, const unsigned char *mem, size_t len) { - size_t indx = s->leng; + size_t idx = s->leng; size_t a = s->allc; - size_t fit = len + indx + 1; /* new string + old string + zero byte */ + size_t fit = len + idx + 1; /* new string + old string + zero byte */ /* try to detect if there is rubbish in the struct */ DEBUGASSERT(s->init == DYNINIT); DEBUGASSERT(s->toobig); - DEBUGASSERT(indx < s->toobig); + DEBUGASSERT(idx < s->toobig); DEBUGASSERT(!s->leng || s->bufr); DEBUGASSERT(a <= s->toobig); DEBUGASSERT(!len || mem); @@ -88,7 +88,7 @@ static CURLcode dyn_nappend(struct dynbuf *s, return CURLE_TOO_LARGE; } else if(!a) { - DEBUGASSERT(!indx); + DEBUGASSERT(!idx); /* first invoke */ if(MIN_FIRST_ALLOC > s->toobig) a = s->toobig; @@ -118,8 +118,8 @@ static CURLcode dyn_nappend(struct dynbuf *s, } if(len) - memcpy(&s->bufr[indx], mem, len); - s->leng = indx + len; + memcpy(&s->bufr[idx], mem, len); + s->leng = idx + len; s->bufr[s->leng] = 0; return CURLE_OK; } @@ -231,6 +231,7 @@ CURLcode curlx_dyn_addf(struct dynbuf *s, const char *fmt, ...) DEBUGASSERT(s); DEBUGASSERT(s->init == DYNINIT); DEBUGASSERT(!s->leng || s->bufr); + DEBUGASSERT(strcmp(fmt, "%s")); /* use curlx_dyn_add instead */ va_start(ap, fmt); result = curlx_dyn_vaddf(s, fmt, ap); va_end(ap); diff --git a/deps/curl/lib/curlx/dynbuf.h b/deps/curl/lib/curlx/dynbuf.h index 27335a6fbf4..00ca0478936 100644 --- a/deps/curl/lib/curlx/dynbuf.h +++ b/deps/curl/lib/curlx/dynbuf.h @@ -62,7 +62,7 @@ int curlx_dyn_vprintf(struct dynbuf *dyn, const char *format, va_list ap_save); char *curlx_dyn_take(struct dynbuf *s, size_t *plen); /* Dynamic buffer max sizes */ -#define MAX_DYNBUF_SIZE (SIZE_T_MAX/2) +#define MAX_DYNBUF_SIZE (SIZE_MAX/2) #define DYN_DOH_RESPONSE 3000 #define DYN_DOH_CNAME 256 diff --git a/deps/curl/lib/curlx/inet_ntop.c b/deps/curl/lib/curlx/inet_ntop.c index e5ff45cb1be..3f8bcbf3668 100644 --- a/deps/curl/lib/curlx/inet_ntop.c +++ b/deps/curl/lib/curlx/inet_ntop.c @@ -54,7 +54,7 @@ * * Returns `dst' (as a const) * Note: - * - uses no statics + * - uses no static variables * - takes an unsigned char* not an in_addr as input */ static char *inet_ntop4(const unsigned char *src, char *dst, size_t size) diff --git a/deps/curl/lib/curlx/inet_ntop.h b/deps/curl/lib/curlx/inet_ntop.h index 68f8c8d132d..490f49e8a19 100644 --- a/deps/curl/lib/curlx/inet_ntop.h +++ b/deps/curl/lib/curlx/inet_ntop.h @@ -26,8 +26,6 @@ #include "../curl_setup.h" -char *curlx_inet_ntop(int af, const void *addr, char *buf, size_t size); - #ifdef HAVE_INET_NTOP #ifdef HAVE_NETINET_IN_H #include @@ -46,6 +44,8 @@ char *curlx_inet_ntop(int af, const void *addr, char *buf, size_t size); #define curlx_inet_ntop(af,addr,buf,size) \ inet_ntop(af, addr, buf, (curl_socklen_t)(size)) #endif -#endif +#else +char *curlx_inet_ntop(int af, const void *addr, char *buf, size_t size); +#endif /* HAVE_INET_NTOP */ #endif /* HEADER_CURL_INET_NTOP_H */ diff --git a/deps/curl/lib/curlx/inet_pton.h b/deps/curl/lib/curlx/inet_pton.h index 610b329f51d..a9ad24c9447 100644 --- a/deps/curl/lib/curlx/inet_pton.h +++ b/deps/curl/lib/curlx/inet_pton.h @@ -26,8 +26,6 @@ #include "../curl_setup.h" -int curlx_inet_pton(int, const char *, void *); - #ifdef HAVE_INET_PTON #ifdef HAVE_NETINET_IN_H #include @@ -43,6 +41,8 @@ int curlx_inet_pton(int, const char *, void *); #else #define curlx_inet_pton(x,y,z) inet_pton(x,y,z) #endif -#endif +#else +int curlx_inet_pton(int, const char *, void *); +#endif /* HAVE_INET_PTON */ #endif /* HEADER_CURL_INET_PTON_H */ diff --git a/deps/curl/lib/curlx/multibyte.h b/deps/curl/lib/curlx/multibyte.h index 7835fdc3b5e..c60ce258c9b 100644 --- a/deps/curl/lib/curlx/multibyte.h +++ b/deps/curl/lib/curlx/multibyte.h @@ -26,14 +26,10 @@ #include "../curl_setup.h" #ifdef _WIN32 - - /* - * MultiByte conversions using Windows kernel32 library. - */ - +/* MultiByte conversions using Windows kernel32 library. */ wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8); char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w); -#endif /* _WIN32 */ +#endif /* * Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8() diff --git a/deps/curl/lib/curlx/nonblock.c b/deps/curl/lib/curlx/nonblock.c index 409b187f1fd..b944f9546bb 100644 --- a/deps/curl/lib/curlx/nonblock.c +++ b/deps/curl/lib/curlx/nonblock.c @@ -46,7 +46,7 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ int nonblock /* TRUE or FALSE */) { -#if defined(HAVE_FCNTL_O_NONBLOCK) +#ifdef HAVE_FCNTL_O_NONBLOCK /* most recent Unix versions */ int flags; flags = sfcntl(sockfd, F_GETFL, 0); diff --git a/deps/curl/lib/curlx/strparse.c b/deps/curl/lib/curlx/strparse.c index ecdf5b96153..a29d8be2fdb 100644 --- a/deps/curl/lib/curlx/strparse.c +++ b/deps/curl/lib/curlx/strparse.c @@ -165,7 +165,7 @@ static int str_num_base(const char **linep, curl_off_t *nump, curl_off_t max, (base == 16) ? 'f' : '7'; DEBUGASSERT(linep && *linep && nump); DEBUGASSERT((base == 8) || (base == 10) || (base == 16)); - DEBUGASSERT(max >= 0); /* mostly to catch SIZE_T_MAX, which is too large */ + DEBUGASSERT(max >= 0); /* mostly to catch SIZE_MAX, which is too large */ *nump = 0; p = *linep; if(!valid_digit(*p, m)) diff --git a/deps/curl/lib/curlx/timeval.c b/deps/curl/lib/curlx/timeval.c index 501bf9c3fd9..bd8b9bcee27 100644 --- a/deps/curl/lib/curlx/timeval.c +++ b/deps/curl/lib/curlx/timeval.c @@ -115,7 +115,7 @@ struct curltime curlx_now(void) (HAVE_BUILTIN_AVAILABLE == 1) have_clock_gettime && #endif - (0 == clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow))) { + (clock_gettime(CLOCK_MONOTONIC_RAW, &tsnow) == 0)) { cnow.tv_sec = tsnow.tv_sec; cnow.tv_usec = (int)(tsnow.tv_nsec / 1000); } @@ -127,7 +127,7 @@ struct curltime curlx_now(void) (HAVE_BUILTIN_AVAILABLE == 1) have_clock_gettime && #endif - (0 == clock_gettime(CLOCK_MONOTONIC, &tsnow))) { + (clock_gettime(CLOCK_MONOTONIC, &tsnow) == 0)) { cnow.tv_sec = tsnow.tv_sec; cnow.tv_usec = (int)(tsnow.tv_nsec / 1000); } @@ -168,11 +168,11 @@ struct curltime curlx_now(void) struct curltime cnow; uint64_t usecs; - if(0 == timebase.denom) - (void) mach_timebase_info(&timebase); + if(timebase.denom == 0) + (void)mach_timebase_info(&timebase); usecs = mach_absolute_time(); - usecs *= timebase.numer; + usecs *= timebase.numer; /* spellchecker:disable-line */ usecs /= timebase.denom; usecs /= 1000; diff --git a/deps/curl/lib/curlx/wait.c b/deps/curl/lib/curlx/wait.c index f568fb6948f..4e10a8297a9 100644 --- a/deps/curl/lib/curlx/wait.c +++ b/deps/curl/lib/curlx/wait.c @@ -68,7 +68,7 @@ int curlx_wait_ms(timediff_t timeout_ms) SET_SOCKERRNO(SOCKEINVAL); return -1; } -#if defined(MSDOS) +#ifdef MSDOS delay((unsigned int)timeout_ms); #elif defined(_WIN32) /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */ diff --git a/deps/curl/lib/curlx/warnless.c b/deps/curl/lib/curlx/warnless.c index c6cb7c6e5e3..bb636a93270 100644 --- a/deps/curl/lib/curlx/warnless.c +++ b/deps/curl/lib/curlx/warnless.c @@ -98,7 +98,7 @@ unsigned long curlx_uztoul(size_t uznum) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif -#if ULONG_MAX < SIZE_T_MAX +#if ULONG_MAX < SIZE_MAX DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG); #endif return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG); @@ -119,7 +119,7 @@ unsigned int curlx_uztoui(size_t uznum) # pragma warning(disable:810) /* conversion may lose significant bits */ #endif -#if UINT_MAX < SIZE_T_MAX +#if UINT_MAX < SIZE_MAX DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT); #endif return (unsigned int)(uznum & (size_t) CURL_MASK_UINT); @@ -243,7 +243,7 @@ int curlx_sztosi(ssize_t sznum) #endif DEBUGASSERT(sznum >= 0); -#if INT_MAX < SSIZE_T_MAX +#if INT_MAX < SSIZE_MAX DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT); #endif return (int)(sznum & (ssize_t) CURL_MASK_SINT); diff --git a/deps/curl/lib/cw-out.c b/deps/curl/lib/cw-out.c index ee7dc65dffc..6d988a00bf8 100644 --- a/deps/curl/lib/cw-out.c +++ b/deps/curl/lib/cw-out.c @@ -74,6 +74,7 @@ typedef enum { CW_OUT_NONE, CW_OUT_BODY, + CW_OUT_BODY_0LEN, CW_OUT_HDS } cw_out_type; @@ -170,6 +171,7 @@ static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype, { switch(otype) { case CW_OUT_BODY: + case CW_OUT_BODY_0LEN: *pwcb = data->set.fwrite_func; *pwcb_data = data->set.out; *pmax_write = CURL_MAX_WRITE_SIZE; @@ -193,6 +195,51 @@ static void cw_get_writefunc(struct Curl_easy *data, cw_out_type otype, } } +static CURLcode cw_out_cb_write(struct cw_out_ctx *ctx, + struct Curl_easy *data, + curl_write_callback wcb, + void *wcb_data, + cw_out_type otype, + const char *buf, size_t blen, + size_t *pnwritten) +{ + size_t nwritten; + CURLcode result; + + DEBUGASSERT(data->conn); + *pnwritten = 0; + Curl_set_in_callback(data, TRUE); + nwritten = wcb((char *)CURL_UNCONST(buf), 1, blen, wcb_data); + Curl_set_in_callback(data, FALSE); + CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes -> %zu", + blen, (otype == CW_OUT_HDS) ? "header" : "body", + nwritten); + if(CURL_WRITEFUNC_PAUSE == nwritten) { + if(data->conn->handler->flags & PROTOPT_NONETWORK) { + /* Protocols that work without network cannot be paused. This is + actually only FILE:// just now, and it cannot pause since the + transfer is not done using the "normal" procedure. */ + failf(data, "Write callback asked for PAUSE when not supported"); + return CURLE_WRITE_ERROR; + } + ctx->paused = TRUE; + CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client"); + result = Curl_xfer_pause_recv(data, TRUE); + return result ? result : CURLE_AGAIN; + } + else if(CURL_WRITEFUNC_ERROR == nwritten) { + failf(data, "client returned ERROR on write of %zu bytes", blen); + return CURLE_WRITE_ERROR; + } + else if(nwritten != blen) { + failf(data, "Failure writing output to destination, " + "passed %zu returned %zd", blen, nwritten); + return CURLE_WRITE_ERROR; + } + *pnwritten = nwritten; + return CURLE_OK; +} + static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx, struct Curl_easy *data, cw_out_type otype, @@ -204,6 +251,7 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx, void *wcb_data; size_t max_write, min_write; size_t wlen, nwritten; + CURLcode result; /* If we errored once, we do not invoke the client callback again */ if(ctx->errored) @@ -217,40 +265,24 @@ static CURLcode cw_out_ptr_flush(struct cw_out_ctx *ctx, } *pconsumed = 0; - while(blen && !ctx->paused) { - if(!flush_all && blen < min_write) - break; - wlen = max_write ? CURLMIN(blen, max_write) : blen; - Curl_set_in_callback(data, TRUE); - nwritten = wcb((char *)CURL_UNCONST(buf), 1, wlen, wcb_data); - Curl_set_in_callback(data, FALSE); - CURL_TRC_WRITE(data, "[OUT] wrote %zu %s bytes -> %zu", - wlen, (otype == CW_OUT_BODY) ? "body" : "header", - nwritten); - if(CURL_WRITEFUNC_PAUSE == nwritten) { - if(data->conn && data->conn->handler->flags & PROTOPT_NONETWORK) { - /* Protocols that work without network cannot be paused. This is - actually only FILE:// just now, and it cannot pause since the - transfer is not done using the "normal" procedure. */ - failf(data, "Write callback asked for PAUSE when not supported"); - return CURLE_WRITE_ERROR; - } - ctx->paused = TRUE; - CURL_TRC_WRITE(data, "[OUT] PAUSE requested by client"); - return Curl_xfer_pause_recv(data, TRUE); - } - else if(CURL_WRITEFUNC_ERROR == nwritten) { - failf(data, "client returned ERROR on write of %zu bytes", wlen); - return CURLE_WRITE_ERROR; - } - else if(nwritten != wlen) { - failf(data, "Failure writing output to destination, " - "passed %zu returned %zd", wlen, nwritten); - return CURLE_WRITE_ERROR; + if(otype == CW_OUT_BODY_0LEN) { + DEBUGASSERT(!blen); + return cw_out_cb_write(ctx, data, wcb, wcb_data, otype, + buf, blen, &nwritten); + } + else { + while(blen && !ctx->paused) { + if(!flush_all && blen < min_write) + break; + wlen = max_write ? CURLMIN(blen, max_write) : blen; + result = cw_out_cb_write(ctx, data, wcb, wcb_data, otype, + buf, wlen, &nwritten); + if(result) + return result; + *pconsumed += nwritten; + blen -= nwritten; + buf += nwritten; } - *pconsumed += nwritten; - blen -= nwritten; - buf += nwritten; } return CURLE_OK; } @@ -262,14 +294,14 @@ static CURLcode cw_out_buf_flush(struct cw_out_ctx *ctx, { CURLcode result = CURLE_OK; - if(curlx_dyn_len(&cwbuf->b)) { + if(curlx_dyn_len(&cwbuf->b) || (cwbuf->type == CW_OUT_BODY_0LEN)) { size_t consumed; result = cw_out_ptr_flush(ctx, data, cwbuf->type, flush_all, curlx_dyn_ptr(&cwbuf->b), curlx_dyn_len(&cwbuf->b), &consumed); - if(result) + if(result && (result != CURLE_AGAIN)) return result; if(consumed) { @@ -382,8 +414,9 @@ static CURLcode cw_out_do_write(struct cw_out_ctx *ctx, size_t consumed; result = cw_out_ptr_flush(ctx, data, otype, flush_all, buf, blen, &consumed); - if(result) + if(result && (result != CURLE_AGAIN)) return result; + result = CURLE_OK; if(consumed < blen) { /* did not write all, append the rest */ result = cw_out_append(ctx, data, otype, @@ -413,7 +446,9 @@ static CURLcode cw_out_write(struct Curl_easy *data, if((type & CLIENTWRITE_BODY) || ((type & CLIENTWRITE_HEADER) && data->set.include_header)) { - result = cw_out_do_write(ctx, data, CW_OUT_BODY, flush_all, buf, blen); + cw_out_type otype = (!blen && (type & CLIENTWRITE_0LEN)) ? + CW_OUT_BODY_0LEN : CW_OUT_BODY; + result = cw_out_do_write(ctx, data, otype, flush_all, buf, blen); if(result) return result; } diff --git a/deps/curl/lib/dict.c b/deps/curl/lib/dict.c index 7f13e6f7ea9..819584f284a 100644 --- a/deps/curl/lib/dict.c +++ b/deps/curl/lib/dict.c @@ -92,10 +92,10 @@ const struct Curl_handler Curl_handler_dict = { ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -242,7 +242,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) failf(data, "Failed sending DICT request"); goto error; } - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); /* no upload */ + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); } else if(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) || curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) || @@ -283,7 +283,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) failf(data, "Failed sending DICT request"); goto error; } - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); } else { @@ -305,7 +305,7 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) goto error; } - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); } } diff --git a/deps/curl/lib/dllmain.c b/deps/curl/lib/dllmain.c index 33076e05714..7ac457ae055 100644 --- a/deps/curl/lib/dllmain.c +++ b/deps/curl/lib/dllmain.c @@ -37,10 +37,8 @@ #if defined(_WIN32) && !defined(CURL_STATICLIB) #if defined(USE_OPENSSL) && \ - !defined(OPENSSL_IS_AWSLC) && \ - !defined(OPENSSL_IS_BORINGSSL) && \ - !defined(LIBRESSL_VERSION_NUMBER) && \ - (OPENSSL_VERSION_NUMBER >= 0x10100000L) + !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) && \ + !defined(LIBRESSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L #define PREVENT_OPENSSL_MEMLEAK #endif diff --git a/deps/curl/lib/doh.c b/deps/curl/lib/doh.c index f96ae0824a4..030b026fe29 100644 --- a/deps/curl/lib/doh.c +++ b/deps/curl/lib/doh.c @@ -348,10 +348,10 @@ static CURLcode doh_probe_run(struct Curl_easy *data, #endif #ifndef DEBUGBUILD /* enforce HTTPS if not debug */ - ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, (long)CURLPROTO_HTTPS); + ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTPS); #else /* in debug mode, also allow http */ - ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, (long)CURLPROTO_HTTP|CURLPROTO_HTTPS); + ERROR_CHECK_SETOPT(CURLOPT_PROTOCOLS, CURLPROTO_HTTP|CURLPROTO_HTTPS); #endif ERROR_CHECK_SETOPT(CURLOPT_TIMEOUT_MS, (long)timeout_ms); ERROR_CHECK_SETOPT(CURLOPT_SHARE, (CURLSH *)data->share); @@ -484,7 +484,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, data->sub_xfer_done = doh_probe_done; /* create IPv4 DoH request */ - result = doh_probe_run(data, DNS_TYPE_A, + result = doh_probe_run(data, CURL_DNS_TYPE_A, hostname, data->set.str[STRING_DOH], data->multi, &dohp->probe_resp[DOH_SLOT_IPV4].probe_mid); @@ -495,7 +495,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, #ifdef USE_IPV6 if((ip_version != CURL_IPRESOLVE_V4) && Curl_ipv6works(data)) { /* create IPv6 DoH request */ - result = doh_probe_run(data, DNS_TYPE_AAAA, + result = doh_probe_run(data, CURL_DNS_TYPE_AAAA, hostname, data->set.str[STRING_DOH], data->multi, &dohp->probe_resp[DOH_SLOT_IPV6].probe_mid); @@ -514,7 +514,7 @@ struct Curl_addrinfo *Curl_doh(struct Curl_easy *data, if(!qname) goto error; } - result = doh_probe_run(data, DNS_TYPE_HTTPS, + result = doh_probe_run(data, CURL_DNS_TYPE_HTTPS, qname ? qname : hostname, data->set.str[STRING_DOH], data->multi, &dohp->probe_resp[DOH_SLOT_HTTPS_RR].probe_mid); @@ -581,7 +581,7 @@ static void doh_store_a(const unsigned char *doh, int index, /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { struct dohaddr *a = &d->addr[d->numaddr]; - a->type = DNS_TYPE_A; + a->type = CURL_DNS_TYPE_A; memcpy(&a->ip.v4, &doh[index], 4); d->numaddr++; } @@ -593,7 +593,7 @@ static void doh_store_aaaa(const unsigned char *doh, int index, /* silently ignore addresses over the limit */ if(d->numaddr < DOH_MAX_ADDR) { struct dohaddr *a = &d->addr[d->numaddr]; - a->type = DNS_TYPE_AAAA; + a->type = CURL_DNS_TYPE_AAAA; memcpy(&a->ip.v6, &doh[index], 16); d->numaddr++; } @@ -681,29 +681,29 @@ static DOHcode doh_rdata(const unsigned char *doh, DOHcode rc; switch(type) { - case DNS_TYPE_A: + case CURL_DNS_TYPE_A: if(rdlength != 4) return DOH_DNS_RDATA_LEN; doh_store_a(doh, index, d); break; - case DNS_TYPE_AAAA: + case CURL_DNS_TYPE_AAAA: if(rdlength != 16) return DOH_DNS_RDATA_LEN; doh_store_aaaa(doh, index, d); break; #ifdef USE_HTTPSRR - case DNS_TYPE_HTTPS: + case CURL_DNS_TYPE_HTTPS: rc = doh_store_https(doh, index, d, rdlength); if(rc) return rc; break; #endif - case DNS_TYPE_CNAME: + case CURL_DNS_TYPE_CNAME: rc = doh_store_cname(doh, dohlen, (unsigned int)index, d); if(rc) return rc; break; - case DNS_TYPE_DNAME: + case CURL_DNS_TYPE_DNAME: /* explicit for clarity; just skip; rely on synthesized CNAME */ break; default: @@ -770,8 +770,8 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, return DOH_DNS_OUT_OF_RANGE; type = doh_get16bit(doh, index); - if((type != DNS_TYPE_CNAME) /* may be synthesized from DNAME */ - && (type != DNS_TYPE_DNAME) /* if present, accept and ignore */ + if((type != CURL_DNS_TYPE_CNAME) /* may be synthesized from DNAME */ + && (type != CURL_DNS_TYPE_DNAME) /* if present, accept and ignore */ && (type != dnstype)) /* Not the same type as was asked for nor CNAME nor DNAME */ return DOH_DNS_UNEXPECTED_TYPE; @@ -855,9 +855,10 @@ UNITTEST DOHcode doh_resp_decode(const unsigned char *doh, return DOH_DNS_MALFORMAT; /* something is wrong */ #ifdef USE_HTTTPS - if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr && !d->numhttps_rrs) + if((type != CURL_DNS_TYPE_NS) && !d->numcname && !d->numaddr && + !d->numhttps_rrs) #else - if((type != DNS_TYPE_NS) && !d->numcname && !d->numaddr) + if((type != CURL_DNS_TYPE_NS) && !d->numcname && !d->numaddr) #endif /* nothing stored! */ return DOH_NO_CONTENT; @@ -873,12 +874,12 @@ static void doh_show(struct Curl_easy *data, infof(data, "[DoH] TTL: %u seconds", d->ttl); for(i = 0; i < d->numaddr; i++) { const struct dohaddr *a = &d->addr[i]; - if(a->type == DNS_TYPE_A) { + if(a->type == CURL_DNS_TYPE_A) { infof(data, "[DoH] A: %u.%u.%u.%u", a->ip.v4[0], a->ip.v4[1], a->ip.v4[2], a->ip.v4[3]); } - else if(a->type == DNS_TYPE_AAAA) { + else if(a->type == CURL_DNS_TYPE_AAAA) { int j; char buffer[128] = "[DoH] AAAA: "; size_t len = strlen(buffer); @@ -948,7 +949,7 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname, for(i = 0; i < de->numaddr; i++) { size_t ss_size; CURL_SA_FAMILY_T addrtype; - if(de->addr[i].type == DNS_TYPE_AAAA) { + if(de->addr[i].type == CURL_DNS_TYPE_AAAA) { #ifndef USE_IPV6 /* we cannot handle IPv6 addresses */ continue; @@ -1025,12 +1026,12 @@ static CURLcode doh2ai(const struct dohentry *de, const char *hostname, static const char *doh_type2name(DNStype dnstype) { switch(dnstype) { - case DNS_TYPE_A: + case CURL_DNS_TYPE_A: return "A"; - case DNS_TYPE_AAAA: + case CURL_DNS_TYPE_AAAA: return "AAAA"; #ifdef USE_HTTPSRR - case DNS_TYPE_HTTPS: + case CURL_DNS_TYPE_HTTPS: return "HTTPS"; #endif default: @@ -1248,8 +1249,8 @@ CURLcode Curl_doh_is_resolved(struct Curl_easy *data, p->dnstype, &de); #ifndef CURL_DISABLE_VERBOSE_STRINGS if(rc[slot]) { - infof(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]), - doh_type2name(p->dnstype), dohp->host); + CURL_TRC_DNS(data, "DoH: %s type %s for %s", doh_strerror(rc[slot]), + doh_type2name(p->dnstype), dohp->host); } #endif } /* next slot */ diff --git a/deps/curl/lib/doh.h b/deps/curl/lib/doh.h index 9146f53580f..3fd7de2c1c5 100644 --- a/deps/curl/lib/doh.h +++ b/deps/curl/lib/doh.h @@ -51,12 +51,12 @@ typedef enum { } DOHcode; typedef enum { - DNS_TYPE_A = 1, - DNS_TYPE_NS = 2, - DNS_TYPE_CNAME = 5, - DNS_TYPE_AAAA = 28, - DNS_TYPE_DNAME = 39, /* RFC6672 */ - DNS_TYPE_HTTPS = 65 + CURL_DNS_TYPE_A = 1, + CURL_DNS_TYPE_NS = 2, + CURL_DNS_TYPE_CNAME = 5, + CURL_DNS_TYPE_AAAA = 28, + CURL_DNS_TYPE_DNAME = 39, /* RFC6672 */ + CURL_DNS_TYPE_HTTPS = 65 } DNStype; enum doh_slot_num { diff --git a/deps/curl/lib/easy.c b/deps/curl/lib/easy.c index 9c1f1c6969b..b9b8d527548 100644 --- a/deps/curl/lib/easy.c +++ b/deps/curl/lib/easy.c @@ -107,7 +107,7 @@ static curl_simple_lock s_lock = CURL_SIMPLE_LOCK_INIT; * ways, but at this point it must be defined as the system-supplied strdup * so the callback pointer is initialized correctly. */ -#if defined(UNDER_CE) +#ifdef UNDER_CE #define system_strdup _strdup #elif !defined(HAVE_STRDUP) #define system_strdup Curl_strdup @@ -465,8 +465,8 @@ static int events_socket(CURL *easy, /* easy handle */ bool found = FALSE; struct Curl_easy *data = easy; -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) easy; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)easy; #endif (void)socketp; @@ -567,6 +567,39 @@ static unsigned int populate_fds(struct pollfd *fds, struct events *ev) return numfds; } +/* poll_fds() + * + * poll the fds[] array + */ +static CURLcode poll_fds(struct events *ev, + struct pollfd *fds, + const unsigned int numfds, + int *pollrc) +{ + if(numfds) { + /* wait for activity or timeout */ +#if DEBUG_EV_POLL + fprintf(stderr, "poll(numfds=%u, timeout=%ldms)\n", numfds, ev->ms); +#endif + *pollrc = Curl_poll(fds, numfds, ev->ms); +#if DEBUG_EV_POLL + fprintf(stderr, "poll(numfds=%u, timeout=%ldms) -> %d\n", + numfds, ev->ms, *pollrc); +#endif + if(*pollrc < 0) + return CURLE_UNRECOVERABLE_POLL; + } + else { +#if DEBUG_EV_POLL + fprintf(stderr, "poll, but no fds, wait timeout=%ldms\n", ev->ms); +#endif + *pollrc = 0; + if(ev->ms > 0) + curlx_wait_ms(ev->ms); + } + return CURLE_OK; +} + /* wait_or_timeout() * * waits for activity on any of the given sockets, or the timeout to trigger. @@ -587,27 +620,9 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev) /* get the time stamp to use to figure out how long poll takes */ before = curlx_now(); - if(numfds) { - /* wait for activity or timeout */ -#if DEBUG_EV_POLL - fprintf(stderr, "poll(numfds=%u, timeout=%ldms)\n", numfds, ev->ms); -#endif - pollrc = Curl_poll(fds, numfds, ev->ms); -#if DEBUG_EV_POLL - fprintf(stderr, "poll(numfds=%u, timeout=%ldms) -> %d\n", - numfds, ev->ms, pollrc); -#endif - if(pollrc < 0) - return CURLE_UNRECOVERABLE_POLL; - } - else { -#if DEBUG_EV_POLL - fprintf(stderr, "poll, but no fds, wait timeout=%ldms\n", ev->ms); -#endif - pollrc = 0; - if(ev->ms > 0) - curlx_wait_ms(ev->ms); - } + result = poll_fds(ev, fds, numfds, &pollrc); + if(result) + return result; ev->msbump = FALSE; /* reset here */ @@ -822,7 +837,6 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events) return result; } - /* * curl_easy_perform() is the external interface that performs a blocking * transfer as previously setup. @@ -841,7 +855,6 @@ CURLcode curl_easy_perform_ev(struct Curl_easy *data) { return easy_perform(data, TRUE); } - #endif /* @@ -950,7 +963,11 @@ static void dupeasy_meta_freeentry(void *p) CURL *curl_easy_duphandle(CURL *d) { struct Curl_easy *data = d; - struct Curl_easy *outcurl = calloc(1, sizeof(struct Curl_easy)); + struct Curl_easy *outcurl = NULL; + + if(!GOOD_EASY_HANDLE(data)) + goto fail; + outcurl = calloc(1, sizeof(struct Curl_easy)); if(!outcurl) goto fail; @@ -1074,6 +1091,9 @@ CURL *curl_easy_duphandle(CURL *d) void curl_easy_reset(CURL *d) { struct Curl_easy *data = d; + if(!GOOD_EASY_HANDLE(data)) + return; + Curl_req_hard_reset(&data->req, data); Curl_hash_clean(&data->meta_hash); @@ -1097,6 +1117,7 @@ void curl_easy_reset(CURL *d) data->progress.hide = TRUE; data->state.current_speed = -1; /* init to negative == impossible */ data->state.retrycount = 0; /* reset the retry counter */ + data->state.recent_conn_id = -1; /* clear remembered connection id */ /* zero out authentication data: */ memset(&data->state.authhost, 0, sizeof(struct auth)); @@ -1154,13 +1175,15 @@ CURLcode curl_easy_pause(CURL *d, int action) /* If not completely pausing both directions now, run again in any case. */ if(!Curl_xfer_is_blocked(data)) { - Curl_expire(data, 0, EXPIRE_RUN_NOW); /* reset the too-slow time keeper */ data->state.keeps_speed.tv_sec = 0; - /* On changes, tell application to update its timers. */ - if(changed && data->multi) { - if(Curl_update_timer(data->multi) && !result) - result = CURLE_ABORTED_BY_CALLBACK; + if(data->multi) { + Curl_multi_mark_dirty(data); /* make it run */ + /* On changes, tell application to update its timers. */ + if(changed) { + if(Curl_update_timer(data->multi) && !result) + result = CURLE_ABORTED_BY_CALLBACK; + } } } @@ -1213,6 +1236,8 @@ CURLcode curl_easy_recv(CURL *d, void *buffer, size_t buflen, size_t *n) struct connectdata *c; struct Curl_easy *data = d; + if(!GOOD_EASY_HANDLE(data)) + return CURLE_BAD_FUNCTION_ARGUMENT; if(Curl_is_in_callback(data)) return CURLE_RECURSIVE_API_CALL; @@ -1288,6 +1313,8 @@ CURLcode curl_easy_send(CURL *d, const void *buffer, size_t buflen, size_t *n) size_t written = 0; CURLcode result; struct Curl_easy *data = d; + if(!GOOD_EASY_HANDLE(data)) + return CURLE_BAD_FUNCTION_ARGUMENT; if(Curl_is_in_callback(data)) return CURLE_RECURSIVE_API_CALL; @@ -1317,7 +1344,7 @@ CURLcode curl_easy_ssls_import(CURL *d, const char *session_key, const unsigned char *shmac, size_t shmac_len, const unsigned char *sdata, size_t sdata_len) { -#ifdef USE_SSLS_EXPORT +#if defined(USE_SSL) && defined(USE_SSLS_EXPORT) struct Curl_easy *data = d; if(!GOOD_EASY_HANDLE(data)) return CURLE_BAD_FUNCTION_ARGUMENT; @@ -1338,7 +1365,7 @@ CURLcode curl_easy_ssls_export(CURL *d, curl_ssls_export_cb *export_fn, void *userptr) { -#ifdef USE_SSLS_EXPORT +#if defined(USE_SSL) && defined(USE_SSLS_EXPORT) struct Curl_easy *data = d; if(!GOOD_EASY_HANDLE(data)) return CURLE_BAD_FUNCTION_ARGUMENT; diff --git a/deps/curl/lib/easy_lock.h b/deps/curl/lib/easy_lock.h index ec324cfc81a..909753f43aa 100644 --- a/deps/curl/lib/easy_lock.h +++ b/deps/curl/lib/easy_lock.h @@ -30,12 +30,6 @@ #if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 -#ifdef __MINGW32__ -#ifndef SRWLOCK_INIT -#define SRWLOCK_INIT NULL -#endif -#endif /* __MINGW32__ */ - #define curl_simple_lock SRWLOCK #define CURL_SIMPLE_LOCK_INIT SRWLOCK_INIT @@ -44,7 +38,7 @@ #elif defined(HAVE_ATOMIC) && defined(HAVE_STDATOMIC_H) #include -#if defined(HAVE_SCHED_YIELD) +#ifdef HAVE_SCHED_YIELD #include #endif diff --git a/deps/curl/lib/easygetopt.c b/deps/curl/lib/easygetopt.c index 01131216320..7ac39bc634e 100644 --- a/deps/curl/lib/easygetopt.c +++ b/deps/curl/lib/easygetopt.c @@ -82,7 +82,7 @@ const struct curl_easyoption *curl_easy_option_by_name(const char *name) return NULL; } -const struct curl_easyoption *curl_easy_option_by_id (CURLoption id) +const struct curl_easyoption *curl_easy_option_by_id(CURLoption id) { (void)id; return NULL; diff --git a/deps/curl/lib/file.c b/deps/curl/lib/file.c index b88f6123056..749759653d5 100644 --- a/deps/curl/lib/file.c +++ b/deps/curl/lib/file.c @@ -120,10 +120,10 @@ const struct Curl_handler Curl_handler_file = { file_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ file_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -292,8 +292,8 @@ static CURLcode file_done(struct Curl_easy *data, CURLcode status, bool premature) { struct FILEPROTO *file = Curl_meta_get(data, CURL_META_FILE_EASY); - (void)status; /* not used */ - (void)premature; /* not used */ + (void)status; + (void)premature; if(file) file_cleanup(file); @@ -305,7 +305,7 @@ static CURLcode file_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection) { - (void)dead_connection; /* not used */ + (void)dead_connection; (void)conn; return file_done(data, CURLE_OK, FALSE); } @@ -348,7 +348,7 @@ static CURLcode file_upload(struct Curl_easy *data, mode |= O_TRUNC; #if (defined(ANDROID) || defined(__ANDROID__)) && \ - (defined(__i386__) || defined(__arm__)) + (defined(__i386__) || defined(__arm__)) fd = open(file->path, mode, (mode_t)data->set.new_file_perms); #else fd = open(file->path, mode, data->set.new_file_perms); @@ -358,7 +358,7 @@ static CURLcode file_upload(struct Curl_easy *data, return CURLE_WRITE_ERROR; } - if(-1 != data->state.infilesize) + if(data->state.infilesize != -1) /* known size of data to "upload" */ Curl_pgrsSetUploadSize(data, data->state.infilesize); @@ -470,7 +470,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done) fd = file->fd; /* VMS: This only works reliable for STREAMLF files */ - if(-1 != fstat(fd, &statbuf)) { + if(fstat(fd, &statbuf) != -1) { if(!S_ISDIR(statbuf.st_mode)) expected_size = statbuf.st_size; /* and store the modification time */ diff --git a/deps/curl/lib/fileinfo.c b/deps/curl/lib/fileinfo.c index c3439af341e..47cdb102e37 100644 --- a/deps/curl/lib/fileinfo.c +++ b/deps/curl/lib/fileinfo.c @@ -23,7 +23,9 @@ ***************************************************************************/ #include "curl_setup.h" + #ifndef CURL_DISABLE_FTP + #include "strdup.h" #include "fileinfo.h" #include "curl_memory.h" @@ -43,4 +45,5 @@ void Curl_fileinfo_cleanup(struct fileinfo *finfo) curlx_dyn_free(&finfo->buf); free(finfo); } + #endif diff --git a/deps/curl/lib/fopen.c b/deps/curl/lib/fopen.c index 38b87f326e3..b28977317a8 100644 --- a/deps/curl/lib/fopen.c +++ b/deps/curl/lib/fopen.c @@ -136,7 +136,7 @@ CURLcode Curl_fopen(struct Curl_easy *data, const char *filename, result = CURLE_WRITE_ERROR; #if (defined(ANDROID) || defined(__ANDROID__)) && \ - (defined(__i386__) || defined(__arm__)) + (defined(__i386__) || defined(__arm__)) fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, (mode_t)(0600|sb.st_mode)); #else fd = open(tempstore, O_WRONLY | O_CREAT | O_EXCL, 0600|sb.st_mode); diff --git a/deps/curl/lib/formdata.c b/deps/curl/lib/formdata.c index 5a4b52ea57a..d8553e32569 100644 --- a/deps/curl/lib/formdata.c +++ b/deps/curl/lib/formdata.c @@ -186,22 +186,24 @@ static void free_formlist(struct FormInfo *ptr) * Examples: * * Simple name/value pair with copied contents: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); + * curl_formadd(&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_COPYCONTENTS, "value", CURLFORM_END); * * name/value pair where only the content pointer is remembered: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END); + * curl_formadd(&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, + * CURLFORM_END); * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used) * * storing a filename (CONTENTTYPE is optional!): - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", - * CURLFORM_END); + * curl_formadd(&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text", + * CURLFORM_END); * * storing multiple filenames: - * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name", - * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END); + * curl_formadd(&post, &last, CURLFORM_COPYNAME, "name", + * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", + * CURLFORM_END); * * Returns: * CURL_FORMADD_OK on success @@ -926,9 +928,9 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost, int curl_formget(struct curl_httppost *form, void *arg, curl_formget_callback append) { - (void) form; - (void) arg; - (void) append; + (void)form; + (void)arg; + (void)append; return CURL_FORMADD_DISABLED; } diff --git a/deps/curl/lib/ftp.c b/deps/curl/lib/ftp.c index 06c486bc917..29c2f789a3e 100644 --- a/deps/curl/lib/ftp.c +++ b/deps/curl/lib/ftp.c @@ -150,7 +150,8 @@ static void _ftp_state(struct Curl_easy *data, #endif ) { -#if defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; #ifdef DEBUGBUILD (void)lineno; #endif @@ -213,10 +214,10 @@ static CURLcode ftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead_connection); static CURLcode ftp_do_more(struct Curl_easy *data, int *completed); static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done); -static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *socks); -static int ftp_domore_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); +static CURLcode ftp_pollset(struct Curl_easy *data, + struct easy_pollset *ps); +static CURLcode ftp_domore_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode ftp_doing(struct Curl_easy *data, bool *dophase_done); static CURLcode ftp_setup_connection(struct Curl_easy *data, @@ -256,10 +257,10 @@ const struct Curl_handler Curl_handler_ftp = { ftp_connect, /* connect_it */ ftp_multi_statemach, /* connecting */ ftp_doing, /* doing */ - ftp_getsock, /* proto_getsock */ - ftp_getsock, /* doing_getsock */ - ftp_domore_getsock, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ftp_pollset, /* proto_pollset */ + ftp_pollset, /* doing_pollset */ + ftp_domore_pollset, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -289,10 +290,10 @@ const struct Curl_handler Curl_handler_ftps = { ftp_connect, /* connect_it */ ftp_multi_statemach, /* connecting */ ftp_doing, /* doing */ - ftp_getsock, /* proto_getsock */ - ftp_getsock, /* doing_getsock */ - ftp_domore_getsock, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ftp_pollset, /* proto_pollset */ + ftp_pollset, /* doing_pollset */ + ftp_domore_pollset, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ftp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -330,19 +331,10 @@ static void close_secondarysocket(struct Curl_easy *data, static void freedirs(struct ftp_conn *ftpc) { - if(ftpc->dirs) { - int i; - for(i = 0; i < ftpc->dirdepth; i++) { - free(ftpc->dirs[i]); - ftpc->dirs[i] = NULL; - } - free(ftpc->dirs); - ftpc->dirs = NULL; - ftpc->dirdepth = 0; - } - Curl_safefree(ftpc->file); - - /* no longer of any use */ + Curl_safefree(ftpc->dirs); + ftpc->dirdepth = 0; + Curl_safefree(ftpc->rawpath); + ftpc->file = NULL; Curl_safefree(ftpc->newhost); } @@ -545,12 +537,13 @@ static CURLcode ftp_initiate_transfer(struct Curl_easy *data, /* FTP upload, shutdown DATA, ignore shutdown errors, as we rely * on the server response on the CONTROL connection. */ - Curl_xfer_setup2(data, CURL_XFER_SEND, -1, TRUE, TRUE); + Curl_xfer_setup_send(data, SECONDARYSOCKET); + Curl_xfer_set_shutdown(data, TRUE, TRUE); } else { /* FTP download, shutdown, do not ignore errors */ - Curl_xfer_setup2(data, CURL_XFER_RECV, - ftpc->retr_size_saved, TRUE, FALSE); + Curl_xfer_setup_recv(data, SECONDARYSOCKET, ftpc->retr_size_saved); + Curl_xfer_set_shutdown(data, TRUE, FALSE); } ftpc->pp.pending_resp = TRUE; /* expect server response */ @@ -578,12 +571,12 @@ static CURLcode ftp_readresp(struct Curl_easy *data, struct ftp_conn *ftpc, int sockindex, struct pingpong *pp, - int *ftpcode, /* return the ftp-code if done */ + int *ftpcodep, /* return the ftp-code if done */ size_t *size) /* size of the response */ { int code; CURLcode result = Curl_pp_readresp(data, sockindex, pp, &code, size); - + DEBUGASSERT(ftpcodep); #ifdef HAVE_GSSAPI { struct connectdata *conn = data->conn; @@ -611,10 +604,9 @@ static CURLcode ftp_readresp(struct Curl_easy *data, if(!ftpc->shutdown) data->info.httpcode = code; - if(ftpcode) - *ftpcode = code; + *ftpcodep = code; - if(421 == code) { + if(code == 421) { /* 421 means "Service not available, closing control connection." and FTP * servers use it to signal that idle session timeout has been exceeded. * If we ignored the response, it could end up hanging in some cases. @@ -640,7 +632,7 @@ static CURLcode ftp_readresp(struct Curl_easy *data, CURLcode Curl_GetFTPResponse(struct Curl_easy *data, ssize_t *nreadp, /* return number of bytes read */ - int *ftpcode) /* return the ftp-code */ + int *ftpcodep) /* return the ftp-code */ { /* * We cannot read just one byte per read() and then go back to select() as @@ -656,20 +648,16 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, struct pingpong *pp = &ftpc->pp; size_t nread; int cache_skip = 0; - int value_to_be_ignored = 0; + DEBUGASSERT(ftpcodep); CURL_TRC_FTP(data, "getFTPResponse start"); *nreadp = 0; - if(ftpcode) - *ftpcode = 0; /* 0 for errors */ - else - /* make the pointer point to something for the rest of this function */ - ftpcode = &value_to_be_ignored; + *ftpcodep = 0; /* 0 for errors */ if(!ftpc) return CURLE_FAILED_INIT; - while(!*ftpcode && !result) { + while(!*ftpcodep && !result) { /* check and reset timeout value every lap */ timediff_t timeout = Curl_pp_state_timeout(data, pp, FALSE); timediff_t interval_ms; @@ -727,7 +715,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, break; } - result = ftp_readresp(data, ftpc, FIRSTSOCKET, pp, ftpcode, &nread); + result = ftp_readresp(data, ftpc, FIRSTSOCKET, pp, ftpcodep, &nread); if(result) break; @@ -746,7 +734,7 @@ CURLcode Curl_GetFTPResponse(struct Curl_easy *data, pp->pending_resp = FALSE; CURL_TRC_FTP(data, "getFTPResponse -> result=%d, nread=%zd, ftpcode=%d", - result, *nreadp, *ftpcode); + result, *nreadp, *ftpcodep); return result; } @@ -780,42 +768,53 @@ static CURLcode ftp_state_pwd(struct Curl_easy *data, } /* For the FTP "protocol connect" and "doing" phases only */ -static int ftp_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks) +static CURLcode ftp_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); - return ftpc ? Curl_pp_getsock(data, &ftpc->pp, socks) : GETSOCK_BLANK; + struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); + return ftpc ? Curl_pp_pollset(data, &ftpc->pp, ps) : CURLE_OK; } /* For the FTP "DO_MORE" phase only */ -static int ftp_domore_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks) +static CURLcode ftp_domore_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); - (void)data; + struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN); if(!ftpc) - return GETSOCK_BLANK; + return CURLE_OK; /* When in DO_MORE state, we could be either waiting for us to connect to a * remote site, or we could wait for that site to connect to us. Or just * handle ordinary commands. */ - CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_CSTATE(ftpc)); + CURL_TRC_FTP(data, "[%s] ftp_domore_pollset()", FTP_CSTATE(ftpc)); if(FTP_STOP == ftpc->state) { /* if stopped and still in this state, then we are also waiting for a connect on the secondary connection */ - DEBUGASSERT(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD || - (conn->cfilter[SECONDARYSOCKET] && - !Curl_conn_is_connected(conn, SECONDARYSOCKET))); - socks[0] = conn->sock[FIRSTSOCKET]; + DEBUGASSERT(data->conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD || + (data->conn->cfilter[SECONDARYSOCKET] && + !Curl_conn_is_connected(data->conn, SECONDARYSOCKET))); /* An unconnected SECONDARY will add its socket by itself * via its adjust_pollset() */ - return GETSOCK_READSOCK(0); + return Curl_pollset_add_in(data, ps, data->conn->sock[FIRSTSOCKET]); } - return Curl_pp_getsock(data, &ftpc->pp, socks); + return Curl_pp_pollset(data, &ftpc->pp, ps); +} + +static int pathlen(struct ftp_conn *ftpc, int num) +{ + DEBUGASSERT(ftpc->dirs); + DEBUGASSERT(ftpc->dirdepth > num); + return ftpc->dirs[num].len; +} + +static const char *pathpiece(struct ftp_conn *ftpc, int num) +{ + DEBUGASSERT(ftpc->dirs); + DEBUGASSERT(ftpc->dirdepth > num); + return &ftpc->rawpath[ ftpc->dirs[num].start ]; } /* This is called after the FTP_QUOTE state is passed. @@ -836,13 +835,13 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data, else { /* FTPFILE_NOCWD with full path: expect ftpc->cwddone! */ DEBUGASSERT((data->set.ftp_filemethod != FTPFILE_NOCWD) || - !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')); + !(ftpc->dirdepth && ftpc->rawpath[0] == '/')); ftpc->count2 = 0; /* count2 counts failed CWDs */ if(data->conn->bits.reuse && ftpc->entrypath && /* no need to go to entrypath when we have an absolute path */ - !(ftpc->dirdepth && ftpc->dirs[0][0] == '/')) { + !(ftpc->dirdepth && ftpc->rawpath[0] == '/')) { /* This is a reused connection. Since we change directory to where the transfer is taking place, we must first get back to the original dir where we ended up after login: */ @@ -857,8 +856,8 @@ static CURLcode ftp_state_cwd(struct Curl_easy *data, ftpc->cwdcount = 1; /* issue the first CWD, the rest is sent when the CWD responses are received... */ - result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", - ftpc->dirs[ftpc->cwdcount -1]); + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %.*s", + pathlen(ftpc, 0), pathpiece(ftpc, 0)); if(!result) ftp_state(data, ftpc, FTP_CWD); } @@ -1257,7 +1256,7 @@ static CURLcode ftp_state_use_port(struct Curl_easy *data, !Curl_conn_is_ssl(conn, SECONDARYSOCKET)) { result = Curl_ssl_cfilter_add(data, conn, SECONDARYSOCKET); } - data->conn->bits.do_more = FALSE; + conn->bits.do_more = FALSE; Curl_pgrsTime(data, TIMER_STARTACCEPT); Curl_expire(data, (data->set.accepttimeout > 0) ? data->set.accepttimeout: DEFAULT_ACCEPT_TIMEOUT, @@ -1416,18 +1415,14 @@ static CURLcode ftp_state_list(struct Curl_easy *data, The other ftp_filemethods will CWD into dir/dir/ first and then just do LIST (in that case: nothing to do here) */ - char *lstArg = NULL; + const char *lstArg = NULL; + int lstArglen = 0; char *cmd; if((data->set.ftp_filemethod == FTPFILE_NOCWD) && ftp->path) { /* url-decode before evaluation: e.g. paths starting/ending with %2f */ - const char *slashPos = NULL; - char *rawPath = NULL; - result = Curl_urldecode(ftp->path, 0, &rawPath, NULL, REJECT_CTRL); - if(result) - return result; - - slashPos = strrchr(rawPath, '/'); + const char *rawPath = ftpc->rawpath; + const char *slashPos = strrchr(rawPath, '/'); if(slashPos) { /* chop off the file part if format is dir/file otherwise remove the trailing slash for dir/dir/ except for absolute path / */ @@ -1436,19 +1431,16 @@ static CURLcode ftp_state_list(struct Curl_easy *data, ++n; lstArg = rawPath; - lstArg[n] = '\0'; + lstArglen = (int)n; } - else - free(rawPath); } - cmd = aprintf("%s%s%s", + cmd = aprintf("%s%s%.*s", data->set.str[STRING_CUSTOMREQUEST] ? data->set.str[STRING_CUSTOMREQUEST] : (data->state.list_only ? "NLST" : "LIST"), lstArg ? " " : "", - lstArg ? lstArg : ""); - free(lstArg); + lstArglen, lstArg ? lstArg : ""); if(!cmd) return CURLE_OUT_OF_MEMORY; @@ -1792,17 +1784,23 @@ static CURLcode ftp_epsv_disable(struct Curl_easy *data, } -static char *control_address(struct connectdata *conn) +static char *control_address_dup(struct Curl_easy *data, + struct connectdata *conn) { + struct ip_quadruple ipquad; + bool is_ipv6; + /* Returns the control connection IP address. If a proxy tunnel is used, returns the original hostname instead, because the effective control connection address is the proxy address, not the ftp host. */ #ifndef CURL_DISABLE_PROXY if(conn->bits.tunnel_proxy || conn->bits.socksproxy) - return conn->host.name; + return strdup(conn->host.name); #endif - return conn->primary.remote_ip; + if(!Curl_conn_get_ip_info(data, conn, FIRSTSOCKET, &is_ipv6, &ipquad)) + return strdup(ipquad.remote_ip); + return NULL; } static bool match_pasv_6nums(const char *p, @@ -1855,7 +1853,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, return CURLE_FTP_WEIRD_PASV_REPLY; } ftpc->newport = (unsigned short)num; - ftpc->newhost = strdup(control_address(conn)); + ftpc->newhost = control_address_dup(data, conn); if(!ftpc->newhost) return CURLE_OUT_OF_MEMORY; } @@ -1899,7 +1897,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, infof(data, "Skip %u.%u.%u.%u for data connection, reuse %s instead", ip[0], ip[1], ip[2], ip[3], conn->host.name); - ftpc->newhost = strdup(control_address(conn)); + ftpc->newhost = control_address_dup(data, conn); } else ftpc->newhost = aprintf("%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]); @@ -1920,17 +1918,24 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, #ifndef CURL_DISABLE_PROXY if(conn->bits.proxy) { - /* - * This connection uses a proxy and we need to connect to the proxy again + /* This connection uses a proxy and we need to connect to the proxy again * here. We do not want to rely on a former host lookup that might've - * expired now, instead we remake the lookup here and now! - */ + * expired now, instead we remake the lookup here and now! */ + struct ip_quadruple ipquad; + bool is_ipv6; const char * const host_name = conn->bits.socksproxy ? conn->socks_proxy.host.name : conn->http_proxy.host.name; - (void)Curl_resolv_blocking(data, host_name, conn->primary.remote_port, - conn->ip_version, &dns); + + result = Curl_conn_get_ip_info(data, data->conn, FIRSTSOCKET, + &is_ipv6, &ipquad); + if(result) + return result; + + (void)Curl_resolv_blocking(data, host_name, ipquad.remote_port, + is_ipv6 ? CURL_IPRESOLVE_V6 : CURL_IPRESOLVE_V4, + &dns); /* we connect to the proxy's port */ - connectport = (unsigned short)conn->primary.remote_port; + connectport = (unsigned short)ipquad.remote_port; if(!dns) { failf(data, "cannot resolve proxy host %s:%hu", host_name, connectport); @@ -1946,7 +1951,7 @@ static CURLcode ftp_state_pasv_resp(struct Curl_easy *data, /* postponed address resolution in case of tcp fastopen */ if(conn->bits.tcp_fastopen && !conn->bits.reuse && !ftpc->newhost[0]) { free(ftpc->newhost); - ftpc->newhost = strdup(control_address(conn)); + ftpc->newhost = control_address_dup(data, conn); if(!ftpc->newhost) return CURLE_OUT_OF_MEMORY; } @@ -2067,7 +2072,7 @@ static CURLcode client_write_header(struct Curl_easy *data, * the body write callback when data->set.include_header is set * via CURLOPT_HEADER. * For historic reasons, FTP never played this game and expects - * all its HEADERs to do that always. Set that flag during the + * all its headers to do that always. Set that flag during the * call to Curl_client_write() so it does the right thing. * * Notice that we cannot enable this flag for FTP in general, @@ -2097,6 +2102,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, int year, month, day, hour, minute, second; struct pingpong *pp = &ftpc->pp; char *resp = curlx_dyn_ptr(&pp->recvbuf) + 4; + bool showtime = FALSE; if(ftp_213_date(resp, &year, &month, &day, &hour, &minute, &second)) { /* we have a time, reformat it */ char timebuf[24]; @@ -2104,7 +2110,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, "%04d%02d%02d %02d:%02d:%02d GMT", year, month, day, hour, minute, second); /* now, convert this into a time() value: */ - data->info.filetime = Curl_getdate_capped(timebuf); + if(!Curl_getdate_capped(timebuf, &data->info.filetime)) + showtime = TRUE; } #ifdef CURL_FTP_HTTPSTYLE_HEAD @@ -2117,10 +2124,8 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data, warning: comparison of unsigned expression in '>= 0' is always true */ #pragma GCC diagnostic ignored "-Wtype-limits" #endif - if(data->req.no_body && - ftpc->file && - data->set.get_filetime && - (data->info.filetime >= 0) ) { + if(data->req.no_body && ftpc->file && + data->set.get_filetime && showtime) { #if defined(__GNUC__) && (defined(__DJGPP__) || defined(__AMIGA__)) #pragma GCC diagnostic pop #endif @@ -2355,7 +2360,7 @@ static CURLcode ftp_state_size_resp(struct Curl_easy *data, if(instate == FTP_SIZE) { #ifdef CURL_FTP_HTTPSTYLE_HEAD - if(-1 != filesize) { + if(filesize != -1) { char clbuf[128]; int clbuflen = msnprintf(clbuf, sizeof(clbuf), "Content-Length: %" FMT_OFF_T "\r\n", filesize); @@ -2686,6 +2691,175 @@ static CURLcode ftp_state_acct_resp(struct Curl_easy *data, return result; } +static CURLcode ftp_pwd_resp(struct Curl_easy *data, + struct ftp_conn *ftpc, + int ftpcode) +{ + struct pingpong *pp = &ftpc->pp; + CURLcode result; + + if(ftpcode == 257) { + char *ptr = curlx_dyn_ptr(&pp->recvbuf) + 4; /* start on the first + letter */ + bool entry_extracted = FALSE; + struct dynbuf out; + curlx_dyn_init(&out, 1000); + + /* Reply format is like + 257[rubbish]"" and the + RFC959 says + + The directory name can contain any character; embedded + double-quotes should be escaped by double-quotes (the + "quote-doubling" convention). + */ + + /* scan for the first double-quote for non-standard responses */ + while(*ptr != '\n' && *ptr != '\0' && *ptr != '"') + ptr++; + + if('\"' == *ptr) { + /* it started good */ + for(ptr++; *ptr; ptr++) { + if('\"' == *ptr) { + if('\"' == ptr[1]) { + /* "quote-doubling" */ + result = curlx_dyn_addn(&out, &ptr[1], 1); + ptr++; + } + else { + /* end of path */ + if(curlx_dyn_len(&out)) + entry_extracted = TRUE; + break; /* get out of this loop */ + } + } + else + result = curlx_dyn_addn(&out, ptr, 1); + if(result) + return result; + } + } + if(entry_extracted) { + /* If the path name does not look like an absolute path (i.e.: it + does not start with a '/'), we probably need some server-dependent + adjustments. For example, this is the case when connecting to + an OS400 FTP server: this server supports two name syntaxes, + the default one being incompatible with standard paths. In + addition, this server switches automatically to the regular path + syntax when one is encountered in a command: this results in + having an entrypath in the wrong syntax when later used in CWD. + The method used here is to check the server OS: we do it only + if the path name looks strange to minimize overhead on other + systems. */ + char *dir = curlx_dyn_ptr(&out); + + if(!ftpc->server_os && dir[0] != '/') { + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); + if(result) { + free(dir); + return result; + } + free(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + free(data->state.most_recent_ftp_entrypath); + data->state.most_recent_ftp_entrypath = strdup(ftpc->entrypath); + if(!data->state.most_recent_ftp_entrypath) + return CURLE_OUT_OF_MEMORY; + ftp_state(data, ftpc, FTP_SYST); + return result; + } + + free(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'", ftpc->entrypath); + /* also save it where getinfo can access it: */ + free(data->state.most_recent_ftp_entrypath); + data->state.most_recent_ftp_entrypath = strdup(ftpc->entrypath); + if(!data->state.most_recent_ftp_entrypath) + return CURLE_OUT_OF_MEMORY; + } + else { + /* could not get the path */ + curlx_dyn_free(&out); + infof(data, "Failed to figure out path"); + } + } + ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ + CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); + return CURLE_OK; +} + +static const char * const ftpauth[] = { "SSL", "TLS" }; + +static CURLcode ftp_wait_resp(struct Curl_easy *data, + struct connectdata *conn, + struct ftp_conn *ftpc, + int ftpcode) +{ + CURLcode result = CURLE_OK; + if(ftpcode == 230) { + /* 230 User logged in - already! Take as 220 if TLS required. */ + if(data->set.use_ssl <= CURLUSESSL_TRY || + conn->bits.ftp_use_control_ssl) + return ftp_state_user_resp(data, ftpc, ftpcode); + } + else if(ftpcode != 220) { + failf(data, "Got a %03d ftp-server response when 220 was expected", + ftpcode); + return CURLE_WEIRD_SERVER_REPLY; + } + + /* We have received a 220 response fine, now we proceed. */ +#ifdef HAVE_GSSAPI + if(data->set.krb) { + /* If not anonymous login, try a secure login. Note that this + procedure is still BLOCKING. */ + + Curl_sec_request_prot(conn, "private"); + /* We set private first as default, in case the line below fails to + set a valid level */ + Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); + + if(Curl_sec_login(data, conn)) { + failf(data, "secure login failed"); + return CURLE_WEIRD_SERVER_REPLY; + } + infof(data, "Authentication successful"); + } +#endif + + if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { + /* We do not have an SSL/TLS control connection yet, but FTPS is + requested. Try an FTPS connection now */ + + ftpc->count3 = 0; + switch((long)data->set.ftpsslauth) { + case CURLFTPAUTH_DEFAULT: + case CURLFTPAUTH_SSL: + ftpc->count2 = 1; /* add one to get next */ + ftpc->count1 = 0; + break; + case CURLFTPAUTH_TLS: + ftpc->count2 = -1; /* subtract one to get next */ + ftpc->count1 = 1; + break; + default: + failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", + (int)data->set.ftpsslauth); + return CURLE_UNKNOWN_OPTION; /* we do not know what to do */ + } + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + if(!result) + ftp_state(data, ftpc, FTP_AUTH); + } + else + result = ftp_state_user(data, ftpc, conn); + return result; +} static CURLcode ftp_pp_statemachine(struct Curl_easy *data, struct connectdata *conn) @@ -2695,7 +2869,6 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN); struct FTP *ftp = Curl_meta_get(data, CURL_META_FTP_EASY); struct pingpong *pp; - static const char * const ftpauth[] = { "SSL", "TLS" }; size_t nread = 0; if(!ftpc || !ftp) @@ -2705,450 +2878,306 @@ static CURLcode ftp_pp_statemachine(struct Curl_easy *data, return Curl_pp_flushsend(data, pp); result = ftp_readresp(data, ftpc, FIRSTSOCKET, pp, &ftpcode, &nread); - if(result) + if(result || !ftpcode) return result; - if(ftpcode) { - /* we have now received a full FTP server response */ - switch(ftpc->state) { - case FTP_WAIT220: - if(ftpcode == 230) { - /* 230 User logged in - already! Take as 220 if TLS required. */ - if(data->set.use_ssl <= CURLUSESSL_TRY || - conn->bits.ftp_use_control_ssl) - return ftp_state_user_resp(data, ftpc, ftpcode); - } - else if(ftpcode != 220) { - failf(data, "Got a %03d ftp-server response when 220 was expected", - ftpcode); - return CURLE_WEIRD_SERVER_REPLY; - } - - /* We have received a 220 response fine, now we proceed. */ -#ifdef HAVE_GSSAPI - if(data->set.krb) { - /* If not anonymous login, try a secure login. Note that this - procedure is still BLOCKING. */ - - Curl_sec_request_prot(conn, "private"); - /* We set private first as default, in case the line below fails to - set a valid level */ - Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]); - - if(Curl_sec_login(data, conn)) { - failf(data, "secure login failed"); - return CURLE_WEIRD_SERVER_REPLY; - } - infof(data, "Authentication successful"); - } -#endif - - if(data->set.use_ssl && !conn->bits.ftp_use_control_ssl) { - /* We do not have an SSL/TLS control connection yet, but FTPS is - requested. Try an FTPS connection now */ - - ftpc->count3 = 0; - switch(data->set.ftpsslauth) { - case CURLFTPAUTH_DEFAULT: - case CURLFTPAUTH_SSL: - ftpc->count2 = 1; /* add one to get next */ - ftpc->count1 = 0; - break; - case CURLFTPAUTH_TLS: - ftpc->count2 = -1; /* subtract one to get next */ - ftpc->count1 = 1; - break; - default: - failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d", - (int)data->set.ftpsslauth); - return CURLE_UNKNOWN_OPTION; /* we do not know what to do */ - } - result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", - ftpauth[ftpc->count1]); - if(!result) - ftp_state(data, ftpc, FTP_AUTH); - } - else - result = ftp_state_user(data, ftpc, conn); - break; + /* we have now received a full FTP server response */ + switch(ftpc->state) { + case FTP_WAIT220: + result = ftp_wait_resp(data, conn, ftpc, ftpcode); + break; - case FTP_AUTH: - /* we have gotten the response to a previous AUTH command */ + case FTP_AUTH: + /* we have gotten the response to a previous AUTH command */ - if(pp->overflow) - return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ + if(pp->overflow) + return CURLE_WEIRD_SERVER_REPLY; /* Forbid pipelining in response. */ - /* RFC2228 (page 5) says: - * - * If the server is willing to accept the named security mechanism, - * and does not require any security data, it must respond with - * reply code 234/334. - */ + /* RFC2228 (page 5) says: + * + * If the server is willing to accept the named security mechanism, + * and does not require any security data, it must respond with + * reply code 234/334. + */ - if((ftpcode == 234) || (ftpcode == 334)) { - /* this was BLOCKING, keep it so for now */ - bool done; - if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { - result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); - if(result) { - /* we failed and bail out */ - return CURLE_USE_SSL_FAILED; - } - } - result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, &done); - if(!result) { - conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ - conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ - result = ftp_state_user(data, ftpc, conn); + if((ftpcode == 234) || (ftpcode == 334)) { + /* this was BLOCKING, keep it so for now */ + bool done; + if(!Curl_conn_is_ssl(conn, FIRSTSOCKET)) { + result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET); + if(result) { + /* we failed and bail out */ + return CURLE_USE_SSL_FAILED; } } - else if(ftpc->count3 < 1) { - ftpc->count3++; - ftpc->count1 += ftpc->count2; /* get next attempt */ - result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", - ftpauth[ftpc->count1]); - /* remain in this same state */ - } - else { - if(data->set.use_ssl > CURLUSESSL_TRY) - /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ - result = CURLE_USE_SSL_FAILED; - else - /* ignore the failure and continue */ - result = ftp_state_user(data, ftpc, conn); - } - break; - - case FTP_USER: - case FTP_PASS: - result = ftp_state_user_resp(data, ftpc, ftpcode); - break; - - case FTP_ACCT: - result = ftp_state_acct_resp(data, ftpc, ftpcode); - break; - - case FTP_PBSZ: - result = - Curl_pp_sendf(data, &ftpc->pp, "PROT %c", - data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); - if(!result) - ftp_state(data, ftpc, FTP_PROT); - break; - - case FTP_PROT: - if(ftpcode/100 == 2) - /* We have enabled SSL for the data connection! */ - conn->bits.ftp_use_data_ssl = - (data->set.use_ssl != CURLUSESSL_CONTROL); - /* FTP servers typically responds with 500 if they decide to reject - our 'P' request */ - else if(data->set.use_ssl > CURLUSESSL_CONTROL) - /* we failed and bails out */ - return CURLE_USE_SSL_FAILED; - - if(data->set.ftp_ccc) { - /* CCC - Clear Command Channel - */ - result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); - if(!result) - ftp_state(data, ftpc, FTP_CCC); + result = Curl_conn_connect(data, FIRSTSOCKET, TRUE, &done); + if(!result) { + conn->bits.ftp_use_data_ssl = FALSE; /* clear-text data */ + conn->bits.ftp_use_control_ssl = TRUE; /* SSL on control */ + result = ftp_state_user(data, ftpc, conn); } + } + else if(ftpc->count3 < 1) { + ftpc->count3++; + ftpc->count1 += ftpc->count2; /* get next attempt */ + result = Curl_pp_sendf(data, &ftpc->pp, "AUTH %s", + ftpauth[ftpc->count1]); + /* remain in this same state */ + } + else { + if(data->set.use_ssl > CURLUSESSL_TRY) + /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */ + result = CURLE_USE_SSL_FAILED; else - result = ftp_state_pwd(data, ftpc); - break; - - case FTP_CCC: - if(ftpcode < 500) { - /* First shut down the SSL layer (note: this call will block) */ - /* This has only been tested on the proftpd server, and the mod_tls - * code sends a close notify alert without waiting for a close notify - * alert in response. Thus we wait for a close notify alert from the - * server, but we do not send one. Let's hope other servers do - * the same... */ - result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET, - (data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)); + /* ignore the failure and continue */ + result = ftp_state_user(data, ftpc, conn); + } + break; - if(result) - failf(data, "Failed to clear the command channel (CCC)"); - } - if(!result) - /* Then continue as normal */ - result = ftp_state_pwd(data, ftpc); - break; + case FTP_USER: + case FTP_PASS: + result = ftp_state_user_resp(data, ftpc, ftpcode); + break; - case FTP_PWD: - if(ftpcode == 257) { - char *ptr = curlx_dyn_ptr(&pp->recvbuf) + 4; /* start on the first - letter */ - bool entry_extracted = FALSE; - struct dynbuf out; - curlx_dyn_init(&out, 1000); + case FTP_ACCT: + result = ftp_state_acct_resp(data, ftpc, ftpcode); + break; - /* Reply format is like - 257[rubbish]"" and the - RFC959 says + case FTP_PBSZ: + result = + Curl_pp_sendf(data, &ftpc->pp, "PROT %c", + data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P'); + if(!result) + ftp_state(data, ftpc, FTP_PROT); + break; - The directory name can contain any character; embedded - double-quotes should be escaped by double-quotes (the - "quote-doubling" convention). - */ + case FTP_PROT: + if(ftpcode/100 == 2) + /* We have enabled SSL for the data connection! */ + conn->bits.ftp_use_data_ssl = + (data->set.use_ssl != CURLUSESSL_CONTROL); + /* FTP servers typically responds with 500 if they decide to reject + our 'P' request */ + else if(data->set.use_ssl > CURLUSESSL_CONTROL) + /* we failed and bails out */ + return CURLE_USE_SSL_FAILED; + + if(data->set.ftp_ccc) { + /* CCC - Clear Command Channel + */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "CCC"); + if(!result) + ftp_state(data, ftpc, FTP_CCC); + } + else + result = ftp_state_pwd(data, ftpc); + break; - /* scan for the first double-quote for non-standard responses */ - while(*ptr != '\n' && *ptr != '\0' && *ptr != '"') - ptr++; + case FTP_CCC: + if(ftpcode < 500) { + /* First shut down the SSL layer (note: this call will block) */ + /* This has only been tested on the proftpd server, and the mod_tls + * code sends a close notify alert without waiting for a close notify + * alert in response. Thus we wait for a close notify alert from the + * server, but we do not send one. Let's hope other servers do + * the same... */ + result = Curl_ssl_cfilter_remove(data, FIRSTSOCKET, + (data->set.ftp_ccc == + (unsigned char)CURLFTPSSL_CCC_ACTIVE)); + if(result) + failf(data, "Failed to clear the command channel (CCC)"); + } + if(!result) + /* Then continue as normal */ + result = ftp_state_pwd(data, ftpc); + break; - if('\"' == *ptr) { - /* it started good */ - for(ptr++; *ptr; ptr++) { - if('\"' == *ptr) { - if('\"' == ptr[1]) { - /* "quote-doubling" */ - result = curlx_dyn_addn(&out, &ptr[1], 1); - ptr++; - } - else { - /* end of path */ - if(curlx_dyn_len(&out)) - entry_extracted = TRUE; - break; /* get out of this loop */ - } - } - else - result = curlx_dyn_addn(&out, ptr, 1); - if(result) - return result; - } - } - if(entry_extracted) { - /* If the path name does not look like an absolute path (i.e.: it - does not start with a '/'), we probably need some server-dependent - adjustments. For example, this is the case when connecting to - an OS400 FTP server: this server supports two name syntaxes, - the default one being incompatible with standard paths. In - addition, this server switches automatically to the regular path - syntax when one is encountered in a command: this results in - having an entrypath in the wrong syntax when later used in CWD. - The method used here is to check the server OS: we do it only - if the path name looks strange to minimize overhead on other - systems. */ - char *dir = curlx_dyn_ptr(&out); - - if(!ftpc->server_os && dir[0] != '/') { - result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SYST"); - if(result) { - free(dir); - return result; - } - free(ftpc->entrypath); - ftpc->entrypath = dir; /* remember this */ - infof(data, "Entry path is '%s'", ftpc->entrypath); - /* also save it where getinfo can access it: */ - free(data->state.most_recent_ftp_entrypath); - data->state.most_recent_ftp_entrypath = strdup(ftpc->entrypath); - if(!data->state.most_recent_ftp_entrypath) - return CURLE_OUT_OF_MEMORY; - ftp_state(data, ftpc, FTP_SYST); - break; - } + case FTP_PWD: + result = ftp_pwd_resp(data, ftpc, ftpcode); + break; - free(ftpc->entrypath); - ftpc->entrypath = dir; /* remember this */ - infof(data, "Entry path is '%s'", ftpc->entrypath); - /* also save it where getinfo can access it: */ - free(data->state.most_recent_ftp_entrypath); - data->state.most_recent_ftp_entrypath = strdup(ftpc->entrypath); - if(!data->state.most_recent_ftp_entrypath) - return CURLE_OUT_OF_MEMORY; - } - else { - /* could not get the path */ - curlx_dyn_free(&out); - infof(data, "Failed to figure out path"); - } - } - ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ - CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); - break; + case FTP_SYST: + if(ftpcode == 215) { + char *ptr = curlx_dyn_ptr(&pp->recvbuf) + 4; /* start on the first + letter */ + char *os; + char *start; - case FTP_SYST: - if(ftpcode == 215) { - char *ptr = curlx_dyn_ptr(&pp->recvbuf) + 4; /* start on the first - letter */ - char *os; - char *start; - - /* Reply format is like - 215 - */ - while(*ptr == ' ') - ptr++; - for(start = ptr; *ptr && *ptr != ' '; ptr++) - ; - os = Curl_memdup0(start, ptr - start); - if(!os) - return CURLE_OUT_OF_MEMORY; + /* Reply format is like + 215 + */ + while(*ptr == ' ') + ptr++; + for(start = ptr; *ptr && *ptr != ' '; ptr++) + ; + os = Curl_memdup0(start, ptr - start); + if(!os) + return CURLE_OUT_OF_MEMORY; - /* Check for special servers here. */ - if(curl_strequal(os, "OS/400")) { - /* Force OS400 name format 1. */ - result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); - if(result) { - free(os); - return result; - } - /* remember target server OS */ - free(ftpc->server_os); - ftpc->server_os = os; - ftp_state(data, ftpc, FTP_NAMEFMT); - break; + /* Check for special servers here. */ + if(curl_strequal(os, "OS/400")) { + /* Force OS400 name format 1. */ + result = Curl_pp_sendf(data, &ftpc->pp, "%s", "SITE NAMEFMT 1"); + if(result) { + free(os); + return result; } - /* Nothing special for the target server. */ /* remember target server OS */ free(ftpc->server_os); ftpc->server_os = os; - } - else { - /* Cannot identify server OS. Continue anyway and cross fingers. */ - } - - ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ - CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); - break; - - case FTP_NAMEFMT: - if(ftpcode == 250) { - /* Name format change successful: reload initial path. */ - ftp_state_pwd(data, ftpc); + ftp_state(data, ftpc, FTP_NAMEFMT); break; } + /* Nothing special for the target server. */ + /* remember target server OS */ + free(ftpc->server_os); + ftpc->server_os = os; + } + else { + /* Cannot identify server OS. Continue anyway and cross fingers. */ + } - ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ - CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); - break; + ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ + CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); + break; - case FTP_QUOTE: - case FTP_POSTQUOTE: - case FTP_RETR_PREQUOTE: - case FTP_STOR_PREQUOTE: - case FTP_LIST_PREQUOTE: - if((ftpcode >= 400) && !ftpc->count2) { - /* failure response code, and not allowed to fail */ - failf(data, "QUOT command failed with %03d", ftpcode); - result = CURLE_QUOTE_ERROR; - } - else - result = ftp_state_quote(data, ftpc, ftp, FALSE, ftpc->state); + case FTP_NAMEFMT: + if(ftpcode == 250) { + /* Name format change successful: reload initial path. */ + ftp_state_pwd(data, ftpc); break; + } - case FTP_CWD: - if(ftpcode/100 != 2) { - /* failure to CWD there */ - if(data->set.ftp_create_missing_dirs && - ftpc->cwdcount && !ftpc->count2) { - /* try making it */ - ftpc->count2++; /* counter to prevent CWD-MKD loops */ - - /* count3 is set to allow MKD to fail once per dir. In the case when - CWD fails and then MKD fails (due to another session raced it to - create the dir) this then allows for a second try to CWD to it. */ - ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0; - - result = Curl_pp_sendf(data, &ftpc->pp, "MKD %s", - ftpc->dirs[ftpc->cwdcount - 1]); - if(!result) - ftp_state(data, ftpc, FTP_MKD); - } - else { - /* return failure */ - failf(data, "Server denied you to change to the given directory"); - ftpc->cwdfail = TRUE; /* do not remember this path as we failed - to enter it */ - result = CURLE_REMOTE_ACCESS_DENIED; - } + ftp_state(data, ftpc, FTP_STOP); /* we are done with CONNECT phase! */ + CURL_TRC_FTP(data, "[%s] protocol connect phase DONE", FTP_CSTATE(ftpc)); + break; + + case FTP_QUOTE: + case FTP_POSTQUOTE: + case FTP_RETR_PREQUOTE: + case FTP_STOR_PREQUOTE: + case FTP_LIST_PREQUOTE: + if((ftpcode >= 400) && !ftpc->count2) { + /* failure response code, and not allowed to fail */ + failf(data, "QUOT command failed with %03d", ftpcode); + result = CURLE_QUOTE_ERROR; + } + else + result = ftp_state_quote(data, ftpc, ftp, FALSE, ftpc->state); + break; + + case FTP_CWD: + if(ftpcode/100 != 2) { + /* failure to CWD there */ + if(data->set.ftp_create_missing_dirs && + ftpc->cwdcount && !ftpc->count2) { + /* try making it */ + ftpc->count2++; /* counter to prevent CWD-MKD loops */ + + /* count3 is set to allow MKD to fail once per dir. In the case when + CWD fails and then MKD fails (due to another session raced it to + create the dir) this then allows for a second try to CWD to it. */ + ftpc->count3 = (data->set.ftp_create_missing_dirs == 2) ? 1 : 0; + + result = Curl_pp_sendf(data, &ftpc->pp, "MKD %.*s", + pathlen(ftpc, ftpc->cwdcount - 1), + pathpiece(ftpc, ftpc->cwdcount - 1)); + if(!result) + ftp_state(data, ftpc, FTP_MKD); } else { - /* success */ - ftpc->count2 = 0; - if(++ftpc->cwdcount <= ftpc->dirdepth) - /* send next CWD */ - result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", - ftpc->dirs[ftpc->cwdcount - 1]); - else - result = ftp_state_mdtm(data, ftpc, ftp); - } - break; - - case FTP_MKD: - if((ftpcode/100 != 2) && !ftpc->count3--) { - /* failure to MKD the dir */ - failf(data, "Failed to MKD dir: %03d", ftpcode); + /* return failure */ + failf(data, "Server denied you to change to the given directory"); + ftpc->cwdfail = TRUE; /* do not remember this path as we failed + to enter it */ result = CURLE_REMOTE_ACCESS_DENIED; } + } + else { + /* success */ + ftpc->count2 = 0; + if(ftpc->cwdcount >= ftpc->dirdepth) + result = ftp_state_mdtm(data, ftpc, ftp); else { - ftp_state(data, ftpc, FTP_CWD); - /* send CWD */ - result = Curl_pp_sendf(data, &ftpc->pp, "CWD %s", - ftpc->dirs[ftpc->cwdcount - 1]); + ftpc->cwdcount++; + /* send next CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %.*s", + pathlen(ftpc, ftpc->cwdcount - 1), + pathpiece(ftpc, ftpc->cwdcount - 1)); } - break; + } + break; - case FTP_MDTM: - result = ftp_state_mdtm_resp(data, ftpc, ftp, ftpcode); - break; + case FTP_MKD: + if((ftpcode/100 != 2) && !ftpc->count3--) { + /* failure to MKD the dir */ + failf(data, "Failed to MKD dir: %03d", ftpcode); + result = CURLE_REMOTE_ACCESS_DENIED; + } + else { + ftp_state(data, ftpc, FTP_CWD); + /* send CWD */ + result = Curl_pp_sendf(data, &ftpc->pp, "CWD %.*s", + pathlen(ftpc, ftpc->cwdcount - 1), + pathpiece(ftpc, ftpc->cwdcount - 1)); + } + break; - case FTP_TYPE: - case FTP_LIST_TYPE: - case FTP_RETR_TYPE: - case FTP_STOR_TYPE: - case FTP_RETR_LIST_TYPE: - result = ftp_state_type_resp(data, ftpc, ftp, ftpcode, ftpc->state); - break; + case FTP_MDTM: + result = ftp_state_mdtm_resp(data, ftpc, ftp, ftpcode); + break; - case FTP_SIZE: - case FTP_RETR_SIZE: - case FTP_STOR_SIZE: - result = ftp_state_size_resp(data, ftpc, ftp, ftpcode, ftpc->state); - break; + case FTP_TYPE: + case FTP_LIST_TYPE: + case FTP_RETR_TYPE: + case FTP_STOR_TYPE: + case FTP_RETR_LIST_TYPE: + result = ftp_state_type_resp(data, ftpc, ftp, ftpcode, ftpc->state); + break; - case FTP_REST: - case FTP_RETR_REST: - result = ftp_state_rest_resp(data, ftpc, ftp, ftpcode, ftpc->state); - break; + case FTP_SIZE: + case FTP_RETR_SIZE: + case FTP_STOR_SIZE: + result = ftp_state_size_resp(data, ftpc, ftp, ftpcode, ftpc->state); + break; - case FTP_PRET: - if(ftpcode != 200) { - /* there only is this one standard OK return code. */ - failf(data, "PRET command not accepted: %03d", ftpcode); - return CURLE_FTP_PRET_FAILED; - } - result = ftp_state_use_pasv(data, ftpc, conn); - break; + case FTP_REST: + case FTP_RETR_REST: + result = ftp_state_rest_resp(data, ftpc, ftp, ftpcode, ftpc->state); + break; - case FTP_PASV: - result = ftp_state_pasv_resp(data, ftpc, ftpcode); - break; + case FTP_PRET: + if(ftpcode != 200) { + /* there only is this one standard OK return code. */ + failf(data, "PRET command not accepted: %03d", ftpcode); + return CURLE_FTP_PRET_FAILED; + } + result = ftp_state_use_pasv(data, ftpc, conn); + break; - case FTP_PORT: - result = ftp_state_port_resp(data, ftpc, ftp, ftpcode); - break; + case FTP_PASV: + result = ftp_state_pasv_resp(data, ftpc, ftpcode); + break; - case FTP_LIST: - case FTP_RETR: - result = ftp_state_get_resp(data, ftpc, ftp, ftpcode, ftpc->state); - break; + case FTP_PORT: + result = ftp_state_port_resp(data, ftpc, ftp, ftpcode); + break; - case FTP_STOR: - result = ftp_state_stor_resp(data, ftpc, ftpcode, ftpc->state); - break; + case FTP_LIST: + case FTP_RETR: + result = ftp_state_get_resp(data, ftpc, ftp, ftpcode, ftpc->state); + break; - case FTP_QUIT: - default: - /* internal error */ - ftp_state(data, ftpc, FTP_STOP); - break; - } - } /* if(ftpcode) */ + case FTP_STOR: + result = ftp_state_stor_resp(data, ftpc, ftpcode, ftpc->state); + break; + + case FTP_QUIT: + default: + /* internal error */ + ftp_state(data, ftpc, FTP_STOP); + break; + } return result; } @@ -3257,8 +3286,6 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, ssize_t nread; int ftpcode; CURLcode result = CURLE_OK; - char *rawPath = NULL; - size_t pathLen = 0; if(!ftp || !ftpc) return CURLE_OK; @@ -3301,14 +3328,11 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, Curl_set_in_callback(data, TRUE); data->set.chunk_end(data->set.wildcardptr); Curl_set_in_callback(data, FALSE); + freedirs(ftpc); } ftpc->known_filesize = -1; } - if(!result) - /* get the url-decoded "raw" path */ - result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, - REJECT_CTRL); if(result) { /* We can limp along anyway (and should try to since we may already be in * the error path) */ @@ -3318,34 +3342,31 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, ftpc->prevpath = NULL; /* no path remembering */ } else { /* remember working directory for connection reuse */ - if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) - free(rawPath); /* full path => no CWDs happened => keep ftpc->prevpath */ - else { - free(ftpc->prevpath); + const char *rawPath = ftpc->rawpath; + if(rawPath) { + if((data->set.ftp_filemethod == FTPFILE_NOCWD) && (rawPath[0] == '/')) + ; /* full path => no CWDs happened => keep ftpc->prevpath */ + else { + size_t pathLen = strlen(ftpc->rawpath); - if(!ftpc->cwdfail) { - if(data->set.ftp_filemethod == FTPFILE_NOCWD) - pathLen = 0; /* relative path => working directory is FTP home */ - else - /* file is url-decoded */ - pathLen -= ftpc->file ? strlen(ftpc->file) : 0; + free(ftpc->prevpath); - rawPath[pathLen] = '\0'; - ftpc->prevpath = rawPath; - } - else { - free(rawPath); - ftpc->prevpath = NULL; /* no path */ + if(!ftpc->cwdfail) { + if(data->set.ftp_filemethod == FTPFILE_NOCWD) + pathLen = 0; /* relative path => working directory is FTP home */ + else + /* file is url-decoded */ + pathLen -= ftpc->file ? strlen(ftpc->file) : 0; + ftpc->prevpath = Curl_memdup0(rawPath, pathLen); + } + else + ftpc->prevpath = NULL; /* no path */ } } - if(ftpc->prevpath) infof(data, "Remembering we are in dir \"%s\"", ftpc->prevpath); } - /* free the dir tree and file parts */ - freedirs(ftpc); - /* shut down the socket to inform the server we are done */ #ifdef UNDER_CE @@ -3438,7 +3459,7 @@ static CURLcode ftp_done(struct Curl_easy *data, CURLcode status, } } else { - if((-1 != data->req.size) && + if((data->req.size != -1) && (data->req.size != data->req.bytecount) && (data->req.maxdownload != data->req.bytecount)) { failf(data, "Received only partial file: %" FMT_OFF_T " bytes", @@ -3753,7 +3774,6 @@ static CURLcode ftp_do_more(struct Curl_easy *data, int *completep) } - /*********************************************************************** * * ftp_perform() @@ -4163,6 +4183,20 @@ static CURLcode ftp_disconnect(struct Curl_easy *data, return CURLE_OK; } +static size_t numof_slashes(const char *str) +{ + const char *slashPos; + size_t num = 0; + do { + slashPos = strchr(str, '/'); + if(slashPos) { + ++num; + str = slashPos + 1; + } + } while(slashPos); + return num; +} + /*********************************************************************** * * ftp_parse_url_path() @@ -4178,18 +4212,21 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data, const char *slashPos = NULL; const char *fileName = NULL; CURLcode result = CURLE_OK; - char *rawPath = NULL; /* url-decoded "raw" path */ + const char *rawPath = NULL; /* url-decoded "raw" path */ size_t pathLen = 0; ftpc->ctl_valid = FALSE; ftpc->cwdfail = FALSE; + if(ftpc->rawpath) + freedirs(ftpc); /* url-decode ftp path before further evaluation */ - result = Curl_urldecode(ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL); + result = Curl_urldecode(ftp->path, 0, &ftpc->rawpath, &pathLen, REJECT_CTRL); if(result) { failf(data, "path contains control characters"); return result; } + rawPath = ftpc->rawpath; switch(data->set.ftp_filemethod) { case FTPFILE_NOCWD: /* fastest, but less standard-compliant */ @@ -4213,17 +4250,11 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data, dirlen = 1; ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); - if(!ftpc->dirs) { - free(rawPath); - return CURLE_OUT_OF_MEMORY; - } - - ftpc->dirs[0] = Curl_memdup0(rawPath, dirlen); - if(!ftpc->dirs[0]) { - free(rawPath); + if(!ftpc->dirs) return CURLE_OUT_OF_MEMORY; - } + ftpc->dirs[0].start = 0; + ftpc->dirs[0].len = (int)dirlen; ftpc->dirdepth = 1; /* we consider it to be a single dir */ fileName = slashPos + 1; /* rest is filename */ } @@ -4236,51 +4267,45 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data, /* current position: begin of next path component */ const char *curPos = rawPath; - /* number of entries allocated for the 'dirs' array */ - size_t dirAlloc = 0; - const char *str = rawPath; - for(; *str != 0; ++str) - if(*str == '/') - ++dirAlloc; + /* number of entries to allocate for the 'dirs' array */ + size_t dirAlloc = numof_slashes(rawPath); + + if(dirAlloc >= 1000) + /* suspiciously deep dir hierarchy */ + return CURLE_URL_MALFORMAT; if(dirAlloc) { ftpc->dirs = calloc(dirAlloc, sizeof(ftpc->dirs[0])); - if(!ftpc->dirs) { - free(rawPath); + if(!ftpc->dirs) return CURLE_OUT_OF_MEMORY; - } /* parse the URL path into separate path components */ - /* !checksrc! disable EQUALSNULL 1 */ - while((slashPos = strchr(curPos, '/')) != NULL) { - size_t compLen = slashPos - curPos; + while(dirAlloc--) { + const char *spos = strchr(curPos, '/'); + size_t clen = spos - curPos; /* path starts with a slash: add that as a directory */ - if((compLen == 0) && (ftpc->dirdepth == 0)) - ++compLen; + if(!clen && (ftpc->dirdepth == 0)) + ++clen; /* we skip empty path components, like "x//y" since the FTP command CWD requires a parameter and a non-existent parameter a) does not work on many servers and b) has no effect on the others. */ - if(compLen > 0) { - char *comp = Curl_memdup0(curPos, compLen); - if(!comp) { - free(rawPath); - return CURLE_OUT_OF_MEMORY; - } - ftpc->dirs[ftpc->dirdepth++] = comp; + if(clen) { + ftpc->dirs[ftpc->dirdepth].start = (int)(curPos - rawPath); + ftpc->dirs[ftpc->dirdepth].len = (int)clen; + ftpc->dirdepth++; } - curPos = slashPos + 1; + curPos = spos + 1; } } - DEBUGASSERT((size_t)ftpc->dirdepth <= dirAlloc); fileName = curPos; /* the rest is the filename (or empty) */ } break; } /* switch */ if(fileName && *fileName) - ftpc->file = strdup(fileName); + ftpc->file = fileName; else ftpc->file = NULL; /* instead of point to a zero byte, we make it a NULL pointer */ @@ -4288,7 +4313,6 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data, if(data->state.upload && !ftpc->file && (ftp->transfer == PPTRANSFER_BODY)) { /* We need a filename when uploading. Return error! */ failf(data, "Uploading to a URL without a filename"); - free(rawPath); return CURLE_URL_MALFORMAT; } @@ -4312,7 +4336,6 @@ CURLcode ftp_parse_url_path(struct Curl_easy *data, } } - free(rawPath); return CURLE_OK; } diff --git a/deps/curl/lib/ftp.h b/deps/curl/lib/ftp.h index 52661981ef3..aba1db7f2d3 100644 --- a/deps/curl/lib/ftp.h +++ b/deps/curl/lib/ftp.h @@ -120,6 +120,11 @@ struct FTP { curl_off_t downloadsize; }; +/* one struct entry for each path component (of 'rawpath') */ +struct pathcomp { + int start; /* start column */ + int len; /* length in bytes */ +}; /* ftp_conn is used for struct connection-oriented data in the connectdata struct */ @@ -128,8 +133,9 @@ struct ftp_conn { char *account; char *alternative_to_user; char *entrypath; /* the PWD reply when we logged on */ - char *file; /* url-decoded filename (or path) */ - char **dirs; /* realloc()ed array for path components */ + const char *file; /* url-decoded filename (or path), points into rawpath */ + char *rawpath; /* URL decoded, allocated, version of the path */ + struct pathcomp *dirs; /* allocated array for path components */ char *newhost; /* the (allocated) IP addr or hostname to connect the data connection to */ char *prevpath; /* url-decoded conn->path from the previous transfer */ diff --git a/deps/curl/lib/gopher.c b/deps/curl/lib/gopher.c index 68ccb59e408..93db85e9d02 100644 --- a/deps/curl/lib/gopher.c +++ b/deps/curl/lib/gopher.c @@ -70,10 +70,10 @@ const struct Curl_handler Curl_handler_gopher = { ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -96,10 +96,10 @@ const struct Curl_handler Curl_handler_gophers = { 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, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -240,7 +240,7 @@ static CURLcode gopher_do(struct Curl_easy *data, bool *done) if(result) return result; - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); return CURLE_OK; } #endif /* CURL_DISABLE_GOPHER */ diff --git a/deps/curl/lib/hmac.c b/deps/curl/lib/hmac.c index 3af1f292dac..5e7dd0df0c2 100644 --- a/deps/curl/lib/hmac.c +++ b/deps/curl/lib/hmac.c @@ -73,7 +73,8 @@ Curl_HMAC_init(const struct HMAC_params *hashparams, /* If the key is too long, replace it by its hash digest. */ if(keylen > hashparams->maxkeylen) { - hashparams->hinit(ctxt->hashctxt1); + if(hashparams->hinit(ctxt->hashctxt1)) + return NULL; hashparams->hupdate(ctxt->hashctxt1, key, keylen); hkey = (unsigned char *) ctxt->hashctxt2 + hashparams->ctxtsize; hashparams->hfinal(hkey, ctxt->hashctxt1); @@ -82,8 +83,9 @@ Curl_HMAC_init(const struct HMAC_params *hashparams, } /* Prime the two hash contexts with the modified key. */ - hashparams->hinit(ctxt->hashctxt1); - hashparams->hinit(ctxt->hashctxt2); + if(hashparams->hinit(ctxt->hashctxt1) || + hashparams->hinit(ctxt->hashctxt2)) + return NULL; for(i = 0; i < keylen; i++) { b = (unsigned char)(*key ^ hmac_ipad); diff --git a/deps/curl/lib/hostip.c b/deps/curl/lib/hostip.c index 191aaeb8de9..2d122fb9996 100644 --- a/deps/curl/lib/hostip.c +++ b/deps/curl/lib/hostip.c @@ -180,9 +180,9 @@ create_dnscache_id(const char *name, } struct dnscache_prune_data { - time_t now; - time_t oldest; /* oldest time in cache not pruned. */ - int max_age_sec; + struct curltime now; + timediff_t oldest_ms; /* oldest time in cache not pruned. */ + timediff_t max_age_ms; }; /* @@ -199,36 +199,38 @@ dnscache_entry_is_stale(void *datap, void *hc) (struct dnscache_prune_data *) datap; struct Curl_dns_entry *dns = (struct Curl_dns_entry *) hc; - if(dns->timestamp) { - /* age in seconds */ - time_t age = prune->now - dns->timestamp; - if(age >= (time_t)prune->max_age_sec) + if(dns->timestamp.tv_sec || dns->timestamp.tv_usec) { + /* get age in milliseconds */ + timediff_t age = curlx_timediff(prune->now, dns->timestamp); + if(!dns->addr) + age *= 2; /* negative entries age twice as fast */ + if(age >= prune->max_age_ms) return TRUE; - if(age > prune->oldest) - prune->oldest = age; + if(age > prune->oldest_ms) + prune->oldest_ms = age; } return FALSE; } /* * Prune the DNS cache. This assumes that a lock has already been taken. - * Returns the 'age' of the oldest still kept entry. + * Returns the 'age' of the oldest still kept entry - in milliseconds. */ -static time_t -dnscache_prune(struct Curl_hash *hostcache, int cache_timeout, - time_t now) +static timediff_t +dnscache_prune(struct Curl_hash *hostcache, timediff_t cache_timeout_ms, + struct curltime now) { struct dnscache_prune_data user; - user.max_age_sec = cache_timeout; + user.max_age_ms = cache_timeout_ms; user.now = now; - user.oldest = 0; + user.oldest_ms = 0; Curl_hash_clean_with_criterium(hostcache, (void *) &user, dnscache_entry_is_stale); - return user.oldest; + return user.oldest_ms; } static struct Curl_dnscache *dnscache_get(struct Curl_easy *data) @@ -261,35 +263,49 @@ static void dnscache_unlock(struct Curl_easy *data, void Curl_dnscache_prune(struct Curl_easy *data) { struct Curl_dnscache *dnscache = dnscache_get(data); - time_t now; + struct curltime now; /* the timeout may be set -1 (forever) */ - int timeout = data->set.dns_cache_timeout; + timediff_t timeout_ms = data->set.dns_cache_timeout_ms; - if(!dnscache) + if(!dnscache || (timeout_ms == -1)) /* NULL hostcache means we cannot do it */ return; dnscache_lock(data, dnscache); - now = time(NULL); + now = curlx_now(); do { /* Remove outdated and unused entries from the hostcache */ - time_t oldest = dnscache_prune(&dnscache->entries, timeout, now); + timediff_t oldest_ms = dnscache_prune(&dnscache->entries, timeout_ms, now); - if(oldest < INT_MAX) - timeout = (int)oldest; /* we know it fits */ + if(Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE) { + if(oldest_ms < INT_MAX) + /* prune the ones over half this age */ + timeout_ms = (int)oldest_ms / 2; + else + timeout_ms = INT_MAX/2; + } else - timeout = INT_MAX - 1; + break; - /* if the cache size is still too big, use the oldest age as new - prune limit */ - } while(timeout && - (Curl_hash_count(&dnscache->entries) > MAX_DNS_CACHE_SIZE)); + /* if the cache size is still too big, use the oldest age as new prune + limit */ + } while(timeout_ms); dnscache_unlock(data, dnscache); } +void Curl_dnscache_clear(struct Curl_easy *data) +{ + struct Curl_dnscache *dnscache = dnscache_get(data); + if(dnscache) { + dnscache_lock(data, dnscache); + Curl_hash_clean(&dnscache->entries); + dnscache_unlock(data, dnscache); + } +} + #ifdef USE_ALARM_TIMEOUT /* Beware this is a global and unique instance. This is used to store the return address that we can jump back to from inside a signal handler. This @@ -327,13 +343,13 @@ static struct Curl_dns_entry *fetch_addr(struct Curl_easy *data, dns = Curl_hash_pick(&dnscache->entries, entry_id, entry_len + 1); } - if(dns && (data->set.dns_cache_timeout != -1)) { + if(dns && (data->set.dns_cache_timeout_ms != -1)) { /* See whether the returned entry is stale. Done before we release lock */ struct dnscache_prune_data user; - user.now = time(NULL); - user.max_age_sec = data->set.dns_cache_timeout; - user.oldest = 0; + user.now = curlx_now(); + user.max_age_ms = data->set.dns_cache_timeout_ms; + user.oldest_ms = 0; if(dnscache_entry_is_stale(&user, dns)) { infof(data, "Hostname in DNS cache was stale, zapped"); @@ -520,12 +536,12 @@ Curl_dnscache_mk_entry(struct Curl_easy *data, dns->refcount = 1; /* the cache has the first reference */ dns->addr = addr; /* this is the address(es) */ - if(permanent) - dns->timestamp = 0; /* an entry that never goes stale */ + if(permanent) { + dns->timestamp.tv_sec = 0; /* an entry that never goes stale */ + dns->timestamp.tv_usec = 0; /* an entry that never goes stale */ + } else { - dns->timestamp = time(NULL); - if(dns->timestamp == 0) - dns->timestamp = 1; + dns->timestamp = curlx_now(); } dns->hostport = port; if(hostlen) @@ -784,6 +800,28 @@ static bool can_resolve_ip_version(struct Curl_easy *data, int ip_version) return TRUE; } +static CURLcode store_negative_resolve(struct Curl_easy *data, + const char *host, + int port) +{ + struct Curl_dnscache *dnscache = dnscache_get(data); + struct Curl_dns_entry *dns; + DEBUGASSERT(dnscache); + if(!dnscache) + return CURLE_FAILED_INIT; + + /* put this new host in the cache */ + dns = dnscache_add_addr(data, dnscache, NULL, host, 0, port, FALSE); + if(dns) { + /* release the returned reference; the cache itself will keep the + * entry alive: */ + dns->refcount--; + infof(data, "Store negative name resolve for %s:%d", host, port); + return CURLE_OK; + } + return CURLE_OUT_OF_MEMORY; +} + /* * Curl_resolv() is the main name resolve function within libcurl. It resolves * a name and returns a pointer to the entry in the 'entry' argument (if one @@ -903,6 +941,11 @@ CURLcode Curl_resolv(struct Curl_easy *data, * or `respwait` is set for an async operation. * Everything else is a failure to resolve. */ if(dns) { + if(!dns->addr) { + infof(data, "Negative DNS entry"); + dns->refcount--; + return CURLE_COULDNT_RESOLVE_HOST; + } *entry = dns; return CURLE_OK; } @@ -928,6 +971,7 @@ CURLcode Curl_resolv(struct Curl_easy *data, Curl_resolv_unlink(data, &dns); *entry = NULL; Curl_async_shutdown(data); + store_negative_resolve(data, hostname, port); return CURLE_COULDNT_RESOLVE_HOST; } @@ -1088,14 +1132,18 @@ CURLcode Curl_resolv_timeout(struct Curl_easy *data, prev_alarm = alarm(curlx_sltoui(timeout/1000L)); } -#else /* USE_ALARM_TIMEOUT */ +#ifdef DEBUGBUILD + Curl_resolve_test_delay(); +#endif + +#else /* !USE_ALARM_TIMEOUT */ #ifndef CURLRES_ASYNCH if(timeoutms) infof(data, "timeout on name lookup is not supported"); #else - (void)timeoutms; /* timeoutms not used with an async resolver */ + (void)timeoutms; #endif -#endif /* else USE_ALARM_TIMEOUT */ +#endif /* USE_ALARM_TIMEOUT */ /* Perform the actual name resolution. This might be interrupted by an * alarm if it takes too long. @@ -1258,7 +1306,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) struct Curl_addrinfo *head = NULL, *tail = NULL; size_t entry_len; char address[64]; -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS const char *addresses = NULL; #endif curl_off_t port = 0; @@ -1283,7 +1331,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data) curlx_str_single(&host, ':')) goto err; -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS addresses = host; #endif @@ -1503,31 +1551,36 @@ CURLcode Curl_resolv_check(struct Curl_easy *data, #ifndef CURL_DISABLE_DOH if(data->conn->bits.doh) { result = Curl_doh_is_resolved(data, dns); + if(result) + Curl_resolver_error(data, NULL); } else #endif result = Curl_async_is_resolved(data, dns); if(*dns) show_resolve_info(data, *dns); + if(result) + store_negative_resolve(data, data->state.async.hostname, + data->state.async.port); return result; } #endif -int Curl_resolv_getsock(struct Curl_easy *data, - curl_socket_t *socks) +CURLcode Curl_resolv_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { #ifdef CURLRES_ASYNCH #ifndef CURL_DISABLE_DOH if(data->conn->bits.doh) /* nothing to wait for during DoH resolve, those handles have their own sockets */ - return GETSOCK_BLANK; + return CURLE_OK; #endif - return Curl_async_getsock(data, socks); + return Curl_async_pollset(data, ps); #else (void)data; - (void)socks; - return GETSOCK_BLANK; + (void)ps; + return CURLE_OK; #endif } @@ -1565,7 +1618,7 @@ CURLcode Curl_once_resolved(struct Curl_easy *data, */ #ifdef USE_CURL_ASYNC -CURLcode Curl_resolver_error(struct Curl_easy *data) +CURLcode Curl_resolver_error(struct Curl_easy *data, const char *detail) { struct connectdata *conn = data->conn; const char *host_or_proxy = "host"; @@ -1581,7 +1634,23 @@ CURLcode Curl_resolver_error(struct Curl_easy *data) } #endif - failf(data, "Could not resolve %s: %s", host_or_proxy, name); + failf(data, "Could not resolve %s: %s%s%s%s", host_or_proxy, name, + detail ? " (" : "", detail ? detail : "", detail ? ")" : ""); return result; } #endif /* USE_CURL_ASYNC */ + +#ifdef DEBUGBUILD +#include "curlx/wait.h" + +void Curl_resolve_test_delay(void) +{ + const char *p = getenv("CURL_DNS_DELAY_MS"); + if(p) { + curl_off_t l; + if(!curlx_str_number(&p, &l, TIME_T_MAX) && l) { + curlx_wait_ms((timediff_t)l); + } + } +} +#endif diff --git a/deps/curl/lib/hostip.h b/deps/curl/lib/hostip.h index cd3d957e1e7..2f78be82c2e 100644 --- a/deps/curl/lib/hostip.h +++ b/deps/curl/lib/hostip.h @@ -47,12 +47,11 @@ #define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this many seconds for a name resolve */ -#define CURL_ASYNC_SUCCESS CURLE_OK - struct addrinfo; struct hostent; struct Curl_easy; struct connectdata; +struct easy_pollset; enum alpnid { ALPN_none = 0, @@ -67,7 +66,7 @@ struct Curl_dns_entry { struct Curl_https_rrinfo *hinfo; #endif /* timestamp == 0 -- permanent CURLOPT_RESOLVE entry (does not time out) */ - time_t timestamp; + struct curltime timestamp; /* reference counter, entry is freed on reaching 0 */ size_t refcount; /* hostname port number that resolved to addr. */ @@ -130,6 +129,9 @@ void Curl_dnscache_destroy(struct Curl_dnscache *dns); /* prune old entries from the DNS cache */ void Curl_dnscache_prune(struct Curl_easy *data); +/* clear the DNS cache */ +void Curl_dnscache_clear(struct Curl_easy *data); + /* IPv4 threadsafe resolve function used for synch and asynch builds */ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port); @@ -196,10 +198,10 @@ CURLcode Curl_resolv_check(struct Curl_easy *data, #else #define Curl_resolv_check(x,y) CURLE_NOT_BUILT_IN #endif -int Curl_resolv_getsock(struct Curl_easy *data, - curl_socket_t *socks); +CURLcode Curl_resolv_pollset(struct Curl_easy *data, + struct easy_pollset *ps); -CURLcode Curl_resolver_error(struct Curl_easy *data); +CURLcode Curl_resolver_error(struct Curl_easy *data, const char *detail); #ifdef CURLRES_SYNCH /* @@ -214,4 +216,8 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data, #endif +#ifdef DEBUGBUILD +void Curl_resolve_test_delay(void); +#endif + #endif /* HEADER_CURL_HOSTIP_H */ diff --git a/deps/curl/lib/hostip4.c b/deps/curl/lib/hostip4.c index 14e4d98a866..2c356f3464e 100644 --- a/deps/curl/lib/hostip4.c +++ b/deps/curl/lib/hostip4.c @@ -94,8 +94,7 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data, #endif /* CURLRES_SYNCH */ #endif /* CURLRES_IPV4 */ -#if defined(CURLRES_IPV4) && \ - !defined(CURLRES_ARES) && !defined(CURLRES_AMIGA) +#if defined(CURLRES_IPV4) && !defined(CURLRES_ARES) && !defined(CURLRES_AMIGA) /* * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function. @@ -108,7 +107,7 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port) { #if !(defined(HAVE_GETADDRINFO) && defined(HAVE_GETADDRINFO_THREADSAFE)) && \ - defined(HAVE_GETHOSTBYNAME_R_3) + defined(HAVE_GETHOSTBYNAME_R_3) int res; #endif struct Curl_addrinfo *ai = NULL; @@ -145,11 +144,11 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, return NULL; /* major failure */ /* * The clearing of the buffer is a workaround for a gethostbyname_r bug in - * qnx nto and it is also _required_ for some of these functions on some + * QNX Neutrino and it is also _required_ for some of these functions on some * platforms. */ -#if defined(HAVE_GETHOSTBYNAME_R_5) +#ifdef HAVE_GETHOSTBYNAME_R_5 /* Solaris, IRIX and more */ h = gethostbyname_r(hostname, (struct hostent *)buf, @@ -287,5 +286,4 @@ struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, return ai; } -#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) && - !defined(CURLRES_AMIGA) */ +#endif /* CURLRES_IPV4 && !CURLRES_ARES && !CURLRES_AMIGA */ diff --git a/deps/curl/lib/hostip6.c b/deps/curl/lib/hostip6.c index ce7f5050ea8..4c05f0247e1 100644 --- a/deps/curl/lib/hostip6.c +++ b/deps/curl/lib/hostip6.c @@ -57,7 +57,7 @@ #include "curl_memory.h" #include "memdebug.h" -#if defined(CURLRES_SYNCH) +#ifdef CURLRES_SYNCH #ifdef DEBUG_ADDRINFO static void dump_addrinfo(const struct Curl_addrinfo *ai) @@ -114,8 +114,8 @@ struct Curl_addrinfo *Curl_sync_getaddrinfo(struct Curl_easy *data, * The AI_NUMERICHOST must not be set to get synthesized IPv6 address from * an IPv4 address on iOS and macOS. */ - if((1 == curlx_inet_pton(AF_INET, hostname, addrbuf)) || - (1 == curlx_inet_pton(AF_INET6, hostname, addrbuf))) { + if((curlx_inet_pton(AF_INET, hostname, addrbuf) == 1) || + (curlx_inet_pton(AF_INET6, hostname, addrbuf) == 1)) { /* the given address is numerical only, prevent a reverse lookup */ hints.ai_flags = AI_NUMERICHOST; } diff --git a/deps/curl/lib/hsts.c b/deps/curl/lib/hsts.c index 91f32276f95..9525158bcc7 100644 --- a/deps/curl/lib/hsts.c +++ b/deps/curl/lib/hsts.c @@ -426,7 +426,7 @@ static CURLcode hsts_add(struct hsts *h, const char *line) bool subdomain = FALSE; struct stsentry *e; char dbuf[MAX_HSTS_DATELEN + 1]; - time_t expires; + time_t expires = 0; const char *hp = curlx_str(&host); /* The date parser works on a null-terminated string. The maximum length @@ -434,8 +434,10 @@ static CURLcode hsts_add(struct hsts *h, const char *line) memcpy(dbuf, curlx_str(&date), curlx_strlen(&date)); dbuf[curlx_strlen(&date)] = 0; - expires = strcmp(dbuf, UNLIMITED) ? Curl_getdate_capped(dbuf) : - TIME_T_MAX; + if(!strcmp(dbuf, UNLIMITED)) + expires = TIME_T_MAX; + else + Curl_getdate_capped(dbuf, &expires); if(hp[0] == '.') { curlx_str_nudge(&host, 1); @@ -478,14 +480,14 @@ static CURLcode hsts_pull(struct Curl_easy *data, struct hsts *h) e.name[0] = 0; /* just to make it clean */ sc = data->set.hsts_read(data, &e, data->set.hsts_read_userp); if(sc == CURLSTS_OK) { - time_t expires; + time_t expires = 0; CURLcode result; DEBUGASSERT(e.name[0]); if(!e.name[0]) /* bail out if no name was stored */ return CURLE_BAD_FUNCTION_ARGUMENT; if(e.expire[0]) - expires = Curl_getdate_capped(e.expire); + Curl_getdate_capped(e.expire, &expires); else expires = TIME_T_MAX; /* the end of time */ result = hsts_create(h, e.name, strlen(e.name), diff --git a/deps/curl/lib/http.c b/deps/curl/lib/http.c index e5a0696274f..e01de6f4772 100644 --- a/deps/curl/lib/http.c +++ b/deps/curl/lib/http.c @@ -105,24 +105,16 @@ static void http_exp100_got100(struct Curl_easy *data); static CURLcode http_firstwrite(struct Curl_easy *data); static CURLcode http_header(struct Curl_easy *data, const char *hd, size_t hdlen); -static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn); static CURLcode http_range(struct Curl_easy *data, Curl_HttpReq httpreq); -static CURLcode http_req_complete(struct Curl_easy *data, - struct dynbuf *r, int httpversion, - Curl_HttpReq httpreq); -static CURLcode http_req_set_reader(struct Curl_easy *data, - Curl_HttpReq httpreq, int httpversion, - const char **tep); +static CURLcode http_req_set_TE(struct Curl_easy *data, + struct dynbuf *req, + int httpversion); static CURLcode http_size(struct Curl_easy *data); static CURLcode http_statusline(struct Curl_easy *data, struct connectdata *conn); -static CURLcode http_target(struct Curl_easy *data, struct connectdata *conn, - struct dynbuf *req); +static CURLcode http_target(struct Curl_easy *data, struct dynbuf *req); static CURLcode http_useragent(struct Curl_easy *data); -#ifdef HAVE_LIBZ -static CURLcode http_transferencode(struct Curl_easy *data); -#endif /* @@ -137,10 +129,10 @@ const struct Curl_handler Curl_handler_http = { Curl_http_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - Curl_http_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + Curl_http_do_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ Curl_http_write_resp, /* write_resp */ Curl_http_write_resp_hd, /* write_resp_hd */ @@ -167,10 +159,10 @@ const struct Curl_handler Curl_handler_https = { Curl_http_connect, /* connect_it */ NULL, /* connecting */ ZERO_NULL, /* doing */ - NULL, /* proto_getsock */ - Curl_http_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + NULL, /* proto_pollset */ + Curl_http_do_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ Curl_http_write_resp, /* write_resp */ Curl_http_write_resp_hd, /* write_resp_hd */ @@ -474,7 +466,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data, if(abort_upload) { /* We'd like to abort the upload - but should we? */ -#if defined(USE_NTLM) +#ifdef USE_NTLM if((data->state.authproxy.picked == CURLAUTH_NTLM) || (data->state.authhost.picked == CURLAUTH_NTLM)) { ongoing_auth = "NTLM"; @@ -486,7 +478,7 @@ static CURLcode http_perhapsrewind(struct Curl_easy *data, } } #endif -#if defined(USE_SPNEGO) +#ifdef USE_SPNEGO /* There is still data left to send */ if((data->state.authproxy.picked == CURLAUTH_NEGOTIATE) || (data->state.authhost.picked == CURLAUTH_NEGOTIATE)) { @@ -1077,7 +1069,9 @@ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, } return result; #else - (void) proxy; + (void)data; + (void)proxy; + (void)auth; /* nothing to do when disabled */ return CURLE_OK; #endif @@ -1321,7 +1315,7 @@ CURLcode Curl_http_follow(struct Curl_easy *data, const char *newurl, data->info.wouldredirect = follow_url; if(reachedmax) { - failf(data, "Maximum (%ld) redirects followed", data->set.maxredirs); + failf(data, "Maximum (%d) redirects followed", data->set.maxredirs); return CURLE_TOO_MANY_REDIRECTS; } return CURLE_OK; @@ -1522,14 +1516,11 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done) /* this returns the socket to wait for in the DO and DOING state for the multi interface and then we are always _sending_ a request and thus we wait for the single socket to become writable only */ -int Curl_http_getsock_do(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks) +CURLcode Curl_http_do_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { /* write mode */ - (void)conn; - socks[0] = Curl_conn_get_socket(data, FIRSTSOCKET); - return GETSOCK_WRITESOCK(0); + return Curl_pollset_add_out(data, ps, data->conn->sock[FIRSTSOCKET]); } /* @@ -1710,10 +1701,8 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, we will force length zero then */ curlx_str_casecompare(&name, "Content-Length")) ; - else if(data->state.aptr.te && - /* when asking for Transfer-Encoding, do not pass on a custom - Connection: */ - curlx_str_casecompare(&name, "Connection")) + else if(curlx_str_casecompare(&name, "Connection")) + /* Normal Connection: header generation takes care of this */ ; else if((httpversion >= 20) && curlx_str_casecompare(&name, "Transfer-Encoding")) @@ -1818,12 +1807,14 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data, } #endif -void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, +void Curl_http_method(struct Curl_easy *data, const char **method, Curl_HttpReq *reqp) { Curl_HttpReq httpreq = (Curl_HttpReq)data->state.httpreq; const char *request; - if((conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && + if(data->conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + httpreq = HTTPREQ_GET; + else if((data->conn->handler->protocol&(PROTO_FAMILY_HTTP|CURLPROTO_FTP)) && data->state.upload) httpreq = HTTPREQ_PUT; @@ -1874,10 +1865,12 @@ static CURLcode http_useragent(struct Curl_easy *data) } -static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn) +static CURLcode http_set_aptr_host(struct Curl_easy *data) { - const char *ptr; + struct connectdata *conn = data->conn; struct dynamically_allocated_data *aptr = &data->state.aptr; + const char *ptr; + if(!data->state.this_is_a_follow) { /* Free to avoid leaking memory on multiple requests */ free(data->state.first_host); @@ -1894,7 +1887,7 @@ static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn) ptr = Curl_checkheaders(data, STRCONST("Host")); if(ptr && (!data->state.this_is_a_follow || curl_strequal(data->state.first_host, conn->host.name))) { -#if !defined(CURL_DISABLE_COOKIES) +#ifndef CURL_DISABLE_COOKIES /* If we have a given custom Host: header, we extract the hostname in order to possibly use it for cookie reasons later on. We only allow the custom Host: header if this is NOT a redirect, as setting Host: in the @@ -1965,7 +1958,6 @@ static CURLcode http_host(struct Curl_easy *data, struct connectdata *conn) * Append the request-target to the HTTP request */ static CURLcode http_target(struct Curl_easy *data, - struct connectdata *conn, struct dynbuf *r) { CURLcode result = CURLE_OK; @@ -1978,7 +1970,7 @@ static CURLcode http_target(struct Curl_easy *data, } #ifndef CURL_DISABLE_PROXY - if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + if(data->conn->bits.httpproxy && !data->conn->bits.tunnel_proxy) { /* Using a proxy but does not tunnel through it */ /* The path sent to the proxy is in fact the entire URL. But if the remote @@ -1992,8 +1984,8 @@ static CURLcode http_target(struct Curl_easy *data, if(!h) return CURLE_OUT_OF_MEMORY; - if(conn->host.dispname != conn->host.name) { - uc = curl_url_set(h, CURLUPART_HOST, conn->host.name, 0); + if(data->conn->host.dispname != data->conn->host.name) { + uc = curl_url_set(h, CURLUPART_HOST, data->conn->host.name, 0); if(uc) { curl_url_cleanup(h); return CURLE_OUT_OF_MEMORY; @@ -2059,8 +2051,6 @@ static CURLcode http_target(struct Curl_easy *data, } else -#else - (void)conn; /* not used in disabled-proxy builds */ #endif { result = curlx_dyn_add(r, path); @@ -2246,21 +2236,13 @@ static CURLcode http_resume(struct Curl_easy *data, Curl_HttpReq httpreq) return CURLE_OK; } -static CURLcode http_req_set_reader(struct Curl_easy *data, - Curl_HttpReq httpreq, int httpversion, - const char **tep) +static CURLcode http_req_set_TE(struct Curl_easy *data, + struct dynbuf *req, + int httpversion) { CURLcode result = CURLE_OK; const char *ptr; - result = set_reader(data, httpreq); - if(result) - return result; - - result = http_resume(data, httpreq); - if(result) - return result; - ptr = Curl_checkheaders(data, STRCONST("Transfer-Encoding")); if(ptr) { /* Some kind of TE is requested, check if 'chunked' is chosen */ @@ -2294,7 +2276,7 @@ static CURLcode http_req_set_reader(struct Curl_easy *data, } if(data->req.upload_chunky) - *tep = "Transfer-Encoding: chunked\r\n"; + result = curlx_dyn_add(req, "Transfer-Encoding: chunked\r\n"); } return result; } @@ -2334,9 +2316,10 @@ static CURLcode addexpect(struct Curl_easy *data, struct dynbuf *r, return CURLE_OK; } -static CURLcode http_req_complete(struct Curl_easy *data, - struct dynbuf *r, int httpversion, - Curl_HttpReq httpreq) +static CURLcode http_add_content_hds(struct Curl_easy *data, + struct dynbuf *r, + int httpversion, + Curl_HttpReq httpreq) { CURLcode result = CURLE_OK; curl_off_t req_clen; @@ -2404,26 +2387,17 @@ static CURLcode http_req_complete(struct Curl_easy *data, break; } - /* end of headers */ - result = curlx_dyn_addn(r, STRCONST("\r\n")); - if(!result) { - Curl_pgrsSetUploadSize(data, req_clen); - if(announced_exp100) - result = http_exp100_add_reader(data); - } + Curl_pgrsSetUploadSize(data, req_clen); + if(announced_exp100) + result = http_exp100_add_reader(data); out: - if(!result) { - /* setup variables for the upcoming transfer */ - Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE); - } return result; } -#if !defined(CURL_DISABLE_COOKIES) +#ifndef CURL_DISABLE_COOKIES static CURLcode http_cookies(struct Curl_easy *data, - struct connectdata *conn, struct dynbuf *r) { CURLcode result = CURLE_OK; @@ -2436,51 +2410,43 @@ static CURLcode http_cookies(struct Curl_easy *data, if(data->cookies || addcookies) { struct Curl_llist list; int count = 0; - int rc = 1; if(data->cookies && data->state.cookie_engine) { const char *host = data->state.aptr.cookiehost ? - data->state.aptr.cookiehost : conn->host.name; - const bool secure_context = - conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || - curl_strequal("localhost", host) || - !strcmp(host, "127.0.0.1") || - !strcmp(host, "::1"); + data->state.aptr.cookiehost : data->conn->host.name; Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - rc = Curl_cookie_getlist(data, data->cookies, host, data->state.up.path, - secure_context, &list); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - if(!rc) { - struct Curl_llist_node *n; - size_t clen = 8; /* hold the size of the generated Cookie: header */ - - /* loop through all cookies that matched */ - for(n = Curl_llist_head(&list); n; n = Curl_node_next(n)) { - struct Cookie *co = Curl_node_elem(n); - if(co->value) { - size_t add; - if(!count) { - result = curlx_dyn_addn(r, STRCONST("Cookie: ")); + if(!Curl_cookie_getlist(data, data->conn, host, &list)) { + struct Curl_llist_node *n; + size_t clen = 8; /* hold the size of the generated Cookie: header */ + + /* loop through all cookies that matched */ + for(n = Curl_llist_head(&list); n; n = Curl_node_next(n)) { + struct Cookie *co = Curl_node_elem(n); + if(co->value) { + size_t add; + if(!count) { + result = curlx_dyn_addn(r, STRCONST("Cookie: ")); + if(result) + break; + } + add = strlen(co->name) + strlen(co->value) + 1; + if(clen + add >= MAX_COOKIE_HEADER_LEN) { + infof(data, "Restricted outgoing cookies due to header size, " + "'%s' not sent", co->name); + linecap = TRUE; + break; + } + result = curlx_dyn_addf(r, "%s%s=%s", count ? "; " : "", + co->name, co->value); if(result) break; + clen += add + (count ? 2 : 0); + count++; } - add = strlen(co->name) + strlen(co->value) + 1; - if(clen + add >= MAX_COOKIE_HEADER_LEN) { - infof(data, "Restricted outgoing cookies due to header size, " - "'%s' not sent", co->name); - linecap = TRUE; - break; - } - result = curlx_dyn_addf(r, "%s%s=%s", count ? "; " : "", - co->name, co->value); - if(result) - break; - clen += add + (count ? 2 : 0); - count++; } + Curl_llist_destroy(&list, NULL); } - Curl_llist_destroy(&list, NULL); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } if(addcookies && !result && !linecap) { if(!count) @@ -2499,7 +2465,7 @@ static CURLcode http_cookies(struct Curl_easy *data, return result; } #else -#define http_cookies(a,b,c) CURLE_OK +#define http_cookies(a,b) CURLE_OK #endif static CURLcode http_range(struct Curl_easy *data, @@ -2621,39 +2587,257 @@ static CURLcode http_firstwrite(struct Curl_easy *data) return CURLE_OK; } -#ifdef HAVE_LIBZ -static CURLcode http_transferencode(struct Curl_easy *data) +static CURLcode http_check_new_conn(struct Curl_easy *data) { - if(!Curl_checkheaders(data, STRCONST("TE")) && - data->set.http_transfer_encoding) { - /* When we are to insert a TE: header in the request, we must also insert - TE in a Connection: header, so we need to merge the custom provided - Connection: header and prevent the original to get sent. Note that if - the user has inserted his/her own TE: header we do not do this magic - but then assume that the user will handle it all! */ - char *cptr = Curl_checkheaders(data, STRCONST("Connection")); -#define TE_HEADER "TE: gzip\r\n" - - Curl_safefree(data->state.aptr.te); - - if(cptr) { - cptr = Curl_copy_header_value(cptr); - if(!cptr) - return CURLE_OUT_OF_MEMORY; + struct connectdata *conn = data->conn; + const char *info_version = NULL; + const char *alpn; + CURLcode result; + + alpn = Curl_conn_get_alpn_negotiated(data, conn); + if(alpn && !strcmp("h3", alpn)) { + DEBUGASSERT(Curl_conn_http_version(data, conn) == 30); + info_version = "HTTP/3"; + } + else if(alpn && !strcmp("h2", alpn)) { +#ifndef CURL_DISABLE_PROXY + if((Curl_conn_http_version(data, conn) != 20) && + conn->bits.proxy && !conn->bits.tunnel_proxy) { + result = Curl_http2_switch(data); + if(result) + return result; + } + else +#endif + DEBUGASSERT(Curl_conn_http_version(data, conn) == 20); + info_version = "HTTP/2"; + } + else { + /* Check if user wants to use HTTP/2 with clear TCP */ + if(Curl_http2_may_switch(data)) { + DEBUGF(infof(data, "HTTP/2 over clean TCP")); + result = Curl_http2_switch(data); + if(result) + return result; + info_version = "HTTP/2"; + /* There is no ALPN here, but the connection is now definitely h2 */ + conn->httpversion_seen = 20; } + else + info_version = "HTTP/1.x"; + } - /* Create the (updated) Connection: header */ - data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, - cptr ? cptr : "", (cptr && *cptr) ? ", ":""); + if(info_version) + infof(data, "using %s", info_version); + return CURLE_OK; +} - free(cptr); - if(!data->state.aptr.te) - return CURLE_OUT_OF_MEMORY; +static CURLcode http_add_connection_hd(struct Curl_easy *data, + struct dynbuf *req) +{ + char *custom = Curl_checkheaders(data, STRCONST("Connection")); + char *custom_val = custom ? Curl_copy_header_value(custom) : NULL; + const char *sep = (custom_val && *custom_val) ? ", " : "Connection: "; + CURLcode result = CURLE_OK; + size_t rlen = curlx_dyn_len(req); + + if(custom && !custom_val) + return CURLE_OUT_OF_MEMORY; + + if(custom_val && *custom_val) + result = curlx_dyn_addf(req, "Connection: %s", custom_val); + if(!result && data->state.http_hd_te) { + result = curlx_dyn_addf(req, "%s%s", sep, "TE"); + sep = ", "; } - return CURLE_OK; + if(!result && data->state.http_hd_upgrade) { + result = curlx_dyn_addf(req, "%s%s", sep, "Upgrade"); + sep = ", "; + } + if(!result && data->state.http_hd_h2_settings) { + result = curlx_dyn_addf(req, "%s%s", sep, "HTTP2-Settings"); + } + if(!result && (rlen < curlx_dyn_len(req))) + result = curlx_dyn_addn(req, STRCONST("\r\n")); + + free(custom_val); + return result; } + +/* Header identifier in order we send them by default */ +typedef enum { + H1_HD_REQUEST, + H1_HD_HOST, +#ifndef CURL_DISABLE_PROXY + H1_HD_PROXY_AUTH, +#endif + H1_HD_USER_AUTH, + H1_HD_RANGE, + H1_HD_USER_AGENT, + H1_HD_ACCEPT, + H1_HD_TE, + H1_HD_ACCEPT_ENCODING, + H1_HD_REFERER, +#ifndef CURL_DISABLE_PROXY + H1_HD_PROXY_CONNECTION, +#endif + H1_HD_TRANSFER_ENCODING, +#ifndef CURL_DISABLE_ALTSVC + H1_HD_ALT_USED, +#endif + H1_HD_UPGRADE, + H1_HD_COOKIES, + H1_HD_CONDITIONALS, + H1_HD_CUSTOM, + H1_HD_CONTENT, + H1_HD_CONNECTION, + H1_HD_LAST /* the last, empty header line */ +} http_hd_t; + +static CURLcode http_add_hd(struct Curl_easy *data, + struct dynbuf *req, + http_hd_t id, + unsigned char httpversion, + const char *method, + Curl_HttpReq httpreq) +{ + CURLcode result = CURLE_OK; + switch(id) { + case H1_HD_REQUEST: + /* add the main request stuff */ + /* GET/HEAD/POST/PUT */ + result = curlx_dyn_addf(req, "%s ", method); + if(!result) + result = http_target(data, req); + if(!result) + result = curlx_dyn_addf(req, " HTTP/%s\r\n", + get_http_string(httpversion)); + break; + + case H1_HD_HOST: + if(data->state.aptr.host) + result = curlx_dyn_add(req, data->state.aptr.host); + break; + +#ifndef CURL_DISABLE_PROXY + case H1_HD_PROXY_AUTH: + if(data->state.aptr.proxyuserpwd) + result = curlx_dyn_add(req, data->state.aptr.proxyuserpwd); + break; #endif + case H1_HD_USER_AUTH: + if(data->state.aptr.userpwd) + result = curlx_dyn_add(req, data->state.aptr.userpwd); + break; + + case H1_HD_RANGE: + if(data->state.use_range && data->state.aptr.rangeline) + result = curlx_dyn_add(req, data->state.aptr.rangeline); + break; + + case H1_HD_USER_AGENT: + if(data->set.str[STRING_USERAGENT] && /* User-Agent: */ + *data->set.str[STRING_USERAGENT] && + data->state.aptr.uagent) + result = curlx_dyn_add(req, data->state.aptr.uagent); + break; + + case H1_HD_ACCEPT: + if(!Curl_checkheaders(data, STRCONST("Accept"))) + result = curlx_dyn_add(req, "Accept: */*\r\n"); + break; + + case H1_HD_TE: +#ifdef HAVE_LIBZ + if(!Curl_checkheaders(data, STRCONST("TE")) && + data->set.http_transfer_encoding) { + data->state.http_hd_te = TRUE; + result = curlx_dyn_add(req, "TE: gzip\r\n"); + } +#endif + break; + + case H1_HD_ACCEPT_ENCODING: + Curl_safefree(data->state.aptr.accept_encoding); + if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) && + data->set.str[STRING_ENCODING]) + result = curlx_dyn_addf(req, "Accept-Encoding: %s\r\n", + data->set.str[STRING_ENCODING]); + break; + + case H1_HD_REFERER: + Curl_safefree(data->state.aptr.ref); + if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) + result = curlx_dyn_addf(req, "Referer: %s\r\n", data->state.referer); + break; + +#ifndef CURL_DISABLE_PROXY + case H1_HD_PROXY_CONNECTION: + if(data->conn->bits.httpproxy && + !data->conn->bits.tunnel_proxy && + !Curl_checkheaders(data, STRCONST("Proxy-Connection")) && + !Curl_checkProxyheaders(data, data->conn, STRCONST("Proxy-Connection"))) + result = curlx_dyn_add(req, "Proxy-Connection: Keep-Alive\r\n"); + break; +#endif + + case H1_HD_TRANSFER_ENCODING: + result = http_req_set_TE(data, req, httpversion); + break; + +#ifndef CURL_DISABLE_ALTSVC + case H1_HD_ALT_USED: + if(data->conn->bits.altused && + !Curl_checkheaders(data, STRCONST("Alt-Used"))) + result = curlx_dyn_addf(req, "Alt-Used: %s:%d\r\n", + data->conn->conn_to_host.name, + data->conn->conn_to_port); + break; +#endif + + case H1_HD_UPGRADE: + if(!Curl_conn_is_ssl(data->conn, FIRSTSOCKET) && (httpversion < 20) && + (data->state.http_neg.wanted & CURL_HTTP_V2x) && + data->state.http_neg.h2_upgrade) { + /* append HTTP2 upgrade magic stuff to the HTTP request if it is not done + over SSL */ + result = Curl_http2_request_upgrade(req, data); + } +#ifndef CURL_DISABLE_WEBSOCKETS + if(!result && data->conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) + result = Curl_ws_request(data, req); +#endif + break; + + case H1_HD_COOKIES: + result = http_cookies(data, req); + break; + + case H1_HD_CONDITIONALS: + result = Curl_add_timecondition(data, req); + break; + + case H1_HD_CUSTOM: + result = Curl_add_custom_headers(data, FALSE, httpversion, req); + break; + + case H1_HD_CONTENT: + result = http_add_content_hds(data, req, httpversion, httpreq); + break; + + case H1_HD_CONNECTION: { + result = http_add_connection_hd(data, req); + break; + } + + case H1_HD_LAST: + result = curlx_dyn_addn(req, STRCONST("\r\n")); + break; + } + return result; +} + /* * Curl_http() gets called from the generic multi_do() function when an HTTP * request is to be performed. This creates and sends a properly constructed @@ -2661,51 +2845,27 @@ static CURLcode http_transferencode(struct Curl_easy *data) */ CURLcode Curl_http(struct Curl_easy *data, bool *done) { - struct connectdata *conn = data->conn; CURLcode result = CURLE_OK; Curl_HttpReq httpreq; - const char *te = ""; /* transfer-encoding */ - const char *request; - const char *httpstring; + const char *method; struct dynbuf req; - char *altused = NULL; - const char *p_accept; /* Accept: string */ unsigned char httpversion; + size_t hd_id; /* Always consider the DO phase done after this function call, even if there may be parts of the request that are not yet sent, since we can deal with the rest of the request in the PERFORM phase. */ *done = TRUE; + /* initialize a dynamic send-buffer */ + curlx_dyn_init(&req, DYN_HTTP_REQUEST); + /* make sure the header buffer is reset - if there are leftovers from a + previous transfer */ + curlx_dyn_reset(&data->state.headerb); - switch(conn->alpn) { - case CURL_HTTP_VERSION_3: - DEBUGASSERT(Curl_conn_http_version(data, conn) == 30); - break; - case CURL_HTTP_VERSION_2: -#ifndef CURL_DISABLE_PROXY - if((Curl_conn_http_version(data, conn) != 20) && - conn->bits.proxy && !conn->bits.tunnel_proxy - ) { - result = Curl_http2_switch(data); - if(result) - goto fail; - } - else -#endif - DEBUGASSERT(Curl_conn_http_version(data, conn) == 20); - break; - case CURL_HTTP_VERSION_1_1: - /* continue with HTTP/1.x when explicitly requested */ - break; - default: - /* Check if user wants to use HTTP/2 with clear TCP */ - if(Curl_http2_may_switch(data)) { - DEBUGF(infof(data, "HTTP/2 over clean TCP")); - result = Curl_http2_switch(data); - if(result) - goto fail; - } - break; + if(!data->conn->bits.reuse) { + result = http_check_new_conn(data); + if(result) + goto out; } /* Add collecting of headers written to client. For a new connection, @@ -2713,151 +2873,67 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) * or multiplex needs it here as well. */ result = Curl_headers_init(data); if(result) - goto fail; - - result = http_host(data, conn); - if(result) - goto fail; + goto out; - result = http_useragent(data); - if(result) - goto fail; + data->state.http_hd_te = FALSE; + data->state.http_hd_upgrade = FALSE; + data->state.http_hd_h2_settings = FALSE; - Curl_http_method(data, conn, &request, &httpreq); + /* what kind of request do we need to send? */ + Curl_http_method(data, &method, &httpreq); - /* setup the authentication headers */ - { + /* select host to send */ + result = http_set_aptr_host(data); + if(!result) { + /* setup the authentication headers, how that method and host are known */ char *pq = NULL; if(data->state.up.query) { pq = aprintf("%s?%s", data->state.up.path, data->state.up.query); if(!pq) return CURLE_OUT_OF_MEMORY; } - result = Curl_http_output_auth(data, conn, request, httpreq, + result = Curl_http_output_auth(data, data->conn, method, httpreq, (pq ? pq : data->state.up.path), FALSE); free(pq); - if(result) - goto fail; - } - - Curl_safefree(data->state.aptr.ref); - if(data->state.referer && !Curl_checkheaders(data, STRCONST("Referer"))) { - data->state.aptr.ref = aprintf("Referer: %s\r\n", data->state.referer); - if(!data->state.aptr.ref) - return CURLE_OUT_OF_MEMORY; } - - if(!Curl_checkheaders(data, STRCONST("Accept-Encoding")) && - data->set.str[STRING_ENCODING]) { - free(data->state.aptr.accept_encoding); - data->state.aptr.accept_encoding = - aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]); - if(!data->state.aptr.accept_encoding) - return CURLE_OUT_OF_MEMORY; - } - else - Curl_safefree(data->state.aptr.accept_encoding); - -#ifdef HAVE_LIBZ - /* we only consider transfer-encoding magic if libz support is built-in */ - result = http_transferencode(data); if(result) - goto fail; -#endif - - httpversion = http_request_version(data); - httpstring = get_http_string(httpversion); + goto out; - result = http_req_set_reader(data, httpreq, httpversion, &te); + result = http_useragent(data); if(result) - goto fail; - - p_accept = Curl_checkheaders(data, - STRCONST("Accept")) ? NULL : "Accept: */*\r\n"; + goto out; - result = http_range(data, httpreq); + /* Setup input reader, resume information and ranges */ + result = set_reader(data, httpreq); + if(!result) + result = http_resume(data, httpreq); + if(!result) + result = http_range(data, httpreq); if(result) - goto fail; + goto out; - /* initialize a dynamic send-buffer */ - curlx_dyn_init(&req, DYN_HTTP_REQUEST); + httpversion = http_request_version(data); + /* Add request line and all headers to `req` */ + for(hd_id = 0; hd_id <= H1_HD_LAST; ++hd_id) { + result = http_add_hd(data, &req, (http_hd_t)hd_id, + httpversion, method, httpreq); + if(result) + goto out; + } - /* make sure the header buffer is reset - if there are leftovers from a - previous transfer */ - curlx_dyn_reset(&data->state.headerb); + /* setup variables for the upcoming transfer and send */ + Curl_xfer_setup_sendrecv(data, FIRSTSOCKET, -1); + result = Curl_req_send(data, &req, httpversion); - /* add the main request stuff */ - /* GET/HEAD/POST/PUT */ - result = curlx_dyn_addf(&req, "%s ", request); - if(!result) - result = http_target(data, conn, &req); - if(result) { - curlx_dyn_free(&req); - goto fail; - } + if((httpversion >= 20) && data->req.upload_chunky) + /* upload_chunky was set above to set up the request in a chunky fashion, + but is disabled here again to avoid that the chunked encoded version is + actually used when sending the request body over h2 */ + data->req.upload_chunky = FALSE; -#ifndef CURL_DISABLE_ALTSVC - if(conn->bits.altused && !Curl_checkheaders(data, STRCONST("Alt-Used"))) { - altused = aprintf("Alt-Used: %s:%d\r\n", - conn->conn_to_host.name, conn->conn_to_port); - if(!altused) { - curlx_dyn_free(&req); - return CURLE_OUT_OF_MEMORY; - } - } -#endif - result = - curlx_dyn_addf(&req, - " HTTP/%s\r\n" /* HTTP version */ - "%s" /* host */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - "%s" /* range */ - "%s" /* user agent */ - "%s" /* accept */ - "%s" /* TE: */ - "%s" /* accept-encoding */ - "%s" /* referer */ - "%s" /* Proxy-Connection */ - "%s" /* transfer-encoding */ - "%s",/* Alt-Used */ - - httpstring, - (data->state.aptr.host ? data->state.aptr.host : ""), -#ifndef CURL_DISABLE_PROXY - data->state.aptr.proxyuserpwd ? - data->state.aptr.proxyuserpwd : "", -#else - "", -#endif - data->state.aptr.userpwd ? data->state.aptr.userpwd : "", - (data->state.use_range && data->state.aptr.rangeline) ? - data->state.aptr.rangeline : "", - (data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && - data->state.aptr.uagent) ? - data->state.aptr.uagent : "", - p_accept ? p_accept : "", - data->state.aptr.te ? data->state.aptr.te : "", - (data->set.str[STRING_ENCODING] && - *data->set.str[STRING_ENCODING] && - data->state.aptr.accept_encoding) ? - data->state.aptr.accept_encoding : "", - (data->state.referer && data->state.aptr.ref) ? - data->state.aptr.ref : "" /* Referer: */, -#ifndef CURL_DISABLE_PROXY - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkheaders(data, STRCONST("Proxy-Connection")) && - !Curl_checkProxyheaders(data, conn, - STRCONST("Proxy-Connection"))) ? - "Proxy-Connection: Keep-Alive\r\n":"", -#else - "", -#endif - te, - altused ? altused : "" - ); +out: + if(CURLE_TOO_LARGE == result) + failf(data, "HTTP request too large"); /* clear userpwd and proxyuserpwd to avoid reusing old credentials * from reused connections */ @@ -2865,53 +2941,7 @@ CURLcode Curl_http(struct Curl_easy *data, bool *done) #ifndef CURL_DISABLE_PROXY Curl_safefree(data->state.aptr.proxyuserpwd); #endif - free(altused); - - if(result) { - curlx_dyn_free(&req); - goto fail; - } - - if(!Curl_conn_is_ssl(conn, FIRSTSOCKET) && (httpversion < 20) && - (data->state.http_neg.wanted & CURL_HTTP_V2x) && - data->state.http_neg.h2_upgrade) { - /* append HTTP2 upgrade magic stuff to the HTTP request if it is not done - over SSL */ - result = Curl_http2_request_upgrade(&req, data); - if(result) { - curlx_dyn_free(&req); - return result; - } - } - - result = http_cookies(data, conn, &req); -#ifndef CURL_DISABLE_WEBSOCKETS - if(!result && conn->handler->protocol&(CURLPROTO_WS|CURLPROTO_WSS)) - result = Curl_ws_request(data, &req); -#endif - if(!result) - result = Curl_add_timecondition(data, &req); - if(!result) - result = Curl_add_custom_headers(data, FALSE, httpversion, &req); - - if(!result) { - /* req_send takes ownership of the 'req' memory on success */ - result = http_req_complete(data, &req, httpversion, httpreq); - if(!result) - result = Curl_req_send(data, &req, httpversion); - } curlx_dyn_free(&req); - if(result) - goto fail; - - if((httpversion >= 20) && data->req.upload_chunky) - /* upload_chunky was set above to set up the request in a chunky fashion, - but is disabled here again to avoid that the chunked encoded version is - actually used when sending the request body over h2 */ - data->req.upload_chunky = FALSE; -fail: - if(CURLE_TOO_LARGE == result) - failf(data, "HTTP request too large"); return result; } @@ -2963,7 +2993,7 @@ checkrtspprefix(struct Curl_easy *data, { statusline result = STATUS_BAD; statusline onmatch = len >= 5 ? STATUS_DONE : STATUS_UNKNOWN; - (void)data; /* unused */ + (void)data; if(checkprefixmax("RTSP/", s, len)) result = onmatch; @@ -3164,7 +3194,8 @@ static CURLcode http_header_l(struct Curl_easy *data, (data->set.timecondition || data->set.get_filetime)) ? HD_VAL(hd, hdlen, "Last-Modified:") : NULL; if(v) { - k->timeofdoc = Curl_getdate_capped(v); + if(Curl_getdate_capped(v, &k->timeofdoc)) + k->timeofdoc = 0; if(data->set.get_filetime) data->info.filetime = k->timeofdoc; return CURLE_OK; @@ -3279,14 +3310,12 @@ static CURLcode http_header_r(struct Curl_easy *data, if(v) { /* Retry-After = HTTP-date / delay-seconds */ curl_off_t retry_after = 0; /* zero for unknown or "now" */ - time_t date; + time_t date = 0; curlx_str_passblanks(&v); /* try it as a date first, because a date can otherwise start with and get treated as a number */ - date = Curl_getdate_capped(v); - - if((time_t)-1 != date) { + if(!Curl_getdate_capped(v, &date)) { time_t current = time(NULL); if(date >= current) /* convert date to number of seconds into the future */ @@ -3319,7 +3348,7 @@ static CURLcode http_header_s(struct Curl_easy *data, (void)hdlen; #endif -#if !defined(CURL_DISABLE_COOKIES) +#ifndef CURL_DISABLE_COOKIES v = (data->cookies && data->state.cookie_engine) ? HD_VAL(hd, hdlen, "Set-Cookie:") : NULL; if(v) { @@ -3327,14 +3356,8 @@ static CURLcode http_header_s(struct Curl_easy *data, * real peer hostname. */ const char *host = data->state.aptr.cookiehost ? data->state.aptr.cookiehost : conn->host.name; - const bool secure_context = - conn->handler->protocol&(CURLPROTO_HTTPS|CURLPROTO_WSS) || - curl_strequal("localhost", host) || - !strcmp(host, "127.0.0.1") || - !strcmp(host, "::1"); - - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, - CURL_LOCK_ACCESS_SINGLE); + const bool secure_context = Curl_secure_context(conn, host); + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_add(data, data->cookies, TRUE, FALSE, v, host, data->state.up.path, secure_context); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); @@ -3766,9 +3789,6 @@ static CURLcode http_on_response(struct Curl_easy *data, if(result) goto out; *pconsumed += blen; /* ws accept handled the data */ - k->header = FALSE; /* we will not get more responses */ - if(data->set.connect_only) - k->keepon &= ~KEEP_RECV; /* read no more content */ } #endif else { @@ -3813,7 +3833,7 @@ static CURLcode http_on_response(struct Curl_easy *data, /* At this point we have some idea about the fate of the connection. If we are closing the connection it may result auth failure. */ -#if defined(USE_NTLM) +#ifdef USE_NTLM if(conn->bits.close && (((data->req.httpcode == 401) && (conn->http_ntlm_state == NTLMSTATE_TYPE2)) || @@ -3823,7 +3843,7 @@ static CURLcode http_on_response(struct Curl_easy *data, data->state.authproblem = TRUE; } #endif -#if defined(USE_SPNEGO) +#ifdef USE_SPNEGO if(conn->bits.close && (((data->req.httpcode == 401) && (conn->http_negotiate_state == GSS_AUTHRECV)) || @@ -3947,7 +3967,7 @@ static CURLcode http_on_response(struct Curl_easy *data, like to call http2_handle_stream_close to properly close a stream. In order to do this, we keep reading until we close the stream. */ - if((0 == k->maxdownload) && (k->httpversion_sent < 20)) + if((k->maxdownload == 0) && (k->httpversion_sent < 20)) k->download_done = TRUE; /* final response without error, prepare to receive the body */ @@ -4368,7 +4388,17 @@ CURLcode Curl_http_req_make(struct httpreq **preq, req = calloc(1, sizeof(*req) + m_len); if(!req) goto out; +#if defined(__GNUC__) && __GNUC__ >= 13 +#pragma GCC diagnostic push +/* error: 'memcpy' offset [137, 142] from the object at 'req' is out of + the bounds of referenced subobject 'method' with type 'char[1]' at + offset 136 */ +#pragma GCC diagnostic ignored "-Warray-bounds" +#endif memcpy(req->method, method, m_len); +#if defined(__GNUC__) && __GNUC__ >= 13 +#pragma GCC diagnostic pop +#endif if(scheme) { req->scheme = Curl_memdup0(scheme, s_len); if(!req->scheme) @@ -4569,7 +4599,7 @@ struct name_const { }; /* keep them sorted by length! */ -static struct name_const H2_NON_FIELD[] = { +static const struct name_const H2_NON_FIELD[] = { { STRCONST("Host") }, { STRCONST("Upgrade") }, { STRCONST("Connection") }, @@ -4771,7 +4801,7 @@ static CURLcode cr_exp100_read(struct Curl_easy *data, /* We are now waiting for a reply from the server or * a timeout on our side IFF the request has been fully sent. */ DEBUGF(infof(data, "cr_exp100_read, start AWAITING_CONTINUE, " - "timeout %ldms", data->set.expect_100_timeout)); + "timeout %dms", data->set.expect_100_timeout)); ctx->state = EXP100_AWAITING_CONTINUE; ctx->start = curlx_now(); Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); @@ -4822,8 +4852,7 @@ static const struct Curl_crtype cr_exp100 = { Curl_creader_def_needs_rewind, Curl_creader_def_total_length, Curl_creader_def_resume_from, - Curl_creader_def_rewind, - Curl_creader_def_unpause, + Curl_creader_def_cntrl, Curl_creader_def_is_paused, cr_exp100_done, sizeof(struct cr_exp100_ctx) diff --git a/deps/curl/lib/http.h b/deps/curl/lib/http.h index 8876f380447..67ef17f5b95 100644 --- a/deps/curl/lib/http.h +++ b/deps/curl/lib/http.h @@ -25,10 +25,6 @@ ***************************************************************************/ #include "curl_setup.h" -#if defined(USE_MSH3) && !defined(_WIN32) -#include -#endif - #include "bufq.h" #include "dynhds.h" #include "ws.h" @@ -62,7 +58,7 @@ typedef unsigned char http_majors; #ifndef CURL_DISABLE_HTTP -#if defined(USE_HTTP3) +#ifdef USE_HTTP3 #include #endif @@ -110,7 +106,7 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data, bool is_connect, CURLcode Curl_dynhds_add_custom(struct Curl_easy *data, bool is_connect, struct dynhds *hds); -void Curl_http_method(struct Curl_easy *data, struct connectdata *conn, +void Curl_http_method(struct Curl_easy *data, const char **method, Curl_HttpReq *); /* protocol-specific functions set up to be called by the main engine */ @@ -119,8 +115,8 @@ CURLcode Curl_http_setup_conn(struct Curl_easy *data, 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); -int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *socks); +CURLcode Curl_http_do_pollset(struct Curl_easy *data, + struct easy_pollset *ps); CURLcode Curl_http_write_resp(struct Curl_easy *data, const char *buf, size_t blen, bool is_eos); diff --git a/deps/curl/lib/http2.c b/deps/curl/lib/http2.c index 36dca426de8..e2cdc9181f5 100644 --- a/deps/curl/lib/http2.c +++ b/deps/curl/lib/http2.c @@ -24,7 +24,7 @@ #include "curl_setup.h" -#ifdef USE_NGHTTP2 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2) #include #include #include "urldata.h" @@ -488,7 +488,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, const uint8_t *value, size_t valuelen, uint8_t flags, void *userp); -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS static int error_callback(nghttp2_session *session, const char *msg, size_t len, void *userp); #endif @@ -523,7 +523,7 @@ static CURLcode cf_h2_ctx_open(struct Curl_cfilter *cf, nghttp2_session_callbacks_set_on_begin_headers_callback( cbs, on_begin_headers); nghttp2_session_callbacks_set_on_header_callback(cbs, on_header); -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS nghttp2_session_callbacks_set_error_callback(cbs, error_callback); #endif @@ -799,7 +799,7 @@ static ssize_t send_callback(nghttp2_session *h2, ctx->nw_out_blocked = 1; return NGHTTP2_ERR_WOULDBLOCK; } - return (nwritten > SSIZE_T_MAX) ? + return (nwritten > SSIZE_MAX) ? NGHTTP2_ERR_CALLBACK_FAILURE : (ssize_t)nwritten; } @@ -1779,7 +1779,7 @@ static ssize_t req_body_read_callback(nghttp2_session *session, return (nread == 0) ? NGHTTP2_ERR_DEFERRED : nread; } -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS static int error_callback(nghttp2_session *session, const char *msg, size_t len, @@ -1820,8 +1820,9 @@ CURLcode Curl_http2_request_upgrade(struct dynbuf *req, return result; } + data->state.http_hd_upgrade = TRUE; + data->state.http_hd_h2_settings = TRUE; result = curlx_dyn_addf(req, - "Connection: Upgrade, HTTP2-Settings\r\n" "Upgrade: %s\r\n" "HTTP2-Settings: %s\r\n", NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64); @@ -2220,7 +2221,7 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream, struct dynhds h2_headers; nghttp2_nv *nva = NULL; const void *body = NULL; - size_t nheader, bodylen, i; + size_t nheader, bodylen; nghttp2_data_provider data_prd; int32_t stream_id; nghttp2_priority_spec pri_spec; @@ -2282,9 +2283,10 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream, goto out; } +#ifndef CURL_DISABLE_VERBOSE_STRINGS #define MAX_ACC 60000 /* <64KB to account for some overhead */ if(Curl_trc_is_verbose(data)) { - size_t acc = 0; + size_t acc = 0, i; infof(data, "[HTTP/2] [%d] OPENED stream for %s", stream_id, data->state.url); @@ -2302,6 +2304,7 @@ static CURLcode h2_submit(struct h2_stream_ctx **pstream, "stream to be rejected.", MAX_ACC); } } +#endif stream->id = stream_id; @@ -2348,7 +2351,7 @@ static CURLcode cf_h2_send(struct Curl_cfilter *cf, struct Curl_easy *data, DEBUGASSERT(stream); } else if(stream->body_eos) { - /* We already wrote this, but CURLE_AGAINed the call due to not + /* We already wrote this, but CURLE_AGAIN-ed the call due to not * being able to flush stream->sendbuf. Make a 0-length write * to trigger flushing again. * If this works, we report to have written `len` bytes. */ @@ -2463,17 +2466,18 @@ static CURLcode cf_h2_flush(struct Curl_cfilter *cf, return result; } -static void cf_h2_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_h2_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_h2_ctx *ctx = cf->ctx; struct cf_call_data save; curl_socket_t sock; bool want_recv, want_send; + CURLcode result = CURLE_OK; if(!ctx->h2) - return; + return CURLE_OK; sock = Curl_conn_cf_get_socket(cf, data); Curl_pollset_check(data, ps, sock, &want_recv, &want_send); @@ -2491,7 +2495,7 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf, (!c_exhaust && nghttp2_session_want_write(ctx->h2)) || !Curl_bufq_is_empty(&ctx->outbufq); - Curl_pollset_set(data, ps, sock, want_recv, want_send); + result = Curl_pollset_set(data, ps, sock, want_recv, want_send); CF_DATA_RESTORE(cf, save); } else if(ctx->sent_goaway && !cf->shutdown) { @@ -2500,9 +2504,10 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf, want_send = nghttp2_session_want_write(ctx->h2) || !Curl_bufq_is_empty(&ctx->outbufq); want_recv = nghttp2_session_want_read(ctx->h2); - Curl_pollset_set(data, ps, sock, want_recv, want_send); + result = Curl_pollset_set(data, ps, sock, want_recv, want_send); CF_DATA_RESTORE(cf, save); } + return result; } static CURLcode cf_h2_connect(struct Curl_cfilter *cf, @@ -3008,23 +3013,23 @@ void *Curl_nghttp2_realloc(void *ptr, size_t size, void *user_data) return Curl_crealloc(ptr, size); } -#else /* !USE_NGHTTP2 */ +#else /* CURL_DISABLE_HTTP || !USE_NGHTTP2 */ /* Satisfy external references even if http2 is not compiled in. */ #include char *curl_pushheader_bynum(struct curl_pushheaders *h, size_t num) { - (void) h; - (void) num; + (void)h; + (void)num; return NULL; } char *curl_pushheader_byname(struct curl_pushheaders *h, const char *header) { - (void) h; - (void) header; + (void)h; + (void)header; return NULL; } -#endif /* USE_NGHTTP2 */ +#endif /* !CURL_DISABLE_HTTP && USE_NGHTTP2 */ diff --git a/deps/curl/lib/http_aws_sigv4.c b/deps/curl/lib/http_aws_sigv4.c index 92c0c1ff4cf..c62db499ca1 100644 --- a/deps/curl/lib/http_aws_sigv4.c +++ b/deps/curl/lib/http_aws_sigv4.c @@ -775,7 +775,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data) } } - Curl_http_method(data, conn, &method, &httpreq); + Curl_http_method(data, &method, &httpreq); payload_hash = parse_content_sha_hdr(data, curlx_str(&provider1), @@ -1149,4 +1149,4 @@ static bool should_urlencode(struct Curl_str *service_name) return true; } -#endif /* !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_AWS) */ +#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_AWS */ diff --git a/deps/curl/lib/http_chunks.c b/deps/curl/lib/http_chunks.c index 63e477c48a6..f735a820c7b 100644 --- a/deps/curl/lib/http_chunks.c +++ b/deps/curl/lib/http_chunks.c @@ -159,7 +159,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data, } else { const char *p; - if(0 == ch->hexindex) { + if(ch->hexindex == 0) { /* This is illegal data, we received junk where we expected a hexadecimal digit. */ failf(data, "chunk hex-length char not a hex digit: 0x%x", *buf); @@ -184,7 +184,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data, /* waiting for the LF after a chunk size */ if(*buf == 0x0a) { /* we are now expecting data to come, unless size was zero! */ - if(0 == ch->datasize) { + if(ch->datasize == 0) { ch->state = CHUNK_TRAILER; /* now check for trailers */ } else { @@ -229,7 +229,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data, FMT_OFF_T " bytes in chunk remain", piece, ch->datasize); - if(0 == ch->datasize) + if(ch->datasize == 0) /* end of data this round, we now expect a trailing CRLF */ ch->state = CHUNK_POSTLF; break; @@ -656,8 +656,7 @@ const struct Curl_crtype Curl_httpchunk_encoder = { Curl_creader_def_needs_rewind, cr_chunked_total_length, Curl_creader_def_resume_from, - Curl_creader_def_rewind, - Curl_creader_def_unpause, + Curl_creader_def_cntrl, Curl_creader_def_is_paused, Curl_creader_def_done, sizeof(struct chunked_reader) diff --git a/deps/curl/lib/http_digest.c b/deps/curl/lib/http_digest.c index 651bb834037..f4e920706c6 100644 --- a/deps/curl/lib/http_digest.c +++ b/deps/curl/lib/http_digest.c @@ -120,7 +120,7 @@ CURLcode Curl_output_digest(struct Curl_easy *data, if(!passwdp) passwdp = ""; -#if defined(USE_WINDOWS_SSPI) +#ifdef USE_WINDOWS_SSPI have_chlg = !!digest->input_token; #else have_chlg = !!digest->nonce; @@ -141,7 +141,7 @@ CURLcode Curl_output_digest(struct Curl_easy *data, https://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie Further details on Digest implementation differences: - http://www.fngtps.com/2006/09/http-authentication + https://web.archive.org/web/2009/fngtps.com/2006/09/http-authentication */ if(authp->iestyle) { diff --git a/deps/curl/lib/http_ntlm.c b/deps/curl/lib/http_ntlm.c index 0dff8f3a007..a172eb848dd 100644 --- a/deps/curl/lib/http_ntlm.c +++ b/deps/curl/lib/http_ntlm.c @@ -45,7 +45,7 @@ /* SSL backend-specific #if branches in this file must be kept in the order documented in curl_ntlm_core. */ -#if defined(USE_WINDOWS_SSPI) +#ifdef USE_WINDOWS_SSPI #include "curl_sspi.h" #endif diff --git a/deps/curl/lib/http_proxy.c b/deps/curl/lib/http_proxy.c index 6f435a86745..2d742856ce8 100644 --- a/deps/curl/lib/http_proxy.c +++ b/deps/curl/lib/http_proxy.c @@ -162,11 +162,6 @@ static CURLcode dynhds_add_custom(struct Curl_easy *data, we will force length zero then */ hd_name_eq(name, namelen, STRCONST("Content-Length:"))) ; - else if(data->state.aptr.te && - /* when asking for Transfer-Encoding, do not pass on a custom - Connection: */ - hd_name_eq(name, namelen, STRCONST("Connection:"))) - ; else if((httpversion >= 20) && hd_name_eq(name, namelen, STRCONST("Transfer-Encoding:"))) /* HTTP/2 and HTTP/3 do not support chunked requests */ @@ -325,36 +320,42 @@ static CURLcode http_proxy_cf_connect(struct Curl_cfilter *cf, if(!ctx->cf_protocol) { struct Curl_cfilter *cf_protocol = NULL; int httpversion = 0; - int alpn = Curl_conn_cf_is_ssl(cf->next) ? - cf->conn->proxy_alpn : CURL_HTTP_VERSION_1_1; - - /* First time call after the subchain connected */ - switch(alpn) { - case CURL_HTTP_VERSION_NONE: - case CURL_HTTP_VERSION_1_0: - case CURL_HTTP_VERSION_1_1: + const char *alpn = Curl_conn_cf_get_alpn_negotiated(cf->next, data); + + if(alpn) + infof(data, "CONNECT: '%s' negotiated", alpn); + else + infof(data, "CONNECT: no ALPN negotiated"); + + if(alpn && !strcmp(alpn, "http/1.0")) { + CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.0"); + result = Curl_cf_h1_proxy_insert_after(cf, data); + if(result) + goto out; + cf_protocol = cf->next; + httpversion = 10; + } + else if(!alpn || !strcmp(alpn, "http/1.1")) { CURL_TRC_CF(data, cf, "installing subfilter for HTTP/1.1"); - infof(data, "CONNECT tunnel: HTTP/1.%d negotiated", - (alpn == CURL_HTTP_VERSION_1_0) ? 0 : 1); result = Curl_cf_h1_proxy_insert_after(cf, data); if(result) goto out; cf_protocol = cf->next; - httpversion = (alpn == CURL_HTTP_VERSION_1_0) ? 10 : 11; - break; + /* Assume that without an ALPN, we are talking to an ancient one */ + httpversion = 11; + } #ifdef USE_NGHTTP2 - case CURL_HTTP_VERSION_2: + else if(!strcmp(alpn, "h2")) { CURL_TRC_CF(data, cf, "installing subfilter for HTTP/2"); - infof(data, "CONNECT tunnel: HTTP/2 negotiated"); result = Curl_cf_h2_proxy_insert_after(cf, data); if(result) goto out; cf_protocol = cf->next; httpversion = 20; - break; + } #endif - default: - infof(data, "CONNECT tunnel: unsupported ALPN(%d) negotiated", alpn); + else { + failf(data, "CONNECT: negotiated ALPN '%s' not supported", alpn); result = CURLE_COULDNT_CONNECT; goto out; } @@ -391,6 +392,12 @@ CURLcode Curl_cf_http_proxy_query(struct Curl_cfilter *cf, *pres1 = (int)cf->conn->http_proxy.port; *((const char **)pres2) = cf->conn->http_proxy.host.name; return CURLE_OK; + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = NULL; + return CURLE_OK; + } default: break; } diff --git a/deps/curl/lib/httpsrr.h b/deps/curl/lib/httpsrr.h index 83119dc6bde..563d1c8e515 100644 --- a/deps/curl/lib/httpsrr.h +++ b/deps/curl/lib/httpsrr.h @@ -76,7 +76,7 @@ void Curl_httpsrr_cleanup(struct Curl_https_rrinfo *rrinfo); #define HTTPS_RR_CODE_ECH 0x05 #define HTTPS_RR_CODE_IPV6 0x06 -#if defined(USE_ARES) +#ifdef USE_ARES CURLcode Curl_httpsrr_from_ares(struct Curl_easy *data, const ares_dns_record_t *dnsrec, struct Curl_https_rrinfo *hinfo); diff --git a/deps/curl/lib/idn.c b/deps/curl/lib/idn.c index 798c9aaef1a..bb6fd2cffc2 100644 --- a/deps/curl/lib/idn.c +++ b/deps/curl/lib/idn.c @@ -51,7 +51,7 @@ #include "memdebug.h" /* for macOS and iOS targets */ -#if defined(USE_APPLE_IDN) +#ifdef USE_APPLE_IDN #include #include #include @@ -152,7 +152,7 @@ static CURLcode mac_ascii_to_idn(const char *in, char **out) #ifdef USE_WIN32_IDN /* using Windows kernel32 and normaliz libraries. */ -#if (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x600) && \ +#if (!defined(_WIN32_WINNT) || _WIN32_WINNT < _WIN32_WINNT_VISTA) && \ (!defined(WINVER) || WINVER < 0x600) WINBASEAPI int WINAPI IdnToAscii(DWORD dwFlags, const WCHAR *lpUnicodeCharStr, @@ -323,8 +323,14 @@ CURLcode Curl_idn_decode(const char *input, char **output) result = CURLE_OUT_OF_MEMORY; } #endif - if(!result) - *output = d; + if(!result) { + if(!d[0]) { /* ended up zero length, not acceptable */ + result = CURLE_URL_MALFORMAT; + free(d); + } + else + *output = d; + } return result; } diff --git a/deps/curl/lib/if2ip.c b/deps/curl/lib/if2ip.c index d685290889e..91ee59c02a7 100644 --- a/deps/curl/lib/if2ip.c +++ b/deps/curl/lib/if2ip.c @@ -94,7 +94,7 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa) #if !defined(CURL_DISABLE_BINDLOCAL) || !defined(CURL_DISABLE_FTP) -#if defined(HAVE_GETIFADDRS) +#ifdef HAVE_GETIFADDRS if2ip_result_t Curl_if2ip(int af, #ifdef USE_IPV6 @@ -109,7 +109,7 @@ if2ip_result_t Curl_if2ip(int af, #if defined(USE_IPV6) && \ !defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID) - (void) local_scope_id; + (void)local_scope_id; #endif if(getifaddrs(&head) >= 0) { @@ -252,14 +252,14 @@ if2ip_result_t Curl_if2ip(int af, const char *interf, char *buf, size_t buf_size) { - (void) af; + (void)af; #ifdef USE_IPV6 - (void) remote_scope; - (void) local_scope_id; + (void)remote_scope; + (void)local_scope_id; #endif - (void) interf; - (void) buf; - (void) buf_size; + (void)interf; + (void)buf; + (void)buf_size; return IF2IP_NOT_FOUND; } diff --git a/deps/curl/lib/imap.c b/deps/curl/lib/imap.c index f25176bb9e2..41aec8ffab7 100644 --- a/deps/curl/lib/imap.c +++ b/deps/curl/lib/imap.c @@ -157,8 +157,8 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done); static CURLcode imap_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead); static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done); -static int imap_getsock(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *socks); +static CURLcode imap_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done); static CURLcode imap_setup_connection(struct Curl_easy *data, struct connectdata *conn); @@ -196,10 +196,10 @@ const struct Curl_handler Curl_handler_imap = { imap_connect, /* connect_it */ imap_multi_statemach, /* connecting */ imap_doing, /* doing */ - imap_getsock, /* proto_getsock */ - imap_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + imap_pollset, /* proto_pollset */ + imap_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ imap_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -227,10 +227,10 @@ const struct Curl_handler Curl_handler_imaps = { imap_connect, /* connect_it */ imap_multi_statemach, /* connecting */ imap_doing, /* doing */ - imap_getsock, /* proto_getsock */ - imap_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + imap_pollset, /* proto_pollset */ + imap_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ imap_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -1005,7 +1005,7 @@ static CURLcode imap_state_servergreet_resp(struct Curl_easy *data, int imapcode, imapstate instate) { - (void)instate; /* no use for this yet */ + (void)instate; if(imapcode == IMAP_RESP_PREAUTH) { /* PREAUTH */ @@ -1030,7 +1030,7 @@ static CURLcode imap_state_capability_resp(struct Curl_easy *data, struct connectdata *conn = data->conn; const char *line = curlx_dyn_ptr(&imapc->pp.recvbuf); - (void)instate; /* no use for this yet */ + (void)instate; /* Do we have an untagged response? */ if(imapcode == '*') { @@ -1111,7 +1111,7 @@ static CURLcode imap_state_starttls_resp(struct Curl_easy *data, { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; /* Pipelining in response is forbidden. */ if(imapc->pp.overflow) @@ -1140,7 +1140,7 @@ static CURLcode imap_state_auth_resp(struct Curl_easy *data, CURLcode result = CURLE_OK; saslprogress progress; - (void)instate; /* no use for this yet */ + (void)instate; result = Curl_sasl_continue(&imapc->sasl, data, imapcode, &progress); if(!result) @@ -1171,7 +1171,7 @@ static CURLcode imap_state_login_resp(struct Curl_easy *data, imapstate instate) { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(imapcode != IMAP_RESP_OK) { failf(data, "Access denied. %c", imapcode); @@ -1194,7 +1194,7 @@ static CURLcode imap_state_listsearch_resp(struct Curl_easy *data, char *line = curlx_dyn_ptr(&imapc->pp.recvbuf); size_t len = imapc->pp.nfinal; - (void)instate; /* No use for this yet */ + (void)instate; if(imapcode == '*') result = Curl_client_write(data, CLIENTWRITE_BODY, line, len); @@ -1217,7 +1217,7 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, CURLcode result = CURLE_OK; const char *line = curlx_dyn_ptr(&imapc->pp.recvbuf); - (void)instate; /* no use for this yet */ + (void)instate; if(imapcode == '*') { /* See if this is an UIDVALIDITY response */ @@ -1279,7 +1279,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, bool parsed = FALSE; curl_off_t size = 0; - (void)instate; /* no use for this yet */ + (void)instate; if(imapcode != '*') { Curl_pgrsSetDownloadSize(data, -1); @@ -1347,7 +1347,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, else { /* IMAP download */ data->req.maxdownload = size; - Curl_xfer_setup1(data, CURL_XFER_RECV, size, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, size); } } else { @@ -1370,7 +1370,7 @@ static CURLcode imap_state_fetch_final_resp(struct Curl_easy *data, { CURLcode result = CURLE_OK; - (void)instate; /* No use for this yet */ + (void)instate; if(imapcode != IMAP_RESP_OK) result = CURLE_WEIRD_SERVER_REPLY; @@ -1388,7 +1388,7 @@ static CURLcode imap_state_append_resp(struct Curl_easy *data, imapstate instate) { CURLcode result = CURLE_OK; - (void)instate; /* No use for this yet */ + (void)instate; if(imapcode != '+') { result = CURLE_UPLOAD_FAILED; @@ -1398,7 +1398,7 @@ static CURLcode imap_state_append_resp(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); /* IMAP upload */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* End of DO phase */ imap_state(data, imapc, IMAP_STOP); @@ -1415,7 +1415,7 @@ static CURLcode imap_state_append_final_resp(struct Curl_easy *data, { CURLcode result = CURLE_OK; - (void)instate; /* No use for this yet */ + (void)instate; if(imapcode != IMAP_RESP_OK) result = CURLE_UPLOAD_FAILED; @@ -1560,13 +1560,12 @@ static CURLcode imap_block_statemach(struct Curl_easy *data, } /* For the IMAP "protocol connect" and "doing" phases only */ -static int imap_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *socks) +static CURLcode imap_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct imap_conn *imapc = Curl_conn_meta_get(conn, CURL_META_IMAP_CONN); - return imapc ? - Curl_pp_getsock(data, &imapc->pp, socks) : GETSOCK_BLANK; + struct imap_conn *imapc = + Curl_conn_meta_get(data->conn, CURL_META_IMAP_CONN); + return imapc ? Curl_pp_pollset(data, &imapc->pp, ps) : CURLE_OK; } /*********************************************************************** diff --git a/deps/curl/lib/krb5.c b/deps/curl/lib/krb5.c index b5effa2a1b7..563d724bbbc 100644 --- a/deps/curl/lib/krb5.c +++ b/deps/curl/lib/krb5.c @@ -130,7 +130,7 @@ krb5_init(void *app_data) static int krb5_check_prot(void *app_data, int level) { - (void)app_data; /* unused */ + (void)app_data; if(level == PROT_CONFIDENTIAL) return -1; return 0; @@ -138,8 +138,7 @@ krb5_check_prot(void *app_data, int level) static int krb5_decode(void *app_data, void *buf, int len, - int level UNUSED_PARAM, - struct connectdata *conn UNUSED_PARAM) + int level, struct connectdata *conn) { gss_ctx_id_t *context = app_data; OM_uint32 maj, min; @@ -470,7 +469,7 @@ static int ftp_send_command(struct Curl_easy *data, const char *message, ...) ftp_code = -1; } - (void)nread; /* Unused */ + (void)nread; return ftp_code; } @@ -703,7 +702,7 @@ static CURLcode sec_send(struct Curl_easy *data, int sockindex, const void *buffer, size_t len, bool eos, size_t *pnwritten) { - (void)eos; /* unused */ + (void)eos; return sec_write(data, sockindex, buffer, len, pnwritten); } @@ -718,7 +717,7 @@ int Curl_sec_read_msg(struct Curl_easy *data, struct connectdata *conn, size_t decoded_sz = 0; CURLcode error; - (void) data; + (void)data; if(!conn->mech) /* not initialized, return error */ diff --git a/deps/curl/lib/ldap.c b/deps/curl/lib/ldap.c index 40e72af0d77..c66a56d7bb2 100644 --- a/deps/curl/lib/ldap.c +++ b/deps/curl/lib/ldap.c @@ -43,7 +43,7 @@ */ /* Wincrypt must be included before anything that could include OpenSSL. */ -#if defined(USE_WIN32_CRYPTO) +#ifdef USE_WIN32_CRYPTO #include /* Undefine wincrypt conflicting symbols for BoringSSL. */ #undef X509_NAME @@ -105,7 +105,7 @@ struct ldap_urldesc { char *lud_host; int lud_port; -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP TCHAR *lud_dn; TCHAR **lud_attrs; #else @@ -113,7 +113,7 @@ struct ldap_urldesc { char **lud_attrs; #endif int lud_scope; -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP TCHAR *lud_filter; #else char *lud_filter; @@ -177,10 +177,10 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -207,10 +207,10 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -224,9 +224,9 @@ const struct Curl_handler Curl_handler_ldaps = { }; #endif -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP -#if defined(USE_WINDOWS_SSPI) +#ifdef USE_WINDOWS_SSPI static int ldap_win_bind_auth(LDAP *server, const char *user, const char *passwd, unsigned long authflags) { @@ -236,19 +236,19 @@ static int ldap_win_bind_auth(LDAP *server, const char *user, memset(&cred, 0, sizeof(cred)); -#if defined(USE_SPNEGO) +#ifdef USE_SPNEGO if(authflags & CURLAUTH_NEGOTIATE) { method = LDAP_AUTH_NEGOTIATE; } else #endif -#if defined(USE_NTLM) +#ifdef USE_NTLM if(authflags & CURLAUTH_NTLM) { method = LDAP_AUTH_NTLM; } else #endif -#if !defined(CURL_DISABLE_DIGEST_AUTH) +#ifndef CURL_DISABLE_DIGEST_AUTH if(authflags & CURLAUTH_DIGEST) { method = LDAP_AUTH_DIGEST; } @@ -273,7 +273,7 @@ static int ldap_win_bind_auth(LDAP *server, const char *user, } return rc; } -#endif /* #if defined(USE_WINDOWS_SSPI) */ +#endif /* USE_WINDOWS_SSPI */ static int ldap_win_bind(struct Curl_easy *data, LDAP *server, const char *user, const char *passwd) @@ -292,7 +292,7 @@ static int ldap_win_bind(struct Curl_easy *data, LDAP *server, curlx_unicodefree(inuser); curlx_unicodefree(inpass); } -#if defined(USE_WINDOWS_SSPI) +#ifdef USE_WINDOWS_SSPI else { rc = (int)ldap_win_bind_auth(server, user, passwd, data->set.httpauth); } @@ -300,9 +300,9 @@ static int ldap_win_bind(struct Curl_easy *data, LDAP *server, return rc; } -#endif /* #if defined(USE_WIN32_LDAP) */ +#endif /* USE_WIN32_LDAP */ -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP #define FREE_ON_WINLDAP(x) curlx_unicodefree(x) #define curl_ldap_num_t ULONG #else @@ -328,13 +328,15 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #ifdef LDAP_OPT_NETWORK_TIMEOUT struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */ #endif -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP TCHAR *host = NULL; #else char *host = NULL; #endif char *user = NULL; char *passwd = NULL; + struct ip_quadruple ipquad; + bool is_ipv6; *done = TRUE; /* unconditionally */ infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d", @@ -352,13 +354,17 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } + result = Curl_conn_get_ip_info(data, conn, FIRSTSOCKET, &is_ipv6, &ipquad); + if(result) + goto quit; + /* Get the URL scheme (either ldap or ldaps) */ if(Curl_conn_is_ssl(conn, FIRSTSOCKET)) ldap_ssl = 1; infof(data, "LDAP local: trying to establish %s connection", ldap_ssl ? "encrypted" : "cleartext"); -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP host = curlx_convert_UTF8_to_tchar(conn->host.name); if(!host) { result = CURLE_OUT_OF_MEMORY; @@ -383,7 +389,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) #ifdef HAVE_LDAP_SSL #ifdef USE_WIN32_LDAP /* Win32 LDAP SDK does not support insecure mode without CA! */ - server = ldap_sslinit(host, (curl_ldap_num_t)conn->primary.remote_port, 1); + server = ldap_sslinit(host, (curl_ldap_num_t)ipquad.remote_port, 1); ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; @@ -422,10 +428,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldap_init(host, conn->primary.remote_port); + server = ldap_init(host, ipquad.remote_port); if(!server) { failf(data, "LDAP local: Cannot connect to %s:%u", - conn->host.dispname, conn->primary.remote_port); + conn->host.dispname, ipquad.remote_port); result = CURLE_COULDNT_CONNECT; goto quit; } @@ -465,10 +471,10 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) goto quit; } else { - server = ldap_init(host, (curl_ldap_num_t)conn->primary.remote_port); + server = ldap_init(host, (curl_ldap_num_t)ipquad.remote_port); if(!server) { failf(data, "LDAP local: Cannot connect to %s:%u", - conn->host.dispname, conn->primary.remote_port); + conn->host.dispname, ipquad.remote_port); result = CURLE_COULDNT_CONNECT; goto quit; } @@ -516,7 +522,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) entryIterator; entryIterator = ldap_next_entry(server, entryIterator), num++) { BerElement *ber = NULL; -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP TCHAR *attribute; #else char *attribute; @@ -527,7 +533,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) { char *name; size_t name_len; -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP TCHAR *dn = ldap_get_dn(server, entryIterator); name = curlx_convert_tchar_to_UTF8(dn); if(!name) { @@ -574,7 +580,7 @@ static CURLcode ldap_do(struct Curl_easy *data, bool *done) attribute = ldap_next_attribute(server, entryIterator, ber)) { BerValue **vals; size_t attr_len; -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP char *attr = curlx_convert_tchar_to_UTF8(attribute); if(!attr) { if(ber) @@ -837,7 +843,7 @@ static int _ldap_url_parse2(struct Curl_easy *data, goto quit; } -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP /* Convert the unescaped string to a tchar */ ludp->lud_dn = curlx_convert_UTF8_to_tchar(unescaped); @@ -868,7 +874,7 @@ static int _ldap_url_parse2(struct Curl_easy *data, const char *atp = p; /* Allocate our array (+1 for the NULL entry) */ -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *)); #else ludp->lud_attrs = calloc(count + 1, sizeof(char *)); @@ -896,7 +902,7 @@ static int _ldap_url_parse2(struct Curl_easy *data, goto quit; } -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP /* Convert the unescaped string to a tchar */ ludp->lud_attrs[i] = curlx_convert_UTF8_to_tchar(unescaped); @@ -960,7 +966,7 @@ static int _ldap_url_parse2(struct Curl_easy *data, goto quit; } -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP /* Convert the unescaped string to a tchar */ ludp->lud_filter = curlx_convert_UTF8_to_tchar(unescaped); @@ -1016,7 +1022,7 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp) if(!ludp) return; -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP curlx_unicodefree(ludp->lud_dn); curlx_unicodefree(ludp->lud_filter); #else @@ -1027,7 +1033,7 @@ static void _ldap_free_urldesc(LDAPURLDesc *ludp) if(ludp->lud_attrs) { size_t i; for(i = 0; i < ludp->lud_attrs_dups; i++) { -#if defined(USE_WIN32_LDAP) +#ifdef USE_WIN32_LDAP curlx_unicodefree(ludp->lud_attrs[i]); #else free(ludp->lud_attrs[i]); diff --git a/deps/curl/lib/libcurl.def b/deps/curl/lib/libcurl.def index 43e26f655c6..d2f5d8318f2 100644 --- a/deps/curl/lib/libcurl.def +++ b/deps/curl/lib/libcurl.def @@ -54,6 +54,7 @@ curl_multi_assign curl_multi_cleanup curl_multi_fdset curl_multi_get_handles +curl_multi_get_offt curl_multi_info_read curl_multi_init curl_multi_perform @@ -95,3 +96,4 @@ curl_version_info curl_ws_meta curl_ws_recv curl_ws_send +curl_ws_start_frame diff --git a/deps/curl/lib/md4.c b/deps/curl/lib/md4.c index a77085a6b28..b9c98d6c4ae 100644 --- a/deps/curl/lib/md4.c +++ b/deps/curl/lib/md4.c @@ -24,7 +24,7 @@ #include "curl_setup.h" -#if defined(USE_CURL_NTLM_CORE) +#ifdef USE_CURL_NTLM_CORE #include @@ -34,7 +34,7 @@ #ifdef USE_OPENSSL #include -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) && !defined(USE_AMISSL) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(USE_AMISSL) /* OpenSSL 3.0.0 marks the MD4 functions as deprecated */ #define OPENSSL_NO_MD4 #else @@ -53,21 +53,14 @@ #ifdef USE_MBEDTLS #include -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 -#include -#else -#include -#endif -#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \ - (MBEDTLS_VERSION_NUMBER < 0x03000000) - #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS +#if MBEDTLS_VERSION_NUMBER < 0x03020000 + #error "mbedTLS 3.2.0 or later required" #endif +#include #endif /* USE_MBEDTLS */ -#if defined(USE_GNUTLS) -#include /* When OpenSSL or wolfSSL is available, we use their MD4 functions. */ -#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4) +#if defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4) #include #elif defined(USE_OPENSSL) && !defined(OPENSSL_NO_MD4) #include @@ -83,6 +76,8 @@ #include #elif defined(USE_WIN32_CRYPTO) #include +#elif defined(USE_GNUTLS) +#include #elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C)) #include #endif @@ -93,27 +88,7 @@ #include "memdebug.h" -#if defined(USE_GNUTLS) - -typedef struct md4_ctx MD4_CTX; - -static int MD4_Init(MD4_CTX *ctx) -{ - md4_init(ctx); - return 1; -} - -static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) -{ - md4_update(ctx, size, data); -} - -static void MD4_Final(unsigned char *result, MD4_CTX *ctx) -{ - md4_digest(ctx, MD4_DIGEST_SIZE, result); -} - -#elif defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4) +#if defined(USE_WOLFSSL) && !defined(WOLFSSL_NO_MD4) #ifdef OPENSSL_COEXIST #define MD4_CTX WOLFSSL_MD4_CTX @@ -193,6 +168,26 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx) CryptReleaseContext(ctx->hCryptProv, 0); } +#elif defined(USE_GNUTLS) + +typedef struct md4_ctx MD4_CTX; + +static int MD4_Init(MD4_CTX *ctx) +{ + md4_init(ctx); + return 1; +} + +static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) +{ + md4_update(ctx, size, data); +} + +static void MD4_Final(unsigned char *result, MD4_CTX *ctx) +{ + md4_digest(ctx, MD4_DIGEST_SIZE, result); +} + #elif(defined(USE_MBEDTLS) && defined(MBEDTLS_MD4_C)) struct md4_ctx { @@ -220,12 +215,7 @@ static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size) static void MD4_Final(unsigned char *result, MD4_CTX *ctx) { if(ctx->data) { -#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) mbedtls_md4(ctx->data, ctx->size, result); -#else - (void) mbedtls_md4_ret(ctx->data, ctx->size, result); -#endif - Curl_safefree(ctx->data); ctx->size = 0; } diff --git a/deps/curl/lib/md5.c b/deps/curl/lib/md5.c index 6a273c56c0e..625670965a1 100644 --- a/deps/curl/lib/md5.c +++ b/deps/curl/lib/md5.c @@ -24,8 +24,8 @@ #include "curl_setup.h" -#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) \ - || !defined(CURL_DISABLE_DIGEST_AUTH) +#if (defined(USE_CURL_NTLM_CORE) && !defined(USE_WINDOWS_SSPI)) || \ + !defined(CURL_DISABLE_DIGEST_AUTH) #include #include @@ -36,10 +36,8 @@ #ifdef USE_MBEDTLS #include - -#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \ - (MBEDTLS_VERSION_NUMBER < 0x03000000) - #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS +#if MBEDTLS_VERSION_NUMBER < 0x03020000 + #error "mbedTLS 3.2.0 or later required" #endif #endif /* USE_MBEDTLS */ @@ -57,7 +55,7 @@ #endif #endif -#if defined(USE_GNUTLS) +#ifdef USE_GNUTLS #include #elif defined(USE_OPENSSL_MD5) #include @@ -84,7 +82,7 @@ #include "curl_memory.h" #include "memdebug.h" -#if defined(USE_GNUTLS) +#ifdef USE_GNUTLS typedef struct md5_ctx my_md5_ctx; @@ -161,15 +159,8 @@ typedef mbedtls_md5_context my_md5_ctx; static CURLcode my_md5_init(void *ctx) { -#if (MBEDTLS_VERSION_NUMBER >= 0x03000000) if(mbedtls_md5_starts(ctx)) return CURLE_OUT_OF_MEMORY; -#elif defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - if(mbedtls_md5_starts_ret(ctx)) - return CURLE_OUT_OF_MEMORY; -#else - (void)mbedtls_md5_starts(ctx); -#endif return CURLE_OK; } @@ -177,20 +168,12 @@ static void my_md5_update(void *ctx, const unsigned char *data, unsigned int length) { -#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - (void) mbedtls_md5_update(ctx, data, length); -#else - (void) mbedtls_md5_update_ret(ctx, data, length); -#endif + (void)mbedtls_md5_update(ctx, data, length); } static void my_md5_final(unsigned char *digest, void *ctx) { -#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - (void) mbedtls_md5_finish(ctx, digest); -#else - (void) mbedtls_md5_finish_ret(ctx, digest); -#endif + (void)mbedtls_md5_finish(ctx, digest); } #elif defined(AN_APPLE_OS) diff --git a/deps/curl/lib/memdebug.c b/deps/curl/lib/memdebug.c index bdcdcbb9074..c1121713ea3 100644 --- a/deps/curl/lib/memdebug.c +++ b/deps/curl/lib/memdebug.c @@ -356,7 +356,7 @@ int curl_dbg_socketpair(int domain, int type, int protocol, { int res = (socketpair)(domain, type, protocol, socket_vector); - if(source && (0 == res)) + if(source && (res == 0)) curl_dbg_log("FD %s:%d socketpair() = " "%" FMT_SOCKET_T " %" FMT_SOCKET_T "\n", source, line, socket_vector[0], socket_vector[1]); @@ -371,7 +371,7 @@ curl_socket_t curl_dbg_accept(curl_socket_t s, void *saddr, void *saddrlen, struct sockaddr *addr = (struct sockaddr *)saddr; curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; - curl_socket_t sockfd = (accept)(s, addr, addrlen); + curl_socket_t sockfd = accept(s, addr, addrlen); if(source && (sockfd != CURL_SOCKET_BAD)) curl_dbg_log("FD %s:%d accept() = %" FMT_SOCKET_T "\n", diff --git a/deps/curl/lib/memdebug.h b/deps/curl/lib/memdebug.h index 03b04b12dc2..30469b99a50 100644 --- a/deps/curl/lib/memdebug.h +++ b/deps/curl/lib/memdebug.h @@ -1,6 +1,5 @@ #ifndef HEADER_CURL_MEMDEBUG_H #define HEADER_CURL_MEMDEBUG_H -#ifdef CURLDEBUG /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -30,99 +29,7 @@ * as well as the library. Do not mix with library internals! */ -#include -#include "functypes.h" - -#ifdef __clang__ -# define ALLOC_FUNC __attribute__((__malloc__)) -# if __clang_major__ >= 4 -# define ALLOC_SIZE(s) __attribute__((__alloc_size__(s))) -# define ALLOC_SIZE2(n, s) __attribute__((__alloc_size__(n, s))) -# else -# define ALLOC_SIZE(s) -# define ALLOC_SIZE2(n, s) -# endif -#elif defined(__GNUC__) && __GNUC__ >= 3 -# define ALLOC_FUNC __attribute__((__malloc__)) -# define ALLOC_SIZE(s) __attribute__((__alloc_size__(s))) -# define ALLOC_SIZE2(n, s) __attribute__((__alloc_size__(n, s))) -#elif defined(_MSC_VER) -# define ALLOC_FUNC __declspec(restrict) -# define ALLOC_SIZE(s) -# define ALLOC_SIZE2(n, s) -#else -# define ALLOC_FUNC -# define ALLOC_SIZE(s) -# define ALLOC_SIZE2(n, s) -#endif - -/* Avoid redundant redeclaration warnings with modern compilers, when including - this header multiple times. */ -#ifndef HEADER_CURL_MEMDEBUG_H_EXTERNS -#define HEADER_CURL_MEMDEBUG_H_EXTERNS -extern FILE *curl_dbg_logfile; - -/* memory functions */ -CURL_EXTERN void curl_dbg_free(void *ptr, int line, const char *source); -CURL_EXTERN ALLOC_FUNC ALLOC_SIZE(1) - void *curl_dbg_malloc(size_t size, int line, const char *source); -CURL_EXTERN ALLOC_FUNC ALLOC_SIZE2(1, 2) - void *curl_dbg_calloc(size_t n, size_t size, int line, const char *source); -CURL_EXTERN ALLOC_SIZE(2) - void *curl_dbg_realloc(void *ptr, size_t size, int line, const char *source); -CURL_EXTERN ALLOC_FUNC - char *curl_dbg_strdup(const char *str, int line, const char *src); -#if defined(_WIN32) && defined(UNICODE) -CURL_EXTERN ALLOC_FUNC - wchar_t *curl_dbg_wcsdup(const wchar_t *str, int line, const char *source); -#endif - -CURL_EXTERN void curl_dbg_memdebug(const char *logname); -CURL_EXTERN void curl_dbg_memlimit(long limit); -CURL_EXTERN void curl_dbg_log(const char *format, ...) CURL_PRINTF(1, 2); - -/* file descriptor manipulators */ -CURL_EXTERN curl_socket_t curl_dbg_socket(int domain, int type, int protocol, - int line, const char *source); -CURL_EXTERN void curl_dbg_mark_sclose(curl_socket_t sockfd, - int line, const char *source); -CURL_EXTERN int curl_dbg_sclose(curl_socket_t sockfd, - int line, const char *source); -CURL_EXTERN curl_socket_t curl_dbg_accept(curl_socket_t s, void *a, void *alen, - int line, const char *source); -#ifdef HAVE_ACCEPT4 -CURL_EXTERN curl_socket_t curl_dbg_accept4(curl_socket_t s, void *saddr, - void *saddrlen, int flags, - int line, const char *source); -#endif -#ifdef HAVE_SOCKETPAIR -CURL_EXTERN int curl_dbg_socketpair(int domain, int type, int protocol, - curl_socket_t socket_vector[2], - int line, const char *source); -#endif - -/* send/receive sockets */ -CURL_EXTERN SEND_TYPE_RETV curl_dbg_send(SEND_TYPE_ARG1 sockfd, - SEND_QUAL_ARG2 SEND_TYPE_ARG2 buf, - SEND_TYPE_ARG3 len, - SEND_TYPE_ARG4 flags, int line, - const char *source); -CURL_EXTERN RECV_TYPE_RETV curl_dbg_recv(RECV_TYPE_ARG1 sockfd, - RECV_TYPE_ARG2 buf, - RECV_TYPE_ARG3 len, - RECV_TYPE_ARG4 flags, int line, - const char *source); - -/* FILE functions */ -CURL_EXTERN int curl_dbg_fclose(FILE *file, int line, const char *source); -CURL_EXTERN ALLOC_FUNC - FILE *curl_dbg_fopen(const char *file, const char *mode, - int line, const char *source); -CURL_EXTERN ALLOC_FUNC - FILE *curl_dbg_fdopen(int filedes, const char *mode, - int line, const char *source); - -#endif /* HEADER_CURL_MEMDEBUG_H_EXTERNS */ +#ifdef CURLDEBUG /* Set this symbol on the command-line, recompile all lib-sources */ #undef strdup @@ -152,9 +59,6 @@ CURL_EXTERN ALLOC_FUNC #undef socket #define socket(domain,type,protocol) \ curl_dbg_socket((int)domain, type, protocol, __LINE__, __FILE__) -#undef accept /* for those with accept as a macro */ -#define accept(sock,addr,len) \ - curl_dbg_accept(sock, addr, len, __LINE__, __FILE__) #ifdef HAVE_ACCEPT4 #undef accept4 /* for those with accept4 as a macro */ #define accept4(sock,addr,len,flags) \ @@ -166,12 +70,6 @@ CURL_EXTERN ALLOC_FUNC __LINE__, __FILE__) #endif -/* sclose is probably already defined, redefine it! */ -#undef sclose -#define sclose(sockfd) curl_dbg_sclose(sockfd,__LINE__,__FILE__) - -#define fake_sclose(sockfd) curl_dbg_mark_sclose(sockfd,__LINE__,__FILE__) - #undef fopen #define fopen(file,mode) curl_dbg_fopen(file,mode,__LINE__,__FILE__) #undef fdopen @@ -180,22 +78,4 @@ CURL_EXTERN ALLOC_FUNC #define fclose(file) curl_dbg_fclose(file,__LINE__,__FILE__) #endif /* CURLDEBUG */ - -/* -** Following section applies even when CURLDEBUG is not defined. -*/ - -#ifndef fake_sclose -#define fake_sclose(x) Curl_nop_stmt -#endif - -/* - * Curl_safefree defined as a macro to allow MemoryTracking feature - * to log free() calls at same location where Curl_safefree is used. - * This macro also assigns NULL to given pointer when free'd. - */ - -#define Curl_safefree(ptr) \ - do { free((ptr)); (ptr) = NULL;} while(0) - #endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/deps/curl/lib/mime.c b/deps/curl/lib/mime.c index 06cd221abfc..894413be17f 100644 --- a/deps/curl/lib/mime.c +++ b/deps/curl/lib/mime.c @@ -36,9 +36,10 @@ struct Curl_easy; #include "strdup.h" #include "curlx/base64.h" -#if !defined(CURL_DISABLE_MIME) && (!defined(CURL_DISABLE_HTTP) || \ - !defined(CURL_DISABLE_SMTP) || \ - !defined(CURL_DISABLE_IMAP)) +#if !defined(CURL_DISABLE_MIME) && \ + (!defined(CURL_DISABLE_HTTP) || \ + !defined(CURL_DISABLE_SMTP) || \ + !defined(CURL_DISABLE_IMAP)) #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include @@ -53,14 +54,13 @@ struct Curl_easy; #include "memdebug.h" #ifdef _WIN32 -# ifndef R_OK +# ifndef R_OK # define R_OK 4 -# endif +# endif #endif - -#define READ_ERROR ((size_t) -1) -#define STOP_FILLING ((size_t) -2) +#define READ_ERROR ((size_t) -1) +#define STOP_FILLING ((size_t) -2) static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, void *instream, bool *hasread); @@ -97,30 +97,30 @@ static const struct mime_encoder encoders[] = { #define QP_CR 3 /* Carriage return. */ #define QP_LF 4 /* Line-feed. */ static const unsigned char qp_class[] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */ - 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */ - QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */ - QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */ + 0, QP_SP, QP_LF, 0, 0, QP_CR, 0, 0, /* 08 - 0F */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 18 - 1F */ + QP_SP, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 20 - 27 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 28 - 2F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 30 - 37 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0 , QP_OK, QP_OK, /* 38 - 3F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 40 - 47 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 48 - 4F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 50 - 57 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 58 - 5F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 60 - 67 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 68 - 6F */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, /* 70 - 77 */ + QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, QP_OK, 0, /* 78 - 7F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 80 - 8F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 90 - 9F */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* A0 - AF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* B0 - BF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* C0 - CF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* D0 - DF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* E0 - EF */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */ }; @@ -129,7 +129,6 @@ static const char aschex[] = "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x41\x42\x43\x44\x45\x46"; - #ifndef __VMS #define filesize(name, stat_data) (stat_data.st_size) #define fopen_read fopen @@ -384,7 +383,7 @@ static size_t encoder_nop_read(char *buffer, size_t size, bool ateof, struct mime_encoder_state *st = &part->encstate; size_t insize = st->bufend - st->bufbeg; - (void) ateof; + (void)ateof; if(!size) return STOP_FILLING; @@ -412,7 +411,7 @@ static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof, struct mime_encoder_state *st = &part->encstate; size_t cursize = st->bufend - st->bufbeg; - (void) ateof; + (void)ateof; if(!size) return STOP_FILLING; @@ -661,7 +660,7 @@ static size_t mime_mem_read(char *buffer, size_t size, size_t nitems, { curl_mimepart *part = (curl_mimepart *) instream; size_t sz = curlx_sotouz(part->datasize - part->state.offset); - (void) size; /* Always 1.*/ + (void)size; /* Always 1 */ if(!nitems) return STOP_FILLING; @@ -1000,7 +999,7 @@ static size_t mime_subparts_read(char *buffer, size_t size, size_t nitems, { curl_mime *mime = (curl_mime *) instream; size_t cursize = 0; - (void) size; /* Always 1. */ + (void)size; /* Always 1 */ while(nitems) { size_t sz = 0; @@ -1593,7 +1592,7 @@ size_t Curl_mime_read(char *buffer, size_t size, size_t nitems, void *instream) size_t ret; bool hasread; - (void) size; /* Always 1. */ + (void)size; /* Always 1 */ /* If `nitems` is <= 4, some encoders will return STOP_FILLING without * adding any data and this loops infinitely. */ @@ -2150,22 +2149,27 @@ static CURLcode cr_mime_resume_from(struct Curl_easy *data, return CURLE_OK; } -static CURLcode cr_mime_rewind(struct Curl_easy *data, - struct Curl_creader *reader) +static CURLcode cr_mime_cntrl(struct Curl_easy *data, + struct Curl_creader *reader, + Curl_creader_cntrl opcode) { struct cr_mime_ctx *ctx = reader->ctx; - CURLcode result = mime_rewind(ctx->part); - if(result) - failf(data, "Cannot rewind mime/post data"); - return result; -} - -static CURLcode cr_mime_unpause(struct Curl_easy *data, - struct Curl_creader *reader) -{ - struct cr_mime_ctx *ctx = reader->ctx; - (void)data; - mime_unpause(ctx->part); + switch(opcode) { + case CURL_CRCNTRL_REWIND: { + CURLcode result = mime_rewind(ctx->part); + if(result) + failf(data, "Cannot rewind mime/post data"); + return result; + } + case CURL_CRCNTRL_UNPAUSE: + mime_unpause(ctx->part); + break; + case CURL_CRCNTRL_CLEAR_EOS: + ctx->seen_eos = FALSE; + break; + default: + break; + } return CURLE_OK; } @@ -2185,8 +2189,7 @@ static const struct Curl_crtype cr_mime = { cr_mime_needs_rewind, cr_mime_total_length, cr_mime_resume_from, - cr_mime_rewind, - cr_mime_unpause, + cr_mime_cntrl, cr_mime_is_paused, Curl_creader_def_done, sizeof(struct cr_mime_ctx) @@ -2220,62 +2223,62 @@ CURLcode Curl_creader_set_mime(struct Curl_easy *data, curl_mimepart *part) /* Mime not compiled in: define stubs for externally-referenced functions. */ curl_mime *curl_mime_init(CURL *easy) { - (void) easy; + (void)easy; return NULL; } void curl_mime_free(curl_mime *mime) { - (void) mime; + (void)mime; } curl_mimepart *curl_mime_addpart(curl_mime *mime) { - (void) mime; + (void)mime; return NULL; } CURLcode curl_mime_name(curl_mimepart *part, const char *name) { - (void) part; - (void) name; + (void)part; + (void)name; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_filename(curl_mimepart *part, const char *filename) { - (void) part; - (void) filename; + (void)part; + (void)filename; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype) { - (void) part; - (void) mimetype; + (void)part; + (void)mimetype; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding) { - (void) part; - (void) encoding; + (void)part; + (void)encoding; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_data(curl_mimepart *part, const char *data, size_t datasize) { - (void) part; - (void) data; - (void) datasize; + (void)part; + (void)data; + (void)datasize; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_filedata(curl_mimepart *part, const char *filename) { - (void) part; - (void) filename; + (void)part; + (void)filename; return CURLE_NOT_BUILT_IN; } @@ -2286,28 +2289,28 @@ CURLcode curl_mime_data_cb(curl_mimepart *part, curl_free_callback freefunc, void *arg) { - (void) part; - (void) datasize; - (void) readfunc; - (void) seekfunc; - (void) freefunc; - (void) arg; + (void)part; + (void)datasize; + (void)readfunc; + (void)seekfunc; + (void)freefunc; + (void)arg; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_subparts(curl_mimepart *part, curl_mime *subparts) { - (void) part; - (void) subparts; + (void)part; + (void)subparts; return CURLE_NOT_BUILT_IN; } CURLcode curl_mime_headers(curl_mimepart *part, struct curl_slist *headers, int take_ownership) { - (void) part; - (void) headers; - (void) take_ownership; + (void)part; + (void)headers; + (void)take_ownership; return CURLE_NOT_BUILT_IN; } diff --git a/deps/curl/lib/mqtt.c b/deps/curl/lib/mqtt.c index 90f857dca56..35afe012075 100644 --- a/deps/curl/lib/mqtt.c +++ b/deps/curl/lib/mqtt.c @@ -107,8 +107,8 @@ static CURLcode mqtt_do(struct Curl_easy *data, bool *done); static CURLcode mqtt_done(struct Curl_easy *data, CURLcode status, bool premature); static CURLcode mqtt_doing(struct Curl_easy *data, bool *done); -static int mqtt_getsock(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *sock); +static CURLcode mqtt_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode mqtt_setup_conn(struct Curl_easy *data, struct connectdata *conn); @@ -125,10 +125,10 @@ const struct Curl_handler Curl_handler_mqtt = { ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ mqtt_doing, /* doing */ - ZERO_NULL, /* proto_getsock */ - mqtt_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + mqtt_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -213,13 +213,10 @@ static CURLcode mqtt_send(struct Curl_easy *data, /* 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 Curl_easy *data, - struct connectdata *conn, - curl_socket_t *sock) +static CURLcode mqtt_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - (void)data; - sock[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_READSOCK(FIRSTSOCKET); + return Curl_pollset_add_in(data, ps, data->conn->sock[FIRSTSOCKET]); } static int mqtt_encode_len(char *buf, size_t len) diff --git a/deps/curl/lib/multi.c b/deps/curl/lib/multi.c index b3a7938e33f..918928d03cc 100644 --- a/deps/curl/lib/multi.c +++ b/deps/curl/lib/multi.c @@ -465,22 +465,6 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d) is called. */ data->multi = multi; - /* Set the timeout for this handle to expire really soon so that it will - be taken care of even when this handle is added in the midst of operation - when only the curl_multi_socket() API is used. During that flow, only - sockets that time-out or have actions will be dealt with. Since this - handle has no action yet, we make sure it times out to get things to - happen. */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); - - rc = Curl_update_timer(multi); - if(rc) { - data->multi = NULL; /* not anymore */ - Curl_uint_tbl_remove(&multi->xfers, data->mid); - data->mid = UINT_MAX; - return rc; - } - /* set the easy handle */ multistate(data, MSTATE_INIT); @@ -495,10 +479,23 @@ CURLMcode curl_multi_add_handle(CURLM *m, CURL *d) /* add the easy handle to the process set */ Curl_uint_bset_add(&multi->process, data->mid); ++multi->xfers_alive; + ++multi->xfers_total_ever; Curl_cpool_xfer_init(data); multi_warn_debug(multi, data); + /* Make sure the new handle will run */ + Curl_multi_mark_dirty(data); + /* Necessary in event based processing, where dirty handles trigger + * a timeout callback invocation. */ + rc = Curl_update_timer(multi); + if(rc) { + data->multi = NULL; /* not anymore */ + Curl_uint_tbl_remove(&multi->xfers, data->mid); + data->mid = UINT_MAX; + return rc; + } + /* The admin handle only ever has default timeouts set. To improve the state somewhat we clone the timeouts from each added handle so that the admin handle always has the same timeouts as the most recently added @@ -539,6 +536,22 @@ static void multi_done_locked(struct connectdata *conn, void *userdata) { struct multi_done_ctx *mdctx = userdata; +#ifndef CURL_DISABLE_VERBOSE_STRINGS + const char *host = +#ifndef CURL_DISABLE_PROXY + conn->bits.socksproxy ? + conn->socks_proxy.host.dispname : + conn->bits.httpproxy ? conn->http_proxy.host.dispname : +#endif + conn->bits.conn_to_host ? conn->conn_to_host.dispname : + conn->host.dispname; + int port = +#ifndef CURL_DISABLE_PROXY + conn->bits.httpproxy ? conn->http_proxy.port : +#endif + conn->bits.conn_to_port ? conn->conn_to_port : + conn->remote_port; +#endif Curl_detach_connection(data); @@ -574,40 +587,43 @@ static void multi_done_locked(struct connectdata *conn, */ if((data->set.reuse_forbid -#if defined(USE_NTLM) +#ifdef USE_NTLM && !(conn->http_ntlm_state == NTLMSTATE_TYPE2 || conn->proxy_ntlm_state == NTLMSTATE_TYPE2) #endif -#if defined(USE_SPNEGO) +#ifdef USE_SPNEGO && !(conn->http_negotiate_state == GSS_AUTHRECV || conn->proxy_negotiate_state == GSS_AUTHRECV) #endif ) || conn->bits.close || (mdctx->premature && !Curl_conn_is_multiplex(conn, FIRSTSOCKET))) { - CURL_TRC_M(data, "multi_done, not reusing connection=%" - FMT_OFF_T ", forbid=%d" - ", close=%d, premature=%d, conn_multiplex=%d", - conn->connection_id, data->set.reuse_forbid, - conn->bits.close, mdctx->premature, - Curl_conn_is_multiplex(conn, FIRSTSOCKET)); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + CURL_TRC_M(data, "multi_done, terminating conn #%" FMT_OFF_T " to %s:%d, " + "forbid=%d, close=%d, premature=%d, conn_multiplex=%d", + conn->connection_id, host, port, data->set.reuse_forbid, + conn->bits.close, mdctx->premature, + Curl_conn_is_multiplex(conn, FIRSTSOCKET)); +#endif connclose(conn, "disconnecting"); Curl_conn_terminate(data, conn, mdctx->premature); } + else if(!Curl_conn_get_max_concurrent(data, conn, FIRSTSOCKET)) { +#ifndef CURL_DISABLE_VERBOSE_STRINGS + CURL_TRC_M(data, "multi_done, conn #%" FMT_OFF_T " to %s:%d was shutdown" + " by server, not reusing", conn->connection_id, host, port); +#endif + connclose(conn, "server shutdown"); + Curl_conn_terminate(data, conn, mdctx->premature); + } else { /* the connection is no longer in use by any transfer */ if(Curl_cpool_conn_now_idle(data, conn)) { /* connection kept in the cpool */ - const char *host = -#ifndef CURL_DISABLE_PROXY - conn->bits.socksproxy ? - conn->socks_proxy.host.dispname : - conn->bits.httpproxy ? conn->http_proxy.host.dispname : -#endif - conn->bits.conn_to_host ? conn->conn_to_host.dispname : - conn->host.dispname; data->state.lastconnect_id = conn->connection_id; - infof(data, "Connection #%" FMT_OFF_T " to host %s left intact", - conn->connection_id, host); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + infof(data, "Connection #%" FMT_OFF_T " to host %s:%d left intact", + conn->connection_id, host, port); +#endif } else { /* connection was removed from the cpool and destroyed. */ @@ -892,118 +908,105 @@ void Curl_attach_connection(struct Curl_easy *data, conn->handler->attach(data, conn); } -static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks) +static CURLcode mstate_connecting_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct connectdata *conn = data->conn; - curl_socket_t sockfd; - - if(!conn) - return GETSOCK_BLANK; - sockfd = Curl_conn_get_socket(data, FIRSTSOCKET); - if(sockfd != CURL_SOCKET_BAD) { - /* Default is to wait to something from the server */ - socks[0] = sockfd; - return GETSOCK_READSOCK(0); + if(data->conn) { + curl_socket_t sockfd = Curl_conn_get_first_socket(data); + if(sockfd != CURL_SOCKET_BAD) { + /* Default is to wait to something from the server */ + return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0); + } } - return GETSOCK_BLANK; + return CURLE_OK; } -static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks) +static CURLcode mstate_protocol_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct connectdata *conn = data->conn; - curl_socket_t sockfd; - - if(!conn) - return GETSOCK_BLANK; - if(conn->handler->proto_getsock) - return conn->handler->proto_getsock(data, conn, socks); - sockfd = Curl_conn_get_socket(data, FIRSTSOCKET); - if(sockfd != CURL_SOCKET_BAD) { - /* Default is to wait to something from the server */ - socks[0] = sockfd; - return GETSOCK_READSOCK(0); + if(data->conn) { + curl_socket_t sockfd; + if(data->conn->handler->proto_pollset) + return data->conn->handler->proto_pollset(data, ps); + sockfd = data->conn->sock[FIRSTSOCKET]; + if(sockfd != CURL_SOCKET_BAD) { + /* Default is to wait to something from the server */ + return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0); + } } - return GETSOCK_BLANK; + return CURLE_OK; } -static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks) +static CURLcode mstate_do_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct connectdata *conn = data->conn; - if(!conn) - return GETSOCK_BLANK; - if(conn->handler->domore_getsock) - return conn->handler->domore_getsock(data, conn, socks); - else if(conn->sockfd != CURL_SOCKET_BAD) { - /* Default is that we want to send something to the server */ - socks[0] = conn->sockfd; - return GETSOCK_WRITESOCK(0); + if(data->conn) { + if(data->conn->handler->doing_pollset) + return data->conn->handler->doing_pollset(data, ps); + else if(CONN_SOCK_IDX_VALID(data->conn->send_idx)) { + /* Default is that we want to send something to the server */ + return Curl_pollset_add_out( + data, ps, data->conn->sock[data->conn->send_idx]); + } } - return GETSOCK_BLANK; + return CURLE_OK; } -static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks) +static CURLcode mstate_domore_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct connectdata *conn = data->conn; - if(!conn) - return GETSOCK_BLANK; - if(conn->handler->doing_getsock) - return conn->handler->doing_getsock(data, conn, socks); - else if(conn->sockfd != CURL_SOCKET_BAD) { - /* Default is that we want to send something to the server */ - socks[0] = conn->sockfd; - return GETSOCK_WRITESOCK(0); + if(data->conn) { + if(data->conn->handler->domore_pollset) + return data->conn->handler->domore_pollset(data, ps); + else if(CONN_SOCK_IDX_VALID(data->conn->send_idx)) { + /* Default is that we want to send something to the server */ + return Curl_pollset_add_out( + data, ps, data->conn->sock[data->conn->send_idx]); + } } - return GETSOCK_BLANK; + return CURLE_OK; } -static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock) +static CURLcode mstate_perform_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct connectdata *conn = data->conn; - if(!conn) - return GETSOCK_BLANK; - else if(conn->handler->perform_getsock) - return conn->handler->perform_getsock(data, conn, sock); + if(!data->conn) + return CURLE_OK; + else if(data->conn->handler->perform_pollset) + return data->conn->handler->perform_pollset(data, ps); else { /* Default is to obey the data->req.keepon flags for send/recv */ - int bitmap = GETSOCK_BLANK; - unsigned sockindex = 0; - if(CURL_WANT_RECV(data)) { - DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD); - bitmap |= GETSOCK_READSOCK(sockindex); - sock[sockindex] = conn->sockfd; - } - - if(Curl_req_want_send(data)) { - if((conn->sockfd != conn->writesockfd) || - bitmap == GETSOCK_BLANK) { - /* only if they are not the same socket and we have a readable - one, we increase index */ - if(bitmap != GETSOCK_BLANK) - sockindex++; /* increase index if we need two entries */ - - DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD); - sock[sockindex] = conn->writesockfd; - } - bitmap |= GETSOCK_WRITESOCK(sockindex); + CURLcode result = CURLE_OK; + if(CURL_WANT_RECV(data) && CONN_SOCK_IDX_VALID(data->conn->recv_idx)) { + result = Curl_pollset_add_in( + data, ps, data->conn->sock[data->conn->recv_idx]); + } + + if(!result && Curl_req_want_send(data) && + CONN_SOCK_IDX_VALID(data->conn->send_idx)) { + result = Curl_pollset_add_out( + data, ps, data->conn->sock[data->conn->send_idx]); } - return bitmap; + return result; } } /* Initializes `poll_set` with the current socket poll actions needed * for transfer `data`. */ -void Curl_multi_getsock(struct Curl_easy *data, - struct easy_pollset *ps, - const char *caller) +CURLMcode Curl_multi_pollset(struct Curl_easy *data, + struct easy_pollset *ps, + const char *caller) { + CURLMcode mresult = CURLM_OK; + CURLcode result = CURLE_OK; bool expect_sockets = TRUE; /* If the transfer has no connection, this is fine. Happens when called via curl_multi_remove_handle() => Curl_multi_ev_assess() => - Curl_multi_getsock(). */ - Curl_pollset_reset(data, ps); + Curl_multi_pollset(). */ + Curl_pollset_reset(ps); if(!data->conn) - return; + return CURLM_OK; switch(data->mstate) { case MSTATE_INIT: @@ -1015,7 +1018,7 @@ void Curl_multi_getsock(struct Curl_easy *data, break; case MSTATE_RESOLVING: - Curl_pollset_add_socks(data, ps, Curl_resolv_getsock); + result = Curl_resolv_pollset(data, ps); /* connection filters are not involved in this phase. It's ok if we get no * sockets to wait for. Resolving can wake up from other sources. */ expect_sockets = FALSE; @@ -1023,31 +1026,40 @@ void Curl_multi_getsock(struct Curl_easy *data, case MSTATE_CONNECTING: case MSTATE_TUNNELING: - Curl_pollset_add_socks(data, ps, connecting_getsock); - Curl_conn_adjust_pollset(data, data->conn, ps); + if(!Curl_xfer_recv_is_paused(data)) { + result = mstate_connecting_pollset(data, ps); + if(!result) + result = Curl_conn_adjust_pollset(data, data->conn, ps); + } + else + expect_sockets = FALSE; break; case MSTATE_PROTOCONNECT: case MSTATE_PROTOCONNECTING: - Curl_pollset_add_socks(data, ps, protocol_getsock); - Curl_conn_adjust_pollset(data, data->conn, ps); + result = mstate_protocol_pollset(data, ps); + if(!result) + result = Curl_conn_adjust_pollset(data, data->conn, ps); break; case MSTATE_DO: case MSTATE_DOING: - Curl_pollset_add_socks(data, ps, doing_getsock); - Curl_conn_adjust_pollset(data, data->conn, ps); + result = mstate_do_pollset(data, ps); + if(!result) + result = Curl_conn_adjust_pollset(data, data->conn, ps); break; case MSTATE_DOING_MORE: - Curl_pollset_add_socks(data, ps, domore_getsock); - Curl_conn_adjust_pollset(data, data->conn, ps); + result = mstate_domore_pollset(data, ps); + if(!result) + result = Curl_conn_adjust_pollset(data, data->conn, ps); break; case MSTATE_DID: /* same as PERFORMING in regard to polling */ case MSTATE_PERFORMING: - Curl_pollset_add_socks(data, ps, perform_getsock); - Curl_conn_adjust_pollset(data, data->conn, ps); + result = mstate_perform_pollset(data, ps); + if(!result) + result = Curl_conn_adjust_pollset(data, data->conn, ps); break; case MSTATE_RATELIMITING: @@ -1069,10 +1081,19 @@ void Curl_multi_getsock(struct Curl_easy *data, break; } + if(result) { + if(result == CURLE_OUT_OF_MEMORY) + mresult = CURLM_OUT_OF_MEMORY; + else { + failf(data, "error determining pollset: %d", result); + mresult = CURLM_INTERNAL_ERROR; + } + goto out; + } /* Unblocked and waiting to receive with buffered input. * Make transfer run again at next opportunity. */ - if(!Curl_xfer_is_blocked(data) && + if(!Curl_xfer_is_blocked(data) && !Curl_xfer_is_too_fast(data) && ((Curl_pollset_want_read(data, ps, data->conn->sock[FIRSTSOCKET]) && Curl_conn_data_pending(data, FIRSTSOCKET)) || (Curl_pollset_want_read(data, ps, data->conn->sock[SECONDARYSOCKET]) && @@ -1082,47 +1103,56 @@ void Curl_multi_getsock(struct Curl_easy *data, Curl_multi_mark_dirty(data); } - switch(ps->num) { - case 0: - CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)", - caller, Curl_llist_count(&data->state.timeoutlist), - Curl_xfer_send_is_paused(data), - Curl_xfer_recv_is_paused(data)); - break; - case 1: - CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu", - caller, ps->sockets[0], - (ps->actions[0] & CURL_POLL_IN) ? "IN" : "", - (ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "", - Curl_llist_count(&data->state.timeoutlist)); - break; - case 2: - CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s, " - "fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu", - caller, ps->sockets[0], - (ps->actions[0] & CURL_POLL_IN) ? "IN" : "", - (ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "", - ps->sockets[1], - (ps->actions[1] & CURL_POLL_IN) ? "IN" : "", - (ps->actions[1] & CURL_POLL_OUT) ? "OUT" : "", - Curl_llist_count(&data->state.timeoutlist)); - break; - default: - CURL_TRC_M(data, "%s pollset[fds=%u], timeouts=%zu", - caller, ps->num, Curl_llist_count(&data->state.timeoutlist)); - break; + if(CURL_TRC_M_is_verbose(data)) { + size_t timeout_count = Curl_llist_count(&data->state.timeoutlist); + switch(ps->n) { + case 0: + CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)", + caller, timeout_count, + Curl_xfer_send_is_paused(data), + Curl_xfer_recv_is_paused(data)); + break; + case 1: + CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu", + caller, ps->sockets[0], + (ps->actions[0] & CURL_POLL_IN) ? "IN" : "", + (ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "", + timeout_count); + break; + case 2: + CURL_TRC_M(data, "%s pollset[fd=%" FMT_SOCKET_T " %s%s, " + "fd=%" FMT_SOCKET_T " %s%s], timeouts=%zu", + caller, ps->sockets[0], + (ps->actions[0] & CURL_POLL_IN) ? "IN" : "", + (ps->actions[0] & CURL_POLL_OUT) ? "OUT" : "", + ps->sockets[1], + (ps->actions[1] & CURL_POLL_IN) ? "IN" : "", + (ps->actions[1] & CURL_POLL_OUT) ? "OUT" : "", + timeout_count); + break; + default: + CURL_TRC_M(data, "%s pollset[fds=%u], timeouts=%zu", + caller, ps->n, timeout_count); + break; + } + CURL_TRC_M_TIMEOUTS(data); } - if(expect_sockets && !ps->num && + + if(expect_sockets && !ps->n && data->multi && + !Curl_uint_bset_contains(&data->multi->dirty, data->mid) && !Curl_llist_count(&data->state.timeoutlist) && !Curl_cwriter_is_paused(data) && !Curl_creader_is_paused(data) && Curl_conn_is_ip_connected(data, FIRSTSOCKET)) { /* We expected sockets for POLL monitoring, but none are set. + * We are not dirty (and run anyway). * We are not waiting on any timer. * None of the READ/WRITE directions are paused. * We are connected to the server on IP level, at least. */ infof(data, "WARNING: no socket in pollset or timer, transfer may stall!"); DEBUGASSERT(0); } +out: + return mresult; } CURLMcode curl_multi_fdset(CURLM *m, @@ -1134,8 +1164,9 @@ CURLMcode curl_multi_fdset(CURLM *m, and then we must make sure that is done. */ int this_max_fd = -1; struct Curl_multi *multi = m; + struct easy_pollset ps; unsigned int i, mid; - (void)exc_fd_set; /* not used */ + (void)exc_fd_set; if(!GOOD_MULTI_HANDLE(multi)) return CURLM_BAD_HANDLE; @@ -1143,22 +1174,22 @@ CURLMcode curl_multi_fdset(CURLM *m, if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + Curl_pollset_init(&ps); if(Curl_uint_bset_first(&multi->process, &mid)) { do { struct Curl_easy *data = Curl_multi_get_easy(multi, mid); - struct easy_pollset ps; if(!data) { DEBUGASSERT(0); continue; } - Curl_multi_getsock(data, &ps, "curl_multi_fdset"); - for(i = 0; i < ps.num; i++) { + Curl_multi_pollset(data, &ps, "curl_multi_fdset"); + for(i = 0; i < ps.n; i++) { if(!FDSET_SOCK(ps.sockets[i])) /* pretend it does not exist */ continue; -#if defined(__DJGPP__) +#ifdef __DJGPP__ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warith-conversion" #endif @@ -1166,7 +1197,7 @@ CURLMcode curl_multi_fdset(CURLM *m, FD_SET(ps.sockets[i], read_fd_set); if(ps.actions[i] & CURL_POLL_OUT) FD_SET(ps.sockets[i], write_fd_set); -#if defined(__DJGPP__) +#ifdef __DJGPP__ #pragma GCC diagnostic pop #endif if((int)ps.sockets[i] > this_max_fd) @@ -1180,6 +1211,7 @@ CURLMcode curl_multi_fdset(CURLM *m, read_fd_set, write_fd_set, &this_max_fd); *max_fd = this_max_fd; + Curl_pollset_cleanup(&ps); return CURLM_OK; } @@ -1192,6 +1224,7 @@ CURLMcode curl_multi_waitfds(CURLM *m, struct Curl_waitfds cwfds; CURLMcode result = CURLM_OK; struct Curl_multi *multi = m; + struct easy_pollset ps; unsigned int need = 0, mid; if(!ufds && (size || !fd_count)) @@ -1203,18 +1236,18 @@ CURLMcode curl_multi_waitfds(CURLM *m, if(multi->in_callback) return CURLM_RECURSIVE_API_CALL; + Curl_pollset_init(&ps); Curl_waitfds_init(&cwfds, ufds, size); if(Curl_uint_bset_first(&multi->process, &mid)) { do { struct Curl_easy *data = Curl_multi_get_easy(multi, mid); - struct easy_pollset ps; if(!data) { DEBUGASSERT(0); Curl_uint_bset_remove(&multi->process, mid); Curl_uint_bset_remove(&multi->dirty, mid); continue; } - Curl_multi_getsock(data, &ps, "curl_multi_waitfds"); + Curl_multi_pollset(data, &ps, "curl_multi_waitfds"); need += Curl_waitfds_add_ps(&cwfds, &ps); } while(Curl_uint_bset_next(&multi->process, mid, &mid)); @@ -1228,6 +1261,7 @@ CURLMcode curl_multi_waitfds(CURLM *m, if(fd_count) *fd_count = need; + Curl_pollset_cleanup(&ps); return result; } @@ -1261,6 +1295,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, struct curltime expire_time; long timeout_internal; int retcode = 0; + struct easy_pollset ps; struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK]; struct curl_pollfds cpfds; unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */ @@ -1285,12 +1320,12 @@ static CURLMcode multi_wait(struct Curl_multi *multi, if(timeout_ms < 0) return CURLM_BAD_FUNCTION_ARGUMENT; + Curl_pollset_init(&ps); Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK); /* Add the curl handles to our pollfds first */ if(Curl_uint_bset_first(&multi->process, &mid)) { do { - struct easy_pollset ps; data = Curl_multi_get_easy(multi, mid); if(!data) { DEBUGASSERT(0); @@ -1298,7 +1333,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, Curl_uint_bset_remove(&multi->dirty, mid); continue; } - Curl_multi_getsock(data, &ps, "multi_wait"); + Curl_multi_pollset(data, &ps, "multi_wait"); if(Curl_pollfds_add_ps(&cpfds, &ps)) { result = CURLM_OUT_OF_MEMORY; goto out; @@ -1497,6 +1532,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi, } out: + Curl_pollset_cleanup(&ps); Curl_pollfds_cleanup(&cpfds); return result; } @@ -1829,7 +1865,7 @@ static void multi_posttransfer(struct Curl_easy *data) if(!data->set.no_signal) signal(SIGPIPE, data->state.prev_signal); #else - (void)data; /* unused parameter */ + (void)data; #endif } @@ -1849,6 +1885,40 @@ static CURLcode multi_follow(struct Curl_easy *data, return CURLE_TOO_MANY_REDIRECTS; } +static CURLcode mspeed_check(struct Curl_easy *data, + struct curltime *nowp) +{ + timediff_t recv_wait_ms = 0; + timediff_t send_wait_ms = 0; + + /* check if over send speed */ + if(data->set.max_send_speed) + send_wait_ms = Curl_pgrsLimitWaitTime(&data->progress.ul, + data->set.max_send_speed, + *nowp); + + /* check if over recv speed */ + if(data->set.max_recv_speed) + recv_wait_ms = Curl_pgrsLimitWaitTime(&data->progress.dl, + data->set.max_recv_speed, + *nowp); + + if(send_wait_ms || recv_wait_ms) { + if(data->mstate != MSTATE_RATELIMITING) { + Curl_ratelimit(data, *nowp); + multistate(data, MSTATE_RATELIMITING); + } + Curl_expire(data, CURLMAX(send_wait_ms, recv_wait_ms), EXPIRE_TOOFAST); + Curl_multi_clear_dirty(data); + return CURLE_AGAIN; + } + else if(data->mstate != MSTATE_PERFORMING) { + multistate(data, MSTATE_PERFORMING); + Curl_ratelimit(data, *nowp); + } + return CURLE_OK; +} + static CURLMcode state_performing(struct Curl_easy *data, struct curltime *nowp, bool *stream_errorp, @@ -1856,33 +1926,12 @@ static CURLMcode state_performing(struct Curl_easy *data, { char *newurl = NULL; bool retry = FALSE; - timediff_t recv_timeout_ms = 0; - timediff_t send_timeout_ms = 0; CURLMcode rc = CURLM_OK; CURLcode result = *resultp = CURLE_OK; *stream_errorp = FALSE; - /* check if over send speed */ - if(data->set.max_send_speed) - send_timeout_ms = Curl_pgrsLimitWaitTime(&data->progress.ul, - data->set.max_send_speed, - *nowp); - - /* check if over recv speed */ - if(data->set.max_recv_speed) - recv_timeout_ms = Curl_pgrsLimitWaitTime(&data->progress.dl, - data->set.max_recv_speed, - *nowp); - - if(send_timeout_ms || recv_timeout_ms) { - Curl_ratelimit(data, *nowp); - multistate(data, MSTATE_RATELIMITING); - if(send_timeout_ms >= recv_timeout_ms) - Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); - else - Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); + if(mspeed_check(data, nowp) == CURLE_AGAIN) return CURLM_OK; - } /* read/write data if it is ready to do so */ result = Curl_sendrecv(data, nowp); @@ -1997,6 +2046,9 @@ static CURLMcode state_performing(struct Curl_easy *data, } } } + else { /* not errored, not done */ + mspeed_check(data, nowp); + } free(newurl); *resultp = result; return rc; @@ -2164,30 +2216,8 @@ static CURLMcode state_ratelimiting(struct Curl_easy *data, multi_done(data, result, TRUE); } else { - timediff_t recv_timeout_ms = 0; - timediff_t send_timeout_ms = 0; - if(data->set.max_send_speed) - send_timeout_ms = - Curl_pgrsLimitWaitTime(&data->progress.ul, - data->set.max_send_speed, - *nowp); - - if(data->set.max_recv_speed) - recv_timeout_ms = - Curl_pgrsLimitWaitTime(&data->progress.dl, - data->set.max_recv_speed, - *nowp); - - if(!send_timeout_ms && !recv_timeout_ms) { - multistate(data, MSTATE_PERFORMING); - Curl_ratelimit(data, *nowp); - /* start performing again right away */ + if(!mspeed_check(data, nowp)) rc = CURLM_CALL_MULTI_PERFORM; - } - else if(send_timeout_ms >= recv_timeout_ms) - Curl_expire(data, send_timeout_ms, EXPIRE_TOOFAST); - else - Curl_expire(data, recv_timeout_ms, EXPIRE_TOOFAST); } *resultp = result; return rc; @@ -2407,22 +2437,24 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, case MSTATE_CONNECTING: /* awaiting a completion of an asynch TCP connect */ DEBUGASSERT(data->conn); - result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected); - if(connected && !result) { - if(!data->conn->bits.reuse && - Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) { - /* new connection, can multiplex, wake pending handles */ - process_pending_handles(data->multi); + if(!Curl_xfer_recv_is_paused(data)) { + result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &connected); + if(connected && !result) { + if(!data->conn->bits.reuse && + Curl_conn_is_multiplex(data->conn, FIRSTSOCKET)) { + /* new connection, can multiplex, wake pending handles */ + process_pending_handles(data->multi); + } + rc = CURLM_CALL_MULTI_PERFORM; + multistate(data, MSTATE_PROTOCONNECT); + } + else if(result) { + /* failure detected */ + multi_posttransfer(data); + multi_done(data, result, TRUE); + stream_error = TRUE; + break; } - rc = CURLM_CALL_MULTI_PERFORM; - multistate(data, MSTATE_PROTOCONNECT); - } - else if(result) { - /* failure detected */ - multi_posttransfer(data); - multi_done(data, result, TRUE); - stream_error = TRUE; - break; } break; @@ -2530,8 +2562,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Only perform the transfer if there is a good socket to work with. Having both BAD is a signal to skip immediately to DONE */ - if((data->conn->sockfd != CURL_SOCKET_BAD) || - (data->conn->writesockfd != CURL_SOCKET_BAD)) + if(CONN_SOCK_IDX_VALID(data->conn->recv_idx) || + CONN_SOCK_IDX_VALID(data->conn->send_idx)) multistate(data, MSTATE_PERFORMING); else { #ifndef CURL_DISABLE_FTP @@ -2766,6 +2798,7 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles) if(t) { /* the removed may have another timeout in queue */ struct Curl_easy *data = Curl_splayget(t); + (void)add_next_timeout(now, multi, data); if(data->mstate == MSTATE_PENDING) { bool stream_unused; CURLcode result_unused; @@ -2774,7 +2807,6 @@ CURLMcode curl_multi_perform(CURLM *m, int *running_handles) move_pending_to_connect(multi, data); } } - (void)add_next_timeout(now, multi, Curl_splayget(t)); } } while(t); @@ -3217,6 +3249,16 @@ CURLMcode curl_multi_setopt(CURLM *m, multi->max_concurrent_streams = (unsigned int)streams; } break; + case CURLMOPT_NETWORK_CHANGED: { + long val = va_arg(param, long); + if(val & CURLMNWC_CLEAR_DNS) { + Curl_dnscache_clear(multi->admin); + } + if(val & CURLMNWC_CLEAR_CONNS) { + Curl_cpool_nw_changed(multi->admin); + } + break; + } default: res = CURLM_UNKNOWN_OPTION; break; @@ -3541,8 +3583,8 @@ void Curl_expire_ex(struct Curl_easy *data, multi->timetree = Curl_splayinsert(*curr_expire, multi->timetree, &data->state.timenode); if(data->id >= 0) - CURL_TRC_M(data, "set expire[%d] in %" FMT_TIMEDIFF_T "ns", - id, curlx_timediff_us(set, *nowp)); + CURL_TRC_M(data, "[TIMEOUT] set %s to expire in %" FMT_TIMEDIFF_T "ns", + CURL_TIMER_NAME(id), curlx_timediff_us(set, *nowp)); } /* @@ -3572,6 +3614,8 @@ void Curl_expire_done(struct Curl_easy *data, expire_id id) { /* remove the timer, if there */ multi_deltimeout(data, id); + if(data->id >= 0) + CURL_TRC_M(data, "[TIMEOUT] cleared %s", CURL_TIMER_NAME(id)); } /* @@ -3603,7 +3647,8 @@ bool Curl_expire_clear(struct Curl_easy *data) /* clear the timeout list too */ Curl_llist_destroy(list, NULL); - CURL_TRC_M(data, "Expire cleared"); + if(data->id >= 0) + CURL_TRC_M(data, "[TIMEOUT] all cleared"); nowp->tv_sec = 0; nowp->tv_usec = 0; return TRUE; @@ -3631,9 +3676,7 @@ static void move_pending_to_connect(struct Curl_multi *multi, Curl_uint_bset_add(&multi->process, data->mid); multistate(data, MSTATE_CONNECT); - - /* Make sure that the handle will be processed soonish. */ - Curl_expire(data, 0, EXPIRE_RUN_NOW); + Curl_multi_mark_dirty(data); /* make it run */ } /* process_pending_handles() moves a handle from PENDING back into the process @@ -3656,9 +3699,13 @@ static void process_pending_handles(struct Curl_multi *multi) if(Curl_uint_bset_first(&multi->pending, &mid)) { do { struct Curl_easy *data = Curl_multi_get_easy(multi, mid); - DEBUGASSERT(data); - if(data) + if(data) { move_pending_to_connect(multi, data); + break; + } + /* transfer no longer known, should not happen */ + Curl_uint_bset_remove(&multi->pending, mid); + DEBUGASSERT(0); } while(Curl_uint_bset_next(&multi->pending, mid, &mid)); } @@ -3704,6 +3751,43 @@ CURL **curl_multi_get_handles(CURLM *m) return a; } +CURLMcode curl_multi_get_offt(CURLM *m, + CURLMinfo_offt info, + curl_off_t *pvalue) +{ + struct Curl_multi *multi = m; + + if(!GOOD_MULTI_HANDLE(multi)) + return CURLM_BAD_HANDLE; + if(!pvalue) + return CURLM_BAD_FUNCTION_ARGUMENT; + + switch(info) { + case CURLMINFO_XFERS_CURRENT: { + unsigned int n = Curl_uint_tbl_count(&multi->xfers); + if(n && multi->admin) + --n; + *pvalue = (curl_off_t)n; + return CURLM_OK; + } + case CURLMINFO_XFERS_RUNNING: + *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->process); + return CURLM_OK; + case CURLMINFO_XFERS_PENDING: + *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->pending); + return CURLM_OK; + case CURLMINFO_XFERS_DONE: + *pvalue = (curl_off_t)Curl_uint_bset_count(&multi->msgsent); + return CURLM_OK; + case CURLMINFO_XFERS_ADDED: + *pvalue = multi->xfers_total_ever; + return CURLM_OK; + default: + *pvalue = -1; + return CURLM_UNKNOWN_OPTION; + } +} + CURLcode Curl_multi_xfer_buf_borrow(struct Curl_easy *data, char **pbuf, size_t *pbuflen) { @@ -3892,6 +3976,12 @@ void Curl_multi_mark_dirty(struct Curl_easy *data) Curl_uint_bset_add(&data->multi->dirty, data->mid); } +void Curl_multi_clear_dirty(struct Curl_easy *data) +{ + if(data->multi && data->mid != UINT_MAX) + Curl_uint_bset_remove(&data->multi->dirty, data->mid); +} + #ifdef DEBUGBUILD static void multi_xfer_dump(struct Curl_multi *multi, unsigned int mid, void *entry) diff --git a/deps/curl/lib/multi_ev.c b/deps/curl/lib/multi_ev.c index 0b4c472849d..61c639d9e48 100644 --- a/deps/curl/lib/multi_ev.c +++ b/deps/curl/lib/multi_ev.c @@ -64,19 +64,21 @@ struct mev_sh_entry { * libcurl application to watch out for */ unsigned int readers; /* this many transfers want to read */ unsigned int writers; /* this many transfers want to write */ + BIT(announced); /* this socket has been passed to the socket + callback at least once */ }; static size_t mev_sh_entry_hash(void *key, size_t key_length, size_t slots_num) { curl_socket_t fd = *((curl_socket_t *) key); - (void) key_length; + (void)key_length; return (fd % (curl_socket_t)slots_num); } static size_t mev_sh_entry_compare(void *k1, size_t k1_len, void *k2, size_t k2_len) { - (void) k1_len; (void) k2_len; + (void)k1_len; (void)k2_len; return (*((curl_socket_t *) k1)) == (*((curl_socket_t *) k2)); } @@ -205,13 +207,14 @@ static CURLMcode mev_forget_socket(struct Curl_multi *multi, return CURLM_OK; /* We managed this socket before, tell the socket callback to forget it. */ - if(multi->socket_cb) { + if(entry->announced && multi->socket_cb) { CURL_TRC_M(data, "ev %s, call(fd=%" FMT_SOCKET_T ", ev=REMOVE)", cause, s); mev_in_callback(multi, TRUE); rc = multi->socket_cb(data, s, CURL_POLL_REMOVE, multi->socket_userp, entry->user_data); mev_in_callback(multi, FALSE); + entry->announced = FALSE; } mev_sh_entry_kill(multi, s); @@ -281,8 +284,8 @@ static CURLMcode mev_sh_entry_update(struct Curl_multi *multi, mev_in_callback(multi, TRUE); rc = multi->socket_cb(data, s, comboaction, multi->socket_userp, entry->user_data); - mev_in_callback(multi, FALSE); + entry->announced = TRUE; if(rc == -1) { multi->dead = TRUE; return CURLM_ABORTED_BY_CALLBACK; @@ -314,7 +317,7 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, DEBUGASSERT(prev_ps); /* Handle changes to sockets the transfer is interested in. */ - for(i = 0; i < ps->num; i++) { + for(i = 0; i < ps->n; i++) { unsigned char last_action; bool first_time = FALSE; /* data/conn appears first time on socket */ @@ -359,7 +362,7 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, entry->conn ? 1 : 0); } else { - for(j = 0; j < prev_ps->num; j++) { + for(j = 0; j < prev_ps->n; j++) { if(s == prev_ps->sockets[j]) { last_action = prev_ps->actions[j]; break; @@ -374,11 +377,11 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, } /* Handle changes to sockets the transfer is NO LONGER interested in. */ - for(i = 0; i < prev_ps->num; i++) { + for(i = 0; i < prev_ps->n; i++) { bool stillused = FALSE; s = prev_ps->sockets[i]; - for(j = 0; j < ps->num; j++) { + for(j = 0; j < ps->n; j++) { if(s == ps->sockets[j]) { /* socket is still supervised */ stillused = TRUE; @@ -434,15 +437,19 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi, } /* for loop over num */ /* Remember for next time */ - memcpy(prev_ps, ps, sizeof(*prev_ps)); + Curl_pollset_move(prev_ps, ps); return CURLM_OK; } static void mev_pollset_dtor(void *key, size_t klen, void *entry) { + struct easy_pollset *ps = entry; (void)key; (void)klen; - free(entry); + if(ps) { + Curl_pollset_cleanup(ps); + free(ps); + } } static struct easy_pollset* @@ -450,7 +457,7 @@ mev_add_new_conn_pollset(struct connectdata *conn) { struct easy_pollset *ps; - ps = calloc(1, sizeof(*ps)); + ps = Curl_pollset_create(); if(!ps) return NULL; if(Curl_conn_meta_set(conn, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor)) @@ -463,7 +470,7 @@ mev_add_new_xfer_pollset(struct Curl_easy *data) { struct easy_pollset *ps; - ps = calloc(1, sizeof(*ps)); + ps = Curl_pollset_create(); if(!ps) return NULL; if(Curl_meta_set(data, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor)) @@ -483,42 +490,47 @@ mev_get_last_pollset(struct Curl_easy *data, return NULL; } -static void mev_init_cur_pollset(struct easy_pollset *ps, - struct Curl_easy *data, - struct connectdata *conn) -{ - memset(ps, 0, sizeof(*ps)); - if(conn) - Curl_conn_adjust_pollset(data, conn, ps); - else if(data) - Curl_multi_getsock(data, ps, "ev assess"); -} - static CURLMcode mev_assess(struct Curl_multi *multi, struct Curl_easy *data, struct connectdata *conn) { - if(multi && multi->socket_cb) { - struct easy_pollset ps, *last_ps; + struct easy_pollset ps, *last_ps; + CURLMcode res = CURLM_OK; - mev_init_cur_pollset(&ps, data, conn); - last_ps = mev_get_last_pollset(data, conn); + if(!multi || !multi->socket_cb) + return CURLM_OK; - if(!last_ps && ps.num) { - if(conn) - last_ps = mev_add_new_conn_pollset(conn); - else - last_ps = mev_add_new_xfer_pollset(data); - if(!last_ps) - return CURLM_OUT_OF_MEMORY; + Curl_pollset_init(&ps); + if(conn) { + CURLcode r = Curl_conn_adjust_pollset(data, conn, &ps); + if(r) { + res = (r == CURLE_OUT_OF_MEMORY) ? + CURLM_OUT_OF_MEMORY : CURLM_INTERNAL_ERROR; + goto out; } + } + else if(data) + Curl_multi_pollset(data, &ps, "ev assess"); + last_ps = mev_get_last_pollset(data, conn); - if(last_ps) - return mev_pollset_diff(multi, data, conn, &ps, last_ps); + if(!last_ps && ps.n) { + if(conn) + last_ps = mev_add_new_conn_pollset(conn); else - DEBUGASSERT(!ps.num); + last_ps = mev_add_new_xfer_pollset(data); + if(!last_ps) { + res = CURLM_OUT_OF_MEMORY; + goto out; + } } - return CURLM_OK; + + if(last_ps) + res = mev_pollset_diff(multi, data, conn, &ps, last_ps); + else + DEBUGASSERT(!ps.n); +out: + Curl_pollset_cleanup(&ps); + return res; } CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi, diff --git a/deps/curl/lib/multihandle.h b/deps/curl/lib/multihandle.h index 4bf2dd811c2..ae41044adc2 100644 --- a/deps/curl/lib/multihandle.h +++ b/deps/curl/lib/multihandle.h @@ -72,15 +72,9 @@ typedef enum { MSTATE_LAST /* 18 - not a true state, never use this */ } CURLMstate; -/* we support N sockets per easy handle. Set the corresponding bit to what - action we should wait for */ -#define MAX_SOCKSPEREASYHANDLE 5 -#define GETSOCK_READABLE (0x00ff) -#define GETSOCK_WRITABLE (0xff00) - #define CURLPIPE_ANY (CURLPIPE_MULTIPLEX) -#if !defined(CURL_DISABLE_SOCKETPAIR) +#ifndef CURL_DISABLE_SOCKETPAIR #define ENABLE_WAKEUP #endif @@ -95,6 +89,7 @@ struct Curl_multi { unsigned int xfers_alive; /* amount of added transfers that have not yet reached COMPLETE state */ + curl_off_t xfers_total_ever; /* total of added transfers, ever. */ struct uint_tbl xfers; /* transfers added to this multi */ /* Each transfer's mid may be present in at most one of these */ struct uint_bset process; /* transfer being processed */ diff --git a/deps/curl/lib/multiif.h b/deps/curl/lib/multiif.h index 1ba0d0f8387..1423d5a03d0 100644 --- a/deps/curl/lib/multiif.h +++ b/deps/curl/lib/multiif.h @@ -53,20 +53,6 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size, size_t dnssize, size_t sesssize); -/* the write bits start at bit 16 for the *getsock() bitmap */ -#define GETSOCK_WRITEBITSTART 16 - -#define GETSOCK_BLANK 0 /* no bits set */ - -/* set the bit for the given sock number to make the bitmap for writable */ -#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x))) - -/* set the bit for the given sock number to make the bitmap for readable */ -#define GETSOCK_READSOCK(x) (1 << (x)) - -/* mask for checking if read and/or write is set for index x */ -#define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x)) - /** * Let the multi handle know that the socket is about to be closed. * The multi will then remove anything it knows about the socket, so @@ -86,9 +72,9 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi, /* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */ unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi); -void Curl_multi_getsock(struct Curl_easy *data, - struct easy_pollset *ps, - const char *caller); +CURLMcode Curl_multi_pollset(struct Curl_easy *data, + struct easy_pollset *ps, + const char *caller); /** * Borrow the transfer buffer from the multi, suitable @@ -176,5 +162,7 @@ unsigned int Curl_multi_xfers_running(struct Curl_multi *multi); /* Mark a transfer as dirty, e.g. to be rerun at earliest convenience. * A cheap operation, can be done many times repeatedly. */ void Curl_multi_mark_dirty(struct Curl_easy *data); +/* Clear transfer from the dirty set. */ +void Curl_multi_clear_dirty(struct Curl_easy *data); #endif /* HEADER_CURL_MULTIIF_H */ diff --git a/deps/curl/lib/netrc.c b/deps/curl/lib/netrc.c index bf53fc01e18..447ee095852 100644 --- a/deps/curl/lib/netrc.c +++ b/deps/curl/lib/netrc.c @@ -390,53 +390,57 @@ const char *Curl_netrc_strerror(NETRCcode ret) */ NETRCcode Curl_parsenetrc(struct store_netrc *store, const char *host, char **loginp, char **passwordp, - char *netrcfile) + const char *netrcfile) { NETRCcode retcode = NETRC_OK; char *filealloc = NULL; if(!netrcfile) { + char *home = NULL; + char *homea = NULL; #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) char pwbuf[1024]; #endif - char *home = NULL; - char *homea = curl_getenv("HOME"); /* portable environment reader */ - if(homea) { - home = homea; + filealloc = curl_getenv("NETRC"); + if(!filealloc) { + homea = curl_getenv("HOME"); /* portable environment reader */ + if(homea) { + home = homea; #if defined(HAVE_GETPWUID_R) && defined(HAVE_GETEUID) - } - else { - struct passwd pw, *pw_res; - if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) - && pw_res) { - home = pw.pw_dir; } + else { + struct passwd pw, *pw_res; + if(!getpwuid_r(geteuid(), &pw, pwbuf, sizeof(pwbuf), &pw_res) + && pw_res) { + home = pw.pw_dir; + } #elif defined(HAVE_GETPWUID) && defined(HAVE_GETEUID) - } - else { - struct passwd *pw; - pw = getpwuid(geteuid()); - if(pw) { - home = pw->pw_dir; } + else { + struct passwd *pw; + pw = getpwuid(geteuid()); + if(pw) { + home = pw->pw_dir; + } #elif defined(_WIN32) - } - else { - homea = curl_getenv("USERPROFILE"); - if(homea) { - home = homea; } + else { + homea = curl_getenv("USERPROFILE"); + if(homea) { + home = homea; + } #endif - } + } - if(!home) - return NETRC_FILE_MISSING; /* no home directory found (or possibly out - of memory) */ + if(!home) + return NETRC_FILE_MISSING; /* no home directory found (or possibly out + of memory) */ - filealloc = aprintf("%s%s.netrc", home, DIR_CHAR); - if(!filealloc) { - free(homea); - return NETRC_OUT_OF_MEMORY; + filealloc = aprintf("%s%s.netrc", home, DIR_CHAR); + if(!filealloc) { + free(homea); + return NETRC_OUT_OF_MEMORY; + } } retcode = parsenetrc(store, host, loginp, passwordp, filealloc); free(filealloc); diff --git a/deps/curl/lib/netrc.h b/deps/curl/lib/netrc.h index ef3bde5212a..0d6d081bfbb 100644 --- a/deps/curl/lib/netrc.h +++ b/deps/curl/lib/netrc.h @@ -48,7 +48,8 @@ void Curl_netrc_init(struct store_netrc *s); void Curl_netrc_cleanup(struct store_netrc *s); NETRCcode Curl_parsenetrc(struct store_netrc *s, const char *host, - char **loginp, char **passwordp, char *filename); + char **loginp, char **passwordp, + const char *filename); /* Assume: (*passwordp)[0]=0, host[0] != 0. * If (*loginp)[0] = 0, search for login and password within a machine * section in the netrc. diff --git a/deps/curl/lib/noproxy.c b/deps/curl/lib/noproxy.c index 306cd6d1f98..22b067ad1b0 100644 --- a/deps/curl/lib/noproxy.c +++ b/deps/curl/lib/noproxy.c @@ -54,9 +54,9 @@ UNITTEST bool Curl_cidr4_match(const char *ipv4, /* 1.2.3.4 address */ /* strange input */ return FALSE; - if(1 != curlx_inet_pton(AF_INET, ipv4, &address)) + if(curlx_inet_pton(AF_INET, ipv4, &address) != 1) return FALSE; - if(1 != curlx_inet_pton(AF_INET, network, &check)) + if(curlx_inet_pton(AF_INET, network, &check) != 1) return FALSE; if(bits && (bits != 32)) { @@ -92,9 +92,9 @@ UNITTEST bool Curl_cidr6_match(const char *ipv6, rest = bits & 0x07; if((bytes > 16) || ((bytes == 16) && rest)) return FALSE; - if(1 != curlx_inet_pton(AF_INET6, ipv6, address)) + if(curlx_inet_pton(AF_INET6, ipv6, address) != 1) return FALSE; - if(1 != curlx_inet_pton(AF_INET6, network, check)) + if(curlx_inet_pton(AF_INET6, network, check) != 1) return FALSE; if(bytes && memcmp(address, check, bytes)) return FALSE; @@ -163,7 +163,7 @@ bool Curl_check_noproxy(const char *name, const char *no_proxy) else { unsigned int address; namelen = strlen(name); - if(1 == curlx_inet_pton(AF_INET, name, &address)) + if(curlx_inet_pton(AF_INET, name, &address) == 1) type = TYPE_IPV4; else { /* ignore trailing dots in the hostname */ diff --git a/deps/curl/lib/openldap.c b/deps/curl/lib/openldap.c index e4714b55801..da26d4a78d0 100644 --- a/deps/curl/lib/openldap.c +++ b/deps/curl/lib/openldap.c @@ -126,10 +126,10 @@ const struct Curl_handler Curl_handler_ldap = { oldap_connect, /* connect_it */ oldap_connecting, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ oldap_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -156,10 +156,10 @@ const struct Curl_handler Curl_handler_ldaps = { oldap_connect, /* connect_it */ oldap_connecting, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ oldap_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -496,7 +496,24 @@ static CURLcode oldap_perform_sasl(struct Curl_easy *data) } #ifdef USE_SSL -static Sockbuf_IO ldapsb_tls; +static int ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg); +static int ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod); +static int ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg); +static ber_slen_t ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, + ber_len_t len); +static ber_slen_t ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, + ber_len_t len); +static int ldapsb_tls_close(Sockbuf_IO_Desc *sbiod); + +static Sockbuf_IO ldapsb_tls = +{ + ldapsb_tls_setup, + ldapsb_tls_remove, + ldapsb_tls_ctrl, + ldapsb_tls_read, + ldapsb_tls_write, + ldapsb_tls_close +}; static bool ssl_installed(struct connectdata *conn) { @@ -924,7 +941,7 @@ static CURLcode oldap_disconnect(struct Curl_easy *data, bool dead_connection) { struct ldapconninfo *li = Curl_conn_meta_get(conn, CURL_META_LDAP_CONN); - (void) dead_connection; + (void)dead_connection; #ifndef USE_SSL (void)data; #endif @@ -993,7 +1010,7 @@ static CURLcode oldap_do(struct Curl_easy *data, bool *done) } lr->msgid = msgid; - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); *done = TRUE; out: @@ -1293,16 +1310,6 @@ ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len) } return ret; } - -static Sockbuf_IO ldapsb_tls = -{ - ldapsb_tls_setup, - ldapsb_tls_remove, - ldapsb_tls_ctrl, - ldapsb_tls_read, - ldapsb_tls_write, - ldapsb_tls_close -}; #endif /* USE_SSL */ #endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */ diff --git a/deps/curl/lib/optiontable.pl b/deps/curl/lib/optiontable.pl index cc38a922cc9..43fbd39d3bf 100755 --- a/deps/curl/lib/optiontable.pl +++ b/deps/curl/lib/optiontable.pl @@ -1,5 +1,8 @@ #!/usr/bin/env perl +use strict; +use warnings; + print <conn; - socks[0] = conn->sock[FIRSTSOCKET]; - - if(pp->sendleft) { - /* write mode */ - return GETSOCK_WRITESOCK(0); - } - - /* read mode */ - return GETSOCK_READSOCK(0); + int flags = pp->sendleft ? CURL_POLL_OUT : CURL_POLL_IN; + return Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], + flags, 0); } bool Curl_pp_needs_flush(struct Curl_easy *data, diff --git a/deps/curl/lib/pingpong.h b/deps/curl/lib/pingpong.h index c6d0a56f0d2..5db96c4345f 100644 --- a/deps/curl/lib/pingpong.h +++ b/deps/curl/lib/pingpong.h @@ -147,8 +147,9 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data, /* call this when a pingpong connection is disconnected */ CURLcode Curl_pp_disconnect(struct pingpong *pp); -int Curl_pp_getsock(struct Curl_easy *data, struct pingpong *pp, - curl_socket_t *socks); +CURLcode Curl_pp_pollset(struct Curl_easy *data, + struct pingpong *pp, + struct easy_pollset *ps); /*********************************************************************** diff --git a/deps/curl/lib/pop3.c b/deps/curl/lib/pop3.c index 514c4b8fa53..f5ecfd178ba 100644 --- a/deps/curl/lib/pop3.c +++ b/deps/curl/lib/pop3.c @@ -153,8 +153,8 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done); static CURLcode pop3_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead); static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done); -static int pop3_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); +static CURLcode pop3_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done); static CURLcode pop3_setup_connection(struct Curl_easy *data, struct connectdata *conn); @@ -186,10 +186,10 @@ const struct Curl_handler Curl_handler_pop3 = { pop3_connect, /* connect_it */ pop3_multi_statemach, /* connecting */ pop3_doing, /* doing */ - pop3_getsock, /* proto_getsock */ - pop3_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + pop3_pollset, /* proto_pollset */ + pop3_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ pop3_disconnect, /* disconnect */ pop3_write, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -217,10 +217,10 @@ const struct Curl_handler Curl_handler_pop3s = { pop3_connect, /* connect_it */ pop3_multi_statemach, /* connecting */ pop3_doing, /* doing */ - pop3_getsock, /* proto_getsock */ - pop3_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + pop3_pollset, /* proto_pollset */ + pop3_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ pop3_disconnect, /* disconnect */ pop3_write, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -811,7 +811,7 @@ static CURLcode pop3_state_servergreet_resp(struct Curl_easy *data, const char *line; size_t len; - (void)instate; /* no use for this yet */ + (void)instate; if(!pop3c) return CURLE_FAILED_INIT; @@ -866,7 +866,7 @@ static CURLcode pop3_state_capa_resp(struct Curl_easy *data, int pop3code, const char *line; size_t len; - (void)instate; /* no use for this yet */ + (void)instate; if(!pop3c) return CURLE_FAILED_INIT; @@ -954,7 +954,7 @@ static CURLcode pop3_state_starttls_resp(struct Curl_easy *data, { struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN); CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(!pop3c) return CURLE_FAILED_INIT; @@ -987,7 +987,7 @@ static CURLcode pop3_state_auth_resp(struct Curl_easy *data, struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN); saslprogress progress; - (void)instate; /* no use for this yet */ + (void)instate; if(!pop3c) return CURLE_FAILED_INIT; @@ -1025,7 +1025,7 @@ static CURLcode pop3_state_apop_resp(struct Curl_easy *data, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(pop3code != '+') { failf(data, "Authentication failed: %d", pop3code); @@ -1046,7 +1046,7 @@ static CURLcode pop3_state_user_resp(struct Curl_easy *data, int pop3code, CURLcode result = CURLE_OK; struct connectdata *conn = data->conn; struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN); - (void)instate; /* no use for this yet */ + (void)instate; if(!pop3c) return CURLE_FAILED_INIT; @@ -1070,7 +1070,7 @@ static CURLcode pop3_state_pass_resp(struct Curl_easy *data, int pop3code, pop3state instate) { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(pop3code != '+') { failf(data, "Access denied. %c", pop3code); @@ -1094,7 +1094,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data, struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN); struct pingpong *pp; - (void)instate; /* no use for this yet */ + (void)instate; if(!pop3 || !pop3c) return CURLE_FAILED_INIT; @@ -1116,7 +1116,7 @@ static CURLcode pop3_state_command_resp(struct Curl_easy *data, if(pop3->transfer == PPTRANSFER_BODY) { /* POP3 download */ - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); if(pp->overflow) { /* The recv buffer contains data that is actually body content so send @@ -1269,13 +1269,12 @@ static CURLcode pop3_block_statemach(struct Curl_easy *data, } /* For the POP3 "protocol connect" and "doing" phases only */ -static int pop3_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks) +static CURLcode pop3_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN); - if(pop3c) - return Curl_pp_getsock(data, &pop3c->pp, socks); - return GETSOCK_BLANK; + struct pop3_conn *pop3c = + Curl_conn_meta_get(data->conn, CURL_META_POP3_CONN); + return pop3c ? Curl_pp_pollset(data, &pop3c->pp, ps) : CURLE_OK; } /*********************************************************************** diff --git a/deps/curl/lib/progress.c b/deps/curl/lib/progress.c index 746805f20fa..fdae3194c55 100644 --- a/deps/curl/lib/progress.c +++ b/deps/curl/lib/progress.c @@ -281,41 +281,40 @@ void Curl_pgrsStartNow(struct Curl_easy *data) * to wait to get back under the speed limit. */ timediff_t Curl_pgrsLimitWaitTime(struct pgrs_dir *d, - curl_off_t speed_limit, + curl_off_t bytes_per_sec, struct curltime now) { - curl_off_t size = d->cur_size - d->limit.start_size; - timediff_t minimum; - timediff_t actual; + curl_off_t bytes = d->cur_size - d->limit.start_size; + timediff_t should_ms; + timediff_t took_ms; - if(!speed_limit || !size) + /* no limit or we did not get to any bytes yet */ + if(!bytes_per_sec || !bytes) return 0; - /* - * 'minimum' is the number of milliseconds 'size' should take to download to - * stay below 'limit'. - */ - if(size < CURL_OFF_T_MAX/1000) - minimum = (timediff_t) (1000 * size / speed_limit); + /* The time it took us to have `bytes` */ + took_ms = curlx_timediff_ceil(now, d->limit.start); + + /* The time it *should* have taken us to have `bytes` + * when obeying the bytes_per_sec speed_limit. */ + if(bytes < CURL_OFF_T_MAX/1000) { + /* (1000 * bytes / (bytes / sec)) = 1000 * sec = ms */ + should_ms = (timediff_t) (1000 * bytes / bytes_per_sec); + } else { - minimum = (timediff_t) (size / speed_limit); - if(minimum < TIMEDIFF_T_MAX/1000) - minimum *= 1000; + /* very large `bytes`, first calc the seconds it should have taken. + * if that is small enough, convert to milliseconds. */ + should_ms = (timediff_t) (bytes / bytes_per_sec); + if(should_ms < TIMEDIFF_T_MAX/1000) + should_ms *= 1000; else - minimum = TIMEDIFF_T_MAX; + should_ms = TIMEDIFF_T_MAX; } - /* - * 'actual' is the time in milliseconds it took to actually download the - * last 'size' bytes. - */ - actual = curlx_timediff_ceil(now, d->limit.start); - if(actual < minimum) { - /* if it downloaded the data faster than the limit, make it wait the - difference */ - return minimum - actual; + if(took_ms < should_ms) { + /* when gotten to `bytes` too fast, wait the difference */ + return should_ms - took_ms; } - return 0; } @@ -449,7 +448,7 @@ static bool progress_calc(struct Curl_easy *data, struct curltime now) /* Figure out the exact time for the time span */ span_ms = curlx_timediff(now, p->speeder_time[checkindex]); - if(0 == span_ms) + if(span_ms == 0) span_ms = 1; /* at least one millisecond MUST have passed */ /* Calculate the average speed the last 'span_ms' milliseconds */ diff --git a/deps/curl/lib/rand.c b/deps/curl/lib/rand.c index 72545e08677..a1a5e42c2bb 100644 --- a/deps/curl/lib/rand.c +++ b/deps/curl/lib/rand.c @@ -48,13 +48,14 @@ #ifdef _WIN32 -#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x600 && \ +#if defined(_WIN32_WINNT) && _WIN32_WINNT >= _WIN32_WINNT_VISTA && \ !defined(CURL_WINDOWS_UWP) # define HAVE_WIN_BCRYPTGENRANDOM # include # ifdef _MSC_VER # pragma comment(lib, "bcrypt.lib") # endif + /* Offered by mingw-w64 v3+. MS SDK v7.0A+. */ # ifndef BCRYPT_USE_SYSTEM_PREFERRED_RNG # define BCRYPT_USE_SYSTEM_PREFERRED_RNG 0x00000002 # endif @@ -72,7 +73,7 @@ CURLcode Curl_win32_random(unsigned char *entropy, size_t length) { memset(entropy, 0, length); -#if defined(HAVE_WIN_BCRYPTGENRANDOM) +#ifdef HAVE_WIN_BCRYPTGENRANDOM if(BCryptGenRandom(NULL, entropy, (ULONG)length, BCRYPT_USE_SYSTEM_PREFERRED_RNG) != STATUS_SUCCESS) return CURLE_FAILED_INIT; @@ -100,7 +101,7 @@ CURLcode Curl_win32_random(unsigned char *entropy, size_t length) } #endif -#if !defined(USE_SSL) +#ifndef USE_SSL /* ---- possibly non-cryptographic version following ---- */ static CURLcode weak_random(struct Curl_easy *data, unsigned char *entropy, @@ -119,7 +120,7 @@ static CURLcode weak_random(struct Curl_easy *data, } #endif -#if defined(HAVE_ARC4RANDOM) +#ifdef HAVE_ARC4RANDOM (void)data; r = (unsigned int)arc4random(); memcpy(entropy, &r, length); diff --git a/deps/curl/lib/request.c b/deps/curl/lib/request.c index 0d9b23ef0c4..8751ada5598 100644 --- a/deps/curl/lib/request.c +++ b/deps/curl/lib/request.c @@ -62,7 +62,7 @@ CURLcode Curl_req_soft_reset(struct SingleRequest *req, req->shutdown = FALSE; req->bytecount = 0; req->writebytecount = 0; - req->header = TRUE; /* assume header */ + req->header = FALSE; req->headerline = 0; req->headerbytecount = 0; req->allheadercount = 0; @@ -153,6 +153,7 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data) req->eos_written = FALSE; req->eos_read = FALSE; req->eos_sent = FALSE; + req->rewind_read = FALSE; req->upload_done = FALSE; req->upload_aborted = FALSE; req->ignorebody = FALSE; @@ -160,7 +161,6 @@ void Curl_req_hard_reset(struct SingleRequest *req, struct Curl_easy *data) req->chunk = FALSE; req->ignore_cl = FALSE; req->upload_chunky = FALSE; - req->getheader = FALSE; req->no_body = data->set.opt_no_body; req->authneg = FALSE; req->shutdown = FALSE; @@ -308,7 +308,7 @@ static CURLcode req_flush(struct Curl_easy *data) } if(data->req.eos_read && !data->req.eos_sent) { - char tmp; + char tmp = 0; size_t nwritten; result = xfer_send(data, &tmp, 0, 0, &nwritten); if(result) @@ -380,8 +380,14 @@ CURLcode Curl_req_send(struct Curl_easy *data, struct dynbuf *req, data->req.httpversion_sent = httpversion; buf = curlx_dyn_ptr(req); blen = curlx_dyn_len(req); - if(!Curl_creader_total_length(data)) { - /* Request without body. Try to send directly from the buf given. */ + /* if the sendbuf is empty and the request without body and + * the length to send fits info a sendbuf chunk, we send it directly. + * If `blen` is larger then `chunk_size`, we can not. Because we + * might have to retry a blocked send later from sendbuf and that + * would result in retry sends with a shrunken length. That is trouble. */ + if(Curl_bufq_is_empty(&data->req.sendbuf) && + !Curl_creader_total_length(data) && + (blen <= data->req.sendbuf.chunk_size)) { data->req.eos_read = TRUE; result = xfer_send(data, buf, blen, blen, &nwritten); if(result) diff --git a/deps/curl/lib/request.h b/deps/curl/lib/request.h index 74d9f534396..bce34de8ba9 100644 --- a/deps/curl/lib/request.h +++ b/deps/curl/lib/request.h @@ -123,7 +123,6 @@ struct SingleRequest { BIT(ignore_cl); /* ignore content-length */ BIT(upload_chunky); /* set TRUE if we are doing chunked transfer-encoding on upload */ - BIT(getheader); /* TRUE if header parsing is wanted */ BIT(no_body); /* the response has no body */ BIT(authneg); /* TRUE when the auth phase has started, which means that we are creating a request with an auth header, diff --git a/deps/curl/lib/rtsp.c b/deps/curl/lib/rtsp.c index ac44bec4222..1d5f44f91b2 100644 --- a/deps/curl/lib/rtsp.c +++ b/deps/curl/lib/rtsp.c @@ -24,7 +24,7 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_RTSP) +#ifndef CURL_DISABLE_RTSP #include "urldata.h" #include @@ -83,8 +83,8 @@ struct RTSP { 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 int rtsp_getsock_do(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); +static CURLcode rtsp_do_pollset(struct Curl_easy *data, + struct easy_pollset *ps); /* * Parse and write out an RTSP response. @@ -100,6 +100,10 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, const char *buf, size_t blen, bool is_eos); +static CURLcode rtsp_rtp_write_resp_hd(struct Curl_easy *data, + const char *buf, + size_t blen, + bool is_eos); static CURLcode rtsp_setup_connection(struct Curl_easy *data, struct connectdata *conn); @@ -110,13 +114,11 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data, /* this returns the socket to wait for in the DO and DOING state for the multi interface and then we are always _sending_ a request and thus we wait for the single socket to become writable only */ -static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *socks) +static CURLcode rtsp_do_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { /* write mode */ - (void)data; - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_WRITESOCK(0); + return Curl_pollset_add_out(data, ps, data->conn->sock[FIRSTSOCKET]); } static @@ -137,13 +139,13 @@ const struct Curl_handler Curl_handler_rtsp = { rtsp_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - rtsp_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + rtsp_do_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ rtsp_rtp_write_resp, /* write_resp */ - ZERO_NULL, /* write_resp_hd */ + rtsp_rtp_write_resp_hd, /* write_resp_hd */ rtsp_conncheck, /* connection_check */ ZERO_NULL, /* attach connection */ Curl_http_follow, /* follow */ @@ -276,6 +278,84 @@ static CURLcode rtsp_done(struct Curl_easy *data, return httpStatus; } + +static CURLcode rtsp_setup_body(struct Curl_easy *data, + Curl_RtspReq rtspreq, + struct dynbuf *reqp) +{ + CURLcode result; + if(rtspreq == RTSPREQ_ANNOUNCE || + rtspreq == RTSPREQ_SET_PARAMETER || + rtspreq == RTSPREQ_GET_PARAMETER) { + curl_off_t req_clen; /* request content length */ + + if(data->state.upload) { + req_clen = data->state.infilesize; + data->state.httpreq = HTTPREQ_PUT; + result = Curl_creader_set_fread(data, req_clen); + if(result) + return result; + } + else { + if(data->set.postfields) { + size_t plen = strlen(data->set.postfields); + req_clen = (curl_off_t)plen; + result = Curl_creader_set_buf(data, data->set.postfields, plen); + } + else if(data->state.infilesize >= 0) { + req_clen = data->state.infilesize; + result = Curl_creader_set_fread(data, req_clen); + } + else { + req_clen = 0; + result = Curl_creader_set_null(data); + } + if(result) + return result; + } + + if(req_clen > 0) { + /* As stated in the http comments, it is probably not wise to + * actually set a custom Content-Length in the headers */ + if(!Curl_checkheaders(data, STRCONST("Content-Length"))) { + result = curlx_dyn_addf(reqp, "Content-Length: %" FMT_OFF_T"\r\n", + req_clen); + if(result) + return result; + } + + if(rtspreq == RTSPREQ_SET_PARAMETER || + rtspreq == RTSPREQ_GET_PARAMETER) { + if(!Curl_checkheaders(data, STRCONST("Content-Type"))) { + result = curlx_dyn_addn(reqp, + STRCONST("Content-Type: " + "text/parameters\r\n")); + if(result) + return result; + } + } + + if(rtspreq == RTSPREQ_ANNOUNCE) { + if(!Curl_checkheaders(data, STRCONST("Content-Type"))) { + result = curlx_dyn_addn(reqp, + STRCONST("Content-Type: " + "application/sdp\r\n")); + if(result) + return result; + } + } + } + else if(rtspreq == RTSPREQ_GET_PARAMETER) { + /* Check for an empty GET_PARAMETER (heartbeat) request */ + data->state.httpreq = HTTPREQ_HEAD; + data->req.no_body = TRUE; + } + } + else + result = Curl_creader_set_null(data); + return result; +} + static CURLcode rtsp_do(struct Curl_easy *data, bool *done) { struct connectdata *conn = data->conn; @@ -372,7 +452,7 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) } if(rtspreq == RTSPREQ_RECEIVE) { - Curl_xfer_setup1(data, CURL_XFER_RECV, -1, TRUE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); goto out; } @@ -559,86 +639,16 @@ static CURLcode rtsp_do(struct Curl_easy *data, bool *done) if(result) goto out; - if(rtspreq == RTSPREQ_ANNOUNCE || - rtspreq == RTSPREQ_SET_PARAMETER || - rtspreq == RTSPREQ_GET_PARAMETER) { - curl_off_t req_clen; /* request content length */ - - if(data->state.upload) { - req_clen = data->state.infilesize; - data->state.httpreq = HTTPREQ_PUT; - result = Curl_creader_set_fread(data, req_clen); - if(result) - goto out; - } - else { - if(data->set.postfields) { - size_t plen = strlen(data->set.postfields); - req_clen = (curl_off_t)plen; - result = Curl_creader_set_buf(data, data->set.postfields, plen); - } - else if(data->state.infilesize >= 0) { - req_clen = data->state.infilesize; - result = Curl_creader_set_fread(data, req_clen); - } - else { - req_clen = 0; - result = Curl_creader_set_null(data); - } - if(result) - goto out; - } - - if(req_clen > 0) { - /* As stated in the http comments, it is probably not wise to - * actually set a custom Content-Length in the headers */ - if(!Curl_checkheaders(data, STRCONST("Content-Length"))) { - result = - curlx_dyn_addf(&req_buffer, "Content-Length: %" FMT_OFF_T"\r\n", - req_clen); - if(result) - goto out; - } - - if(rtspreq == RTSPREQ_SET_PARAMETER || - rtspreq == RTSPREQ_GET_PARAMETER) { - if(!Curl_checkheaders(data, STRCONST("Content-Type"))) { - result = curlx_dyn_addn(&req_buffer, - STRCONST("Content-Type: " - "text/parameters\r\n")); - if(result) - goto out; - } - } - - if(rtspreq == RTSPREQ_ANNOUNCE) { - if(!Curl_checkheaders(data, STRCONST("Content-Type"))) { - result = curlx_dyn_addn(&req_buffer, - STRCONST("Content-Type: " - "application/sdp\r\n")); - if(result) - goto out; - } - } - } - else if(rtspreq == RTSPREQ_GET_PARAMETER) { - /* Check for an empty GET_PARAMETER (heartbeat) request */ - data->state.httpreq = HTTPREQ_HEAD; - data->req.no_body = TRUE; - } - } - else { - result = Curl_creader_set_null(data); - if(result) - goto out; - } + result = rtsp_setup_body(data, rtspreq, &req_buffer); + if(result) + goto out; /* Finish the request buffer */ result = curlx_dyn_addn(&req_buffer, STRCONST("\r\n")); if(result) goto out; - Curl_xfer_setup1(data, CURL_XFER_SENDRECV, -1, TRUE); + Curl_xfer_setup_sendrecv(data, FIRSTSOCKET, -1); /* issue the request */ result = Curl_req_send(data, &req_buffer, httpversion); @@ -937,6 +947,14 @@ static CURLcode rtsp_rtp_write_resp(struct Curl_easy *data, return result; } +static CURLcode rtsp_rtp_write_resp_hd(struct Curl_easy *data, + const char *buf, + size_t blen, + bool is_eos) +{ + return rtsp_rtp_write_resp(data, buf, blen, is_eos); +} + static CURLcode rtp_client_write(struct Curl_easy *data, const char *ptr, size_t len) { diff --git a/deps/curl/lib/select.c b/deps/curl/lib/select.c index 2353c474df3..af78cb836b0 100644 --- a/deps/curl/lib/select.c +++ b/deps/curl/lib/select.c @@ -41,6 +41,7 @@ #include "urldata.h" #include "connect.h" #include "select.h" +#include "curl_trc.h" #include "curlx/timediff.h" #include "curlx/wait.h" #include "curlx/warnless.h" @@ -423,7 +424,7 @@ CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds, DEBUGASSERT(cpfds); DEBUGASSERT(ps); - for(i = 0; i < ps->num; i++) { + for(i = 0; i < ps->n; i++) { short events = 0; if(ps->actions[i] & CURL_POLL_IN) events |= POLLIN; @@ -481,7 +482,7 @@ unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds, DEBUGASSERT(cwfds); DEBUGASSERT(ps); - for(i = 0; i < ps->num; i++) { + for(i = 0; i < ps->n; i++) { short events = 0; if(ps->actions[i] & CURL_POLL_IN) events |= CURL_WAIT_POLLIN; @@ -492,3 +493,233 @@ unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds, } return need; } + +void Curl_pollset_reset(struct easy_pollset *ps) +{ + unsigned int i; + ps->n = 0; +#ifdef DEBUGBUILD + DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC); +#endif + DEBUGASSERT(ps->count); + for(i = 0; i < ps->count; i++) + ps->sockets[i] = CURL_SOCKET_BAD; + memset(ps->actions, 0, ps->count * sizeof(ps->actions[0])); +} + +void Curl_pollset_init(struct easy_pollset *ps) +{ +#ifdef DEBUGBUILD + ps->init = CURL_EASY_POLLSET_MAGIC; +#endif + ps->sockets = ps->def_sockets; + ps->actions = ps->def_actions; + ps->count = CURL_ARRAYSIZE(ps->def_sockets); + ps->n = 0; + Curl_pollset_reset(ps); +} + +struct easy_pollset *Curl_pollset_create(void) +{ + struct easy_pollset *ps = calloc(1, sizeof(*ps)); + if(ps) + Curl_pollset_init(ps); + return ps; +} + +void Curl_pollset_cleanup(struct easy_pollset *ps) +{ +#ifdef DEBUGBUILD + DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC); +#endif + if(ps->sockets != ps->def_sockets) { + free(ps->sockets); + ps->sockets = ps->def_sockets; + } + if(ps->actions != ps->def_actions) { + free(ps->actions); + ps->actions = ps->def_actions; + } + ps->count = CURL_ARRAYSIZE(ps->def_sockets); + Curl_pollset_reset(ps); +} + +void Curl_pollset_move(struct easy_pollset *to, struct easy_pollset *from) +{ + Curl_pollset_cleanup(to); /* deallocate anything in to */ + if(from->sockets != from->def_sockets) { + DEBUGASSERT(from->actions != from->def_actions); + to->sockets = from->sockets; + to->actions = from->actions; + to->count = from->count; + to->n = from->n; + Curl_pollset_init(from); + } + else { + DEBUGASSERT(to->sockets == to->def_sockets); + DEBUGASSERT(to->actions == to->def_actions); + memcpy(to->sockets, from->sockets, to->count * sizeof(to->sockets[0])); + memcpy(to->actions, from->actions, to->count * sizeof(to->actions[0])); + to->n = from->n; + Curl_pollset_init(from); + } +} + +/** + * + */ +CURLcode Curl_pollset_change(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + int add_flags, int remove_flags) +{ + unsigned int i; + +#ifdef DEBUGBUILD + DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC); +#endif + + (void)data; + DEBUGASSERT(VALID_SOCK(sock)); + if(!VALID_SOCK(sock)) + return CURLE_BAD_FUNCTION_ARGUMENT; + + DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT)); + DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT)); + DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */ + for(i = 0; i < ps->n; ++i) { + if(ps->sockets[i] == sock) { + ps->actions[i] &= (unsigned char)(~remove_flags); + ps->actions[i] |= (unsigned char)add_flags; + /* all gone? remove socket */ + if(!ps->actions[i]) { + if((i + 1) < ps->n) { + memmove(&ps->sockets[i], &ps->sockets[i + 1], + (ps->n - (i + 1)) * sizeof(ps->sockets[0])); + memmove(&ps->actions[i], &ps->actions[i + 1], + (ps->n - (i + 1)) * sizeof(ps->actions[0])); + } + --ps->n; + } + return CURLE_OK; + } + } + /* not present */ + if(add_flags) { + if(i >= ps->count) { /* need to grow */ + unsigned int new_count = CURLMAX(ps->count * 2, 8); + curl_socket_t *nsockets; + unsigned char *nactions; + + CURL_TRC_M(data, "growing pollset capacity from %u to %u", + ps->count, new_count); + if(new_count <= ps->count) + return CURLE_OUT_OF_MEMORY; + nsockets = calloc(new_count, sizeof(nsockets[0])); + if(!nsockets) + return CURLE_OUT_OF_MEMORY; + nactions = calloc(new_count, sizeof(nactions[0])); + if(!nactions) { + free(nsockets); + return CURLE_OUT_OF_MEMORY; + } + memcpy(nsockets, ps->sockets, ps->count * sizeof(ps->sockets[0])); + memcpy(nactions, ps->actions, ps->count * sizeof(ps->actions[0])); + if(ps->sockets != ps->def_sockets) + free(ps->sockets); + ps->sockets = nsockets; + if(ps->actions != ps->def_actions) + free(ps->actions); + ps->actions = nactions; + ps->count = new_count; + } + DEBUGASSERT(i < ps->count); + if(i < ps->count) { + ps->sockets[i] = sock; + ps->actions[i] = (unsigned char)add_flags; + ps->n = i + 1; + } + } + return CURLE_OK; +} + +CURLcode Curl_pollset_set(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + bool do_in, bool do_out) +{ + return Curl_pollset_change(data, ps, sock, + (do_in ? CURL_POLL_IN : 0)| + (do_out ? CURL_POLL_OUT : 0), + (!do_in ? CURL_POLL_IN : 0)| + (!do_out ? CURL_POLL_OUT : 0)); +} + +int Curl_pollset_poll(struct Curl_easy *data, + struct easy_pollset *ps, + timediff_t timeout_ms) +{ + struct pollfd *pfds; + unsigned int i, npfds; + int result; + + (void)data; + DEBUGASSERT(data); + DEBUGASSERT(data->conn); + + if(!ps->n) + return curlx_wait_ms(timeout_ms); + + pfds = calloc(ps->n, sizeof(*pfds)); + if(!pfds) + return -1; + + npfds = 0; + for(i = 0; i < ps->n; ++i) { + short events = 0; + if(ps->actions[i] & CURL_POLL_IN) { + events |= POLLIN; + } + if(ps->actions[i] & CURL_POLL_OUT) { + events |= POLLOUT; + } + if(events) { + pfds[npfds].fd = ps->sockets[i]; + pfds[npfds].events = events; + ++npfds; + } + } + + result = Curl_poll(pfds, npfds, timeout_ms); + free(pfds); + return result; +} + +void Curl_pollset_check(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + bool *pwant_read, bool *pwant_write) +{ + unsigned int i; + + (void)data; + DEBUGASSERT(VALID_SOCK(sock)); + for(i = 0; i < ps->n; ++i) { + if(ps->sockets[i] == sock) { + *pwant_read = !!(ps->actions[i] & CURL_POLL_IN); + *pwant_write = !!(ps->actions[i] & CURL_POLL_OUT); + return; + } + } + *pwant_read = *pwant_write = FALSE; +} + +bool Curl_pollset_want_read(struct Curl_easy *data, + struct easy_pollset *ps, + curl_socket_t sock) +{ + unsigned int i; + (void)data; + for(i = 0; i < ps->n; ++i) { + if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN)) + return TRUE; + } + return FALSE; +} diff --git a/deps/curl/lib/select.h b/deps/curl/lib/select.h index e9cec600f3b..47cdd31267f 100644 --- a/deps/curl/lib/select.h +++ b/deps/curl/lib/select.h @@ -110,6 +110,90 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms); } while(0) #endif + +/* Keep the sockets to poll for an easy handle. + * `actions` are bitmaps of CURL_POLL_IN and CURL_POLL_OUT. + * Starts with small capacity, grows on demand. + */ +#define EZ_POLLSET_DEF_COUNT 2 + +struct easy_pollset { + curl_socket_t *sockets; + unsigned char *actions; + unsigned int n; + unsigned int count; +#ifdef DEBUGBUILD + int init; +#endif + curl_socket_t def_sockets[EZ_POLLSET_DEF_COUNT]; + unsigned char def_actions[EZ_POLLSET_DEF_COUNT]; +}; + +#ifdef DEBUGBUILD +#define CURL_EASY_POLLSET_MAGIC 0x7a657370 +#endif + + +/* allocate and initialise */ +struct easy_pollset *Curl_pollset_create(void); + +/* Initialize before first use */ +void Curl_pollset_init(struct easy_pollset *ps); +/* Free any allocated resources */ +void Curl_pollset_cleanup(struct easy_pollset *ps); +/* Reset to an empty pollset */ +void Curl_pollset_reset(struct easy_pollset *ps); +/* Move pollset from to pollset to, replacing all in to, + * leaving from empty. */ +void Curl_pollset_move(struct easy_pollset *to, struct easy_pollset *from); + +/* Change the poll flags (CURL_POLL_IN/CURL_POLL_OUT) to the poll set for + * socket `sock`. If the socket is not already part of the poll set, it + * will be added. + * If the socket is present and all poll flags are cleared, it will be removed. + */ +CURLcode Curl_pollset_change(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + int add_flags, int remove_flags); + +CURLcode Curl_pollset_set(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + bool do_in, bool do_out); + +#define Curl_pollset_add_in(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), CURL_POLL_IN, 0) +#define Curl_pollset_add_out(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), CURL_POLL_OUT, 0) +#define Curl_pollset_add_inout(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), \ + CURL_POLL_IN|CURL_POLL_OUT, 0) +#define Curl_pollset_set_in_only(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), \ + CURL_POLL_IN, CURL_POLL_OUT) +#define Curl_pollset_set_out_only(data, ps, sock) \ + Curl_pollset_change((data), (ps), (sock), \ + CURL_POLL_OUT, CURL_POLL_IN) + +/* return < = on error, 0 on timeout or how many sockets are ready */ +int Curl_pollset_poll(struct Curl_easy *data, + struct easy_pollset *ps, + timediff_t timeout_ms); + +/** + * Check if the pollset, as is, wants to read and/or write regarding + * the given socket. + */ +void Curl_pollset_check(struct Curl_easy *data, + struct easy_pollset *ps, curl_socket_t sock, + bool *pwant_read, bool *pwant_write); + +/** + * Return TRUE if the pollset contains socket with CURL_POLL_IN. + */ +bool Curl_pollset_want_read(struct Curl_easy *data, + struct easy_pollset *ps, + curl_socket_t sock); + struct curl_pollfds { struct pollfd *pfds; unsigned int n; diff --git a/deps/curl/lib/sendf.c b/deps/curl/lib/sendf.c index 339a8773b47..551bb5ca81a 100644 --- a/deps/curl/lib/sendf.c +++ b/deps/curl/lib/sendf.c @@ -151,7 +151,7 @@ CURLcode Curl_client_start(struct Curl_easy *data) CURL_TRC_READ(data, "client start, rewind readers"); while(r) { - result = r->crt->rewind(data, r); + result = r->crt->cntrl(data, r, CURL_CRCNTRL_REWIND); if(result) { failf(data, "rewind of client reader '%s' failed: %d", r->crt->name, result); @@ -203,8 +203,8 @@ CURLcode Curl_cwriter_def_write(struct Curl_easy *data, void Curl_cwriter_def_close(struct Curl_easy *data, struct Curl_cwriter *writer) { - (void) data; - (void) writer; + (void)data; + (void)writer; } static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit) @@ -218,15 +218,15 @@ static size_t get_max_body_write_len(struct Curl_easy *data, curl_off_t limit) return 0; } #if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T - else if(remain_diff > SSIZE_T_MAX) { - return SIZE_T_MAX; + else if(remain_diff > SSIZE_MAX) { + return SIZE_MAX; } #endif else { return (size_t)remain_diff; } } - return SIZE_T_MAX; + return SIZE_MAX; } struct cw_download_ctx { @@ -281,7 +281,7 @@ static CURLcode cw_download_write(struct Curl_easy *data, * This gives deterministic BODY writes on varying buffer receive * lengths. */ nwrite = nbytes; - if(-1 != data->req.maxdownload) { + if(data->req.maxdownload != -1) { size_t wmax = get_max_body_write_len(data, data->req.maxdownload); if(nwrite > wmax) { excess_len = nbytes - wmax; @@ -293,9 +293,9 @@ static CURLcode cw_download_write(struct Curl_easy *data, } if((type & CLIENTWRITE_EOS) && !data->req.no_body && - (data->req.maxdownload > data->req.bytecount)) { + (data->req.size > data->req.bytecount)) { failf(data, "end of response with %" FMT_OFF_T " bytes missing", - data->req.maxdownload - data->req.bytecount); + data->req.size - data->req.bytecount); return CURLE_PARTIAL_FILE; } } @@ -543,6 +543,15 @@ CURLcode Curl_creader_read(struct Curl_easy *data, return reader->crt->do_read(data, reader, buf, blen, nread, eos); } +void Curl_creader_clear_eos(struct Curl_easy *data, + struct Curl_creader *reader) +{ + while(reader) { + (void)reader->crt->cntrl(data, reader, CURL_CRCNTRL_CLEAR_EOS); + reader = reader->next; + } +} + CURLcode Curl_creader_def_init(struct Curl_easy *data, struct Curl_creader *reader) { @@ -598,19 +607,13 @@ CURLcode Curl_creader_def_resume_from(struct Curl_easy *data, return CURLE_READ_ERROR; } -CURLcode Curl_creader_def_rewind(struct Curl_easy *data, - struct Curl_creader *reader) -{ - (void)data; - (void)reader; - return CURLE_OK; -} - -CURLcode Curl_creader_def_unpause(struct Curl_easy *data, - struct Curl_creader *reader) +CURLcode Curl_creader_def_cntrl(struct Curl_easy *data, + struct Curl_creader *reader, + Curl_creader_cntrl opcode) { (void)data; (void)reader; + (void)opcode; return CURLE_OK; } @@ -879,7 +882,7 @@ static CURLcode cr_in_rewind(struct Curl_easy *data, int err = fseek(data->state.in, 0, SEEK_SET); CURL_TRC_READ(data, "cr_in, rewind via fseek -> %d(%d)", (int)err, (int)errno); - if(-1 != err) + if(err != -1) /* successful rewind */ return CURLE_OK; } @@ -891,12 +894,24 @@ static CURLcode cr_in_rewind(struct Curl_easy *data, return CURLE_OK; } -static CURLcode cr_in_unpause(struct Curl_easy *data, - struct Curl_creader *reader) +static CURLcode cr_in_cntrl(struct Curl_easy *data, + struct Curl_creader *reader, + Curl_creader_cntrl opcode) { struct cr_in_ctx *ctx = reader->ctx; - (void)data; - ctx->is_paused = FALSE; + + switch(opcode) { + case CURL_CRCNTRL_REWIND: + return cr_in_rewind(data, reader); + case CURL_CRCNTRL_UNPAUSE: + ctx->is_paused = FALSE; + break; + case CURL_CRCNTRL_CLEAR_EOS: + ctx->seen_eos = FALSE; + break; + default: + break; + } return CURLE_OK; } @@ -916,8 +931,7 @@ static const struct Curl_crtype cr_in = { cr_in_needs_rewind, cr_in_total_length, cr_in_resume_from, - cr_in_rewind, - cr_in_unpause, + cr_in_cntrl, cr_in_is_paused, Curl_creader_def_done, sizeof(struct cr_in_ctx) @@ -1077,8 +1091,7 @@ static const struct Curl_crtype cr_lc = { Curl_creader_def_needs_rewind, cr_lc_total_length, Curl_creader_def_resume_from, - Curl_creader_def_rewind, - Curl_creader_def_unpause, + Curl_creader_def_cntrl, Curl_creader_def_is_paused, Curl_creader_def_done, sizeof(struct cr_lc_ctx) @@ -1251,8 +1264,7 @@ static const struct Curl_crtype cr_null = { Curl_creader_def_needs_rewind, cr_null_total_length, Curl_creader_def_resume_from, - Curl_creader_def_rewind, - Curl_creader_def_unpause, + Curl_creader_def_cntrl, Curl_creader_def_is_paused, Curl_creader_def_done, sizeof(struct Curl_creader) @@ -1312,12 +1324,19 @@ static bool cr_buf_needs_rewind(struct Curl_easy *data, return ctx->index > 0; } -static CURLcode cr_buf_rewind(struct Curl_easy *data, - struct Curl_creader *reader) +static CURLcode cr_buf_cntrl(struct Curl_easy *data, + struct Curl_creader *reader, + Curl_creader_cntrl opcode) { struct cr_buf_ctx *ctx = reader->ctx; (void)data; - ctx->index = 0; + switch(opcode) { + case CURL_CRCNTRL_REWIND: + ctx->index = 0; + break; + default: + break; + } return CURLE_OK; } @@ -1360,8 +1379,7 @@ static const struct Curl_crtype cr_buf = { cr_buf_needs_rewind, cr_buf_total_length, cr_buf_resume_from, - cr_buf_rewind, - Curl_creader_def_unpause, + cr_buf_cntrl, Curl_creader_def_is_paused, Curl_creader_def_done, sizeof(struct cr_buf_ctx) @@ -1417,7 +1435,7 @@ CURLcode Curl_creader_unpause(struct Curl_easy *data) CURLcode result = CURLE_OK; while(reader) { - result = reader->crt->unpause(data, reader); + result = reader->crt->cntrl(data, reader, CURL_CRCNTRL_UNPAUSE); if(result) break; reader = reader->next; diff --git a/deps/curl/lib/sendf.h b/deps/curl/lib/sendf.h index e5cc600bfe5..68674439010 100644 --- a/deps/curl/lib/sendf.h +++ b/deps/curl/lib/sendf.h @@ -50,6 +50,7 @@ #define CLIENTWRITE_1XX (1<<5) /* a 1xx response related HEADER */ #define CLIENTWRITE_TRAILER (1<<6) /* a trailer HEADER */ #define CLIENTWRITE_EOS (1<<7) /* End Of transfer download Stream */ +#define CLIENTWRITE_0LEN (1<<8) /* write even 0-length buffers */ /** * Write `len` bytes at `prt` to the client. `type` indicates what @@ -202,6 +203,11 @@ void Curl_cwriter_def_close(struct Curl_easy *data, struct Curl_cwriter *writer); +typedef enum { + CURL_CRCNTRL_REWIND, + CURL_CRCNTRL_UNPAUSE, + CURL_CRCNTRL_CLEAR_EOS +} Curl_creader_cntrl; /* Client Reader Type, provides the implementation */ struct Curl_crtype { @@ -215,8 +221,8 @@ struct Curl_crtype { struct Curl_creader *reader); CURLcode (*resume_from)(struct Curl_easy *data, struct Curl_creader *reader, curl_off_t offset); - CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader); - CURLcode (*unpause)(struct Curl_easy *data, struct Curl_creader *reader); + CURLcode (*cntrl)(struct Curl_easy *data, struct Curl_creader *reader, + Curl_creader_cntrl opcode); bool (*is_paused)(struct Curl_easy *data, struct Curl_creader *reader); void (*done)(struct Curl_easy *data, struct Curl_creader *reader, int premature); @@ -264,10 +270,9 @@ curl_off_t Curl_creader_def_total_length(struct Curl_easy *data, CURLcode Curl_creader_def_resume_from(struct Curl_easy *data, struct Curl_creader *reader, curl_off_t offset); -CURLcode Curl_creader_def_rewind(struct Curl_easy *data, - struct Curl_creader *reader); -CURLcode Curl_creader_def_unpause(struct Curl_easy *data, - struct Curl_creader *reader); +CURLcode Curl_creader_def_cntrl(struct Curl_easy *data, + struct Curl_creader *reader, + Curl_creader_cntrl opcode); bool Curl_creader_def_is_paused(struct Curl_easy *data, struct Curl_creader *reader); void Curl_creader_def_done(struct Curl_easy *data, @@ -281,6 +286,10 @@ CURLcode Curl_creader_read(struct Curl_easy *data, struct Curl_creader *reader, char *buf, size_t blen, size_t *nread, bool *eos); +/* Tell the reader and all below that any EOS state is to be cleared */ +void Curl_creader_clear_eos(struct Curl_easy *data, + struct Curl_creader *reader); + /** * Create a new creader instance with given type and phase. Is not * inserted into the writer chain by this call. diff --git a/deps/curl/lib/setopt.c b/deps/curl/lib/setopt.c index 1380c33db6f..5adfe4dbebb 100644 --- a/deps/curl/lib/setopt.c +++ b/deps/curl/lib/setopt.c @@ -60,7 +60,6 @@ #include "curl_memory.h" #include "memdebug.h" - static CURLcode setopt_set_timeout_sec(timediff_t *ptimeout_ms, long secs) { if(secs < 0) @@ -327,8 +326,8 @@ static CURLcode setopt_HTTP_VERSION(struct Curl_easy *data, long arg) #endif /* ! CURL_DISABLE_HTTP */ #ifdef USE_SSL -static CURLcode setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, - long arg) +CURLcode Curl_setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, + long arg) { /* * Set explicit SSL version to try to connect with, as some SSL @@ -353,6 +352,8 @@ static CURLcode setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, version_max < CURL_SSLVERSION_MAX_NONE || version_max >= CURL_SSLVERSION_MAX_LAST) return CURLE_BAD_FUNCTION_ARGUMENT; + if(version == CURL_SSLVERSION_DEFAULT) + version = CURL_SSLVERSION_TLSv1_2; primary->version = (unsigned char)version; primary->version_max = (unsigned int)version_max; @@ -438,67 +439,38 @@ static void set_ssl_options(struct ssl_config_data *ssl, } #endif -static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, - long arg) +static CURLcode setopt_bool(struct Curl_easy *data, CURLoption option, + long arg, bool *set) { - bool enabled = (0 != arg); - unsigned long uarg = (unsigned long)arg; + bool enabled = !!arg; + struct UserDefined *s = &data->set; switch(option) { - case CURLOPT_DNS_CACHE_TIMEOUT: - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; - - data->set.dns_cache_timeout = (int)arg; - break; - case CURLOPT_CA_CACHE_TIMEOUT: - if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) { - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; - - data->set.general_ssl.ca_cache_timeout = (int)arg; - } - else - return CURLE_NOT_BUILT_IN; - break; - case CURLOPT_MAXCONNECTS: - /* - * Set the absolute number of maximum simultaneous alive connection that - * libcurl is allowed to have. - */ - if(uarg > UINT_MAX) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.maxconnects = (unsigned int)uarg; - break; case CURLOPT_FORBID_REUSE: /* * When this transfer is done, it must not be left to be reused by a * subsequent transfer but shall be closed immediately. */ - data->set.reuse_forbid = enabled; + s->reuse_forbid = enabled; break; case CURLOPT_FRESH_CONNECT: /* * This transfer shall not use a previously cached connection but * should be made with a fresh new connect! */ - data->set.reuse_fresh = enabled; + s->reuse_fresh = enabled; break; case CURLOPT_VERBOSE: /* * Verbose means infof() calls that give a lot of information about * the connection and transfer procedures as well as internal choices. */ - data->set.verbose = enabled; + s->verbose = enabled; break; case CURLOPT_HEADER: /* * Set to include the header in the general data output stream. */ - data->set.include_header = enabled; + s->include_header = enabled; break; case CURLOPT_NOPROGRESS: /* @@ -510,13 +482,13 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, /* * Do not include the body part in the output data stream. */ - data->set.opt_no_body = enabled; + s->opt_no_body = enabled; #ifndef CURL_DISABLE_HTTP - if(data->set.opt_no_body) + if(s->opt_no_body) /* in HTTP lingo, no body means using the HEAD request... */ - data->set.method = HTTPREQ_HEAD; - else if(data->set.method == HTTPREQ_HEAD) - data->set.method = HTTPREQ_GET; + s->method = HTTPREQ_HEAD; + else if(s->method == HTTPREQ_HEAD) + s->method = HTTPREQ_GET; #endif break; case CURLOPT_FAILONERROR: @@ -524,10 +496,10 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, * Do not output the >=400 error code HTML-page, but instead only * return error. */ - data->set.http_fail_on_error = enabled; + s->http_fail_on_error = enabled; break; case CURLOPT_KEEP_SENDING_ON_ERROR: - data->set.http_keep_sending_on_error = enabled; + s->http_keep_sending_on_error = enabled; break; case CURLOPT_UPLOAD: case CURLOPT_PUT: @@ -535,119 +507,27 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, * We want to sent data to the remote host. If this is HTTP, that equals * using the PUT request. */ - if(arg) { + if(enabled) { /* If this is HTTP, PUT is what's needed to "upload" */ - data->set.method = HTTPREQ_PUT; - data->set.opt_no_body = FALSE; /* this is implied */ + s->method = HTTPREQ_PUT; + s->opt_no_body = FALSE; /* this is implied */ } else /* In HTTP, the opposite of upload is GET (unless NOBODY is true as then this can be changed to HEAD later on) */ - data->set.method = HTTPREQ_GET; + s->method = HTTPREQ_GET; break; case CURLOPT_FILETIME: /* * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ - data->set.get_filetime = enabled; - break; - case CURLOPT_SERVER_RESPONSE_TIMEOUT: - /* - * Option that specifies how quickly a server response must be obtained - * before it is considered failure. For pingpong protocols. - */ - return setopt_set_timeout_sec(&data->set.server_response_timeout, arg); - - case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: - /* - * Option that specifies how quickly a server response must be obtained - * before it is considered failure. For pingpong protocols. - */ - return setopt_set_timeout_ms(&data->set.server_response_timeout, arg); - -#ifndef CURL_DISABLE_TFTP - case CURLOPT_TFTP_NO_OPTIONS: - /* - * Option that prevents libcurl from sending TFTP option requests to the - * server. - */ - data->set.tftp_no_options = enabled; - break; - case CURLOPT_TFTP_BLKSIZE: - /* - * TFTP option that specifies the block size to use for data transmission. - */ - if(arg < TFTP_BLKSIZE_MIN) - arg = 512; - else if(arg > TFTP_BLKSIZE_MAX) - arg = TFTP_BLKSIZE_MAX; - data->set.tftp_blksize = arg; - break; -#endif -#ifndef CURL_DISABLE_NETRC - case CURLOPT_NETRC: - /* - * Parse the $HOME/.netrc file - */ - if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.use_netrc = (unsigned char)arg; - break; -#endif - case CURLOPT_TRANSFERTEXT: - /* - * This option was previously named 'FTPASCII'. Renamed to work with - * more protocols than merely FTP. - * - * Transfer using ASCII (instead of BINARY). - */ - data->set.prefer_ascii = enabled; - break; - case CURLOPT_TIMECONDITION: - /* - * Set HTTP time condition. This must be one of the defines in the - * curl/curl.h header file. - */ - if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.timecondition = (unsigned char)arg; - break; - case CURLOPT_TIMEVALUE: - /* - * This is the value to compare with the remote document with the - * method set with CURLOPT_TIMECONDITION - */ - data->set.timevalue = (time_t)arg; - break; - case CURLOPT_SSLVERSION: -#ifndef CURL_DISABLE_PROXY - case CURLOPT_PROXY_SSLVERSION: -#endif -#ifdef USE_SSL - return setopt_SSLVERSION(data, option, arg); -#else - return CURLE_NOT_BUILT_IN; -#endif - - case CURLOPT_POSTFIELDSIZE: - /* - * The size of the POSTFIELD data to prevent libcurl to do strlen() to - * figure it out. Enables binary posts. - */ - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - - if(data->set.postfieldsize < arg && - data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { - /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ - Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]); - data->set.postfields = NULL; - } - - data->set.postfieldsize = arg; + s->get_filetime = enabled; break; #ifndef CURL_DISABLE_HTTP + case CURLOPT_HTTP09_ALLOWED: + s->http09_allowed = enabled; + break; #if !defined(CURL_DISABLE_COOKIES) case CURLOPT_COOKIESESSION: /* @@ -656,171 +536,80 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, * cookies that are marked as being session cookies, as they belong to a * previous session. */ - data->set.cookiesession = enabled; + s->cookiesession = enabled; break; #endif case CURLOPT_AUTOREFERER: /* * Switch on automatic referer that gets set if curl follows locations. */ - data->set.http_auto_referer = enabled; + s->http_auto_referer = enabled; break; case CURLOPT_TRANSFER_ENCODING: - data->set.http_transfer_encoding = enabled; - break; - - case CURLOPT_FOLLOWLOCATION: - /* - * Follow Location: header hints on an HTTP-server. - */ - if(uarg > 3) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.http_follow_mode = (unsigned char)uarg; + s->http_transfer_encoding = enabled; break; - case CURLOPT_UNRESTRICTED_AUTH: /* * Send authentication (user+password) when following locations, even when * hostname changed. */ - data->set.allow_auth_to_other_hosts = enabled; - break; - - case CURLOPT_MAXREDIRS: - /* - * The maximum amount of hops you allow curl to follow Location: - * headers. This should mostly be used to detect never-ending loops. - */ - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.maxredirs = arg; + s->allow_auth_to_other_hosts = enabled; break; - case CURLOPT_POSTREDIR: + case CURLOPT_HTTP_TRANSFER_DECODING: /* - * 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 - * CURL_REDIR_POST_303 - POST is kept as POST after 303 - * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303 - * other - POST is kept as POST after 301 and 302 + * disable libcurl transfer encoding is used */ - if(arg < CURL_REDIR_GET_ALL) - /* no return error on too high numbers since the bitmask could be - extended in a future */ - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.keep_post = arg & CURL_REDIR_POST_ALL; + s->http_te_skip = !enabled; /* reversed */ break; - case CURLOPT_POST: - /* Does this option serve a purpose anymore? Yes it does, when - CURLOPT_POSTFIELDS is not used and the POST data is read off the - callback! */ - if(arg) { - data->set.method = HTTPREQ_POST; - data->set.opt_no_body = FALSE; /* this is implied */ - } - else - data->set.method = HTTPREQ_GET; - break; - case CURLOPT_HEADEROPT: + case CURLOPT_HTTP_CONTENT_DECODING: /* - * Set header option. + * raw data passed to the application when content encoding is used */ - data->set.sep_headers = !!(arg & CURLHEADER_SEPARATE); + s->http_ce_skip = !enabled; /* reversed */ break; - case CURLOPT_HTTPAUTH: - return httpauth(data, FALSE, uarg); case CURLOPT_HTTPGET: /* * Set to force us do HTTP GET */ if(enabled) { - data->set.method = HTTPREQ_GET; - data->set.opt_no_body = FALSE; /* this is implied */ + s->method = HTTPREQ_GET; + s->opt_no_body = FALSE; /* this is implied */ } break; - - case CURLOPT_HTTP_VERSION: - return setopt_HTTP_VERSION(data, arg); - - case CURLOPT_EXPECT_100_TIMEOUT_MS: - /* - * Time to wait for a response to an HTTP request containing an - * Expect: 100-continue header before sending the data anyway. - */ - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.expect_100_timeout = arg; - break; - - case CURLOPT_HTTP09_ALLOWED: - data->set.http09_allowed = enabled; + case CURLOPT_POST: + /* Does this option serve a purpose anymore? Yes it does, when + CURLOPT_POSTFIELDS is not used and the POST data is read off the + callback! */ + if(enabled) { + s->method = HTTPREQ_POST; + s->opt_no_body = FALSE; /* this is implied */ + } + else + s->method = HTTPREQ_GET; break; #endif /* ! CURL_DISABLE_HTTP */ - -#ifndef CURL_DISABLE_MIME - case CURLOPT_MIME_OPTIONS: - data->set.mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE); - break; -#endif #ifndef CURL_DISABLE_PROXY case CURLOPT_HTTPPROXYTUNNEL: /* * Tunnel operations through the proxy instead of normal proxy use */ - data->set.tunnel_thru_httpproxy = enabled; - break; - - case CURLOPT_PROXYPORT: - /* - * Explicitly set HTTP proxy port number. - */ - if((arg < 0) || (arg > 65535)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.proxyport = (unsigned short)arg; - break; - - case CURLOPT_PROXYAUTH: - return httpauth(data, TRUE, uarg); - - case CURLOPT_PROXYTYPE: - /* - * Set proxy type. - */ - if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.proxytype = (unsigned char)(curl_proxytype)arg; - break; - - case CURLOPT_PROXY_TRANSFER_MODE: - /* - * set transfer mode (;type=) when doing FTP via an HTTP proxy - */ - if(uarg > 1) - /* reserve other values for future use */ - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.proxy_transfer_mode = (bool)uarg; - break; - case CURLOPT_SOCKS5_AUTH: - if(uarg & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) - return CURLE_NOT_BUILT_IN; - data->set.socks5auth = (unsigned char)uarg; + s->tunnel_thru_httpproxy = enabled; break; case CURLOPT_HAPROXYPROTOCOL: /* * Set to send the HAProxy Proxy Protocol header */ - data->set.haproxyprotocol = enabled; + s->haproxyprotocol = enabled; break; case CURLOPT_PROXY_SSL_VERIFYPEER: /* * Enable peer SSL verifying for proxy. */ - data->set.proxy_ssl.primary.verifypeer = enabled; + s->proxy_ssl.primary.verifypeer = enabled; /* Update the current connection proxy_ssl_config. */ Curl_ssl_conn_config_update(data, TRUE); @@ -829,19 +618,24 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, /* * Enable verification of the hostname in the peer certificate for proxy */ - data->set.proxy_ssl.primary.verifyhost = enabled; + s->proxy_ssl.primary.verifyhost = enabled; /* Update the current connection proxy_ssl_config. */ Curl_ssl_conn_config_update(data, TRUE); break; + case CURLOPT_PROXY_TRANSFER_MODE: + /* + * set transfer mode (;type=) when doing FTP via an HTTP proxy + */ + s->proxy_transfer_mode = enabled; + break; #endif /* ! CURL_DISABLE_PROXY */ - #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) case CURLOPT_SOCKS5_GSSAPI_NEC: /* * Set flag for NEC SOCK5 support */ - data->set.socks5_gssapi_nec = enabled; + s->socks5_gssapi_nec = enabled; break; #endif #ifdef CURL_LIST_ONLY_PROTOCOL @@ -850,7 +644,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, * An option that changes the command to one that asks for a list only, no * file info details. Used for FTP, POP3 and SFTP. */ - data->set.list_only = enabled; + s->list_only = enabled; break; #endif case CURLOPT_APPEND: @@ -858,202 +652,86 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, * We want to upload and append to an existing file. Used for FTP and * SFTP. */ - data->set.remote_append = enabled; + s->remote_append = enabled; break; - #ifndef CURL_DISABLE_FTP - case CURLOPT_FTP_FILEMETHOD: - /* - * How do access files over FTP. - */ - if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ftp_filemethod = (unsigned char)arg; - break; case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = enabled; + s->ftp_use_eprt = enabled; break; case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = enabled; + s->ftp_use_epsv = enabled; break; case CURLOPT_FTP_USE_PRET: - data->set.ftp_use_pret = enabled; - break; - - case CURLOPT_FTP_SSL_CCC: - if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ftp_ccc = (unsigned char)arg; + s->ftp_use_pret = enabled; break; - case CURLOPT_FTP_SKIP_PASV_IP: /* * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the * bypass of the IP address in PASV responses. */ - data->set.ftp_skip_ip = enabled; + s->ftp_skip_ip = enabled; break; - - case CURLOPT_FTPSSLAUTH: - /* - * Set a specific auth for FTP-SSL transfers. - */ - if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ftpsslauth = (unsigned char)(curl_ftpauth)arg; + case CURLOPT_WILDCARDMATCH: + s->wildcard_enabled = enabled; break; - case CURLOPT_ACCEPTTIMEOUT_MS: +#endif + case CURLOPT_CRLF: /* - * The maximum time for curl to wait for FTP server connect + * Kludgy option to enable CRLF conversions. Subject for removal. */ - return setopt_set_timeout_ms(&data->set.accepttimeout, arg); - - case CURLOPT_WILDCARDMATCH: - data->set.wildcard_enabled = enabled; + s->crlf = enabled; break; -#endif /* ! CURL_DISABLE_FTP */ -#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) - case CURLOPT_FTP_CREATE_MISSING_DIRS: + +#ifndef CURL_DISABLE_TFTP + case CURLOPT_TFTP_NO_OPTIONS: /* - * An FTP/SFTP option that modifies an upload to create missing - * directories on the server. + * Option that prevents libcurl from sending TFTP option requests to the + * server. */ - /* reserve other values for future use */ - if((arg < CURLFTP_CREATE_DIR_NONE) || (arg > CURLFTP_CREATE_DIR_RETRY)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ftp_create_missing_dirs = (unsigned char)arg; + s->tftp_no_options = enabled; break; -#endif /* ! CURL_DISABLE_FTP || USE_SSH */ - case CURLOPT_INFILESIZE: +#endif /* ! CURL_DISABLE_TFTP */ + case CURLOPT_TRANSFERTEXT: /* - * If known, this should inform curl about the file size of the - * to-be-uploaded file. + * This option was previously named 'FTPASCII'. Renamed to work with + * more protocols than merely FTP. + * + * Transfer using ASCII (instead of BINARY). */ - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.filesize = arg; + s->prefer_ascii = enabled; break; - case CURLOPT_LOW_SPEED_LIMIT: + case CURLOPT_SSL_VERIFYPEER: /* - * The low speed limit that if transfers are below this for - * CURLOPT_LOW_SPEED_TIME, the transfer is aborted. + * Enable peer SSL verifying. */ - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.low_speed_limit = arg; + s->ssl.primary.verifypeer = enabled; + + /* Update the current connection ssl_config. */ + Curl_ssl_conn_config_update(data, FALSE); break; - case CURLOPT_LOW_SPEED_TIME: +#ifndef CURL_DISABLE_DOH + case CURLOPT_DOH_SSL_VERIFYPEER: /* - * The low speed time that if transfers are below the set - * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted. + * Enable peer SSL verifying for DoH. */ - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.low_speed_time = arg; + s->doh_verifypeer = enabled; break; - case CURLOPT_PORT: + case CURLOPT_DOH_SSL_VERIFYHOST: /* - * The port number to use when getting the URL. 0 disables it. + * Enable verification of the hostname in the peer certificate for DoH */ - if((arg < 0) || (arg > 65535)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.use_port = (unsigned short)arg; + s->doh_verifyhost = enabled; break; - case CURLOPT_TIMEOUT: - /* - * The maximum time you allow curl to use for a single transfer - * operation. - */ - return setopt_set_timeout_sec(&data->set.timeout, arg); - - case CURLOPT_TIMEOUT_MS: - return setopt_set_timeout_ms(&data->set.timeout, arg); - - case CURLOPT_CONNECTTIMEOUT: - /* - * The maximum time you allow curl to use to connect. - */ - return setopt_set_timeout_sec(&data->set.connecttimeout, arg); - - case CURLOPT_CONNECTTIMEOUT_MS: - return setopt_set_timeout_ms(&data->set.connecttimeout, arg); - - case CURLOPT_RESUME_FROM: - /* - * Resume transfer at the given file position - */ - if(arg < -1) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.set_resume_from = arg; - break; - - case CURLOPT_CRLF: - /* - * Kludgy option to enable CRLF conversions. Subject for removal. - */ - data->set.crlf = enabled; - break; - -#ifndef CURL_DISABLE_BINDLOCAL - case CURLOPT_LOCALPORT: - /* - * Set what local port to bind the socket to when performing an operation. - */ - if((arg < 0) || (arg > 65535)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.localport = curlx_sltous(arg); - break; - case CURLOPT_LOCALPORTRANGE: - /* - * Set number of local ports to try, starting with CURLOPT_LOCALPORT. - */ - if((arg < 0) || (arg > 65535)) - return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.localportrange = curlx_sltous(arg); - break; -#endif - -#ifdef HAVE_GSSAPI - case CURLOPT_GSSAPI_DELEGATION: - /* - * GSS-API credential delegation bitmask - */ - data->set.gssapi_delegation = (unsigned char)uarg& - (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG); - break; -#endif - case CURLOPT_SSL_VERIFYPEER: - /* - * Enable peer SSL verifying. - */ - data->set.ssl.primary.verifypeer = enabled; - - /* Update the current connection ssl_config. */ - Curl_ssl_conn_config_update(data, FALSE); - break; -#ifndef CURL_DISABLE_DOH - case CURLOPT_DOH_SSL_VERIFYPEER: - /* - * Enable peer SSL verifying for DoH. - */ - data->set.doh_verifypeer = enabled; - break; - case CURLOPT_DOH_SSL_VERIFYHOST: - /* - * Enable verification of the hostname in the peer certificate for DoH - */ - data->set.doh_verifyhost = enabled; - break; - case CURLOPT_DOH_SSL_VERIFYSTATUS: + case CURLOPT_DOH_SSL_VERIFYSTATUS: /* * Enable certificate status verifying for DoH. */ if(!Curl_ssl_cert_status_request()) return CURLE_NOT_BUILT_IN; - data->set.doh_verifystatus = enabled; + s->doh_verifystatus = enabled; break; #endif /* ! CURL_DISABLE_DOH */ case CURLOPT_SSL_VERIFYHOST: @@ -1064,7 +742,7 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, /* Obviously people are not reading documentation and too many thought this argument took a boolean when it was not and misused it. Treat 1 and 2 the same */ - data->set.ssl.primary.verifyhost = enabled; + s->ssl.primary.verifyhost = enabled; /* Update the current connection ssl_config. */ Curl_ssl_conn_config_update(data, FALSE); @@ -1076,84 +754,383 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, if(!Curl_ssl_cert_status_request()) return CURLE_NOT_BUILT_IN; - data->set.ssl.primary.verifystatus = enabled; + s->ssl.primary.verifystatus = enabled; /* Update the current connection ssl_config. */ Curl_ssl_conn_config_update(data, FALSE); break; - case CURLOPT_SSL_FALSESTART: - /* - * No TLS backends support false start anymore. - */ - return CURLE_NOT_BUILT_IN; case CURLOPT_CERTINFO: #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_CERTINFO)) - data->set.ssl.certinfo = enabled; + s->ssl.certinfo = enabled; else #endif return CURLE_NOT_BUILT_IN; break; - case CURLOPT_BUFFERSIZE: + case CURLOPT_NOSIGNAL: /* - * The application kindly asks for a differently sized receive buffer. - * If it seems reasonable, we will use it. + * The application asks not to set any signal() or alarm() handlers, + * even when using a timeout. */ - if(arg > READBUFFER_MAX) - arg = READBUFFER_MAX; - else if(arg < 1) - arg = READBUFFER_SIZE; - else if(arg < READBUFFER_MIN) - arg = READBUFFER_MIN; - - data->set.buffer_size = (unsigned int)arg; + s->no_signal = enabled; break; - - case CURLOPT_UPLOAD_BUFFERSIZE: + case CURLOPT_TCP_NODELAY: /* - * The application kindly asks for a differently sized upload buffer. - * Cap it to sensible. + * Enable or disable TCP_NODELAY, which will disable/enable the Nagle + * algorithm */ - if(arg > UPLOADBUFFER_MAX) - arg = UPLOADBUFFER_MAX; - else if(arg < UPLOADBUFFER_MIN) - arg = UPLOADBUFFER_MIN; + s->tcp_nodelay = enabled; + break; + + case CURLOPT_IGNORE_CONTENT_LENGTH: + s->ignorecl = enabled; + break; + case CURLOPT_SSL_SESSIONID_CACHE: + s->ssl.primary.cache_session = enabled; +#ifndef CURL_DISABLE_PROXY + s->proxy_ssl.primary.cache_session = + s->ssl.primary.cache_session; +#endif + break; +#ifdef USE_SSH + case CURLOPT_SSH_COMPRESSION: + s->ssh_compression = enabled; + break; +#endif /* ! USE_SSH */ +#ifndef CURL_DISABLE_SMTP + case CURLOPT_MAIL_RCPT_ALLOWFAILS: + /* allow RCPT TO command to fail for some recipients */ + s->mail_rcpt_allowfails = enabled; + break; +#endif /* !CURL_DISABLE_SMTP */ + case CURLOPT_SASL_IR: + /* Enable/disable SASL initial response */ + s->sasl_ir = enabled; + break; + case CURLOPT_TCP_KEEPALIVE: + s->tcp_keepalive = enabled; + break; + case CURLOPT_TCP_FASTOPEN: +#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ + defined(TCP_FASTOPEN_CONNECT) + s->tcp_fastopen = enabled; +#else + return CURLE_NOT_BUILT_IN; +#endif + break; + case CURLOPT_SSL_ENABLE_ALPN: + s->ssl_enable_alpn = enabled; + break; + case CURLOPT_PATH_AS_IS: + s->path_as_is = enabled; + break; + case CURLOPT_PIPEWAIT: + s->pipewait = enabled; + break; + case CURLOPT_SUPPRESS_CONNECT_HEADERS: + s->suppress_connect_headers = enabled; + break; +#ifndef CURL_DISABLE_SHUFFLE_DNS + case CURLOPT_DNS_SHUFFLE_ADDRESSES: + s->dns_shuffle_addresses = enabled; + break; +#endif + case CURLOPT_DISALLOW_USERNAME_IN_URL: + s->disallow_username_in_url = enabled; + break; + case CURLOPT_QUICK_EXIT: + s->quick_exit = enabled; + break; + default: + return CURLE_OK; + } + if((arg > 1) || (arg < 0)) + /* reserve other values for future use */ + infof(data, "boolean setopt(%d) got unsupported argument %ld," + " treated as %d", option, arg, enabled); + + *set = TRUE; + return CURLE_OK; +} + +static CURLcode value_range(long *value, long below_error, long min, long max) +{ + if(*value < below_error) + return CURLE_BAD_FUNCTION_ARGUMENT; + else if(*value < min) + *value = min; + else if(*value > max) + *value = max; + return CURLE_OK; +} - data->set.upload_buffer_size = (unsigned int)arg; +static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, + long arg) +{ + unsigned long uarg = (unsigned long)arg; + bool set = FALSE; + CURLcode result = setopt_bool(data, option, arg, &set); + struct UserDefined *s = &data->set; + if(set || result) + return result; + + switch(option) { + case CURLOPT_DNS_CACHE_TIMEOUT: + return setopt_set_timeout_sec(&s->dns_cache_timeout_ms, arg); + + case CURLOPT_CA_CACHE_TIMEOUT: + if(Curl_ssl_supports(data, SSLSUPP_CA_CACHE)) { + result = value_range(&arg, -1, -1, INT_MAX); + if(result) + return result; + + s->general_ssl.ca_cache_timeout = (int)arg; + } + else + return CURLE_NOT_BUILT_IN; break; + case CURLOPT_MAXCONNECTS: + result = value_range(&arg, 1, 1, UINT_MAX); + if(result) + return result; + s->maxconnects = (unsigned int)arg; + break; + case CURLOPT_SERVER_RESPONSE_TIMEOUT: + return setopt_set_timeout_sec(&s->server_response_timeout, arg); - case CURLOPT_NOSIGNAL: - /* - * The application asks not to set any signal() or alarm() handlers, - * even when using a timeout. - */ - data->set.no_signal = enabled; + case CURLOPT_SERVER_RESPONSE_TIMEOUT_MS: + return setopt_set_timeout_ms(&s->server_response_timeout, arg); + +#ifndef CURL_DISABLE_TFTP + case CURLOPT_TFTP_BLKSIZE: + result = value_range(&arg, 0, TFTP_BLKSIZE_MIN, TFTP_BLKSIZE_MAX); + if(result) + return result; + s->tftp_blksize = (unsigned short)arg; + break; +#endif +#ifndef CURL_DISABLE_NETRC + case CURLOPT_NETRC: + if((arg < CURL_NETRC_IGNORED) || (arg >= CURL_NETRC_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->use_netrc = (unsigned char)arg; + break; +#endif + case CURLOPT_TIMECONDITION: + if((arg < CURL_TIMECOND_NONE) || (arg >= CURL_TIMECOND_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->timecondition = (unsigned char)arg; + break; + case CURLOPT_TIMEVALUE: + s->timevalue = (time_t)arg; + break; + case CURLOPT_SSLVERSION: +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXY_SSLVERSION: +#endif + return Curl_setopt_SSLVERSION(data, option, arg); + + case CURLOPT_POSTFIELDSIZE: + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + + if(s->postfieldsize < arg && + s->postfields == s->str[STRING_COPYPOSTFIELDS]) { + /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ + Curl_safefree(s->str[STRING_COPYPOSTFIELDS]); + s->postfields = NULL; + } + + s->postfieldsize = arg; break; +#ifndef CURL_DISABLE_HTTP + case CURLOPT_FOLLOWLOCATION: + if(uarg > 3) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->http_follow_mode = (unsigned char)uarg; + break; + + case CURLOPT_MAXREDIRS: + result = value_range(&arg, -1, 0, 0x7fff); + if(result) + return result; + s->maxredirs = (short)arg; + break; + + case CURLOPT_POSTREDIR: + if(arg < CURL_REDIR_GET_ALL) + /* no return error on too high numbers since the bitmask could be + extended in a future */ + return CURLE_BAD_FUNCTION_ARGUMENT; + s->keep_post = arg & CURL_REDIR_POST_ALL; + break; + + case CURLOPT_HEADEROPT: + s->sep_headers = !!(arg & CURLHEADER_SEPARATE); + break; + case CURLOPT_HTTPAUTH: + return httpauth(data, FALSE, uarg); + + case CURLOPT_HTTP_VERSION: + return setopt_HTTP_VERSION(data, arg); + + case CURLOPT_EXPECT_100_TIMEOUT_MS: + result = value_range(&arg, 0, 0, 0xffff); + if(result) + return result; + s->expect_100_timeout = (unsigned short)arg; + break; + +#endif /* ! CURL_DISABLE_HTTP */ + +#ifndef CURL_DISABLE_MIME + case CURLOPT_MIME_OPTIONS: + s->mime_formescape = !!(arg & CURLMIMEOPT_FORMESCAPE); + break; +#endif +#ifndef CURL_DISABLE_PROXY + case CURLOPT_PROXYPORT: + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->proxyport = (unsigned short)arg; + break; + + case CURLOPT_PROXYAUTH: + return httpauth(data, TRUE, uarg); + + case CURLOPT_PROXYTYPE: + if((arg < CURLPROXY_HTTP) || (arg > CURLPROXY_SOCKS5_HOSTNAME)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->proxytype = (unsigned char)arg; + break; + + case CURLOPT_SOCKS5_AUTH: + if(uarg & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + return CURLE_NOT_BUILT_IN; + s->socks5auth = (unsigned char)uarg; + break; +#endif /* ! CURL_DISABLE_PROXY */ + +#ifndef CURL_DISABLE_FTP + case CURLOPT_FTP_FILEMETHOD: + if((arg < CURLFTPMETHOD_DEFAULT) || (arg >= CURLFTPMETHOD_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->ftp_filemethod = (unsigned char)arg; + break; + case CURLOPT_FTP_SSL_CCC: + if((arg < CURLFTPSSL_CCC_NONE) || (arg >= CURLFTPSSL_CCC_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->ftp_ccc = (unsigned char)arg; + break; + + case CURLOPT_FTPSSLAUTH: + if((arg < CURLFTPAUTH_DEFAULT) || (arg >= CURLFTPAUTH_LAST)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->ftpsslauth = (unsigned char)arg; + break; + case CURLOPT_ACCEPTTIMEOUT_MS: + return setopt_set_timeout_ms(&s->accepttimeout, arg); +#endif /* ! CURL_DISABLE_FTP */ +#if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) + case CURLOPT_FTP_CREATE_MISSING_DIRS: + if((arg < CURLFTP_CREATE_DIR_NONE) || (arg > CURLFTP_CREATE_DIR_RETRY)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->ftp_create_missing_dirs = (unsigned char)arg; + break; +#endif /* ! CURL_DISABLE_FTP || USE_SSH */ + case CURLOPT_INFILESIZE: + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->filesize = arg; + break; + case CURLOPT_LOW_SPEED_LIMIT: + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->low_speed_limit = arg; + break; + case CURLOPT_LOW_SPEED_TIME: + if(arg < 0) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->low_speed_time = arg; + break; + case CURLOPT_PORT: + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->use_port = (unsigned short)arg; + break; + case CURLOPT_TIMEOUT: + return setopt_set_timeout_sec(&s->timeout, arg); + + case CURLOPT_TIMEOUT_MS: + return setopt_set_timeout_ms(&s->timeout, arg); + + case CURLOPT_CONNECTTIMEOUT: + return setopt_set_timeout_sec(&s->connecttimeout, arg); + + case CURLOPT_CONNECTTIMEOUT_MS: + return setopt_set_timeout_ms(&s->connecttimeout, arg); + + case CURLOPT_RESUME_FROM: + if(arg < -1) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->set_resume_from = arg; + break; + +#ifndef CURL_DISABLE_BINDLOCAL + case CURLOPT_LOCALPORT: + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->localport = curlx_sltous(arg); + break; + case CURLOPT_LOCALPORTRANGE: + if((arg < 0) || (arg > 65535)) + return CURLE_BAD_FUNCTION_ARGUMENT; + s->localportrange = curlx_sltous(arg); + break; +#endif + +#ifdef HAVE_GSSAPI + case CURLOPT_GSSAPI_DELEGATION: + s->gssapi_delegation = (unsigned char)uarg& + (CURLGSSAPI_DELEGATION_POLICY_FLAG|CURLGSSAPI_DELEGATION_FLAG); + break; +#endif + + case CURLOPT_SSL_FALSESTART: + return CURLE_NOT_BUILT_IN; + case CURLOPT_BUFFERSIZE: + result = value_range(&arg, 0, READBUFFER_MIN, READBUFFER_MAX); + if(result) + return result; + s->buffer_size = (unsigned int)arg; + break; + + case CURLOPT_UPLOAD_BUFFERSIZE: + result = value_range(&arg, 0, UPLOADBUFFER_MIN, UPLOADBUFFER_MAX); + if(result) + return result; + s->upload_buffer_size = (unsigned int)arg; + break; + case CURLOPT_MAXFILESIZE: - /* - * Set the maximum size of a file to download. - */ if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.max_filesize = arg; + s->max_filesize = arg; break; #ifdef USE_SSL case CURLOPT_USE_SSL: - /* - * Make transfers attempt to use SSL/TLS. - */ if((arg < CURLUSESSL_NONE) || (arg >= CURLUSESSL_LAST)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.use_ssl = (unsigned char)arg; + s->use_ssl = (unsigned char)arg; break; case CURLOPT_SSL_OPTIONS: - set_ssl_options(&data->set.ssl, &data->set.ssl.primary, arg); + set_ssl_options(&s->ssl, &s->ssl.primary, arg); break; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSL_OPTIONS: - set_ssl_options(&data->set.proxy_ssl, &data->set.proxy_ssl.primary, arg); + set_ssl_options(&s->proxy_ssl, &s->proxy_ssl.primary, arg); break; #endif @@ -1161,218 +1138,108 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, case CURLOPT_IPRESOLVE: if((arg < CURL_IPRESOLVE_WHATEVER) || (arg > CURL_IPRESOLVE_V6)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.ipver = (unsigned char) arg; - break; - case CURLOPT_TCP_NODELAY: - /* - * Enable or disable TCP_NODELAY, which will disable/enable the Nagle - * algorithm - */ - data->set.tcp_nodelay = enabled; - break; - - case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = enabled; + s->ipver = (unsigned char) arg; break; case CURLOPT_CONNECT_ONLY: - /* - * No data transfer. - * (1) - only do connection - * (2) - do first get request but get no content - */ - if(arg > 2) + if(arg < 0 || arg > 2) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.connect_only = !!arg; - data->set.connect_only_ws = (arg == 2); + s->connect_only = !!arg; + s->connect_only_ws = (arg == 2); break; - case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.primary.cache_session = enabled; -#ifndef CURL_DISABLE_PROXY - data->set.proxy_ssl.primary.cache_session = - data->set.ssl.primary.cache_session; -#endif - break; #ifdef USE_SSH - /* we only include SSH options if explicitly built to support SSH */ case CURLOPT_SSH_AUTH_TYPES: - data->set.ssh_auth_types = (int)arg; - break; - case CURLOPT_SSH_COMPRESSION: - data->set.ssh_compression = enabled; + s->ssh_auth_types = (int)arg; break; #endif - case CURLOPT_HTTP_TRANSFER_DECODING: - /* - * disable libcurl transfer encoding is used - */ - data->set.http_te_skip = !enabled; /* reversed */ - break; - - case CURLOPT_HTTP_CONTENT_DECODING: - /* - * raw data passed to the application when content encoding is used - */ - data->set.http_ce_skip = !enabled; /* reversed */ - break; - #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) case CURLOPT_NEW_FILE_PERMS: - /* - * Uses these permissions instead of 0644 - */ if((arg < 0) || (arg > 0777)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.new_file_perms = (unsigned int)arg; + s->new_file_perms = (unsigned int)arg; break; #endif #ifdef USE_SSH case CURLOPT_NEW_DIRECTORY_PERMS: - /* - * Uses these permissions instead of 0755 - */ if((arg < 0) || (arg > 0777)) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.new_directory_perms = (unsigned int)arg; + s->new_directory_perms = (unsigned int)arg; break; #endif #ifdef USE_IPV6 case CURLOPT_ADDRESS_SCOPE: - /* - * Use this scope id when using IPv6 - * We always get longs when passed plain numericals so we should check - * that the value fits into an unsigned 32-bit integer. - */ #if SIZEOF_LONG > 4 if(uarg > UINT_MAX) return CURLE_BAD_FUNCTION_ARGUMENT; #endif - data->set.scope_id = (unsigned int)uarg; + s->scope_id = (unsigned int)uarg; break; #endif case CURLOPT_PROTOCOLS: - /* set the bitmask for the protocols that are allowed to be used for the - transfer, which thus helps the app which takes URLs from users or other - external inputs and want to restrict what protocol(s) to deal with. - Defaults to CURLPROTO_ALL. */ - data->set.allowed_protocols = (curl_prot_t)arg; + s->allowed_protocols = (curl_prot_t)arg; break; case CURLOPT_REDIR_PROTOCOLS: - /* set the bitmask for the protocols that libcurl is allowed to follow to, - as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol - needs to be set in both bitmasks to be allowed to get redirected to. */ - data->set.redir_protocols = (curl_prot_t)arg; + s->redir_protocols = (curl_prot_t)arg; break; -#ifndef CURL_DISABLE_SMTP - case CURLOPT_MAIL_RCPT_ALLOWFAILS: - /* allow RCPT TO command to fail for some recipients */ - data->set.mail_rcpt_allowfails = enabled; - break; -#endif /* !CURL_DISABLE_SMTP */ - case CURLOPT_SASL_IR: - /* Enable/disable SASL initial response */ - data->set.sasl_ir = enabled; - break; #ifndef CURL_DISABLE_RTSP case CURLOPT_RTSP_REQUEST: return setopt_RTSP_REQUEST(data, arg); case CURLOPT_RTSP_CLIENT_CSEQ: - /* - * Set the CSEQ number to issue for the next RTSP request. Useful if the - * application is resuming a previously broken connection. The CSEQ - * will increment from this new number henceforth. - */ data->state.rtsp_next_client_CSeq = arg; break; case CURLOPT_RTSP_SERVER_CSEQ: - /* Same as the above, but for server-initiated requests */ data->state.rtsp_next_server_CSeq = arg; break; #endif /* ! CURL_DISABLE_RTSP */ - case CURLOPT_TCP_KEEPALIVE: - data->set.tcp_keepalive = enabled; - break; case CURLOPT_TCP_KEEPIDLE: - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; - data->set.tcp_keepidle = (int)arg; + result = value_range(&arg, 0, 0, INT_MAX); + if(result) + return result; + s->tcp_keepidle = (int)arg; break; case CURLOPT_TCP_KEEPINTVL: - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; - data->set.tcp_keepintvl = (int)arg; + result = value_range(&arg, 0, 0, INT_MAX); + if(result) + return result; + s->tcp_keepintvl = (int)arg; break; case CURLOPT_TCP_KEEPCNT: - if(arg < 0) - return CURLE_BAD_FUNCTION_ARGUMENT; - else if(arg > INT_MAX) - arg = INT_MAX; - data->set.tcp_keepcnt = (int)arg; - break; - case CURLOPT_TCP_FASTOPEN: -#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN) || \ - defined(TCP_FASTOPEN_CONNECT) - data->set.tcp_fastopen = enabled; -#else - return CURLE_NOT_BUILT_IN; -#endif + result = value_range(&arg, 0, 0, INT_MAX); + if(result) + return result; + s->tcp_keepcnt = (int)arg; break; case CURLOPT_SSL_ENABLE_NPN: break; - case CURLOPT_SSL_ENABLE_ALPN: - data->set.ssl_enable_alpn = enabled; - break; - case CURLOPT_PATH_AS_IS: - data->set.path_as_is = enabled; - break; - case CURLOPT_PIPEWAIT: - data->set.pipewait = enabled; - break; case CURLOPT_STREAM_WEIGHT: #if defined(USE_HTTP2) || defined(USE_HTTP3) if((arg >= 1) && (arg <= 256)) - data->set.priority.weight = (int)arg; + s->priority.weight = (int)arg; break; #else return CURLE_NOT_BUILT_IN; #endif - case CURLOPT_SUPPRESS_CONNECT_HEADERS: - data->set.suppress_connect_headers = enabled; - break; case CURLOPT_HAPPY_EYEBALLS_TIMEOUT_MS: - return setopt_set_timeout_ms(&data->set.happy_eyeballs_timeout, arg); - -#ifndef CURL_DISABLE_SHUFFLE_DNS - case CURLOPT_DNS_SHUFFLE_ADDRESSES: - data->set.dns_shuffle_addresses = enabled; - break; -#endif - case CURLOPT_DISALLOW_USERNAME_IN_URL: - data->set.disallow_username_in_url = enabled; - break; + return setopt_set_timeout_ms(&s->happy_eyeballs_timeout, arg); case CURLOPT_UPKEEP_INTERVAL_MS: if(arg < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.upkeep_interval_ms = arg; + s->upkeep_interval_ms = arg; break; case CURLOPT_MAXAGE_CONN: - return setopt_set_timeout_sec(&data->set.conn_max_idle_ms, arg); + return setopt_set_timeout_sec(&s->conn_max_idle_ms, arg); case CURLOPT_MAXLIFETIME_CONN: - return setopt_set_timeout_sec(&data->set.conn_max_age_ms, arg); + return setopt_set_timeout_sec(&s->conn_max_age_ms, arg); #ifndef CURL_DISABLE_HSTS case CURLOPT_HSTS_CTRL: @@ -1402,27 +1269,20 @@ static CURLcode setopt_long(struct Curl_easy *data, CURLoption option, #endif /* ! CURL_DISABLE_ALTSVC */ #ifndef CURL_DISABLE_WEBSOCKETS case CURLOPT_WS_OPTIONS: - data->set.ws_raw_mode = (bool)(arg & CURLWS_RAW_MODE); - data->set.ws_no_auto_pong = (bool)(arg & CURLWS_NOAUTOPONG); + s->ws_raw_mode = (bool)(arg & CURLWS_RAW_MODE); + s->ws_no_auto_pong = (bool)(arg & CURLWS_NOAUTOPONG); break; #endif - case CURLOPT_QUICK_EXIT: - data->set.quick_exit = enabled; - break; case CURLOPT_DNS_USE_GLOBAL_CACHE: /* deprecated */ break; case CURLOPT_SSLENGINE_DEFAULT: - /* - * flag to set engine as default. - */ - Curl_safefree(data->set.str[STRING_SSL_ENGINE]); + Curl_safefree(s->str[STRING_SSL_ENGINE]); return Curl_ssl_set_engine_default(data); case CURLOPT_UPLOAD_FLAGS: - data->set.upload_flags = (unsigned char)arg; + s->upload_flags = (unsigned char)arg; break; default: - /* unknown option */ return CURLE_UNKNOWN_OPTION; } return CURLE_OK; @@ -1432,6 +1292,7 @@ static CURLcode setopt_slist(struct Curl_easy *data, CURLoption option, struct curl_slist *slist) { CURLcode result = CURLE_OK; + struct UserDefined *s = &data->set; switch(option) { #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXYHEADER: @@ -1445,7 +1306,7 @@ static CURLcode setopt_slist(struct Curl_easy *data, CURLoption option, * * Set this option to NULL to restore the previous behavior. */ - data->set.proxyheaders = slist; + s->proxyheaders = slist; break; #endif #ifndef CURL_DISABLE_HTTP @@ -1453,7 +1314,7 @@ static CURLcode setopt_slist(struct Curl_easy *data, CURLoption option, /* * Set a list of aliases for HTTP 200 in response header */ - data->set.http200aliases = slist; + s->http200aliases = slist; break; #endif #if !defined(CURL_DISABLE_FTP) || defined(USE_SSH) @@ -1461,19 +1322,19 @@ static CURLcode setopt_slist(struct Curl_easy *data, CURLoption option, /* * List of RAW FTP commands to use after a transfer */ - data->set.postquote = slist; + s->postquote = slist; break; case CURLOPT_PREQUOTE: /* * List of RAW FTP commands to use prior to RETR (Wesley Laxton) */ - data->set.prequote = slist; + s->prequote = slist; break; case CURLOPT_QUOTE: /* * List of RAW FTP commands to use before a transfer */ - data->set.quote = slist; + s->quote = slist; break; #endif case CURLOPT_RESOLVE: @@ -1490,15 +1351,15 @@ static CURLcode setopt_slist(struct Curl_easy *data, CURLoption option, * This API can remove any entry from the DNS cache, but only entries * that are not actually in use right now will be pruned immediately. */ - data->set.resolve = slist; - data->state.resolve = data->set.resolve; + s->resolve = slist; + data->state.resolve = s->resolve; break; #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MIME) case CURLOPT_HTTPHEADER: /* * Set a list with HTTP headers to use (or replace internals with) */ - data->set.headers = slist; + s->headers = slist; break; #endif #ifndef CURL_DISABLE_TELNET @@ -1506,17 +1367,17 @@ static CURLcode setopt_slist(struct Curl_easy *data, CURLoption option, /* * Set a linked list of telnet options */ - data->set.telnet_options = slist; + s->telnet_options = slist; break; #endif #ifndef CURL_DISABLE_SMTP case CURLOPT_MAIL_RCPT: /* Set the list of mail recipients */ - data->set.mail_rcpt = slist; + s->mail_rcpt = slist; break; #endif case CURLOPT_CONNECT_TO: - data->set.connect_to = slist; + s->connect_to = slist; break; default: return CURLE_UNKNOWN_OPTION; @@ -1529,6 +1390,7 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, va_list param) { CURLcode result = CURLE_OK; + struct UserDefined *s = &data->set; switch(option) { #ifndef CURL_DISABLE_HTTP #ifndef CURL_DISABLE_FORM_API @@ -1536,9 +1398,9 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, /* * Set to make us do HTTP POST. Legacy API-style. */ - data->set.httppost = va_arg(param, struct curl_httppost *); - data->set.method = HTTPREQ_POST_FORM; - data->set.opt_no_body = FALSE; /* this is implied */ + s->httppost = va_arg(param, struct curl_httppost *); + s->method = HTTPREQ_POST_FORM; + s->opt_no_body = FALSE; /* this is implied */ Curl_mime_cleanpart(data->state.formp); Curl_safefree(data->state.formp); data->state.mimepost = NULL; @@ -1552,12 +1414,12 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, /* * Set to make us do MIME POST */ - result = Curl_mime_set_subparts(&data->set.mimepost, + result = Curl_mime_set_subparts(&s->mimepost, va_arg(param, curl_mime *), FALSE); if(!result) { - data->set.method = HTTPREQ_POST_MIME; - data->set.opt_no_body = FALSE; /* this is implied */ + s->method = HTTPREQ_POST_MIME; + s->opt_no_body = FALSE; /* this is implied */ #ifndef CURL_DISABLE_FORM_API Curl_mime_cleanpart(data->state.formp); Curl_safefree(data->state.formp); @@ -1572,9 +1434,9 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, * Set to a FILE * that should receive all error writes. This * defaults to stderr for normal operations. */ - data->set.err = va_arg(param, FILE *); - if(!data->set.err) - data->set.err = stderr; + s->err = va_arg(param, FILE *); + if(!s->err) + s->err = stderr; break; case CURLOPT_SHARE: { @@ -1661,22 +1523,115 @@ static CURLcode setopt_pointers(struct Curl_easy *data, CURLoption option, return result; } +#ifndef CURL_DISABLE_COOKIES +static CURLcode cookielist(struct Curl_easy *data, + const char *ptr) +{ + if(!ptr) + return CURLE_OK; + + if(curl_strequal(ptr, "ALL")) { + /* clear all cookies */ + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_clearall(data->cookies); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + else if(curl_strequal(ptr, "SESS")) { + /* clear session cookies */ + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + Curl_cookie_clearsess(data->cookies); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + else if(curl_strequal(ptr, "FLUSH")) { + /* flush cookies to file, takes care of the locking */ + Curl_flush_cookies(data, FALSE); + } + else if(curl_strequal(ptr, "RELOAD")) { + /* reload cookies from file */ + Curl_cookie_loadfiles(data); + } + else { + if(!data->cookies) { + /* if cookie engine was not running, activate it */ + data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); + if(!data->cookies) + return CURLE_OUT_OF_MEMORY; + } + + /* general protection against mistakes and abuse */ + if(strlen(ptr) > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + + Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); + if(checkprefix("Set-Cookie:", ptr)) + /* HTTP Header format line */ + Curl_cookie_add(data, data->cookies, TRUE, FALSE, ptr + 11, NULL, + NULL, TRUE); + else + /* Netscape format line */ + Curl_cookie_add(data, data->cookies, FALSE, FALSE, ptr, NULL, + NULL, TRUE); + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); + } + return CURLE_OK; +} + +static CURLcode cookiefile(struct Curl_easy *data, + const char *ptr) +{ + /* + * Set cookie file to read and parse. Can be used multiple times. + */ + if(ptr) { + struct curl_slist *cl; + /* general protection against mistakes and abuse */ + if(strlen(ptr) > CURL_MAX_INPUT_LENGTH) + return CURLE_BAD_FUNCTION_ARGUMENT; + /* append the cookie filename to the list of filenames, and deal with + them later */ + cl = curl_slist_append(data->state.cookielist, ptr); + if(!cl) { + curl_slist_free_all(data->state.cookielist); + data->state.cookielist = NULL; + return CURLE_OUT_OF_MEMORY; + } + data->state.cookielist = cl; /* store the list for later use */ + } + else { + /* clear the list of cookie files */ + curl_slist_free_all(data->state.cookielist); + data->state.cookielist = NULL; + + if(!data->share || !data->share->cookies) { + /* throw away all existing cookies if this is not a shared cookie + container */ + Curl_cookie_clearall(data->cookies); + Curl_cookie_cleanup(data->cookies); + } + /* disable the cookie engine */ + data->cookies = NULL; + } + return CURLE_OK; +} +#endif + static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, char *ptr) { CURLcode result = CURLE_OK; + struct UserDefined *s = &data->set; switch(option) { case CURLOPT_SSL_CIPHER_LIST: if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) /* set a list of cipher we want to use in the SSL connection */ - return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST], ptr); + return Curl_setstropt(&s->str[STRING_SSL_CIPHER_LIST], ptr); else return CURLE_NOT_BUILT_IN; #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSL_CIPHER_LIST: if(Curl_ssl_supports(data, SSLSUPP_CIPHER_LIST)) { /* set a list of cipher we want to use in the SSL connection for proxy */ - return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER_LIST_PROXY], + return Curl_setstropt(&s->str[STRING_SSL_CIPHER_LIST_PROXY], ptr); } else @@ -1685,7 +1640,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, case CURLOPT_TLS13_CIPHERS: if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) { /* set preferred list of TLS 1.3 cipher suites */ - return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST], ptr); + return Curl_setstropt(&s->str[STRING_SSL_CIPHER13_LIST], ptr); } else return CURLE_NOT_BUILT_IN; @@ -1693,7 +1648,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, case CURLOPT_PROXY_TLS13_CIPHERS: if(Curl_ssl_supports(data, SSLSUPP_TLS13_CIPHERSUITES)) /* set preferred list of TLS 1.3 cipher suites for proxy */ - return Curl_setstropt(&data->set.str[STRING_SSL_CIPHER13_LIST_PROXY], + return Curl_setstropt(&s->str[STRING_SSL_CIPHER13_LIST_PROXY], ptr); else return CURLE_NOT_BUILT_IN; @@ -1703,13 +1658,13 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, case CURLOPT_EGDSOCKET: break; case CURLOPT_REQUEST_TARGET: - return Curl_setstropt(&data->set.str[STRING_TARGET], ptr); + return Curl_setstropt(&s->str[STRING_TARGET], ptr); #ifndef CURL_DISABLE_NETRC case CURLOPT_NETRC_FILE: /* * Use this file instead of the $HOME/.netrc file */ - return Curl_setstropt(&data->set.str[STRING_NETRC_FILE], ptr); + return Curl_setstropt(&s->str[STRING_NETRC_FILE], ptr); #endif #if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_MQTT) @@ -1719,16 +1674,16 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to * CURLOPT_COPYPOSTFIELDS and not altered later. */ - if(!ptr || data->set.postfieldsize == -1) - result = Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], ptr); + if(!ptr || s->postfieldsize == -1) + result = Curl_setstropt(&s->str[STRING_COPYPOSTFIELDS], ptr); else { - if(data->set.postfieldsize < 0) + if(s->postfieldsize < 0) return CURLE_BAD_FUNCTION_ARGUMENT; #if SIZEOF_CURL_OFF_T > SIZEOF_SIZE_T /* * Check that requested length does not overflow the size_t type. */ - else if(data->set.postfieldsize > SIZE_T_MAX) + else if(s->postfieldsize > SIZE_MAX) return CURLE_OUT_OF_MEMORY; #endif else { @@ -1737,28 +1692,28 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, mark that postfields is used rather than read function or form data. */ - char *p = Curl_memdup0(ptr, (size_t)data->set.postfieldsize); + char *p = Curl_memdup0(ptr, (size_t)s->postfieldsize); if(!p) return CURLE_OUT_OF_MEMORY; else { - free(data->set.str[STRING_COPYPOSTFIELDS]); - data->set.str[STRING_COPYPOSTFIELDS] = p; + free(s->str[STRING_COPYPOSTFIELDS]); + s->str[STRING_COPYPOSTFIELDS] = p; } } } - data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS]; - data->set.method = HTTPREQ_POST; + s->postfields = s->str[STRING_COPYPOSTFIELDS]; + s->method = HTTPREQ_POST; break; case CURLOPT_POSTFIELDS: /* * Like above, but use static data instead of copying it. */ - data->set.postfields = ptr; + s->postfields = ptr; /* Release old copied data. */ - Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]); - data->set.method = HTTPREQ_POST; + Curl_safefree(s->str[STRING_COPYPOSTFIELDS]); + s->method = HTTPREQ_POST; break; #endif /* ! CURL_DISABLE_HTTP || ! CURL_DISABLE_MQTT */ @@ -1776,22 +1731,22 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, if(ptr && !*ptr) { char all[256]; Curl_all_content_encodings(all, sizeof(all)); - return Curl_setstropt(&data->set.str[STRING_ENCODING], all); + return Curl_setstropt(&s->str[STRING_ENCODING], all); } - return Curl_setstropt(&data->set.str[STRING_ENCODING], ptr); + return Curl_setstropt(&s->str[STRING_ENCODING], ptr); -#if !defined(CURL_DISABLE_AWS) +#ifndef CURL_DISABLE_AWS 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], ptr); + result = Curl_setstropt(&s->str[STRING_AWS_SIGV4], ptr); /* * Basic been set by default it need to be unset here */ - if(data->set.str[STRING_AWS_SIGV4]) - data->set.httpauth = CURLAUTH_AWS_SIGV4; + if(s->str[STRING_AWS_SIGV4]) + s->httpauth = CURLAUTH_AWS_SIGV4; break; #endif case CURLOPT_REFERER: @@ -1802,70 +1757,38 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, Curl_safefree(data->state.referer); data->state.referer_alloc = FALSE; } - result = Curl_setstropt(&data->set.str[STRING_SET_REFERER], ptr); - data->state.referer = data->set.str[STRING_SET_REFERER]; + result = Curl_setstropt(&s->str[STRING_SET_REFERER], ptr); + data->state.referer = s->str[STRING_SET_REFERER]; break; case CURLOPT_USERAGENT: /* * String to use in the HTTP User-Agent field */ - return Curl_setstropt(&data->set.str[STRING_USERAGENT], ptr); + return Curl_setstropt(&s->str[STRING_USERAGENT], ptr); -#if !defined(CURL_DISABLE_COOKIES) +#ifndef CURL_DISABLE_COOKIES case CURLOPT_COOKIE: /* * Cookie string to send to the remote server in the request. */ - return Curl_setstropt(&data->set.str[STRING_COOKIE], ptr); + return Curl_setstropt(&s->str[STRING_COOKIE], ptr); case CURLOPT_COOKIEFILE: - /* - * Set cookie file to read and parse. Can be used multiple times. - */ - if(ptr) { - struct curl_slist *cl; - /* general protection against mistakes and abuse */ - if(strlen(ptr) > CURL_MAX_INPUT_LENGTH) - return CURLE_BAD_FUNCTION_ARGUMENT; - /* append the cookie filename to the list of filenames, and deal with - them later */ - cl = curl_slist_append(data->state.cookielist, ptr); - if(!cl) { - curl_slist_free_all(data->state.cookielist); - data->state.cookielist = NULL; - return CURLE_OUT_OF_MEMORY; - } - data->state.cookielist = cl; /* store the list for later use */ - } - else { - /* clear the list of cookie files */ - curl_slist_free_all(data->state.cookielist); - data->state.cookielist = NULL; - - if(!data->share || !data->share->cookies) { - /* throw away all existing cookies if this is not a shared cookie - container */ - Curl_cookie_clearall(data->cookies); - Curl_cookie_cleanup(data->cookies); - } - /* disable the cookie engine */ - data->cookies = NULL; - } - break; + return cookiefile(data, ptr); case CURLOPT_COOKIEJAR: /* * Set cookie filename to dump all cookies to when we are done. */ - result = Curl_setstropt(&data->set.str[STRING_COOKIEJAR], ptr); + result = Curl_setstropt(&s->str[STRING_COOKIEJAR], ptr); if(!result) { /* * Activate the cookie parser. This may or may not already * have been made. */ struct CookieInfo *newcookies = - Curl_cookie_init(data, NULL, data->cookies, data->set.cookiesession); + Curl_cookie_init(data, NULL, data->cookies, s->cookiesession); if(!newcookies) result = CURLE_OUT_OF_MEMORY; data->cookies = newcookies; @@ -1873,54 +1796,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, break; case CURLOPT_COOKIELIST: - if(!ptr) - break; - - if(curl_strequal(ptr, "ALL")) { - /* clear all cookies */ - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_clearall(data->cookies); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - else if(curl_strequal(ptr, "SESS")) { - /* clear session cookies */ - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - Curl_cookie_clearsess(data->cookies); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - else if(curl_strequal(ptr, "FLUSH")) { - /* flush cookies to file, takes care of the locking */ - Curl_flush_cookies(data, FALSE); - } - else if(curl_strequal(ptr, "RELOAD")) { - /* reload cookies from file */ - Curl_cookie_loadfiles(data); - break; - } - else { - if(!data->cookies) { - /* if cookie engine was not running, activate it */ - data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE); - if(!data->cookies) - return CURLE_OUT_OF_MEMORY; - } - - /* general protection against mistakes and abuse */ - if(strlen(ptr) > CURL_MAX_INPUT_LENGTH) - return CURLE_BAD_FUNCTION_ARGUMENT; - - Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); - if(checkprefix("Set-Cookie:", ptr)) - /* HTTP Header format line */ - Curl_cookie_add(data, data->cookies, TRUE, FALSE, ptr + 11, NULL, - NULL, TRUE); - else - /* Netscape format line */ - Curl_cookie_add(data, data->cookies, FALSE, FALSE, ptr, NULL, - NULL, TRUE); - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); - } - break; + return cookielist(data, ptr); #endif /* !CURL_DISABLE_COOKIES */ #endif /* ! CURL_DISABLE_HTTP */ @@ -1929,10 +1805,10 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * Set a custom string to use as request */ - return Curl_setstropt(&data->set.str[STRING_CUSTOMREQUEST], ptr); + return Curl_setstropt(&s->str[STRING_CUSTOMREQUEST], ptr); /* we do not set - data->set.method = HTTPREQ_CUSTOM; + s->method = HTTPREQ_CUSTOM; here, we continue as if we were using the already set type and this just changes the actual request keyword */ @@ -1948,7 +1824,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Setting it to NULL, means no proxy but allows the environment variables * to decide for us (if CURLOPT_SOCKS_PROXY setting it to NULL). */ - return Curl_setstropt(&data->set.str[STRING_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_PROXY], ptr); case CURLOPT_PRE_PROXY: /* @@ -1957,7 +1833,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * If the proxy is set to "" or NULL we explicitly say that we do not want * to use the socks proxy. */ - return Curl_setstropt(&data->set.str[STRING_PRE_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_PRE_PROXY], ptr); #endif /* CURL_DISABLE_PROXY */ #ifndef CURL_DISABLE_PROXY @@ -1966,58 +1842,58 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * Set proxy authentication service name for Kerberos 5 and SPNEGO */ - return Curl_setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME], ptr); + return Curl_setstropt(&s->str[STRING_PROXY_SERVICE_NAME], ptr); #endif case CURLOPT_SERVICE_NAME: /* * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO */ - return Curl_setstropt(&data->set.str[STRING_SERVICE_NAME], ptr); + return Curl_setstropt(&s->str[STRING_SERVICE_NAME], ptr); case CURLOPT_HEADERDATA: /* * Custom pointer to pass the header write callback function */ - data->set.writeheader = ptr; + s->writeheader = ptr; break; case CURLOPT_READDATA: /* * FILE pointer to read the file to be uploaded from. Or possibly used as * argument to the read callback. */ - data->set.in_set = ptr; + s->in_set = ptr; break; case CURLOPT_WRITEDATA: /* * FILE pointer to write to. Or possibly used as argument to the write * callback. */ - data->set.out = ptr; + s->out = ptr; break; case CURLOPT_DEBUGDATA: /* * Set to a void * that should receive all error writes. This * defaults to CURLOPT_STDERR for normal operations. */ - data->set.debugdata = ptr; + s->debugdata = ptr; break; case CURLOPT_PROGRESSDATA: /* * Custom client data to pass to the progress callback */ - data->set.progress_client = ptr; + s->progress_client = ptr; break; case CURLOPT_SEEKDATA: /* * Seek control callback. Might be NULL. */ - data->set.seek_client = ptr; + s->seek_client = ptr; break; case CURLOPT_IOCTLDATA: /* * I/O control data pointer. Might be NULL. */ - data->set.ioctl_client = ptr; + s->ioctl_client = ptr; break; case CURLOPT_SSL_CTX_DATA: /* @@ -2025,7 +1901,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) { - data->set.ssl.fsslctxp = ptr; + s->ssl.fsslctxp = ptr; break; } else @@ -2035,33 +1911,33 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * socket callback data pointer. Might be NULL. */ - data->set.sockopt_client = ptr; + s->sockopt_client = ptr; break; case CURLOPT_OPENSOCKETDATA: /* * socket callback data pointer. Might be NULL. */ - data->set.opensocket_client = ptr; + s->opensocket_client = ptr; break; case CURLOPT_RESOLVER_START_DATA: /* * resolver start callback data pointer. Might be NULL. */ - data->set.resolver_start_client = ptr; + s->resolver_start_client = ptr; break; case CURLOPT_CLOSESOCKETDATA: /* * socket callback data pointer. Might be NULL. */ - data->set.closesocket_client = ptr; + s->closesocket_client = ptr; break; case CURLOPT_TRAILERDATA: #ifndef CURL_DISABLE_HTTP - data->set.trailer_data = ptr; + s->trailer_data = ptr; #endif break; case CURLOPT_PREREQDATA: - data->set.prereq_userp = ptr; + s->prereq_userp = ptr; break; case CURLOPT_ERRORBUFFER: @@ -2069,7 +1945,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Error buffer provided by the caller to get the human readable error * string in. */ - data->set.errorbuffer = ptr; + s->errorbuffer = ptr; break; #ifndef CURL_DISABLE_FTP @@ -2077,23 +1953,23 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * Use FTP PORT, this also specifies which IP address to use */ - result = Curl_setstropt(&data->set.str[STRING_FTPPORT], ptr); - data->set.ftp_use_port = !!(data->set.str[STRING_FTPPORT]); + result = Curl_setstropt(&s->str[STRING_FTPPORT], ptr); + s->ftp_use_port = !!(s->str[STRING_FTPPORT]); break; case CURLOPT_FTP_ACCOUNT: - return Curl_setstropt(&data->set.str[STRING_FTP_ACCOUNT], ptr); + return Curl_setstropt(&s->str[STRING_FTP_ACCOUNT], ptr); case CURLOPT_FTP_ALTERNATIVE_TO_USER: - return Curl_setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER], ptr); + return Curl_setstropt(&s->str[STRING_FTP_ALTERNATIVE_TO_USER], ptr); #ifdef HAVE_GSSAPI case CURLOPT_KRBLEVEL: /* * A string that defines the kerberos security level. */ - result = Curl_setstropt(&data->set.str[STRING_KRB_LEVEL], ptr); - data->set.krb = !!(data->set.str[STRING_KRB_LEVEL]); + result = Curl_setstropt(&s->str[STRING_KRB_LEVEL], ptr); + s->krb = !!(s->str[STRING_KRB_LEVEL]); break; #endif #endif @@ -2105,40 +1981,40 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, Curl_safefree(data->state.url); data->state.url_alloc = FALSE; } - result = Curl_setstropt(&data->set.str[STRING_SET_URL], ptr); - data->state.url = data->set.str[STRING_SET_URL]; + result = Curl_setstropt(&s->str[STRING_SET_URL], ptr); + data->state.url = s->str[STRING_SET_URL]; break; case CURLOPT_USERPWD: /* * user:password to use in the operation */ - return setstropt_userpwd(ptr, &data->set.str[STRING_USERNAME], - &data->set.str[STRING_PASSWORD]); + return setstropt_userpwd(ptr, &s->str[STRING_USERNAME], + &s->str[STRING_PASSWORD]); case CURLOPT_USERNAME: /* * authentication username to use in the operation */ - return Curl_setstropt(&data->set.str[STRING_USERNAME], ptr); + return Curl_setstropt(&s->str[STRING_USERNAME], ptr); case CURLOPT_PASSWORD: /* * authentication password to use in the operation */ - return Curl_setstropt(&data->set.str[STRING_PASSWORD], ptr); + return Curl_setstropt(&s->str[STRING_PASSWORD], ptr); case CURLOPT_LOGIN_OPTIONS: /* * authentication options to use in the operation */ - return Curl_setstropt(&data->set.str[STRING_OPTIONS], ptr); + return Curl_setstropt(&s->str[STRING_OPTIONS], ptr); case CURLOPT_XOAUTH2_BEARER: /* * OAuth 2.0 bearer token to use in the operation */ - return Curl_setstropt(&data->set.str[STRING_BEARER], ptr); + return Curl_setstropt(&s->str[STRING_BEARER], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXYUSERPWD: { @@ -2151,13 +2027,13 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* URL decode the components */ if(!result && u) { - Curl_safefree(data->set.str[STRING_PROXYUSERNAME]); - result = Curl_urldecode(u, 0, &data->set.str[STRING_PROXYUSERNAME], NULL, + Curl_safefree(s->str[STRING_PROXYUSERNAME]); + result = Curl_urldecode(u, 0, &s->str[STRING_PROXYUSERNAME], NULL, REJECT_ZERO); } if(!result && p) { - Curl_safefree(data->set.str[STRING_PROXYPASSWORD]); - result = Curl_urldecode(p, 0, &data->set.str[STRING_PROXYPASSWORD], NULL, + Curl_safefree(s->str[STRING_PROXYPASSWORD]); + result = Curl_urldecode(p, 0, &s->str[STRING_PROXYPASSWORD], NULL, REJECT_ZERO); } free(u); @@ -2168,26 +2044,26 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * authentication username to use in the operation */ - return Curl_setstropt(&data->set.str[STRING_PROXYUSERNAME], ptr); + return Curl_setstropt(&s->str[STRING_PROXYUSERNAME], ptr); case CURLOPT_PROXYPASSWORD: /* * authentication password to use in the operation */ - return Curl_setstropt(&data->set.str[STRING_PROXYPASSWORD], ptr); + return Curl_setstropt(&s->str[STRING_PROXYPASSWORD], ptr); case CURLOPT_NOPROXY: /* * proxy exception list */ - return Curl_setstropt(&data->set.str[STRING_NOPROXY], ptr); + return Curl_setstropt(&s->str[STRING_NOPROXY], ptr); #endif /* ! CURL_DISABLE_PROXY */ case CURLOPT_RANGE: /* * What range of the file you want to transfer */ - return Curl_setstropt(&data->set.str[STRING_SET_RANGE], ptr); + return Curl_setstropt(&s->str[STRING_SET_RANGE], ptr); case CURLOPT_CURLU: /* @@ -2199,77 +2075,77 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, } else data->state.url = NULL; - Curl_safefree(data->set.str[STRING_SET_URL]); - data->set.uh = (CURLU *)ptr; + Curl_safefree(s->str[STRING_SET_URL]); + s->uh = (CURLU *)ptr; break; case CURLOPT_SSLCERT: /* * String that holds filename of the SSL certificate to use */ - return Curl_setstropt(&data->set.str[STRING_CERT], ptr); + return Curl_setstropt(&s->str[STRING_CERT], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLCERT: /* * String that holds filename of the SSL certificate to use for proxy */ - return Curl_setstropt(&data->set.str[STRING_CERT_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_CERT_PROXY], ptr); #endif case CURLOPT_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use */ - return Curl_setstropt(&data->set.str[STRING_CERT_TYPE], ptr); + return Curl_setstropt(&s->str[STRING_CERT_TYPE], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLCERTTYPE: /* * String that holds file type of the SSL certificate to use for proxy */ - return Curl_setstropt(&data->set.str[STRING_CERT_TYPE_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_CERT_TYPE_PROXY], ptr); #endif case CURLOPT_SSLKEY: /* * String that holds filename of the SSL key to use */ - return Curl_setstropt(&data->set.str[STRING_KEY], ptr); + return Curl_setstropt(&s->str[STRING_KEY], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLKEY: /* * String that holds filename of the SSL key to use for proxy */ - return Curl_setstropt(&data->set.str[STRING_KEY_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_KEY_PROXY], ptr); #endif case CURLOPT_SSLKEYTYPE: /* * String that holds file type of the SSL key to use */ - return Curl_setstropt(&data->set.str[STRING_KEY_TYPE], ptr); + return Curl_setstropt(&s->str[STRING_KEY_TYPE], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLKEYTYPE: /* * String that holds file type of the SSL key to use for proxy */ - return Curl_setstropt(&data->set.str[STRING_KEY_TYPE_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_KEY_TYPE_PROXY], ptr); #endif case CURLOPT_KEYPASSWD: /* * String that holds the SSL or SSH private key password. */ - return Curl_setstropt(&data->set.str[STRING_KEY_PASSWD], ptr); + return Curl_setstropt(&s->str[STRING_KEY_PASSWD], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_KEYPASSWD: /* * String that holds the SSL private key password for proxy. */ - return Curl_setstropt(&data->set.str[STRING_KEY_PASSWD_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_KEY_PASSWD_PROXY], ptr); #endif case CURLOPT_SSLENGINE: @@ -2277,7 +2153,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * String that holds the SSL crypto engine. */ if(ptr && ptr[0]) { - result = Curl_setstropt(&data->set.str[STRING_SSL_ENGINE], ptr); + result = Curl_setstropt(&s->str[STRING_SSL_ENGINE], ptr); if(!result) { result = Curl_ssl_set_engine(data, ptr); } @@ -2289,9 +2165,9 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * Set the client IP to send through HAProxy PROXY protocol */ - result = Curl_setstropt(&data->set.str[STRING_HAPROXY_CLIENT_IP], ptr); + result = Curl_setstropt(&s->str[STRING_HAPROXY_CLIENT_IP], ptr); /* enable the HAProxy protocol */ - data->set.haproxyprotocol = TRUE; + s->haproxyprotocol = TRUE; break; #endif @@ -2301,9 +2177,9 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * performing an operation and thus what from-IP your connection will use. */ return setstropt_interface(ptr, - &data->set.str[STRING_DEVICE], - &data->set.str[STRING_INTERFACE], - &data->set.str[STRING_BINDHOST]); + &s->str[STRING_DEVICE], + &s->str[STRING_INTERFACE], + &s->str[STRING_BINDHOST]); case CURLOPT_PINNEDPUBLICKEY: /* @@ -2312,7 +2188,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) - return Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY], ptr); + return Curl_setstropt(&s->str[STRING_SSL_PINNEDPUBLICKEY], ptr); #endif return CURLE_NOT_BUILT_IN; @@ -2324,7 +2200,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_PINNEDPUBKEY)) - return Curl_setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY], + return Curl_setstropt(&s->str[STRING_SSL_PINNEDPUBLICKEY_PROXY], ptr); #endif return CURLE_NOT_BUILT_IN; @@ -2333,7 +2209,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * Set CA info for SSL connection. Specify filename of the CA certificate */ - return Curl_setstropt(&data->set.str[STRING_SSL_CAFILE], ptr); + return Curl_setstropt(&s->str[STRING_SSL_CAFILE], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_CAINFO: @@ -2341,7 +2217,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Set CA info SSL connection for proxy. Specify filename of the * CA certificate */ - return Curl_setstropt(&data->set.str[STRING_SSL_CAFILE_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_SSL_CAFILE_PROXY], ptr); #endif case CURLOPT_CAPATH: @@ -2352,7 +2228,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) /* This does not work on Windows. */ - return Curl_setstropt(&data->set.str[STRING_SSL_CAPATH], ptr); + return Curl_setstropt(&s->str[STRING_SSL_CAPATH], ptr); #endif return CURLE_NOT_BUILT_IN; #ifndef CURL_DISABLE_PROXY @@ -2364,7 +2240,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_CA_PATH)) /* This does not work on Windows. */ - return Curl_setstropt(&data->set.str[STRING_SSL_CAPATH_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_SSL_CAPATH_PROXY], ptr); #endif return CURLE_NOT_BUILT_IN; #endif @@ -2373,7 +2249,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Set CRL file info for SSL connection. Specify filename of the CRL * to check certificates revocation */ - return Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE], ptr); + return Curl_setstropt(&s->str[STRING_SSL_CRLFILE], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_CRLFILE: @@ -2381,7 +2257,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Set CRL file info for SSL connection for proxy. Specify filename of the * CRL to check certificates revocation */ - return Curl_setstropt(&data->set.str[STRING_SSL_CRLFILE_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_SSL_CRLFILE_PROXY], ptr); #endif case CURLOPT_ISSUERCERT: @@ -2389,7 +2265,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Set Issuer certificate file * to check certificates issuer */ - return Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT], ptr); + return Curl_setstropt(&s->str[STRING_SSL_ISSUERCERT], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_ISSUERCERT: @@ -2397,14 +2273,14 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Set Issuer certificate file * to check certificates issuer */ - return Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_SSL_ISSUERCERT_PROXY], ptr); #endif case CURLOPT_PRIVATE: /* * Set private data pointer. */ - data->set.private_data = ptr; + s->private_data = ptr; break; #ifdef USE_SSL @@ -2413,7 +2289,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Set accepted curves in SSL connection setup. * Specify colon-delimited list of curve algorithm names. */ - return Curl_setstropt(&data->set.str[STRING_SSL_EC_CURVES], ptr); + return Curl_setstropt(&s->str[STRING_SSL_EC_CURVES], ptr); case CURLOPT_SSL_SIGNATURE_ALGORITHMS: /* @@ -2421,7 +2297,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Specify colon-delimited list of signature scheme names. */ if(Curl_ssl_supports(data, SSLSUPP_SIGNATURE_ALGORITHMS)) - return Curl_setstropt(&data->set.str[STRING_SSL_SIGNATURE_ALGORITHMS], + return Curl_setstropt(&s->str[STRING_SSL_SIGNATURE_ALGORITHMS], ptr); return CURLE_NOT_BUILT_IN; #endif @@ -2430,13 +2306,13 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, /* * Use this file instead of the $HOME/.ssh/id_dsa.pub file */ - return Curl_setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY], ptr); + return Curl_setstropt(&s->str[STRING_SSH_PUBLIC_KEY], ptr); case CURLOPT_SSH_PRIVATE_KEYFILE: /* * Use this file instead of the $HOME/.ssh/id_dsa file */ - return Curl_setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY], ptr); + return Curl_setstropt(&s->str[STRING_SSH_PRIVATE_KEY], ptr); #if defined(USE_LIBSSH2) || defined(USE_LIBSSH) case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5: @@ -2444,19 +2320,19 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Option to allow for the MD5 of the host public key to be checked * for validation purposes. */ - return Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5], ptr); + return Curl_setstropt(&s->str[STRING_SSH_HOST_PUBLIC_KEY_MD5], ptr); case CURLOPT_SSH_KNOWNHOSTS: /* * Store the filename to read known hosts from. */ - return Curl_setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS], ptr); + return Curl_setstropt(&s->str[STRING_SSH_KNOWNHOSTS], ptr); #endif case CURLOPT_SSH_KEYDATA: /* * Custom client data to pass to the SSH keyfunc callback */ - data->set.ssh_keyfunc_userp = ptr; + s->ssh_keyfunc_userp = ptr; break; #ifdef USE_LIBSSH2 case CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256: @@ -2464,47 +2340,47 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Option to allow for the SHA256 of the host public key to be checked * for validation purposes. */ - return Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_SHA256], + return Curl_setstropt(&s->str[STRING_SSH_HOST_PUBLIC_KEY_SHA256], ptr); case CURLOPT_SSH_HOSTKEYDATA: /* * Custom client data to pass to the SSH keyfunc callback */ - data->set.ssh_hostkeyfunc_userp = ptr; + s->ssh_hostkeyfunc_userp = ptr; break; #endif /* USE_LIBSSH2 */ #endif /* USE_SSH */ case CURLOPT_PROTOCOLS_STR: if(ptr) - return protocol2num(ptr, &data->set.allowed_protocols); + return protocol2num(ptr, &s->allowed_protocols); /* make a NULL argument reset to default */ - data->set.allowed_protocols = (curl_prot_t) CURLPROTO_ALL; + s->allowed_protocols = (curl_prot_t) CURLPROTO_ALL; break; case CURLOPT_REDIR_PROTOCOLS_STR: if(ptr) - return protocol2num(ptr, &data->set.redir_protocols); + return protocol2num(ptr, &s->redir_protocols); /* make a NULL argument reset to default */ - data->set.redir_protocols = (curl_prot_t) CURLPROTO_REDIR; + s->redir_protocols = (curl_prot_t) CURLPROTO_REDIR; break; case CURLOPT_DEFAULT_PROTOCOL: /* Set the protocol to use when the URL does not include any protocol */ - return Curl_setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL], ptr); + return Curl_setstropt(&s->str[STRING_DEFAULT_PROTOCOL], ptr); #ifndef CURL_DISABLE_SMTP case CURLOPT_MAIL_FROM: /* Set the SMTP mail originator */ - return Curl_setstropt(&data->set.str[STRING_MAIL_FROM], ptr); + return Curl_setstropt(&s->str[STRING_MAIL_FROM], ptr); case CURLOPT_MAIL_AUTH: /* Set the SMTP auth originator */ - return Curl_setstropt(&data->set.str[STRING_MAIL_AUTH], ptr); + return Curl_setstropt(&s->str[STRING_MAIL_AUTH], ptr); #endif case CURLOPT_SASL_AUTHZID: /* Authorization identity (identity to act as) */ - return Curl_setstropt(&data->set.str[STRING_SASL_AUTHZID], ptr); + return Curl_setstropt(&s->str[STRING_SASL_AUTHZID], ptr); #ifndef CURL_DISABLE_RTSP case CURLOPT_RTSP_SESSION_ID: @@ -2512,48 +2388,48 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, * Set the RTSP Session ID manually. Useful if the application is * resuming a previously established RTSP session */ - return Curl_setstropt(&data->set.str[STRING_RTSP_SESSION_ID], ptr); + return Curl_setstropt(&s->str[STRING_RTSP_SESSION_ID], ptr); case CURLOPT_RTSP_STREAM_URI: /* * Set the Stream URI for the RTSP request. Unless the request is * for generic server options, the application will need to set this. */ - return Curl_setstropt(&data->set.str[STRING_RTSP_STREAM_URI], ptr); + return Curl_setstropt(&s->str[STRING_RTSP_STREAM_URI], ptr); case CURLOPT_RTSP_TRANSPORT: /* * The content of the Transport: header for the RTSP request */ - return Curl_setstropt(&data->set.str[STRING_RTSP_TRANSPORT], ptr); + return Curl_setstropt(&s->str[STRING_RTSP_TRANSPORT], ptr); case CURLOPT_INTERLEAVEDATA: - data->set.rtp_out = ptr; + s->rtp_out = ptr; break; #endif /* ! CURL_DISABLE_RTSP */ #ifndef CURL_DISABLE_FTP case CURLOPT_CHUNK_DATA: - data->set.wildcardptr = ptr; + s->wildcardptr = ptr; break; case CURLOPT_FNMATCH_DATA: - data->set.fnmatch_data = ptr; + s->fnmatch_data = ptr; break; #endif #ifdef USE_TLS_SRP case CURLOPT_TLSAUTH_USERNAME: - return Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME], ptr); + return Curl_setstropt(&s->str[STRING_TLSAUTH_USERNAME], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_TLSAUTH_USERNAME: - return Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_TLSAUTH_USERNAME_PROXY], ptr); #endif case CURLOPT_TLSAUTH_PASSWORD: - return Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD], ptr); + return Curl_setstropt(&s->str[STRING_TLSAUTH_PASSWORD], ptr); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_TLSAUTH_PASSWORD: - return Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY], ptr); + return Curl_setstropt(&s->str[STRING_TLSAUTH_PASSWORD_PROXY], ptr); #endif case CURLOPT_TLSAUTH_TYPE: if(ptr && !curl_strequal(ptr, "SRP")) @@ -2568,25 +2444,25 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, #endif #ifdef CURLRES_ARES case CURLOPT_DNS_SERVERS: - result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS], ptr); + result = Curl_setstropt(&s->str[STRING_DNS_SERVERS], ptr); if(result) return result; return Curl_async_ares_set_dns_servers(data); case CURLOPT_DNS_INTERFACE: - result = Curl_setstropt(&data->set.str[STRING_DNS_INTERFACE], ptr); + result = Curl_setstropt(&s->str[STRING_DNS_INTERFACE], ptr); if(result) return result; return Curl_async_ares_set_dns_interface(data); case CURLOPT_DNS_LOCAL_IP4: - result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP4], ptr); + result = Curl_setstropt(&s->str[STRING_DNS_LOCAL_IP4], ptr); if(result) return result; return Curl_async_ares_set_dns_local_ip4(data); case CURLOPT_DNS_LOCAL_IP6: - result = Curl_setstropt(&data->set.str[STRING_DNS_LOCAL_IP6], ptr); + result = Curl_setstropt(&s->str[STRING_DNS_LOCAL_IP6], ptr); if(result) return result; return Curl_async_ares_set_dns_local_ip6(data); @@ -2594,27 +2470,27 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, #endif #ifdef USE_UNIX_SOCKETS case CURLOPT_UNIX_SOCKET_PATH: - data->set.abstract_unix_socket = FALSE; - return Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], ptr); + s->abstract_unix_socket = FALSE; + return Curl_setstropt(&s->str[STRING_UNIX_SOCKET_PATH], ptr); case CURLOPT_ABSTRACT_UNIX_SOCKET: - data->set.abstract_unix_socket = TRUE; - return Curl_setstropt(&data->set.str[STRING_UNIX_SOCKET_PATH], ptr); + s->abstract_unix_socket = TRUE; + return Curl_setstropt(&s->str[STRING_UNIX_SOCKET_PATH], ptr); #endif #ifndef CURL_DISABLE_DOH case CURLOPT_DOH_URL: - result = Curl_setstropt(&data->set.str[STRING_DOH], ptr); - data->set.doh = !!(data->set.str[STRING_DOH]); + result = Curl_setstropt(&s->str[STRING_DOH], ptr); + s->doh = !!(s->str[STRING_DOH]); break; #endif #ifndef CURL_DISABLE_HSTS case CURLOPT_HSTSREADDATA: - data->set.hsts_read_userp = ptr; + s->hsts_read_userp = ptr; break; case CURLOPT_HSTSWRITEDATA: - data->set.hsts_write_userp = ptr; + s->hsts_write_userp = ptr; break; case CURLOPT_HSTS: { struct curl_slist *h; @@ -2624,7 +2500,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, return CURLE_OUT_OF_MEMORY; } if(ptr) { - result = Curl_setstropt(&data->set.str[STRING_HSTS], ptr); + result = Curl_setstropt(&s->str[STRING_HSTS], ptr); if(result) return result; /* this needs to build a list of filenames to read from, so that it can @@ -2656,7 +2532,7 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, if(!data->asi) return CURLE_OUT_OF_MEMORY; } - result = Curl_setstropt(&data->set.str[STRING_ALTSVC], ptr); + result = Curl_setstropt(&s->str[STRING_ALTSVC], ptr); if(result) return result; if(ptr) @@ -2668,35 +2544,35 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, size_t plen = 0; if(!ptr) { - data->set.tls_ech = CURLECH_DISABLE; + s->tls_ech = CURLECH_DISABLE; return CURLE_OK; } plen = strlen(ptr); if(plen > CURL_MAX_INPUT_LENGTH) { - data->set.tls_ech = CURLECH_DISABLE; + s->tls_ech = CURLECH_DISABLE; return CURLE_BAD_FUNCTION_ARGUMENT; } /* set tls_ech flag value, preserving CLA_CFG bit */ if(!strcmp(ptr, "false")) - data->set.tls_ech = CURLECH_DISABLE | - (data->set.tls_ech & CURLECH_CLA_CFG); + s->tls_ech = CURLECH_DISABLE | + (s->tls_ech & CURLECH_CLA_CFG); else if(!strcmp(ptr, "grease")) - data->set.tls_ech = CURLECH_GREASE | - (data->set.tls_ech & CURLECH_CLA_CFG); + s->tls_ech = CURLECH_GREASE | + (s->tls_ech & CURLECH_CLA_CFG); else if(!strcmp(ptr, "true")) - data->set.tls_ech = CURLECH_ENABLE | - (data->set.tls_ech & CURLECH_CLA_CFG); + s->tls_ech = CURLECH_ENABLE | + (s->tls_ech & CURLECH_CLA_CFG); else if(!strcmp(ptr, "hard")) - data->set.tls_ech = CURLECH_HARD | - (data->set.tls_ech & CURLECH_CLA_CFG); + s->tls_ech = CURLECH_HARD | + (s->tls_ech & CURLECH_CLA_CFG); else if(plen > 5 && !strncmp(ptr, "ecl:", 4)) { - result = Curl_setstropt(&data->set.str[STRING_ECH_CONFIG], ptr + 4); + result = Curl_setstropt(&s->str[STRING_ECH_CONFIG], ptr + 4); if(result) return result; - data->set.tls_ech |= CURLECH_CLA_CFG; + s->tls_ech |= CURLECH_CLA_CFG; } else if(plen > 4 && !strncmp(ptr, "pn:", 3)) { - result = Curl_setstropt(&data->set.str[STRING_ECH_PUBLIC], ptr + 3); + result = Curl_setstropt(&s->str[STRING_ECH_PUBLIC], ptr + 3); if(result) return result; } @@ -2712,13 +2588,14 @@ static CURLcode setopt_cptr(struct Curl_easy *data, CURLoption option, static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, va_list param) { + struct UserDefined *s = &data->set; switch(option) { case CURLOPT_PROGRESSFUNCTION: /* * Progress callback function */ - data->set.fprogress = va_arg(param, curl_progress_callback); - if(data->set.fprogress) + s->fprogress = va_arg(param, curl_progress_callback); + if(s->fprogress) data->progress.callback = TRUE; /* no longer internal */ else data->progress.callback = FALSE; /* NULL enforces internal */ @@ -2728,8 +2605,8 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, /* * Transfer info callback function */ - data->set.fxferinfo = va_arg(param, curl_xferinfo_callback); - if(data->set.fxferinfo) + s->fxferinfo = va_arg(param, curl_xferinfo_callback); + if(s->fxferinfo) data->progress.callback = TRUE; /* no longer internal */ else data->progress.callback = FALSE; /* NULL enforces internal */ @@ -2739,7 +2616,7 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, /* * stderr write callback. */ - data->set.fdebug = va_arg(param, curl_debug_callback); + s->fdebug = va_arg(param, curl_debug_callback); /* * if the callback provided is NULL, it will use the default callback */ @@ -2748,41 +2625,41 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, /* * Set header write callback */ - data->set.fwrite_header = va_arg(param, curl_write_callback); + s->fwrite_header = va_arg(param, curl_write_callback); break; case CURLOPT_WRITEFUNCTION: /* * Set data write callback */ - data->set.fwrite_func = va_arg(param, curl_write_callback); - if(!data->set.fwrite_func) + s->fwrite_func = va_arg(param, curl_write_callback); + if(!s->fwrite_func) /* When set to NULL, reset to our internal default function */ - data->set.fwrite_func = (curl_write_callback)fwrite; + s->fwrite_func = (curl_write_callback)fwrite; break; case CURLOPT_READFUNCTION: /* * Read data callback */ - data->set.fread_func_set = va_arg(param, curl_read_callback); - if(!data->set.fread_func_set) { - data->set.is_fread_set = 0; + s->fread_func_set = va_arg(param, curl_read_callback); + if(!s->fread_func_set) { + s->is_fread_set = 0; /* When set to NULL, reset to our internal default function */ - data->set.fread_func_set = (curl_read_callback)fread; + s->fread_func_set = (curl_read_callback)fread; } else - data->set.is_fread_set = 1; + s->is_fread_set = 1; break; case CURLOPT_SEEKFUNCTION: /* * Seek callback. Might be NULL. */ - data->set.seek_func = va_arg(param, curl_seek_callback); + s->seek_func = va_arg(param, curl_seek_callback); break; case CURLOPT_IOCTLFUNCTION: /* * I/O control callback. Might be NULL. */ - data->set.ioctl_func = va_arg(param, curl_ioctl_callback); + s->ioctl_func = va_arg(param, curl_ioctl_callback); break; case CURLOPT_SSL_CTX_FUNCTION: /* @@ -2790,7 +2667,7 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_SSL_CTX)) { - data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); + s->ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback); break; } else @@ -2801,7 +2678,7 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, /* * socket callback function: called after socket() but before connect() */ - data->set.fsockopt = va_arg(param, curl_sockopt_callback); + s->fsockopt = va_arg(param, curl_sockopt_callback); break; case CURLOPT_OPENSOCKETFUNCTION: @@ -2809,7 +2686,7 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, * open/create socket callback function: called instead of socket(), * before connect() */ - data->set.fopensocket = va_arg(param, curl_opensocket_callback); + s->fopensocket = va_arg(param, curl_opensocket_callback); break; case CURLOPT_CLOSESOCKETFUNCTION: @@ -2817,7 +2694,7 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, * close socket callback function: called instead of close() * when shutting down a connection */ - data->set.fclosesocket = va_arg(param, curl_closesocket_callback); + s->fclosesocket = va_arg(param, curl_closesocket_callback); break; case CURLOPT_RESOLVER_START_FUNCTION: @@ -2825,21 +2702,21 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, * resolver start callback function: called before a new resolver request * is started */ - data->set.resolver_start = va_arg(param, curl_resolver_start_callback); + s->resolver_start = va_arg(param, curl_resolver_start_callback); break; #ifdef USE_SSH #ifdef USE_LIBSSH2 case CURLOPT_SSH_HOSTKEYFUNCTION: /* the callback to check the hostkey without the knownhost file */ - data->set.ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback); + s->ssh_hostkeyfunc = va_arg(param, curl_sshhostkeycallback); break; #endif case CURLOPT_SSH_KEYFUNCTION: /* setting to NULL is fine since the ssh.c functions themselves will then revert to use the internal default */ - data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback); + s->ssh_keyfunc = va_arg(param, curl_sshkeycallback); break; #endif /* USE_SSH */ @@ -2847,35 +2724,35 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, #ifndef CURL_DISABLE_RTSP case CURLOPT_INTERLEAVEFUNCTION: /* Set the user defined RTP write function */ - data->set.fwrite_rtp = va_arg(param, curl_write_callback); + s->fwrite_rtp = va_arg(param, curl_write_callback); break; #endif #ifndef CURL_DISABLE_FTP case CURLOPT_CHUNK_BGN_FUNCTION: - data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); + s->chunk_bgn = va_arg(param, curl_chunk_bgn_callback); break; case CURLOPT_CHUNK_END_FUNCTION: - data->set.chunk_end = va_arg(param, curl_chunk_end_callback); + s->chunk_end = va_arg(param, curl_chunk_end_callback); break; case CURLOPT_FNMATCH_FUNCTION: - data->set.fnmatch = va_arg(param, curl_fnmatch_callback); + s->fnmatch = va_arg(param, curl_fnmatch_callback); break; #endif #ifndef CURL_DISABLE_HTTP case CURLOPT_TRAILERFUNCTION: - data->set.trailer_callback = va_arg(param, curl_trailer_callback); + s->trailer_callback = va_arg(param, curl_trailer_callback); break; #endif #ifndef CURL_DISABLE_HSTS case CURLOPT_HSTSREADFUNCTION: - data->set.hsts_read = va_arg(param, curl_hstsread_callback); + s->hsts_read = va_arg(param, curl_hstsread_callback); break; case CURLOPT_HSTSWRITEFUNCTION: - data->set.hsts_write = va_arg(param, curl_hstswrite_callback); + s->hsts_write = va_arg(param, curl_hstswrite_callback); break; #endif case CURLOPT_PREREQFUNCTION: - data->set.fprereq = va_arg(param, curl_prereq_callback); + s->fprereq = va_arg(param, curl_prereq_callback); break; default: return CURLE_UNKNOWN_OPTION; @@ -2886,13 +2763,14 @@ static CURLcode setopt_func(struct Curl_easy *data, CURLoption option, static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, curl_off_t offt) { + struct UserDefined *s = &data->set; switch(option) { case CURLOPT_TIMEVALUE_LARGE: /* * This is the value to compare with the remote document with the * method set with CURLOPT_TIMECONDITION */ - data->set.timevalue = (time_t)offt; + s->timevalue = (time_t)offt; break; /* MQTT "borrows" some of the HTTP options */ @@ -2904,13 +2782,13 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, if(offt < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - if(data->set.postfieldsize < offt && - data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) { + if(s->postfieldsize < offt && + s->postfields == s->str[STRING_COPYPOSTFIELDS]) { /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */ - Curl_safefree(data->set.str[STRING_COPYPOSTFIELDS]); - data->set.postfields = NULL; + Curl_safefree(s->str[STRING_COPYPOSTFIELDS]); + s->postfields = NULL; } - data->set.postfieldsize = offt; + s->postfieldsize = offt; break; case CURLOPT_INFILESIZE_LARGE: /* @@ -2919,7 +2797,7 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, */ if(offt < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.filesize = offt; + s->filesize = offt; break; case CURLOPT_MAX_SEND_SPEED_LARGE: /* @@ -2928,7 +2806,7 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, */ if(offt < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.max_send_speed = offt; + s->max_send_speed = offt; break; case CURLOPT_MAX_RECV_SPEED_LARGE: /* @@ -2937,7 +2815,7 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, */ if(offt < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.max_recv_speed = offt; + s->max_recv_speed = offt; break; case CURLOPT_RESUME_FROM_LARGE: /* @@ -2945,7 +2823,7 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, */ if(offt < -1) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.set_resume_from = offt; + s->set_resume_from = offt; break; case CURLOPT_MAXFILESIZE_LARGE: /* @@ -2953,7 +2831,7 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, */ if(offt < 0) return CURLE_BAD_FUNCTION_ARGUMENT; - data->set.max_filesize = offt; + s->max_filesize = offt; break; default: @@ -2965,23 +2843,24 @@ static CURLcode setopt_offt(struct Curl_easy *data, CURLoption option, static CURLcode setopt_blob(struct Curl_easy *data, CURLoption option, struct curl_blob *blob) { + struct UserDefined *s = &data->set; switch(option) { case CURLOPT_SSLCERT_BLOB: /* * Blob that holds file content of the SSL certificate to use */ - return Curl_setblobopt(&data->set.blobs[BLOB_CERT], blob); + return Curl_setblobopt(&s->blobs[BLOB_CERT], blob); #ifndef CURL_DISABLE_PROXY case CURLOPT_PROXY_SSLCERT_BLOB: /* * Blob that holds file content of the SSL certificate to use for proxy */ - return Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY], blob); + return Curl_setblobopt(&s->blobs[BLOB_CERT_PROXY], blob); case CURLOPT_PROXY_SSLKEY_BLOB: /* * Blob that holds file content of the SSL key to use for proxy */ - return Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY], blob); + return Curl_setblobopt(&s->blobs[BLOB_KEY_PROXY], blob); case CURLOPT_PROXY_CAINFO_BLOB: /* * Blob that holds CA info for SSL connection proxy. @@ -2989,21 +2868,21 @@ static CURLcode setopt_blob(struct Curl_easy *data, CURLoption option, */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) - return Curl_setblobopt(&data->set.blobs[BLOB_CAINFO_PROXY], blob); + return Curl_setblobopt(&s->blobs[BLOB_CAINFO_PROXY], blob); #endif return CURLE_NOT_BUILT_IN; case CURLOPT_PROXY_ISSUERCERT_BLOB: /* * Blob that holds Issuer certificate to check certificates issuer */ - return Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY], + return Curl_setblobopt(&s->blobs[BLOB_SSL_ISSUERCERT_PROXY], blob); #endif case CURLOPT_SSLKEY_BLOB: /* * Blob that holds file content of the SSL key to use */ - return Curl_setblobopt(&data->set.blobs[BLOB_KEY], blob); + return Curl_setblobopt(&s->blobs[BLOB_KEY], blob); case CURLOPT_CAINFO_BLOB: /* * Blob that holds CA info for SSL connection. @@ -3011,14 +2890,14 @@ static CURLcode setopt_blob(struct Curl_easy *data, CURLoption option, */ #ifdef USE_SSL if(Curl_ssl_supports(data, SSLSUPP_CAINFO_BLOB)) - return Curl_setblobopt(&data->set.blobs[BLOB_CAINFO], blob); + return Curl_setblobopt(&s->blobs[BLOB_CAINFO], blob); #endif return CURLE_NOT_BUILT_IN; case CURLOPT_ISSUERCERT_BLOB: /* * Blob that holds Issuer certificate to check certificates issuer */ - return Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT], blob); + return Curl_setblobopt(&s->blobs[BLOB_SSL_ISSUERCERT], blob); default: return CURLE_UNKNOWN_OPTION; diff --git a/deps/curl/lib/setopt.h b/deps/curl/lib/setopt.h index b0237467bd6..c323dd74a37 100644 --- a/deps/curl/lib/setopt.h +++ b/deps/curl/lib/setopt.h @@ -24,6 +24,13 @@ * ***************************************************************************/ +#ifdef USE_SSL +CURLcode Curl_setopt_SSLVERSION(struct Curl_easy *data, CURLoption option, + long arg); +#else +#define Curl_setopt_SSLVERSION(a,b,c) CURLE_NOT_BUILT_IN +#endif + CURLcode Curl_setstropt(char **charp, const char *s) WARN_UNUSED_RESULT; CURLcode Curl_setblobopt(struct curl_blob **blobp, const struct curl_blob *blob) WARN_UNUSED_RESULT; diff --git a/deps/curl/lib/sha256.c b/deps/curl/lib/sha256.c index d73e0ef0937..6f519add58a 100644 --- a/deps/curl/lib/sha256.c +++ b/deps/curl/lib/sha256.c @@ -25,8 +25,8 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) \ - || defined(USE_LIBSSH2) || defined(USE_SSL) +#if !defined(CURL_DISABLE_AWS) || !defined(CURL_DISABLE_DIGEST_AUTH) || \ + defined(USE_LIBSSH2) || defined(USE_SSL) #include "curlx/warnless.h" #include "curl_sha256.h" @@ -38,9 +38,8 @@ #include #elif defined(USE_MBEDTLS) #include -#if(MBEDTLS_VERSION_NUMBER >= 0x02070000) && \ - (MBEDTLS_VERSION_NUMBER < 0x03000000) - #define HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS +#if MBEDTLS_VERSION_NUMBER < 0x03020000 + #error "mbedTLS 3.2.0 or later required" #endif #include #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ @@ -134,11 +133,7 @@ typedef mbedtls_sha256_context my_sha256_ctx; static CURLcode my_sha256_init(void *ctx) { -#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - (void) mbedtls_sha256_starts(ctx, 0); -#else - (void) mbedtls_sha256_starts_ret(ctx, 0); -#endif + (void)mbedtls_sha256_starts(ctx, 0); return CURLE_OK; } @@ -146,20 +141,12 @@ static void my_sha256_update(void *ctx, const unsigned char *data, unsigned int length) { -#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - (void) mbedtls_sha256_update(ctx, data, length); -#else - (void) mbedtls_sha256_update_ret(ctx, data, length); -#endif + (void)mbedtls_sha256_update(ctx, data, length); } static void my_sha256_final(unsigned char *digest, void *ctx) { -#if !defined(HAS_MBEDTLS_RESULT_CODE_BASED_FUNCTIONS) - (void) mbedtls_sha256_finish(ctx, digest); -#else - (void) mbedtls_sha256_finish_ret(ctx, digest); -#endif + (void)mbedtls_sha256_finish(ctx, digest); } #elif defined(AN_APPLE_OS) @@ -167,7 +154,7 @@ typedef CC_SHA256_CTX my_sha256_ctx; static CURLcode my_sha256_init(void *ctx) { - (void) CC_SHA256_Init(ctx); + (void)CC_SHA256_Init(ctx); return CURLE_OK; } @@ -175,12 +162,12 @@ static void my_sha256_update(void *ctx, const unsigned char *data, unsigned int length) { - (void) CC_SHA256_Update(ctx, data, length); + (void)CC_SHA256_Update(ctx, data, length); } static void my_sha256_final(unsigned char *digest, void *ctx) { - (void) CC_SHA256_Final(digest, ctx); + (void)CC_SHA256_Final(digest, ctx); } #elif defined(USE_WIN32_CRYPTO) @@ -191,7 +178,8 @@ struct sha256_ctx { }; typedef struct sha256_ctx my_sha256_ctx; -#if !defined(CALG_SHA_256) +/* Offered when targeting Vista (XP SP2+) */ +#ifndef CALG_SHA_256 #define CALG_SHA_256 0x0000800c #endif diff --git a/deps/curl/lib/smb.c b/deps/curl/lib/smb.c index 3eee16468de..81cf6e7cc1f 100644 --- a/deps/curl/lib/smb.c +++ b/deps/curl/lib/smb.c @@ -36,6 +36,7 @@ #include "connect.h" #include "progress.h" #include "transfer.h" +#include "select.h" #include "vtls/vtls.h" #include "curl_ntlm_core.h" #include "escape.h" @@ -298,8 +299,8 @@ 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 int smb_getsock(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *socks); +static CURLcode smb_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode smb_parse_url_path(struct Curl_easy *data, struct smb_conn *smbc, struct smb_request *req); @@ -316,10 +317,10 @@ const struct Curl_handler Curl_handler_smb = { smb_connect, /* connect_it */ smb_connection_state, /* connecting */ smb_request_state, /* doing */ - smb_getsock, /* proto_getsock */ - smb_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + smb_pollset, /* proto_pollset */ + smb_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -345,10 +346,10 @@ const struct Curl_handler Curl_handler_smbs = { smb_connect, /* connect_it */ smb_connection_state, /* connecting */ smb_request_state, /* doing */ - smb_getsock, /* proto_getsock */ - smb_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + smb_pollset, /* proto_pollset */ + smb_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -496,7 +497,7 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done) struct smb_conn *smbc = Curl_conn_meta_get(conn, CURL_META_SMB_CONN); char *slash; - (void) done; + (void)done; if(!smbc) return CURLE_FAILED_INIT; @@ -1204,12 +1205,10 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done) return CURLE_OK; } -static int smb_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks) +static CURLcode smb_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - (void)data; - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0); + return Curl_pollset_add_inout(data, ps, data->conn->sock[FIRSTSOCKET]); } static CURLcode smb_do(struct Curl_easy *data, bool *done) @@ -1267,5 +1266,4 @@ static CURLcode smb_parse_url_path(struct Curl_easy *data, return CURLE_OK; } -#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE && - SIZEOF_CURL_OFF_T > 4 */ +#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE && SIZEOF_CURL_OFF_T > 4 */ diff --git a/deps/curl/lib/smb.h b/deps/curl/lib/smb.h index eb4df6550a3..aa0be881c13 100644 --- a/deps/curl/lib/smb.h +++ b/deps/curl/lib/smb.h @@ -26,12 +26,11 @@ ***************************************************************************/ #if !defined(CURL_DISABLE_SMB) && defined(USE_CURL_NTLM_CORE) && \ - (SIZEOF_CURL_OFF_T > 4) + (SIZEOF_CURL_OFF_T > 4) extern const struct Curl_handler Curl_handler_smb; extern const struct Curl_handler Curl_handler_smbs; -#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE && - SIZEOF_CURL_OFF_T > 4 */ +#endif /* CURL_DISABLE_SMB && USE_CURL_NTLM_CORE && SIZEOF_CURL_OFF_T > 4 */ #endif /* HEADER_CURL_SMB_H */ diff --git a/deps/curl/lib/smtp.c b/deps/curl/lib/smtp.c index d2adf43a7c2..5dba1f9ea8c 100644 --- a/deps/curl/lib/smtp.c +++ b/deps/curl/lib/smtp.c @@ -157,8 +157,8 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done); static CURLcode smtp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead); static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done); -static int smtp_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); +static CURLcode smtp_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done); static CURLcode smtp_setup_connection(struct Curl_easy *data, struct connectdata *conn); @@ -169,7 +169,8 @@ static CURLcode smtp_parse_url_path(struct Curl_easy *data, static CURLcode smtp_parse_custom_request(struct Curl_easy *data, struct SMTP *smtp); static CURLcode smtp_parse_address(const char *fqma, - char **address, struct hostname *host); + char **address, struct hostname *host, + const char **suffix); static CURLcode smtp_perform_auth(struct Curl_easy *data, const char *mech, const struct bufref *initresp); static CURLcode smtp_continue_auth(struct Curl_easy *data, const char *mech, @@ -191,10 +192,10 @@ const struct Curl_handler Curl_handler_smtp = { smtp_connect, /* connect_it */ smtp_multi_statemach, /* connecting */ smtp_doing, /* doing */ - smtp_getsock, /* proto_getsock */ - smtp_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + smtp_pollset, /* proto_pollset */ + smtp_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -222,10 +223,10 @@ const struct Curl_handler Curl_handler_smtps = { smtp_connect, /* connect_it */ smtp_multi_statemach, /* connecting */ smtp_doing, /* doing */ - smtp_getsock, /* proto_getsock */ - smtp_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + smtp_pollset, /* proto_pollset */ + smtp_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -357,7 +358,7 @@ static void smtp_state(struct Curl_easy *data, struct smtp_conn *smtpc, smtpstate newstate) { -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS /* for debug purposes */ static const char * const names[] = { "STOP", @@ -379,6 +380,8 @@ static void smtp_state(struct Curl_easy *data, if(smtpc->state != newstate) CURL_TRC_SMTP(data, "state change from %s to %s", names[smtpc->state], names[newstate]); +#else + (void)data; #endif smtpc->state = newstate; @@ -618,11 +621,12 @@ static CURLcode smtp_perform_command(struct Curl_easy *data, if((!smtp->custom) || (!smtp->custom[0])) { char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; + const char *suffix = ""; /* Parse the mailbox to verify into the local address and hostname parts, converting the hostname to an IDN A-label if necessary */ result = smtp_parse_address(smtp->rcpt->data, - &address, &host); + &address, &host, &suffix); if(result) return result; @@ -692,11 +696,12 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, if(data->set.str[STRING_MAIL_FROM]) { char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; + const char *suffix = ""; /* Parse the FROM mailbox into the local address and hostname parts, converting the hostname to an IDN A-label if necessary */ result = smtp_parse_address(data->set.str[STRING_MAIL_FROM], - &address, &host); + &address, &host, &suffix); if(result) goto out; @@ -707,14 +712,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, (!Curl_is_ASCII_name(host.name))); if(host.name) { - from = aprintf("<%s@%s>", address, host.name); + from = aprintf("<%s@%s>%s", address, host.name, suffix); Curl_free_idnconverted_hostname(&host); } else /* An invalid mailbox was provided but we will simply let the server worry about that and reply with a 501 error */ - from = aprintf("<%s>", address); + from = aprintf("<%s>%s", address, suffix); free(address); } @@ -732,11 +737,12 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, if(data->set.str[STRING_MAIL_AUTH][0] != '\0') { char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; + const char *suffix = ""; /* Parse the AUTH mailbox into the local address and hostname parts, converting the hostname to an IDN A-label if necessary */ result = smtp_parse_address(data->set.str[STRING_MAIL_AUTH], - &address, &host); + &address, &host, &suffix); if(result) goto out; @@ -748,14 +754,14 @@ static CURLcode smtp_perform_mail(struct Curl_easy *data, utf8 = TRUE; if(host.name) { - auth = aprintf("<%s@%s>", address, host.name); + auth = aprintf("<%s@%s>%s", address, host.name, suffix); Curl_free_idnconverted_hostname(&host); } else /* An invalid mailbox was provided but we will simply let the server worry about it */ - auth = aprintf("<%s>", address); + auth = aprintf("<%s>%s", address, suffix); free(address); } else @@ -865,22 +871,24 @@ static CURLcode smtp_perform_rcpt_to(struct Curl_easy *data, CURLcode result = CURLE_OK; char *address = NULL; struct hostname host = { NULL, NULL, NULL, NULL }; + const char *suffix = ""; /* Parse the recipient mailbox into the local address and hostname parts, converting the hostname to an IDN A-label if necessary */ result = smtp_parse_address(smtp->rcpt->data, - &address, &host); + &address, &host, &suffix); if(result) return result; /* Send the RCPT TO command */ if(host.name) - result = Curl_pp_sendf(data, &smtpc->pp, "RCPT TO:<%s@%s>", - address, host.name); + result = Curl_pp_sendf(data, &smtpc->pp, "RCPT TO:<%s@%s>%s", + address, host.name, suffix); else /* An invalid mailbox was provided but we will simply let the server worry about that and reply with a 501 error */ - result = Curl_pp_sendf(data, &smtpc->pp, "RCPT TO:<%s>", address); + result = Curl_pp_sendf(data, &smtpc->pp, "RCPT TO:<%s>%s", + address, suffix); Curl_free_idnconverted_hostname(&host); free(address); @@ -916,7 +924,7 @@ static CURLcode smtp_state_servergreet_resp(struct Curl_easy *data, smtpstate instate) { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(smtpcode/100 != 2) { failf(data, "Got unexpected smtp-server response: %d", smtpcode); @@ -935,7 +943,7 @@ static CURLcode smtp_state_starttls_resp(struct Curl_easy *data, smtpstate instate) { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; /* Pipelining in response is forbidden. */ if(smtpc->pp.overflow) @@ -965,7 +973,7 @@ static CURLcode smtp_state_ehlo_resp(struct Curl_easy *data, const char *line = curlx_dyn_ptr(&smtpc->pp.recvbuf); size_t len = smtpc->pp.nfinal; - (void)instate; /* no use for this yet */ + (void)instate; if(smtpcode/100 != 2 && smtpcode != 1) { if(data->set.use_ssl <= CURLUSESSL_TRY @@ -1066,7 +1074,7 @@ static CURLcode smtp_state_helo_resp(struct Curl_easy *data, smtpstate instate) { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(smtpcode/100 != 2) { failf(data, "Remote access denied: %d", smtpcode); @@ -1088,7 +1096,7 @@ static CURLcode smtp_state_auth_resp(struct Curl_easy *data, CURLcode result = CURLE_OK; saslprogress progress; - (void)instate; /* no use for this yet */ + (void)instate; result = Curl_sasl_continue(&smtpc->sasl, data, smtpcode, &progress); if(!result) @@ -1118,7 +1126,7 @@ static CURLcode smtp_state_command_resp(struct Curl_easy *data, char *line = curlx_dyn_ptr(&smtpc->pp.recvbuf); size_t len = smtpc->pp.nfinal; - (void)instate; /* no use for this yet */ + (void)instate; if((smtp->rcpt && smtpcode/100 != 2 && smtpcode != 553 && smtpcode != 1) || (!smtp->rcpt && smtpcode/100 != 2 && smtpcode != 1)) { @@ -1158,7 +1166,7 @@ static CURLcode smtp_state_mail_resp(struct Curl_easy *data, smtpstate instate) { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(smtpcode/100 != 2) { failf(data, "MAIL failed: %d", smtpcode); @@ -1182,7 +1190,7 @@ static CURLcode smtp_state_rcpt_resp(struct Curl_easy *data, bool is_smtp_err = FALSE; bool is_smtp_blocking_err = FALSE; - (void)instate; /* no use for this yet */ + (void)instate; is_smtp_err = (smtpcode/100 != 2); @@ -1238,7 +1246,7 @@ static CURLcode smtp_state_data_resp(struct Curl_easy *data, smtpstate instate) { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(smtpcode != 354) { failf(data, "DATA failed: %d", smtpcode); @@ -1249,7 +1257,7 @@ static CURLcode smtp_state_data_resp(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); /* SMTP upload */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* End of DO phase */ smtp_state(data, smtpc, SMTP_STOP); @@ -1267,7 +1275,7 @@ static CURLcode smtp_state_postdata_resp(struct Curl_easy *data, { CURLcode result = CURLE_OK; - (void)instate; /* no use for this yet */ + (void)instate; if(smtpcode != 250) result = CURLE_WEIRD_SERVER_REPLY; @@ -1405,12 +1413,12 @@ static CURLcode smtp_block_statemach(struct Curl_easy *data, } /* For the SMTP "protocol connect" and "doing" phases only */ -static int smtp_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks) +static CURLcode smtp_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - struct smtp_conn *smtpc = Curl_conn_meta_get(conn, CURL_META_SMTP_CONN); - return smtpc ? - Curl_pp_getsock(data, &smtpc->pp, socks) : GETSOCK_BLANK; + struct smtp_conn *smtpc = + Curl_conn_meta_get(data->conn, CURL_META_SMTP_CONN); + return smtpc ? Curl_pp_pollset(data, &smtpc->pp, ps) : CURLE_OK; } /*********************************************************************** @@ -1866,10 +1874,11 @@ static CURLcode smtp_parse_custom_request(struct Curl_easy *data, * the address part with the hostname being NULL. */ static CURLcode smtp_parse_address(const char *fqma, char **address, - struct hostname *host) + struct hostname *host, const char **suffix) { CURLcode result = CURLE_OK; size_t length; + char *addressend; /* Duplicate the fully qualified email address so we can manipulate it, ensuring it does not contain the delimiters if specified */ @@ -1877,10 +1886,19 @@ static CURLcode smtp_parse_address(const char *fqma, char **address, if(!dup) return CURLE_OUT_OF_MEMORY; - length = strlen(dup); - if(length) { - if(dup[length - 1] == '>') - dup[length - 1] = '\0'; + if(fqma[0] != '<') { + length = strlen(dup); + if(length) { + if(dup[length - 1] == '>') + dup[length - 1] = '\0'; + } + } + else { + addressend = strrchr(dup, '>'); + if(addressend) { + *addressend = '\0'; + *suffix = addressend + 1; + } } /* Extract the hostname from the address (if we can) */ @@ -1890,7 +1908,7 @@ static CURLcode smtp_parse_address(const char *fqma, char **address, host->name = host->name + 1; /* Attempt to convert the hostname to IDN ACE */ - (void) Curl_idnconvert_hostname(host); + (void)Curl_idnconvert_hostname(host); /* If Curl_idnconvert_hostname() fails then we shall attempt to continue and send the hostname using UTF-8 rather than as 7-bit ACE (which is @@ -2051,8 +2069,7 @@ static const struct Curl_crtype cr_eob = { Curl_creader_def_needs_rewind, cr_eob_total_length, Curl_creader_def_resume_from, - Curl_creader_def_rewind, - Curl_creader_def_unpause, + Curl_creader_def_cntrl, Curl_creader_def_is_paused, Curl_creader_def_done, sizeof(struct cr_eob_ctx) diff --git a/deps/curl/lib/socketpair.c b/deps/curl/lib/socketpair.c index 1d1d5a66f30..4151a9bb979 100644 --- a/deps/curl/lib/socketpair.c +++ b/deps/curl/lib/socketpair.c @@ -84,6 +84,7 @@ int Curl_pipe(curl_socket_t socks[2], bool nonblocking) #ifndef CURL_DISABLE_SOCKETPAIR #ifdef HAVE_SOCKETPAIR +#ifdef USE_SOCKETPAIR int Curl_socketpair(int domain, int type, int protocol, curl_socket_t socks[2], bool nonblocking) { @@ -104,6 +105,7 @@ int Curl_socketpair(int domain, int type, int protocol, #endif return 0; } +#endif /* USE_SOCKETPAIR */ #else /* !HAVE_SOCKETPAIR */ #ifdef _WIN32 /* @@ -199,7 +201,7 @@ int Curl_socketpair(int domain, int type, int protocol, pfd[0].events = POLLIN; pfd[0].revents = 0; (void)Curl_poll(pfd, 1, 1000); /* one second */ - socks[1] = accept(listener, NULL, NULL); + socks[1] = CURL_ACCEPT(listener, NULL, NULL); if(socks[1] == CURL_SOCKET_BAD) goto error; else { diff --git a/deps/curl/lib/socketpair.h b/deps/curl/lib/socketpair.h index 5541899445b..e601f5f71be 100644 --- a/deps/curl/lib/socketpair.h +++ b/deps/curl/lib/socketpair.h @@ -66,8 +66,9 @@ int Curl_pipe(curl_socket_t socks[2], bool nonblocking); #define SOCKETPAIR_TYPE SOCK_STREAM #endif -#define wakeup_create(p,nb)\ -Curl_socketpair(SOCKETPAIR_FAMILY, SOCKETPAIR_TYPE, 0, p, nb) +#define USE_SOCKETPAIR +#define wakeup_create(p,nb) \ + Curl_socketpair(SOCKETPAIR_FAMILY, SOCKETPAIR_TYPE, 0, p, nb) #endif /* USE_EVENTFD */ diff --git a/deps/curl/lib/socks.c b/deps/curl/lib/socks.c index 7d25ef52087..fc6c9730f87 100644 --- a/deps/curl/lib/socks.c +++ b/deps/curl/lib/socks.c @@ -24,7 +24,7 @@ #include "curl_setup.h" -#if !defined(CURL_DISABLE_PROXY) +#ifndef CURL_DISABLE_PROXY #ifdef HAVE_NETINET_IN_H #include @@ -141,13 +141,15 @@ int Curl_blockread_all(struct Curl_cfilter *cf, #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #define DEBUG_AND_VERBOSE -#define sxstate(x,d,y) socksstate(x,d,y, __LINE__) +#define sxstate(x,c,d,y) socksstate(x,c,d,y, __LINE__) #else -#define sxstate(x,d,y) socksstate(x,d,y) +#define sxstate(x,c,d,y) socksstate(x,c,d,y) #endif /* always use this function to change state, to make debugging easier */ -static void socksstate(struct socks_state *sx, struct Curl_easy *data, +static void socksstate(struct socks_state *sx, + struct Curl_cfilter *cf, + struct Curl_easy *data, enum connect_t state #ifdef DEBUG_AND_VERBOSE , int lineno @@ -179,6 +181,7 @@ static void socksstate(struct socks_state *sx, struct Curl_easy *data, }; #endif + (void)cf; (void)data; if(oldstate == state) /* do not bother when the new state is the same as the old state */ @@ -187,10 +190,8 @@ static void socksstate(struct socks_state *sx, struct Curl_easy *data, sx->state = state; #ifdef DEBUG_AND_VERBOSE - infof(data, - "SXSTATE: %s => %s; line %d", - socks_statename[oldstate], socks_statename[sx->state], - lineno); + CURL_TRC_CF(data, cf, "[%s] -> [%s] (line %d)", + socks_statename[oldstate], socks_statename[sx->state], lineno); #endif } @@ -284,12 +285,10 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, case CONNECT_SOCKS_INIT: /* SOCKS4 can only do IPv4, insist! */ conn->ip_version = CURL_IPRESOLVE_V4; - if(conn->bits.httpproxy) - infof(data, "SOCKS4%s: connecting to HTTP proxy %s port %d", - protocol4a ? "a" : "", sx->hostname, sx->remote_port); - - infof(data, "SOCKS4 communication to %s:%d", - sx->hostname, sx->remote_port); + CURL_TRC_CF(data, cf, "SOCKS4%s communication to%s %s:%d", + protocol4a ? "a" : "", + conn->bits.httpproxy ? " HTTP proxy" : "", + sx->hostname, sx->remote_port); /* * Compose socks4 request @@ -313,18 +312,19 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, cf->conn->ip_version, TRUE, &dns); if(result == CURLE_AGAIN) { - sxstate(sx, data, CONNECT_RESOLVING); - infof(data, "SOCKS4 non-blocking resolve of %s", sx->hostname); + sxstate(sx, cf, data, CONNECT_RESOLVING); + CURL_TRC_CF(data, cf, "SOCKS4 non-blocking resolve of %s", + sx->hostname); return CURLPX_OK; } else if(result) return CURLPX_RESOLVE_HOST; - sxstate(sx, data, CONNECT_RESOLVED); + sxstate(sx, cf, data, CONNECT_RESOLVED); goto CONNECT_RESOLVED; } /* socks4a does not resolve anything locally */ - sxstate(sx, data, CONNECT_REQ_INIT); + sxstate(sx, cf, data, CONNECT_REQ_INIT); goto CONNECT_REQ_INIT; case CONNECT_RESOLVING: @@ -362,8 +362,8 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, socksreq[6] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[2]; socksreq[7] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[3]; - infof(data, "SOCKS4 connect to IPv4 %s (locally resolved)", buf); - + CURL_TRC_CF(data, cf, "SOCKS4 connect to IPv4 %s (locally resolved)", + buf); Curl_resolv_unlink(data, &dns); /* not used anymore from now on */ } else @@ -424,7 +424,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, sx->outp = socksreq; DEBUGASSERT(packetsize <= sizeof(sx->buffer)); sx->outstanding = packetsize; - sxstate(sx, data, CONNECT_REQ_SENDING); + sxstate(sx, cf, data, CONNECT_REQ_SENDING); } FALLTHROUGH(); case CONNECT_REQ_SENDING: @@ -440,7 +440,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, /* done sending! */ sx->outstanding = 8; /* receive data size */ sx->outp = socksreq; - sxstate(sx, data, CONNECT_SOCKS_READ); + sxstate(sx, cf, data, CONNECT_SOCKS_READ); FALLTHROUGH(); case CONNECT_SOCKS_READ: @@ -453,7 +453,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, /* remain in reading state */ return CURLPX_OK; } - sxstate(sx, data, CONNECT_DONE); + sxstate(sx, cf, data, CONNECT_DONE); break; default: /* lots of unused states in SOCKS4 */ break; @@ -488,11 +488,11 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, /* Result */ switch(socksreq[1]) { case 90: - infof(data, "SOCKS4%s request granted.", protocol4a ? "a" : ""); + CURL_TRC_CF(data, cf, "SOCKS4%s request granted.", protocol4a ? "a" : ""); break; case 91: failf(data, - "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" ", request rejected or failed.", socksreq[4], socksreq[5], socksreq[6], socksreq[7], (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), @@ -500,7 +500,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, return CURLPX_REQUEST_FAILED; case 92: failf(data, - "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" ", request rejected because SOCKS server cannot connect to " "identd on the client.", socksreq[4], socksreq[5], socksreq[6], socksreq[7], @@ -509,7 +509,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, return CURLPX_IDENTD; case 93: failf(data, - "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" ", request rejected because the client program and identd " "report different user-ids.", socksreq[4], socksreq[5], socksreq[6], socksreq[7], @@ -518,7 +518,7 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, return CURLPX_IDENTD_DIFFER; default: failf(data, - "cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" + "[SOCKS] cannot complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)" ", Unknown.", socksreq[4], socksreq[5], socksreq[6], socksreq[7], (((unsigned char)socksreq[2] << 8) | (unsigned char)socksreq[3]), @@ -529,6 +529,110 @@ static CURLproxycode do_SOCKS4(struct Curl_cfilter *cf, return CURLPX_OK; /* Proxy was successful! */ } +static CURLproxycode socks5_init(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data, + const bool socks5_resolve_local, + const size_t hostname_len) +{ + struct connectdata *conn = cf->conn; + const unsigned char auth = data->set.socks5auth; + unsigned char *socksreq = sx->buffer; + + if(conn->bits.httpproxy) + CURL_TRC_CF(data, cf, "SOCKS5: connecting to HTTP proxy %s port %d", + sx->hostname, sx->remote_port); + + /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ + if(!socks5_resolve_local && hostname_len > 255) { + failf(data, "SOCKS5: the destination hostname is too long to be " + "resolved remotely by the proxy."); + return CURLPX_LONG_HOSTNAME; + } + + if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) + infof(data, "warning: unsupported value passed to " + "CURLOPT_SOCKS5_AUTH: %u", auth); + if(!(auth & CURLAUTH_BASIC)) + /* disable username/password auth */ + sx->proxy_user = NULL; + + if(!sx->outstanding) { + size_t idx = 0; + socksreq[idx++] = 5; /* version */ + idx++; /* number of authentication methods */ + socksreq[idx++] = 0; /* no authentication */ +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(auth & CURLAUTH_GSSAPI) + socksreq[idx++] = 1; /* GSS-API */ +#endif + if(sx->proxy_user) + socksreq[idx++] = 2; /* username/password */ + /* write the number of authentication methods */ + socksreq[1] = (unsigned char) (idx - 2); + + sx->outp = socksreq; + DEBUGASSERT(idx <= sizeof(sx->buffer)); + sx->outstanding = idx; + } + + return socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, + "initial SOCKS5 request"); +} + +static CURLproxycode socks5_auth_init(struct Curl_cfilter *cf, + struct socks_state *sx, + struct Curl_easy *data) +{ + /* Needs username and password */ + size_t proxy_user_len, proxy_password_len; + size_t len = 0; + unsigned char *socksreq = sx->buffer; + + if(sx->proxy_user && sx->proxy_password) { + proxy_user_len = strlen(sx->proxy_user); + proxy_password_len = strlen(sx->proxy_password); + } + else { + proxy_user_len = 0; + proxy_password_len = 0; + } + + /* username/password request looks like + * +----+------+----------+------+----------+ + * |VER | ULEN | UNAME | PLEN | PASSWD | + * +----+------+----------+------+----------+ + * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | + * +----+------+----------+------+----------+ + */ + socksreq[len++] = 1; /* username/pw subnegotiation version */ + socksreq[len++] = (unsigned char) proxy_user_len; + if(sx->proxy_user && proxy_user_len) { + /* the length must fit in a single byte */ + if(proxy_user_len > 255) { + failf(data, "Excessive username length for proxy auth"); + return CURLPX_LONG_USER; + } + memcpy(socksreq + len, sx->proxy_user, proxy_user_len); + } + len += proxy_user_len; + socksreq[len++] = (unsigned char) proxy_password_len; + if(sx->proxy_password && proxy_password_len) { + /* the length must fit in a single byte */ + if(proxy_password_len > 255) { + failf(data, "Excessive password length for proxy auth"); + return CURLPX_LONG_PASSWD; + } + memcpy(socksreq + len, sx->proxy_password, proxy_password_len); + } + len += proxy_password_len; + sxstate(sx, cf, data, CONNECT_AUTH_SEND); + DEBUGASSERT(len <= sizeof(sx->buffer)); + sx->outstanding = len; + sx->outp = socksreq; + return CURLPX_OK; +} + /* * This function logs in to a SOCKS5 proxy and sends the specifics to the final * destination server. @@ -555,65 +659,21 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, */ struct connectdata *conn = cf->conn; unsigned char *socksreq = sx->buffer; - size_t idx; CURLcode result; CURLproxycode presult; bool socks5_resolve_local = (conn->socks_proxy.proxytype == CURLPROXY_SOCKS5); const size_t hostname_len = strlen(sx->hostname); size_t len = 0; - const unsigned char auth = data->set.socks5auth; bool allow_gssapi = FALSE; struct Curl_dns_entry *dns = NULL; switch(sx->state) { case CONNECT_SOCKS_INIT: - if(conn->bits.httpproxy) - infof(data, "SOCKS5: connecting to HTTP proxy %s port %d", - sx->hostname, sx->remote_port); - - /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */ - if(!socks5_resolve_local && hostname_len > 255) { - failf(data, "SOCKS5: the destination hostname is too long to be " - "resolved remotely by the proxy."); - return CURLPX_LONG_HOSTNAME; - } - - if(auth & ~(CURLAUTH_BASIC | CURLAUTH_GSSAPI)) - infof(data, - "warning: unsupported value passed to CURLOPT_SOCKS5_AUTH: %u", - auth); - if(!(auth & CURLAUTH_BASIC)) - /* disable username/password auth */ - sx->proxy_user = NULL; -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(auth & CURLAUTH_GSSAPI) - allow_gssapi = TRUE; -#endif - - idx = 0; - socksreq[idx++] = 5; /* version */ - idx++; /* number of authentication methods */ - socksreq[idx++] = 0; /* no authentication */ - if(allow_gssapi) - socksreq[idx++] = 1; /* GSS-API */ - if(sx->proxy_user) - socksreq[idx++] = 2; /* username/password */ - /* write the number of authentication methods */ - socksreq[1] = (unsigned char) (idx - 2); - - sx->outp = socksreq; - DEBUGASSERT(idx <= sizeof(sx->buffer)); - sx->outstanding = idx; - presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, - "initial SOCKS5 request"); - if(CURLPX_OK != presult) + presult = socks5_init(cf, sx, data, socks5_resolve_local, hostname_len); + if(presult || sx->outstanding) return presult; - else if(sx->outstanding) { - /* remain in sending state */ - return CURLPX_OK; - } - sxstate(sx, data, CONNECT_SOCKS_READ); + sxstate(sx, cf, data, CONNECT_SOCKS_READ); goto CONNECT_SOCKS_READ_INIT; case CONNECT_SOCKS_SEND: presult = socks_state_send(cf, sx, data, CURLPX_SEND_CONNECT, @@ -633,6 +693,10 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, case CONNECT_SOCKS_READ: presult = socks_state_recv(cf, sx, data, CURLPX_RECV_CONNECT, "initial SOCKS5 response"); +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + if(data->set.socks5auth & CURLAUTH_GSSAPI) + allow_gssapi = TRUE; +#endif if(CURLPX_OK != presult) return presult; else if(sx->outstanding) { @@ -645,17 +709,17 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, } else if(socksreq[1] == 0) { /* DONE! No authentication needed. Send request. */ - sxstate(sx, data, CONNECT_REQ_INIT); + sxstate(sx, cf, data, CONNECT_REQ_INIT); goto CONNECT_REQ_INIT; } else if(socksreq[1] == 2) { /* regular name + password authentication */ - sxstate(sx, data, CONNECT_AUTH_INIT); + sxstate(sx, cf, data, CONNECT_AUTH_INIT); goto CONNECT_AUTH_INIT; } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) else if(allow_gssapi && (socksreq[1] == 1)) { - sxstate(sx, data, CONNECT_GSSAPI_INIT); + sxstate(sx, cf, data, CONNECT_GSSAPI_INIT); result = Curl_SOCKS5_gssapi_negotiate(cf, data); if(result) { failf(data, "Unable to negotiate SOCKS5 GSS-API context."); @@ -688,52 +752,10 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, break; CONNECT_AUTH_INIT: - case CONNECT_AUTH_INIT: { - /* Needs username and password */ - size_t proxy_user_len, proxy_password_len; - if(sx->proxy_user && sx->proxy_password) { - proxy_user_len = strlen(sx->proxy_user); - proxy_password_len = strlen(sx->proxy_password); - } - else { - proxy_user_len = 0; - proxy_password_len = 0; - } - - /* username/password request looks like - * +----+------+----------+------+----------+ - * |VER | ULEN | UNAME | PLEN | PASSWD | - * +----+------+----------+------+----------+ - * | 1 | 1 | 1 to 255 | 1 | 1 to 255 | - * +----+------+----------+------+----------+ - */ - len = 0; - socksreq[len++] = 1; /* username/pw subnegotiation version */ - socksreq[len++] = (unsigned char) proxy_user_len; - if(sx->proxy_user && proxy_user_len) { - /* the length must fit in a single byte */ - if(proxy_user_len > 255) { - failf(data, "Excessive username length for proxy auth"); - return CURLPX_LONG_USER; - } - memcpy(socksreq + len, sx->proxy_user, proxy_user_len); - } - len += proxy_user_len; - socksreq[len++] = (unsigned char) proxy_password_len; - if(sx->proxy_password && proxy_password_len) { - /* the length must fit in a single byte */ - if(proxy_password_len > 255) { - failf(data, "Excessive password length for proxy auth"); - return CURLPX_LONG_PASSWD; - } - memcpy(socksreq + len, sx->proxy_password, proxy_password_len); - } - len += proxy_password_len; - sxstate(sx, data, CONNECT_AUTH_SEND); - DEBUGASSERT(len <= sizeof(sx->buffer)); - sx->outstanding = len; - sx->outp = socksreq; - } + case CONNECT_AUTH_INIT: + presult = socks5_auth_init(cf, sx, data); + if(presult) + return presult; FALLTHROUGH(); case CONNECT_AUTH_SEND: presult = socks_state_send(cf, sx, data, CURLPX_SEND_AUTH, @@ -746,7 +768,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, } sx->outp = socksreq; sx->outstanding = 2; - sxstate(sx, data, CONNECT_AUTH_READ); + sxstate(sx, cf, data, CONNECT_AUTH_READ); FALLTHROUGH(); case CONNECT_AUTH_READ: presult = socks_state_recv(cf, sx, data, CURLPX_RECV_AUTH, @@ -765,7 +787,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, } /* Everything is good so far, user was authenticated! */ - sxstate(sx, data, CONNECT_REQ_INIT); + sxstate(sx, cf, data, CONNECT_REQ_INIT); FALLTHROUGH(); case CONNECT_REQ_INIT: CONNECT_REQ_INIT: @@ -774,12 +796,12 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, cf->conn->ip_version, TRUE, &dns); if(result == CURLE_AGAIN) { - sxstate(sx, data, CONNECT_RESOLVING); + sxstate(sx, cf, data, CONNECT_RESOLVING); return CURLPX_OK; } else if(result) return CURLPX_RESOLVE_HOST; - sxstate(sx, data, CONNECT_RESOLVED); + sxstate(sx, cf, data, CONNECT_RESOLVED); goto CONNECT_RESOLVED; } goto CONNECT_RESOLVE_REMOTE; @@ -831,8 +853,8 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, socksreq[len++] = ((unsigned char *)&saddr_in->sin_addr.s_addr)[i]; } - infof(data, "SOCKS5 connect to %s:%d (locally resolved)", dest, - sx->remote_port); + CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (locally resolved)", + dest, sx->remote_port); } #ifdef USE_IPV6 else if(hp->ai_family == AF_INET6) { @@ -846,8 +868,8 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, ((unsigned char *)&saddr_in6->sin6_addr.s6_addr)[i]; } - infof(data, "SOCKS5 connect to [%s]:%d (locally resolved)", dest, - sx->remote_port); + CURL_TRC_CF(data, cf, "SOCKS5 connect to [%s]:%d (locally resolved)", + dest, sx->remote_port); } #endif else { @@ -874,7 +896,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, #ifdef USE_IPV6 if(conn->bits.ipv6_ip) { char ip6[16]; - if(1 != curlx_inet_pton(AF_INET6, sx->hostname, ip6)) + if(curlx_inet_pton(AF_INET6, sx->hostname, ip6) != 1) return CURLPX_BAD_ADDRESS_TYPE; socksreq[len++] = 4; memcpy(&socksreq[len], ip6, sizeof(ip6)); @@ -882,7 +904,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, } else #endif - if(1 == curlx_inet_pton(AF_INET, sx->hostname, ip4)) { + if(curlx_inet_pton(AF_INET, sx->hostname, ip4) == 1) { socksreq[len++] = 1; memcpy(&socksreq[len], ip4, sizeof(ip4)); len += sizeof(ip4); @@ -893,8 +915,8 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, memcpy(&socksreq[len], sx->hostname, hostname_len); /* w/o NULL */ len += hostname_len; } - infof(data, "SOCKS5 connect to %s:%d (remotely resolved)", - sx->hostname, sx->remote_port); + CURL_TRC_CF(data, cf, "SOCKS5 connect to %s:%d (remotely resolved)", + sx->hostname, sx->remote_port); } FALLTHROUGH(); @@ -914,7 +936,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, sx->outp = socksreq; DEBUGASSERT(len <= sizeof(sx->buffer)); sx->outstanding = len; - sxstate(sx, data, CONNECT_REQ_SENDING); + sxstate(sx, cf, data, CONNECT_REQ_SENDING); FALLTHROUGH(); case CONNECT_REQ_SENDING: presult = socks_state_send(cf, sx, data, CURLPX_SEND_REQUEST, @@ -933,7 +955,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, #endif sx->outstanding = 10; /* minimum packet size is 10 */ sx->outp = socksreq; - sxstate(sx, data, CONNECT_REQ_READ); + sxstate(sx, cf, data, CONNECT_REQ_READ); FALLTHROUGH(); case CONNECT_REQ_READ: presult = socks_state_recv(cf, sx, data, CURLPX_RECV_REQACK, @@ -984,7 +1006,7 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, ATYP: o IP v4 address: X'01', BND.ADDR = 4 byte - o domain name: X'03', BND.ADDR = [ 1 byte length, string ] + o domain name: X'03', BND.ADDR = [ 1 byte length, string ] o IP v6 address: X'04', BND.ADDR = 16 byte */ @@ -1015,10 +1037,10 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, DEBUGASSERT(len <= sizeof(sx->buffer)); sx->outstanding = len - 10; /* get the rest */ sx->outp = &socksreq[10]; - sxstate(sx, data, CONNECT_REQ_READ_MORE); + sxstate(sx, cf, data, CONNECT_REQ_READ_MORE); } else { - sxstate(sx, data, CONNECT_DONE); + sxstate(sx, cf, data, CONNECT_DONE); break; } #if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) @@ -1034,9 +1056,9 @@ static CURLproxycode do_SOCKS5(struct Curl_cfilter *cf, /* remain in reading state */ return CURLPX_OK; } - sxstate(sx, data, CONNECT_DONE); + sxstate(sx, cf, data, CONNECT_DONE); } - infof(data, "SOCKS5 request granted."); + CURL_TRC_CF(data, cf, "SOCKS5 request granted."); return CURLPX_OK; /* Proxy was successful! */ } @@ -1117,7 +1139,7 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, /* for the secondary socket (FTP), use the "connect to host" * but ignore the "connect to port" (use the secondary port) */ - sxstate(sx, data, CONNECT_SOCKS_INIT); + sxstate(sx, cf, data, CONNECT_SOCKS_INIT); sx->hostname = conn->bits.httpproxy ? conn->http_proxy.host.name : @@ -1137,7 +1159,21 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, result = connect_SOCKS(cf, sx, data); if(!result && sx->state == CONNECT_DONE) { cf->connected = TRUE; - Curl_verboseconnect(data, conn, cf->sockindex); +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_is_verbose(data)) { + struct ip_quadruple ipquad; + bool is_ipv6; + result = Curl_conn_cf_get_ip_info(cf->next, data, &is_ipv6, &ipquad); + if(result) + return result; + infof(data, "Opened %sSOCKS connection from %s port %u to %s port %u " + "(via %s port %u)", + (sockindex == SECONDARYSOCKET) ? "2nd " : "", + ipquad.local_ip, ipquad.local_port, + sx->hostname, sx->remote_port, + ipquad.remote_ip, ipquad.remote_port); + } +#endif socks_proxy_cf_free(cf); } @@ -1145,11 +1181,12 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf, return result; } -static void socks_cf_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode socks_cf_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct socks_state *sx = cf->ctx; + CURLcode result = CURLE_OK; if(!cf->connected && sx) { /* If we are not connected, the filter below is and has nothing @@ -1161,13 +1198,14 @@ static void socks_cf_adjust_pollset(struct Curl_cfilter *cf, case CONNECT_AUTH_READ: case CONNECT_REQ_READ: case CONNECT_REQ_READ_MORE: - Curl_pollset_set_in_only(data, ps, sock); + result = Curl_pollset_set_in_only(data, ps, sock); break; default: - Curl_pollset_set_out_only(data, ps, sock); + result = Curl_pollset_set_out_only(data, ps, sock); break; } } + return result; } static void socks_proxy_cf_close(struct Curl_cfilter *cf, @@ -1193,15 +1231,22 @@ static CURLcode socks_cf_query(struct Curl_cfilter *cf, { struct socks_state *sx = cf->ctx; - if(sx) { - switch(query) { - case CF_QUERY_HOST_PORT: + switch(query) { + case CF_QUERY_HOST_PORT: + if(sx) { *pres1 = sx->remote_port; *((const char **)pres2) = sx->hostname; return CURLE_OK; - default: - break; } + break; + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = NULL; + return CURLE_OK; + } + default: + break; } return cf->next ? cf->next->cft->query(cf->next, data, query, pres1, pres2) : @@ -1209,7 +1254,7 @@ static CURLcode socks_cf_query(struct Curl_cfilter *cf, } struct Curl_cftype Curl_cft_socks_proxy = { - "SOCKS-PROXYY", + "SOCKS", CF_TYPE_IP_CONNECT|CF_TYPE_PROXY, 0, socks_proxy_cf_destroy, diff --git a/deps/curl/lib/socks_gssapi.c b/deps/curl/lib/socks_gssapi.c index f23a1ae6edf..0a7ddd5ff1d 100644 --- a/deps/curl/lib/socks_gssapi.c +++ b/deps/curl/lib/socks_gssapi.c @@ -212,7 +212,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, &nwritten); - if(code || (4 != nwritten)) { + if(code || (nwritten != 4)) { failf(data, "Failed to send GSS-API authentication request."); gss_release_name(&gss_status, &server); gss_release_buffer(&gss_status, &gss_recv_token); @@ -420,7 +420,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, &nwritten); - if(code || (4 != nwritten)) { + if(code || (nwritten != 4)) { failf(data, "Failed to send GSS-API encryption request."); gss_release_buffer(&gss_status, &gss_w_token); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -431,7 +431,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, memcpy(socksreq, &gss_enc, 1); code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE, &nwritten); - if(code || (1 != nwritten)) { + if(code || (nwritten != 1)) { failf(data, "Failed to send GSS-API encryption type."); Curl_gss_delete_sec_context(&gss_status, &gss_context, NULL); return CURLE_COULDNT_CONNECT; diff --git a/deps/curl/lib/socks_sspi.c b/deps/curl/lib/socks_sspi.c index 82147562b76..49210585b0f 100644 --- a/deps/curl/lib/socks_sspi.c +++ b/deps/curl/lib/socks_sspi.c @@ -90,7 +90,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, unsigned char socksreq[4]; /* room for GSS-API exchange header only */ const char *service = data->set.str[STRING_PROXY_SERVICE_NAME] ? data->set.str[STRING_PROXY_SERVICE_NAME] : "rcmd"; - const size_t service_length = strlen(service); /* GSS-API request looks like * +----+------+-----+----------------+ @@ -101,20 +100,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, */ /* prepare service name */ - if(strchr(service, '/')) { + if(strchr(service, '/')) service_name = strdup(service); - if(!service_name) - return CURLE_OUT_OF_MEMORY; - } - else { - service_name = malloc(service_length + - strlen(conn->socks_proxy.host.name) + 2); - if(!service_name) - return CURLE_OUT_OF_MEMORY; - msnprintf(service_name, service_length + - strlen(conn->socks_proxy.host.name) + 2, "%s/%s", - service, conn->socks_proxy.host.name); - } + else + service_name = aprintf("%s/%s", service, conn->socks_proxy.host.name); + if(!service_name) + return CURLE_OUT_OF_MEMORY; input_desc.cBuffers = 1; input_desc.pBuffers = &sspi_recv_token; @@ -132,6 +123,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, sspi_send_token.cbBuffer = 0; sspi_send_token.pvBuffer = NULL; + sspi_w_token[0].pvBuffer = + sspi_w_token[1].pvBuffer = + sspi_w_token[2].pvBuffer = NULL; + wrap_desc.cBuffers = 3; wrap_desc.pBuffers = sspi_w_token; wrap_desc.ulVersion = SECBUFFER_VERSION; @@ -139,21 +134,19 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, cred_handle.dwLower = 0; cred_handle.dwUpper = 0; - status = Curl_pSecFn->AcquireCredentialsHandle(NULL, + names.sUserName = NULL; + + status = + Curl_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)CURL_UNCONST(TEXT("Kerberos")), - SECPKG_CRED_OUTBOUND, - NULL, - NULL, - NULL, - NULL, - &cred_handle, - &expiry); + SECPKG_CRED_OUTBOUND, + NULL, NULL, NULL, NULL, + &cred_handle, &expiry); if(check_sspi_err(data, status, "AcquireCredentialsHandle")) { failf(data, "Failed to acquire credentials."); - free(service_name); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } (void)curlx_nonblock(sock, FALSE); @@ -164,24 +157,24 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, TCHAR *sname; sname = curlx_convert_UTF8_to_tchar(service_name); - if(!sname) - return CURLE_OUT_OF_MEMORY; - - status = Curl_pSecFn->InitializeSecurityContext(&cred_handle, - context_handle, - sname, - ISC_REQ_MUTUAL_AUTH | - ISC_REQ_ALLOCATE_MEMORY | - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT, - 0, - SECURITY_NATIVE_DREP, - &input_desc, - 0, - &sspi_context, - &output_desc, - &sspi_ret_flags, - &expiry); + if(!sname) { + result = CURLE_OUT_OF_MEMORY; + goto error; + } + + status = + Curl_pSecFn->InitializeSecurityContext(&cred_handle, context_handle, + sname, + ISC_REQ_MUTUAL_AUTH | + ISC_REQ_ALLOCATE_MEMORY | + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT, + 0, SECURITY_NATIVE_DREP, + &input_desc, 0, + &sspi_context, + &output_desc, + &sspi_ret_flags, + &expiry); curlx_unicodefree(sname); @@ -192,13 +185,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } if(check_sspi_err(data, status, "InitializeSecurityContext")) { - free(service_name); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - if(sspi_recv_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); failf(data, "Failed to initialise security context."); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } if(sspi_send_token.cbBuffer) { @@ -209,16 +198,10 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, &written); - if(code || (4 != written)) { + if(code || (written != 4)) { failf(data, "Failed to send SSPI authentication request."); - free(service_name); - if(sspi_send_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - if(sspi_recv_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } code = Curl_conn_cf_send(cf->next, data, @@ -226,16 +209,9 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, sspi_send_token.cbBuffer, FALSE, &written); if(code || (sspi_send_token.cbBuffer != written)) { failf(data, "Failed to send SSPI authentication token."); - free(service_name); - if(sspi_send_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - if(sspi_recv_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } - } if(sspi_send_token.pvBuffer) { @@ -266,29 +242,23 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI authentication response."); - free(service_name); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } /* ignore the first (VER) byte */ if(socksreq[1] == 255) { /* status / message type */ failf(data, "User was rejected by the SOCKS5 server (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - free(service_name); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } if(socksreq[1] != 1) { /* status / message type */ failf(data, "Invalid SSPI authentication response type (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - free(service_name); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } memcpy(&us_length, socksreq + 2, sizeof(short)); @@ -298,39 +268,32 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, sspi_recv_token.pvBuffer = malloc(us_length); if(!sspi_recv_token.pvBuffer) { - free(service_name); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto error; } result = Curl_blockread_all(cf, data, (char *)sspi_recv_token.pvBuffer, sspi_recv_token.cbBuffer, &actualread); if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI authentication token."); - free(service_name); - if(sspi_recv_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); - Curl_pSecFn->FreeCredentialsHandle(&cred_handle); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } context_handle = &sspi_context; } - free(service_name); + Curl_safefree(service_name); /* Everything is good so far, user was authenticated! */ status = Curl_pSecFn->QueryCredentialsAttributes(&cred_handle, - SECPKG_CRED_ATTR_NAMES, - &names); + SECPKG_CRED_ATTR_NAMES, + &names); Curl_pSecFn->FreeCredentialsHandle(&cred_handle); if(check_sspi_err(data, status, "QueryCredentialAttributes")) { - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - Curl_pSecFn->FreeContextBuffer(names.sUserName); failf(data, "Failed to determine username."); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } else { #ifndef CURL_DISABLE_VERBOSE_STRINGS @@ -396,12 +359,12 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } else { status = Curl_pSecFn->QueryContextAttributes(&sspi_context, - SECPKG_ATTR_SIZES, - &sspi_sizes); + SECPKG_ATTR_SIZES, + &sspi_sizes); if(check_sspi_err(data, status, "QueryContextAttributes")) { - Curl_pSecFn->DeleteSecurityContext(&sspi_context); failf(data, "Failed to query security context attributes."); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer; @@ -409,16 +372,15 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer); if(!sspi_w_token[0].pvBuffer) { - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto error; } sspi_w_token[1].cbBuffer = 1; sspi_w_token[1].pvBuffer = malloc(1); if(!sspi_w_token[1].pvBuffer) { - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto error; } memcpy(sspi_w_token[1].pvBuffer, &gss_enc, 1); @@ -426,42 +388,33 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize; sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize); if(!sspi_w_token[2].pvBuffer) { - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto error; } status = Curl_pSecFn->EncryptMessage(&sspi_context, - KERB_WRAP_NO_ENCRYPT, - &wrap_desc, - 0); + KERB_WRAP_NO_ENCRYPT, + &wrap_desc, 0); if(check_sspi_err(data, status, "EncryptMessage")) { - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); failf(data, "Failed to query security context attributes."); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } - sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer - + sspi_w_token[1].cbBuffer - + sspi_w_token[2].cbBuffer; + sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer + + sspi_w_token[1].cbBuffer + + sspi_w_token[2].cbBuffer; sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer); if(!sspi_send_token.pvBuffer) { - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto error; } memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); - memcpy((PUCHAR) sspi_send_token.pvBuffer - + sspi_w_token[0].cbBuffer - + sspi_w_token[1].cbBuffer, + memcpy((PUCHAR) sspi_send_token.pvBuffer + + sspi_w_token[0].cbBuffer + + sspi_w_token[1].cbBuffer, sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer); Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); @@ -480,22 +433,20 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 4, FALSE, &written); - if(code || (4 != written)) { + if(code || (written != 4)) { failf(data, "Failed to send SSPI encryption request."); - if(sspi_send_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } if(data->set.socks5_gssapi_nec) { memcpy(socksreq, &gss_enc, 1); code = Curl_conn_cf_send(cf->next, data, (char *)socksreq, 1, FALSE, &written); - if(code || (1 != written)) { + if(code || (written != 1)) { failf(data, "Failed to send SSPI encryption type."); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } } else { @@ -504,10 +455,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, sspi_send_token.cbBuffer, FALSE, &written); if(code || (sspi_send_token.cbBuffer != (size_t)written)) { failf(data, "Failed to send SSPI encryption type."); - if(sspi_send_token.pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } if(sspi_send_token.pvBuffer) Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); @@ -516,23 +465,23 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, result = Curl_blockread_all(cf, data, (char *)socksreq, 4, &actualread); if(result || (actualread != 4)) { failf(data, "Failed to receive SSPI encryption response."); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } /* ignore the first (VER) byte */ if(socksreq[1] == 255) { /* status / message type */ failf(data, "User was rejected by the SOCKS5 server (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } if(socksreq[1] != 2) { /* status / message type */ failf(data, "Invalid SSPI encryption response type (%u %u).", (unsigned int)socksreq[0], (unsigned int)socksreq[1]); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } memcpy(&us_length, socksreq + 2, sizeof(short)); @@ -541,8 +490,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, sspi_w_token[0].cbBuffer = us_length; sspi_w_token[0].pvBuffer = malloc(us_length); if(!sspi_w_token[0].pvBuffer) { - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_OUT_OF_MEMORY; + result = CURLE_OUT_OF_MEMORY; + goto error; } result = Curl_blockread_all(cf, data, (char *)sspi_w_token[0].pvBuffer, @@ -550,9 +499,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(result || (actualread != us_length)) { failf(data, "Failed to receive SSPI encryption type."); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } @@ -563,30 +511,20 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, sspi_w_token[1].cbBuffer = 0; sspi_w_token[1].pvBuffer = NULL; - status = Curl_pSecFn->DecryptMessage(&sspi_context, - &wrap_desc, - 0, - &qop); + status = Curl_pSecFn->DecryptMessage(&sspi_context, &wrap_desc, + 0, &qop); if(check_sspi_err(data, status, "DecryptMessage")) { - if(sspi_w_token[0].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - if(sspi_w_token[1].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); failf(data, "Failed to query security context attributes."); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } if(sspi_w_token[1].cbBuffer != 1) { failf(data, "Invalid SSPI encryption response length (%lu).", (unsigned long)sspi_w_token[1].cbBuffer); - if(sspi_w_token[0].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - if(sspi_w_token[1].pvBuffer) - Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } memcpy(socksreq, sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer); @@ -597,9 +535,8 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, if(sspi_w_token[0].cbBuffer != 1) { failf(data, "Invalid SSPI encryption response length (%lu).", (unsigned long)sspi_w_token[0].cbBuffer); - Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); - Curl_pSecFn->DeleteSecurityContext(&sspi_context); - return CURLE_COULDNT_CONNECT; + result = CURLE_COULDNT_CONNECT; + goto error; } memcpy(socksreq, sspi_w_token[0].pvBuffer, sspi_w_token[0].cbBuffer); Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); @@ -621,5 +558,22 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(struct Curl_cfilter *cf, } */ return CURLE_OK; +error: + free(service_name); + Curl_pSecFn->FreeCredentialsHandle(&cred_handle); + Curl_pSecFn->DeleteSecurityContext(&sspi_context); + if(sspi_recv_token.pvBuffer) + Curl_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer); + if(sspi_send_token.pvBuffer) + Curl_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); + if(names.sUserName) + Curl_pSecFn->FreeContextBuffer(names.sUserName); + if(sspi_w_token[0].pvBuffer) + Curl_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); + if(sspi_w_token[1].pvBuffer) + Curl_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer); + if(sspi_w_token[2].pvBuffer) + Curl_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer); + return result; } #endif diff --git a/deps/curl/lib/splay.c b/deps/curl/lib/splay.c index 7a0e419ce68..3ca8678b2b2 100644 --- a/deps/curl/lib/splay.c +++ b/deps/curl/lib/splay.c @@ -94,6 +94,10 @@ struct Curl_tree *Curl_splay(struct curltime i, return t; } +static const struct curltime SPLAY_SUBNODE = { + ~0, -1 +}; + /* Insert key i into the tree t. Return a pointer to the resulting tree or * NULL if something went wrong. * @@ -103,10 +107,6 @@ struct Curl_tree *Curl_splayinsert(struct curltime i, struct Curl_tree *t, struct Curl_tree *node) { - static const struct curltime KEY_NOTUSED = { - ~0, -1 - }; /* will *NEVER* appear */ - DEBUGASSERT(node); if(t) { @@ -117,8 +117,7 @@ struct Curl_tree *Curl_splayinsert(struct curltime i, doubly-linked circular list of nodes. We add the new 'node' struct to the end of this list. */ - node->key = KEY_NOTUSED; /* we set the key in the sub node to NOTUSED - to quickly identify this node as a subnode */ + node->key = SPLAY_SUBNODE; /* identify this node as a subnode */ node->samen = t; node->samep = t->samep; t->samep->samen = node; @@ -214,9 +213,6 @@ int Curl_splayremove(struct Curl_tree *t, struct Curl_tree *removenode, struct Curl_tree **newroot) { - static const struct curltime KEY_NOTUSED = { - ~0, -1 - }; /* will *NEVER* appear */ struct Curl_tree *x; if(!t) @@ -224,11 +220,12 @@ int Curl_splayremove(struct Curl_tree *t, DEBUGASSERT(removenode); - if(compare(KEY_NOTUSED, removenode->key) == 0) { - /* Key set to NOTUSED means it is a subnode within a 'same' linked list - and thus we can unlink it easily. */ + if(compare(SPLAY_SUBNODE, removenode->key) == 0) { + /* It is a subnode within a 'same' linked list and thus we can unlink it + easily. */ + DEBUGASSERT(removenode->samen != removenode); if(removenode->samen == removenode) - /* A non-subnode should never be set to KEY_NOTUSED */ + /* A non-subnode should never be set to SPLAY_SUBNODE */ return 3; removenode->samep->samen = removenode->samen; @@ -249,8 +246,9 @@ int Curl_splayremove(struct Curl_tree *t, is not actually in the tree. We cannot just compare the keys here as a double remove in quick - succession of a node with key != KEY_NOTUSED && same != NULL + succession of a node with key != SPLAY_SUBNODE && same != NULL could return the same key but a different node. */ + DEBUGASSERT(t == removenode); if(t != removenode) return 2; diff --git a/deps/curl/lib/strdup.c b/deps/curl/lib/strdup.c index 69c41a5e252..66fd7c60eb5 100644 --- a/deps/curl/lib/strdup.c +++ b/deps/curl/lib/strdup.c @@ -71,7 +71,7 @@ wchar_t *Curl_wcsdup(const wchar_t *src) { size_t length = wcslen(src); - if(length > (SIZE_T_MAX / sizeof(wchar_t)) - 1) + if(length > (SIZE_MAX / sizeof(wchar_t)) - 1) return (wchar_t *)NULL; /* integer overflow */ return (wchar_t *)Curl_memdup(src, (length + 1) * sizeof(wchar_t)); diff --git a/deps/curl/lib/strequal.c b/deps/curl/lib/strequal.c index fb6be51dd5d..17dd34b7f3a 100644 --- a/deps/curl/lib/strequal.c +++ b/deps/curl/lib/strequal.c @@ -59,7 +59,7 @@ static int ncasecompare(const char *first, const char *second, size_t max) first++; second++; } - if(0 == max) + if(max == 0) return 1; /* they are equal this far */ return Curl_raw_toupper(*first) == Curl_raw_toupper(*second); diff --git a/deps/curl/lib/strerror.c b/deps/curl/lib/strerror.c index 90694882c3c..f0f36ed1b71 100644 --- a/deps/curl/lib/strerror.c +++ b/deps/curl/lib/strerror.c @@ -809,7 +809,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen) * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated * message string, or EINVAL if 'errnum' is not a valid error number. */ - if(0 != strerror_r(err, buf, buflen)) { + if(strerror_r(err, buf, buflen)) { if('\0' == buf[0]) curl_msnprintf(buf, buflen, "Unknown error %d", err); } diff --git a/deps/curl/lib/telnet.c b/deps/curl/lib/telnet.c index bd599dece26..cc827c1b3e8 100644 --- a/deps/curl/lib/telnet.c +++ b/deps/curl/lib/telnet.c @@ -188,10 +188,10 @@ const struct Curl_handler Curl_handler_telnet = { ZERO_NULL, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - ZERO_NULL, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + ZERO_NULL, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -1287,8 +1287,8 @@ static CURLcode send_telnet_data(struct Curl_easy *data, static CURLcode telnet_done(struct Curl_easy *data, CURLcode status, bool premature) { - (void)status; /* unused */ - (void)premature; /* not used */ + (void)status; + (void)premature; Curl_meta_remove(data, CURL_META_TELNET_EASY); return CURLE_OK; } diff --git a/deps/curl/lib/tftp.c b/deps/curl/lib/tftp.c index 5ea986dbb4b..4c2fadc2caf 100644 --- a/deps/curl/lib/tftp.c +++ b/deps/curl/lib/tftp.c @@ -160,8 +160,8 @@ static CURLcode tftp_setup_connection(struct Curl_easy *data, struct connectdata *conn); static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done); static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done); -static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *socks); +static CURLcode tftp_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode tftp_translate_code(tftp_error_t error); @@ -178,10 +178,10 @@ const struct Curl_handler Curl_handler_tftp = { tftp_connect, /* connect_it */ tftp_multi_statemach, /* connecting */ tftp_doing, /* doing */ - tftp_getsock, /* proto_getsock */ - tftp_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + tftp_pollset, /* proto_pollset */ + tftp_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -1061,8 +1061,8 @@ static CURLcode tftp_done(struct Curl_easy *data, CURLcode status, struct connectdata *conn = data->conn; struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN); - (void)status; /* unused */ - (void)premature; /* not used */ + (void)status; + (void)premature; if(Curl_pgrsDone(data)) return CURLE_ABORTED_BY_CALLBACK; @@ -1074,19 +1074,10 @@ static CURLcode tftp_done(struct Curl_easy *data, CURLcode status, return result; } -/********************************************************** - * - * tftp_getsock - * - * The getsock callback - * - **********************************************************/ -static int tftp_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks) +static CURLcode tftp_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - (void)data; - socks[0] = conn->sock[FIRSTSOCKET]; - return GETSOCK_READSOCK(0); + return Curl_pollset_add_in(data, ps, data->conn->sock[FIRSTSOCKET]); } /********************************************************** diff --git a/deps/curl/lib/transfer.c b/deps/curl/lib/transfer.c index 15a61f69978..1297a3e82d2 100644 --- a/deps/curl/lib/transfer.c +++ b/deps/curl/lib/transfer.c @@ -162,38 +162,23 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc) static CURLcode xfer_recv_shutdown(struct Curl_easy *data, bool *done) { - int sockindex; - if(!data || !data->conn) return CURLE_FAILED_INIT; - if(data->conn->sockfd == CURL_SOCKET_BAD) - return CURLE_FAILED_INIT; - sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]); - return Curl_conn_shutdown(data, sockindex, done); + return Curl_conn_shutdown(data, data->conn->recv_idx, done); } static bool xfer_recv_shutdown_started(struct Curl_easy *data) { - int sockindex; - if(!data || !data->conn) return FALSE; - if(data->conn->sockfd == CURL_SOCKET_BAD) - return FALSE; - sockindex = (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET]); - return Curl_shutdown_started(data, sockindex); + return Curl_shutdown_started(data, data->conn->recv_idx); } CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done) { - int sockindex; - if(!data || !data->conn) return CURLE_FAILED_INIT; - if(data->conn->writesockfd == CURL_SOCKET_BAD) - return CURLE_FAILED_INIT; - sockindex = (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]); - return Curl_conn_shutdown(data, sockindex, done); + return Curl_conn_shutdown(data, data->conn->send_idx, done); } /** @@ -295,9 +280,10 @@ static CURLcode sendrecv_dl(struct Curl_easy *data, if(bytestoread && data->set.max_recv_speed > 0) { /* In case of speed limit on receiving: if this loop already got - * data, break out. If not, limit the amount of bytes to receive. - * The overall, timed, speed limiting is done in multi.c */ - if(total_received) + * a quarter of the quota, break out. We want to stutter a bit + * to keep in the limit, but too small receives will just cost + * cpu unnecessarily. */ + if(total_received >= (data->set.max_recv_speed / 4)) break; if(data->set.max_recv_speed < (curl_off_t)bytestoread) bytestoread = (size_t)data->set.max_recv_speed; @@ -481,7 +467,7 @@ CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp) } /* If there is nothing more to send/recv, the request is done */ - if(0 == (k->keepon&(KEEP_RECVBITS|KEEP_SENDBITS))) + if((k->keepon & (KEEP_RECVBITS|KEEP_SENDBITS)) == 0) data->req.done = TRUE; out: @@ -732,101 +718,88 @@ CURLcode Curl_retry_request(struct Curl_easy *data, char **url) return CURLE_OK; } -/* - * xfer_setup() is called to setup basic properties for the transfer. - */ static void xfer_setup( struct Curl_easy *data, /* transfer */ - int sockindex, /* socket index to read from or -1 */ - curl_off_t size, /* -1 if unknown at this point */ - bool getheader, /* TRUE if header parsing is wanted */ - int writesockindex, /* socket index to write to, it may be the same we - read from. -1 disables */ - bool shutdown, /* shutdown connection at transfer end. Only - * supported when sending OR receiving. */ - bool shutdown_err_ignore /* errors during shutdown do not fail the - * transfer */ + int send_idx, /* sockindex to send on or -1 */ + int recv_idx, /* sockindex to receive on or -1 */ + curl_off_t recv_size /* how much to receive, -1 if unknown */ ) { struct SingleRequest *k = &data->req; struct connectdata *conn = data->conn; - bool want_send = Curl_req_want_send(data); DEBUGASSERT(conn != NULL); - DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); - DEBUGASSERT((writesockindex <= 1) && (writesockindex >= -1)); - DEBUGASSERT(!shutdown || (sockindex == -1) || (writesockindex == -1)); - - if(Curl_conn_is_multiplex(conn, FIRSTSOCKET) || want_send) { - /* when multiplexing, the read/write sockets need to be the same! */ - conn->sockfd = sockindex == -1 ? - ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) : - conn->sock[sockindex]; - conn->writesockfd = conn->sockfd; - if(want_send) - /* special and HTTP-specific */ - writesockindex = FIRSTSOCKET; - } - else { - conn->sockfd = sockindex == -1 ? - CURL_SOCKET_BAD : conn->sock[sockindex]; - conn->writesockfd = writesockindex == -1 ? - CURL_SOCKET_BAD : conn->sock[writesockindex]; - } - - k->getheader = getheader; - k->size = size; - k->shutdown = shutdown; - k->shutdown_err_ignore = shutdown_err_ignore; + /* indexes are in range */ + DEBUGASSERT((send_idx <= 1) && (send_idx >= -1)); + DEBUGASSERT((recv_idx <= 1) && (recv_idx >= -1)); + /* if request wants to send, switching off the send direction is wrong */ + DEBUGASSERT((send_idx >= 0) || !Curl_req_want_send(data)); + + conn->send_idx = send_idx; + conn->recv_idx = recv_idx; + + /* without receiving, there should be not recv_size */ + DEBUGASSERT((conn->recv_idx >= 0) || (recv_size == -1)); + k->size = recv_size; + k->header = !!conn->handler->write_resp_hd; + /* by default, we do not shutdown at the end of the transfer */ + k->shutdown = FALSE; + k->shutdown_err_ignore = FALSE; /* The code sequence below is placed in this function just because all necessary input is not always known in do_complete() as this function may be called after that */ + if(!k->header && (recv_size > 0)) + Curl_pgrsSetDownloadSize(data, recv_size); - if(!k->getheader) { - k->header = FALSE; - if(size > 0) - Curl_pgrsSetDownloadSize(data, size); - } /* we want header and/or body, if neither then do not do this! */ - if(k->getheader || !data->req.no_body) { + if(conn->handler->write_resp_hd || !data->req.no_body) { - if(sockindex != -1) + if(conn->recv_idx != -1) k->keepon |= KEEP_RECV; - if(writesockindex != -1) + if(conn->send_idx != -1) k->keepon |= KEEP_SEND; - } /* if(k->getheader || !data->req.no_body) */ + } + CURL_TRC_M(data, "xfer_setup: recv_idx=%d, send_idx=%d", + conn->recv_idx, conn->send_idx); } void Curl_xfer_setup_nop(struct Curl_easy *data) { - xfer_setup(data, -1, -1, FALSE, -1, FALSE, FALSE); + xfer_setup(data, -1, -1, -1); +} + +void Curl_xfer_setup_sendrecv(struct Curl_easy *data, + int sockindex, + curl_off_t recv_size) +{ + xfer_setup(data, sockindex, sockindex, recv_size); +} + +void Curl_xfer_setup_send(struct Curl_easy *data, + int sockindex) +{ + xfer_setup(data, sockindex, -1, -1); } -void Curl_xfer_setup1(struct Curl_easy *data, - int send_recv, - curl_off_t recv_size, - bool getheader) +void Curl_xfer_setup_recv(struct Curl_easy *data, + int sockindex, + curl_off_t recv_size) { - int recv_index = (send_recv & CURL_XFER_RECV) ? FIRSTSOCKET : -1; - int send_index = (send_recv & CURL_XFER_SEND) ? FIRSTSOCKET : -1; - DEBUGASSERT((recv_index >= 0) || (recv_size == -1)); - xfer_setup(data, recv_index, recv_size, getheader, send_index, FALSE, FALSE); + xfer_setup(data, -1, sockindex, recv_size); } -void Curl_xfer_setup2(struct Curl_easy *data, - int send_recv, - curl_off_t recv_size, - bool shutdown, - bool shutdown_err_ignore) +void Curl_xfer_set_shutdown(struct Curl_easy *data, + bool shutdown, + bool ignore_errors) { - int recv_index = (send_recv & CURL_XFER_RECV) ? SECONDARYSOCKET : -1; - int send_index = (send_recv & CURL_XFER_SEND) ? SECONDARYSOCKET : -1; - DEBUGASSERT((recv_index >= 0) || (recv_size == -1)); - xfer_setup(data, recv_index, recv_size, FALSE, send_index, - shutdown, shutdown_err_ignore); + /* Shutdown should only be set when the transfer only sends or receives. */ + DEBUGASSERT(!shutdown || + (data->conn->send_idx < 0) || (data->conn->recv_idx < 0)); + data->req.shutdown = shutdown; + data->req.shutdown_err_ignore = ignore_errors; } CURLcode Curl_xfer_write_resp(struct Curl_easy *data, @@ -886,18 +859,12 @@ CURLcode Curl_xfer_write_done(struct Curl_easy *data, bool premature) bool Curl_xfer_needs_flush(struct Curl_easy *data) { - int sockindex; - sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) && - (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET])); - return Curl_conn_needs_flush(data, sockindex); + return Curl_conn_needs_flush(data, data->conn->send_idx); } CURLcode Curl_xfer_flush(struct Curl_easy *data) { - int sockindex; - sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) && - (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET])); - return Curl_conn_flush(data, sockindex); + return Curl_conn_flush(data, data->conn->send_idx); } CURLcode Curl_xfer_send(struct Curl_easy *data, @@ -905,14 +872,12 @@ CURLcode Curl_xfer_send(struct Curl_easy *data, size_t *pnwritten) { CURLcode result; - int sockindex; DEBUGASSERT(data); DEBUGASSERT(data->conn); - sockindex = ((data->conn->writesockfd != CURL_SOCKET_BAD) && - (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET])); - result = Curl_conn_send(data, sockindex, buf, blen, eos, pnwritten); + result = Curl_conn_send(data, data->conn->send_idx, + buf, blen, eos, pnwritten); if(result == CURLE_AGAIN) { result = CURLE_OK; *pnwritten = 0; @@ -929,17 +894,13 @@ CURLcode Curl_xfer_recv(struct Curl_easy *data, char *buf, size_t blen, size_t *pnrcvd) { - int sockindex; - DEBUGASSERT(data); DEBUGASSERT(data->conn); DEBUGASSERT(data->set.buffer_size > 0); - sockindex = ((data->conn->sockfd != CURL_SOCKET_BAD) && - (data->conn->sockfd == data->conn->sock[SECONDARYSOCKET])); if((size_t)data->set.buffer_size < blen) blen = (size_t)data->set.buffer_size; - return Curl_conn_recv(data, sockindex, buf, blen, pnrcvd); + return Curl_conn_recv(data, data->conn->recv_idx, buf, blen, pnrcvd); } CURLcode Curl_xfer_send_close(struct Curl_easy *data) @@ -998,3 +959,15 @@ CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable) Curl_conn_ev_data_pause(data, enable); return result; } + +bool Curl_xfer_is_too_fast(struct Curl_easy *data) +{ + struct Curl_llist_node *e = Curl_llist_head(&data->state.timeoutlist); + while(e) { + struct time_node *n = Curl_node_elem(e); + e = Curl_node_next(e); + if(n->eid == EXPIRE_TOOFAST) + return TRUE; + } + return FALSE; +} diff --git a/deps/curl/lib/transfer.h b/deps/curl/lib/transfer.h index 92278226be2..6145efb4a5f 100644 --- a/deps/curl/lib/transfer.h +++ b/deps/curl/lib/transfer.h @@ -34,8 +34,6 @@ void Curl_init_CONNECT(struct Curl_easy *data); CURLcode Curl_pretransfer(struct Curl_easy *data); CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp); -int Curl_single_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); CURLcode Curl_retry_request(struct Curl_easy *data, char **url); bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc); @@ -66,38 +64,33 @@ bool Curl_xfer_write_is_paused(struct Curl_easy *data); CURLcode Curl_xfer_write_resp_hd(struct Curl_easy *data, const char *hd0, size_t hdlen, bool is_eos); -#define CURL_XFER_NOP (0) -#define CURL_XFER_RECV (1<<(0)) -#define CURL_XFER_SEND (1<<(1)) -#define CURL_XFER_SENDRECV (CURL_XFER_RECV|CURL_XFER_SEND) - -/** - * The transfer is neither receiving nor sending now. - */ +/* The transfer is neither receiving nor sending. */ void Curl_xfer_setup_nop(struct Curl_easy *data); -/** - * The transfer will use socket 1 to send/recv. `recv_size` is - * the amount to receive or -1 if unknown. `getheader` indicates - * response header processing is expected. - */ -void Curl_xfer_setup1(struct Curl_easy *data, - int send_recv, - curl_off_t recv_size, - bool getheader); +/* The transfer sends data on the given socket index */ +void Curl_xfer_setup_send(struct Curl_easy *data, + int sockindex); + +/* The transfer receives data on the given socket index, the + * amount to receive (or -1 if unknown). */ +void Curl_xfer_setup_recv(struct Curl_easy *data, + int sockindex, + curl_off_t recv_size); + +/* *After* Curl_xfer_setup_xxx(), tell the transfer to shutdown the + * connection at the end. Let the transfer either fail or ignore any + * errors during shutdown. */ +void Curl_xfer_set_shutdown(struct Curl_easy *data, + bool shutdown, + bool ignore_errors); /** - * The transfer will use socket 2 to send/recv. `recv_size` is - * the amount to receive or -1 if unknown. With `shutdown` being - * set, the transfer is only allowed to either send OR receive - * and the socket 2 connection will be shutdown at the end of - * the transfer. An unclean shutdown will fail the transfer - * unless `shutdown_err_ignore` is TRUE. + * The transfer will use socket 1 to send/recv. `recv_size` is + * the amount to receive or -1 if unknown. */ -void Curl_xfer_setup2(struct Curl_easy *data, - int send_recv, - curl_off_t recv_size, - bool shutdown, bool shutdown_err_ignore); +void Curl_xfer_setup_sendrecv(struct Curl_easy *data, + int sockindex, + curl_off_t recv_size); /** * Multi has set transfer to DONE. Last chance to trigger @@ -150,5 +143,7 @@ bool Curl_xfer_recv_is_paused(struct Curl_easy *data); CURLcode Curl_xfer_pause_send(struct Curl_easy *data, bool enable); CURLcode Curl_xfer_pause_recv(struct Curl_easy *data, bool enable); +/* Query if transfer has expire timeout TOOFAST set. */ +bool Curl_xfer_is_too_fast(struct Curl_easy *data); #endif /* HEADER_CURL_TRANSFER_H */ diff --git a/deps/curl/lib/uint-bset.c b/deps/curl/lib/uint-bset.c index e612c390a6b..1c60f22adff 100644 --- a/deps/curl/lib/uint-bset.c +++ b/deps/curl/lib/uint-bset.c @@ -79,8 +79,9 @@ UNITTEST unsigned int Curl_uint_bset_capacity(struct uint_bset *bset) { return bset->nslots * 64; } +#endif -UNITTEST unsigned int Curl_uint_bset_count(struct uint_bset *bset) +unsigned int Curl_uint_bset_count(struct uint_bset *bset) { unsigned int i; unsigned int n = 0; @@ -90,7 +91,6 @@ UNITTEST unsigned int Curl_uint_bset_count(struct uint_bset *bset) } return n; } -#endif bool Curl_uint_bset_empty(struct uint_bset *bset) { diff --git a/deps/curl/lib/url.c b/deps/curl/lib/url.c index e4f250f54ae..b52267cb673 100644 --- a/deps/curl/lib/url.c +++ b/deps/curl/lib/url.c @@ -60,6 +60,9 @@ #endif #if defined(HAVE_IF_NAMETOINDEX) && defined(_WIN32) +#if defined(__MINGW32__) && (__MINGW64_VERSION_MAJOR <= 5) +#include /* workaround for old mingw-w64 missing to include it */ +#endif #include #endif @@ -317,7 +320,6 @@ CURLcode Curl_close(struct Curl_easy **datap) Curl_safefree(data->state.aptr.uagent); Curl_safefree(data->state.aptr.userpwd); Curl_safefree(data->state.aptr.accept_encoding); - Curl_safefree(data->state.aptr.te); Curl_safefree(data->state.aptr.rangeline); Curl_safefree(data->state.aptr.ref); Curl_safefree(data->state.aptr.host); @@ -385,7 +387,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) set->ftp_filemethod = FTPFILE_MULTICWD; set->ftp_skip_ip = TRUE; /* skip PASV IP by default */ #endif - set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */ + set->dns_cache_timeout_ms = 60000; /* Timeout every 60 seconds by default */ /* Timeout every 24 hours by default */ set->general_ssl.ca_cache_timeout = 24 * 60 * 60; @@ -455,6 +457,14 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data) #endif } + /* set default minimum TLS version */ +#ifdef USE_SSL + Curl_setopt_SSLVERSION(data, CURLOPT_SSLVERSION, CURL_SSLVERSION_DEFAULT); +#ifndef CURL_DISABLE_PROXY + Curl_setopt_SSLVERSION(data, CURLOPT_PROXY_SSLVERSION, + CURL_SSLVERSION_DEFAULT); +#endif +#endif #ifndef CURL_DISABLE_FTP set->wildcard_enabled = FALSE; set->chunk_bgn = ZERO_NULL; @@ -832,7 +842,7 @@ static bool url_match_connect_config(struct connectdata *conn, struct url_conn_match *m) { /* connect-only or to-be-closed connections will not be reused */ - if(conn->connect_only || conn->bits.close) + if(conn->connect_only || conn->bits.close || conn->bits.no_reuse) return FALSE; /* ip_version must match */ @@ -1373,38 +1383,6 @@ ConnectionExists(struct Curl_easy *data, return result; } -/* - * verboseconnect() displays verbose information after a connect - */ -#ifndef CURL_DISABLE_VERBOSE_STRINGS -void Curl_verboseconnect(struct Curl_easy *data, - struct connectdata *conn, int sockindex) -{ - if(data->set.verbose && sockindex == SECONDARYSOCKET) - infof(data, "Connected 2nd connection to %s port %u", - conn->secondary.remote_ip, conn->secondary.remote_port); - else - infof(data, "Connected to %s (%s) port %u", - CURL_CONN_HOST_DISPNAME(conn), conn->primary.remote_ip, - conn->primary.remote_port); -#ifndef CURL_DISABLE_HTTP - if(conn->handler->protocol & PROTO_FAMILY_HTTP) { - switch(conn->alpn) { - case CURL_HTTP_VERSION_3: - infof(data, "using HTTP/3"); - break; - case CURL_HTTP_VERSION_2: - infof(data, "using HTTP/2"); - break; - default: - infof(data, "using HTTP/1.x"); - break; - } - } -#endif -} -#endif - /* * Allocate and initialize a new connectdata object. */ @@ -1418,10 +1396,9 @@ static struct connectdata *allocate_conn(struct Curl_easy *data) conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */ - conn->sockfd = CURL_SOCKET_BAD; - conn->writesockfd = CURL_SOCKET_BAD; + conn->recv_idx = 0; /* default for receiving transfer data */ + conn->send_idx = 0; /* default for sending transfer data */ conn->connection_id = -1; /* no ID */ - conn->primary.remote_port = -1; /* unknown at this point */ conn->remote_port = -1; /* unknown at this point */ /* Default protocol-independent behavior does not support persistent @@ -2033,7 +2010,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data, valid = FALSE; } if(valid) - conn->primary.remote_port = conn->remote_port = (unsigned short)port; + conn->remote_port = (unsigned short)port; } (void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0); @@ -2092,33 +2069,21 @@ static CURLcode setup_range(struct Curl_easy *data) static CURLcode setup_connection_internals(struct Curl_easy *data, struct connectdata *conn) { - const struct Curl_handler *p; const char *hostname; int port; CURLcode result; - /* Perform setup complement if some. */ - p = conn->handler; - - if(p->setup_connection) { - result = (*p->setup_connection)(data, conn); - + if(conn->handler->setup_connection) { + result = conn->handler->setup_connection(data, conn); if(result) return result; - - p = conn->handler; /* May have changed. */ } - if(conn->primary.remote_port < 0) - /* we check for -1 here since if proxy was detected already, this was - likely already set to the proxy port */ - conn->primary.remote_port = p->defport; - /* Now create the destination name */ #ifndef CURL_DISABLE_PROXY if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { hostname = conn->http_proxy.host.name; - port = conn->primary.remote_port; + port = conn->http_proxy.port; } else #endif @@ -2241,7 +2206,7 @@ static char *detect_proxy(struct Curl_easy *data, */ static CURLcode parse_proxy(struct Curl_easy *data, struct connectdata *conn, char *proxy, - curl_proxytype proxytype) + long proxytype) { char *portptr = NULL; int port = -1; @@ -2379,12 +2344,8 @@ static CURLcode parse_proxy(struct Curl_easy *data, port = CURL_DEFAULT_PROXY_PORT; } } - if(port >= 0) { + if(port >= 0) proxyinfo->port = port; - if(conn->primary.remote_port < 0 || sockstype || - !conn->socks_proxy.host.rawalloc) - conn->primary.remote_port = port; - } /* now, clone the proxy hostname */ uc = curl_url_get(uhp, CURLUPART_HOST, &host, CURLU_URLDECODE); @@ -2559,7 +2520,7 @@ static CURLcode create_conn_helper_init_proxy(struct Curl_easy *data, * connection that may exist registered to the same proxy host. ***********************************************************************/ if(proxy || socksproxy) { - curl_proxytype ptype = (curl_proxytype)conn->http_proxy.proxytype; + long ptype = conn->http_proxy.proxytype; if(proxy) { result = parse_proxy(data, conn, proxy, ptype); Curl_safefree(proxy); /* parse_proxy copies the proxy string */ @@ -2952,7 +2913,7 @@ static CURLcode parse_connect_to_host_port(struct Curl_easy *data, CURLcode result = CURLE_OK; #ifdef CURL_DISABLE_VERBOSE_STRINGS - (void) data; + (void)data; #endif *hostname_result = NULL; @@ -3191,8 +3152,8 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data, &as /* to */, allowed_alpns); } - #endif - #ifdef USE_HTTP2 +#endif +#ifdef USE_HTTP2 if(!hit && (neg->wanted & CURL_HTTP_V2x) && !neg->h2_prior_knowledge) { srcalpnid = ALPN_h2; @@ -3201,7 +3162,7 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data, &as /* to */, allowed_alpns); } - #endif +#endif if(!hit && (neg->wanted & CURL_HTTP_V1x) && !neg->only_10) { srcalpnid = ALPN_h1; @@ -3263,7 +3224,7 @@ static CURLcode resolve_unix(struct Curl_easy *data, /* Unix domain sockets are local. The host gets ignored, just use the * specified domain socket address. Do not cache "DNS entries". There is - * no DNS involved and we already have the filesystem path available. */ + * no DNS involved and we already have the file system path available. */ hostaddr = calloc(1, sizeof(struct Curl_dns_entry)); if(!hostaddr) return CURLE_OUT_OF_MEMORY; @@ -3293,6 +3254,7 @@ static CURLcode resolve_server(struct Curl_easy *data, struct Curl_dns_entry **pdns) { struct hostname *ehost; + int eport; timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE); const char *peertype = "host"; CURLcode result; @@ -3322,6 +3284,8 @@ static CURLcode resolve_server(struct Curl_easy *data, if(CONN_IS_PROXIED(conn)) { ehost = conn->bits.socksproxy ? &conn->socks_proxy.host : &conn->http_proxy.host; + eport = conn->bits.socksproxy ? conn->socks_proxy.port : + conn->http_proxy.port; peertype = "proxy"; } else @@ -3330,8 +3294,7 @@ static CURLcode resolve_server(struct Curl_easy *data, ehost = conn->bits.conn_to_host ? &conn->conn_to_host : &conn->host; /* If not connecting via a proxy, extract the port from the URL, if it is * there, thus overriding any defaults that might have been set above. */ - conn->primary.remote_port = conn->bits.conn_to_port ? conn->conn_to_port : - conn->remote_port; + eport = conn->bits.conn_to_port ? conn->conn_to_port : conn->remote_port; } /* Resolve target host right on */ @@ -3340,7 +3303,7 @@ static CURLcode resolve_server(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; result = Curl_resolv_timeout(data, conn->hostname_resolve, - conn->primary.remote_port, conn->ip_version, + eport, conn->ip_version, pdns, timeout_ms); DEBUGASSERT(!result || !*pdns); if(result == CURLE_AGAIN) { @@ -3717,7 +3680,7 @@ static CURLcode create_conn(struct Curl_easy *data, *in_connect = conn; #ifndef CURL_DISABLE_PROXY - infof(data, "Re-using existing %s: connection%s with %s %s", + infof(data, "Reusing existing %s: connection%s with %s %s", conn->given->scheme, tls_upgraded ? " (upgraded to SSL)" : "", conn->bits.proxy ? "proxy" : "host", @@ -3725,7 +3688,7 @@ static CURLcode create_conn(struct Curl_easy *data, conn->http_proxy.host.name ? conn->http_proxy.host.dispname : conn->host.dispname); #else - infof(data, "Re-using existing %s: connection%s with host %s", + infof(data, "Reusing existing %s: connection%s with host %s", conn->given->scheme, tls_upgraded ? " (upgraded to SSL)" : "", conn->host.dispname); @@ -4078,7 +4041,7 @@ void Curl_data_priority_clear_state(struct Curl_easy *data) memset(&data->state.priority, 0, sizeof(data->state.priority)); } -#endif /* defined(USE_HTTP2) || defined(USE_HTTP3) */ +#endif /* USE_HTTP2 || USE_HTTP3 */ CURLcode Curl_conn_meta_set(struct connectdata *conn, const char *key, diff --git a/deps/curl/lib/url.h b/deps/curl/lib/url.h index bd4060c8846..11a69d41578 100644 --- a/deps/curl/lib/url.h +++ b/deps/curl/lib/url.h @@ -79,13 +79,6 @@ const struct Curl_handler *Curl_getn_scheme_handler(const char *scheme, #define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless specified */ -#ifdef CURL_DISABLE_VERBOSE_STRINGS -#define Curl_verboseconnect(x,y,z) Curl_nop_stmt -#else -void Curl_verboseconnect(struct Curl_easy *data, struct connectdata *conn, - int sockindex); -#endif - /** * Return TRUE iff the given connection is considered dead. * @param nowp NULL or pointer to time being checked against. @@ -118,7 +111,7 @@ CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2); void Curl_data_priority_clear_state(struct Curl_easy *data); #else #define Curl_data_priority_clear_state(x) -#endif /* !(defined(USE_HTTP2) || defined(USE_HTTP3)) */ +#endif /* USE_HTTP2 || USE_HTTP3 */ #ifdef USE_NGHTTP2 CURLcode Curl_data_priority_add_child(struct Curl_easy *parent, diff --git a/deps/curl/lib/urlapi.c b/deps/curl/lib/urlapi.c index c266fd3ebc2..c89852794e0 100644 --- a/deps/curl/lib/urlapi.c +++ b/deps/curl/lib/urlapi.c @@ -511,7 +511,7 @@ static CURLUcode ipv6_parse(struct Curl_URL *u, char *hostname, { char dest[16]; /* fits a binary IPv6 address */ hostname[hlen] = 0; /* end the address there */ - if(1 != curlx_inet_pton(AF_INET6, hostname, dest)) + if(curlx_inet_pton(AF_INET6, hostname, dest) != 1) return CURLUE_BAD_IPV6; if(curlx_inet_ntop(AF_INET6, dest, hostname, hlen)) { hlen = strlen(hostname); /* might be shorter now */ @@ -1757,13 +1757,26 @@ static CURLUcode urlset_clear(CURLU *u, CURLUPart what) return CURLUE_OK; } +static bool allowed_in_path(unsigned char x) +{ + switch(x) { + case '!': case '$': case '&': case '\'': + case '(': case ')': case '{': case '}': + case '[': case ']': case '*': case '+': + case ',': case ';': case '=': case ':': + case '@': case '/': + return TRUE; + } + return FALSE; +} + CURLUcode curl_url_set(CURLU *u, CURLUPart what, const char *part, unsigned int flags) { char **storep = NULL; bool urlencode = (flags & CURLU_URLENCODE) ? 1 : 0; bool plusencode = FALSE; - bool urlskipslash = FALSE; + bool pathmode = FALSE; bool leadingslash = FALSE; bool appendquery = FALSE; bool equalsencode = FALSE; @@ -1808,7 +1821,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, case CURLUPART_PORT: return set_url_port(u, part); case CURLUPART_PATH: - urlskipslash = TRUE; + pathmode = TRUE; leadingslash = TRUE; /* enforce */ storep = &u->path; break; @@ -1850,7 +1863,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what, return CURLUE_OUT_OF_MEMORY; } else if(ISUNRESERVED(*i) || - ((*i == '/') && urlskipslash) || + (pathmode && allowed_in_path(*i)) || ((*i == '=') && equalsencode)) { if((*i == '=') && equalsencode) /* only skip the first equals sign */ diff --git a/deps/curl/lib/urldata.h b/deps/curl/lib/urldata.h index e54721dd983..cf181af641f 100644 --- a/deps/curl/lib/urldata.h +++ b/deps/curl/lib/urldata.h @@ -70,11 +70,11 @@ struct curl_trc_featt; * platforms that have a >= 64-bit type and then we use such a type for the * protocol fields in the protocol handler. */ -#define CURLPROTO_WS (1<<30) +#define CURLPROTO_WS (1L<<30) #define CURLPROTO_WSS ((curl_prot_t)1<<31) #else -#define CURLPROTO_WS 0 -#define CURLPROTO_WSS 0 +#define CURLPROTO_WS 0L +#define CURLPROTO_WSS 0L #endif /* the default protocols accepting a redirect to */ @@ -317,7 +317,7 @@ struct ssl_general_config { #ifndef CURL_DISABLE_DIGEST_AUTH /* Struct used for Digest challenge-response authentication */ struct digestdata { -#if defined(USE_WINDOWS_SSPI) +#ifdef USE_WINDOWS_SSPI BYTE *input_token; size_t input_token_len; CtxtHandle *http_context; @@ -423,6 +423,7 @@ struct ConnectBits { BIT(parallel_connect); /* set TRUE when a parallel connect attempt has started (happy eyeballs) */ BIT(aborted); /* connection was aborted, e.g. in unclean state */ + BIT(no_reuse); /* connection should not be reused */ BIT(shutdown_handler); /* connection shutdown: handler shut down */ BIT(shutdown_filters); /* connection shutdown: filters shut down */ BIT(in_cpool); /* connection is kept in a connection pool */ @@ -470,15 +471,6 @@ struct hostname { #define FIRSTSOCKET 0 #define SECONDARYSOCKET 1 -/* Polling requested by an easy handle. - * `action` is CURL_POLL_IN, CURL_POLL_OUT or CURL_POLL_INOUT. - */ -struct easy_pollset { - curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; - unsigned int num; - unsigned char actions[MAX_SOCKSPEREASYHANDLE]; -}; - /* * Specific protocol handler. */ @@ -515,24 +507,24 @@ struct Curl_handler { /* Called from the multi interface during the PROTOCONNECT phase, and it should then return a proper fd set */ - int (*proto_getsock)(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); + CURLcode (*proto_pollset)(struct Curl_easy *data, + struct easy_pollset *ps); /* Called from the multi interface during the DOING phase, and it should then return a proper fd set */ - int (*doing_getsock)(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); + CURLcode (*doing_pollset)(struct Curl_easy *data, + struct easy_pollset *ps); /* Called from the multi interface during the DO_MORE phase, and it should then return a proper fd set */ - int (*domore_getsock)(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); + CURLcode (*domore_pollset)(struct Curl_easy *data, + struct easy_pollset *ps); /* Called from the multi interface during the DO_DONE, PERFORM and WAITPERFORM phases, and it should then return a proper fd set. Not setting this will make libcurl use the generic default one. */ - int (*perform_getsock)(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *socks); + CURLcode (*perform_pollset)(struct Curl_easy *data, + struct easy_pollset *ps); /* This function *MAY* be set to a protocol-dependent function that is run * by the curl_disconnect(), as a step in the disconnection. If the handler @@ -625,8 +617,7 @@ struct ip_quadruple { struct proxy_info { struct hostname host; int port; - unsigned char proxytype; /* curl_proxytype: what kind of proxy that is in - use */ + unsigned char proxytype; /* what kind of proxy that is in use */ char *user; /* proxy username string, allocated */ char *passwd; /* proxy password string, allocated */ }; @@ -674,14 +665,6 @@ struct connectdata { struct proxy_info socks_proxy; struct proxy_info http_proxy; #endif - /* 'primary' and 'secondary' get filled with IP quadruple - (local/remote numerical ip address and port) whenever a connect is - *attempted*. - When more than one address is tried for a connection these will hold data - for the last attempt. When the connection is actually established - these are updated with data which comes directly from the socket. */ - struct ip_quadruple primary; - struct ip_quadruple secondary; char *user; /* username string, allocated */ char *passwd; /* password string, allocated */ char *options; /* options string, allocated */ @@ -689,11 +672,18 @@ struct connectdata { char *oauth_bearer; /* OAUTH2 bearer, allocated */ struct curltime created; /* creation time */ struct curltime lastused; /* when returned to the connection poolas idle */ - curl_socket_t sock[2]; /* two sockets, the second is used for the data - transfer when doing FTP */ + + /* A connection can have one or two sockets and connection filters. + * The protocol using the 2nd one is FTP for CONTROL+DATA sockets */ + curl_socket_t sock[2]; + struct Curl_cfilter *cfilter[2]; /* connection filters */ Curl_recv *recv[2]; Curl_send *send[2]; - struct Curl_cfilter *cfilter[2]; /* connection filters */ + int recv_idx; /* on which socket index to receive, default 0 */ + int send_idx; /* on which socket index to send, default 0 */ + +#define CONN_SOCK_IDX_VALID(i) (((i) >= 0) && ((i) < 2)) + struct { struct curltime start[2]; /* when filter shutdown started */ timediff_t timeout_ms; /* 0 means no timeout */ @@ -715,10 +705,6 @@ struct connectdata { /**** curl_get() phase fields */ - curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */ - curl_socket_t writesockfd; /* socket to write to, it may be the same we read - from. CURL_SOCKET_BAD disables */ - #ifdef HAVE_GSSAPI BIT(sec_complete); /* if Kerberos is enabled for this connection */ unsigned char command_prot; /* enum protection_level */ @@ -742,10 +728,10 @@ struct connectdata { /*************** Request - specific items ************/ #if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS) - CtxtHandle *sslContext; + CtxtHandle *sslContext; /* mingw-w64 v9+. MS SDK 7.0A+. */ #endif -#if defined(USE_NTLM) +#ifdef USE_NTLM curlntlm http_ntlm_state; curlntlm proxy_ntlm_state; #endif @@ -780,17 +766,12 @@ struct connectdata { unsigned short localport; unsigned short secondary_port; /* secondary socket remote port to connect to (ftp) */ - unsigned char alpn; /* APLN TLS negotiated protocol, a CURL_HTTP_VERSION* - value */ -#ifndef CURL_DISABLE_PROXY - unsigned char proxy_alpn; /* APLN of proxy tunnel, CURL_HTTP_VERSION* */ -#endif unsigned char transport_wanted; /* one of the TRNSPRT_* defines. Not necessarily the transport the connection ends using due to Alt-Svc and happy eyeballing. Use `Curl_conn_get_transport() for actual value once the connection is set up. */ unsigned char ip_version; /* copied from the Curl_easy at creation time */ - /* HTTP version last responded with by the server. + /* HTTP version last responded with by the server or negotiated via ALPN. * 0 at start, then one of 09, 10, 11, etc. */ unsigned char httpversion_seen; unsigned char connect_only; @@ -966,7 +947,6 @@ typedef enum { EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */ EXPIRE_HAPPY_EYEBALLS, EXPIRE_MULTI_PENDING, - EXPIRE_RUN_NOW, EXPIRE_SPEEDCHECK, EXPIRE_TIMEOUT, EXPIRE_TOOFAST, @@ -1053,7 +1033,7 @@ struct UrlState { struct Curl_async async; /* asynchronous name resolver data */ #endif -#if defined(USE_OPENSSL) +#ifdef USE_OPENSSL /* void instead of ENGINE to avoid bleeding OpenSSL into this header */ void *engine; /* void instead of OSSL_PROVIDER */ @@ -1142,7 +1122,6 @@ struct UrlState { #ifndef CURL_DISABLE_RTSP char *rtsp_transport; #endif - char *te; /* TE: request header */ /* transfer credentials */ char *user; @@ -1198,6 +1177,11 @@ struct UrlState { internal use and the user does not have ownership of the handle. */ BIT(http_ignorecustom); /* ignore custom method from now */ +#ifndef CURL_DISABLE_HTTP + BIT(http_hd_te); /* Added HTTP header TE: */ + BIT(http_hd_upgrade); /* Added HTTP header Upgrade: */ + BIT(http_hd_h2_settings); /* Added HTTP header H2Settings: */ +#endif }; /* @@ -1255,7 +1239,7 @@ enum dupstring { STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */ STRING_FTPPORT, /* port to send with the FTP PORT command */ #endif -#if defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI STRING_KRB_LEVEL, /* krb security level */ #endif #ifndef CURL_DISABLE_NETRC @@ -1371,8 +1355,6 @@ struct UserDefined { void *writeheader; /* write the header to this if non-NULL */ unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */ unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */ - long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1 - for infinity */ void *postfields; /* if POST, set the fields' values here */ curl_seek_callback seek_func; /* function that seeks the input */ curl_off_t postfieldsize; /* if POST, this might have a size to use instead @@ -1411,9 +1393,6 @@ struct UserDefined { is to be reused */ timediff_t conn_max_age_ms; /* max time since creation to allow a connection that is to be reused */ -#ifndef CURL_DISABLE_TFTP - long tftp_blksize; /* in bytes, 0 means use default */ -#endif curl_off_t filesize; /* size of file to upload, -1 means unknown */ long low_speed_limit; /* bytes/second */ long low_speed_time; /* number of seconds */ @@ -1441,11 +1420,11 @@ struct UserDefined { unsigned short proxyport; /* If non-zero, use this port number by default. If the proxy string features a ":[port]" that one will override this. */ - unsigned char proxytype; /* what kind of proxy: curl_proxytype */ + unsigned char proxytype; /* what kind of proxy */ unsigned char socks5auth;/* kind of SOCKS5 authentication to use (bitmask) */ #endif struct ssl_general_config general_ssl; /* general user defined SSL stuff */ - int dns_cache_timeout; /* DNS cache timeout (seconds) */ + timediff_t dns_cache_timeout_ms; /* DNS cache timeout (milliseconds) */ unsigned int buffer_size; /* size of receive buffer to use */ unsigned int upload_buffer_size; /* size of upload buffer to use, keep it >= CURL_MAX_WRITE_SIZE */ @@ -1508,7 +1487,6 @@ struct UserDefined { int tcp_keepintvl; /* seconds between TCP keepalive probes */ int tcp_keepcnt; /* maximum number of keepalive probes */ - long expect_100_timeout; /* in milliseconds */ #if defined(USE_HTTP2) || defined(USE_HTTP3) struct Curl_data_priority priority; #endif @@ -1528,6 +1506,9 @@ struct UserDefined { #ifdef USE_ECH int tls_ech; /* TLS ECH configuration */ #endif + short maxredirs; /* maximum no. of http(s) redirects to follow, + set to -1 for infinity */ + unsigned short expect_100_timeout; /* in milliseconds */ unsigned short use_port; /* which port to use (when not using default) */ #ifndef CURL_DISABLE_BINDLOCAL unsigned short localport; /* local port number to bind to */ @@ -1535,6 +1516,9 @@ struct UserDefined { in case the 'localport' one cannot be bind()ed */ #endif +#ifndef CURL_DISABLE_TFTP + unsigned short tftp_blksize; /* in bytes, 0 means use default */ +#endif #ifndef CURL_DISABLE_NETRC unsigned char use_netrc; /* enum CURL_NETRC_OPTION values */ #endif @@ -1620,7 +1604,7 @@ struct UserDefined { location: */ BIT(opt_no_body); /* as set with CURLOPT_NOBODY */ BIT(verbose); /* output verbosity */ -#if defined(HAVE_GSSAPI) +#ifdef HAVE_GSSAPI BIT(krb); /* Kerberos connection requested */ #endif BIT(reuse_forbid); /* forbidden to be reused, close after use */ diff --git a/deps/curl/lib/vauth/cleartext.c b/deps/curl/lib/vauth/cleartext.c index 8fc5d41b9a3..ebf026fcf5f 100644 --- a/deps/curl/lib/vauth/cleartext.c +++ b/deps/curl/lib/vauth/cleartext.c @@ -74,8 +74,8 @@ CURLcode Curl_auth_create_plain_message(const char *authzid, plen = strlen(passwd); /* Compute binary message length. Check for overflows. */ - if((zlen > SIZE_T_MAX/4) || (clen > SIZE_T_MAX/4) || - (plen > (SIZE_T_MAX/2 - 2))) + if((zlen > SIZE_MAX/4) || (clen > SIZE_MAX/4) || + (plen > (SIZE_MAX/2 - 2))) return CURLE_OUT_OF_MEMORY; plainlen = zlen + clen + plen + 2; diff --git a/deps/curl/lib/vauth/digest_sspi.c b/deps/curl/lib/vauth/digest_sspi.c index 28d0b3599c2..c74b8f86539 100644 --- a/deps/curl/lib/vauth/digest_sspi.c +++ b/deps/curl/lib/vauth/digest_sspi.c @@ -203,7 +203,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, status == SEC_I_COMPLETE_AND_CONTINUE) Curl_pSecFn->CompleteAuthToken(&credentials, &resp_desc); else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS char buffer[STRERROR_LEN]; #endif @@ -215,7 +215,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS infof(data, "schannel: InitializeSecurityContext failed: %s", Curl_sspi_strerror(status, buffer, sizeof(buffer))); #endif @@ -411,7 +411,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, SecBufferDesc chlg_desc; SECURITY_STATUS status; - (void) data; + (void)data; /* Query the security package for DigestSSP */ status = @@ -602,7 +602,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, status == SEC_I_COMPLETE_AND_CONTINUE) Curl_pSecFn->CompleteAuthToken(&credentials, &resp_desc); else if(status != SEC_E_OK && status != SEC_I_CONTINUE_NEEDED) { -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS char buffer[STRERROR_LEN]; #endif @@ -616,7 +616,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(status == SEC_E_INSUFFICIENT_MEMORY) return CURLE_OUT_OF_MEMORY; -#if !defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifndef CURL_DISABLE_VERBOSE_STRINGS infof(data, "schannel: InitializeSecurityContext failed: %s", Curl_sspi_strerror(status, buffer, sizeof(buffer))); #endif diff --git a/deps/curl/lib/vauth/krb5_gssapi.c b/deps/curl/lib/vauth/krb5_gssapi.c index 78f4be3dc94..fd46619d846 100644 --- a/deps/curl/lib/vauth/krb5_gssapi.c +++ b/deps/curl/lib/vauth/krb5_gssapi.c @@ -99,8 +99,8 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; - (void) userp; - (void) passwdp; + (void)userp; + (void)passwdp; if(!krb5->spn) { gss_buffer_desc spn_token = GSS_C_EMPTY_BUFFER; diff --git a/deps/curl/lib/vauth/krb5_sspi.c b/deps/curl/lib/vauth/krb5_sspi.c index a29358569d9..ea26f82750a 100644 --- a/deps/curl/lib/vauth/krb5_sspi.c +++ b/deps/curl/lib/vauth/krb5_sspi.c @@ -270,8 +270,8 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data, SecPkgContext_Sizes sizes; SECURITY_STATUS status; -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; #endif /* Ensure we have a valid challenge message */ diff --git a/deps/curl/lib/vauth/ntlm.c b/deps/curl/lib/vauth/ntlm.c index 5cda790dda3..6164cd388be 100644 --- a/deps/curl/lib/vauth/ntlm.c +++ b/deps/curl/lib/vauth/ntlm.c @@ -235,7 +235,7 @@ static void ntlm_print_hex(FILE *handle, const char *buf, size_t len) { const char *p = buf; - (void) handle; + (void)handle; fprintf(stderr, "0x"); while(len-- > 0) @@ -268,8 +268,8 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data, const unsigned char *type2 = Curl_bufref_ptr(type2ref); size_t type2len = Curl_bufref_len(type2ref); -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; #endif if(type2len >= 48) { @@ -368,7 +368,7 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const unsigned char *type2 = Curl_bufref_ptr(type2ref); size_t type2len = Curl_bufref_len(type2ref); -#if defined(CURL_DISABLE_VERBOSE_STRINGS) +#ifdef CURL_DISABLE_VERBOSE_STRINGS (void)data; #endif diff --git a/deps/curl/lib/vauth/ntlm_sspi.c b/deps/curl/lib/vauth/ntlm_sspi.c index 86b4bccfdf4..d45e2db38e1 100644 --- a/deps/curl/lib/vauth/ntlm_sspi.c +++ b/deps/curl/lib/vauth/ntlm_sspi.c @@ -205,8 +205,8 @@ CURLcode Curl_auth_decode_ntlm_type2_message(struct Curl_easy *data, const struct bufref *type2, struct ntlmdata *ntlm) { -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; #endif /* Ensure we have a valid type-2 message */ @@ -257,11 +257,11 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data, unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; #endif - (void) passwdp; - (void) userp; + (void)passwdp; + (void)userp; /* Setup the type-2 "input" security buffer */ type_2_desc.ulVersion = SECBUFFER_VERSION; diff --git a/deps/curl/lib/vauth/spnego_gssapi.c b/deps/curl/lib/vauth/spnego_gssapi.c index 1e576c71348..4ed02a398ca 100644 --- a/deps/curl/lib/vauth/spnego_gssapi.c +++ b/deps/curl/lib/vauth/spnego_gssapi.c @@ -98,8 +98,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, gss_channel_bindings_t chan_bindings = GSS_C_NO_CHANNEL_BINDINGS; struct gss_channel_bindings_struct chan; - (void) user; - (void) password; + (void)user; + (void)password; if(nego->context && nego->status == GSS_S_COMPLETE) { /* We finished successfully our part of authentication, but server diff --git a/deps/curl/lib/vauth/spnego_sspi.c b/deps/curl/lib/vauth/spnego_sspi.c index c19a1ff4236..9c481252612 100644 --- a/deps/curl/lib/vauth/spnego_sspi.c +++ b/deps/curl/lib/vauth/spnego_sspi.c @@ -107,8 +107,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, unsigned long attrs; TimeStamp expiry; /* For Windows 9x compatibility of SSPI calls */ -#if defined(CURL_DISABLE_VERBOSE_STRINGS) - (void) data; +#ifdef CURL_DISABLE_VERBOSE_STRINGS + (void)data; #endif if(nego->context && nego->status == SEC_E_OK) { diff --git a/deps/curl/lib/vauth/vauth.c b/deps/curl/lib/vauth/vauth.c index 7a85b7041f6..1b44aa6de1a 100644 --- a/deps/curl/lib/vauth/vauth.c +++ b/deps/curl/lib/vauth/vauth.c @@ -54,7 +54,7 @@ * * Returns a pointer to the newly allocated SPN. */ -#if !defined(USE_WINDOWS_SSPI) +#ifndef USE_WINDOWS_SSPI char *Curl_auth_build_spn(const char *service, const char *host, const char *realm) { @@ -79,7 +79,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host, TCHAR *tchar_spn = NULL; TCHAR *dupe_tchar_spn = NULL; - (void) realm; + (void)realm; /* Note: We could use DsMakeSPN() or DsClientMakeSpnForTargetServer() rather than doing this ourselves but the first is only available in Windows XP diff --git a/deps/curl/lib/vauth/vauth.h b/deps/curl/lib/vauth/vauth.h index 7d085e33fdb..d9e73a0ed12 100644 --- a/deps/curl/lib/vauth/vauth.h +++ b/deps/curl/lib/vauth/vauth.h @@ -32,11 +32,11 @@ struct Curl_easy; struct connectdata; -#if !defined(CURL_DISABLE_DIGEST_AUTH) +#ifndef CURL_DISABLE_DIGEST_AUTH struct digestdata; #endif -#if defined(USE_NTLM) +#ifdef USE_NTLM struct ntlmdata; #endif @@ -44,7 +44,7 @@ struct ntlmdata; struct negotiatedata; #endif -#if defined(USE_GSASL) +#ifdef USE_GSASL struct gsasldata; #endif @@ -60,7 +60,7 @@ struct gsasldata; bool Curl_auth_allowed_to_host(struct Curl_easy *data); /* This is used to build an SPN string */ -#if !defined(USE_WINDOWS_SSPI) +#ifndef USE_WINDOWS_SSPI char *Curl_auth_build_spn(const char *service, const char *host, const char *realm); #else @@ -153,7 +153,7 @@ CURLcode Curl_auth_gsasl_token(struct Curl_easy *data, void Curl_auth_gsasl_cleanup(struct gsasldata *digest); #endif -#if defined(USE_NTLM) +#ifdef USE_NTLM /* meta key for storing NTML meta at connection */ #define CURL_META_NTLM_CONN "meta:auth:ntml:conn" @@ -231,7 +231,7 @@ CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, const char *bearer, struct bufref *out); -#if defined(USE_KERBEROS5) +#ifdef USE_KERBEROS5 #ifdef HAVE_GSSAPI # ifdef HAVE_GSSGNU @@ -250,7 +250,7 @@ CURLcode Curl_auth_create_xoauth_bearer_message(const char *user, #define CURL_META_KRB5_CONN "meta:auth:krb5:conn" struct kerberos5data { -#if defined(USE_WINDOWS_SSPI) +#ifdef USE_WINDOWS_SSPI CredHandle *credentials; CtxtHandle *context; TCHAR *spn; diff --git a/deps/curl/lib/version.c b/deps/curl/lib/version.c index bf4c76d016c..a2d48672009 100644 --- a/deps/curl/lib/version.c +++ b/deps/curl/lib/version.c @@ -197,10 +197,10 @@ char *curl_version(void) #ifdef USE_SSH char ssh_version[30]; #endif -#ifdef USE_NGHTTP2 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2) char h2_version[30]; #endif -#ifdef USE_HTTP3 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) char h3_version[30]; #endif #ifdef USE_LIBRTMP @@ -258,11 +258,11 @@ char *curl_version(void) Curl_ssh_version(ssh_version, sizeof(ssh_version)); src[i++] = ssh_version; #endif -#ifdef USE_NGHTTP2 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2) Curl_http2_ver(h2_version, sizeof(h2_version)); src[i++] = h2_version; #endif -#ifdef USE_HTTP3 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) Curl_quic_ver(h3_version, sizeof(h3_version)); src[i++] = h3_version; #endif @@ -428,7 +428,7 @@ static int idn_present(curl_version_info_data *info) !defined(CURL_DISABLE_HTTP) static int https_proxy_present(curl_version_info_data *info) { - (void) info; + (void)info; return Curl_ssl_supports(NULL, SSLSUPP_HTTPS_PROXY); } #endif @@ -436,7 +436,7 @@ static int https_proxy_present(curl_version_info_data *info) #if defined(USE_SSL) && defined(USE_ECH) static int ech_present(curl_version_info_data *info) { - (void) info; + (void)info; return Curl_ssl_supports(NULL, SSLSUPP_ECH); } #endif @@ -488,17 +488,17 @@ static const struct feat features_table[] = { #ifndef CURL_DISABLE_HSTS FEATURE("HSTS", NULL, CURL_VERSION_HSTS), #endif -#if defined(USE_NGHTTP2) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGHTTP2) FEATURE("HTTP2", NULL, CURL_VERSION_HTTP2), #endif -#if defined(USE_HTTP3) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) FEATURE("HTTP3", NULL, CURL_VERSION_HTTP3), #endif #if defined(USE_SSL) && !defined(CURL_DISABLE_PROXY) && \ !defined(CURL_DISABLE_HTTP) FEATURE("HTTPS-proxy", https_proxy_present, CURL_VERSION_HTTPS_PROXY), #endif -#if defined(USE_HTTPSRR) +#ifdef USE_HTTPSRR FEATURE("HTTPSRR", NULL, 0), #endif #if defined(USE_LIBIDN2) || defined(USE_WIN32_IDN) || defined(USE_APPLE_IDN) @@ -523,7 +523,7 @@ static const struct feat features_table[] = { #ifdef USE_NTLM FEATURE("NTLM", NULL, CURL_VERSION_NTLM), #endif -#if defined(USE_LIBPSL) +#ifdef USE_LIBPSL FEATURE("PSL", NULL, CURL_VERSION_PSL), #endif #ifdef USE_SPNEGO @@ -532,7 +532,7 @@ static const struct feat features_table[] = { #ifdef USE_SSL FEATURE("SSL", NULL, CURL_VERSION_SSL), #endif -#if defined(USE_SSLS_EXPORT) +#ifdef USE_SSLS_EXPORT FEATURE("SSLS-EXPORT", NULL, 0), #endif #ifdef USE_WINDOWS_SSPI @@ -607,7 +607,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp) const struct feat *p; int features = 0; -#if defined(USE_SSH) +#ifdef USE_SSH static char ssh_buf[80]; /* 'ssh_buffer' clashes with libssh/libssh.h */ #endif #ifdef USE_SSL @@ -624,7 +624,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp) static char zstd_buffer[80]; #endif - (void)stamp; /* avoid compiler warnings, we do not use this */ + (void)stamp; #ifdef USE_SSL Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer)); @@ -648,7 +648,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp) version_info.libidn = idn2_check_version(IDN2_VERSION); #endif -#if defined(USE_SSH) +#ifdef USE_SSH Curl_ssh_version(ssh_buf, sizeof(ssh_buf)); version_info.libssh_version = ssh_buf; #endif @@ -673,7 +673,7 @@ curl_version_info_data *curl_version_info(CURLversion stamp) } #endif -#ifdef USE_HTTP3 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) { static char quicbuffer[80]; Curl_quic_ver(quicbuffer, sizeof(quicbuffer)); diff --git a/deps/curl/lib/vquic/curl_msh3.c b/deps/curl/lib/vquic/curl_msh3.c deleted file mode 100644 index 6566447ba10..00000000000 --- a/deps/curl/lib/vquic/curl_msh3.c +++ /dev/null @@ -1,1095 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) Daniel Stenberg, , et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at https://curl.se/docs/copyright.html. - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so, under the terms of the COPYING file. - * - * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY - * KIND, either express or implied. - * - * SPDX-License-Identifier: curl - * - ***************************************************************************/ - -#include "../curl_setup.h" - -#ifdef USE_MSH3 - -#include "../urldata.h" -#include "../hash.h" -#include "../uint-hash.h" -#include "../curlx/timeval.h" -#include "../multiif.h" -#include "../sendf.h" -#include "../curl_trc.h" -#include "../cfilters.h" -#include "../cf-socket.h" -#include "../connect.h" -#include "../progress.h" -#include "../http1.h" -#include "curl_msh3.h" -#include "../socketpair.h" -#include "../vtls/vtls.h" -#include "vquic.h" -#include "vquic_int.h" - -/* The last 3 #include files should be in this order */ -#include "../curl_printf.h" -#include "../curl_memory.h" -#include "../memdebug.h" - -#ifdef CURL_DISABLE_SOCKETPAIR -#error "MSH3 cannot be build with CURL_DISABLE_SOCKETPAIR set" -#endif - -#define H3_STREAM_WINDOW_SIZE (128 * 1024) -#define H3_STREAM_CHUNK_SIZE (16 * 1024) -#define H3_STREAM_RECV_CHUNKS \ - (H3_STREAM_WINDOW_SIZE / H3_STREAM_CHUNK_SIZE) - -#ifdef _WIN32 -#define msh3_lock CRITICAL_SECTION -#define msh3_lock_initialize(lock) InitializeCriticalSection(lock) -#define msh3_lock_uninitialize(lock) DeleteCriticalSection(lock) -#define msh3_lock_acquire(lock) EnterCriticalSection(lock) -#define msh3_lock_release(lock) LeaveCriticalSection(lock) -#else /* !_WIN32 */ -#include -#define msh3_lock pthread_mutex_t -#define msh3_lock_initialize(lock) do { \ - pthread_mutexattr_t attr; \ - pthread_mutexattr_init(&attr); \ - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); \ - pthread_mutex_init(lock, &attr); \ - pthread_mutexattr_destroy(&attr); \ -} while(0) -#define msh3_lock_uninitialize(lock) pthread_mutex_destroy(lock) -#define msh3_lock_acquire(lock) pthread_mutex_lock(lock) -#define msh3_lock_release(lock) pthread_mutex_unlock(lock) -#endif /* _WIN32 */ - - -static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection, - void *IfContext); -static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection, - void *IfContext); -static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection, - void *IfContext, - MSH3_REQUEST *Request); -static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request, - void *IfContext, - const MSH3_HEADER *Header); -static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request, - void *IfContext, uint32_t *Length, - const uint8_t *Data); -static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext, - bool Aborted, uint64_t AbortError); -static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request, - void *IfContext); -static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request, - void *IfContext, void *SendContext); - - -void Curl_msh3_ver(char *p, size_t len) -{ - uint32_t v[4]; - MsH3Version(v); - (void)msnprintf(p, len, "msh3/%d.%d.%d.%d", v[0], v[1], v[2], v[3]); -} - -#define SP_LOCAL 0 -#define SP_REMOTE 1 - -struct cf_msh3_ctx { - MSH3_API *api; - MSH3_CONNECTION *qconn; - struct Curl_sockaddr_ex addr; - curl_socket_t sock[2]; /* fake socket pair until we get support in msh3 */ - char l_ip[MAX_IPADR_LEN]; /* local IP as string */ - int l_port; /* local port number */ - struct cf_call_data call_data; - struct curltime connect_started; /* time the current attempt started */ - struct curltime handshake_at; /* time connect handshake finished */ - struct uint_hash streams; /* hash `data->mid` to `stream_ctx` */ - /* Flags written by msh3/msquic thread */ - BIT(handshake_complete); - BIT(handshake_succeeded); - BIT(connected); - BIT(initialized); - /* Flags written by curl thread */ - BIT(verbose); - BIT(active); -}; - -static void h3_stream_hash_free(unsigned int id, void *stream); - -static CURLcode cf_msh3_ctx_init(struct cf_msh3_ctx *ctx, - const struct Curl_addrinfo *ai) -{ - CURLcode result; - - DEBUGASSERT(!ctx->initialized); - Curl_uint_hash_init(&ctx->streams, 63, h3_stream_hash_free); - - result = Curl_sock_assign_addr(&ctx->addr, ai, TRNSPRT_QUIC); - if(result) - return result; - - ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; - ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD; - ctx->initialized = TRUE; - - return result; -} - -static void cf_msh3_ctx_free(struct cf_msh3_ctx *ctx) -{ - if(ctx && ctx->initialized) { - Curl_uint_hash_destroy(&ctx->streams); - } - free(ctx); -} - -static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data); - -/* How to access `call_data` from a cf_msh3 filter */ -#undef CF_CTX_CALL_DATA -#define CF_CTX_CALL_DATA(cf) \ - ((struct cf_msh3_ctx *)(cf)->ctx)->call_data - -/** - * All about the H3 internals of a stream - */ -struct h3_stream_ctx { - struct MSH3_REQUEST *req; - struct bufq recvbuf; /* h3 response */ -#ifdef _WIN32 - CRITICAL_SECTION recv_lock; -#else /* !_WIN32 */ - pthread_mutex_t recv_lock; -#endif /* _WIN32 */ - uint64_t error3; /* HTTP/3 stream error code */ - int status_code; /* HTTP status code */ - CURLcode recv_error; - BIT(closed); - BIT(reset); - BIT(upload_done); - BIT(firstheader); /* FALSE until headers arrive */ - BIT(recv_header_complete); -}; - -static void h3_stream_ctx_free(struct h3_stream_ctx *stream) -{ - Curl_bufq_free(&stream->recvbuf); - free(stream); -} - -static void h3_stream_hash_free(unsigned int id, void *stream) -{ - (void)id; - DEBUGASSERT(stream); - h3_stream_ctx_free((struct h3_stream_ctx *)stream); -} - -static CURLcode h3_data_setup(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - - if(stream) - return CURLE_OK; - - stream = calloc(1, sizeof(*stream)); - if(!stream) - return CURLE_OUT_OF_MEMORY; - - stream->req = ZERO_NULL; - msh3_lock_initialize(&stream->recv_lock); - Curl_bufq_init2(&stream->recvbuf, H3_STREAM_CHUNK_SIZE, - H3_STREAM_RECV_CHUNKS, BUFQ_OPT_SOFT_LIMIT); - CURL_TRC_CF(data, cf, "data setup"); - - if(!Curl_uint_hash_set(&ctx->streams, data->mid, stream)) { - h3_stream_ctx_free(stream); - return CURLE_OUT_OF_MEMORY; - } - - return CURLE_OK; -} - -static void h3_data_done(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - - (void)cf; - if(stream) { - CURL_TRC_CF(data, cf, "easy handle is done"); - Curl_uint_hash_remove(&ctx->streams, data->mid); - } -} - -static void drain_stream_from_other_thread(struct Curl_easy *data, - struct h3_stream_ctx *stream) -{ - (void)data; - (void)stream; - /* cannot expire from other thread. - here is the disconnect between msh3 and curl */ -} - -static void h3_drain_stream(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - (void)cf; - Curl_multi_mark_dirty(data); -} - -static const MSH3_CONNECTION_IF msh3_conn_if = { - msh3_conn_connected, - msh3_conn_shutdown_complete, - msh3_conn_new_request -}; - -static void MSH3_CALL msh3_conn_connected(MSH3_CONNECTION *Connection, - void *IfContext) -{ - struct Curl_cfilter *cf = IfContext; - struct cf_msh3_ctx *ctx = cf->ctx; - struct Curl_easy *data = CF_DATA_CURRENT(cf); - (void)Connection; - - CURL_TRC_CF(data, cf, "[MSH3] connected"); - ctx->handshake_succeeded = TRUE; - ctx->connected = TRUE; - ctx->handshake_complete = TRUE; -} - -static void MSH3_CALL msh3_conn_shutdown_complete(MSH3_CONNECTION *Connection, - void *IfContext) -{ - struct Curl_cfilter *cf = IfContext; - struct cf_msh3_ctx *ctx = cf->ctx; - struct Curl_easy *data = CF_DATA_CURRENT(cf); - - (void)Connection; - CURL_TRC_CF(data, cf, "[MSH3] shutdown complete"); - ctx->connected = FALSE; - ctx->handshake_complete = TRUE; -} - -static void MSH3_CALL msh3_conn_new_request(MSH3_CONNECTION *Connection, - void *IfContext, - MSH3_REQUEST *Request) -{ - (void)Connection; - (void)IfContext; - (void)Request; -} - -static const MSH3_REQUEST_IF msh3_request_if = { - msh3_header_received, - msh3_data_received, - msh3_complete, - msh3_shutdown_complete, - msh3_data_sent -}; - -/* Decode HTTP status code. Returns -1 if no valid status code was - decoded. (duplicate from http2.c) */ -static int decode_status_code(const char *value, size_t len) -{ - int i; - int res; - - if(len != 3) { - return -1; - } - - res = 0; - - for(i = 0; i < 3; ++i) { - char c = value[i]; - - if(c < '0' || c > '9') { - return -1; - } - - res *= 10; - res += c - '0'; - } - - return res; -} - -/* - * write_resp_raw() copies response data in raw format to the `data`'s - * receive buffer. If not enough space is available, it appends to the - * `data`'s overflow buffer. - */ -static CURLcode write_resp_raw(struct Curl_easy *data, - const void *mem, size_t memlen) -{ - struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data); - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - CURLcode result = CURLE_OK; - size_t nwritten; - - if(!stream) - return CURLE_RECV_ERROR; - - result = Curl_bufq_write(&stream->recvbuf, mem, memlen, &nwritten); - if(result) - return result; - - if(nwritten < memlen) { - /* This MUST not happen. Our recbuf is dimensioned to hold the - * full max_stream_window and then some for this very reason. */ - DEBUGASSERT(0); - return CURLE_RECV_ERROR; - } - return result; -} - -static void MSH3_CALL msh3_header_received(MSH3_REQUEST *Request, - void *userp, - const MSH3_HEADER *hd) -{ - struct Curl_easy *data = userp; - struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data); - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - CURLcode result; - (void)Request; - - DEBUGF(infof(data, "[MSH3] header received, stream=%d", !!stream)); - if(!stream || stream->recv_header_complete) { - return; - } - - msh3_lock_acquire(&stream->recv_lock); - - if((hd->NameLength == 7) && - !strncmp(HTTP_PSEUDO_STATUS, (const char *)hd->Name, 7)) { - char line[14]; /* status line is always 13 characters long */ - size_t ncopy; - - DEBUGASSERT(!stream->firstheader); - stream->status_code = decode_status_code(hd->Value, hd->ValueLength); - DEBUGASSERT(stream->status_code != -1); - ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", - stream->status_code); - result = write_resp_raw(data, line, ncopy); - if(result) - stream->recv_error = result; - stream->firstheader = TRUE; - } - else { - /* store as an HTTP1-style header */ - DEBUGASSERT(stream->firstheader); - result = write_resp_raw(data, hd->Name, hd->NameLength); - if(!result) - result = write_resp_raw(data, ": ", 2); - if(!result) - result = write_resp_raw(data, hd->Value, hd->ValueLength); - if(!result) - result = write_resp_raw(data, "\r\n", 2); - if(result) { - stream->recv_error = result; - } - } - - drain_stream_from_other_thread(data, stream); - msh3_lock_release(&stream->recv_lock); -} - -static bool MSH3_CALL msh3_data_received(MSH3_REQUEST *Request, - void *IfContext, uint32_t *buflen, - const uint8_t *buf) -{ - struct Curl_easy *data = IfContext; - struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data); - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - CURLcode result; - bool rv = FALSE; - - /* We would like to limit the amount of data we are buffer here. There seems - * to be no mechanism in msh3 to adjust flow control and it is undocumented - * what happens if we return FALSE here or less length (buflen is an inout - * parameter). - */ - (void)Request; - if(!stream) - return FALSE; - - msh3_lock_acquire(&stream->recv_lock); - - if(!stream->recv_header_complete) { - result = write_resp_raw(data, "\r\n", 2); - if(result) { - stream->recv_error = result; - goto out; - } - stream->recv_header_complete = TRUE; - } - - result = write_resp_raw(data, buf, *buflen); - if(result) { - stream->recv_error = result; - } - rv = TRUE; - -out: - msh3_lock_release(&stream->recv_lock); - return rv; -} - -static void MSH3_CALL msh3_complete(MSH3_REQUEST *Request, void *IfContext, - bool aborted, uint64_t error) -{ - struct Curl_easy *data = IfContext; - struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data); - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - - (void)Request; - if(!stream) - return; - msh3_lock_acquire(&stream->recv_lock); - stream->closed = TRUE; - stream->recv_header_complete = TRUE; - if(error) - stream->error3 = error; - if(aborted) - stream->reset = TRUE; - msh3_lock_release(&stream->recv_lock); -} - -static void MSH3_CALL msh3_shutdown_complete(MSH3_REQUEST *Request, - void *IfContext) -{ - struct Curl_easy *data = IfContext; - struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data); - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - - if(!stream) - return; - (void)Request; - (void)stream; -} - -static void MSH3_CALL msh3_data_sent(MSH3_REQUEST *Request, - void *IfContext, void *SendContext) -{ - struct Curl_easy *data = IfContext; - struct cf_msh3_ctx *ctx = h3_get_msh3_ctx(data); - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - if(!stream) - return; - (void)Request; - (void)stream; - (void)SendContext; -} - -static CURLcode recv_closed_stream(struct Curl_cfilter *cf, - struct Curl_easy *data, - size_t *pnread) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - - (void)cf; - *pnread = 0; - if(!stream) - return CURLE_RECV_ERROR; - - if(stream->reset) { - failf(data, "HTTP/3 stream reset by server"); - CURL_TRC_CF(data, cf, "cf_recv, was reset"); - return CURLE_PARTIAL_FILE; - } - else if(stream->error3) { - failf(data, "HTTP/3 stream was not closed cleanly: (error %zd)", - (ssize_t)stream->error3); - CURL_TRC_CF(data, cf, "cf_recv, closed uncleanly"); - return CURLE_HTTP3; - } - else { - CURL_TRC_CF(data, cf, "cf_recv, closed ok"); - } - return CURLE_OK; -} - -static void set_quic_expire(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - - /* we have no indication from msh3 when it would be a good time - * to juggle the connection again. So, we compromise by calling - * us again every some milliseconds. */ - (void)cf; - if(stream && stream->req && !stream->closed) { - Curl_expire(data, 10, EXPIRE_QUIC); - } - else { - Curl_expire(data, 50, EXPIRE_QUIC); - } -} - -static CURLcode cf_msh3_recv(struct Curl_cfilter *cf, struct Curl_easy *data, - char *buf, size_t len, size_t *pnread) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - struct cf_call_data save; - CURLcode result = CURLE_OK; - - *pnread = 0; - CURL_TRC_CF(data, cf, "cf_recv(len=%zu), stream=%d", len, !!stream); - if(!stream) - return CURLE_RECV_ERROR; - CF_DATA_SAVE(save, cf, data); - - msh3_lock_acquire(&stream->recv_lock); - - if(stream->recv_error) { - failf(data, "request aborted"); - result = stream->recv_error; - goto out; - } - - if(!Curl_bufq_is_empty(&stream->recvbuf)) { - result = Curl_bufq_cread(&stream->recvbuf, buf, len, pnread); - CURL_TRC_CF(data, cf, "read recvbuf(len=%zu) -> %d, %zu", - len, result, *pnread); - if(result) - goto out; - if(stream->closed) - h3_drain_stream(cf, data); - } - else if(stream->closed) { - result = recv_closed_stream(cf, data, pnread); - goto out; - } - else { - CURL_TRC_CF(data, cf, "req: nothing here, call again"); - result = CURLE_AGAIN; - } - -out: - msh3_lock_release(&stream->recv_lock); - set_quic_expire(cf, data); - CF_DATA_RESTORE(cf, save); - return result; -} - -static CURLcode cf_msh3_send(struct Curl_cfilter *cf, struct Curl_easy *data, - const void *buf, size_t len, bool eos, - size_t *pnwritten) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - struct h1_req_parser h1; - struct dynhds h2_headers; - MSH3_HEADER *nva = NULL; - size_t nheader, i; - ssize_t nwritten = -1; - struct cf_call_data save; - CURLcode result = CURLE_OK; - - *pnwritten = 0; - CF_DATA_SAVE(save, cf, data); - - Curl_h1_req_parse_init(&h1, H1_PARSE_DEFAULT_MAX_LINE_LEN); - Curl_dynhds_init(&h2_headers, 0, DYN_HTTP_REQUEST); - - /* Sizes must match for cast below to work" */ - DEBUGASSERT(stream); - CURL_TRC_CF(data, cf, "req: send %zu bytes", len); - - if(!stream->req) { - /* The first send on the request contains the headers and possibly some - data. Parse out the headers and create the request, then if there is - any data left over go ahead and send it too. */ - nwritten = Curl_h1_req_parse_read(&h1, buf, len, NULL, 0, &result); - if(nwritten < 0) - goto out; - DEBUGASSERT(h1.done); - DEBUGASSERT(h1.req); - *pnwritten = (size_t)nwritten; - - result = Curl_http_req_to_h2(&h2_headers, h1.req, data); - if(result) - goto out; - - nheader = Curl_dynhds_count(&h2_headers); - nva = malloc(sizeof(MSH3_HEADER) * nheader); - if(!nva) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - for(i = 0; i < nheader; ++i) { - struct dynhds_entry *e = Curl_dynhds_getn(&h2_headers, i); - nva[i].Name = e->name; - nva[i].NameLength = e->namelen; - nva[i].Value = e->value; - nva[i].ValueLength = e->valuelen; - } - - CURL_TRC_CF(data, cf, "req: send %zu headers", nheader); - stream->req = MsH3RequestOpen(ctx->qconn, &msh3_request_if, data, - nva, nheader, - eos ? MSH3_REQUEST_FLAG_FIN : - MSH3_REQUEST_FLAG_NONE); - if(!stream->req) { - failf(data, "request open failed"); - result = CURLE_SEND_ERROR; - } - result = CURLE_OK; - *pnwritten = len; - goto out; - } - else { - /* request is open */ - CURL_TRC_CF(data, cf, "req: send %zu body bytes", len); - if(len > 0xFFFFFFFF) { - len = 0xFFFFFFFF; - } - - if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_NONE, buf, - (uint32_t)len, stream)) { - result = CURLE_SEND_ERROR; - goto out; - } - - /* msh3/msquic will hold onto this memory until the send complete event. - How do we make sure curl does not free it until then? */ - result = CURLE_OK; - *pnwritten = len; - } - -out: - set_quic_expire(cf, data); - free(nva); - Curl_h1_req_parse_free(&h1); - Curl_dynhds_free(&h2_headers); - CF_DATA_RESTORE(cf, save); - return result; -} - -static void cf_msh3_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - struct cf_call_data save; - - CF_DATA_SAVE(save, cf, data); - if(stream && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) { - if(stream->recv_error) { - Curl_pollset_add_in(data, ps, ctx->sock[SP_LOCAL]); - h3_drain_stream(cf, data); - } - else if(stream->req) { - Curl_pollset_add_out(data, ps, ctx->sock[SP_LOCAL]); - h3_drain_stream(cf, data); - } - } -} - -static bool cf_msh3_data_pending(struct Curl_cfilter *cf, - const struct Curl_easy *data) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - struct cf_call_data save; - bool pending = FALSE; - - CF_DATA_SAVE(save, cf, data); - - (void)cf; - if(stream && stream->req) { - msh3_lock_acquire(&stream->recv_lock); - CURL_TRC_CF((struct Curl_easy *)CURL_UNCONST(data), cf, - "data pending = %zu", - Curl_bufq_len(&stream->recvbuf)); - pending = !Curl_bufq_is_empty(&stream->recvbuf); - msh3_lock_release(&stream->recv_lock); - if(pending) - h3_drain_stream(cf, (struct Curl_easy *)CURL_UNCONST(data)); - } - - CF_DATA_RESTORE(cf, save); - return pending; -} - -static CURLcode h3_data_pause(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool pause) -{ - if(!pause) { - h3_drain_stream(cf, data); - Curl_expire(data, 0, EXPIRE_RUN_NOW); - } - return CURLE_OK; -} - -static CURLcode cf_msh3_data_event(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct h3_stream_ctx *stream = H3_STREAM_CTX(ctx, data); - struct cf_call_data save; - CURLcode result = CURLE_OK; - - CF_DATA_SAVE(save, cf, data); - - (void)arg1; - (void)arg2; - switch(event) { - case CF_CTRL_DATA_SETUP: - result = h3_data_setup(cf, data); - break; - case CF_CTRL_DATA_PAUSE: - result = h3_data_pause(cf, data, (arg1 != 0)); - break; - case CF_CTRL_DATA_DONE: - h3_data_done(cf, data); - break; - case CF_CTRL_DATA_DONE_SEND: - CURL_TRC_CF(data, cf, "req: send done"); - if(stream) { - stream->upload_done = TRUE; - if(stream->req) { - char buf[1]; - if(!MsH3RequestSend(stream->req, MSH3_REQUEST_FLAG_FIN, - buf, 0, data)) { - result = CURLE_SEND_ERROR; - } - } - } - break; - default: - break; - } - - CF_DATA_RESTORE(cf, save); - return result; -} - -static CURLcode cf_connect_start(struct Curl_cfilter *cf, - struct Curl_easy *data) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct ssl_primary_config *conn_config; - MSH3_ADDR addr = {0}; - CURLcode result; - bool verify; - - DEBUGASSERT(ctx->initialized); - conn_config = Curl_ssl_cf_get_primary_config(cf); - if(!conn_config) - return CURLE_FAILED_INIT; - verify = !!conn_config->verifypeer; - - memcpy(&addr, &ctx->addr.curl_sa_addr, ctx->addr.addrlen); - MSH3_SET_PORT(&addr, (uint16_t)cf->conn->remote_port); - - if(verify && (conn_config->CAfile || conn_config->CApath)) { - /* Note there's currently no way to provide trust anchors to MSH3 and - that causes tests to fail. */ - CURL_TRC_CF(data, cf, "non-standard CA not supported, " - "attempting with built-in verification"); - } - - CURL_TRC_CF(data, cf, "connecting to %s:%d (verify=%d)", - cf->conn->host.name, (int)cf->conn->remote_port, verify); - - ctx->api = MsH3ApiOpen(); - if(!ctx->api) { - failf(data, "cannot create msh3 api"); - return CURLE_FAILED_INIT; - } - - ctx->qconn = MsH3ConnectionOpen(ctx->api, - &msh3_conn_if, - cf, - cf->conn->host.name, - &addr, - !verify); - if(!ctx->qconn) { - failf(data, "cannot create msh3 connection"); - if(ctx->api) { - MsH3ApiClose(ctx->api); - ctx->api = NULL; - } - return CURLE_FAILED_INIT; - } - - result = h3_data_setup(cf, data); - if(result) - return result; - - return CURLE_OK; -} - -static CURLcode cf_msh3_connect(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *done) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct cf_call_data save; - CURLcode result = CURLE_OK; - - if(cf->connected) { - *done = TRUE; - return CURLE_OK; - } - - CF_DATA_SAVE(save, cf, data); - - if(ctx->sock[SP_LOCAL] == CURL_SOCKET_BAD) { - if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, &ctx->sock[0], FALSE) < 0) { - ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; - ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD; - return CURLE_COULDNT_CONNECT; - } - } - - *done = FALSE; - if(!ctx->qconn) { - ctx->connect_started = curlx_now(); - result = cf_connect_start(cf, data); - if(result) - goto out; - } - - if(ctx->handshake_complete) { - ctx->handshake_at = curlx_now(); - if(ctx->handshake_succeeded) { - CURL_TRC_CF(data, cf, "handshake succeeded"); - cf->conn->bits.multiplex = TRUE; /* at least potentially multiplexed */ - cf->connected = TRUE; - cf->conn->alpn = CURL_HTTP_VERSION_3; - *done = TRUE; - connkeep(cf->conn, "HTTP/3 default"); - Curl_pgrsTime(data, TIMER_APPCONNECT); - } - else { - failf(data, "failed to connect, handshake failed"); - result = CURLE_COULDNT_CONNECT; - } - } - -out: - CF_DATA_RESTORE(cf, save); - return result; -} - -static void cf_msh3_close(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - struct cf_call_data save; - - (void)data; - CF_DATA_SAVE(save, cf, data); - - if(ctx) { - CURL_TRC_CF(data, cf, "destroying"); - if(ctx->qconn) { - MsH3ConnectionClose(ctx->qconn); - ctx->qconn = NULL; - } - if(ctx->api) { - MsH3ApiClose(ctx->api); - ctx->api = NULL; - } - - if(ctx->active) { - /* We share our socket at cf->conn->sock[cf->sockindex] when active. - * If it is no longer there, someone has stolen (and hopefully - * closed it) and we just forget about it. - */ - ctx->active = FALSE; - if(ctx->sock[SP_LOCAL] == cf->conn->sock[cf->sockindex]) { - CURL_TRC_CF(data, cf, "cf_msh3_close(%d) active", - (int)ctx->sock[SP_LOCAL]); - cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD; - } - else { - CURL_TRC_CF(data, cf, "cf_socket_close(%d) no longer at " - "conn->sock[], discarding", (int)ctx->sock[SP_LOCAL]); - ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; - } - } - if(ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD) { - sclose(ctx->sock[SP_LOCAL]); - } - if(ctx->sock[SP_REMOTE] != CURL_SOCKET_BAD) { - sclose(ctx->sock[SP_REMOTE]); - } - ctx->sock[SP_LOCAL] = CURL_SOCKET_BAD; - ctx->sock[SP_REMOTE] = CURL_SOCKET_BAD; - } - CF_DATA_RESTORE(cf, save); -} - -static void cf_msh3_destroy(struct Curl_cfilter *cf, struct Curl_easy *data) -{ - struct cf_call_data save; - - CF_DATA_SAVE(save, cf, data); - cf_msh3_close(cf, data); - if(cf->ctx) { - cf_msh3_ctx_free(cf->ctx); - cf->ctx = NULL; - } - /* no CF_DATA_RESTORE(cf, save); its gone */ -} - -static CURLcode cf_msh3_query(struct Curl_cfilter *cf, - struct Curl_easy *data, - int query, int *pres1, void *pres2) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - - switch(query) { - case CF_QUERY_MAX_CONCURRENT: { - /* We do not have access to this so far, fake it */ - (void)ctx; - *pres1 = 100; - return CURLE_OK; - } - case CF_QUERY_TIMER_CONNECT: { - struct curltime *when = pres2; - /* we do not know when the first byte arrived */ - if(cf->connected) - *when = ctx->handshake_at; - return CURLE_OK; - } - case CF_QUERY_TIMER_APPCONNECT: { - struct curltime *when = pres2; - if(cf->connected) - *when = ctx->handshake_at; - return CURLE_OK; - } - case CF_QUERY_HTTP_VERSION: - *pres1 = 30; - return CURLE_OK; - default: - break; - } - return cf->next ? - cf->next->cft->query(cf->next, data, query, pres1, pres2) : - CURLE_UNKNOWN_OPTION; -} - -static bool cf_msh3_conn_is_alive(struct Curl_cfilter *cf, - struct Curl_easy *data, - bool *input_pending) -{ - struct cf_msh3_ctx *ctx = cf->ctx; - - (void)data; - *input_pending = FALSE; - return ctx && ctx->sock[SP_LOCAL] != CURL_SOCKET_BAD && ctx->qconn && - ctx->connected; -} - -struct Curl_cftype Curl_cft_http3 = { - "HTTP/3", - CF_TYPE_IP_CONNECT | CF_TYPE_SSL | CF_TYPE_MULTIPLEX | CF_TYPE_HTTP, - 0, - cf_msh3_destroy, - cf_msh3_connect, - cf_msh3_close, - Curl_cf_def_shutdown, - cf_msh3_adjust_pollset, - cf_msh3_data_pending, - cf_msh3_send, - cf_msh3_recv, - cf_msh3_data_event, - cf_msh3_conn_is_alive, - Curl_cf_def_conn_keep_alive, - cf_msh3_query, -}; - -static struct cf_msh3_ctx *h3_get_msh3_ctx(struct Curl_easy *data) -{ - if(data && data->conn) { - struct Curl_cfilter *cf = data->conn->cfilter[FIRSTSOCKET]; - while(cf) { - if(cf->cft == &Curl_cft_http3) - return cf->ctx; - cf = cf->next; - } - } - DEBUGF(infof(data, "no filter context found")); - return NULL; -} - -CURLcode Curl_cf_msh3_create(struct Curl_cfilter **pcf, - struct Curl_easy *data, - struct connectdata *conn, - const struct Curl_addrinfo *ai) -{ - struct cf_msh3_ctx *ctx = NULL; - struct Curl_cfilter *cf = NULL; - CURLcode result; - - (void)data; - (void)conn; - (void)ai; /* msh3 resolves itself? */ - ctx = calloc(1, sizeof(*ctx)); - if(!ctx) { - result = CURLE_OUT_OF_MEMORY; - goto out; - } - - result = cf_msh3_ctx_init(ctx, ai); - if(result) - goto out; - - result = Curl_cf_create(&cf, &Curl_cft_http3, ctx); - -out: - *pcf = (!result) ? cf : NULL; - if(result) { - Curl_safefree(cf); - cf_msh3_ctx_free(ctx); - } - - return result; -} - -bool Curl_conn_is_msh3(const struct Curl_easy *data, - const struct connectdata *conn, - int sockindex) -{ - struct Curl_cfilter *cf = conn ? conn->cfilter[sockindex] : NULL; - - (void)data; - for(; cf; cf = cf->next) { - if(cf->cft == &Curl_cft_http3) - return TRUE; - if(cf->cft->flags & CF_TYPE_IP_CONNECT) - return FALSE; - } - return FALSE; -} - -#endif /* USE_MSH3 */ diff --git a/deps/curl/lib/vquic/curl_ngtcp2.c b/deps/curl/lib/vquic/curl_ngtcp2.c index 69d54ecce28..6470f1506d1 100644 --- a/deps/curl/lib/vquic/curl_ngtcp2.c +++ b/deps/curl/lib/vquic/curl_ngtcp2.c @@ -24,7 +24,7 @@ #include "../curl_setup.h" -#if defined(USE_NGTCP2) && defined(USE_NGHTTP3) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGTCP2) && defined(USE_NGHTTP3) #include #include @@ -155,7 +155,7 @@ struct cf_ngtcp2_ctx { BIT(initialized); BIT(tls_handshake_complete); /* TLS handshake is done */ BIT(use_earlydata); /* Using 0RTT data */ - BIT(earlydata_accepted); /* 0RTT was acceptd by server */ + BIT(earlydata_accepted); /* 0RTT was accepted by server */ BIT(shutdown_started); /* queued shutdown packets */ }; @@ -431,9 +431,9 @@ static void quic_settings(struct cf_ngtcp2_ctx *ctx, s->log_printf = NULL; #endif - (void)data; s->initial_ts = pktx->ts; - s->handshake_timeout = QUIC_HANDSHAKE_TIMEOUT; + s->handshake_timeout = (data->set.connecttimeout > 0) ? + data->set.connecttimeout * NGTCP2_MILLISECONDS : QUIC_HANDSHAKE_TIMEOUT; s->max_window = 100 * ctx->max_stream_window; s->max_stream_window = 10 * ctx->max_stream_window; @@ -833,6 +833,9 @@ static ngtcp2_callbacks ng_callbacks = { cb_recv_rx_key, NULL, /* recv_tx_key */ NULL, /* early_data_rejected */ +#ifdef NGTCP2_CALLBACKS_V2 + NULL, /* begin_path_validation */ +#endif }; #if defined(_MSC_VER) && defined(_DLL) @@ -895,15 +898,16 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf, return CURLE_OK; } -static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_ngtcp2_ctx *ctx = cf->ctx; bool want_recv, want_send; + CURLcode result = CURLE_OK; if(!ctx->qconn) - return; + return CURLE_OK; Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send); if(!want_send && !Curl_bufq_is_empty(&ctx->q.sendbuf)) @@ -923,9 +927,10 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf, want_send = (!s_exhaust && want_send) || !Curl_bufq_is_empty(&ctx->q.sendbuf); - Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send); + result = Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send); CF_DATA_RESTORE(cf, save); } + return result; } static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid, @@ -1182,7 +1187,12 @@ static nghttp3_callbacks ngh3_callbacks = { NULL, /* end_stream */ cb_h3_reset_stream, NULL, /* shutdown */ - NULL /* recv_settings */ + NULL, /* recv_settings */ +#ifdef NGHTTP3_CALLBACKS_V2 + NULL, /* recv_origin */ + NULL, /* end_origin */ + NULL, /* rand */ +#endif }; static CURLcode init_ngh3_conn(struct Curl_cfilter *cf, @@ -1202,7 +1212,7 @@ static CURLcode init_ngh3_conn(struct Curl_cfilter *cf, rc = nghttp3_conn_client_new(&ctx->h3conn, &ngh3_callbacks, &ctx->h3settings, - nghttp3_mem_default(), + Curl_nghttp3_mem(), cf); if(rc) { failf(data, "error creating nghttp3 connection instance"); @@ -1331,7 +1341,6 @@ static CURLcode cf_ngtcp2_recv(struct Curl_cfilter *cf, struct Curl_easy *data, result = Curl_1st_err(result, check_and_set_expiry(cf, data, &pktx)); CURL_TRC_CF(data, cf, "[%" FMT_PRId64 "] cf_recv(blen=%zu) -> %dm, %zu", - stream ? stream->id : -1, blen, result, *pnread); CF_DATA_RESTORE(cf, save); return result; @@ -1946,9 +1955,9 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf, return CURLE_OK; } -static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) +static CURLcode cf_ngtcp2_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) { struct cf_ngtcp2_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -1986,6 +1995,10 @@ static CURLcode cf_ngtcp2_data_event(struct Curl_cfilter *cf, } break; } + case CF_CTRL_CONN_INFO_UPDATE: + if(!cf->sockindex && cf->connected) + cf->conn->httpversion_seen = 30; + break; default: break; } @@ -2462,7 +2475,7 @@ static const struct alpn_spec ALPN_SPEC_H3 = { &ctx->connected_path, NGTCP2_PROTO_VER_V1, &ng_callbacks, &ctx->settings, &ctx->transport_params, - NULL, cf); + Curl_ngtcp2_mem(), cf); if(rc) return CURLE_QUIC_CONNECT_ERROR; @@ -2536,7 +2549,6 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, if(result) goto out; if(cf->connected) { - cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; goto out; } @@ -2558,7 +2570,6 @@ static CURLcode cf_ngtcp2_connect(struct Curl_cfilter *cf, if(!result) { CURL_TRC_CF(data, cf, "peer verified"); cf->connected = TRUE; - cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; connkeep(cf->conn, "HTTP/3 default"); } @@ -2653,10 +2664,16 @@ static CURLcode cf_ngtcp2_query(struct Curl_cfilter *cf, case CF_QUERY_SSL_CTX_INFO: { struct curl_tlssessioninfo *info = pres2; if(Curl_vquic_tls_get_ssl_info(&ctx->tls, - (query == CF_QUERY_SSL_INFO), info)) + (query == CF_QUERY_SSL_CTX_INFO), info)) return CURLE_OK; break; } + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = cf->connected ? "h3" : NULL; + return CURLE_OK; + } default: break; } @@ -2720,7 +2737,7 @@ struct Curl_cftype Curl_cft_http3 = { Curl_cf_def_data_pending, cf_ngtcp2_send, cf_ngtcp2_recv, - cf_ngtcp2_data_event, + cf_ngtcp2_cntrl, cf_ngtcp2_conn_is_alive, Curl_cf_def_conn_keep_alive, cf_ngtcp2_query, diff --git a/deps/curl/lib/vquic/curl_ngtcp2.h b/deps/curl/lib/vquic/curl_ngtcp2.h index a4ccef49fec..86753a3a6ba 100644 --- a/deps/curl/lib/vquic/curl_ngtcp2.h +++ b/deps/curl/lib/vquic/curl_ngtcp2.h @@ -26,7 +26,7 @@ #include "../curl_setup.h" -#if defined(USE_NGTCP2) && defined(USE_NGHTTP3) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_NGTCP2) && defined(USE_NGHTTP3) #ifdef HAVE_NETINET_UDP_H #include diff --git a/deps/curl/lib/vquic/curl_osslq.c b/deps/curl/lib/vquic/curl_osslq.c index 90fed6c44f0..3586ad0d556 100644 --- a/deps/curl/lib/vquic/curl_osslq.c +++ b/deps/curl/lib/vquic/curl_osslq.c @@ -24,7 +24,8 @@ #include "../curl_setup.h" -#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_OPENSSL_QUIC) && \ + defined(USE_NGHTTP3) #include #include @@ -118,17 +119,17 @@ static const char *osslq_SSL_ERROR_to_str(int err) return "SSL_ERROR_WANT_CONNECT"; case SSL_ERROR_WANT_ACCEPT: return "SSL_ERROR_WANT_ACCEPT"; -#if defined(SSL_ERROR_WANT_ASYNC) +#ifdef SSL_ERROR_WANT_ASYNC /* OpenSSL 1.1.0+, LibreSSL 3.6.0+ */ case SSL_ERROR_WANT_ASYNC: return "SSL_ERROR_WANT_ASYNC"; #endif -#if defined(SSL_ERROR_WANT_ASYNC_JOB) +#ifdef SSL_ERROR_WANT_ASYNC_JOB /* OpenSSL 1.1.0+, LibreSSL 3.6.0+ */ case SSL_ERROR_WANT_ASYNC_JOB: return "SSL_ERROR_WANT_ASYNC_JOB"; #endif -#if defined(SSL_ERROR_WANT_EARLY) - case SSL_ERROR_WANT_EARLY: - return "SSL_ERROR_WANT_EARLY"; +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB /* OpenSSL 1.1.1, LibreSSL 3.6.0+ */ + case SSL_ERROR_WANT_CLIENT_HELLO_CB: + return "SSL_ERROR_WANT_CLIENT_HELLO_CB"; #endif default: return "SSL_ERROR unknown"; @@ -159,11 +160,11 @@ static char *osslq_strerror(unsigned long error, char *buf, size_t size) static CURLcode make_bio_addr(BIO_ADDR **pbio_addr, const struct Curl_sockaddr_ex *addr) { - BIO_ADDR *ba; + BIO_ADDR *bio_addr; CURLcode result = CURLE_FAILED_INIT; - ba = BIO_ADDR_new(); - if(!ba) { + bio_addr = BIO_ADDR_new(); + if(!bio_addr) { result = CURLE_OUT_OF_MEMORY; goto out; } @@ -172,7 +173,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr, case AF_INET: { struct sockaddr_in * const sin = (struct sockaddr_in * const)CURL_UNCONST(&addr->curl_sa_addr); - if(!BIO_ADDR_rawmake(ba, AF_INET, &sin->sin_addr, + if(!BIO_ADDR_rawmake(bio_addr, AF_INET, &sin->sin_addr, sizeof(sin->sin_addr), sin->sin_port)) { goto out; } @@ -183,7 +184,7 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr, case AF_INET6: { struct sockaddr_in6 * const sin = (struct sockaddr_in6 * const)CURL_UNCONST(&addr->curl_sa_addr); - if(!BIO_ADDR_rawmake(ba, AF_INET6, &sin->sin6_addr, + if(!BIO_ADDR_rawmake(bio_addr, AF_INET6, &sin->sin6_addr, sizeof(sin->sin6_addr), sin->sin6_port)) { } result = CURLE_OK; @@ -197,11 +198,11 @@ static CURLcode make_bio_addr(BIO_ADDR **pbio_addr, } out: - if(result && ba) { - BIO_ADDR_free(ba); - ba = NULL; + if(result && bio_addr) { + BIO_ADDR_free(bio_addr); + bio_addr = NULL; } - *pbio_addr = ba; + *pbio_addr = bio_addr; return result; } @@ -513,7 +514,7 @@ static CURLcode cf_osslq_ssl_err(struct Curl_cfilter *cf, else err_descr = "SSL certificate verification failed"; } -#if defined(SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED) +#ifdef SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED /* SSL_R_TLSV13_ALERT_CERTIFICATE_REQUIRED is only available on OpenSSL version above v1.1.1, not LibreSSL, BoringSSL, or AWS-LC */ else if((lib == ERR_LIB_SSL) && @@ -1086,7 +1087,12 @@ static nghttp3_callbacks ngh3_callbacks = { NULL, /* end_stream */ cb_h3_reset_stream, NULL, /* shutdown */ - NULL /* recv_settings */ + NULL, /* recv_settings */ +#ifdef NGHTTP3_CALLBACKS_V2 + NULL, /* recv_origin */ + NULL, /* end_origin */ + NULL, /* rand */ +#endif }; static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn, @@ -1100,7 +1106,7 @@ static CURLcode cf_osslq_h3conn_init(struct cf_osslq_ctx *ctx, SSL *conn, rc = nghttp3_conn_client_new(&h3->conn, &ngh3_callbacks, &h3->settings, - nghttp3_mem_default(), + Curl_nghttp3_mem(), user_data); if(rc) { result = CURLE_OUT_OF_MEMORY; @@ -1796,7 +1802,6 @@ static CURLcode cf_osslq_connect(struct Curl_cfilter *cf, if(!result) { CURL_TRC_CF(data, cf, "peer verified"); cf->connected = TRUE; - cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; connkeep(cf->conn, "HTTP/3 default"); } @@ -2163,9 +2168,9 @@ static bool cf_osslq_data_pending(struct Curl_cfilter *cf, return stream && !Curl_bufq_is_empty(&stream->recvbuf); } -static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) +static CURLcode cf_osslq_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) { struct cf_osslq_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -2201,6 +2206,10 @@ static CURLcode cf_osslq_data_event(struct Curl_cfilter *cf, } break; } + case CF_CTRL_CONN_INFO_UPDATE: + if(!cf->sockindex && cf->connected) + cf->conn->httpversion_seen = 30; + break; default: break; } @@ -2261,11 +2270,12 @@ static bool cf_osslq_conn_is_alive(struct Curl_cfilter *cf, return alive; } -static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_osslq_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_osslq_ctx *ctx = cf->ctx; + CURLcode result = CURLE_OK; if(!ctx->tls.ossl.ssl) { /* NOP */ @@ -2273,9 +2283,9 @@ static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf, else if(!cf->connected) { /* during handshake, transfer has not started yet. we always * add our socket for polling if SSL wants to send/recv */ - Curl_pollset_set(data, ps, ctx->q.sockfd, - SSL_net_read_desired(ctx->tls.ossl.ssl), - SSL_net_write_desired(ctx->tls.ossl.ssl)); + result = Curl_pollset_set(data, ps, ctx->q.sockfd, + SSL_net_read_desired(ctx->tls.ossl.ssl), + SSL_net_write_desired(ctx->tls.ossl.ssl)); } else { /* once connected, we only modify the socket if it is present. @@ -2283,15 +2293,16 @@ static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf, bool want_recv, want_send; Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send); if(want_recv || want_send) { - Curl_pollset_set(data, ps, ctx->q.sockfd, - SSL_net_read_desired(ctx->tls.ossl.ssl), - SSL_net_write_desired(ctx->tls.ossl.ssl)); + result = Curl_pollset_set(data, ps, ctx->q.sockfd, + SSL_net_read_desired(ctx->tls.ossl.ssl), + SSL_net_write_desired(ctx->tls.ossl.ssl)); } else if(ctx->need_recv || ctx->need_send) { - Curl_pollset_set(data, ps, ctx->q.sockfd, - ctx->need_recv, ctx->need_send); + result = Curl_pollset_set(data, ps, ctx->q.sockfd, + ctx->need_recv, ctx->need_send); } } + return result; } static CURLcode cf_osslq_query(struct Curl_cfilter *cf, @@ -2347,10 +2358,16 @@ static CURLcode cf_osslq_query(struct Curl_cfilter *cf, case CF_QUERY_SSL_CTX_INFO: { struct curl_tlssessioninfo *info = pres2; if(Curl_vquic_tls_get_ssl_info(&ctx->tls, - (query == CF_QUERY_SSL_INFO), info)) + (query == CF_QUERY_SSL_CTX_INFO), info)) return CURLE_OK; break; } + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = cf->connected ? "h3" : NULL; + return CURLE_OK; + } default: break; } @@ -2371,7 +2388,7 @@ struct Curl_cftype Curl_cft_http3 = { cf_osslq_data_pending, cf_osslq_send, cf_osslq_recv, - cf_osslq_data_event, + cf_osslq_cntrl, cf_osslq_conn_is_alive, Curl_cf_def_conn_keep_alive, cf_osslq_query, @@ -2443,4 +2460,4 @@ void Curl_osslq_ver(char *p, size_t len) (void)msnprintf(p, len, "nghttp3/%s", ht3->version_str); } -#endif /* USE_OPENSSL_QUIC && USE_NGHTTP3 */ +#endif /* !CURL_DISABLE_HTTP && USE_OPENSSL_QUIC && USE_NGHTTP3 */ diff --git a/deps/curl/lib/vquic/curl_osslq.h b/deps/curl/lib/vquic/curl_osslq.h index a2809c92bcc..9f5025f8aeb 100644 --- a/deps/curl/lib/vquic/curl_osslq.h +++ b/deps/curl/lib/vquic/curl_osslq.h @@ -26,7 +26,8 @@ #include "../curl_setup.h" -#if defined(USE_OPENSSL_QUIC) && defined(USE_NGHTTP3) +#if !defined(CURL_DISABLE_HTTP) && defined(USE_OPENSSL_QUIC) && \ + defined(USE_NGHTTP3) #ifdef HAVE_NETINET_UDP_H #include diff --git a/deps/curl/lib/vquic/curl_quiche.c b/deps/curl/lib/vquic/curl_quiche.c index 920913d288a..179ccf8aa1a 100644 --- a/deps/curl/lib/vquic/curl_quiche.c +++ b/deps/curl/lib/vquic/curl_quiche.c @@ -24,7 +24,7 @@ #include "../curl_setup.h" -#ifdef USE_QUICHE +#if !defined(CURL_DISABLE_HTTP) && defined(USE_QUICHE) #include #include #include @@ -40,6 +40,7 @@ #include "../connect.h" #include "../progress.h" #include "../strerror.h" +#include "../select.h" #include "../http1.h" #include "vquic.h" #include "vquic_int.h" @@ -1024,6 +1025,7 @@ static CURLcode h3_open_stream(struct Curl_cfilter *cf, stream3_id = quiche_h3_send_request(ctx->h3c, ctx->qconn, nva, nheader, stream->send_closed); + CURL_TRC_CF(data, cf, "quiche_send_request() -> %" FMT_PRIu64, stream3_id); if(stream3_id < 0) { if(QUICHE_H3_ERR_STREAM_BLOCKED == stream3_id) { /* quiche seems to report this error if the connection window is @@ -1141,15 +1143,16 @@ static bool stream_is_writeable(struct Curl_cfilter *cf, ctx->qconn, (curl_uint64_t)stream->id, 1) > 0); } -static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode cf_quiche_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct cf_quiche_ctx *ctx = cf->ctx; bool want_recv, want_send; + CURLcode result = CURLE_OK; if(!ctx->qconn) - return; + return CURLE_OK; Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send); if(want_recv || want_send) { @@ -1164,8 +1167,9 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf, want_send = (!s_exhaust && want_send) || !Curl_bufq_is_empty(&ctx->q.sendbuf); - Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send); + result = Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send); } + return result; } /* @@ -1194,9 +1198,9 @@ static CURLcode h3_data_pause(struct Curl_cfilter *cf, return CURLE_OK; } -static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, - struct Curl_easy *data, - int event, int arg1, void *arg2) +static CURLcode cf_quiche_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) { struct cf_quiche_ctx *ctx = cf->ctx; CURLcode result = CURLE_OK; @@ -1235,6 +1239,10 @@ static CURLcode cf_quiche_data_event(struct Curl_cfilter *cf, } break; } + case CF_CTRL_CONN_INFO_UPDATE: + if(!cf->sockindex && cf->connected) + cf->conn->httpversion_seen = 30; + break; default: break; } @@ -1416,7 +1424,6 @@ static CURLcode cf_quiche_connect(struct Curl_cfilter *cf, goto out; } cf->connected = TRUE; - cf->conn->alpn = CURL_HTTP_VERSION_3; *done = TRUE; connkeep(cf->conn, "HTTP/3 default"); } @@ -1552,10 +1559,16 @@ static CURLcode cf_quiche_query(struct Curl_cfilter *cf, case CF_QUERY_SSL_CTX_INFO: { struct curl_tlssessioninfo *info = pres2; if(Curl_vquic_tls_get_ssl_info(&ctx->tls, - (query == CF_QUERY_SSL_INFO), info)) + (query == CF_QUERY_SSL_CTX_INFO), info)) return CURLE_OK; break; } + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = cf->connected ? "h3" : NULL; + return CURLE_OK; + } default: break; } @@ -1613,7 +1626,7 @@ struct Curl_cftype Curl_cft_http3 = { cf_quiche_data_pending, cf_quiche_send, cf_quiche_recv, - cf_quiche_data_event, + cf_quiche_cntrl, cf_quiche_conn_is_alive, Curl_cf_def_conn_keep_alive, cf_quiche_query, diff --git a/deps/curl/lib/vquic/curl_quiche.h b/deps/curl/lib/vquic/curl_quiche.h index b2c767216fb..bee966eeb7a 100644 --- a/deps/curl/lib/vquic/curl_quiche.h +++ b/deps/curl/lib/vquic/curl_quiche.h @@ -26,7 +26,7 @@ #include "../curl_setup.h" -#ifdef USE_QUICHE +#if !defined(CURL_DISABLE_HTTP) && defined(USE_QUICHE) #include #include diff --git a/deps/curl/lib/vquic/vquic-tls.c b/deps/curl/lib/vquic/vquic-tls.c index 8a53c83b33b..4bdd23c981c 100644 --- a/deps/curl/lib/vquic/vquic-tls.c +++ b/deps/curl/lib/vquic/vquic-tls.c @@ -167,7 +167,7 @@ CURLcode Curl_vquic_tls_verify_peer(struct curl_tls_ctx *ctx, #ifdef USE_OPENSSL (void)conn_config; - result = Curl_oss_check_peer_cert(cf, data, &ctx->ossl, peer); + result = Curl_ossl_check_peer_cert(cf, data, &ctx->ossl, peer); #elif defined(USE_GNUTLS) if(conn_config->verifyhost) { result = Curl_gtls_verifyserver(data, ctx->gtls.session, @@ -208,7 +208,7 @@ bool Curl_vquic_tls_get_ssl_info(struct curl_tls_ctx *ctx, return TRUE; #elif defined(USE_GNUTLS) (void)give_ssl_ctx; /* gnutls always returns its session */ - info->backend = CURLSSLBACKEND_OPENSSL; + info->backend = CURLSSLBACKEND_GNUTLS; info->internals = ctx->gtls.session; return TRUE; #elif defined(USE_WOLFSSL) diff --git a/deps/curl/lib/vquic/vquic.c b/deps/curl/lib/vquic/vquic.c index 691c0d3fa73..647450a29ba 100644 --- a/deps/curl/lib/vquic/vquic.c +++ b/deps/curl/lib/vquic/vquic.c @@ -30,12 +30,14 @@ #ifdef HAVE_FCNTL_H #include #endif +#ifdef USE_NGHTTP3 +#include +#endif #include "../urldata.h" #include "../bufq.h" #include "../curlx/dynbuf.h" #include "../cfilters.h" #include "../curl_trc.h" -#include "curl_msh3.h" #include "curl_ngtcp2.h" #include "curl_osslq.h" #include "curl_quiche.h" @@ -52,7 +54,7 @@ #include "../memdebug.h" -#ifdef USE_HTTP3 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) #define NW_CHUNK_SIZE (64 * 1024) #define NW_SEND_CHUNKS 2 @@ -76,8 +78,6 @@ void Curl_quic_ver(char *p, size_t len) Curl_osslq_ver(p, len); #elif defined(USE_QUICHE) Curl_quiche_ver(p, len); -#elif defined(USE_MSH3) - Curl_msh3_ver(p, len); #endif } @@ -186,8 +186,9 @@ static CURLcode do_sendmsg(struct Curl_cfilter *cf, return CURLE_SEND_ERROR; } } - else { - assert(pktlen == (size_t)sent); + else if(pktlen != (size_t)sent) { + failf(data, "sendmsg() sent only %zd/%zu bytes", sent, pktlen); + return CURLE_SEND_ERROR; } #else ssize_t sent; @@ -615,7 +616,7 @@ CURLcode vquic_recv_packets(struct Curl_cfilter *cf, vquic_recv_pkt_cb *recv_cb, void *userp) { CURLcode result; -#if defined(HAVE_SENDMMSG) +#ifdef HAVE_SENDMMSG result = recvmmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp); #elif defined(HAVE_SENDMSG) result = recvmsg_packets(cf, data, qctx, max_pkts, recv_cb, userp); @@ -645,7 +646,7 @@ CURLcode Curl_qlogdir(struct Curl_easy *data, size_t scidlen, int *qlogfdp) { - const char *qlog_dir = getenv("QLOGDIR"); + char *qlog_dir = curl_getenv("QLOGDIR"); *qlogfdp = -1; if(qlog_dir) { struct dynbuf fname; @@ -670,6 +671,7 @@ CURLcode Curl_qlogdir(struct Curl_easy *data, *qlogfdp = qlogfd; } curlx_dyn_free(&fname); + free(qlog_dir); if(result) return result; } @@ -691,8 +693,6 @@ CURLcode Curl_cf_quic_create(struct Curl_cfilter **pcf, return Curl_cf_osslq_create(pcf, data, conn, ai); #elif defined(USE_QUICHE) return Curl_cf_quiche_create(pcf, data, conn, ai); -#elif defined(USE_MSH3) - return Curl_cf_msh3_create(pcf, data, conn, ai); #else *pcf = NULL; (void)data; @@ -728,7 +728,63 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data, return CURLE_OK; } -#else /* USE_HTTP3 */ +#if defined(USE_NGTCP2) || defined(USE_NGHTTP3) + +static void *vquic_ngtcp2_malloc(size_t size, void *user_data) +{ + (void)user_data; + return Curl_cmalloc(size); +} + +static void vquic_ngtcp2_free(void *ptr, void *user_data) +{ + (void)user_data; + Curl_cfree(ptr); +} + +static void *vquic_ngtcp2_calloc(size_t nmemb, size_t size, void *user_data) +{ + (void)user_data; + return Curl_ccalloc(nmemb, size); +} + +static void *vquic_ngtcp2_realloc(void *ptr, size_t size, void *user_data) +{ + (void)user_data; + return Curl_crealloc(ptr, size); +} + +#ifdef USE_NGTCP2 +static struct ngtcp2_mem vquic_ngtcp2_mem = { + NULL, + vquic_ngtcp2_malloc, + vquic_ngtcp2_free, + vquic_ngtcp2_calloc, + vquic_ngtcp2_realloc +}; +struct ngtcp2_mem *Curl_ngtcp2_mem(void) +{ + return &vquic_ngtcp2_mem; +} +#endif + +#ifdef USE_NGHTTP3 +static struct nghttp3_mem vquic_nghttp3_mem = { + NULL, + vquic_ngtcp2_malloc, + vquic_ngtcp2_free, + vquic_ngtcp2_calloc, + vquic_ngtcp2_realloc +}; +struct nghttp3_mem *Curl_nghttp3_mem(void) +{ + return &vquic_nghttp3_mem; +} +#endif + +#endif /* USE_NGTCP2 || USE_NGHTTP3 */ + +#else /* CURL_DISABLE_HTTP || !USE_HTTP3 */ CURLcode Curl_conn_may_http3(struct Curl_easy *data, const struct connectdata *conn, @@ -741,4 +797,4 @@ CURLcode Curl_conn_may_http3(struct Curl_easy *data, return CURLE_NOT_BUILT_IN; } -#endif /* !USE_HTTP3 */ +#endif /* !CURL_DISABLE_HTTP && USE_HTTP3 */ diff --git a/deps/curl/lib/vquic/vquic.h b/deps/curl/lib/vquic/vquic.h index 3577a857e33..0f81334f293 100644 --- a/deps/curl/lib/vquic/vquic.h +++ b/deps/curl/lib/vquic/vquic.h @@ -26,7 +26,7 @@ #include "../curl_setup.h" -#ifdef USE_HTTP3 +#if !defined(CURL_DISABLE_HTTP) && defined(USE_HTTP3) struct Curl_cfilter; struct Curl_easy; struct connectdata; @@ -51,7 +51,7 @@ extern struct Curl_cftype Curl_cft_http3; #else #define Curl_vquic_init() 1 -#endif /* !USE_HTTP3 */ +#endif /* !CURL_DISABLE_HTTP && USE_HTTP3 */ CURLcode Curl_conn_may_http3(struct Curl_easy *data, const struct connectdata *conn, diff --git a/deps/curl/lib/vquic/vquic_int.h b/deps/curl/lib/vquic/vquic_int.h index d271368d290..38189beb703 100644 --- a/deps/curl/lib/vquic/vquic_int.h +++ b/deps/curl/lib/vquic/vquic_int.h @@ -91,4 +91,13 @@ CURLcode vquic_recv_packets(struct Curl_cfilter *cf, #endif /* !USE_HTTP3 */ +#ifdef USE_NGTCP2 +struct ngtcp2_mem; +struct ngtcp2_mem *Curl_ngtcp2_mem(void); +#endif +#ifdef USE_NGHTTP3 +struct nghttp3_mem; +struct nghttp3_mem *Curl_nghttp3_mem(void); +#endif + #endif /* HEADER_CURL_VQUIC_QUIC_INT_H */ diff --git a/deps/curl/lib/vssh/curl_path.c b/deps/curl/lib/vssh/curl_path.c index 474a5ecb8e2..021e85faf8e 100644 --- a/deps/curl/lib/vssh/curl_path.c +++ b/deps/curl/lib/vssh/curl_path.c @@ -24,7 +24,7 @@ #include "../curl_setup.h" -#if defined(USE_SSH) +#ifdef USE_SSH #include "curl_path.h" #include diff --git a/deps/curl/lib/vssh/libssh.c b/deps/curl/lib/vssh/libssh.c index 3bae943c7ce..695532ff851 100644 --- a/deps/curl/lib/vssh/libssh.c +++ b/deps/curl/lib/vssh/libssh.c @@ -125,8 +125,8 @@ CURLcode sftp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done); -static int myssh_getsock(struct Curl_easy *data, - struct connectdata *conn, curl_socket_t *sock); +static CURLcode myssh_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static void myssh_block2waitfor(struct connectdata *conn, struct ssh_conn *sshc, bool block); @@ -148,10 +148,10 @@ const struct Curl_handler Curl_handler_scp = { myssh_connect, /* connect_it */ myssh_multi_statemach, /* connecting */ scp_doing, /* doing */ - myssh_getsock, /* proto_getsock */ - myssh_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - myssh_getsock, /* perform_getsock */ + myssh_pollset, /* proto_pollset */ + myssh_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + myssh_pollset, /* perform_pollset */ scp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -177,10 +177,10 @@ const struct Curl_handler Curl_handler_sftp = { myssh_connect, /* connect_it */ myssh_multi_statemach, /* connecting */ sftp_doing, /* doing */ - myssh_getsock, /* proto_getsock */ - myssh_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - myssh_getsock, /* perform_getsock */ + myssh_pollset, /* proto_pollset */ + myssh_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + myssh_pollset, /* perform_pollset */ sftp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -218,10 +218,10 @@ static CURLcode sftp_error_to_CURLE(int err) return CURLE_SSH; } -#ifndef DEBUGBUILD -#define myssh_to(x,y,z) myssh_set_state(x,y,z) -#else +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) #define myssh_to(x,y,z) myssh_set_state(x,y,z, __LINE__) +#else +#define myssh_to(x,y,z) myssh_set_state(x,y,z) #endif /* @@ -231,7 +231,7 @@ static CURLcode sftp_error_to_CURLE(int err) static void myssh_set_state(struct Curl_easy *data, struct ssh_conn *sshc, sshstate nowstate -#ifdef DEBUGBUILD +#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) , int lineno #endif ) @@ -1115,8 +1115,8 @@ static int myssh_in_AUTH_DONE(struct Curl_easy *data, /* At this point we have an authenticated ssh session. */ infof(data, "Authentication complete"); Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ - data->conn->sockfd = data->conn->sock[FIRSTSOCKET]; - data->conn->writesockfd = CURL_SOCKET_BAD; + data->conn->recv_idx = FIRSTSOCKET; + data->conn->send_idx = -1; if(data->conn->handler->protocol == CURLPROTO_SFTP) { myssh_to(data, sshc, SSH_SFTP_INIT); @@ -1251,10 +1251,10 @@ static int myssh_in_UPLOAD_INIT(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->sockfd = data->conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; /* store this original bitmask setup to use later on if we cannot figure out a "real" bitmask */ @@ -1423,10 +1423,10 @@ static int myssh_in_SFTP_DOWNLOAD_STAT(struct Curl_easy *data, myssh_to(data, sshc, SSH_STOP); return rc; } - Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, data->req.size); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->writesockfd = data->conn->sockfd; + data->conn->send_idx = 0; sshc->sftp_recv_state = 0; myssh_to(data, sshc, SSH_STOP); @@ -1468,10 +1468,8 @@ static int myssh_in_SFTP_SHUTDOWN(struct Curl_easy *data, before we proceed */ ssh_set_blocking(sshc->ssh_session, 0); #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) - if(sshc->sftp_aio) { - sftp_aio_free(sshc->sftp_aio); - sshc->sftp_aio = NULL; - } + SFTP_AIO_FREE(sshc->sftp_send_aio); + SFTP_AIO_FREE(sshc->sftp_recv_aio); #endif if(sshc->sftp_file) { @@ -1857,9 +1855,9 @@ static int myssh_in_SFTP_QUOTE_STAT(struct Curl_easy *data, } else if(!strncmp(cmd, "atime", 5) || !strncmp(cmd, "mtime", 5)) { - time_t date = Curl_getdate_capped(sshc->quote_path1); + time_t date; bool fail = FALSE; - if(date == -1) { + if(Curl_getdate_capped(sshc->quote_path1, &date)) { failf(data, "incorrect date format for %.*s", 5, cmd); fail = TRUE; } @@ -2242,10 +2240,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, } /* upload data */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->sockfd = conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; /* store this original bitmask setup to use later on if we cannot figure out a "real" bitmask */ @@ -2281,10 +2279,10 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, /* download data */ bytecount = ssh_scp_request_get_size(sshc->scp_session); data->req.maxdownload = (curl_off_t) bytecount; - Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, bytecount); /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->writesockfd = conn->sockfd; + conn->send_idx = 0; myssh_to(data, sshc, SSH_STOP); break; @@ -2392,25 +2390,19 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data, /* called by the multi interface to figure out what socket(s) to wait for and for what actions in the DO_DONE, PERFORM and WAITPERFORM states */ -static int myssh_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *sock) +static CURLcode myssh_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - int bitmap = GETSOCK_BLANK; - (void)data; - sock[0] = conn->sock[FIRSTSOCKET]; - - if(conn->waitfor & KEEP_RECV) - bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); - - if(conn->waitfor & KEEP_SEND) - bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); - - if(!conn->waitfor) - bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); - - DEBUGF(infof(data, "ssh_getsock -> %x", bitmap)); - return bitmap; + int flags = 0; + if(data->conn->waitfor & KEEP_RECV) + flags |= CURL_POLL_IN; + if(data->conn->waitfor & KEEP_SEND) + flags |= CURL_POLL_OUT; + if(!data->conn->waitfor) + flags |= CURL_POLL_OUT; + return flags ? + Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) : + CURLE_OK; } static void myssh_block2waitfor(struct connectdata *conn, @@ -2439,7 +2431,7 @@ static CURLcode myssh_multi_statemach(struct Curl_easy *data, struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); - bool block; /* we store the status and use that to provide a ssh_getsock() + bool block; /* we store the status and use that to provide a ssh_pollset() implementation */ CURLcode result; @@ -2487,8 +2479,8 @@ static CURLcode myssh_block_statemach(struct Curl_easy *data, if(block) { curl_socket_t fd_read = conn->sock[FIRSTSOCKET]; /* wait for the socket to become ready */ - (void) Curl_socket_check(fd_read, CURL_SOCKET_BAD, - CURL_SOCKET_BAD, left > 1000 ? 1000 : left); + (void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, + CURL_SOCKET_BAD, left > 1000 ? 1000 : left); } } @@ -2807,7 +2799,7 @@ static CURLcode scp_disconnect(struct Curl_easy *data, CURLcode result = CURLE_OK; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); - (void) dead_connection; + (void)dead_connection; if(sshc && sshc->ssh_session && sshp) { /* only if there is a session still around to use! */ @@ -2848,7 +2840,7 @@ static CURLcode scp_done(struct Curl_easy *data, CURLcode status, bool premature) { struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); - (void) premature; /* not used */ + (void)premature; if(!sshc) return CURLE_FAILED_INIT; @@ -2866,7 +2858,7 @@ static CURLcode scp_send(struct Curl_easy *data, int sockindex, struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); - (void) sockindex; /* we only support SCP on the fixed known primary socket */ + (void)sockindex; /* we only support SCP on the fixed known primary socket */ (void)eos; *pnwritten = 0; @@ -2899,7 +2891,7 @@ static CURLcode scp_recv(struct Curl_easy *data, int sockindex, struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); ssize_t nread; - (void) sockindex; /* we only support SCP on the fixed known primary socket */ + (void)sockindex; /* we only support SCP on the fixed known primary socket */ *pnread = 0; if(!sshc) @@ -2984,7 +2976,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); CURLcode result = CURLE_OK; - (void) dead_connection; + (void)dead_connection; DEBUGF(infof(data, "SSH DISCONNECT starts now")); @@ -3033,32 +3025,30 @@ static CURLcode sftp_send(struct Curl_easy *data, int sockindex, if(!sshc) return CURLE_FAILED_INIT; - /* limit the writes to the maximum specified in Section 3 of - * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02 - */ - if(len > 32768) - len = 32768; #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) switch(sshc->sftp_send_state) { case 0: sftp_file_set_nonblocking(sshc->sftp_file); if(sftp_aio_begin_write(sshc->sftp_file, mem, len, - &sshc->sftp_aio) == SSH_ERROR) { + &sshc->sftp_send_aio) == SSH_ERROR) { return CURLE_SEND_ERROR; } sshc->sftp_send_state = 1; FALLTHROUGH(); case 1: - nwrite = sftp_aio_wait_write(&sshc->sftp_aio); + nwrite = sftp_aio_wait_write(&sshc->sftp_send_aio); myssh_block2waitfor(conn, sshc, (nwrite == SSH_AGAIN) ? TRUE : FALSE); if(nwrite == SSH_AGAIN) return CURLE_AGAIN; else if(nwrite < 0) return CURLE_SEND_ERROR; - if(sshc->sftp_aio) { - sftp_aio_free(sshc->sftp_aio); - sshc->sftp_aio = NULL; - } + + /* + * sftp_aio_wait_write() would free sftp_send_aio and + * assign it NULL in all cases except when it returns + * SSH_AGAIN. + */ + sshc->sftp_send_state = 0; *pnwritten = (size_t)nwrite; return CURLE_OK; @@ -3067,6 +3057,17 @@ static CURLcode sftp_send(struct Curl_easy *data, int sockindex, return CURLE_SEND_ERROR; } #else + /* + * limit the writes to the maximum specified in Section 3 of + * https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-02 + * + * libssh started applying appropriate read/write length limits + * internally since version 0.11.0, hence such an operation is + * not needed for versions after (and including) 0.11.0. + */ + if(len > 32768) + len = 32768; + nwrite = sftp_write(sshc->sftp_file, mem, len); myssh_block2waitfor(conn, sshc, FALSE); @@ -3106,16 +3107,28 @@ static CURLcode sftp_recv(struct Curl_easy *data, int sockindex, switch(sshc->sftp_recv_state) { case 0: +#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) + if(sftp_aio_begin_read(sshc->sftp_file, len, + &sshc->sftp_recv_aio) == SSH_ERROR) { + return CURLE_RECV_ERROR; + } +#else sshc->sftp_file_index = sftp_async_read_begin(sshc->sftp_file, (uint32_t)len); if(sshc->sftp_file_index < 0) return CURLE_RECV_ERROR; +#endif FALLTHROUGH(); case 1: sshc->sftp_recv_state = 1; + +#if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) + nread = sftp_aio_wait_read(&sshc->sftp_recv_aio, mem, len); +#else nread = sftp_async_read(sshc->sftp_file, mem, (uint32_t)len, (uint32_t)sshc->sftp_file_index); +#endif myssh_block2waitfor(conn, sshc, (nread == SSH_AGAIN)); @@ -3124,6 +3137,12 @@ static CURLcode sftp_recv(struct Curl_easy *data, int sockindex, else if(nread < 0) return CURLE_RECV_ERROR; + /* + * sftp_aio_wait_read() would free sftp_recv_aio and + * assign it NULL in all cases except when it returns + * SSH_AGAIN. + */ + sshc->sftp_recv_state = 0; *pnread = (size_t)nread; return CURLE_OK; diff --git a/deps/curl/lib/vssh/libssh2.c b/deps/curl/lib/vssh/libssh2.c index d599d3cc509..5dfc377ec14 100644 --- a/deps/curl/lib/vssh/libssh2.c +++ b/deps/curl/lib/vssh/libssh2.c @@ -99,8 +99,8 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead); static CURLcode sftp_perform(struct Curl_easy *data, bool *connected, bool *dophase_done); -static int ssh_getsock(struct Curl_easy *data, struct connectdata *conn, - curl_socket_t *sock); +static CURLcode ssh_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode ssh_setup_connection(struct Curl_easy *data, struct connectdata *conn); static void ssh_attach(struct Curl_easy *data, struct connectdata *conn); @@ -119,10 +119,10 @@ const struct Curl_handler Curl_handler_scp = { ssh_connect, /* connect_it */ ssh_multi_statemach, /* connecting */ scp_doing, /* doing */ - ssh_getsock, /* proto_getsock */ - ssh_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ssh_getsock, /* perform_getsock */ + ssh_pollset, /* proto_pollset */ + ssh_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ssh_pollset, /* perform_pollset */ scp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -150,10 +150,10 @@ const struct Curl_handler Curl_handler_sftp = { ssh_connect, /* connect_it */ ssh_multi_statemach, /* connecting */ sftp_doing, /* doing */ - ssh_getsock, /* proto_getsock */ - ssh_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ssh_getsock, /* perform_getsock */ + ssh_pollset, /* proto_pollset */ + ssh_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ssh_pollset, /* perform_pollset */ sftp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -276,19 +276,19 @@ static CURLcode libssh2_session_error_to_CURLE(int err) static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc) { - (void)abstract; /* arg not used */ + (void)abstract; return Curl_cmalloc(count); } static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc) { - (void)abstract; /* arg not used */ + (void)abstract; return Curl_crealloc(ptr, count); } static LIBSSH2_FREE_FUNC(my_libssh2_free) { - (void)abstract; /* arg not used */ + (void)abstract; if(ptr) /* ssh2 agent sometimes call free with null ptr */ Curl_cfree(ptr); } @@ -1199,10 +1199,10 @@ sftp_upload_init(struct Curl_easy *data, Curl_pgrsSetUploadSize(data, data->state.infilesize); } /* upload data */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->sockfd = data->conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; /* store this original bitmask setup to use later on if we cannot figure out a "real" bitmask */ @@ -1390,16 +1390,16 @@ sftp_quote_stat(struct Curl_easy *data, } else if(!strncmp(cmd, "atime", 5) || !strncmp(cmd, "mtime", 5)) { - time_t date = Curl_getdate_capped(sshc->quote_path1); + time_t date; bool fail = FALSE; - if(date == -1) { + if(Curl_getdate_capped(sshc->quote_path1, &date)) { failf(data, "incorrect date format for %.*s", 5, cmd); fail = TRUE; } #if SIZEOF_TIME_T > SIZEOF_LONG if(date > 0xffffffff) { - /* if 'long' cannot old >32-bit, this date cannot be sent */ + /* if 'long' cannot hold >32-bit, this date cannot be sent */ failf(data, "date overflow"); fail = TRUE; } @@ -1540,10 +1540,10 @@ sftp_download_stat(struct Curl_easy *data, myssh_state(data, sshc, SSH_STOP); return CURLE_OK; } - Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, data->req.size); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->writesockfd = data->conn->sockfd; + data->conn->send_idx = 0; myssh_state(data, sshc, SSH_STOP); @@ -1945,8 +1945,8 @@ static CURLcode ssh_state_auth_done(struct Curl_easy *data, Curl_pgrsTime(data, TIMER_APPCONNECT); /* SSH is connected */ - conn->sockfd = conn->sock[FIRSTSOCKET]; - conn->writesockfd = CURL_SOCKET_BAD; + data->conn->recv_idx = FIRSTSOCKET; + conn->send_idx = -1; if(conn->handler->protocol == CURLPROTO_SFTP) { myssh_state(data, sshc, SSH_SFTP_INIT); @@ -2460,10 +2460,10 @@ static CURLcode ssh_state_scp_download_init(struct Curl_easy *data, /* download data */ bytecount = (curl_off_t)sb.st_size; data->req.maxdownload = (curl_off_t)sb.st_size; - Curl_xfer_setup1(data, CURL_XFER_RECV, bytecount, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, bytecount); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->writesockfd = data->conn->sockfd; + data->conn->send_idx = 0; myssh_state(data, sshc, SSH_STOP); return CURLE_OK; @@ -2609,10 +2609,10 @@ static CURLcode ssh_state_scp_upload_init(struct Curl_easy *data, /* upload data */ data->req.size = data->state.infilesize; Curl_pgrsSetUploadSize(data, data->state.infilesize); - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); + Curl_xfer_setup_send(data, FIRSTSOCKET); /* not set by Curl_xfer_setup to preserve keepon bits */ - data->conn->sockfd = data->conn->writesockfd; + data->conn->recv_idx = FIRSTSOCKET; /* store this original bitmask setup to use later on if we cannot figure out a "real" bitmask */ @@ -3073,7 +3073,7 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, break; } - } while(!result && (sshc->state != SSH_STOP)); + } while(!result && (sshc->state != SSH_STOP) && !*block); if(result == CURLE_AGAIN) { /* we would block, we need to wait for the socket to be ready (in the @@ -3087,22 +3087,17 @@ static CURLcode ssh_statemachine(struct Curl_easy *data, /* called by the multi interface to figure out what socket(s) to wait for and for what actions in the DO_DONE, PERFORM and WAITPERFORM states */ -static int ssh_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *sock) +static CURLcode ssh_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - int bitmap = GETSOCK_BLANK; - (void)data; - - sock[0] = conn->sock[FIRSTSOCKET]; - - if(conn->waitfor & KEEP_RECV) - bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); - - if(conn->waitfor & KEEP_SEND) - bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); - - return bitmap; + int flags = 0; + if(data->conn->waitfor & KEEP_RECV) + flags |= CURL_POLL_IN; + if(data->conn->waitfor & KEEP_SEND) + flags |= CURL_POLL_OUT; + return flags ? + Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) : + CURLE_OK; } /* @@ -3139,7 +3134,7 @@ static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done) struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); CURLcode result = CURLE_OK; - bool block; /* we store the status and use that to provide a ssh_getsock() + bool block; /* we store the status and use that to provide a ssh_pollset() implementation */ if(!sshc || !sshp) return CURLE_FAILED_INIT; @@ -3695,7 +3690,7 @@ static CURLcode scp_disconnect(struct Curl_easy *data, CURLcode result = CURLE_OK; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); - (void) dead_connection; + (void)dead_connection; if(sshc && sshc->ssh_session && sshp) { /* only if there is a session still around to use! */ @@ -3737,7 +3732,7 @@ static CURLcode scp_done(struct Curl_easy *data, CURLcode status, bool premature) { struct ssh_conn *sshc = Curl_conn_meta_get(data->conn, CURL_META_SSH_CONN); - (void)premature; /* not used */ + (void)premature; if(sshc && !status) myssh_state(data, sshc, SSH_SCP_DONE); @@ -3867,7 +3862,7 @@ static CURLcode sftp_disconnect(struct Curl_easy *data, CURLcode result = CURLE_OK; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY); - (void) dead_connection; + (void)dead_connection; DEBUGF(infof(data, "SSH DISCONNECT starts now")); diff --git a/deps/curl/lib/vssh/ssh.h b/deps/curl/lib/vssh/ssh.h index 4056c39b200..75b31bd931f 100644 --- a/deps/curl/lib/vssh/ssh.h +++ b/deps/curl/lib/vssh/ssh.h @@ -26,7 +26,7 @@ #include "../curl_setup.h" -#if defined(USE_LIBSSH2) +#ifdef USE_LIBSSH2 #include #include #elif defined(USE_LIBSSH) @@ -162,7 +162,7 @@ struct ssh_conn { int orig_waitfor; /* default READ/WRITE bits wait for */ char *slash_pos; /* used by the SFTP_CREATE_DIRS state */ -#if defined(USE_LIBSSH) +#ifdef USE_LIBSSH CURLcode actualcode; /* the actual error code */ char *readdir_linkPath; size_t readdir_len; @@ -180,10 +180,13 @@ struct ssh_conn { unsigned sftp_recv_state; /* 0 or 1 */ #if LIBSSH_VERSION_INT > SSH_VERSION_INT(0, 11, 0) - sftp_aio sftp_aio; + sftp_aio sftp_recv_aio; + + sftp_aio sftp_send_aio; unsigned sftp_send_state; /* 0 or 1 */ -#endif +#else int sftp_file_index; /* for async read */ +#endif sftp_attributes readdir_attrs; /* used by the SFTP readdir actions */ sftp_attributes readdir_link_attrs; /* used by the SFTP readdir actions */ sftp_attributes quote_attrs; /* used by the SFTP_QUOTE state */ @@ -228,7 +231,7 @@ struct ssh_conn { #endif #endif -#if defined(USE_LIBSSH2) +#ifdef USE_LIBSSH2 /* Feature detection based on version numbers to better work with non-configure platforms */ diff --git a/deps/curl/lib/vssh/wolfssh.c b/deps/curl/lib/vssh/wolfssh.c index eed73fd9192..7cd0402a99d 100644 --- a/deps/curl/lib/vssh/wolfssh.c +++ b/deps/curl/lib/vssh/wolfssh.c @@ -66,9 +66,8 @@ static CURLcode wsftp_doing(struct Curl_easy *data, static CURLcode wsftp_disconnect(struct Curl_easy *data, struct connectdata *conn, bool dead); -static int wssh_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *sock); +static CURLcode wssh_pollset(struct Curl_easy *data, + struct easy_pollset *ps); static CURLcode wssh_setup_connection(struct Curl_easy *data, struct connectdata *conn); static void wssh_sshc_cleanup(struct ssh_conn *sshc); @@ -87,10 +86,10 @@ const struct Curl_handler Curl_handler_scp = { wssh_connect, /* connect_it */ wssh_multi_statemach, /* connecting */ wscp_doing, /* doing */ - wssh_getsock, /* proto_getsock */ - wssh_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - wssh_getsock, /* perform_getsock */ + wssh_pollset, /* proto_pollset */ + wssh_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + wssh_pollset, /* perform_pollset */ wscp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -118,10 +117,10 @@ const struct Curl_handler Curl_handler_sftp = { wssh_connect, /* connect_it */ wssh_multi_statemach, /* connecting */ wsftp_doing, /* doing */ - wssh_getsock, /* proto_getsock */ - wssh_getsock, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - wssh_getsock, /* perform_getsock */ + wssh_pollset, /* proto_pollset */ + wssh_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + wssh_pollset, /* perform_pollset */ wsftp_disconnect, /* disconnect */ ZERO_NULL, /* write_resp */ ZERO_NULL, /* write_resp_hd */ @@ -464,6 +463,150 @@ static CURLcode wssh_connect(struct Curl_easy *data, bool *done) return CURLE_FAILED_INIT; } +static CURLcode wssh_sftp_upload_init(struct Curl_easy *data, + struct ssh_conn *sshc, + struct SSHPROTO *sftp_scp, + bool *block) +{ + word32 flags; + WS_SFTP_FILEATRB createattrs; + struct connectdata *conn = data->conn; + int rc; + if(data->state.resume_from) { + WS_SFTP_FILEATRB attrs; + if(data->state.resume_from < 0) { + rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, + &attrs); + if(rc != WS_SUCCESS) + return CURLE_SSH; + + if(rc) { + data->state.resume_from = 0; + } + else { + curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; + if(size < 0) { + failf(data, "Bad file size (%" FMT_OFF_T ")", size); + return CURLE_BAD_DOWNLOAD_RESUME; + } + data->state.resume_from = size; + } + } + } + + if(data->set.remote_append) + /* Try to open for append, but create if nonexisting */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND; + else if(data->state.resume_from > 0) + /* If we have restart position then open for append */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND; + else + /* Clear file before writing (normal behavior) */ + flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC; + + memset(&createattrs, 0, sizeof(createattrs)); + createattrs.per = (word32)data->set.new_file_perms; + sshc->handleSz = sizeof(sshc->handle); + rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, + flags, &createattrs, + sshc->handle, &sshc->handleSz); + if(rc == WS_FATAL_ERROR) + rc = wolfSSH_get_error(sshc->ssh_session); + if(rc == WS_WANT_READ) { + *block = TRUE; + conn->waitfor = KEEP_RECV; + return CURLE_OK; + } + else if(rc == WS_WANT_WRITE) { + *block = TRUE; + conn->waitfor = KEEP_SEND; + return CURLE_OK; + } + else if(rc == WS_SUCCESS) { + infof(data, "wolfssh SFTP open succeeded"); + } + else { + failf(data, "wolfssh SFTP upload open failed: %d", rc); + return CURLE_SSH; + } + wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); + + /* If we have a restart point then we need to seek to the correct + position. */ + if(data->state.resume_from > 0) { + /* Let's read off the proper amount of bytes from the input. */ + int seekerr = CURL_SEEKFUNC_OK; + if(data->set.seek_func) { + Curl_set_in_callback(data, TRUE); + seekerr = data->set.seek_func(data->set.seek_client, + data->state.resume_from, SEEK_SET); + Curl_set_in_callback(data, FALSE); + } + + if(seekerr != CURL_SEEKFUNC_OK) { + curl_off_t passed = 0; + + if(seekerr != CURL_SEEKFUNC_CANTSEEK) { + failf(data, "Could not seek stream"); + return CURLE_FTP_COULDNT_USE_REST; + } + /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */ + do { + char scratch[4*1024]; + size_t readthisamountnow = + (data->state.resume_from - passed > + (curl_off_t)sizeof(scratch)) ? + sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); + + size_t actuallyread; + Curl_set_in_callback(data, TRUE); + actuallyread = data->state.fread_func(scratch, 1, + readthisamountnow, + data->state.in); + Curl_set_in_callback(data, FALSE); + + passed += actuallyread; + if((actuallyread == 0) || (actuallyread > readthisamountnow)) { + /* this checks for greater-than only to make sure that the + CURL_READFUNC_ABORT return code still aborts */ + failf(data, "Failed to read data"); + return CURLE_FTP_COULDNT_USE_REST; + } + } while(passed < data->state.resume_from); + } + + /* now, decrease the size of the read */ + if(data->state.infilesize > 0) { + data->state.infilesize -= data->state.resume_from; + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + + sshc->offset += data->state.resume_from; + } + if(data->state.infilesize > 0) { + data->req.size = data->state.infilesize; + Curl_pgrsSetUploadSize(data, data->state.infilesize); + } + /* upload data */ + Curl_xfer_setup_send(data, FIRSTSOCKET); + + /* not set by Curl_xfer_setup to preserve keepon bits */ + data->conn->recv_idx = FIRSTSOCKET; + + /* store this original bitmask setup to use later on if we cannot + figure out a "real" bitmask */ + sshc->orig_waitfor = data->req.keepon; + + /* since we do not really wait for anything at this point, we want the state + machine to move on as soon as possible */ + Curl_multi_mark_dirty(data); + + wssh_state(data, sshc, SSH_STOP); + + return CURLE_OK; +} + /* * wssh_statemach_act() runs the SSH state machine as far as it can without * blocking and without reaching the end. The data the pointer 'block' points @@ -598,148 +741,10 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_INIT); } break; - case SSH_SFTP_UPLOAD_INIT: { - word32 flags; - WS_SFTP_FILEATRB createattrs; - if(data->state.resume_from) { - WS_SFTP_FILEATRB attrs; - if(data->state.resume_from < 0) { - rc = wolfSSH_SFTP_STAT(sshc->ssh_session, sftp_scp->path, - &attrs); - if(rc != WS_SUCCESS) - break; - - if(rc) { - data->state.resume_from = 0; - } - else { - curl_off_t size = ((curl_off_t)attrs.sz[1] << 32) | attrs.sz[0]; - if(size < 0) { - failf(data, "Bad file size (%" FMT_OFF_T ")", size); - return CURLE_BAD_DOWNLOAD_RESUME; - } - data->state.resume_from = size; - } - } - } - - if(data->set.remote_append) - /* Try to open for append, but create if nonexisting */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_APPEND; - else if(data->state.resume_from > 0) - /* If we have restart position then open for append */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_APPEND; - else - /* Clear file before writing (normal behavior) */ - flags = WOLFSSH_FXF_WRITE|WOLFSSH_FXF_CREAT|WOLFSSH_FXF_TRUNC; - - memset(&createattrs, 0, sizeof(createattrs)); - createattrs.per = (word32)data->set.new_file_perms; - sshc->handleSz = sizeof(sshc->handle); - rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, - flags, &createattrs, - sshc->handle, &sshc->handleSz); - if(rc == WS_FATAL_ERROR) - rc = wolfSSH_get_error(sshc->ssh_session); - if(rc == WS_WANT_READ) { - *block = TRUE; - conn->waitfor = KEEP_RECV; - return CURLE_OK; - } - else if(rc == WS_WANT_WRITE) { - *block = TRUE; - conn->waitfor = KEEP_SEND; - return CURLE_OK; - } - else if(rc == WS_SUCCESS) { - infof(data, "wolfssh SFTP open succeeded"); - } - else { - failf(data, "wolfssh SFTP upload open failed: %d", rc); - return CURLE_SSH; - } - wssh_state(data, sshc, SSH_SFTP_DOWNLOAD_STAT); - - /* If we have a restart point then we need to seek to the correct - position. */ - if(data->state.resume_from > 0) { - /* Let's read off the proper amount of bytes from the input. */ - int seekerr = CURL_SEEKFUNC_OK; - if(data->set.seek_func) { - Curl_set_in_callback(data, TRUE); - seekerr = data->set.seek_func(data->set.seek_client, - data->state.resume_from, SEEK_SET); - Curl_set_in_callback(data, FALSE); - } - - if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed = 0; - - if(seekerr != CURL_SEEKFUNC_CANTSEEK) { - failf(data, "Could not seek stream"); - return CURLE_FTP_COULDNT_USE_REST; - } - /* seekerr == CURL_SEEKFUNC_CANTSEEK (cannot seek to offset) */ - do { - char scratch[4*1024]; - size_t readthisamountnow = - (data->state.resume_from - passed > - (curl_off_t)sizeof(scratch)) ? - sizeof(scratch) : curlx_sotouz(data->state.resume_from - passed); - - size_t actuallyread; - Curl_set_in_callback(data, TRUE); - actuallyread = data->state.fread_func(scratch, 1, - readthisamountnow, - data->state.in); - Curl_set_in_callback(data, FALSE); - - passed += actuallyread; - if((actuallyread == 0) || (actuallyread > readthisamountnow)) { - /* this checks for greater-than only to make sure that the - CURL_READFUNC_ABORT return code still aborts */ - failf(data, "Failed to read data"); - return CURLE_FTP_COULDNT_USE_REST; - } - } while(passed < data->state.resume_from); - } - - /* now, decrease the size of the read */ - if(data->state.infilesize > 0) { - data->state.infilesize -= data->state.resume_from; - data->req.size = data->state.infilesize; - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - - sshc->offset += data->state.resume_from; - } - if(data->state.infilesize > 0) { - data->req.size = data->state.infilesize; - Curl_pgrsSetUploadSize(data, data->state.infilesize); - } - /* upload data */ - Curl_xfer_setup1(data, CURL_XFER_SEND, -1, FALSE); - - /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->sockfd = conn->writesockfd; - - if(result) { - wssh_state(data, sshc, SSH_SFTP_CLOSE); - sshc->actualcode = result; - } - else { - /* store this original bitmask setup to use later on if we cannot - figure out a "real" bitmask */ - sshc->orig_waitfor = data->req.keepon; - - /* since we do not really wait for anything at this point, we want the - state machine to move on as soon as possible */ - Curl_multi_mark_dirty(data); - - wssh_state(data, sshc, SSH_STOP); - } + case SSH_SFTP_UPLOAD_INIT: + result = wssh_sftp_upload_init(data, sshc, sftp_scp, block); break; - } + case SSH_SFTP_DOWNLOAD_INIT: sshc->handleSz = sizeof(sshc->handle); rc = wolfSSH_SFTP_Open(sshc->ssh_session, sftp_scp->path, @@ -817,10 +822,10 @@ static CURLcode wssh_statemach_act(struct Curl_easy *data, wssh_state(data, sshc, SSH_STOP); break; } - Curl_xfer_setup1(data, CURL_XFER_RECV, data->req.size, FALSE); + Curl_xfer_setup_recv(data, FIRSTSOCKET, data->req.size); /* not set by Curl_xfer_setup to preserve keepon bits */ - conn->writesockfd = conn->sockfd; + conn->send_idx = 0; if(result) { /* this should never occur; the close state should be entered @@ -932,7 +937,7 @@ static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done) struct connectdata *conn = data->conn; struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN); CURLcode result = CURLE_OK; - bool block; /* we store the status and use that to provide a ssh_getsock() + bool block; /* we store the status and use that to provide a ssh_pollset() implementation */ if(!sshc) return CURLE_FAILED_INIT; @@ -1185,21 +1190,17 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data, return result; } -static int wssh_getsock(struct Curl_easy *data, - struct connectdata *conn, - curl_socket_t *sock) +static CURLcode wssh_pollset(struct Curl_easy *data, + struct easy_pollset *ps) { - int bitmap = GETSOCK_BLANK; - int dir = conn->waitfor; - (void)data; - sock[0] = conn->sock[FIRSTSOCKET]; - - if(dir == KEEP_RECV) - bitmap |= GETSOCK_READSOCK(FIRSTSOCKET); - else if(dir == KEEP_SEND) - bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET); - - return bitmap; + int flags = 0; + if(data->conn->waitfor & KEEP_RECV) + flags |= CURL_POLL_IN; + if(data->conn->waitfor & KEEP_SEND) + flags |= CURL_POLL_OUT; + return flags ? + Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) : + CURLE_OK; } void Curl_ssh_version(char *buffer, size_t buflen) diff --git a/deps/curl/lib/vtls/cipher_suite.c b/deps/curl/lib/vtls/cipher_suite.c index cefc92c580b..4bf60c1a4ab 100644 --- a/deps/curl/lib/vtls/cipher_suite.c +++ b/deps/curl/lib/vtls/cipher_suite.c @@ -70,7 +70,7 @@ static const char *cs_txt = "ECDH" "\0" "ECDHE" "\0" "ECDSA" "\0" - "EDE" "\0" + "EDE" "\0" /* spellchecker:disable-line */ "GCM" "\0" "MD5" "\0" "NULL" "\0" @@ -80,7 +80,7 @@ static const char *cs_txt = "SHA" "\0" "SHA256" "\0" "SHA384" "\0" -#if defined(USE_MBEDTLS) +#ifdef USE_MBEDTLS "ARIA" "\0" "ARIA128" "\0" "ARIA256" "\0" @@ -111,7 +111,7 @@ enum { CS_TXT_IDX_ECDH, CS_TXT_IDX_ECDHE, CS_TXT_IDX_ECDSA, - CS_TXT_IDX_EDE, + CS_TXT_IDX_EDE, /* spellchecker:disable-line */ CS_TXT_IDX_GCM, CS_TXT_IDX_MD5, CS_TXT_IDX_NULL, @@ -121,7 +121,7 @@ enum { CS_TXT_IDX_SHA, CS_TXT_IDX_SHA256, CS_TXT_IDX_SHA384, -#if defined(USE_MBEDTLS) +#ifdef USE_MBEDTLS CS_TXT_IDX_ARIA, CS_TXT_IDX_ARIA128, CS_TXT_IDX_ARIA256, @@ -180,7 +180,7 @@ static const struct cs_entry cs_list [] = { CS_ENTRY(0xCCA8, ECDHE,RSA,CHACHA20,POLY1305,,,,), CS_ENTRY(0xCCA9, TLS,ECDHE,ECDSA,WITH,CHACHA20,POLY1305,SHA256,), CS_ENTRY(0xCCA9, ECDHE,ECDSA,CHACHA20,POLY1305,,,,), -#if defined(USE_MBEDTLS) +#ifdef USE_MBEDTLS CS_ENTRY(0x002F, TLS,RSA,WITH,AES,128,CBC,SHA,), CS_ENTRY(0x002F, AES128,SHA,,,,,,), CS_ENTRY(0x0035, TLS,RSA,WITH,AES,256,CBC,SHA,), @@ -234,7 +234,7 @@ static const struct cs_entry cs_list [] = { CS_ENTRY(0xC032, TLS,ECDH,RSA,WITH,AES,256,GCM,SHA384), CS_ENTRY(0xC032, ECDH,RSA,AES256,GCM,SHA384,,,), #endif -#if defined(USE_MBEDTLS) +#ifdef USE_MBEDTLS CS_ENTRY(0x0001, TLS,RSA,WITH,NULL,MD5,,,), CS_ENTRY(0x0001, NULL,MD5,,,,,,), CS_ENTRY(0x0002, TLS,RSA,WITH,NULL,SHA,,,), @@ -322,7 +322,7 @@ static const struct cs_entry cs_list [] = { CS_ENTRY(0xCCAB, TLS,PSK,WITH,CHACHA20,POLY1305,SHA256,,), CS_ENTRY(0xCCAB, PSK,CHACHA20,POLY1305,,,,,), #endif -#if defined(USE_MBEDTLS) +#ifdef USE_MBEDTLS CS_ENTRY(0xC09C, TLS,RSA,WITH,AES,128,CCM,,), CS_ENTRY(0xC09C, AES128,CCM,,,,,,), CS_ENTRY(0xC09D, TLS,RSA,WITH,AES,256,CCM,,), @@ -340,7 +340,7 @@ static const struct cs_entry cs_list [] = { CS_ENTRY(0xC0AF, TLS,ECDHE,ECDSA,WITH,AES,256,CCM,8), CS_ENTRY(0xC0AF, ECDHE,ECDSA,AES256,CCM8,,,,), #endif -#if defined(USE_MBEDTLS) +#ifdef USE_MBEDTLS /* entries marked ns are "non-standard", they are not in OpenSSL */ CS_ENTRY(0x0041, TLS,RSA,WITH,CAMELLIA,128,CBC,SHA,), CS_ENTRY(0x0041, CAMELLIA128,SHA,,,,,,), diff --git a/deps/curl/lib/vtls/gtls.c b/deps/curl/lib/vtls/gtls.c index f5e02975a04..f38c90e66c3 100644 --- a/deps/curl/lib/vtls/gtls.c +++ b/deps/curl/lib/vtls/gtls.c @@ -77,7 +77,12 @@ static bool gtls_inited = FALSE; #error "too old GnuTLS version" #endif -# include +#undef CURL_GNUTLS_EARLY_DATA +#if GNUTLS_VERSION_NUMBER >= 0x03060d +#define CURL_GNUTLS_EARLY_DATA +#endif + +#include struct gtls_ssl_backend_data { struct gtls_ctx gtls; @@ -334,12 +339,13 @@ gnutls_set_ssl_version_min_max(struct Curl_easy *data, if((ssl_version == CURL_SSLVERSION_DEFAULT) || (ssl_version == CURL_SSLVERSION_TLSv1)) ssl_version = CURL_SSLVERSION_TLSv1_0; - if(ssl_version_max == CURL_SSLVERSION_MAX_NONE) - ssl_version_max = CURL_SSLVERSION_MAX_DEFAULT; + if((ssl_version_max == CURL_SSLVERSION_MAX_NONE) || + (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) + ssl_version_max = tls13support ? + CURL_SSLVERSION_MAX_TLSv1_3 : CURL_SSLVERSION_MAX_TLSv1_2; if(peer->transport == TRNSPRT_QUIC) { - if((ssl_version_max != CURL_SSLVERSION_MAX_DEFAULT) && - (ssl_version_max < CURL_SSLVERSION_MAX_TLSv1_3)) { + if(ssl_version_max < CURL_SSLVERSION_MAX_TLSv1_3) { failf(data, "QUIC needs at least TLS version 1.3"); return CURLE_SSL_CONNECT_ERROR; } @@ -347,19 +353,6 @@ gnutls_set_ssl_version_min_max(struct Curl_easy *data, return CURLE_OK; } - if(!tls13support) { - /* If the running GnuTLS does not support TLS 1.3, we must not specify a - prioritylist involving that since it will make GnuTLS return an en - error back at us */ - if((ssl_version_max == CURL_SSLVERSION_MAX_TLSv1_3) || - (ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT)) { - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2; - } - } - else if(ssl_version_max == CURL_SSLVERSION_MAX_DEFAULT) { - ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_3; - } - switch(ssl_version | ssl_version_max) { case CURL_SSLVERSION_TLSv1_0 | CURL_SSLVERSION_MAX_TLSv1_0: *prioritylist = GNUTLS_CIPHERS ":-VERS-SSL3.0:-VERS-TLS-ALL:" @@ -433,7 +426,7 @@ CURLcode Curl_gtls_shared_creds_create(struct Curl_easy *data, CURLcode Curl_gtls_shared_creds_up_ref(struct gtls_shared_creds *creds) { DEBUGASSERT(creds); - if(creds->refcount < SIZE_T_MAX) { + if(creds->refcount < SIZE_MAX) { ++creds->refcount; return CURLE_OK; } @@ -667,6 +660,7 @@ CURLcode Curl_gtls_client_trust_setup(struct Curl_cfilter *cf, return CURLE_OK; } +#ifdef CURL_GNUTLS_EARLY_DATA CURLcode Curl_gtls_cache_session(struct Curl_cfilter *cf, struct Curl_easy *data, const char *ssl_peer_key, @@ -727,6 +721,7 @@ CURLcode Curl_gtls_cache_session(struct Curl_cfilter *cf, } return result; } +#endif int Curl_glts_get_ietf_proto(gnutls_session_t session) { @@ -739,13 +734,16 @@ int Curl_glts_get_ietf_proto(gnutls_session_t session) return CURL_IETF_PROTO_TLS1_1; case GNUTLS_TLS1_2: return CURL_IETF_PROTO_TLS1_2; +#if GNUTLS_VERSION_NUMBER >= 0x030603 case GNUTLS_TLS1_3: return CURL_IETF_PROTO_TLS1_3; +#endif default: return CURL_IETF_PROTO_UNKNOWN; } } +#ifdef CURL_GNUTLS_EARLY_DATA static CURLcode cf_gtls_update_session_id(struct Curl_cfilter *cf, struct Curl_easy *data, gnutls_session_t session) @@ -781,6 +779,7 @@ static int gtls_handshake_cb(gnutls_session_t session, unsigned int htype, } return 0; } +#endif static CURLcode gtls_set_priority(struct Curl_cfilter *cf, struct Curl_easy *data, @@ -895,6 +894,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf, /* Initialize TLS session as a client */ init_flags = GNUTLS_CLIENT; +#ifdef CURL_GNUTLS_EARLY_DATA if(peer->transport == TRNSPRT_QUIC && earlydata_max > 0) init_flags |= GNUTLS_ENABLE_EARLY_DATA | GNUTLS_NO_END_OF_EARLY_DATA; else if(earlydata_max > 0 && earlydata_max != 0xFFFFFFFFUL) @@ -903,21 +903,17 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf, * and one announcing 0xFFFFFFFFUL. On TCP+TLS, this is unlikely, but * on QUIC this is common. */ init_flags |= GNUTLS_ENABLE_EARLY_DATA; +#endif -#if defined(GNUTLS_FORCE_CLIENT_CERT) +#ifdef GNUTLS_FORCE_CLIENT_CERT init_flags |= GNUTLS_FORCE_CLIENT_CERT; #endif -#if defined(GNUTLS_NO_TICKETS_TLS12) - init_flags |= GNUTLS_NO_TICKETS_TLS12; -#elif defined(GNUTLS_NO_TICKETS) - /* Disable TLS session tickets for non 1.3 connections */ - if((config->version != CURL_SSLVERSION_TLSv1_3) && - (config->version != CURL_SSLVERSION_DEFAULT)) - init_flags |= GNUTLS_NO_TICKETS; +#ifdef GNUTLS_NO_TICKETS_TLS12 + init_flags |= GNUTLS_NO_TICKETS_TLS12; #endif -#if defined(GNUTLS_NO_STATUS_REQUEST) +#ifdef GNUTLS_NO_STATUS_REQUEST if(!config->verifystatus) /* Disable the "status_request" TLS extension, enabled by default since GnuTLS 3.8.0. */ @@ -1049,6 +1045,7 @@ static CURLcode gtls_client_init(struct Curl_cfilter *cf, return CURLE_OK; } +#ifdef CURL_GNUTLS_EARLY_DATA static int keylog_callback(gnutls_session_t session, const char *label, const gnutls_datum_t *secret) { @@ -1097,6 +1094,7 @@ static CURLcode gtls_on_session_reuse(struct Curl_cfilter *cf, } return result; } +#endif CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, struct Curl_cfilter *cf, @@ -1144,9 +1142,7 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, else { infof(data, "SSL reusing session with ALPN '%s'", scs->alpn ? scs->alpn : "-"); - if(ssl_config->earlydata && scs->alpn && - !cf->conn->connect_only && - (gnutls_protocol_get_version(gctx->session) == GNUTLS_TLS1_3)) { + if(ssl_config->earlydata && scs->alpn && !cf->conn->connect_only) { bool do_early_data = FALSE; if(sess_reuse_cb) { result = sess_reuse_cb(cf, data, &alpns, scs, &do_early_data); @@ -1177,11 +1173,13 @@ CURLcode Curl_gtls_ctx_init(struct gtls_ctx *gctx, goto out; } +#ifdef CURL_GNUTLS_EARLY_DATA /* Open the file if a TLS or QUIC backend has not done this before. */ Curl_tls_keylog_open(); if(Curl_tls_keylog_enabled()) { gnutls_session_set_keylog_function(gctx->session, keylog_callback); } +#endif /* convert the ALPN string from our arguments to a list of strings that * gnutls wants and will convert internally back to this string for sending @@ -1226,7 +1224,13 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) result = Curl_gtls_ctx_init(&backend->gtls, cf, data, &connssl->peer, connssl->alpn, NULL, NULL, cf, - gtls_on_session_reuse); +#ifdef CURL_GNUTLS_EARLY_DATA + gtls_on_session_reuse +#else + NULL +#endif + ); + if(result) return result; @@ -1237,9 +1241,11 @@ gtls_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) infof(data, VTLS_INFOF_ALPN_OFFER_1STR, proto.data); } +#ifdef CURL_GNUTLS_EARLY_DATA gnutls_handshake_set_hook_function(backend->gtls.session, GNUTLS_HANDSHAKE_ANY, GNUTLS_HOOK_POST, gtls_handshake_cb); +#endif /* register callback functions and handle to send and receive data. */ gnutls_transport_set_ptr(backend->gtls.session, cf); @@ -1329,6 +1335,190 @@ void Curl_gtls_report_handshake(struct Curl_easy *data, #endif } +static void gtls_msg_verify_result(struct Curl_easy *data, + struct ssl_peer *peer, + gnutls_x509_crt_t x509_cert, + bool was_verified, + bool needs_verified) +{ + char certname[65] = ""; /* limited to 64 chars by ASN.1 */ + size_t size = sizeof(certname); + int rc; + + rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, + 0, /* the first and only one */ + FALSE, certname, &size); + if(rc) { + infof(data, "error fetching CN from cert:%s", gnutls_strerror(rc)); + certname[0] = 0; + } + + if(!was_verified) { + if(needs_verified) { + failf(data, "SSL: certificate subject name (%s) does not match " + "target hostname '%s'", certname, peer->dispname); + } + else + infof(data, " common name: %s (does not match '%s')", + certname, peer->dispname); + } + else + infof(data, " common name: %s (matched)", certname); +} + +static void gtls_infof_cert(struct Curl_easy *data, + gnutls_x509_crt_t x509_cert) +{ +#ifndef CURL_DISABLE_VERBOSE_STRINGS + if(Curl_trc_is_verbose(data)) { + gnutls_datum_t certfields; + int rc, algo; + time_t tstamp; + unsigned int bits; + + /* public key algorithm's parameters */ + algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); + infof(data, " certificate public key: %s", + gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo)); + + /* version of the X.509 certificate. */ + infof(data, " certificate version: #%d", + gnutls_x509_crt_get_version(x509_cert)); + + rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields); + if(rc) + infof(data, "Failed to get certificate name"); + else { + infof(data, " subject: %s", certfields.data); + + tstamp = gnutls_x509_crt_get_activation_time(x509_cert); + showtime(data, "start date", tstamp); + + tstamp = gnutls_x509_crt_get_expiration_time(x509_cert); + showtime(data, "expire date", tstamp); + + gnutls_free(certfields.data); + } + + rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields); + if(rc) + infof(data, "Failed to get certificate issuer"); + else { + infof(data, " issuer: %s", certfields.data); + + gnutls_free(certfields.data); + } + } +#else + (void)data; + (void)x509_cert; +#endif +} + +static CURLcode gtls_verify_ocsp_status(struct Curl_easy *data, + gnutls_session_t session) +{ + gnutls_ocsp_resp_t ocsp_resp = NULL; + gnutls_datum_t status_request; + gnutls_ocsp_cert_status_t status; + gnutls_x509_crl_reason_t reason; + CURLcode result = CURLE_OK; + int rc; + + rc = gnutls_ocsp_status_request_get(session, &status_request); + + if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { + failf(data, "No OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto out; + } + else if(rc < 0) { + failf(data, "Invalid OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto out; + } + + gnutls_ocsp_resp_init(&ocsp_resp); + + rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); + if(rc < 0) { + failf(data, "Invalid OCSP response received"); + result = CURLE_SSL_INVALIDCERTSTATUS; + goto out; + } + + (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, + &status, NULL, NULL, NULL, &reason); + + switch(status) { + case GNUTLS_OCSP_CERT_GOOD: + break; + + case GNUTLS_OCSP_CERT_REVOKED: { + const char *crl_reason; + + switch(reason) { + default: + case GNUTLS_X509_CRLREASON_UNSPECIFIED: + crl_reason = "unspecified reason"; + break; + + case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: + crl_reason = "private key compromised"; + break; + + case GNUTLS_X509_CRLREASON_CACOMPROMISE: + crl_reason = "CA compromised"; + break; + + case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: + crl_reason = "affiliation has changed"; + break; + + case GNUTLS_X509_CRLREASON_SUPERSEDED: + crl_reason = "certificate superseded"; + break; + + case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: + crl_reason = "operation has ceased"; + break; + + case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: + crl_reason = "certificate is on hold"; + break; + + case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: + crl_reason = "will be removed from delta CRL"; + break; + + case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: + crl_reason = "privilege withdrawn"; + break; + + case GNUTLS_X509_CRLREASON_AACOMPROMISE: + crl_reason = "AA compromised"; + break; + } + + failf(data, "Server certificate was revoked: %s", crl_reason); + break; + } + + default: + case GNUTLS_OCSP_CERT_UNKNOWN: + failf(data, "Server certificate status is unknown"); + break; + } + + result = (status != GNUTLS_OCSP_CERT_GOOD) ? + CURLE_SSL_INVALIDCERTSTATUS : CURLE_OK; + +out: + if(ocsp_resp) + gnutls_ocsp_resp_deinit(ocsp_resp); + return result; +} + CURLcode Curl_gtls_verifyserver(struct Curl_easy *data, gnutls_session_t session, @@ -1340,18 +1530,10 @@ Curl_gtls_verifyserver(struct Curl_easy *data, unsigned int cert_list_size; const gnutls_datum_t *chainp; unsigned int verify_status = 0; - gnutls_x509_crt_t x509_cert, x509_issuer; - gnutls_datum_t issuerp; - gnutls_datum_t certfields; - char certname[65] = ""; /* limited to 64 chars by ASN.1 */ - size_t size; + gnutls_x509_crt_t x509_cert = NULL, x509_issuer = NULL; time_t certclock; int rc; CURLcode result = CURLE_OK; -#ifndef CURL_DISABLE_VERBOSE_STRINGS - int algo; - unsigned int bits; -#endif long * const certverifyresult = &ssl_config->certverifyresult; /* This function will return the peer's raw certificate (chain) as sent by @@ -1375,7 +1557,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, #endif failf(data, "failed to get server cert"); *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND; - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; #ifdef USE_GNUTLS_SRP } #endif @@ -1388,7 +1571,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data, result = Curl_ssl_init_certinfo(data, (int)cert_list_size); if(result) - return result; + goto out; for(i = 0; i < cert_list_size; i++) { const char *beg = (const char *) chainp[i].data; @@ -1396,7 +1579,7 @@ Curl_gtls_verifyserver(struct Curl_easy *data, result = Curl_extract_certinfo(data, (int)i, beg, end); if(result) - return result; + goto out; } } @@ -1412,7 +1595,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(rc < 0) { failf(data, "server cert verify failed: %d", rc); *certverifyresult = rc; - return CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; + goto out; } *certverifyresult = verify_status; @@ -1434,7 +1618,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, config->CAfile ? config->CAfile : "none", ssl_config->primary.CRLfile ? ssl_config->primary.CRLfile : "none"); - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; } else infof(data, " server certificate verification FAILED"); @@ -1446,97 +1631,9 @@ Curl_gtls_verifyserver(struct Curl_easy *data, infof(data, " server certificate verification SKIPPED"); if(config->verifystatus) { - gnutls_datum_t status_request; - gnutls_ocsp_resp_t ocsp_resp; - gnutls_ocsp_cert_status_t status; - gnutls_x509_crl_reason_t reason; - - rc = gnutls_ocsp_status_request_get(session, &status_request); - - if(rc == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) { - failf(data, "No OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - if(rc < 0) { - failf(data, "Invalid OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - gnutls_ocsp_resp_init(&ocsp_resp); - - rc = gnutls_ocsp_resp_import(ocsp_resp, &status_request); - if(rc < 0) { - failf(data, "Invalid OCSP response received"); - return CURLE_SSL_INVALIDCERTSTATUS; - } - - (void)gnutls_ocsp_resp_get_single(ocsp_resp, 0, NULL, NULL, NULL, NULL, - &status, NULL, NULL, NULL, &reason); - - switch(status) { - case GNUTLS_OCSP_CERT_GOOD: - break; - - case GNUTLS_OCSP_CERT_REVOKED: { - const char *crl_reason; - - switch(reason) { - default: - case GNUTLS_X509_CRLREASON_UNSPECIFIED: - crl_reason = "unspecified reason"; - break; - - case GNUTLS_X509_CRLREASON_KEYCOMPROMISE: - crl_reason = "private key compromised"; - break; - - case GNUTLS_X509_CRLREASON_CACOMPROMISE: - crl_reason = "CA compromised"; - break; - - case GNUTLS_X509_CRLREASON_AFFILIATIONCHANGED: - crl_reason = "affiliation has changed"; - break; - - case GNUTLS_X509_CRLREASON_SUPERSEDED: - crl_reason = "certificate superseded"; - break; - - case GNUTLS_X509_CRLREASON_CESSATIONOFOPERATION: - crl_reason = "operation has ceased"; - break; - - case GNUTLS_X509_CRLREASON_CERTIFICATEHOLD: - crl_reason = "certificate is on hold"; - break; - - case GNUTLS_X509_CRLREASON_REMOVEFROMCRL: - crl_reason = "will be removed from delta CRL"; - break; - - case GNUTLS_X509_CRLREASON_PRIVILEGEWITHDRAWN: - crl_reason = "privilege withdrawn"; - break; - - case GNUTLS_X509_CRLREASON_AACOMPROMISE: - crl_reason = "AA compromised"; - break; - } - - failf(data, "Server certificate was revoked: %s", crl_reason); - break; - } - - default: - case GNUTLS_OCSP_CERT_UNKNOWN: - failf(data, "Server certificate status is unknown"); - break; - } - - gnutls_ocsp_resp_deinit(ocsp_resp); - if(status != GNUTLS_OCSP_CERT_GOOD) - return CURLE_SSL_INVALIDCERTSTATUS; + result = gtls_verify_ocsp_status(data, session); + if(result) + goto out; } else infof(data, " server certificate status verification SKIPPED"); @@ -1550,33 +1647,22 @@ Curl_gtls_verifyserver(struct Curl_easy *data, gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER); if(config->issuercert) { + gnutls_datum_t issuerp; gnutls_x509_crt_init(&x509_issuer); issuerp = load_file(config->issuercert); gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM); rc = (int)gnutls_x509_crt_check_issuer(x509_cert, x509_issuer); - gnutls_x509_crt_deinit(x509_issuer); unload_file(issuerp); if(rc <= 0) { failf(data, "server certificate issuer check failed (IssuerCert: %s)", config->issuercert ? config->issuercert : "none"); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_ISSUER_ERROR; + result = CURLE_SSL_ISSUER_ERROR; + goto out; } infof(data, " server certificate issuer check OK (Issuer Cert: %s)", config->issuercert ? config->issuercert : "none"); } - size = sizeof(certname); - rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME, - 0, /* the first and only one */ - FALSE, - certname, - &size); - if(rc) { - infof(data, "error fetching CN from cert:%s", - gnutls_strerror(rc)); - } - /* This function will check if the given certificate's subject matches the given hostname. This is a basic implementation of the matching described in RFC2818 (HTTPS), which takes into account wildcards, and the subject @@ -1631,19 +1717,12 @@ Curl_gtls_verifyserver(struct Curl_easy *data, } } #endif - if(!rc) { - if(config->verifyhost) { - failf(data, "SSL: certificate subject name (%s) does not match " - "target hostname '%s'", certname, peer->dispname); - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; - } - else - infof(data, " common name: %s (does not match '%s')", - certname, peer->dispname); - } - else - infof(data, " common name: %s (matched)", certname); + + result = (!rc && config->verifyhost) ? + CURLE_PEER_FAILED_VERIFICATION : CURLE_OK; + gtls_msg_verify_result(data, peer, x509_cert, rc, config->verifyhost); + if(result) + goto out; /* Check for time-based validity */ certclock = gnutls_x509_crt_get_expiration_time(x509_cert); @@ -1652,8 +1731,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(config->verifypeer) { failf(data, "server cert expiration date verify failed"); *certverifyresult = GNUTLS_CERT_EXPIRED; - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; + goto out; } else infof(data, " server certificate expiration date verify FAILED"); @@ -1663,8 +1742,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(config->verifypeer) { failf(data, "server certificate expiration date has passed."); *certverifyresult = GNUTLS_CERT_EXPIRED; - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; } else infof(data, " server certificate expiration date FAILED"); @@ -1679,8 +1758,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(config->verifypeer) { failf(data, "server cert activation date verify failed"); *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; - gnutls_x509_crt_deinit(x509_cert); - return CURLE_SSL_CONNECT_ERROR; + result = CURLE_SSL_CONNECT_ERROR; + goto out; } else infof(data, " server certificate activation date verify FAILED"); @@ -1690,8 +1769,8 @@ Curl_gtls_verifyserver(struct Curl_easy *data, if(config->verifypeer) { failf(data, "server certificate not activated yet."); *certverifyresult = GNUTLS_CERT_NOT_ACTIVATED; - gnutls_x509_crt_deinit(x509_cert); - return CURLE_PEER_FAILED_VERIFICATION; + result = CURLE_PEER_FAILED_VERIFICATION; + goto out; } else infof(data, " server certificate activation date FAILED"); @@ -1704,59 +1783,17 @@ Curl_gtls_verifyserver(struct Curl_easy *data, result = pkp_pin_peer_pubkey(data, x509_cert, pinned_key); if(result != CURLE_OK) { failf(data, "SSL: public key does not match pinned public key"); - gnutls_x509_crt_deinit(x509_cert); - return result; + goto out; } } - /* Show: - - - subject - - start date - - expire date - - common name - - issuer - - */ - -#ifndef CURL_DISABLE_VERBOSE_STRINGS - /* public key algorithm's parameters */ - algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits); - infof(data, " certificate public key: %s", - gnutls_pk_algorithm_get_name((gnutls_pk_algorithm_t)algo)); - - /* version of the X.509 certificate. */ - infof(data, " certificate version: #%d", - gnutls_x509_crt_get_version(x509_cert)); - - - rc = gnutls_x509_crt_get_dn2(x509_cert, &certfields); - if(rc) - infof(data, "Failed to get certificate name"); - else { - infof(data, " subject: %s", certfields.data); - - certclock = gnutls_x509_crt_get_activation_time(x509_cert); - showtime(data, "start date", certclock); - - certclock = gnutls_x509_crt_get_expiration_time(x509_cert); - showtime(data, "expire date", certclock); - - gnutls_free(certfields.data); - } - - rc = gnutls_x509_crt_get_issuer_dn2(x509_cert, &certfields); - if(rc) - infof(data, "Failed to get certificate issuer"); - else { - infof(data, " issuer: %s", certfields.data); - - gnutls_free(certfields.data); - } -#endif - - gnutls_x509_crt_deinit(x509_cert); + gtls_infof_cert(data, x509_cert); +out: + if(x509_issuer) + gnutls_x509_crt_deinit(x509_issuer); + if(x509_cert) + gnutls_x509_crt_deinit(x509_cert); return result; } @@ -1781,15 +1818,18 @@ static CURLcode gtls_verifyserver(struct Curl_cfilter *cf, if(result) goto out; +#ifdef CURL_GNUTLS_EARLY_DATA /* Only on TLSv1.2 or lower do we have the session id now. For * TLSv1.3 we get it via a SESSION_TICKET message that arrives later. */ if(gnutls_protocol_get_version(session) < GNUTLS_TLS1_3) result = cf_gtls_update_session_id(cf, data, session); +#endif out: return result; } +#ifdef CURL_GNUTLS_EARLY_DATA static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf, struct Curl_easy *data) { @@ -1828,6 +1868,7 @@ static CURLcode gtls_send_earlydata(struct Curl_cfilter *cf, out: return result; } +#endif /* * This function is called after the TCP connect has completed. Setup the TLS @@ -1864,6 +1905,7 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf, } if(connssl->connecting_state == ssl_connect_2) { +#ifdef CURL_GNUTLS_EARLY_DATA if(connssl->earlydata_state == ssl_earlydata_await) { goto out; } @@ -1875,7 +1917,7 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf, } DEBUGASSERT((connssl->earlydata_state == ssl_earlydata_none) || (connssl->earlydata_state == ssl_earlydata_sent)); - +#endif result = handshake(cf, data); if(result) goto out; @@ -1906,6 +1948,7 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf, if(result) goto out; +#ifdef CURL_GNUTLS_EARLY_DATA if(connssl->earlydata_state > ssl_earlydata_none) { /* We should be in this state by now */ DEBUGASSERT(connssl->earlydata_state == ssl_earlydata_sent); @@ -1914,6 +1957,7 @@ static CURLcode gtls_connect_common(struct Curl_cfilter *cf, GNUTLS_SFLAGS_EARLY_DATA) ? ssl_earlydata_accepted : ssl_earlydata_rejected; } +#endif connssl->connecting_state = ssl_connect_done; } @@ -1935,6 +1979,7 @@ static CURLcode gtls_connect(struct Curl_cfilter *cf, struct Curl_easy *data, bool *done) { +#ifdef CURL_GNUTLS_EARLY_DATA struct ssl_connect_data *connssl = cf->ctx; if((connssl->state == ssl_connection_deferred) && (connssl->earlydata_state == ssl_earlydata_await)) { @@ -1942,6 +1987,7 @@ static CURLcode gtls_connect(struct Curl_cfilter *cf, *done = TRUE; return CURLE_OK; } +#endif return gtls_connect_common(cf, data, done); } @@ -1955,7 +2001,7 @@ static bool gtls_data_pending(struct Curl_cfilter *cf, DEBUGASSERT(ctx && ctx->backend); backend = (struct gtls_ssl_backend_data *)ctx->backend; if(backend->gtls.session && - 0 != gnutls_record_check_pending(backend->gtls.session)) + gnutls_record_check_pending(backend->gtls.session) != 0) return TRUE; return FALSE; } @@ -2090,7 +2136,7 @@ static void gtls_close(struct Curl_cfilter *cf, struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; - (void) data; + (void)data; DEBUGASSERT(backend); CURL_TRC_CF(data, cf, "close"); if(backend->gtls.session) { @@ -2186,7 +2232,7 @@ static bool gtls_cert_status_request(void) } static void *gtls_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info) { struct gtls_ssl_backend_data *backend = (struct gtls_ssl_backend_data *)connssl->backend; diff --git a/deps/curl/lib/vtls/hostcheck.c b/deps/curl/lib/vtls/hostcheck.c index 68af9be57d0..23ba33951f1 100644 --- a/deps/curl/lib/vtls/hostcheck.c +++ b/deps/curl/lib/vtls/hostcheck.c @@ -24,8 +24,7 @@ #include "../curl_setup.h" -#if defined(USE_OPENSSL) \ - || defined(USE_SCHANNEL) +#if defined(USE_OPENSSL) || defined(USE_SCHANNEL) /* these backends use functions from this file */ #ifdef HAVE_NETINET_IN_H diff --git a/deps/curl/lib/vtls/hostcheck.h b/deps/curl/lib/vtls/hostcheck.h index 6b4e3796443..b843d09c65e 100644 --- a/deps/curl/lib/vtls/hostcheck.h +++ b/deps/curl/lib/vtls/hostcheck.h @@ -26,8 +26,12 @@ #include +#if defined(USE_OPENSSL) || defined(USE_SCHANNEL) + /* returns TRUE if there is a match */ bool Curl_cert_hostcheck(const char *match_pattern, size_t matchlen, const char *hostname, size_t hostlen); +#endif + #endif /* HEADER_CURL_HOSTCHECK_H */ diff --git a/deps/curl/lib/vtls/mbedtls.c b/deps/curl/lib/vtls/mbedtls.c index 75190d30f3e..7b1a31e42f5 100644 --- a/deps/curl/lib/vtls/mbedtls.c +++ b/deps/curl/lib/vtls/mbedtls.c @@ -37,11 +37,10 @@ /* #define MBEDTLS_DEBUG */ #include -#if MBEDTLS_VERSION_NUMBER >= 0x02040000 -#include -#else -#include +#if MBEDTLS_VERSION_NUMBER < 0x03020000 + #error "mbedTLS 3.2.0 or later required" #endif +#include #include #include @@ -49,13 +48,9 @@ #include #include #include - -#if MBEDTLS_VERSION_MAJOR >= 2 -# ifdef MBEDTLS_DEBUG -# include -# endif -#endif /* MBEDTLS_VERSION_MAJOR >= 2 */ - +#ifdef MBEDTLS_DEBUG +#include +#endif #include "cipher_suite.h" #include "../urldata.h" #include "../sendf.h" @@ -104,8 +99,7 @@ struct mbed_ssl_backend_data { }; /* apply threading? */ -#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || \ - defined(_WIN32) +#if (defined(USE_THREADS_POSIX) && defined(HAVE_PTHREAD_H)) || defined(_WIN32) #define HAS_THREADING_SUPPORT #endif @@ -113,19 +107,6 @@ struct mbed_ssl_backend_data { #define mbedtls_strerror(a,b,c) b[0] = 0 #endif -/* PSA can be used independently of TLS 1.3 */ -#if defined(MBEDTLS_USE_PSA_CRYPTO) && MBEDTLS_VERSION_NUMBER >= 0x03060000 -#define HAS_PSA_SUPPORT -#endif - -#if defined(MBEDTLS_SSL_PROTO_TLS1_3) && MBEDTLS_VERSION_NUMBER >= 0x03060000 -#define HAS_TLS13_SUPPORT -#endif - -#if defined(HAS_TLS13_SUPPORT) && defined(MBEDTLS_SSL_SESSION_TICKETS) -#define HAS_SESSION_TICKETS -#endif - #ifdef HAS_THREADING_SUPPORT static mbedtls_entropy_context ts_entropy; @@ -171,9 +152,9 @@ static void mbed_debug(void *context, int level, const char *f_name, int line_nb, const char *line) { struct Curl_easy *data = (struct Curl_easy *)context; - (void) level; - (void) line_nb; - (void) f_name; + (void)level; + (void)line_nb; + (void)f_name; if(data) { size_t len = strlen(line); @@ -264,45 +245,25 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, * function basically always sets TLS 1.2 as min/max, unless given * unsupported option values. */ -#if MBEDTLS_VERSION_NUMBER < 0x03020000 - int ver_min = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ - int ver_max = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ -#else - /* mbedTLS 3.2.0 (2022) introduced new methods for setting TLS version */ mbedtls_ssl_protocol_version ver_min = MBEDTLS_SSL_VERSION_TLS1_2; mbedtls_ssl_protocol_version ver_max = -#ifdef HAS_TLS13_SUPPORT +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 MBEDTLS_SSL_VERSION_TLS1_3 #else MBEDTLS_SSL_VERSION_TLS1_2 #endif ; -#endif switch(conn_config->version) { case CURL_SSLVERSION_DEFAULT: -#if MBEDTLS_VERSION_NUMBER < 0x03000000 - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - ver_min = MBEDTLS_SSL_MINOR_VERSION_1; - break; - case CURL_SSLVERSION_TLSv1_1: - ver_min = MBEDTLS_SSL_MINOR_VERSION_2; - break; -#else case CURL_SSLVERSION_TLSv1: case CURL_SSLVERSION_TLSv1_0: case CURL_SSLVERSION_TLSv1_1: -#endif case CURL_SSLVERSION_TLSv1_2: -#if MBEDTLS_VERSION_NUMBER < 0x03020000 - ver_min = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ -#else ver_min = MBEDTLS_SSL_VERSION_TLS1_2; -#endif break; case CURL_SSLVERSION_TLSv1_3: -#ifdef HAS_TLS13_SUPPORT +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 ver_min = MBEDTLS_SSL_VERSION_TLS1_3; break; #endif @@ -316,42 +277,22 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, case CURL_SSLVERSION_MAX_DEFAULT: case CURL_SSLVERSION_MAX_NONE: case CURL_SSLVERSION_MAX_TLSv1_3: -#ifdef HAS_TLS13_SUPPORT +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 ver_max = MBEDTLS_SSL_VERSION_TLS1_3; break; #endif case CURL_SSLVERSION_MAX_TLSv1_2: -#if MBEDTLS_VERSION_NUMBER < 0x03020000 - ver_max = MBEDTLS_SSL_MINOR_VERSION_3; /* TLS 1.2 */ -#else ver_max = MBEDTLS_SSL_VERSION_TLS1_2; -#endif - break; -#if MBEDTLS_VERSION_NUMBER < 0x03000000 - case CURL_SSLVERSION_MAX_TLSv1_1: - ver_max = MBEDTLS_SSL_MINOR_VERSION_2; break; - case CURL_SSLVERSION_MAX_TLSv1_0: - ver_max = MBEDTLS_SSL_MINOR_VERSION_1; - break; -#else case CURL_SSLVERSION_MAX_TLSv1_1: case CURL_SSLVERSION_MAX_TLSv1_0: -#endif default: failf(data, "mbedTLS: unsupported maximum TLS version value"); return CURLE_SSL_CONNECT_ERROR; } -#if MBEDTLS_VERSION_NUMBER < 0x03020000 - mbedtls_ssl_conf_min_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, - ver_min); - mbedtls_ssl_conf_max_version(&backend->config, MBEDTLS_SSL_MAJOR_VERSION_3, - ver_max); -#else mbedtls_ssl_conf_min_tls_version(&backend->config, ver_min); mbedtls_ssl_conf_max_tls_version(&backend->config, ver_max); -#endif return CURLE_OK; } @@ -361,7 +302,6 @@ mbed_set_ssl_version_min_max(struct Curl_easy *data, cipher suite present in other SSL implementations. Provide provisional support for specifying the cipher suite here. */ #ifdef MBEDTLS_TLS_ECJPAKE_WITH_AES_128_CCM_8 -#if MBEDTLS_VERSION_NUMBER >= 0x03020000 static int mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size, bool prefer_rfc) @@ -372,7 +312,6 @@ mbed_cipher_suite_get_str(uint16_t id, char *buf, size_t buf_size, return Curl_cipher_suite_get_str(id, buf, buf_size, prefer_rfc); return 0; } -#endif static uint16_t mbed_cipher_suite_walk_str(const char **str, const char **end) @@ -411,8 +350,8 @@ mbed_set_selected_ciphers(struct Curl_easy *data, if(!selected) return CURLE_OUT_OF_MEMORY; -#ifndef HAS_TLS13_SUPPORT - (void) ciphers13, (void) j; +#ifndef MBEDTLS_SSL_PROTO_TLS1_3 + (void)ciphers13, (void)j; #else if(!ciphers13) { /* Add default TLSv1.3 ciphers to selection */ @@ -459,7 +398,7 @@ mbed_set_selected_ciphers(struct Curl_easy *data, selected[count++] = id; } -#ifdef HAS_TLS13_SUPPORT +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 if(ciphers == ciphers13 && ciphers12) { ciphers = ciphers12; goto add_ciphers; @@ -500,9 +439,8 @@ mbed_set_selected_ciphers(struct Curl_easy *data, static void mbed_dump_cert_info(struct Curl_easy *data, const mbedtls_x509_crt *crt) { -#if defined(CURL_DISABLE_VERBOSE_STRINGS) || \ - (MBEDTLS_VERSION_NUMBER >= 0x03000000 && defined(MBEDTLS_X509_REMOVE_INFO)) - (void) data, (void) crt; +#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(MBEDTLS_X509_REMOVE_INFO) + (void)data, (void)crt; #else const size_t bufsize = 16384; char *p, *buffer = malloc(bufsize); @@ -559,7 +497,7 @@ static int mbed_verify_cb(void *ptr, mbedtls_x509_crt *crt, *flags &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH; if(*flags) { -#if MBEDTLS_VERSION_NUMBER < 0x03000000 || !defined(MBEDTLS_X509_REMOVE_INFO) +#ifndef MBEDTLS_X509_REMOVE_INFO char buf[128]; mbedtls_x509_crt_verify_info(buf, sizeof(buf), "", *flags); failf(data, "mbedTLS: %s", buf); @@ -659,7 +597,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CACERT_BADFILE; } #else - failf(data, "mbedtls: functions that use the filesystem not built in"); + failf(data, "mbedtls: functions that use the file system not built in"); return CURLE_NOT_BUILT_IN; #endif } @@ -677,7 +615,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CACERT_BADFILE; } #else - failf(data, "mbedtls: functions that use the filesystem not built in"); + failf(data, "mbedtls: functions that use the file system not built in"); return CURLE_NOT_BUILT_IN; #endif } @@ -697,7 +635,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CERTPROBLEM; } #else - failf(data, "mbedtls: functions that use the filesystem not built in"); + failf(data, "mbedtls: functions that use the file system not built in"); return CURLE_NOT_BUILT_IN; #endif } @@ -728,15 +666,10 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) if(ssl_config->key || ssl_config->key_blob) { if(ssl_config->key) { #ifdef MBEDTLS_FS_IO -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key, ssl_config->key_passwd, mbedtls_ctr_drbg_random, &backend->ctr_drbg); -#else - ret = mbedtls_pk_parse_keyfile(&backend->pk, ssl_config->key, - ssl_config->key_passwd); -#endif if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; @@ -748,7 +681,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CERTPROBLEM; } #else - failf(data, "mbedtls: functions that use the filesystem not built in"); + failf(data, "mbedtls: functions that use the file system not built in"); return CURLE_NOT_BUILT_IN; #endif } @@ -757,17 +690,11 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) const unsigned char *key_data = (const unsigned char *)ssl_key_blob->data; const char *passwd = ssl_config->key_passwd; -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, (const unsigned char *)passwd, passwd ? strlen(passwd) : 0, mbedtls_ctr_drbg_random, &backend->ctr_drbg); -#else - ret = mbedtls_pk_parse_key(&backend->pk, key_data, ssl_key_blob->len, - (const unsigned char *)passwd, - passwd ? strlen(passwd) : 0); -#endif if(ret == 0 && !(mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_RSA) || mbedtls_pk_can_do(&backend->pk, MBEDTLS_PK_ECKEY))) ret = MBEDTLS_ERR_PK_TYPE_MISMATCH; @@ -797,7 +724,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CRL_BADFILE; } #else - failf(data, "mbedtls: functions that use the filesystem not built in"); + failf(data, "mbedtls: functions that use the file system not built in"); return CURLE_NOT_BUILT_IN; #endif } @@ -820,7 +747,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) return CURLE_SSL_CONNECT_ERROR; } -#if defined(HAS_SESSION_TICKETS) && MBEDTLS_VERSION_NUMBER >= 0x03060100 +#ifdef MBEDTLS_SSL_SESSION_TICKETS /* New in mbedTLS 3.6.1, need to enable, default is now disabled */ mbedtls_ssl_conf_tls13_enable_signal_new_session_tickets(&backend->config, MBEDTLS_SSL_TLS1_3_SIGNAL_NEW_SESSION_TICKETS_ENABLED); @@ -859,7 +786,7 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) mbedtls_bio_cf_read, NULL /* rev_timeout() */); -#ifndef HAS_TLS13_SUPPORT +#ifndef MBEDTLS_SSL_PROTO_TLS1_3 if(conn_config->cipher_list) { CURLcode result = mbed_set_selected_ciphers(data, backend, conn_config->cipher_list, @@ -881,12 +808,12 @@ mbed_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } -#if defined(MBEDTLS_SSL_RENEGOTIATION) +#ifdef MBEDTLS_SSL_RENEGOTIATION mbedtls_ssl_conf_renegotiation(&backend->config, MBEDTLS_SSL_RENEGOTIATION_ENABLED); #endif -#if defined(MBEDTLS_SSL_SESSION_TICKETS) +#ifdef MBEDTLS_SSL_SESSION_TICKETS mbedtls_ssl_conf_session_tickets(&backend->config, MBEDTLS_SSL_SESSION_TICKETS_DISABLED); #endif @@ -1021,17 +948,14 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) } else if(ret) { char errorbuf[128]; -#if MBEDTLS_VERSION_NUMBER >= 0x03020000 CURL_TRC_CF(data, cf, "TLS version %04X", mbedtls_ssl_get_version_number(&backend->ssl)); -#endif mbedtls_strerror(ret, errorbuf, sizeof(errorbuf)); failf(data, "ssl_handshake returned: (-0x%04X) %s", -ret, errorbuf); return CURLE_SSL_CONNECT_ERROR; } -#if MBEDTLS_VERSION_NUMBER >= 0x03020000 { char cipher_str[64]; uint16_t cipher_id; @@ -1041,10 +965,6 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) infof(data, "mbedTLS: %s Handshake complete, cipher is %s", mbedtls_ssl_get_version(&backend->ssl), cipher_str); } -#else - infof(data, "mbedTLS: %s Handshake complete", - mbedtls_ssl_get_version(&backend->ssl)); -#endif if(pinnedpubkey) { int size; @@ -1054,12 +974,7 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) unsigned char *pubkey = NULL; peercert = mbedtls_ssl_get_peer_cert(&backend->ssl); -#if MBEDTLS_VERSION_NUMBER == 0x03000000 - if(!peercert || !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p) || - !peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len)) { -#else if(!peercert || !peercert->raw.p || !peercert->raw.len) { -#endif failf(data, "Failed due to missing peer certificate"); return CURLE_SSL_PINNEDPUBKEYNOTMATCH; } @@ -1081,24 +996,13 @@ mbed_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) /* Make a copy of our const peercert because mbedtls_pk_write_pubkey_der needs a non-const key, for now. https://github.com/Mbed-TLS/mbedtls/issues/396 */ -#if MBEDTLS_VERSION_NUMBER == 0x03000000 - if(mbedtls_x509_crt_parse_der(p, - peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(p), - peercert->MBEDTLS_PRIVATE(raw).MBEDTLS_PRIVATE(len))) { -#else if(mbedtls_x509_crt_parse_der(p, peercert->raw.p, peercert->raw.len)) { -#endif failf(data, "Failed copying peer certificate"); result = CURLE_SSL_PINNEDPUBKEYNOTMATCH; goto pinnedpubkey_error; } -#if MBEDTLS_VERSION_NUMBER == 0x03000000 - size = mbedtls_pk_write_pubkey_der(&p->MBEDTLS_PRIVATE(pk), pubkey, - PUB_DER_MAX_BYTES); -#else size = mbedtls_pk_write_pubkey_der(&p->pk, pubkey, PUB_DER_MAX_BYTES); -#endif if(size <= 0) { failf(data, "Failed copying public key from peer certificate"); @@ -1181,11 +1085,7 @@ mbed_new_session(struct Curl_cfilter *cf, struct Curl_easy *data) goto out; } -#if MBEDTLS_VERSION_NUMBER >= 0x03020000 ietf_tls_id = mbedtls_ssl_get_version_number(&backend->ssl); -#else - ietf_tls_id = CURL_IETF_PROTO_UNKNOWN; -#endif result = Curl_ssl_session_create(sdata, slen, ietf_tls_id, connssl->negotiated.alpn, 0, 0, @@ -1236,7 +1136,7 @@ static CURLcode mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data, CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X", len, -nwritten); result = ((nwritten == MBEDTLS_ERR_SSL_WANT_WRITE) -#ifdef HAS_TLS13_SUPPORT +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 || (nwritten == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) #endif ) ? CURLE_AGAIN : CURLE_SEND_ERROR; @@ -1306,7 +1206,7 @@ static CURLcode mbedtls_shutdown(struct Curl_cfilter *cf, * WANT_READ, but has not encountered an EAGAIN. */ if(ret == MBEDTLS_ERR_SSL_WANT_READ) ret = mbedtls_ssl_read(&backend->ssl, buf, sizeof(buf)); -#ifdef HAS_TLS13_SUPPORT +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 if(ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET) continue; #endif @@ -1388,7 +1288,7 @@ static CURLcode mbed_recv(struct Curl_cfilter *cf, struct Curl_easy *data, CURL_TRC_CF(data, cf, "mbedtls_ssl_read(len=%zu) -> -0x%04X", buffersize, -nread); switch(nread) { -#ifdef HAS_SESSION_TICKETS +#ifdef MBEDTLS_SSL_SESSION_TICKETS case MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET: mbed_new_session(cf, data); FALLTHROUGH(); @@ -1427,7 +1327,7 @@ static size_t mbedtls_version(char *buffer, size_t size) static CURLcode mbedtls_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { -#if defined(MBEDTLS_CTR_DRBG_C) +#ifdef MBEDTLS_CTR_DRBG_C int ret; mbedtls_entropy_context ctr_entropy; mbedtls_ctr_drbg_context ctr_drbg; @@ -1486,16 +1386,12 @@ static CURLcode mbedtls_connect(struct Curl_cfilter *cf, if(ssl_connect_3 == connssl->connecting_state) { /* For tls1.3 we get notified about new sessions */ -#if MBEDTLS_VERSION_NUMBER >= 0x03020000 struct ssl_connect_data *ctx = cf->ctx; struct mbed_ssl_backend_data *backend = (struct mbed_ssl_backend_data *)ctx->backend; if(mbedtls_ssl_get_version_number(&backend->ssl) <= MBEDTLS_SSL_VERSION_TLS1_2) { -#else - { /* no TLSv1.3 supported here */ -#endif retcode = mbed_new_session(cf, data); if(retcode) return retcode; @@ -1522,7 +1418,7 @@ static int mbedtls_init(void) #ifdef HAS_THREADING_SUPPORT entropy_init_mutex(&ts_entropy); #endif -#ifdef HAS_PSA_SUPPORT +#ifdef MBEDTLS_USE_PSA_CRYPTO /* requires mbedTLS 3.6.0+ */ { int ret; #ifdef HAS_THREADING_SUPPORT @@ -1535,7 +1431,7 @@ static int mbedtls_init(void) if(ret != PSA_SUCCESS) return 0; } -#endif /* HAS_PSA_SUPPORT */ +#endif /* MBEDTLS_USE_PSA_CRYPTO */ return 1; } @@ -1562,25 +1458,17 @@ static bool mbedtls_data_pending(struct Curl_cfilter *cf, static CURLcode mbedtls_sha256sum(const unsigned char *input, size_t inputlen, unsigned char *sha256sum, - size_t sha256len UNUSED_PARAM) + size_t sha256len) { (void)sha256len; -#if MBEDTLS_VERSION_NUMBER < 0x02070000 - mbedtls_sha256(input, inputlen, sha256sum, 0); -#else /* returns 0 on success, otherwise failure */ -#if MBEDTLS_VERSION_NUMBER >= 0x03000000 if(mbedtls_sha256(input, inputlen, sha256sum, 0) != 0) -#else - if(mbedtls_sha256_ret(input, inputlen, sha256sum, 0) != 0) -#endif return CURLE_BAD_FUNCTION_ARGUMENT; -#endif return CURLE_OK; } static void *mbedtls_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info) { struct mbed_ssl_backend_data *backend = (struct mbed_ssl_backend_data *)connssl->backend; @@ -1597,7 +1485,7 @@ const struct Curl_ssl Curl_ssl_mbedtls = { SSLSUPP_CERTINFO | SSLSUPP_PINNEDPUBKEY | SSLSUPP_SSL_CTX | -#ifdef HAS_TLS13_SUPPORT +#ifdef MBEDTLS_SSL_PROTO_TLS1_3 /* requires mbedTLS 3.6.0+ */ SSLSUPP_TLS13_CIPHERSUITES | #endif SSLSUPP_HTTPS_PROXY | diff --git a/deps/curl/lib/vtls/openssl.c b/deps/curl/lib/vtls/openssl.c index b0f91cf400f..a49203ab07d 100644 --- a/deps/curl/lib/vtls/openssl.c +++ b/deps/curl/lib/vtls/openssl.c @@ -61,6 +61,7 @@ #include "../vauth/vauth.h" #include "keylog.h" #include "hostcheck.h" +#include "../transfer.h" #include "../multiif.h" #include "../curlx/strparse.h" #include "../strdup.h" @@ -89,11 +90,9 @@ #define USE_ECH_OPENSSL #endif -#ifdef USE_ECH_OPENSSL -# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) -# include -# endif -#endif /* USE_ECH_OPENSSL */ +#if defined(USE_ECH_OPENSSL) && !defined(HAVE_BORINGSSL_LIKE) +#include +#endif #ifndef OPENSSL_NO_OCSP #include @@ -105,15 +104,15 @@ #endif #ifdef LIBRESSL_VERSION_NUMBER -# /* As of LibreSSL 2.0.0-4.0.0: OPENSSL_VERSION_NUMBER == 0x20000000L */ -# if LIBRESSL_VERSION_NUMBER < 0x2090100fL /* 2019-04-13 */ -# error "LibreSSL 2.9.1 or later required" -# endif +/* As of LibreSSL 2.0.0-4.0.0: OPENSSL_VERSION_NUMBER == 0x20000000L */ +# if LIBRESSL_VERSION_NUMBER < 0x2090100fL /* 2019-04-13 */ +# error "LibreSSL 2.9.1 or later required" +# endif #elif OPENSSL_VERSION_NUMBER < 0x1000201fL /* 2015-03-19 */ -# error "OpenSSL 1.0.2a or later required" +# error "OpenSSL 1.0.2a or later required" #endif -#if OPENSSL_VERSION_NUMBER >= 0x3000000fL && !defined(OPENSSL_NO_UI_CONSOLE) +#if defined(HAVE_OPENSSL3) && !defined(OPENSSL_NO_UI_CONSOLE) #include #include /* this is used in the following conditions to make them easier to read */ @@ -122,10 +121,15 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #endif -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) && \ - !defined(OPENSSL_IS_BORINGSSL)) - #define HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN 1 +/* + * AWS-LC has `SSL_CTX_set_default_read_buffer_len()?` but runs into + * decryption failures with large buffers. Sporadic failures in + * test_10_08 with h2 proxy uploads, increased frequency + * with CURL_DBG_SOCK_RBLOCK=50. Looks like a bug on their part. + */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ + !defined(LIBRESSL_VERSION_NUMBER) && !defined(HAVE_BORINGSSL_LIKE) +#define HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN 1 #endif #include "../curlx/warnless.h" @@ -134,17 +138,6 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #include "../curl_memory.h" #include "../memdebug.h" -/* Uncomment the ALLOW_RENEG line to a real #define if you want to allow TLS - renegotiations when built with BoringSSL. Renegotiating is non-compliant - with HTTP/2 and "an extremely dangerous protocol feature". Beware. - -#define ALLOW_RENEG 1 - */ - -#ifndef OPENSSL_VERSION_NUMBER -#error "OPENSSL_VERSION_NUMBER not defined" -#endif - #if defined(USE_OPENSSL_ENGINE) || defined(OPENSSL_HAS_PROVIDERS) #include #endif @@ -174,7 +167,7 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #define HAVE_SSL_COMP_FREE_COMPRESSION_METHODS 1 #endif -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#ifdef HAVE_OPENSSL3 #define HAVE_EVP_PKEY_GET_PARAMS 1 #endif @@ -197,10 +190,10 @@ static void ossl_provider_cleanup(struct Curl_easy *data); (defined(LIBRESSL_VERSION_NUMBER) && \ LIBRESSL_VERSION_NUMBER >= 0x3040100fL)) && \ !defined(OPENSSL_IS_BORINGSSL) - #define HAVE_SSL_CTX_SET_CIPHERSUITES - #ifndef OPENSSL_IS_AWSLC - #define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH - #endif +# define HAVE_SSL_CTX_SET_CIPHERSUITES +# ifndef OPENSSL_IS_AWSLC +# define HAVE_SSL_CTX_SET_POST_HANDSHAKE_AUTH +# endif #endif /* Whether SSL_CTX_set1_sigalgs_list is available @@ -208,9 +201,8 @@ static void ossl_provider_cleanup(struct Curl_easy *data); * BoringSSL: supported since 0.20240913.0 (commit 826ce15) * LibreSSL: no */ -#if (OPENSSL_VERSION_NUMBER >= 0x10002000L && \ - !defined(LIBRESSL_VERSION_NUMBER)) - #define HAVE_SSL_CTX_SET1_SIGALGS +#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER) +#define HAVE_SSL_CTX_SET1_SIGALGS #endif #ifdef LIBRESSL_VERSION_NUMBER @@ -219,21 +211,23 @@ static void ossl_provider_cleanup(struct Curl_easy *data); #define OSSL_PACKAGE "BoringSSL" #elif defined(OPENSSL_IS_AWSLC) #define OSSL_PACKAGE "AWS-LC" -#elif (defined(USE_NGTCP2) && defined(USE_NGHTTP3) && \ - !defined(OPENSSL_QUIC_API2)) || defined(USE_MSH3) +#elif defined(USE_NGTCP2) && defined(USE_NGHTTP3) && \ + !defined(OPENSSL_QUIC_API2) #define OSSL_PACKAGE "quictls" #else #define OSSL_PACKAGE "OpenSSL" #endif -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#ifdef HAVE_BORINGSSL_LIKE typedef size_t numcert_t; +typedef uint32_t sslerr_t; #else typedef int numcert_t; +typedef unsigned long sslerr_t; #endif #define ossl_valsize_t numcert_t -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* up2date versions of OpenSSL maintain reasonably secure defaults without * breaking compatibility, so it is better not to override the defaults in curl */ @@ -244,36 +238,16 @@ typedef int numcert_t; "ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH" #endif -#ifdef HAVE_OPENSSL_SRP -/* the function exists */ -#ifdef USE_TLS_SRP -/* the functionality is not disabled */ -#define USE_OPENSSL_SRP -#endif -#endif - -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L #define HAVE_RANDOM_INIT_BY_DEFAULT 1 #endif -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ - !defined(OPENSSL_IS_BORINGSSL) && \ - !defined(OPENSSL_IS_AWSLC) -#define HAVE_OPENSSL_VERSION -#endif - -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) -typedef uint32_t sslerr_t; -#else -typedef unsigned long sslerr_t; -#endif - /* * Whether the OpenSSL version has the API needed to support sharing an * X509_STORE between connections. The API is: * * `X509_STORE_up_ref` -- Introduced: OpenSSL 1.1.0. */ -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* OpenSSL >= 1.1.0 */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* OpenSSL >= 1.1.0 */ #define HAVE_SSL_X509_STORE_SHARE #endif @@ -344,8 +318,7 @@ static CURLcode X509V3_ext(struct Curl_easy *data, { int i; CURLcode result = CURLE_OK; -#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ - !defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) const STACK_OF(X509_EXTENSION) *exts = extsarg; #else STACK_OF(X509_EXTENSION) *exts = CURL_UNCONST(extsarg); @@ -703,13 +676,11 @@ static long ossl_bio_cf_ctrl(BIO *bio, int cmd, long num, void *ptr) case BIO_CTRL_DUP: ret = 1; break; -#ifdef BIO_CTRL_EOF case BIO_CTRL_EOF: { /* EOF has been reached on input? */ struct ssl_connect_data *connssl = cf->ctx; return connssl->peer_closed; } -#endif default: ret = 0; break; @@ -850,13 +821,19 @@ static void ossl_keylog_callback(const SSL *ssl, const char *line) static void ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done) { - const SSL_SESSION *session = SSL_get_session(ssl); + const SSL_SESSION *session; unsigned char client_random[SSL3_RANDOM_SIZE]; unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH]; int master_key_length = 0; - if(!session || *keylog_done) + ERR_set_mark(); + + session = SSL_get_session(ssl); + + if(!session || *keylog_done) { + ERR_pop_to_mark(); return; + } #if OPENSSL_VERSION_NUMBER >= 0x10100000L /* ssl->s3 is not checked in OpenSSL 1.1.0-pre6, but let's assume that @@ -872,6 +849,8 @@ ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done) } #endif + ERR_pop_to_mark(); + /* The handshake has not progressed sufficiently yet, or this is a TLS 1.3 * session (when curl was built with older OpenSSL headers and running with * newer OpenSSL runtime libraries). */ @@ -905,17 +884,17 @@ static const char *SSL_ERROR_to_str(int err) return "SSL_ERROR_WANT_CONNECT"; case SSL_ERROR_WANT_ACCEPT: return "SSL_ERROR_WANT_ACCEPT"; -#ifdef SSL_ERROR_WANT_ASYNC +#ifdef SSL_ERROR_WANT_ASYNC /* OpenSSL 1.1.0+, LibreSSL 3.6.0+ */ case SSL_ERROR_WANT_ASYNC: return "SSL_ERROR_WANT_ASYNC"; #endif -#ifdef SSL_ERROR_WANT_ASYNC_JOB +#ifdef SSL_ERROR_WANT_ASYNC_JOB /* OpenSSL 1.1.0+, LibreSSL 3.6.0+ */ case SSL_ERROR_WANT_ASYNC_JOB: return "SSL_ERROR_WANT_ASYNC_JOB"; #endif -#ifdef SSL_ERROR_WANT_EARLY - case SSL_ERROR_WANT_EARLY: - return "SSL_ERROR_WANT_EARLY"; +#ifdef SSL_ERROR_WANT_CLIENT_HELLO_CB /* OpenSSL 1.1.1, LibreSSL 3.6.0+ */ + case SSL_ERROR_WANT_CLIENT_HELLO_CB: + return "SSL_ERROR_WANT_CLIENT_HELLO_CB"; #endif default: return "SSL_ERROR unknown"; @@ -940,7 +919,7 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) *buf = '\0'; } -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#ifdef HAVE_BORINGSSL_LIKE ERR_error_string_n((uint32_t)error, buf, size); #else ERR_error_string_n(error, buf, size); @@ -958,7 +937,7 @@ static char *ossl_strerror(unsigned long error, char *buf, size_t size) static int passwd_callback(char *buf, int num, int encrypting, void *password) { - DEBUGASSERT(0 == encrypting); + DEBUGASSERT(encrypting == 0); if(!encrypting && num >= 0 && password) { int klen = curlx_uztosi(strlen((char *)password)); @@ -975,7 +954,7 @@ static int passwd_callback(char *buf, int num, int encrypting, */ static bool rand_enough(void) { - return 0 != RAND_status(); + return RAND_status() != 0; } static CURLcode ossl_seed(struct Curl_easy *data) @@ -1124,7 +1103,7 @@ static bool is_pkcs11_uri(const char *string) #endif static CURLcode ossl_set_engine(struct Curl_easy *data, const char *engine); -#if defined(OPENSSL_HAS_PROVIDERS) +#ifdef OPENSSL_HAS_PROVIDERS static CURLcode ossl_set_provider(struct Curl_easy *data, const char *provider); #endif @@ -1249,27 +1228,438 @@ use_certificate_chain_blob(SSL_CTX *ctx, const struct curl_blob *blob, return ret; } -static -int cert_stuff(struct Curl_easy *data, - SSL_CTX* ctx, - char *cert_file, - const struct curl_blob *cert_blob, - const char *cert_type, - char *key_file, - const struct curl_blob *key_blob, - const char *key_type, - char *key_passwd) +static int enginecheck(struct Curl_easy *data, + SSL_CTX* ctx, + const char *key_file, + const char *key_passwd) +#ifdef USE_OPENSSL_ENGINE +{ + EVP_PKEY *priv_key = NULL; + + /* Implicitly use pkcs11 engine if none was provided and the + * key_file is a PKCS#11 URI */ + if(!data->state.engine) { + if(is_pkcs11_uri(key_file)) { + if(ossl_set_engine(data, "pkcs11") != CURLE_OK) { + return 0; + } + } + } + + if(data->state.engine) { + UI_METHOD *ui_method = + UI_create_method(OSSL_UI_METHOD_CAST("curl user interface")); + if(!ui_method) { + failf(data, "unable do create " OSSL_PACKAGE " user-interface method"); + return 0; + } + UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); + UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); + UI_method_set_reader(ui_method, ssl_ui_reader); + UI_method_set_writer(ui_method, ssl_ui_writer); + priv_key = ENGINE_load_private_key(data->state.engine, key_file, + ui_method, + CURL_UNCONST(key_passwd)); + UI_destroy_method(ui_method); + if(!priv_key) { + failf(data, "failed to load private key from crypto engine"); + return 0; + } + if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { + failf(data, "unable to set private key"); + EVP_PKEY_free(priv_key); + return 0; + } + EVP_PKEY_free(priv_key); /* we do not need the handle any more... */ + } + else { + failf(data, "crypto engine not set, cannot load private key"); + return 0; + } + return 1; +} +#else +{ + (void)ctx; + (void)key_file; + (void)key_passwd; + failf(data, "SSL_FILETYPE_ENGINE not supported for private key"); + return 0; +} +#endif + +static int providercheck(struct Curl_easy *data, + SSL_CTX* ctx, + const char *key_file) +#ifdef OPENSSL_HAS_PROVIDERS { char error_buffer[256]; - bool check_privkey = TRUE; + /* Implicitly use pkcs11 provider if none was provided and the + * key_file is a PKCS#11 URI */ + if(!data->state.provider_loaded) { + if(is_pkcs11_uri(key_file)) { + if(ossl_set_provider(data, "pkcs11") != CURLE_OK) { + return 0; + } + } + } + if(data->state.provider_loaded) { + /* Load the private key from the provider */ + EVP_PKEY *priv_key = NULL; + OSSL_STORE_CTX *store = NULL; + OSSL_STORE_INFO *info = NULL; + UI_METHOD *ui_method = + UI_create_method(OSSL_UI_METHOD_CAST("curl user interface")); + if(!ui_method) { + failf(data, "unable do create " OSSL_PACKAGE " user-interface method"); + return 0; + } + UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); + UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); + UI_method_set_reader(ui_method, ssl_ui_reader); + UI_method_set_writer(ui_method, ssl_ui_writer); + + store = OSSL_STORE_open_ex(key_file, data->state.libctx, + data->state.propq, ui_method, NULL, NULL, + NULL, NULL); + if(!store) { + failf(data, "Failed to open OpenSSL store: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + if(OSSL_STORE_expect(store, OSSL_STORE_INFO_PKEY) != 1) { + failf(data, "Failed to set store preference. Ignoring the error: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + } + + info = OSSL_STORE_load(store); + if(info) { + int ossl_type = OSSL_STORE_INFO_get_type(info); + + if(ossl_type == OSSL_STORE_INFO_PKEY) + priv_key = OSSL_STORE_INFO_get1_PKEY(info); + OSSL_STORE_INFO_free(info); + } + OSSL_STORE_close(store); + UI_destroy_method(ui_method); + if(!priv_key) { + failf(data, "No private key found in the openssl store: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + + if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { + failf(data, "unable to set private key [%s]", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + EVP_PKEY_free(priv_key); + return 0; + } + EVP_PKEY_free(priv_key); /* we do not need the handle any more... */ + } + else { + failf(data, "crypto provider not set, cannot load private key"); + return 0; + } + return 1; +} +#else +{ + (void)ctx; + (void)key_file; + failf(data, "SSL_FILETYPE_PROVIDER not supported for private key"); + return 0; +} +#endif + +static int engineload(struct Curl_easy *data, + SSL_CTX* ctx, + const char *cert_file) +/* ENGINE_CTRL_GET_CMD_FROM_NAME supported by OpenSSL, LibreSSL <=3.8.3 */ +#if defined(USE_OPENSSL_ENGINE) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME) +{ + char error_buffer[256]; + /* Implicitly use pkcs11 engine if none was provided and the + * cert_file is a PKCS#11 URI */ + if(!data->state.engine) { + if(is_pkcs11_uri(cert_file)) { + if(ossl_set_engine(data, "pkcs11") != CURLE_OK) { + return 0; + } + } + } + + if(data->state.engine) { + const char *cmd_name = "LOAD_CERT_CTRL"; + struct { + const char *cert_id; + X509 *cert; + } params; + + params.cert_id = cert_file; + params.cert = NULL; + + /* Does the engine supports LOAD_CERT_CTRL ? */ + if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME, + 0, CURL_UNCONST(cmd_name), NULL)) { + failf(data, "ssl engine does not support loading certificates"); + return 0; + } + + /* Load the certificate from the engine */ + if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name, + 0, ¶ms, NULL, 1)) { + failf(data, "ssl engine cannot load client cert with id" + " '%s' [%s]", cert_file, + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + + if(!params.cert) { + failf(data, "ssl engine did not initialized the certificate " + "properly."); + return 0; + } + + if(SSL_CTX_use_certificate(ctx, params.cert) != 1) { + failf(data, "unable to set client certificate [%s]", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + X509_free(params.cert); /* we do not need the handle any more... */ + } + else { + failf(data, "crypto engine not set, cannot load certificate"); + return 0; + } + return 1; +} +#else +{ + (void)ctx; + (void)cert_file; + failf(data, "SSL_FILETYPE_ENGINE not supported for certificate"); + return 0; +} +#endif + +static int providerload(struct Curl_easy *data, + SSL_CTX* ctx, + const char *cert_file) +#ifdef OPENSSL_HAS_PROVIDERS +{ + char error_buffer[256]; + /* Implicitly use pkcs11 provider if none was provided and the + * cert_file is a PKCS#11 URI */ + if(!data->state.provider_loaded) { + if(is_pkcs11_uri(cert_file)) { + if(ossl_set_provider(data, "pkcs11") != CURLE_OK) { + return 0; + } + } + } + + if(data->state.provider_loaded) { + /* Load the certificate from the provider */ + OSSL_STORE_INFO *info = NULL; + X509 *cert = NULL; + OSSL_STORE_CTX *store = + OSSL_STORE_open_ex(cert_file, data->state.libctx, + NULL, NULL, NULL, NULL, NULL, NULL); + if(!store) { + failf(data, "Failed to open OpenSSL store: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + if(OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) != 1) { + failf(data, "Failed to set store preference. Ignoring the error: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + } + + info = OSSL_STORE_load(store); + if(info) { + int ossl_type = OSSL_STORE_INFO_get_type(info); + + if(ossl_type == OSSL_STORE_INFO_CERT) + cert = OSSL_STORE_INFO_get1_CERT(info); + OSSL_STORE_INFO_free(info); + } + OSSL_STORE_close(store); + if(!cert) { + failf(data, "No cert found in the openssl store: %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + + if(SSL_CTX_use_certificate(ctx, cert) != 1) { + failf(data, "unable to set client certificate [%s]", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer))); + return 0; + } + X509_free(cert); /* we do not need the handle any more... */ + } + else { + failf(data, "crypto provider not set, cannot load certificate"); + return 0; + } + return 1; +} +#else +{ + (void)ctx; + (void)cert_file; + failf(data, "SSL_FILETYPE_PROVIDER not supported for certificate"); + return 0; +} +#endif + +static int pkcs12load(struct Curl_easy *data, + SSL_CTX* ctx, + const struct curl_blob *cert_blob, + const char *cert_file, + const char *key_passwd) +{ + char error_buffer[256]; + BIO *cert_bio = NULL; + PKCS12 *p12 = NULL; + EVP_PKEY *pri; + X509 *x509; + int cert_done = 0; + STACK_OF(X509) *ca = NULL; + if(cert_blob) { + cert_bio = BIO_new_mem_buf(cert_blob->data, (int)(cert_blob->len)); + if(!cert_bio) { + failf(data, + "BIO_new_mem_buf NULL, " OSSL_PACKAGE " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return 0; + } + } + else { + cert_bio = BIO_new(BIO_s_file()); + if(!cert_bio) { + failf(data, + "BIO_new return NULL, " OSSL_PACKAGE " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + return 0; + } + + if(BIO_read_filename(cert_bio, CURL_UNCONST(cert_file)) <= 0) { + failf(data, "could not open PKCS12 file '%s'", cert_file); + BIO_free(cert_bio); + return 0; + } + } + + p12 = d2i_PKCS12_bio(cert_bio, NULL); + BIO_free(cert_bio); + + if(!p12) { + failf(data, "error reading PKCS12 file '%s'", + cert_blob ? "(memory blob)" : cert_file); + return 0; + } + + PKCS12_PBE_add(); + + if(!PKCS12_parse(p12, key_passwd, &pri, &x509, &ca)) { + failf(data, + "could not parse PKCS12 file, check password, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + PKCS12_free(p12); + return 0; + } + + PKCS12_free(p12); + + if(SSL_CTX_use_certificate(ctx, x509) != 1) { + failf(data, + "could not load PKCS12 client certificate, " OSSL_PACKAGE + " error %s", + ossl_strerror(ERR_get_error(), error_buffer, + sizeof(error_buffer)) ); + goto fail; + } + + if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { + failf(data, "unable to use private key from PKCS12 file '%s'", + cert_file); + goto fail; + } + + if(!SSL_CTX_check_private_key(ctx)) { + failf(data, "private key from PKCS12 file '%s' " + "does not match certificate in same file", cert_file); + goto fail; + } + /* Set Certificate Verification chain */ + if(ca) { + while(sk_X509_num(ca)) { + /* + * Note that sk_X509_pop() is used below to make sure the cert is + * removed from the stack properly before getting passed to + * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously + * we used sk_X509_value() instead, but then we would clean it in the + * subsequent sk_X509_pop_free() call. + */ + X509 *x = sk_X509_pop(ca); + if(!SSL_CTX_add_client_CA(ctx, x)) { + X509_free(x); + failf(data, "cannot add certificate to client CA list"); + goto fail; + } + if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { + X509_free(x); + failf(data, "cannot add certificate to certificate chain"); + goto fail; + } + } + } + + cert_done = 1; +fail: + EVP_PKEY_free(pri); + X509_free(x509); + sk_X509_pop_free(ca, X509_free); + if(!cert_done) + return 0; /* failure! */ + return 1; +} + + +static CURLcode client_cert(struct Curl_easy *data, + SSL_CTX* ctx, + char *cert_file, + const struct curl_blob *cert_blob, + const char *cert_type, + char *key_file, + const struct curl_blob *key_blob, + const char *key_type, + char *key_passwd) +{ + char error_buffer[256]; + bool check_privkey = TRUE; int file_type = ossl_do_file_type(cert_type); if(cert_file || cert_blob || (file_type == SSL_FILETYPE_ENGINE) || (file_type == SSL_FILETYPE_PROVIDER)) { SSL *ssl; X509 *x509; - int cert_done = 0; + bool pcks12_done = FALSE; int cert_use_result; if(key_passwd) { @@ -1279,7 +1669,6 @@ int cert_stuff(struct Curl_easy *data, SSL_CTX_set_default_passwd_cb(ctx, passwd_callback); } - switch(file_type) { case SSL_FILETYPE_PEM: /* SSL_CTX_use_certificate_chain_file() only works on PEM files */ @@ -1294,7 +1683,7 @@ int cert_stuff(struct Curl_easy *data, (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file), ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); - return 0; + return CURLE_SSL_CERTPROBLEM; } break; @@ -1314,249 +1703,29 @@ int cert_stuff(struct Curl_easy *data, (cert_blob ? "CURLOPT_SSLCERT_BLOB" : cert_file), ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); - return 0; + return CURLE_SSL_CERTPROBLEM; } break; - case SSL_FILETYPE_ENGINE: -#if defined(USE_OPENSSL_ENGINE) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME) - { - /* Implicitly use pkcs11 engine if none was provided and the - * cert_file is a PKCS#11 URI */ - if(!data->state.engine) { - if(is_pkcs11_uri(cert_file)) { - if(ossl_set_engine(data, "pkcs11") != CURLE_OK) { - return 0; - } - } - } - - if(data->state.engine) { - const char *cmd_name = "LOAD_CERT_CTRL"; - struct { - const char *cert_id; - X509 *cert; - } params; - - params.cert_id = cert_file; - params.cert = NULL; - - /* Does the engine supports LOAD_CERT_CTRL ? */ - if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME, - 0, CURL_UNCONST(cmd_name), NULL)) { - failf(data, "ssl engine does not support loading certificates"); - return 0; - } - - /* Load the certificate from the engine */ - if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name, - 0, ¶ms, NULL, 1)) { - failf(data, "ssl engine cannot load client cert with id" - " '%s' [%s]", cert_file, - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - if(!params.cert) { - failf(data, "ssl engine did not initialized the certificate " - "properly."); - return 0; - } + case SSL_FILETYPE_ENGINE: + if(!engineload(data, ctx, cert_file)) + return CURLE_SSL_CERTPROBLEM; + break; - if(SSL_CTX_use_certificate(ctx, params.cert) != 1) { - failf(data, "unable to set client certificate [%s]", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - X509_free(params.cert); /* we do not need the handle any more... */ - } - else { - failf(data, "crypto engine not set, cannot load certificate"); - return 0; - } - } - break; -#endif -#if defined(OPENSSL_HAS_PROVIDERS) - /* fall through to compatible provider */ case SSL_FILETYPE_PROVIDER: - { - /* Implicitly use pkcs11 provider if none was provided and the - * cert_file is a PKCS#11 URI */ - if(!data->state.provider_loaded) { - if(is_pkcs11_uri(cert_file)) { - if(ossl_set_provider(data, "pkcs11") != CURLE_OK) { - return 0; - } - } - } - - if(data->state.provider_loaded) { - /* Load the certificate from the provider */ - OSSL_STORE_INFO *info = NULL; - X509 *cert = NULL; - OSSL_STORE_CTX *store = - OSSL_STORE_open_ex(cert_file, data->state.libctx, - NULL, NULL, NULL, NULL, NULL, NULL); - if(!store) { - failf(data, "Failed to open OpenSSL store: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - if(OSSL_STORE_expect(store, OSSL_STORE_INFO_CERT) != 1) { - failf(data, "Failed to set store preference. Ignoring the error: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - } - - info = OSSL_STORE_load(store); - if(info) { - int ossl_type = OSSL_STORE_INFO_get_type(info); - - if(ossl_type == OSSL_STORE_INFO_CERT) - cert = OSSL_STORE_INFO_get1_CERT(info); - OSSL_STORE_INFO_free(info); - } - OSSL_STORE_close(store); - if(!cert) { - failf(data, "No cert found in the openssl store: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - - if(SSL_CTX_use_certificate(ctx, cert) != 1) { - failf(data, "unable to set client certificate [%s]", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - X509_free(cert); /* we do not need the handle any more... */ - } - else { - failf(data, "crypto provider not set, cannot load certificate"); - return 0; - } - } - break; -#endif + if(!providerload(data, ctx, cert_file)) + return CURLE_SSL_CERTPROBLEM; + break; case SSL_FILETYPE_PKCS12: - { - BIO *cert_bio = NULL; - PKCS12 *p12 = NULL; - EVP_PKEY *pri; - STACK_OF(X509) *ca = NULL; - if(cert_blob) { - cert_bio = BIO_new_mem_buf(cert_blob->data, (int)(cert_blob->len)); - if(!cert_bio) { - failf(data, - "BIO_new_mem_buf NULL, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - return 0; - } - } - else { - cert_bio = BIO_new(BIO_s_file()); - if(!cert_bio) { - failf(data, - "BIO_new return NULL, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - return 0; - } - - if(BIO_read_filename(cert_bio, cert_file) <= 0) { - failf(data, "could not open PKCS12 file '%s'", cert_file); - BIO_free(cert_bio); - return 0; - } - } - - p12 = d2i_PKCS12_bio(cert_bio, NULL); - BIO_free(cert_bio); - - if(!p12) { - failf(data, "error reading PKCS12 file '%s'", - cert_blob ? "(memory blob)" : cert_file); - return 0; - } - - PKCS12_PBE_add(); - - if(!PKCS12_parse(p12, key_passwd, &pri, &x509, &ca)) { - failf(data, - "could not parse PKCS12 file, check password, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - PKCS12_free(p12); - return 0; - } - - PKCS12_free(p12); - - if(SSL_CTX_use_certificate(ctx, x509) != 1) { - failf(data, - "could not load PKCS12 client certificate, " OSSL_PACKAGE - " error %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer)) ); - goto fail; - } - - if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) { - failf(data, "unable to use private key from PKCS12 file '%s'", - cert_file); - goto fail; - } - - if(!SSL_CTX_check_private_key (ctx)) { - failf(data, "private key from PKCS12 file '%s' " - "does not match certificate in same file", cert_file); - goto fail; - } - /* Set Certificate Verification chain */ - if(ca) { - while(sk_X509_num(ca)) { - /* - * Note that sk_X509_pop() is used below to make sure the cert is - * removed from the stack properly before getting passed to - * SSL_CTX_add_extra_chain_cert(), which takes ownership. Previously - * we used sk_X509_value() instead, but then we would clean it in the - * subsequent sk_X509_pop_free() call. - */ - X509 *x = sk_X509_pop(ca); - if(!SSL_CTX_add_client_CA(ctx, x)) { - X509_free(x); - failf(data, "cannot add certificate to client CA list"); - goto fail; - } - if(!SSL_CTX_add_extra_chain_cert(ctx, x)) { - X509_free(x); - failf(data, "cannot add certificate to certificate chain"); - goto fail; - } - } - } - - cert_done = 1; -fail: - EVP_PKEY_free(pri); - X509_free(x509); - sk_X509_pop_free(ca, X509_free); - if(!cert_done) - return 0; /* failure! */ + if(!pkcs12load(data, ctx, cert_blob, cert_file, key_passwd)) + return CURLE_SSL_CERTPROBLEM; + pcks12_done = TRUE; break; - } + default: failf(data, "not supported file type '%s' for certificate", cert_type); - return 0; + return CURLE_BAD_FUNCTION_ARGUMENT; } if((!key_file) && (!key_blob)) { @@ -1568,9 +1737,6 @@ int cert_stuff(struct Curl_easy *data, switch(file_type) { case SSL_FILETYPE_PEM: - if(cert_done) - break; - FALLTHROUGH(); case SSL_FILETYPE_ASN1: cert_use_result = key_blob ? use_privatekey_blob(ctx, key_blob, file_type, key_passwd) : @@ -1579,153 +1745,34 @@ int cert_stuff(struct Curl_easy *data, failf(data, "unable to set private key file: '%s' type %s", key_file ? key_file : "(memory blob)", key_type ? key_type : "PEM"); - return 0; + return CURLE_BAD_FUNCTION_ARGUMENT; } break; case SSL_FILETYPE_ENGINE: -#ifdef USE_OPENSSL_ENGINE - { - EVP_PKEY *priv_key = NULL; - - /* Implicitly use pkcs11 engine if none was provided and the - * key_file is a PKCS#11 URI */ - if(!data->state.engine) { - if(is_pkcs11_uri(key_file)) { - if(ossl_set_engine(data, "pkcs11") != CURLE_OK) { - return 0; - } - } - } + if(!enginecheck(data, ctx, key_file, key_passwd)) + return CURLE_SSL_CERTPROBLEM; + break; - if(data->state.engine) { - UI_METHOD *ui_method = - UI_create_method(OSSL_UI_METHOD_CAST("curl user interface")); - if(!ui_method) { - failf(data, "unable do create " OSSL_PACKAGE - " user-interface method"); - return 0; - } - UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); - UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); - UI_method_set_reader(ui_method, ssl_ui_reader); - UI_method_set_writer(ui_method, ssl_ui_writer); - priv_key = ENGINE_load_private_key(data->state.engine, key_file, - ui_method, - key_passwd); - UI_destroy_method(ui_method); - if(!priv_key) { - failf(data, "failed to load private key from crypto engine"); - return 0; - } - if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { - failf(data, "unable to set private key"); - EVP_PKEY_free(priv_key); - return 0; - } - EVP_PKEY_free(priv_key); /* we do not need the handle any more... */ - } - else { - failf(data, "crypto engine not set, cannot load private key"); - return 0; - } - } - break; -#endif -#if defined(OPENSSL_HAS_PROVIDERS) - /* fall through to compatible provider */ case SSL_FILETYPE_PROVIDER: - { - /* Implicitly use pkcs11 provider if none was provided and the - * key_file is a PKCS#11 URI */ - if(!data->state.provider_loaded) { - if(is_pkcs11_uri(key_file)) { - if(ossl_set_provider(data, "pkcs11") != CURLE_OK) { - return 0; - } - } - } - - if(data->state.provider_loaded) { - /* Load the private key from the provider */ - EVP_PKEY *priv_key = NULL; - OSSL_STORE_CTX *store = NULL; - OSSL_STORE_INFO *info = NULL; - UI_METHOD *ui_method = - UI_create_method(OSSL_UI_METHOD_CAST("curl user interface")); - if(!ui_method) { - failf(data, "unable do create " OSSL_PACKAGE - " user-interface method"); - return 0; - } - UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL())); - UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL())); - UI_method_set_reader(ui_method, ssl_ui_reader); - UI_method_set_writer(ui_method, ssl_ui_writer); - - store = OSSL_STORE_open_ex(key_file, data->state.libctx, - data->state.propq, ui_method, NULL, NULL, - NULL, NULL); - if(!store) { - failf(data, "Failed to open OpenSSL store: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - if(OSSL_STORE_expect(store, OSSL_STORE_INFO_PKEY) != 1) { - failf(data, "Failed to set store preference. Ignoring the error: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - } - - info = OSSL_STORE_load(store); - if(info) { - int ossl_type = OSSL_STORE_INFO_get_type(info); - - if(ossl_type == OSSL_STORE_INFO_PKEY) - priv_key = OSSL_STORE_INFO_get1_PKEY(info); - OSSL_STORE_INFO_free(info); - } - OSSL_STORE_close(store); - UI_destroy_method(ui_method); - if(!priv_key) { - failf(data, "No private key found in the openssl store: %s", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - return 0; - } - - if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) { - failf(data, "unable to set private key [%s]", - ossl_strerror(ERR_get_error(), error_buffer, - sizeof(error_buffer))); - EVP_PKEY_free(priv_key); - return 0; - } - EVP_PKEY_free(priv_key); /* we do not need the handle any more... */ - } - else { - failf(data, "crypto provider not set, cannot load private key"); - return 0; - } - } - break; -#endif + if(!providercheck(data, ctx, key_file)) + return CURLE_SSL_CERTPROBLEM; + break; case SSL_FILETYPE_PKCS12: - if(!cert_done) { + if(!pcks12_done) { failf(data, "file type P12 for private key not supported"); - return 0; + return CURLE_SSL_CERTPROBLEM; } break; default: failf(data, "not supported file type for private key"); - return 0; + return CURLE_BAD_FUNCTION_ARGUMENT; } ssl = SSL_new(ctx); if(!ssl) { failf(data, "unable to create an SSL structure"); - return 0; + return CURLE_OUT_OF_MEMORY; } x509 = SSL_get_certificate(ssl); @@ -1738,8 +1785,7 @@ int cert_stuff(struct Curl_easy *data, EVP_PKEY_free(pktmp); } -#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_IS_BORINGSSL) && \ - !defined(OPENSSL_NO_DEPRECATED_3_0) +#if !defined(OPENSSL_NO_RSA) && !defined(OPENSSL_NO_DEPRECATED_3_0) { /* If RSA is used, do not check the private key if its flags indicate * it does not support it. */ @@ -1769,11 +1815,11 @@ int cert_stuff(struct Curl_easy *data, * the SSL context */ if(!SSL_CTX_check_private_key(ctx)) { failf(data, "Private key does not match the certificate public key"); - return 0; + return CURLE_SSL_CERTPROBLEM; } } } - return 1; + return CURLE_OK; } /* returns non-zero on failure */ @@ -1785,8 +1831,10 @@ static CURLcode x509_name_oneline(X509_NAME *a, struct dynbuf *d) CURLcode result = CURLE_OUT_OF_MEMORY; if(bio_out) { + unsigned long flags = XN_FLAG_SEP_SPLUS_SPC | + (XN_FLAG_ONELINE & ~ASN1_STRFLGS_ESC_MSB & ~XN_FLAG_SPC_EQ); curlx_dyn_reset(d); - rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC); + rc = X509_NAME_print_ex(bio_out, a, 0, flags); if(rc != -1) { BIO_get_mem_ptr(bio_out, &biomem); result = curlx_dyn_addn(d, biomem->data, biomem->length); @@ -1824,12 +1872,6 @@ static int ossl_init(void) ENGINE_load_builtin_engines(); #endif -/* CONF_MFLAGS_DEFAULT_SECTION was introduced some time between 0.9.8b and - 0.9.8e */ -#ifndef CONF_MFLAGS_DEFAULT_SECTION -#define CONF_MFLAGS_DEFAULT_SECTION 0x0 -#endif - #ifndef CURL_DISABLE_OPENSSL_AUTO_LOAD_CONFIG CONF_modules_load_file(NULL, NULL, CONF_MFLAGS_DEFAULT_SECTION| @@ -1940,7 +1982,7 @@ static CURLcode ossl_set_engine_default(struct Curl_easy *data) } } #else - (void) data; + (void)data; #endif return CURLE_OK; } @@ -1963,11 +2005,11 @@ static struct curl_slist *ossl_engines_list(struct Curl_easy *data) list = beg; } #endif - (void) data; + (void)data; return list; } -#if defined(OPENSSL_HAS_PROVIDERS) +#ifdef OPENSSL_HAS_PROVIDERS static void ossl_provider_cleanup(struct Curl_easy *data) { @@ -2242,28 +2284,6 @@ static void ossl_close_all(struct Curl_easy *data) /* ====================================================== */ -/* - * Match subjectAltName against the hostname. - */ -static bool subj_alt_hostcheck(struct Curl_easy *data, - const char *match_pattern, - size_t matchlen, - const char *hostname, - size_t hostlen, - const char *dispname) -{ -#ifdef CURL_DISABLE_VERBOSE_STRINGS - (void)dispname; - (void)data; -#endif - if(Curl_cert_hostcheck(match_pattern, matchlen, hostname, hostlen)) { - infof(data, " subjectAltName: host \"%s\" matched cert's \"%s\"", - dispname, match_pattern); - return TRUE; - } - return FALSE; -} - /* Quote from RFC2818 section 3.1 "Server Identity" If a subjectAltName extension of type dNSName is present, that MUST @@ -2288,7 +2308,8 @@ static bool subj_alt_hostcheck(struct Curl_easy *data, */ static CURLcode ossl_verifyhost(struct Curl_easy *data, struct connectdata *conn, - struct ssl_peer *peer, X509 *server_cert) + struct ssl_peer *peer, + X509 *server_cert) { bool matched = FALSE; int target; /* target type, GEN_DNS or GEN_IPADD */ @@ -2302,10 +2323,9 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, CURLcode result = CURLE_OK; bool dNSName = FALSE; /* if a dNSName field exists in the cert */ bool iPAddress = FALSE; /* if an iPAddress field exists in the cert */ - size_t hostlen; + size_t hostlen = strlen(peer->hostname); (void)conn; - hostlen = strlen(peer->hostname); switch(peer->type) { case CURL_SSL_PEER_IPV4: if(!curlx_inet_pton(AF_INET, peer->hostname, &addr)) @@ -2334,22 +2354,20 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL); if(altnames) { -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#ifdef HAVE_BORINGSSL_LIKE size_t numalts; size_t i; #else int numalts; int i; #endif - bool dnsmatched = FALSE; - bool ipmatched = FALSE; /* get amount of alternatives, RFC2459 claims there MUST be at least one, but we do not depend on it... */ numalts = sk_GENERAL_NAME_num(altnames); /* loop through all alternatives - until a dnsmatch */ - for(i = 0; (i < numalts) && !dnsmatched; i++) { + for(i = 0; (i < numalts) && !matched; i++) { /* get a handle to alternative name number i */ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i); @@ -2378,10 +2396,10 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, if((altlen == strlen(altptr)) && /* if this is not true, there was an embedded zero in the name string and we cannot match it. */ - subj_alt_hostcheck(data, altptr, altlen, - peer->hostname, hostlen, - peer->dispname)) { - dnsmatched = TRUE; + Curl_cert_hostcheck(altptr, altlen, peer->hostname, hostlen)) { + matched = TRUE; + infof(data, " subjectAltName: host \"%s\" matched cert's \"%.*s\"", + peer->dispname, (int)altlen, altptr); } break; @@ -2389,7 +2407,7 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, /* compare alternative IP address if the data chunk is the same size our server IP address is */ if((altlen == addrlen) && !memcmp(altptr, &addr, altlen)) { - ipmatched = TRUE; + matched = TRUE; infof(data, " subjectAltName: host \"%s\" matched cert's IP address!", peer->dispname); @@ -2399,9 +2417,6 @@ static CURLcode ossl_verifyhost(struct Curl_easy *data, } } GENERAL_NAMES_free(altnames); - - if(dnsmatched || ipmatched) - matched = TRUE; } if(matched) @@ -2495,7 +2510,7 @@ static CURLcode verifystatus(struct Curl_cfilter *cf, struct ossl_ctx *octx) { int i, ocsp_status; -#ifdef OPENSSL_IS_AWSLC +#ifdef HAVE_BORINGSSL_LIKE const uint8_t *status; #else unsigned char *status; @@ -2628,15 +2643,9 @@ static CURLcode verifystatus(struct Curl_cfilter *cf, } #endif -#endif /* USE_OPENSSL */ - -/* The SSL_CTRL_SET_MSG_CALLBACK does not exist in ancient OpenSSL versions - and thus this cannot be done there. */ -#ifdef SSL_CTRL_SET_MSG_CALLBACK - static const char *ssl_msg_type(int ssl_ver, int msg) { -#ifdef SSL2_VERSION_MAJOR +#ifdef SSL2_VERSION_MAJOR /* OpenSSL 1.0.2, LibreSSL <=3.9.2 */ if(ssl_ver == SSL2_VERSION_MAJOR) { switch(msg) { case SSL2_MT_ERROR: @@ -2782,7 +2791,7 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, verstr = "TLSv1.2"; break; #endif -#ifdef TLS1_3_VERSION +#ifdef TLS1_3_VERSION /* OpenSSL 1.1.1+, all forks */ case TLS1_3_VERSION: verstr = "TLSv1.3"; break; @@ -2846,19 +2855,15 @@ static void ossl_trace(int direction, int ssl_ver, int content_type, Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT : CURLINFO_SSL_DATA_IN, (const char *)buf, len); - (void) ssl; + (void)ssl; } -#endif - -#ifdef USE_OPENSSL -/* ====================================================== */ /* Check for ALPN support. */ #ifndef OPENSSL_NO_TLSEXT # define HAS_ALPN_OPENSSL #endif -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ static CURLcode ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) { @@ -2868,9 +2873,7 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) long curl_ssl_version_max; /* convert curl min SSL version option to OpenSSL constant */ -#if (defined(OPENSSL_IS_BORINGSSL) || \ - defined(OPENSSL_IS_AWSLC) || \ - defined(LIBRESSL_VERSION_NUMBER)) +#if defined(HAVE_BORINGSSL_LIKE) || defined(LIBRESSL_VERSION_NUMBER) uint16_t ossl_ssl_version_min = 0; uint16_t ossl_ssl_version_max = 0; #else @@ -2947,9 +2950,9 @@ ossl_set_ssl_version_min_max(struct Curl_cfilter *cf, SSL_CTX *ctx) } #endif -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#ifdef HAVE_BORINGSSL_LIKE typedef uint32_t ctx_option_t; -#elif OPENSSL_VERSION_NUMBER >= 0x30000000L +#elif defined(HAVE_OPENSSL3) typedef uint64_t ctx_option_t; #elif OPENSSL_VERSION_NUMBER >= 0x10100000L && \ !defined(LIBRESSL_VERSION_NUMBER) @@ -2958,7 +2961,7 @@ typedef unsigned long ctx_option_t; typedef long ctx_option_t; #endif -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) /* 1.1.0 */ +#if OPENSSL_VERSION_NUMBER < 0x10100000L /* 1.1.0 */ static CURLcode ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, struct Curl_cfilter *cf, @@ -2968,7 +2971,7 @@ ossl_set_ssl_version_min_max_legacy(ctx_option_t *ctx_options, long ssl_version = conn_config->version; long ssl_version_max = conn_config->version_max; - (void) data; /* In case it is unused. */ + (void)data; /* In case it is unused. */ switch(ssl_version) { case CURL_SSLVERSION_TLSv1_3: @@ -3373,7 +3376,7 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, } if(ssl_cafile || ssl_capath) { -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#ifdef HAVE_OPENSSL3 /* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */ if(ssl_cafile && !X509_STORE_load_file(store, ssl_cafile)) { if(!imported_native_ca && !imported_ca_info_blob) { @@ -3450,10 +3453,7 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, https://web.archive.org/web/20190422050538/ rt.openssl.org/Ticket/Display.html?id=3621 */ -#ifdef X509_V_FLAG_TRUSTED_FIRST X509_STORE_set_flags(store, X509_V_FLAG_TRUSTED_FIRST); -#endif -#ifdef X509_V_FLAG_PARTIAL_CHAIN if(!ssl_config->no_partialchain && !ssl_crlfile) { /* Have intermediate certificates in the trust store be treated as trust-anchors, in the same way as self-signed root CA certificates @@ -3465,7 +3465,6 @@ static CURLcode ossl_populate_x509_store(struct Curl_cfilter *cf, */ X509_STORE_set_flags(store, X509_V_FLAG_PARTIAL_CHAIN); } -#endif } return result; @@ -3613,6 +3612,8 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, !ssl_config->primary.CRLfile && !ssl_config->native_ca_store; + ERR_set_mark(); + cached_store = ossl_get_cached_x509_store(cf, data); if(cached_store && cache_criteria_met && X509_STORE_up_ref(cached_store)) { SSL_CTX_set_cert_store(ssl_ctx, cached_store); @@ -3626,6 +3627,8 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, } } + ERR_pop_to_mark(); + return result; } #else /* HAVE_SSL_X509_STORE_SHARE */ @@ -3633,9 +3636,17 @@ CURLcode Curl_ssl_setup_x509_store(struct Curl_cfilter *cf, struct Curl_easy *data, SSL_CTX *ssl_ctx) { - X509_STORE *store = SSL_CTX_get_cert_store(ssl_ctx); + CURLcode result; + X509_STORE *store; + + ERR_set_mark(); - return ossl_populate_x509_store(cf, data, store); + store = SSL_CTX_get_cert_store(ssl_ctx); + result = ossl_populate_x509_store(cf, data, store); + + ERR_pop_to_mark(); + + return result; } #endif /* HAVE_SSL_X509_STORE_SHARE */ @@ -3746,14 +3757,14 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx, if(data->set.tls_ech & CURLECH_GREASE) { infof(data, "ECH: will GREASE ClientHello"); -# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +# ifdef HAVE_BORINGSSL_LIKE SSL_set_enable_ech_grease(octx->ssl, 1); # else SSL_set_options(octx->ssl, SSL_OP_ECH_GREASE); # endif } else if(data->set.tls_ech & CURLECH_CLA_CFG) { -# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +# ifdef HAVE_BORINGSSL_LIKE /* have to do base64 decode here for BoringSSL */ const char *b64 = data->set.str[STRING_ECH_CONFIG]; @@ -3834,7 +3845,7 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx, Curl_resolv_unlink(data, &dns); } } -# if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +# ifdef HAVE_BORINGSSL_LIKE if(trying_ech_now && outername) { infof(data, "ECH: setting public_name not supported with BoringSSL"); return CURLE_SSL_CONNECT_ERROR; @@ -3851,7 +3862,7 @@ static CURLcode ossl_init_ech(struct ossl_ctx *octx, return CURLE_SSL_CONNECT_ERROR; } } -# endif /* OPENSSL_IS_BORINGSSL || OPENSSL_IS_AWSLC */ +# endif /* HAVE_BORINGSSL_LIKE */ if(trying_ech_now && SSL_set_min_proto_version(octx->ssl, TLS1_3_VERSION) != 1) { infof(data, "ECH: cannot force TLSv1.3 [ERROR]"); @@ -3887,15 +3898,9 @@ static CURLcode ossl_init_ssl(struct ossl_ctx *octx, SSL_set_tlsext_status_type(octx->ssl, TLSEXT_STATUSTYPE_ocsp); #endif -#if (defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC)) && \ - defined(ALLOW_RENEG) - SSL_set_renegotiate_mode(octx->ssl, ssl_renegotiate_freely); -#endif - SSL_set_connect_state(octx->ssl); octx->server_cert = NULL; -#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME if(peer->sni) { if(!SSL_set_tlsext_host_name(octx->ssl, peer->sni)) { failf(data, "Failed set SNI"); @@ -3909,9 +3914,7 @@ static CURLcode ossl_init_ssl(struct ossl_ctx *octx, if(result) return result; } -#endif /* USE_ECH_OPENSSL */ - -#endif +#endif /* USE_ECH_OPENSSL */ return ossl_init_session_and_alpns(octx, cf, data, peer, alpns_requested, sess_reuse_cb); @@ -3939,11 +3942,11 @@ static CURLcode ossl_init_method(struct Curl_cfilter *cf, case CURL_SSLVERSION_TLSv1_2: case CURL_SSLVERSION_TLSv1_3: /* it will be handled later with the context options */ - #if (OPENSSL_VERSION_NUMBER >= 0x10100000L) +#if OPENSSL_VERSION_NUMBER >= 0x10100000L *pmethod = TLS_client_method(); - #else +#else *pmethod = SSLv23_client_method(); - #endif +#endif break; case CURL_SSLVERSION_SSLv2: failf(data, "No SSLv2 support"); @@ -4037,13 +4040,11 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, return result; } -#ifdef SSL_CTRL_SET_MSG_CALLBACK if(data->set.fdebug && data->set.verbose) { /* the SSL trace callback is only used for verbose logging */ SSL_CTX_set_msg_callback(octx->ssl_ctx, ossl_trace); SSL_CTX_set_msg_callback_arg(octx->ssl_ctx, cf); } -#endif /* OpenSSL contains code to work around lots of bugs and flaws in various SSL-implementations. SSL_CTX_set_options() is used to enabled those @@ -4081,27 +4082,15 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit must not be set. */ - ctx_options = SSL_OP_ALL; - -#ifdef SSL_OP_NO_TICKET - ctx_options |= SSL_OP_NO_TICKET; -#endif - -#ifdef SSL_OP_NO_COMPRESSION - ctx_options |= SSL_OP_NO_COMPRESSION; -#endif + ctx_options = SSL_OP_ALL | SSL_OP_NO_TICKET | SSL_OP_NO_COMPRESSION; -#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG /* mitigate CVE-2010-4180 */ ctx_options &= ~(ctx_option_t)SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG; -#endif -#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS /* unless the user explicitly asks to allow the protocol vulnerability we use the work-around */ if(!ssl_config->enable_beast) ctx_options &= ~(ctx_option_t)SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; -#endif switch(ssl_version_min) { case CURL_SSLVERSION_SSLv2: @@ -4120,12 +4109,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, ctx_options |= SSL_OP_NO_SSLv2; ctx_options |= SSL_OP_NO_SSLv3; -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) /* 1.1.0 */ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L /* 1.1.0 */ result = ossl_set_ssl_version_min_max(cf, octx->ssl_ctx); #else result = ossl_set_ssl_version_min_max_legacy(&ctx_options, cf, data); #endif - if(result != CURLE_OK) + if(result) return result; break; @@ -4146,15 +4135,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, However using a large buffer (8 packets) actually decreases performance. 4 packets is better. */ - #ifdef HAVE_SSL_CTX_SET_DEFAULT_READ_BUFFER_LEN SSL_CTX_set_default_read_buffer_len(octx->ssl_ctx, 0x401e * 4); #endif -#ifdef SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER /* We do retry writes sometimes from another buffer address */ SSL_CTX_set_mode(octx->ssl_ctx, SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER); -#endif ciphers = conn_config->cipher_list; if(!ciphers && (peer->transport != TRNSPRT_QUIC)) @@ -4183,14 +4169,12 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, #endif if(ssl_cert || ssl_cert_blob || ssl_cert_type) { - if(!result && - !cert_stuff(data, octx->ssl_ctx, - ssl_cert, ssl_cert_blob, ssl_cert_type, - ssl_config->key, ssl_config->key_blob, - ssl_config->key_type, ssl_config->key_passwd)) - result = CURLE_SSL_CERTPROBLEM; + result = client_cert(data, octx->ssl_ctx, + ssl_cert, ssl_cert_blob, ssl_cert_type, + ssl_config->key, ssl_config->key_blob, + ssl_config->key_type, ssl_config->key_passwd); if(result) - /* failf() is already done in cert_stuff() */ + /* failf() is already done in client_cert() */ return result; } @@ -4202,7 +4186,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, { const char *curves = conn_config->curves; if(curves) { -#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#ifdef HAVE_BORINGSSL_LIKE #define OSSL_CURVE_CAST(x) (x) #else #define OSSL_CURVE_CAST(x) (char *)CURL_UNCONST(x) @@ -4229,7 +4213,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, } #endif -#ifdef USE_OPENSSL_SRP +#if defined(HAVE_OPENSSL_SRP) && defined(USE_TLS_SRP) if(ssl_config->primary.username && Curl_auth_allowed_to_host(data)) { char * const ssl_username = ssl_config->primary.username; char * const ssl_password = ssl_config->primary.password; @@ -4252,7 +4236,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, } } } -#endif +#endif /* HAVE_OPENSSL_SRP && USE_TLS_SRP */ /* OpenSSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue @@ -4342,9 +4326,9 @@ void Curl_ossl_report_handshake(struct Curl_easy *data, int psigtype_nid = NID_undef; const char *negotiated_group_name = NULL; -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#ifdef HAVE_OPENSSL3 SSL_get_peer_signature_type_nid(octx->ssl, &psigtype_nid); -#if (OPENSSL_VERSION_NUMBER >= 0x30200000L) +#if OPENSSL_VERSION_NUMBER >= 0x30200000L negotiated_group_name = SSL_get0_group_name(octx->ssl); #else negotiated_group_name = @@ -4425,7 +4409,7 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, CURLcode result = CURLE_OK; size_t rcl = 0; int rv = 1; -# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +# ifndef HAVE_BORINGSSL_LIKE char *inner = NULL; unsigned char *rcs = NULL; char *outer = NULL; @@ -4440,7 +4424,7 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, /* nothing to trace if not doing ECH */ if(!ECH_ENABLED(data)) return; -# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +# ifndef HAVE_BORINGSSL_LIKE rv = SSL_ech_get1_retry_config(ssl, &rcs, &rcl); # else SSL_get0_ech_retry_configs(ssl, &rcs, &rcl); @@ -4455,7 +4439,7 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, if(!result && b64str) { infof(data, "ECH: retry_configs %s", b64str); free(b64str); -#if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +#ifndef HAVE_BORINGSSL_LIKE rv = SSL_ech_get1_status(ssl, &inner, &outer); infof(data, "ECH: retry_configs for %s from %s, %d %d", inner ? inner : "NULL", outer ? outer : "NULL", reason, rv); @@ -4471,7 +4455,7 @@ static void ossl_trace_ech_retry_configs(struct Curl_easy *data, SSL* ssl, } else infof(data, "ECH: no retry_configs (rv = %d)", rv); -# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +# ifndef HAVE_BORINGSSL_LIKE OPENSSL_free((void *)rcs); # endif return; @@ -4514,7 +4498,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, /* 1 is fine 0 is "not successful but was shut down controlled" <0 is "handshake was not successful, because a fatal error occurred" */ - if(1 != err) { + if(err != 1) { int detail = SSL_get_error(octx->ssl, err); CURL_TRC_CF(data, cf, "SSL_connect() -> err=%d, detail=%d", err, detail); @@ -4538,7 +4522,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, #ifdef SSL_ERROR_WANT_RETRY_VERIFY if(SSL_ERROR_WANT_RETRY_VERIFY == detail) { CURL_TRC_CF(data, cf, "SSL_connect() -> want retry_verify"); - connssl->io_need = CURL_SSL_IO_NEED_RECV; + Curl_xfer_pause_recv(data, TRUE); return CURLE_AGAIN; } #endif @@ -4590,7 +4574,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, #endif #ifdef USE_ECH_OPENSSL else if((lib == ERR_LIB_SSL) && -# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +# ifndef HAVE_BORINGSSL_LIKE (reason == SSL_R_ECH_REQUIRED)) { # else (reason == SSL_R_ECH_REJECTED)) { @@ -4635,8 +4619,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, connssl->connecting_state = ssl_connect_3; Curl_ossl_report_handshake(data, octx); -#ifdef USE_ECH_OPENSSL -# if !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +#if defined(USE_ECH_OPENSSL) && !defined(HAVE_BORINGSSL_LIKE) if(ECH_ENABLED(data)) { char *inner = NULL, *outer = NULL; const char *status = NULL; @@ -4694,8 +4677,7 @@ static CURLcode ossl_connect_step2(struct Curl_cfilter *cf, else { infof(data, "ECH: result: status is not attempted"); } -# endif /* !OPENSSL_IS_BORINGSSL && !OPENSSL_IS_AWSLC */ -#endif /* USE_ECH_OPENSSL */ +#endif /* USE_ECH_OPENSSL && !HAVE_BORINGSSL_LIKE */ #ifdef HAS_ALPN_OPENSSL /* Sets data and len to negotiated protocol, len is 0 if no protocol was @@ -4772,12 +4754,10 @@ static CURLcode ossl_pkp_pin_peer_pubkey(struct Curl_easy *data, X509* cert, return result; } -#if (OPENSSL_VERSION_NUMBER >= 0x10100000L) && \ +#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \ !(defined(LIBRESSL_VERSION_NUMBER) && \ LIBRESSL_VERSION_NUMBER < 0x3060000fL) && \ - !defined(OPENSSL_IS_BORINGSSL) && \ - !defined(OPENSSL_IS_AWSLC) && \ - !defined(CURL_DISABLE_VERBOSE_STRINGS) + !defined(HAVE_BORINGSSL_LIKE) && !defined(CURL_DISABLE_VERBOSE_STRINGS) static void infof_certstack(struct Curl_easy *data, const SSL *ssl) { STACK_OF(X509) *certstack; @@ -4812,11 +4792,11 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl) current_pkey = X509_get0_pubkey(current_cert); key_bits = EVP_PKEY_bits(current_pkey); -#if (OPENSSL_VERSION_NUMBER < 0x30000000L) +#ifndef HAVE_OPENSSL3 #define EVP_PKEY_get_security_bits EVP_PKEY_security_bits #endif key_sec_bits = EVP_PKEY_get_security_bits(current_pkey); -#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) +#ifdef HAVE_OPENSSL3 { char group_name[80] = ""; get_group_name = EVP_PKEY_get_group_name(current_pkey, group_name, @@ -4843,10 +4823,10 @@ static void infof_certstack(struct Curl_easy *data, const SSL *ssl) #define MAX_CERT_NAME_LENGTH 2048 -CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct ossl_ctx *octx, - struct ssl_peer *peer) +CURLcode Curl_ossl_check_peer_cert(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ossl_ctx *octx, + struct ssl_peer *peer) { struct connectdata *conn = cf->conn; struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); @@ -4867,8 +4847,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, if(!mem) { failf(data, - "BIO_new return NULL, " OSSL_PACKAGE - " error %s", + "BIO_new return NULL, " OSSL_PACKAGE " error %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); return CURLE_OUT_OF_MEMORY; @@ -4944,8 +4923,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, (int)conn_config->issuercert_blob->len); if(!fp) { failf(data, - "BIO_new_mem_buf NULL, " OSSL_PACKAGE - " error %s", + "BIO_new_mem_buf NULL, " OSSL_PACKAGE " error %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); X509_free(octx->server_cert); @@ -4957,8 +4935,7 @@ CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, fp = BIO_new(BIO_s_file()); if(!fp) { failf(data, - "BIO_new return NULL, " OSSL_PACKAGE - " error %s", + "BIO_new return NULL, " OSSL_PACKAGE " error %s", ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)) ); X509_free(octx->server_cert); @@ -5078,7 +5055,7 @@ static CURLcode ossl_connect_step3(struct Curl_cfilter *cf, * operations. */ - result = Curl_oss_check_peer_cert(cf, data, octx, &connssl->peer); + result = Curl_ossl_check_peer_cert(cf, data, octx, &connssl->peer); if(result) /* on error, remove sessions we might have in the pool */ Curl_ssl_scache_remove_all(cf, data, connssl->peer.scache_key); @@ -5274,6 +5251,17 @@ static CURLcode ossl_send(struct Curl_cfilter *cf, connssl->io_need = CURL_SSL_IO_NEED_NONE; memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len; + if(octx->blocked_ssl_write_len && (octx->blocked_ssl_write_len != memlen)) { + /* The previous SSL_write() call was blocked, using that length. + * We need to use that again or OpenSSL will freak out. A shorter + * length should not happen and is a bug in libcurl. */ + if(octx->blocked_ssl_write_len > memlen) { + DEBUGASSERT(0); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + memlen = octx->blocked_ssl_write_len; + } + octx->blocked_ssl_write_len = 0; nwritten = SSL_write(octx->ssl, mem, memlen); if(nwritten > 0) @@ -5284,16 +5272,19 @@ static CURLcode ossl_send(struct Curl_cfilter *cf, switch(err) { case SSL_ERROR_WANT_READ: connssl->io_need = CURL_SSL_IO_NEED_RECV; + octx->blocked_ssl_write_len = memlen; result = CURLE_AGAIN; goto out; case SSL_ERROR_WANT_WRITE: result = CURLE_AGAIN; + octx->blocked_ssl_write_len = memlen; goto out; case SSL_ERROR_SYSCALL: { int sockerr = SOCKERRNO; if(octx->io_result == CURLE_AGAIN) { + octx->blocked_ssl_write_len = memlen; result = CURLE_AGAIN; goto out; } @@ -5526,9 +5517,9 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, int sockindex, return CURLE_OK; #else /* No X509_get_signature_nid support */ - (void)data; /* unused */ - (void)sockindex; /* unused */ - (void)binding; /* unused */ + (void)data; + (void)sockindex; + (void)binding; return CURLE_OK; #endif } @@ -5552,16 +5543,14 @@ size_t Curl_ossl_version(char *buffer, size_t size) #elif defined(OPENSSL_IS_BORINGSSL) #ifdef CURL_BORINGSSL_VERSION return msnprintf(buffer, size, "%s/%s", - OSSL_PACKAGE, - CURL_BORINGSSL_VERSION); + OSSL_PACKAGE, CURL_BORINGSSL_VERSION); #else return msnprintf(buffer, size, OSSL_PACKAGE); #endif #elif defined(OPENSSL_IS_AWSLC) return msnprintf(buffer, size, "%s/%s", - OSSL_PACKAGE, - AWSLC_VERSION_NUMBER_STRING); -#elif defined(HAVE_OPENSSL_VERSION) && defined(OPENSSL_VERSION_STRING) + OSSL_PACKAGE, AWSLC_VERSION_NUMBER_STRING); +#elif defined(OPENSSL_VERSION_STRING) /* OpenSSL 3+ */ return msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING)); #else @@ -5596,7 +5585,7 @@ size_t Curl_ossl_version(char *buffer, size_t size) (ssleay_value >> 20) & 0xff, (ssleay_value >> 12) & 0xff, sub); -#endif /* OPENSSL_IS_BORINGSSL */ +#endif } /* can be called with data == NULL */ @@ -5625,7 +5614,7 @@ static CURLcode ossl_sha256sum(const unsigned char *tmp, /* input */ { EVP_MD_CTX *mdctx; unsigned int len = 0; - (void) unused; + (void)unused; mdctx = EVP_MD_CTX_create(); if(!mdctx) diff --git a/deps/curl/lib/vtls/openssl.h b/deps/curl/lib/vtls/openssl.h index 1338eafb585..e263ee2eb26 100644 --- a/deps/curl/lib/vtls/openssl.h +++ b/deps/curl/lib/vtls/openssl.h @@ -37,6 +37,14 @@ #include "../urldata.h" +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +#define HAVE_OPENSSL3 /* non-fork OpenSSL 3.x or later */ +#endif + +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) +#define HAVE_BORINGSSL_LIKE +#endif + /* * Whether SSL_CTX_set_keylog_callback is available. * OpenSSL: supported since 1.1.1 https://github.com/openssl/openssl/pull/2287 @@ -44,15 +52,13 @@ * LibreSSL: not supported. 3.5.0+ has a stub function that does nothing. */ #if (OPENSSL_VERSION_NUMBER >= 0x10101000L && \ - !defined(LIBRESSL_VERSION_NUMBER)) || \ - defined(OPENSSL_IS_BORINGSSL) + !defined(LIBRESSL_VERSION_NUMBER)) || defined(HAVE_BORINGSSL_LIKE) #define HAVE_KEYLOG_CALLBACK #endif /* Check for OpenSSL 1.1.1 which has early data support. */ #undef HAVE_OPENSSL_EARLYDATA -#if OPENSSL_VERSION_NUMBER >= 0x10100010L && defined(TLS1_3_VERSION) && \ - !defined(OPENSSL_IS_BORINGSSL) && !defined(OPENSSL_IS_AWSLC) +#if defined(TLS1_3_VERSION) && !defined(HAVE_BORINGSSL_LIKE) #define HAVE_OPENSSL_EARLYDATA #endif @@ -68,6 +74,8 @@ struct ossl_ctx { X509* server_cert; BIO_METHOD *bio_method; CURLcode io_result; /* result of last BIO cfilter operation */ + /* blocked writes need to retry with same length, remember it */ + int blocked_ssl_write_len; #ifndef HAVE_KEYLOG_CALLBACK /* Set to true once a valid keylog entry has been created to avoid dupes. This is a bool and not a bitfield because it is passed by address. */ @@ -101,7 +109,7 @@ CURLcode Curl_ossl_ctx_init(struct ossl_ctx *octx, void *ssl_user_data, Curl_ossl_init_session_reuse_cb *sess_reuse_cb); -#if (OPENSSL_VERSION_NUMBER < 0x30000000L) +#ifndef HAVE_OPENSSL3 #define SSL_get1_peer_certificate SSL_get_peer_certificate #endif @@ -137,10 +145,10 @@ CURLcode Curl_ossl_add_session(struct Curl_cfilter *cf, * ssl config verifypeer or -host is set. Otherwise all this is for * informational purposes only! */ -CURLcode Curl_oss_check_peer_cert(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct ossl_ctx *octx, - struct ssl_peer *peer); +CURLcode Curl_ossl_check_peer_cert(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct ossl_ctx *octx, + struct ssl_peer *peer); /* Report properties of a successful handshake */ void Curl_ossl_report_handshake(struct Curl_easy *data, diff --git a/deps/curl/lib/vtls/rustls.c b/deps/curl/lib/vtls/rustls.c index 4e1b78a759d..221a7a6215a 100644 --- a/deps/curl/lib/vtls/rustls.c +++ b/deps/curl/lib/vtls/rustls.c @@ -393,9 +393,11 @@ cr_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* A server certificate verify callback for Rustls that always returns RUSTLS_RESULT_OK, or in other words disable certificate verification. */ static uint32_t -cr_verify_none(void *userdata UNUSED_PARAM, - const rustls_verify_server_cert_params *params UNUSED_PARAM) +cr_verify_none(void *userdata, + const rustls_verify_server_cert_params *params) { + (void)userdata; + (void)params; return RUSTLS_RESULT_OK; } @@ -583,7 +585,7 @@ init_config_builder(struct Curl_easy *data, goto cleanup; } -#if defined(USE_ECH) +#ifdef USE_ECH if(ECH_ENABLED(data)) { tls_versions[0] = RUSTLS_TLS_VERSION_TLSV1_3; tls_versions_len = 1; @@ -918,7 +920,7 @@ init_config_builder_client_auth(struct Curl_easy *data, return result; } -#if defined(USE_ECH) +#ifdef USE_ECH static CURLcode init_config_builder_ech(struct Curl_easy *data, const struct ssl_connect_data *connssl, @@ -1077,7 +1079,7 @@ cr_init_backend(struct Curl_cfilter *cf, struct Curl_easy *data, } } -#if defined(USE_ECH) +#ifdef USE_ECH if(ECH_ENABLED(data)) { result = init_config_builder_ech(data, connssl, config_builder); if(result != CURLE_OK && data->set.tls_ech & CURLECH_HARD) { @@ -1295,12 +1297,13 @@ cr_connect(struct Curl_cfilter *cf, static void * cr_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info) { struct rustls_ssl_backend_data *backend = (struct rustls_ssl_backend_data *)connssl->backend; + (void)info; DEBUGASSERT(backend); - return &backend->conn; + return backend->conn; } static CURLcode diff --git a/deps/curl/lib/vtls/schannel.c b/deps/curl/lib/vtls/schannel.c index 2ac61ba7946..1afc6790cc5 100644 --- a/deps/curl/lib/vtls/schannel.c +++ b/deps/curl/lib/vtls/schannel.c @@ -57,6 +57,7 @@ #include "../curlx/version_win32.h" #include "../rand.h" #include "../curlx/strparse.h" +#include "../progress.h" /* The last #include file should be: */ #include "../curl_memory.h" @@ -65,62 +66,37 @@ /* Some verbose debug messages are wrapped by SCH_DEV() instead of DEBUGF() * and only shown if CURL_SCHANNEL_DEV_DEBUG was defined at build time. These * messages are extra verbose and intended for curl developers debugging - * Schannel recv decryption. + * Schannel recv decryption and renegotiation. */ #ifdef CURL_SCHANNEL_DEV_DEBUG #define SCH_DEV(x) x +#define SCH_DEV_SHOWBOOL(x) \ + infof(data, "schannel: " #x " %s", (x) ? "TRUE" : "FALSE"); #else #define SCH_DEV(x) do { } while(0) +#define SCH_DEV_SHOWBOOL(x) do { } while(0) #endif -#ifndef BCRYPT_CHAIN_MODE_CCM -#define BCRYPT_CHAIN_MODE_CCM L"ChainingModeCCM" -#endif - -#ifndef BCRYPT_CHAIN_MODE_GCM -#define BCRYPT_CHAIN_MODE_GCM L"ChainingModeGCM" -#endif - -#ifndef BCRYPT_AES_ALGORITHM -#define BCRYPT_AES_ALGORITHM L"AES" -#endif - -#ifndef BCRYPT_SHA256_ALGORITHM -#define BCRYPT_SHA256_ALGORITHM L"SHA256" -#endif - -#ifndef BCRYPT_SHA384_ALGORITHM -#define BCRYPT_SHA384_ALGORITHM L"SHA384" -#endif - -#ifdef HAS_CLIENT_CERT_PATH -#ifdef UNICODE -#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W -#else -#define CURL_CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_A -#endif -#endif - +/* Offered by mingw-w64 v8+. MS SDK 7.0A+. */ #ifndef SP_PROT_TLS1_0_CLIENT #define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT #endif - #ifndef SP_PROT_TLS1_1_CLIENT #define SP_PROT_TLS1_1_CLIENT 0x00000200 #endif - #ifndef SP_PROT_TLS1_2_CLIENT #define SP_PROT_TLS1_2_CLIENT 0x00000800 #endif +/* Offered by mingw-w64 v8+. MS SDK ~10+/~VS2017+. */ #ifndef SP_PROT_TLS1_3_CLIENT #define SP_PROT_TLS1_3_CLIENT 0x00002000 #endif - #ifndef SCH_USE_STRONG_CRYPTO #define SCH_USE_STRONG_CRYPTO 0x00400000 #endif +/* Offered by mingw-w64 v10+. MS SDK 7.0A+. */ #ifndef SECBUFFER_ALERT #define SECBUFFER_ALERT 17 #endif @@ -137,6 +113,7 @@ * #define failf(x, y, ...) printf(y, __VA_ARGS__) */ +/* Offered when targeting Vista (XP SP2+) */ #ifndef CALG_SHA_256 #define CALG_SHA_256 0x0000800c #endif @@ -147,14 +124,19 @@ #define ALG_CLASS_DHASH ALG_CLASS_HASH #endif +/* Offered by mingw-w64 v4+. MS SDK 6.0A+. */ #ifndef PKCS12_NO_PERSIST_KEY #define PKCS12_NO_PERSIST_KEY 0x00008000 #endif +/* Offered by mingw-w64 v4+. MS SDK ~10+/~VS2017+. */ #ifndef CERT_FIND_HAS_PRIVATE_KEY #define CERT_FIND_HAS_PRIVATE_KEY (21 << CERT_COMPARE_SHIFT) #endif +/* key to use at `multi->proto_hash` */ +#define MPROTO_SCHANNEL_CERT_SHARE_KEY "tls:schannel:cert:share" + /* ALPN requires version 8.1 of the Windows SDK, which was shipped with Visual Studio 2013, aka _MSC_VER 1800: https://technet.microsoft.com/en-us/library/hh831771%28v=ws.11%29.aspx @@ -286,7 +268,7 @@ static const struct algo algs[]= { #ifdef CALG_TEK CIPHEROPTION(CALG_TEK), #endif - CIPHEROPTION(CALG_CYLINK_MEK), + CIPHEROPTION(CALG_CYLINK_MEK), /* spellchecker:disable-line */ CIPHEROPTION(CALG_SSL3_SHAMD5), #ifdef CALG_SSL3_MASTER CIPHEROPTION(CALG_SSL3_MASTER), @@ -379,7 +361,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers, { const char *startCur = ciphers; int algCount = 0; - while(startCur && (0 != *startCur) && (algCount < NUM_CIPHERS)) { + while(startCur && *startCur && (algCount < NUM_CIPHERS)) { curl_off_t alg; if(curlx_str_number(&startCur, &alg, INT_MAX) || !alg) alg = get_alg_id_by_name(startCur); @@ -402,8 +384,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers, return CURLE_OK; } -#ifdef HAS_CLIENT_CERT_PATH - +#ifndef UNDER_CE /* Function allocates memory for store_path only if CURLE_OK is returned */ static CURLcode get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path, @@ -469,10 +450,8 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, struct ssl_primary_config *conn_config = Curl_ssl_cf_get_primary_config(cf); struct ssl_config_data *ssl_config = Curl_ssl_cf_get_config(cf, data); -#ifdef HAS_CLIENT_CERT_PATH PCCERT_CONTEXT client_certs[1] = { NULL }; HCERTSTORE client_cert_store = NULL; -#endif SECURITY_STATUS sspi_status = SEC_E_OK; CURLcode result; @@ -486,11 +465,9 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, DEBUGASSERT(backend); if(conn_config->verifypeer) { -#ifdef HAS_MANUAL_VERIFY_API if(backend->use_manual_cred_validation) flags = SCH_CRED_MANUAL_CRED_VALIDATION; else -#endif flags = SCH_CRED_AUTO_CRED_VALIDATION; if(ssl_config->no_revoke) { @@ -545,7 +522,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, case CURL_SSLVERSION_TLSv1_3: { result = schannel_set_ssl_version_min_max(&enabled_protocols, cf, data); - if(result != CURLE_OK) + if(result) return result; break; } @@ -558,7 +535,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, return CURLE_SSL_CONNECT_ERROR; } -#ifdef HAS_CLIENT_CERT_PATH +#ifndef UNDER_CE /* client certificate */ if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { DWORD cert_store_name = 0; @@ -709,7 +686,13 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, } else { cert_store = - CertOpenStore(CURL_CERT_STORE_PROV_SYSTEM, 0, + CertOpenStore( +#ifdef UNICODE + CERT_STORE_PROV_SYSTEM_W, +#else + CERT_STORE_PROV_SYSTEM_A, +#endif + 0, (HCRYPTPROV)NULL, CERT_STORE_OPEN_EXISTING_FLAG | cert_store_name, cert_store_path); @@ -751,16 +734,12 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if(!client_certs[0]) { /* CRYPT_E_NOT_FOUND / E_INVALIDARG */ CertCloseStore(cert_store, 0); + failf(data, "schannel: client cert not found in cert store"); return CURLE_SSL_CERTPROBLEM; } } client_cert_store = cert_store; } -#else - if(data->set.ssl.primary.clientcert || data->set.ssl.primary.cert_blob) { - failf(data, "schannel: client cert support not built in"); - return CURLE_NOT_BUILT_IN; - } #endif /* allocate memory for the reusable credential handle */ @@ -769,23 +748,19 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, if(!backend->cred) { failf(data, "schannel: unable to allocate memory"); -#ifdef HAS_CLIENT_CERT_PATH if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); if(client_cert_store) CertCloseStore(client_cert_store, 0); -#endif return CURLE_OUT_OF_MEMORY; } backend->cred->refcount = 1; -#ifdef HAS_CLIENT_CERT_PATH /* Since we did not persist the key, we need to extend the store's * lifetime until the end of the connection */ backend->cred->client_cert_store = client_cert_store; -#endif /* We support TLS 1.3 starting in Windows 10 version 1809 (OS build 17763) as long as the user did not set a legacy algorithm list @@ -811,12 +786,10 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, credentials.pTlsParameters->grbitDisabledProtocols = (DWORD)~enabled_protocols; -#ifdef HAS_CLIENT_CERT_PATH if(client_certs[0]) { credentials.cCreds = 1; credentials.paCred = client_certs; } -#endif sspi_status = Curl_pSecFn->AcquireCredentialsHandle(NULL, @@ -843,7 +816,7 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, "user set an algorithm cipher list."); } result = set_ssl_ciphers(&schannel_cred, ciphers, algIds); - if(CURLE_OK != result) { + if(result) { failf(data, "schannel: Failed setting algorithm cipher list"); return result; } @@ -852,12 +825,10 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, schannel_cred.dwFlags = flags | SCH_USE_STRONG_CRYPTO; } -#ifdef HAS_CLIENT_CERT_PATH if(client_certs[0]) { schannel_cred.cCreds = 1; schannel_cred.paCred = client_certs; } -#endif sspi_status = Curl_pSecFn->AcquireCredentialsHandle(NULL, @@ -868,10 +839,8 @@ schannel_acquire_credential_handle(struct Curl_cfilter *cf, &backend->cred->time_stamp); } -#ifdef HAS_CLIENT_CERT_PATH if(client_certs[0]) CertFreeCertificateContext(client_certs[0]); -#endif if(sspi_status != SEC_E_OK) { char buffer[STRERROR_LEN]; @@ -935,15 +904,10 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) #endif #ifdef UNDER_CE -#ifdef HAS_MANUAL_VERIFY_API /* certificate validation on Windows CE does not seem to work right; we will * do it following a more manual process. */ backend->use_manual_cred_validation = TRUE; #else -#error "compiler too old to support Windows CE requisite manual cert verify" -#endif -#else -#ifdef HAS_MANUAL_VERIFY_API if(conn_config->CAfile || conn_config->ca_info_blob) { if(curlx_verify_windows_version(6, 1, 0, PLATFORM_WINNT, VERSION_GREATER_THAN_EQUAL)) { @@ -957,12 +921,6 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) } else backend->use_manual_cred_validation = FALSE; -#else - if(conn_config->CAfile || conn_config->ca_info_blob) { - failf(data, "schannel: CA cert support not built in"); - return CURLE_NOT_BUILT_IN; - } -#endif #endif backend->cred = NULL; @@ -1106,17 +1064,17 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) failf(data, "schannel: SNI or certificate check failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); return CURLE_PEER_FAILED_VERIFICATION; - /* - case SEC_E_INVALID_HANDLE: - case SEC_E_INVALID_TOKEN: - case SEC_E_LOGON_DENIED: - case SEC_E_TARGET_UNKNOWN: - case SEC_E_NO_AUTHENTICATING_AUTHORITY: - case SEC_E_INTERNAL_ERROR: - case SEC_E_NO_CREDENTIALS: - case SEC_E_UNSUPPORTED_FUNCTION: - case SEC_E_APPLICATION_PROTOCOL_MISMATCH: - */ +#if 0 + case SEC_E_INVALID_HANDLE: + case SEC_E_INVALID_TOKEN: + case SEC_E_LOGON_DENIED: + case SEC_E_TARGET_UNKNOWN: + case SEC_E_NO_AUTHENTICATING_AUTHORITY: + case SEC_E_INTERNAL_ERROR: + case SEC_E_NO_CREDENTIALS: + case SEC_E_UNSUPPORTED_FUNCTION: + case SEC_E_APPLICATION_PROTOCOL_MISMATCH: +#endif default: failf(data, "schannel: initial InitializeSecurityContext failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); @@ -1132,7 +1090,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) outbuf.pvBuffer, outbuf.cbBuffer, FALSE, &written); Curl_pSecFn->FreeContextBuffer(outbuf.pvBuffer); - if((result != CURLE_OK) || (outbuf.cbBuffer != written)) { + if(result || (outbuf.cbBuffer != written)) { failf(data, "schannel: failed to send initial handshake data: " "sent %zu of %lu bytes", written, outbuf.cbBuffer); return CURLE_SSL_CONNECT_ERROR; @@ -1145,6 +1103,7 @@ schannel_connect_step1(struct Curl_cfilter *cf, struct Curl_easy *data) backend->recv_sspi_close_notify = FALSE; backend->recv_connection_closed = FALSE; backend->recv_renegotiating = FALSE; + backend->renegotiate_state.started = FALSE; backend->encdata_is_incomplete = FALSE; /* continue to second handshake step */ @@ -1230,27 +1189,34 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) if(doread) { /* read encrypted handshake data from socket */ result = Curl_conn_cf_recv(cf->next, data, - (char *) (backend->encdata_buffer + - backend->encdata_offset), + (char *)(backend->encdata_buffer + + backend->encdata_offset), backend->encdata_length - backend->encdata_offset, &nread); if(result == CURLE_AGAIN) { - connssl->io_need = CURL_SSL_IO_NEED_RECV; - DEBUGF(infof(data, "schannel: failed to receive handshake, " - "need more data")); - return CURLE_OK; + if(!backend->encdata_offset || backend->encdata_is_incomplete) { + connssl->io_need = CURL_SSL_IO_NEED_RECV; + DEBUGF(infof(data, "schannel: failed to receive handshake, " + "need more data")); + return CURLE_OK; + } + else { + DEBUGF(infof(data, "schannel: no new handshake data received, " + "continuing to process existing handshake data")); + } } - else if((result != CURLE_OK) || (nread == 0)) { + else if(result || (nread == 0)) { failf(data, "schannel: failed to receive handshake, " "SSL/TLS connection failed"); return CURLE_SSL_CONNECT_ERROR; } - - /* increase encrypted data buffer offset */ - backend->encdata_offset += nread; - backend->encdata_is_incomplete = FALSE; - SCH_DEV(infof(data, "schannel: encrypted data got %zu", nread)); + else { + /* increase encrypted data buffer offset */ + backend->encdata_offset += nread; + backend->encdata_is_incomplete = FALSE; + SCH_DEV(infof(data, "schannel: encrypted data got %zu", nread)); + } } SCH_DEV(infof(data, @@ -1278,6 +1244,17 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) memcpy(inbuf[0].pvBuffer, backend->encdata_buffer, backend->encdata_offset); + /* The socket must be writeable (or a poll error occurred) before we call + InitializeSecurityContext to continue processing the received TLS + records. This is because that function is not idempotent and we don't + support partial save/resume sending replies of handshake tokens. */ + if(!SOCKET_WRITABLE(Curl_conn_cf_get_socket(cf, data), 0)) { + SCH_DEV(infof(data, "schannel: handshake waiting for writeable socket")); + connssl->io_need = CURL_SSL_IO_NEED_SEND; + free(inbuf[0].pvBuffer); + return CURLE_OK; + } + sspi_status = Curl_pSecFn->InitializeSecurityContext( &backend->cred->cred_handle, &backend->ctxt->ctxt_handle, backend->cred->sni_hostname, backend->req_flags, @@ -1320,8 +1297,7 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) result = Curl_conn_cf_send(cf->next, data, outbuf[i].pvBuffer, outbuf[i].cbBuffer, FALSE, &written); - if((result != CURLE_OK) || - (outbuf[i].cbBuffer != written)) { + if(result || (outbuf[i].cbBuffer != written)) { failf(data, "schannel: failed to send next handshake data: " "sent %zu of %lu bytes", written, outbuf[i].cbBuffer); return CURLE_SSL_CONNECT_ERROR; @@ -1349,17 +1325,17 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) failf(data, "schannel: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); return CURLE_PEER_FAILED_VERIFICATION; - /* - case SEC_E_INVALID_HANDLE: - case SEC_E_INVALID_TOKEN: - case SEC_E_LOGON_DENIED: - case SEC_E_TARGET_UNKNOWN: - case SEC_E_NO_AUTHENTICATING_AUTHORITY: - case SEC_E_INTERNAL_ERROR: - case SEC_E_NO_CREDENTIALS: - case SEC_E_UNSUPPORTED_FUNCTION: - case SEC_E_APPLICATION_PROTOCOL_MISMATCH: - */ +#if 0 + case SEC_E_INVALID_HANDLE: + case SEC_E_INVALID_TOKEN: + case SEC_E_LOGON_DENIED: + case SEC_E_TARGET_UNKNOWN: + case SEC_E_NO_AUTHENTICATING_AUTHORITY: + case SEC_E_INTERNAL_ERROR: + case SEC_E_NO_CREDENTIALS: + case SEC_E_UNSUPPORTED_FUNCTION: + case SEC_E_APPLICATION_PROTOCOL_MISMATCH: +#endif default: failf(data, "schannel: next InitializeSecurityContext failed: %s", Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer))); @@ -1427,12 +1403,10 @@ schannel_connect_step2(struct Curl_cfilter *cf, struct Curl_easy *data) } } -#ifdef HAS_MANUAL_VERIFY_API if(conn_config->verifypeer && backend->use_manual_cred_validation) { /* Certificate verification also verifies the hostname if verifyhost */ return Curl_verify_certificate(cf, data); } -#endif /* Verify the hostname manually when certificate verification is disabled, because in that case Schannel will not verify it. */ @@ -1485,7 +1459,7 @@ static bool cert_counter_callback(const CERT_CONTEXT *ccert_context, bool reverse_order, void *certs_count) { - (void)reverse_order; /* unused */ + (void)reverse_order; if(valid_cert_encoding(ccert_context)) (*(int *)certs_count)++; return TRUE; @@ -1527,12 +1501,10 @@ static void schannel_session_free(void *sessionid) if(cred->refcount == 0) { Curl_pSecFn->FreeCredentialsHandle(&cred->cred_handle); curlx_unicodefree(cred->sni_hostname); -#ifdef HAS_CLIENT_CERT_PATH if(cred->client_cert_store) { CertCloseStore(cred->client_cert_store, 0); cred->client_cert_store = NULL; } -#endif Curl_safefree(cred); } } @@ -1591,19 +1563,18 @@ schannel_connect_step3(struct Curl_cfilter *cf, struct Curl_easy *data) if(alpn_result.ProtoNegoStatus == SecApplicationProtocolNegotiationStatus_Success) { - unsigned char prev_alpn = cf->conn->alpn; - + if(backend->recv_renegotiating && + connssl->negotiated.alpn && + strncmp(connssl->negotiated.alpn, + (const char *)alpn_result.ProtocolId, + alpn_result.ProtocolIdSize)) { + /* Renegotiation selected a different protocol now, we cannot + * deal with this */ + failf(data, "schannel: server selected an ALPN protocol too late"); + return CURLE_SSL_CONNECT_ERROR; + } Curl_alpn_set_negotiated(cf, data, connssl, alpn_result.ProtocolId, alpn_result.ProtocolIdSize); - if(backend->recv_renegotiating) { - if(prev_alpn != cf->conn->alpn && - prev_alpn != CURL_HTTP_VERSION_NONE) { - /* Renegotiation selected a different protocol now, we cannot - * deal with this */ - failf(data, "schannel: server selected an ALPN protocol too late"); - return CURLE_SSL_CONNECT_ERROR; - } - } } else { if(!backend->recv_renegotiating) @@ -1694,7 +1665,7 @@ static CURLcode schannel_connect(struct Curl_cfilter *cf, if(ssl_connect_done == connssl->connecting_state) { connssl->state = ssl_connection_complete; -#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS +#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS /* mingw-w64 v9+. MS SDK 7.0A+. */ /* When SSPI is used in combination with Schannel * we need the Schannel context to create the Schannel * binding to pass the IIS extended protection checks. @@ -1714,6 +1685,205 @@ static CURLcode schannel_connect(struct Curl_cfilter *cf, return CURLE_OK; } +enum schannel_renegotiate_caller_t { + SCH_RENEG_CALLER_IS_RECV, + SCH_RENEG_CALLER_IS_SEND +}; + +/* This function renegotiates the connection due to a server request received + by schannel_recv. This function returns CURLE_AGAIN if the renegotiation is + incomplete. In that case, we remain in the renegotiation (connecting) stage + and future calls to schannel_recv and schannel_send must call this function + first to complete the renegotiation. */ +static CURLcode +schannel_recv_renegotiate(struct Curl_cfilter *cf, struct Curl_easy *data, + enum schannel_renegotiate_caller_t caller) +{ + CURLcode result; + curl_socket_t sockfd; + const timediff_t max_renegotiate_ms = 5 * 60 * 1000; /* 5 minutes */ + struct ssl_connect_data *connssl = cf->ctx; + struct schannel_ssl_backend_data *backend = + (struct schannel_ssl_backend_data *)connssl->backend; + struct schannel_renegotiate_state *rs = &backend->renegotiate_state; + + if(!backend || !backend->recv_renegotiating) { + failf(data, "schannel: unexpected call to schannel_recv_renegotiate"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(caller == SCH_RENEG_CALLER_IS_RECV) + SCH_DEV(infof(data, "schannel: renegotiation caller is schannel_recv")); + else if(caller == SCH_RENEG_CALLER_IS_SEND) + SCH_DEV(infof(data, "schannel: renegotiation caller is schannel_send")); + else { + failf(data, "schannel: unknown caller for schannel_recv_renegotiate"); + return CURLE_SSL_CONNECT_ERROR; + } + + sockfd = Curl_conn_cf_get_socket(cf, data); + + if(sockfd == CURL_SOCKET_BAD) { + failf(data, "schannel: renegotiation missing socket"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(!rs->started) { /* new renegotiation */ + infof(data, "schannel: renegotiating SSL/TLS connection"); + DEBUGASSERT(connssl->state == ssl_connection_complete); + DEBUGASSERT(connssl->connecting_state == ssl_connect_done); + connssl->state = ssl_connection_negotiating; + connssl->connecting_state = ssl_connect_2; + memset(rs, 0, sizeof(*rs)); + rs->io_need = CURL_SSL_IO_NEED_SEND; + rs->start_time = curlx_now(); + rs->started = TRUE; + } + + for(;;) { + bool block_read, block_write, blocking, done; + curl_socket_t readfd, writefd; + timediff_t elapsed; + + elapsed = curlx_timediff(curlx_now(), rs->start_time); + if(elapsed >= max_renegotiate_ms) { + failf(data, "schannel: renegotiation timeout"); + result = CURLE_SSL_CONNECT_ERROR; + break; + } + + /* the current io_need state may have been overwritten since the last time + this function was called. restore the io_need state needed to continue + the renegotiation. */ + + connssl->io_need = rs->io_need; + + result = schannel_connect(cf, data, &done); + + rs->io_need = connssl->io_need; + + if(!result && !done) + result = CURLE_AGAIN; + + if(result != CURLE_AGAIN) + break; + + readfd = (rs->io_need & CURL_SSL_IO_NEED_RECV) ? sockfd : CURL_SOCKET_BAD; + writefd = (rs->io_need & CURL_SSL_IO_NEED_SEND) ? sockfd : CURL_SOCKET_BAD; + + if(readfd == CURL_SOCKET_BAD && writefd == CURL_SOCKET_BAD) + continue; + + /* connect should not have requested io read and write together */ + DEBUGASSERT(readfd == CURL_SOCKET_BAD || writefd == CURL_SOCKET_BAD); + + /* This function is partially blocking to avoid a stoppage that would + * occur if the user is waiting on the socket only in one direction. + * + * For example, if the user has called recv then they may not be waiting + * for a writeable socket and vice versa, so we block to avoid that. + * + * In practice a wait is unlikely to occur. For caller recv if handshake + * data needs to be sent then we block for a writeable socket that should + * be writeable immediately except for OS resource constraints. For caller + * send if handshake data needs to be received then we block for a readable + * socket, which could take some time, but it's more likely the user has + * called recv since they had called it prior (only recv can start + * renegotiation and probably the user is going to call it again to get + * more of their data before calling send). + */ + + block_read = (caller == SCH_RENEG_CALLER_IS_SEND) ? TRUE : FALSE; + block_write = (caller == SCH_RENEG_CALLER_IS_RECV) ? TRUE : FALSE; + + blocking = (block_read && (readfd != CURL_SOCKET_BAD)) || + (block_write && (writefd != CURL_SOCKET_BAD)); + + SCH_DEV_SHOWBOOL(block_read); + SCH_DEV_SHOWBOOL(block_write); + SCH_DEV_SHOWBOOL(blocking); + + for(;;) { + int what; + timediff_t timeout, remaining; + + if(Curl_pgrsUpdate(data)) { + result = CURLE_ABORTED_BY_CALLBACK; + break; + } + + elapsed = curlx_timediff(curlx_now(), rs->start_time); + if(elapsed >= max_renegotiate_ms) { + failf(data, "schannel: renegotiation timeout"); + result = CURLE_SSL_CONNECT_ERROR; + break; + } + remaining = max_renegotiate_ms - elapsed; + + if(blocking) { + timeout = Curl_timeleft(data, NULL, FALSE); + + if(timeout < 0) { + result = CURLE_OPERATION_TIMEDOUT; + break; + } + + /* the blocking is in intervals so that the progress function can be + called every second */ + if(!timeout || timeout > 1000) + timeout = 1000; + + if(timeout > remaining) + timeout = remaining; + } + else + timeout = 0; + + SCH_DEV(infof(data, "schannel: renegotiation wait until socket is" + "%s%s for up to %" FMT_TIMEDIFF_T " ms", + ((readfd != CURL_SOCKET_BAD) ? " readable" : ""), + ((writefd != CURL_SOCKET_BAD) ? " writeable" : ""), + timeout)); + + what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd, timeout); + + if(what > 0 && (what & (CURL_CSELECT_IN | CURL_CSELECT_OUT))) { + SCH_DEV(infof(data, "schannel: renegotiation socket %s%s", + ((what & CURL_CSELECT_IN) ? "CURL_CSELECT_IN " : ""), + ((what & CURL_CSELECT_OUT) ? "CURL_CSELECT_OUT " : ""))); + result = CURLE_AGAIN; + break; + } + else if(!what) { + SCH_DEV(infof(data, "schannel: renegotiation socket timeout")); + if(blocking) + continue; + else + return CURLE_AGAIN; + } + + failf(data, "schannel: socket error during renegotiation"); + result = CURLE_SSL_CONNECT_ERROR; + break; + } + if(result != CURLE_AGAIN) + break; + } + + DEBUGASSERT(result != CURLE_AGAIN); + + rs->started = FALSE; + backend->recv_renegotiating = FALSE; + connssl->io_need = CURL_SSL_IO_NEED_NONE; + + if(result) + failf(data, "schannel: renegotiation failed"); + else + infof(data, "schannel: SSL/TLS connection renegotiated"); + + return result; +} + static CURLcode schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, const void *buf, size_t len, size_t *pnwritten) @@ -1731,6 +1901,12 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, DEBUGASSERT(backend); *pnwritten = 0; + if(backend->recv_renegotiating) { + result = schannel_recv_renegotiate(cf, data, SCH_RENEG_CALLER_IS_SEND); + if(result) + return result; + } + /* check if the maximum stream sizes were queried */ if(backend->stream_sizes.cbMaximumMessage == 0) { sspi_status = Curl_pSecFn->QueryContextAttributes( @@ -1750,7 +1926,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* calculate the complete message length and allocate a buffer for it */ data_len = backend->stream_sizes.cbHeader + len + backend->stream_sizes.cbTrailer; - ptr = (unsigned char *) malloc(data_len); + ptr = (unsigned char *)malloc(data_len); if(!ptr) { return CURLE_OUT_OF_MEMORY; } @@ -1771,7 +1947,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, /* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */ sspi_status = Curl_pSecFn->EncryptMessage(&backend->ctxt->ctxt_handle, 0, - &outbuf_desc, 0); + &outbuf_desc, 0); /* check if the message was encrypted */ if(sspi_status == SEC_E_OK) { @@ -1816,7 +1992,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, result = CURLE_SEND_ERROR; break; } - else if(0 == what) { + else if(what == 0) { failf(data, "schannel: timed out sending data " "(bytes sent: %zu)", *pnwritten); result = CURLE_OPERATION_TIMEDOUT; @@ -1829,7 +2005,7 @@ schannel_send(struct Curl_cfilter *cf, struct Curl_easy *data, FALSE, &this_write); if(result == CURLE_AGAIN) continue; - else if(result != CURLE_OK) { + else if(result) { break; } @@ -1862,7 +2038,6 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, struct ssl_connect_data *connssl = cf->ctx; unsigned char *reallocated_buffer; size_t reallocated_length; - bool done = FALSE; SecBuffer inbuf[4]; SecBufferDesc inbuf_desc; SECURITY_STATUS sspi_status = SEC_E_OK; @@ -1876,6 +2051,12 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, DEBUGASSERT(backend); *pnread = 0; + if(backend->recv_renegotiating) { + result = schannel_recv_renegotiate(cf, data, SCH_RENEG_CALLER_IS_RECV); + if(result) + return result; + } + /**************************************************************************** * Do not return or set backend->recv_unrecoverable_err unless in the * cleanup. The pattern for return error is set *err, optional infof, goto @@ -2068,21 +2249,13 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, goto cleanup; } - /* begin renegotiation */ - infof(data, "schannel: renegotiating SSL/TLS connection"); - connssl->state = ssl_connection_negotiating; - connssl->connecting_state = ssl_connect_2; - connssl->io_need = CURL_SSL_IO_NEED_SEND; backend->recv_renegotiating = TRUE; - result = schannel_connect(cf, data, &done); - backend->recv_renegotiating = FALSE; - if(result) { - infof(data, "schannel: renegotiation failed"); + result = schannel_recv_renegotiate(cf, data, SCH_RENEG_CALLER_IS_RECV); + if(result) goto cleanup; - } + /* now retry receiving data */ sspi_status = SEC_E_OK; - infof(data, "schannel: SSL/TLS connection renegotiated"); continue; } /* check if the server closed the connection */ @@ -2380,26 +2553,16 @@ static void schannel_close(struct Curl_cfilter *cf, struct Curl_easy *data) static int schannel_init(void) { #if defined(HAS_ALPN_SCHANNEL) && !defined(UNDER_CE) - bool wine = FALSE; - bool wine_has_alpn = FALSE; - -#ifndef CURL_WINDOWS_UWP typedef const char *(APIENTRY *WINE_GET_VERSION_FN)(void); - /* GetModuleHandle() not available for UWP. - Assume no WINE because WINE has no UWP support. */ WINE_GET_VERSION_FN p_wine_get_version = CURLX_FUNCTION_CAST(WINE_GET_VERSION_FN, (GetProcAddress(GetModuleHandleA("ntdll"), "wine_get_version"))); - wine = !!p_wine_get_version; - if(wine) { + if(p_wine_get_version) { /* WINE detected */ const char *wine_version = p_wine_get_version(); /* e.g. "6.0.2" */ /* Assume ALPN support with WINE 6.0 or upper */ - wine_has_alpn = wine_version && atoi(wine_version) >= 6; + s_win_has_alpn = wine_version && atoi(wine_version) >= 6; } -#endif - if(wine) - s_win_has_alpn = wine_has_alpn; else { /* ALPN is supported on Windows 8.1 / Server 2012 R2 and above. */ s_win_has_alpn = curlx_verify_windows_version(6, 3, 0, PLATFORM_WINNT, @@ -2420,7 +2583,7 @@ static size_t schannel_version(char *buffer, size_t size) return msnprintf(buffer, size, "Schannel"); } -static CURLcode schannel_random(struct Curl_easy *data UNUSED_PARAM, +static CURLcode schannel_random(struct Curl_easy *data, unsigned char *entropy, size_t length) { (void)data; @@ -2504,13 +2667,6 @@ static void schannel_checksum(const unsigned char *input, DWORD provType, const unsigned int algId) { -#ifdef CURL_WINDOWS_UWP - (void)input; - (void)inputlen; - (void)provType; - (void)algId; - memset(checksum, 0, checksumlen); -#else HCRYPTPROV hProv = 0; HCRYPTHASH hHash = 0; DWORD cbHashSize = 0; @@ -2556,7 +2712,6 @@ static void schannel_checksum(const unsigned char *input, if(hProv) CryptReleaseContext(hProv, 0); -#endif } static CURLcode schannel_sha256sum(const unsigned char *input, @@ -2570,7 +2725,7 @@ static CURLcode schannel_sha256sum(const unsigned char *input, } static void *schannel_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info) { struct schannel_ssl_backend_data *backend = (struct schannel_ssl_backend_data *)connssl->backend; @@ -2726,12 +2881,8 @@ const struct Curl_ssl Curl_ssl_schannel = { { CURLSSLBACKEND_SCHANNEL, "schannel" }, /* info */ SSLSUPP_CERTINFO | -#ifdef HAS_MANUAL_VERIFY_API SSLSUPP_CAINFO_BLOB | -#endif -#ifndef CURL_WINDOWS_UWP SSLSUPP_PINNEDPUBKEY | -#endif SSLSUPP_CA_CACHE | SSLSUPP_HTTPS_PROXY | SSLSUPP_CIPHER_LIST, diff --git a/deps/curl/lib/vtls/schannel.h b/deps/curl/lib/vtls/schannel.h index c3512dd1323..9d0bea221a9 100644 --- a/deps/curl/lib/vtls/schannel.h +++ b/deps/curl/lib/vtls/schannel.h @@ -37,7 +37,7 @@ #pragma warning(pop) #endif /* Wincrypt must be included before anything that could include OpenSSL. */ -#if defined(USE_WIN32_CRYPTO) +#ifdef USE_WIN32_CRYPTO #include /* Undefine wincrypt conflicting symbols for BoringSSL. */ #undef X509_NAME @@ -68,7 +68,7 @@ * BoringSSL's : So just undefine those defines here * (and only here). */ -#if defined(OPENSSL_IS_BORINGSSL) +#if defined(OPENSSL_IS_BORINGSSL) || defined(OPENSSL_IS_AWSLC) # undef X509_NAME # undef X509_CERT_PAIR # undef X509_EXTENSIONS diff --git a/deps/curl/lib/vtls/schannel_int.h b/deps/curl/lib/vtls/schannel_int.h index 511a852c7a2..5483d12b5bb 100644 --- a/deps/curl/lib/vtls/schannel_int.h +++ b/deps/curl/lib/vtls/schannel_int.h @@ -30,32 +30,6 @@ #include "vtls.h" -#if (defined(__MINGW32__) || defined(CERT_CHAIN_REVOCATION_CHECK_CHAIN)) \ - && !defined(CURL_WINDOWS_UWP) -#define HAS_MANUAL_VERIFY_API -#endif - -#if defined(CryptStringToBinary) && defined(CRYPT_STRING_HEX) \ - && !defined(DISABLE_SCHANNEL_CLIENT_CERT) -#define HAS_CLIENT_CERT_PATH -#endif - -#ifndef CRYPT_DECODE_NOCOPY_FLAG -#define CRYPT_DECODE_NOCOPY_FLAG 0x1 -#endif - -#ifndef CRYPT_DECODE_ALLOC_FLAG -#define CRYPT_DECODE_ALLOC_FLAG 0x8000 -#endif - -#ifndef CERT_ALT_NAME_DNS_NAME -#define CERT_ALT_NAME_DNS_NAME 3 -#endif - -#ifndef CERT_ALT_NAME_IP_ADDRESS -#define CERT_ALT_NAME_IP_ADDRESS 8 -#endif - #if defined(_MSC_VER) && (_MSC_VER <= 1600) /* Workaround for warning: 'type cast' : conversion from 'int' to 'LPCSTR' of greater size */ @@ -67,6 +41,7 @@ #define CERT_STORE_PROV_SYSTEM_W ((LPCSTR)(size_t)10) #endif +/* Offered by mingw-w64 v8+, MS SDK ~10+/~VS2022+ */ #ifndef SCH_CREDENTIALS_VERSION #define SCH_CREDENTIALS_VERSION 0x00000005 @@ -83,7 +58,7 @@ typedef struct _CRYPTO_SETTINGS { eTlsAlgorithmUsage eAlgorithmUsage; UNICODE_STRING strCngAlgId; DWORD cChainingModes; - PUNICODE_STRING rgstrChainingModes; + PUNICODE_STRING rgstrChainingModes; /* spellchecker:disable-line */ DWORD dwMinBitLength; DWORD dwMaxBitLength; } CRYPTO_SETTINGS, * PCRYPTO_SETTINGS; @@ -91,7 +66,7 @@ typedef struct _CRYPTO_SETTINGS { /* !checksrc! disable TYPEDEFSTRUCT 1 */ typedef struct _TLS_PARAMETERS { DWORD cAlpnIds; - PUNICODE_STRING rgstrAlpnIds; + PUNICODE_STRING rgstrAlpnIds; /* spellchecker:disable-line */ DWORD grbitDisabledProtocols; DWORD cDisabledCrypto; PCRYPTO_SETTINGS pDisabledCrypto; @@ -126,9 +101,7 @@ struct Curl_schannel_cred { CredHandle cred_handle; TimeStamp time_stamp; TCHAR *sni_hostname; -#ifdef HAS_CLIENT_CERT_PATH HCERTSTORE client_cert_store; -#endif int refcount; }; @@ -150,20 +123,20 @@ struct schannel_ssl_backend_data { more bytes into encdata then set this back to false. */ unsigned long req_flags, ret_flags; CURLcode recv_unrecoverable_err; /* schannel_recv had an unrecoverable err */ + struct schannel_renegotiate_state { + bool started; + struct curltime start_time; + int io_need; + } renegotiate_state; BIT(recv_sspi_close_notify); /* true if connection closed by close_notify */ BIT(recv_connection_closed); /* true if connection closed, regardless how */ BIT(recv_renegotiating); /* true if recv is doing renegotiation */ BIT(use_alpn); /* true if ALPN is used for this connection */ -#ifdef HAS_MANUAL_VERIFY_API BIT(use_manual_cred_validation); /* true if manual cred validation is used */ -#endif BIT(sent_shutdown); BIT(encdata_is_incomplete); }; -/* key to use at `multi->proto_hash` */ -#define MPROTO_SCHANNEL_CERT_SHARE_KEY "tls:schannel:cert:share" - struct schannel_cert_share { unsigned char CAinfo_blob_digest[CURL_SHA256_DIGEST_LENGTH]; size_t CAinfo_blob_size; /* CA info blob size */ diff --git a/deps/curl/lib/vtls/schannel_verify.c b/deps/curl/lib/vtls/schannel_verify.c index 7db13f2a251..17e42707631 100644 --- a/deps/curl/lib/vtls/schannel_verify.c +++ b/deps/curl/lib/vtls/schannel_verify.c @@ -56,8 +56,6 @@ #define BACKEND ((struct schannel_ssl_backend_data *)connssl->backend) -#ifdef HAS_MANUAL_VERIFY_API - #ifdef __MINGW32CE__ #define CERT_QUERY_OBJECT_BLOB 0x00000002 #define CERT_QUERY_CONTENT_CERT 1 @@ -94,7 +92,7 @@ struct cert_chain_engine_config_win8 { DWORD dwExclusiveFlags; }; -/* Not defined before mingw-w64 4.0.0 */ +/* Offered by mingw-w64 v4+. MS SDK ~10+/~VS2017+. */ #ifndef CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG #define CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG 0x00000001 #endif @@ -370,11 +368,7 @@ static CURLcode add_certs_file_to_store(HCERTSTORE trust_store, return result; } -#endif - -#endif /* HAS_MANUAL_VERIFY_API */ -#ifndef UNDER_CE /* * Returns the number of characters necessary to populate all the host_names. * If host_names is not NULL, populate it with all the hostnames. Each string @@ -390,18 +384,11 @@ static DWORD cert_get_name_string(struct Curl_easy *data, BOOL Win8_compat) { DWORD actual_length = 0; -#if defined(CURL_WINDOWS_UWP) - (void)data; - (void)cert_context; - (void)host_names; - (void)length; - (void)alt_name_info; - (void)Win8_compat; -#else BOOL compute_content = FALSE; LPTSTR current_pos = NULL; DWORD i; +/* Offered by mingw-w64 v4+. MS SDK ~10+/~VS2017+. */ #ifdef CERT_NAME_SEARCH_ALL_NAMES_FLAG /* CERT_NAME_SEARCH_ALL_NAMES_FLAG is available from Windows 8 onwards. */ if(Win8_compat) { @@ -471,7 +458,6 @@ static DWORD cert_get_name_string(struct Curl_easy *data, /* Last string has double null-terminator. */ *current_pos = '\0'; } -#endif return actual_length; } @@ -510,12 +496,6 @@ static bool get_alt_name_info(struct Curl_easy *data, LPDWORD alt_name_info_size) { bool result = FALSE; -#if defined(CURL_WINDOWS_UWP) - (void)data; - (void)ctx; - (void)alt_name_info; - (void)alt_name_info_size; -#else PCERT_INFO cert_info = NULL; PCERT_EXTENSION extension = NULL; CRYPT_DECODE_PARA decode_para = { sizeof(CRYPT_DECODE_PARA), NULL, NULL }; @@ -553,7 +533,6 @@ static bool get_alt_name_info(struct Curl_easy *data, return result; } result = TRUE; -#endif return result; } #endif /* !UNDER_CE */ @@ -767,7 +746,6 @@ CURLcode Curl_verify_host(struct Curl_cfilter *cf, return result; } -#ifdef HAS_MANUAL_VERIFY_API /* Verify the server's certificate and hostname */ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, struct Curl_easy *data) @@ -801,8 +779,8 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, #ifndef UNDER_CE if(result == CURLE_OK && - (conn_config->CAfile || conn_config->ca_info_blob) && - BACKEND->use_manual_cred_validation) { + (conn_config->CAfile || conn_config->ca_info_blob) && + BACKEND->use_manual_cred_validation) { /* * Create a chain engine that uses the certificates in the CA file as * trusted certificates. This is only supported on Windows 7+. @@ -979,5 +957,4 @@ CURLcode Curl_verify_certificate(struct Curl_cfilter *cf, return result; } -#endif /* HAS_MANUAL_VERIFY_API */ #endif /* USE_SCHANNEL */ diff --git a/deps/curl/lib/vtls/vtls.c b/deps/curl/lib/vtls/vtls.c index db4e57342e3..f17f9142bed 100644 --- a/deps/curl/lib/vtls/vtls.c +++ b/deps/curl/lib/vtls/vtls.c @@ -137,9 +137,11 @@ static bool blobcmp(struct curl_blob *first, struct curl_blob *second) } #ifdef USE_SSL +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_PROXY) static const struct alpn_spec ALPN_SPEC_H11 = { { ALPN_HTTP_1_1 }, 1 }; +#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_PROXY */ #ifdef USE_HTTP2 static const struct alpn_spec ALPN_SPEC_H2 = { { ALPN_H2 }, 1 @@ -149,6 +151,7 @@ static const struct alpn_spec ALPN_SPEC_H2_H11 = { }; #endif +#if !defined(CURL_DISABLE_HTTP) || !defined(CURL_DISABLE_PROXY) static const struct alpn_spec * alpn_get_spec(http_majors allowed, bool use_alpn) { @@ -167,6 +170,7 @@ alpn_get_spec(http_majors allowed, bool use_alpn) Avoid "http/1.0" because some servers do not support it. */ return &ALPN_SPEC_H11; } +#endif /* !CURL_DISABLE_HTTP || !CURL_DISABLE_PROXY */ #endif /* USE_SSL */ @@ -499,26 +503,30 @@ void Curl_ssl_close_all(struct Curl_easy *data) Curl_ssl->close_all(data); } -void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, - struct easy_pollset *ps) +CURLcode Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct ssl_connect_data *connssl = cf->ctx; if(connssl->io_need) { curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data); + CURLcode result = CURLE_OK; if(sock != CURL_SOCKET_BAD) { if(connssl->io_need & CURL_SSL_IO_NEED_SEND) { - Curl_pollset_set_out_only(data, ps, sock); + result = Curl_pollset_set_out_only(data, ps, sock); CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%" FMT_SOCKET_T, sock); } else { - Curl_pollset_set_in_only(data, ps, sock); + result = Curl_pollset_set_in_only(data, ps, sock); CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%" FMT_SOCKET_T, sock); } } + return result; } + return CURLE_OK; } /* Selects an SSL crypto engine @@ -666,7 +674,7 @@ static CURLcode pubkey_pem_to_der(const char *pem, pem_count = begin_pos - pem; /* Invalid if not at beginning AND not directly following \n */ - if(0 != pem_count && '\n' != pem[pem_count - 1]) + if(pem_count && '\n' != pem[pem_count - 1]) return CURLE_BAD_CONTENT_ENCODING; /* 26 is length of "-----BEGIN PUBLIC KEY-----" */ @@ -882,6 +890,14 @@ static int multissl_init(void) return 1; } +static CURLcode multissl_random(struct Curl_easy *data, + unsigned char *entropy, size_t length) +{ + if(multissl_setup(NULL)) + return CURLE_FAILED_INIT; + return Curl_ssl->random(data, entropy, length); +} + static CURLcode multissl_connect(struct Curl_cfilter *cf, struct Curl_easy *data, bool *done) { @@ -890,13 +906,13 @@ static CURLcode multissl_connect(struct Curl_cfilter *cf, return Curl_ssl->do_connect(cf, data, done); } -static void multissl_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode multissl_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { if(multissl_setup(NULL)) - return; - Curl_ssl->adjust_pollset(cf, data, ps); + return CURLE_OK; + return Curl_ssl->adjust_pollset(cf, data, ps); } static void *multissl_get_internals(struct ssl_connect_data *connssl, @@ -943,7 +959,7 @@ static const struct Curl_ssl Curl_ssl_multi = { multissl_version, /* version */ NULL, /* shutdown */ NULL, /* data_pending */ - NULL, /* random */ + multissl_random, /* random */ NULL, /* cert_status_request */ multissl_connect, /* connect */ multissl_adjust_pollset, /* adjust_pollset */ @@ -960,7 +976,7 @@ static const struct Curl_ssl Curl_ssl_multi = { }; const struct Curl_ssl *Curl_ssl = -#if defined(CURL_WITH_MULTI_SSL) +#ifdef CURL_WITH_MULTI_SSL &Curl_ssl_multi; #elif defined(USE_WOLFSSL) &Curl_ssl_wolfssl; @@ -979,22 +995,22 @@ const struct Curl_ssl *Curl_ssl = #endif static const struct Curl_ssl *available_backends[] = { -#if defined(USE_WOLFSSL) +#ifdef USE_WOLFSSL &Curl_ssl_wolfssl, #endif -#if defined(USE_GNUTLS) +#ifdef USE_GNUTLS &Curl_ssl_gnutls, #endif -#if defined(USE_MBEDTLS) +#ifdef USE_MBEDTLS &Curl_ssl_mbedtls, #endif -#if defined(USE_OPENSSL) +#ifdef USE_OPENSSL &Curl_ssl_openssl, #endif -#if defined(USE_SCHANNEL) +#ifdef USE_SCHANNEL &Curl_ssl_schannel, #endif -#if defined(USE_RUSTLS) +#ifdef USE_RUSTLS &Curl_ssl_rustls, #endif NULL @@ -1007,7 +1023,7 @@ void Curl_ssl_cleanup(void) /* only cleanup if we did a previous init */ if(Curl_ssl->cleanup) Curl_ssl->cleanup(); -#if defined(CURL_WITH_MULTI_SSL) +#ifdef CURL_WITH_MULTI_SSL Curl_ssl = &Curl_ssl_multi; #endif init_ssl = FALSE; @@ -1112,7 +1128,7 @@ CURLsslset Curl_init_sslset_nolock(curl_sslbackend id, const char *name, return id == Curl_ssl->info.id || (name && curl_strequal(name, Curl_ssl->info.name)) ? CURLSSLSET_OK : -#if defined(CURL_WITH_MULTI_SSL) +#ifdef CURL_WITH_MULTI_SSL CURLSSLSET_TOO_LATE; #else CURLSSLSET_UNKNOWN_BACKEND; @@ -1533,16 +1549,18 @@ static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf, return result; } -static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf, - struct Curl_easy *data, - struct easy_pollset *ps) +static CURLcode ssl_cf_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps) { struct ssl_connect_data *connssl = cf->ctx; struct cf_call_data save; + CURLcode result; CF_DATA_SAVE(save, cf, data); - connssl->ssl_impl->adjust_pollset(cf, data, ps); + result = connssl->ssl_impl->adjust_pollset(cf, data, ps); CF_DATA_RESTORE(cf, save); + return result; } static CURLcode ssl_cf_query(struct Curl_cfilter *cf, @@ -1559,15 +1577,24 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf, return CURLE_OK; } case CF_QUERY_SSL_INFO: - case CF_QUERY_SSL_CTX_INFO: { - struct curl_tlssessioninfo *info = pres2; - struct cf_call_data save; - CF_DATA_SAVE(save, cf, data); - info->backend = Curl_ssl_backend(); - info->internals = connssl->ssl_impl->get_internals( - cf->ctx, (query == CF_QUERY_SSL_INFO) ? - CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION); - CF_DATA_RESTORE(cf, save); + case CF_QUERY_SSL_CTX_INFO: + if(!Curl_ssl_cf_is_proxy(cf)) { + struct curl_tlssessioninfo *info = pres2; + struct cf_call_data save; + CF_DATA_SAVE(save, cf, data); + info->backend = Curl_ssl_backend(); + info->internals = connssl->ssl_impl->get_internals( + cf->ctx, (query == CF_QUERY_SSL_INFO) ? + CURLINFO_TLS_SSL_PTR : CURLINFO_TLS_SESSION); + CF_DATA_RESTORE(cf, save); + return CURLE_OK; + } + break; + case CF_QUERY_ALPN_NEGOTIATED: { + const char **palpn = pres2; + DEBUGASSERT(palpn); + *palpn = connssl->negotiated.alpn; + CURL_TRC_CF(data, cf, "query ALPN: returning '%s'", *palpn); return CURLE_OK; } default: @@ -1578,6 +1605,30 @@ static CURLcode ssl_cf_query(struct Curl_cfilter *cf, CURLE_UNKNOWN_OPTION; } +static CURLcode ssl_cf_cntrl(struct Curl_cfilter *cf, + struct Curl_easy *data, + int event, int arg1, void *arg2) +{ + struct ssl_connect_data *connssl = cf->ctx; + + (void)arg1; + (void)arg2; + (void)data; + switch(event) { + case CF_CTRL_CONN_INFO_UPDATE: + if(connssl->negotiated.alpn && !cf->sockindex) { + if(!strcmp("http/1.1", connssl->negotiated.alpn)) + cf->conn->httpversion_seen = 11; + else if(!strcmp("h2", connssl->negotiated.alpn)) + cf->conn->httpversion_seen = 20; + else if(!strcmp("h3", connssl->negotiated.alpn)) + cf->conn->httpversion_seen = 30; + } + break; + } + return CURLE_OK; +} + static bool cf_ssl_is_alive(struct Curl_cfilter *cf, struct Curl_easy *data, bool *input_pending) { @@ -1601,7 +1652,7 @@ struct Curl_cftype Curl_cft_ssl = { ssl_cf_data_pending, ssl_cf_send, ssl_cf_recv, - Curl_cf_def_cntrl, + ssl_cf_cntrl, cf_ssl_is_alive, Curl_cf_def_conn_keep_alive, ssl_cf_query, @@ -1624,7 +1675,7 @@ struct Curl_cftype Curl_cft_ssl_proxy = { Curl_cf_def_cntrl, cf_ssl_is_alive, Curl_cf_def_conn_keep_alive, - Curl_cf_def_query, + ssl_cf_query, }; #endif /* !CURL_DISABLE_PROXY */ @@ -1640,6 +1691,7 @@ static CURLcode cf_ssl_create(struct Curl_cfilter **pcf, DEBUGASSERT(data->conn); #ifdef CURL_DISABLE_HTTP + (void)conn; /* We only support ALPN for HTTP so far. */ DEBUGASSERT(!conn->bits.tls_enable_alpn); ctx = cf_ctx_new(data, NULL); @@ -1695,9 +1747,11 @@ static CURLcode cf_ssl_proxy_create(struct Curl_cfilter **pcf, struct Curl_cfilter *cf = NULL; struct ssl_connect_data *ctx; CURLcode result; - bool use_alpn = conn->bits.tls_enable_alpn; + /* ALPN is default, but if user explicitly disables it, obey */ + bool use_alpn = data->set.ssl_enable_alpn; http_majors allowed = CURL_HTTP_V1x; + (void)conn; #ifdef USE_HTTP2 if(conn->http_proxy.proxytype == CURLPROXY_HTTPS2) { use_alpn = TRUE; @@ -1777,7 +1831,7 @@ static CURLcode vtls_shutdown_blocking(struct Curl_cfilter *cf, result = CURLE_RECV_ERROR; goto out; } - else if(0 == what) { + else if(what == 0) { /* timeout */ failf(data, "SSL shutdown timeout"); result = CURLE_OPERATION_TIMEDOUT; @@ -1926,14 +1980,7 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, size_t proto_len) { CURLcode result = CURLE_OK; - unsigned char *palpn = -#ifndef CURL_DISABLE_PROXY - (cf->conn->bits.tunnel_proxy && Curl_ssl_cf_is_proxy(cf)) ? - &cf->conn->proxy_alpn : &cf->conn->alpn -#else - &cf->conn->alpn -#endif - ; + (void)cf; if(connssl->negotiated.alpn) { /* When we ask for a specific ALPN protocol, we need the confirmation @@ -1975,38 +2022,12 @@ CURLcode Curl_alpn_set_negotiated(struct Curl_cfilter *cf, } if(proto && proto_len) { - if(proto_len == ALPN_HTTP_1_1_LENGTH && - !memcmp(ALPN_HTTP_1_1, proto, ALPN_HTTP_1_1_LENGTH)) { - *palpn = CURL_HTTP_VERSION_1_1; - } -#ifdef USE_HTTP2 - else if(proto_len == ALPN_H2_LENGTH && - !memcmp(ALPN_H2, proto, ALPN_H2_LENGTH)) { - *palpn = CURL_HTTP_VERSION_2; - } -#endif -#ifdef USE_HTTP3 - else if(proto_len == ALPN_H3_LENGTH && - !memcmp(ALPN_H3, proto, ALPN_H3_LENGTH)) { - *palpn = CURL_HTTP_VERSION_3; - } -#endif - else { - *palpn = CURL_HTTP_VERSION_NONE; - failf(data, "unsupported ALPN protocol: '%.*s'", (int)proto_len, proto); - /* Previous code just ignored it and some vtls backends even ignore the - * return code of this function. */ - /* return CURLE_NOT_BUILT_IN; */ - goto out; - } - if(connssl->state == ssl_connection_deferred) infof(data, VTLS_INFOF_ALPN_DEFERRED, (int)proto_len, proto); else infof(data, VTLS_INFOF_ALPN_ACCEPTED, (int)proto_len, proto); } else { - *palpn = CURL_HTTP_VERSION_NONE; if(connssl->state == ssl_connection_deferred) infof(data, VTLS_INFOF_NO_ALPN_DEFERRED); else diff --git a/deps/curl/lib/vtls/vtls_int.h b/deps/curl/lib/vtls/vtls_int.h index 11987c382a3..de0b735e22b 100644 --- a/deps/curl/lib/vtls/vtls_int.h +++ b/deps/curl/lib/vtls/vtls_int.h @@ -166,8 +166,8 @@ struct Curl_ssl { /* During handshake/shutdown, adjust the pollset to include the socket * for POLLOUT or POLLIN as needed. Mandatory. */ - void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data, - struct easy_pollset *ps); + CURLcode (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data, + struct easy_pollset *ps); void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info); void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data); void (*close_all)(struct Curl_easy *data); @@ -190,8 +190,9 @@ struct Curl_ssl { extern const struct Curl_ssl *Curl_ssl; -void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data, - struct easy_pollset *ps); +CURLcode Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, + struct Curl_easy *data, + struct easy_pollset *ps); /** * Get the SSL filter below the given one or NULL if there is none. diff --git a/deps/curl/lib/vtls/vtls_spack.c b/deps/curl/lib/vtls/vtls_spack.c index 152fad7eb30..10d16f213d4 100644 --- a/deps/curl/lib/vtls/vtls_spack.c +++ b/deps/curl/lib/vtls/vtls_spack.c @@ -24,7 +24,7 @@ #include "../curl_setup.h" -#ifdef USE_SSLS_EXPORT +#if defined(USE_SSL) && defined(USE_SSLS_EXPORT) #include "../urldata.h" #include "../curl_trc.h" @@ -343,4 +343,4 @@ CURLcode Curl_ssl_session_unpack(struct Curl_easy *data, return r; } -#endif /* USE_SSLS_EXPORT */ +#endif /* USE_SSL && USE_SSLS_EXPORT */ diff --git a/deps/curl/lib/vtls/vtls_spack.h b/deps/curl/lib/vtls/vtls_spack.h index 4cdabae30e6..86796ee62ed 100644 --- a/deps/curl/lib/vtls/vtls_spack.h +++ b/deps/curl/lib/vtls/vtls_spack.h @@ -25,7 +25,7 @@ ***************************************************************************/ #include "../curl_setup.h" -#ifdef USE_SSLS_EXPORT +#if defined(USE_SSL) && defined(USE_SSLS_EXPORT) struct dynbuf; struct Curl_ssl_session; @@ -38,6 +38,6 @@ CURLcode Curl_ssl_session_unpack(struct Curl_easy *data, const void *bufv, size_t buflen, struct Curl_ssl_session **ps); -#endif /* USE_SSLS_EXPORT */ +#endif /* USE_SSL && USE_SSLS_EXPORT */ #endif /* HEADER_CURL_VTLS_SPACK_H */ diff --git a/deps/curl/lib/vtls/wolfssl.c b/deps/curl/lib/vtls/wolfssl.c index c3560e8b8d1..afbb9b82182 100644 --- a/deps/curl/lib/vtls/wolfssl.c +++ b/deps/curl/lib/vtls/wolfssl.c @@ -178,7 +178,7 @@ wssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret, Curl_tls_keylog_write(label, client_random, secret, secretSz); return 0; } -#endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */ +#endif /* HAVE_SECRET_CALLBACK && WOLFSSL_TLS13 */ static void wssl_log_tls12_secret(WOLFSSL *ssl) { @@ -243,12 +243,12 @@ static const struct group_name_map gnm[] = { { WOLFSSL_ML_KEM_512, "ML_KEM_512" }, { WOLFSSL_ML_KEM_768, "ML_KEM_768" }, { WOLFSSL_ML_KEM_1024, "ML_KEM_1024" }, - { WOLFSSL_P256_ML_KEM_512, "P256_ML_KEM_512" }, - { WOLFSSL_P384_ML_KEM_768, "P384_ML_KEM_768" }, - { WOLFSSL_P521_ML_KEM_1024, "P521_ML_KEM_1024" }, - { WOLFSSL_P256_ML_KEM_768, "P256_ML_KEM_768" }, - { WOLFSSL_P384_ML_KEM_1024, "P384_ML_KEM_1024" }, - { WOLFSSL_X25519_ML_KEM_768, "X25519_ML_KEM_768" }, + { WOLFSSL_SECP256R1MLKEM512, "SecP256r1MLKEM512" }, + { WOLFSSL_SECP384R1MLKEM768, "SecP384r1MLKEM768" }, + { WOLFSSL_SECP521R1MLKEM1024, "SecP521r1MLKEM1024" }, + { WOLFSSL_SECP256R1MLKEM768, "SecP256r1MLKEM768" }, + { WOLFSSL_SECP384R1MLKEM1024, "SecP384r1MLKEM1024" }, + { WOLFSSL_X25519MLKEM768, "X25519MLKEM768" }, { 0, NULL } }; #endif @@ -931,13 +931,170 @@ wssl_legacy_CTX_set_min_proto_version(WOLFSSL_CTX* ctx, int version) static int wssl_legacy_CTX_set_max_proto_version(WOLFSSL_CTX* ctx, int version) { - (void) ctx, (void) version; + (void)ctx, (void)version; return WOLFSSL_NOT_IMPLEMENTED; } #define wolfSSL_CTX_set_min_proto_version wssl_legacy_CTX_set_min_proto_version #define wolfSSL_CTX_set_max_proto_version wssl_legacy_CTX_set_max_proto_version #endif +static CURLcode client_certificate(struct Curl_easy *data, + struct ssl_config_data *ssl_config, + struct wssl_ctx *wctx) +{ + /* Load the client certificate, and private key */ +#ifndef NO_FILESYSTEM + if(ssl_config->primary.cert_blob || ssl_config->primary.clientcert) { + const char *cert_file = ssl_config->primary.clientcert; + const char *key_file = ssl_config->key; + const struct curl_blob *cert_blob = ssl_config->primary.cert_blob; + const struct curl_blob *key_blob = ssl_config->key_blob; + int file_type = wssl_do_file_type(ssl_config->cert_type); + int rc; + + switch(file_type) { + case WOLFSSL_FILETYPE_PEM: + rc = cert_blob ? + wolfSSL_CTX_use_certificate_chain_buffer(wctx->ssl_ctx, + cert_blob->data, + (long)cert_blob->len) : + wolfSSL_CTX_use_certificate_chain_file(wctx->ssl_ctx, cert_file); + break; + case WOLFSSL_FILETYPE_ASN1: + rc = cert_blob ? + wolfSSL_CTX_use_certificate_buffer(wctx->ssl_ctx, cert_blob->data, + (long)cert_blob->len, file_type) : + wolfSSL_CTX_use_certificate_file(wctx->ssl_ctx, cert_file, file_type); + break; + default: + failf(data, "unknown cert type"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(rc != 1) { + failf(data, "unable to use client certificate"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(!key_blob && !key_file) { + key_blob = cert_blob; + key_file = cert_file; + } + else + file_type = wssl_do_file_type(ssl_config->key_type); + + rc = key_blob ? + wolfSSL_CTX_use_PrivateKey_buffer(wctx->ssl_ctx, key_blob->data, + (long)key_blob->len, file_type) : + wolfSSL_CTX_use_PrivateKey_file(wctx->ssl_ctx, key_file, file_type); + if(rc != 1) { + failf(data, "unable to set private key"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#else /* NO_FILESYSTEM */ + if(ssl_config->primary.cert_blob) { + const struct curl_blob *cert_blob = ssl_config->primary.cert_blob; + const struct curl_blob *key_blob = ssl_config->key_blob; + int file_type = wssl_do_file_type(ssl_config->cert_type); + int rc; + + switch(file_type) { + case WOLFSSL_FILETYPE_PEM: + rc = wolfSSL_CTX_use_certificate_chain_buffer(wctx->ssl_ctx, + cert_blob->data, + (long)cert_blob->len); + break; + case WOLFSSL_FILETYPE_ASN1: + rc = wolfSSL_CTX_use_certificate_buffer(wctx->ssl_ctx, cert_blob->data, + (long)cert_blob->len, file_type); + break; + default: + failf(data, "unknown cert type"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(rc != 1) { + failf(data, "unable to use client certificate"); + return CURLE_SSL_CONNECT_ERROR; + } + + if(!key_blob) + key_blob = cert_blob; + else + file_type = wssl_do_file_type(ssl_config->key_type); + + if(wolfSSL_CTX_use_PrivateKey_buffer(wctx->ssl_ctx, key_blob->data, + (long)key_blob->len, + file_type) != 1) { + failf(data, "unable to set private key"); + return CURLE_SSL_CONNECT_ERROR; + } + } +#endif /* !NO_FILESYSTEM */ + return CURLE_OK; +} + +static CURLcode ssl_version(struct Curl_easy *data, + struct ssl_primary_config *conn_config, + struct wssl_ctx *wctx) +{ + int res; + switch(conn_config->version) { + case CURL_SSLVERSION_DEFAULT: + case CURL_SSLVERSION_TLSv1: + case CURL_SSLVERSION_TLSv1_0: + res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_VERSION); + break; + case CURL_SSLVERSION_TLSv1_1: + res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_1_VERSION); + break; + case CURL_SSLVERSION_TLSv1_2: + res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_2_VERSION); + break; +#ifdef WOLFSSL_TLS13 + case CURL_SSLVERSION_TLSv1_3: + res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_3_VERSION); + break; +#endif + default: + failf(data, "wolfSSL: unsupported minimum TLS version value"); + return CURLE_SSL_CONNECT_ERROR; + } + if(res != WOLFSSL_SUCCESS) { + failf(data, "wolfSSL: failed set the minimum TLS version"); + return CURLE_SSL_CONNECT_ERROR; + } + + switch(conn_config->version_max) { +#ifdef WOLFSSL_TLS13 + case CURL_SSLVERSION_MAX_TLSv1_3: + res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_3_VERSION); + break; +#endif + case CURL_SSLVERSION_MAX_TLSv1_2: + res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_2_VERSION); + break; + case CURL_SSLVERSION_MAX_TLSv1_1: + res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_1_VERSION); + break; + case CURL_SSLVERSION_MAX_TLSv1_0: + res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_VERSION); + break; + case CURL_SSLVERSION_MAX_DEFAULT: + case CURL_SSLVERSION_MAX_NONE: + res = WOLFSSL_SUCCESS; + break; + default: + failf(data, "wolfSSL: unsupported maximum TLS version value"); + return CURLE_SSL_CONNECT_ERROR; + } + if(res != WOLFSSL_SUCCESS) { + failf(data, "wolfSSL: failed set the maximum TLS version"); + return CURLE_SSL_CONNECT_ERROR; + } + return CURLE_OK; +} + + #define QUIC_CIPHERS \ "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_" \ "POLY1305_SHA256:TLS_AES_128_CCM_SHA256" @@ -957,7 +1114,6 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, struct ssl_primary_config *conn_config; WOLFSSL_METHOD* req_method = NULL; struct alpn_spec alpns; - int res; char *curves; #ifdef WOLFSSL_HAVE_KYBER word16 pqkem = 0; @@ -998,63 +1154,9 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, goto out; } - switch(conn_config->version) { - case CURL_SSLVERSION_DEFAULT: - case CURL_SSLVERSION_TLSv1: - case CURL_SSLVERSION_TLSv1_0: - res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_VERSION); - break; - case CURL_SSLVERSION_TLSv1_1: - res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_1_VERSION); - break; - case CURL_SSLVERSION_TLSv1_2: - res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_2_VERSION); - break; -#ifdef WOLFSSL_TLS13 - case CURL_SSLVERSION_TLSv1_3: - res = wolfSSL_CTX_set_min_proto_version(wctx->ssl_ctx, TLS1_3_VERSION); - break; -#endif - default: - failf(data, "wolfSSL: unsupported minimum TLS version value"); - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - if(res != WOLFSSL_SUCCESS) { - failf(data, "wolfSSL: failed set the minimum TLS version"); - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - - switch(conn_config->version_max) { -#ifdef WOLFSSL_TLS13 - case CURL_SSLVERSION_MAX_TLSv1_3: - res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_3_VERSION); - break; -#endif - case CURL_SSLVERSION_MAX_TLSv1_2: - res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_2_VERSION); - break; - case CURL_SSLVERSION_MAX_TLSv1_1: - res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_1_VERSION); - break; - case CURL_SSLVERSION_MAX_TLSv1_0: - res = wolfSSL_CTX_set_max_proto_version(wctx->ssl_ctx, TLS1_VERSION); - break; - case CURL_SSLVERSION_MAX_DEFAULT: - case CURL_SSLVERSION_MAX_NONE: - res = WOLFSSL_SUCCESS; - break; - default: - failf(data, "wolfSSL: unsupported maximum TLS version value"); - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - if(res != WOLFSSL_SUCCESS) { - failf(data, "wolfSSL: failed set the maximum TLS version"); - result = CURLE_SSL_CONNECT_ERROR; + result = ssl_version(data, conn_config, wctx); + if(result) goto out; - } #ifndef WOLFSSL_TLS13 { @@ -1129,100 +1231,9 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, } } - /* Load the client certificate, and private key */ -#ifndef NO_FILESYSTEM - if(ssl_config->primary.cert_blob || ssl_config->primary.clientcert) { - const char *cert_file = ssl_config->primary.clientcert; - const char *key_file = ssl_config->key; - const struct curl_blob *cert_blob = ssl_config->primary.cert_blob; - const struct curl_blob *key_blob = ssl_config->key_blob; - int file_type = wssl_do_file_type(ssl_config->cert_type); - int rc; - - switch(file_type) { - case WOLFSSL_FILETYPE_PEM: - rc = cert_blob ? - wolfSSL_CTX_use_certificate_chain_buffer(wctx->ssl_ctx, - cert_blob->data, - (long)cert_blob->len) : - wolfSSL_CTX_use_certificate_chain_file(wctx->ssl_ctx, cert_file); - break; - case WOLFSSL_FILETYPE_ASN1: - rc = cert_blob ? - wolfSSL_CTX_use_certificate_buffer(wctx->ssl_ctx, cert_blob->data, - (long)cert_blob->len, file_type) : - wolfSSL_CTX_use_certificate_file(wctx->ssl_ctx, cert_file, file_type); - break; - default: - failf(data, "unknown cert type"); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; - } - if(rc != 1) { - failf(data, "unable to use client certificate"); - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - - if(!key_blob && !key_file) { - key_blob = cert_blob; - key_file = cert_file; - } - else - file_type = wssl_do_file_type(ssl_config->key_type); - - rc = key_blob ? - wolfSSL_CTX_use_PrivateKey_buffer(wctx->ssl_ctx, key_blob->data, - (long)key_blob->len, file_type) : - wolfSSL_CTX_use_PrivateKey_file(wctx->ssl_ctx, key_file, file_type); - if(rc != 1) { - failf(data, "unable to set private key"); - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - } -#else /* NO_FILESYSTEM */ - if(ssl_config->primary.cert_blob) { - const struct curl_blob *cert_blob = ssl_config->primary.cert_blob; - const struct curl_blob *key_blob = ssl_config->key_blob; - int file_type = wssl_do_file_type(ssl_config->cert_type); - int rc; - - switch(file_type) { - case WOLFSSL_FILETYPE_PEM: - rc = wolfSSL_CTX_use_certificate_chain_buffer(wctx->ssl_ctx, - cert_blob->data, - (long)cert_blob->len); - break; - case WOLFSSL_FILETYPE_ASN1: - rc = wolfSSL_CTX_use_certificate_buffer(wctx->ssl_ctx, cert_blob->data, - (long)cert_blob->len, file_type); - break; - default: - failf(data, "unknown cert type"); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; - } - if(rc != 1) { - failf(data, "unable to use client certificate"); - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - - if(!key_blob) - key_blob = cert_blob; - else - file_type = wssl_do_file_type(ssl_config->key_type); - - if(wolfSSL_CTX_use_PrivateKey_buffer(wctx->ssl_ctx, key_blob->data, - (long)key_blob->len, - file_type) != 1) { - failf(data, "unable to set private key"); - result = CURLE_SSL_CONNECT_ERROR; - goto out; - } - } -#endif /* !NO_FILESYSTEM */ + result = client_certificate(data, ssl_config, wctx); + if(result) + goto out; /* SSL always tries to verify the peer, this only says whether it should * fail to connect if the verification fails, or if it should continue @@ -1275,7 +1286,7 @@ CURLcode Curl_wssl_ctx_init(struct wssl_ctx *wctx, #ifdef NO_FILESYSTEM else if(conn_config->verifypeer) { failf(data, "SSL: Certificates cannot be loaded because wolfSSL was built" - " with \"no filesystem\". Either disable peer verification" + " with \"no file system\". Either disable peer verification" " (insecure) or if you are building an application with libcurl you" " can load certificates via CURLOPT_SSL_CTX_FUNCTION."); result = CURLE_SSL_CONNECT_ERROR; @@ -1542,6 +1553,7 @@ CURLcode Curl_wssl_verify_pinned(struct Curl_cfilter *cf, data->set.str[STRING_SSL_PINNEDPUBLICKEY]; #else const char * const pinnedpubkey = data->set.str[STRING_SSL_PINNEDPUBLICKEY]; + (void)cf; #endif if(pinnedpubkey) { @@ -1758,7 +1770,7 @@ static CURLcode wssl_handshake(struct Curl_cfilter *cf, } } #ifdef USE_ECH_WOLFSSL - else if(-1 == detail) { + else if(detail == -1) { /* try access a retry_config ECHConfigList for tracing */ byte echConfigs[1000]; word32 echConfigsLen = 1000; @@ -1966,7 +1978,7 @@ static void wssl_close(struct Curl_cfilter *cf, struct Curl_easy *data) struct ssl_connect_data *connssl = cf->ctx; struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend; - (void) data; + (void)data; DEBUGASSERT(wssl); @@ -2239,12 +2251,12 @@ static CURLcode wssl_sha256sum(const unsigned char *tmp, /* input */ } static void *wssl_get_internals(struct ssl_connect_data *connssl, - CURLINFO info UNUSED_PARAM) + CURLINFO info) { struct wssl_ctx *wssl = (struct wssl_ctx *)connssl->backend; - (void)info; DEBUGASSERT(wssl); - return wssl->ssl; + return info == CURLINFO_TLS_SESSION ? + (void *)wssl->ssl_ctx : (void *)wssl->ssl; } const struct Curl_ssl Curl_ssl_wolfssl = { diff --git a/deps/curl/lib/vtls/wolfssl.h b/deps/curl/lib/vtls/wolfssl.h index 19ca609c849..7ff4cfb8817 100644 --- a/deps/curl/lib/vtls/wolfssl.h +++ b/deps/curl/lib/vtls/wolfssl.h @@ -44,7 +44,7 @@ struct wssl_ctx { struct WOLFSSL *ssl; CURLcode io_result; /* result of last BIO cfilter operation */ CURLcode hs_result; /* result of handshake */ - int io_send_blocked_len; /* length of last BIO write that EAGAINed */ + int io_send_blocked_len; /* length of last BIO write that EAGAIN-ed */ BIT(x509_store_setup); /* x509 store has been set up */ BIT(shutting_down); /* TLS is being shut down */ }; diff --git a/deps/curl/lib/ws.c b/deps/curl/lib/ws.c index 7f8a688ca17..3b654281604 100644 --- a/deps/curl/lib/ws.c +++ b/deps/curl/lib/ws.c @@ -108,6 +108,15 @@ struct ws_encoder { BIT(contfragment); /* set TRUE if the previous fragment sent was not final */ }; +/* Control frames are allowed up to 125 characters, rfc6455, ch. 5.5 */ +#define WS_MAX_CNTRL_LEN 125 + +struct ws_cntrl_frame { + unsigned int type; + size_t payload_len; + unsigned char payload[WS_MAX_CNTRL_LEN]; +}; + /* A websocket connection with en- and decoder that treat frames * and keep track of boundaries. */ struct websocket { @@ -116,7 +125,8 @@ struct websocket { struct ws_encoder enc; /* decode of we frames */ struct bufq recvbuf; /* raw data from the server */ struct bufq sendbuf; /* raw data to be sent to the server */ - struct curl_ws_frame frame; /* the current WS FRAME received */ + struct curl_ws_frame recvframe; /* the current WS FRAME received */ + struct ws_cntrl_frame pending; /* a control frame pending to be sent */ size_t sendbuf_payload; /* number of payload bytes in sendbuf */ }; @@ -220,62 +230,66 @@ static int ws_frame_firstbyte2flags(struct Curl_easy *data, } } -static unsigned char ws_frame_flags2firstbyte(struct Curl_easy *data, - unsigned int flags, - bool contfragment, - CURLcode *err) +static CURLcode ws_frame_flags2firstbyte(struct Curl_easy *data, + unsigned int flags, + bool contfragment, + unsigned char *pfirstbyte) { + *pfirstbyte = 0; switch(flags & ~CURLWS_OFFSET) { case 0: if(contfragment) { - infof(data, "[WS] no flags given; interpreting as continuation " + CURL_TRC_WS(data, "no flags given; interpreting as continuation " "fragment for compatibility"); - return (WSBIT_OPCODE_CONT | WSBIT_FIN); + *pfirstbyte = (WSBIT_OPCODE_CONT | WSBIT_FIN); + return CURLE_OK; } failf(data, "[WS] no flags given"); - *err = CURLE_BAD_FUNCTION_ARGUMENT; - return 0xff; + return CURLE_BAD_FUNCTION_ARGUMENT; case CURLWS_CONT: if(contfragment) { infof(data, "[WS] setting CURLWS_CONT flag without message type is " "supported for compatibility but highly discouraged"); - return WSBIT_OPCODE_CONT; + *pfirstbyte = WSBIT_OPCODE_CONT; + return CURLE_OK; } failf(data, "[WS] No ongoing fragmented message to continue"); - *err = CURLE_BAD_FUNCTION_ARGUMENT; - return 0xff; + return CURLE_BAD_FUNCTION_ARGUMENT; case CURLWS_TEXT: - return contfragment ? (WSBIT_OPCODE_CONT | WSBIT_FIN) - : (WSBIT_OPCODE_TEXT | WSBIT_FIN); + *pfirstbyte = contfragment ? (WSBIT_OPCODE_CONT | WSBIT_FIN) + : (WSBIT_OPCODE_TEXT | WSBIT_FIN); + return CURLE_OK; case (CURLWS_TEXT | CURLWS_CONT): - return contfragment ? WSBIT_OPCODE_CONT : WSBIT_OPCODE_TEXT; + *pfirstbyte = contfragment ? WSBIT_OPCODE_CONT : WSBIT_OPCODE_TEXT; + return CURLE_OK; case CURLWS_BINARY: - return contfragment ? (WSBIT_OPCODE_CONT | WSBIT_FIN) - : (WSBIT_OPCODE_BIN | WSBIT_FIN); + *pfirstbyte = contfragment ? (WSBIT_OPCODE_CONT | WSBIT_FIN) + : (WSBIT_OPCODE_BIN | WSBIT_FIN); + return CURLE_OK; case (CURLWS_BINARY | CURLWS_CONT): - return contfragment ? WSBIT_OPCODE_CONT : WSBIT_OPCODE_BIN; + *pfirstbyte = contfragment ? WSBIT_OPCODE_CONT : WSBIT_OPCODE_BIN; + return CURLE_OK; case CURLWS_CLOSE: - return WSBIT_OPCODE_CLOSE | WSBIT_FIN; + *pfirstbyte = WSBIT_OPCODE_CLOSE | WSBIT_FIN; + return CURLE_OK; case (CURLWS_CLOSE | CURLWS_CONT): failf(data, "[WS] CLOSE frame must not be fragmented"); - *err = CURLE_BAD_FUNCTION_ARGUMENT; - return 0xff; + return CURLE_BAD_FUNCTION_ARGUMENT; case CURLWS_PING: - return WSBIT_OPCODE_PING | WSBIT_FIN; + *pfirstbyte = WSBIT_OPCODE_PING | WSBIT_FIN; + return CURLE_OK; case (CURLWS_PING | CURLWS_CONT): failf(data, "[WS] PING frame must not be fragmented"); - *err = CURLE_BAD_FUNCTION_ARGUMENT; - return 0xff; + return CURLE_BAD_FUNCTION_ARGUMENT; case CURLWS_PONG: - return WSBIT_OPCODE_PONG | WSBIT_FIN; + *pfirstbyte = WSBIT_OPCODE_PONG | WSBIT_FIN; + return CURLE_OK; case (CURLWS_PONG | CURLWS_CONT): failf(data, "[WS] PONG frame must not be fragmented"); - *err = CURLE_BAD_FUNCTION_ARGUMENT; - return 0xff; + return CURLE_BAD_FUNCTION_ARGUMENT; default: failf(data, "[WS] unknown flags: %x", flags); - *err = CURLE_BAD_FUNCTION_ARGUMENT; - return 0xff; + return CURLE_BAD_FUNCTION_ARGUMENT; } } @@ -308,15 +322,16 @@ static void ws_dec_info(struct ws_decoder *dec, struct Curl_easy *data, } } -static CURLcode ws_send_raw_blocking(CURL *data, struct websocket *ws, +static CURLcode ws_send_raw_blocking(struct Curl_easy *data, + struct websocket *ws, const char *buffer, size_t buflen); -typedef ssize_t ws_write_payload(const unsigned char *buf, size_t buflen, - int frame_age, int frame_flags, - curl_off_t payload_offset, - curl_off_t payload_len, - void *userp, - CURLcode *err); +typedef CURLcode ws_write_payload(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *userp, + size_t *pnwritten); static void ws_dec_next_frame(struct ws_decoder *dec) { @@ -385,21 +400,20 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, ws_dec_reset(dec); return CURLE_RECV_ERROR; } - if(dec->frame_flags & CURLWS_PING && dec->head[1] > 125) { + if(dec->frame_flags & CURLWS_PING && dec->head[1] > WS_MAX_CNTRL_LEN) { /* The maximum valid size of PING frames is 125 bytes. Accepting overlong pings would mean sending equivalent pongs! */ failf(data, "[WS] received PING frame is too big"); ws_dec_reset(dec); return CURLE_RECV_ERROR; } - if(dec->frame_flags & CURLWS_PONG && dec->head[1] > 125) { + if(dec->frame_flags & CURLWS_PONG && dec->head[1] > WS_MAX_CNTRL_LEN) { /* The maximum valid size of PONG frames is 125 bytes. */ failf(data, "[WS] received PONG frame is too big"); ws_dec_reset(dec); return CURLE_RECV_ERROR; } - if(dec->frame_flags & CURLWS_CLOSE && dec->head[1] > 125) { - /* The maximum valid size of CLOSE frames is 125 bytes. */ + if(dec->frame_flags & CURLWS_CLOSE && dec->head[1] > WS_MAX_CNTRL_LEN) { failf(data, "[WS] received CLOSE frame is too big"); ws_dec_reset(dec); return CURLE_RECV_ERROR; @@ -469,12 +483,12 @@ static CURLcode ws_dec_read_head(struct ws_decoder *dec, static CURLcode ws_dec_pass_payload(struct ws_decoder *dec, struct Curl_easy *data, struct bufq *inraw, - ws_write_payload *write_payload, + ws_write_payload *write_cb, void *write_ctx) { const unsigned char *inbuf; size_t inlen; - ssize_t nwritten; + size_t nwritten; CURLcode result; curl_off_t remain = dec->payload_len - dec->payload_offset; @@ -482,15 +496,15 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec, while(remain && Curl_bufq_peek(inraw, &inbuf, &inlen)) { if((curl_off_t)inlen > remain) inlen = (size_t)remain; - nwritten = write_payload(inbuf, inlen, dec->frame_age, dec->frame_flags, - dec->payload_offset, dec->payload_len, - write_ctx, &result); - if(nwritten < 0) + result = write_cb(inbuf, inlen, dec->frame_age, dec->frame_flags, + dec->payload_offset, dec->payload_len, + write_ctx, &nwritten); + if(result) return result; - Curl_bufq_skip(inraw, (size_t)nwritten); - dec->payload_offset += (curl_off_t)nwritten; + Curl_bufq_skip(inraw, nwritten); + dec->payload_offset += nwritten; remain = dec->payload_len - dec->payload_offset; - CURL_TRC_WS(data, "passed %zd bytes payload, %" + CURL_TRC_WS(data, "passed %zu bytes payload, %" FMT_OFF_T " remain", nwritten, remain); } @@ -500,7 +514,7 @@ static CURLcode ws_dec_pass_payload(struct ws_decoder *dec, static CURLcode ws_dec_pass(struct ws_decoder *dec, struct Curl_easy *data, struct bufq *inraw, - ws_write_payload *write_payload, + ws_write_payload *write_cb, void *write_ctx) { CURLcode result; @@ -517,7 +531,7 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, result = ws_dec_read_head(dec, data, inraw); if(result) { if(result != CURLE_AGAIN) { - infof(data, "[WS] decode error %d", (int)result); + failf(data, "[WS] decode frame error %d", (int)result); break; /* real error */ } /* incomplete ws frame head */ @@ -527,19 +541,19 @@ static CURLcode ws_dec_pass(struct ws_decoder *dec, /* head parsing done */ dec->state = WS_DEC_PAYLOAD; if(dec->payload_len == 0) { - ssize_t nwritten; + size_t nwritten; const unsigned char tmp = '\0'; /* special case of a 0 length frame, need to write once */ - nwritten = write_payload(&tmp, 0, dec->frame_age, dec->frame_flags, - 0, 0, write_ctx, &result); - if(nwritten < 0) + result = write_cb(&tmp, 0, dec->frame_age, dec->frame_flags, + 0, 0, write_ctx, &nwritten); + if(result) return result; dec->state = WS_DEC_INIT; break; } FALLTHROUGH(); case WS_DEC_PAYLOAD: - result = ws_dec_pass_payload(dec, data, inraw, write_payload, write_ctx); + result = ws_dec_pass_payload(dec, data, inraw, write_cb, write_ctx); ws_dec_info(dec, data, "passing"); if(result) return result; @@ -561,11 +575,11 @@ static void update_meta(struct websocket *ws, { curl_off_t bytesleft = (payload_len - payload_offset - cur_len); - ws->frame.age = frame_age; - ws->frame.flags = frame_flags; - ws->frame.offset = payload_offset; - ws->frame.len = cur_len; - ws->frame.bytesleft = bytesleft; + ws->recvframe.age = frame_age; + ws->recvframe.flags = frame_flags; + ws->recvframe.offset = payload_offset; + ws->recvframe.len = cur_len; + ws->recvframe.bytesleft = bytesleft; } /* WebSockets decoding client writer */ @@ -586,7 +600,7 @@ static CURLcode ws_cw_init(struct Curl_easy *data, static void ws_cw_close(struct Curl_easy *data, struct Curl_cwriter *writer) { struct ws_cw_ctx *ctx = writer->ctx; - (void) data; + (void)data; Curl_bufq_free(&ctx->buf); } @@ -597,42 +611,82 @@ struct ws_cw_dec_ctx { int cw_type; }; -static ssize_t ws_cw_dec_next(const unsigned char *buf, size_t buflen, - int frame_age, int frame_flags, - curl_off_t payload_offset, - curl_off_t payload_len, - void *user_data, - CURLcode *err) +static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws, + bool blocking); +static CURLcode ws_enc_send(struct Curl_easy *data, + struct websocket *ws, + const unsigned char *buffer, + size_t buflen, + curl_off_t fragsize, + unsigned int flags, + size_t *sent); +static CURLcode ws_enc_add_pending(struct Curl_easy *data, + struct websocket *ws); + +static CURLcode ws_enc_add_cntrl(struct Curl_easy *data, + struct websocket *ws, + const unsigned char *payload, + size_t plen, + unsigned int frame_type) +{ + DEBUGASSERT(plen <= WS_MAX_CNTRL_LEN); + if(plen > WS_MAX_CNTRL_LEN) + return CURLE_BAD_FUNCTION_ARGUMENT; + + /* Overwrite any pending frame with the new one, we keep + * only one. */ + ws->pending.type = frame_type; + ws->pending.payload_len = plen; + memcpy(ws->pending.payload, payload, plen); + + if(!ws->enc.payload_remain) { /* not in the middle of another frame */ + CURLcode result = ws_enc_add_pending(data, ws); + if(!result) + (void)ws_flush(data, ws, Curl_is_in_callback(data)); + return result; + } + return CURLE_OK; +} + +static CURLcode ws_cw_dec_next(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *user_data, + size_t *pnwritten) { struct ws_cw_dec_ctx *ctx = user_data; struct Curl_easy *data = ctx->data; struct websocket *ws = ctx->ws; bool auto_pong = !data->set.ws_no_auto_pong; curl_off_t remain = (payload_len - (payload_offset + buflen)); + CURLcode result; (void)frame_age; + *pnwritten = 0; if(auto_pong && (frame_flags & CURLWS_PING) && !remain) { /* auto-respond to PINGs, only works for single-frame payloads atm */ - size_t bytes; - infof(data, "[WS] auto-respond to PING with a PONG"); + CURL_TRC_WS(data, "auto PONG to [PING payload=%" FMT_OFF_T + "/%" FMT_OFF_T "]", payload_offset, payload_len); /* send back the exact same content as a PONG */ - *err = curl_ws_send(data, buf, buflen, &bytes, 0, CURLWS_PONG); - if(*err) - return -1; + result = ws_enc_add_cntrl(data, ws, buf, buflen, CURLWS_PONG); + if(result) + return result; } else if(buflen || !remain) { /* forward the decoded frame to the next client writer. */ update_meta(ws, frame_age, frame_flags, payload_offset, payload_len, buflen); - *err = Curl_cwriter_write(data, ctx->next_writer, ctx->cw_type, + result = Curl_cwriter_write(data, ctx->next_writer, + (ctx->cw_type | CLIENTWRITE_0LEN), (const char *)buf, buflen); - if(*err) - return -1; + if(result) + return result; } - *err = CURLE_OK; - return (ssize_t)buflen; + *pnwritten = buflen; + return CURLE_OK; } static CURLcode ws_cw_write(struct Curl_easy *data, @@ -643,6 +697,7 @@ static CURLcode ws_cw_write(struct Curl_easy *data, struct websocket *ws; CURLcode result; + CURL_TRC_WRITE(data, "ws_cw_write(len=%zu, type=%d)", nbytes, type); if(!(type & CLIENTWRITE_BODY) || data->set.ws_raw_mode) return Curl_cwriter_write(data, writer->next, type, buf, nbytes); @@ -657,7 +712,7 @@ static CURLcode ws_cw_write(struct Curl_easy *data, result = Curl_bufq_write(&ctx->buf, (const unsigned char *)buf, nbytes, &nwritten); if(result) { - infof(data, "WS: error adding data to buffer %d", result); + infof(data, "[WS] error adding data to buffer %d", result); return result; } } @@ -673,11 +728,10 @@ static CURLcode ws_cw_write(struct Curl_easy *data, if(result == CURLE_AGAIN) { /* insufficient amount of data, keep it for later. * we pretend to have written all since we have a copy */ - CURL_TRC_WS(data, "buffered incomplete frame head"); return CURLE_OK; } else if(result) { - infof(data, "[WS] decode error %d", (int)result); + failf(data, "[WS] decode payload error %d", (int)result); return result; } } @@ -747,36 +801,33 @@ static void ws_enc_init(struct ws_encoder *enc) +---------------------------------------------------------------+ */ -static ssize_t ws_enc_write_head(struct Curl_easy *data, +static CURLcode ws_enc_add_frame(struct Curl_easy *data, struct ws_encoder *enc, unsigned int flags, curl_off_t payload_len, - struct bufq *out, - CURLcode *err) + struct bufq *out) { - unsigned char firstbyte = 0; + unsigned char firstb = 0; unsigned char head[14]; - size_t hlen, n; + CURLcode result; + size_t hlen, nwritten; if(payload_len < 0) { failf(data, "[WS] starting new frame with negative payload length %" FMT_OFF_T, payload_len); - *err = CURLE_SEND_ERROR; - return -1; + return CURLE_SEND_ERROR; } if(enc->payload_remain > 0) { /* trying to write a new frame before the previous one is finished */ failf(data, "[WS] starting new frame with %zd bytes from last one " "remaining to be sent", (ssize_t)enc->payload_remain); - *err = CURLE_SEND_ERROR; - return -1; + return CURLE_SEND_ERROR; } - firstbyte = ws_frame_flags2firstbyte(data, flags, enc->contfragment, err); - if(*err) { - return -1; - } + result = ws_frame_flags2firstbyte(data, flags, enc->contfragment, &firstb); + if(result) + return result; /* fragmentation only applies to data frames (text/binary); * control frames (close/ping/pong) do not affect the CONT status */ @@ -784,26 +835,20 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data, enc->contfragment = (flags & CURLWS_CONT) ? (bit)TRUE : (bit)FALSE; } - if(flags & CURLWS_PING && payload_len > 125) { - /* The maximum valid size of PING frames is 125 bytes. */ + if(flags & CURLWS_PING && payload_len > WS_MAX_CNTRL_LEN) { failf(data, "[WS] given PING frame is too big"); - *err = CURLE_TOO_LARGE; - return -1; + return CURLE_TOO_LARGE; } - if(flags & CURLWS_PONG && payload_len > 125) { - /* The maximum valid size of PONG frames is 125 bytes. */ + if(flags & CURLWS_PONG && payload_len > WS_MAX_CNTRL_LEN) { failf(data, "[WS] given PONG frame is too big"); - *err = CURLE_TOO_LARGE; - return -1; + return CURLE_TOO_LARGE; } - if(flags & CURLWS_CLOSE && payload_len > 125) { - /* The maximum valid size of CLOSE frames is 125 bytes. */ + if(flags & CURLWS_CLOSE && payload_len > WS_MAX_CNTRL_LEN) { failf(data, "[WS] given CLOSE frame is too big"); - *err = CURLE_TOO_LARGE; - return -1; + return CURLE_TOO_LARGE; } - head[0] = enc->firstbyte = firstbyte; + head[0] = enc->firstbyte = firstb; if(payload_len > 65535) { head[1] = 127 | WSBIT_MASK; head[2] = (unsigned char)((payload_len >> 56) & 0xff); @@ -830,35 +875,63 @@ static ssize_t ws_enc_write_head(struct Curl_easy *data, enc->payload_remain = enc->payload_len = payload_len; ws_enc_info(enc, data, "sending"); + /* 4 bytes random */ + + result = Curl_rand(data, (unsigned char *)&enc->mask, sizeof(enc->mask)); + if(result) + return result; + +#ifdef DEBUGBUILD + if(getenv("CURL_WS_FORCE_ZERO_MASK")) + /* force the bit mask to 0x00000000, effectively disabling masking */ + memset(&enc->mask, 0, sizeof(enc->mask)); +#endif + /* add 4 bytes mask */ memcpy(&head[hlen], &enc->mask, 4); hlen += 4; /* reset for payload to come */ enc->xori = 0; - *err = Curl_bufq_write(out, head, hlen, &n); - if(*err) - return -1; - if(n != hlen) { + result = Curl_bufq_write(out, head, hlen, &nwritten); + if(result) + return result; + if(nwritten != hlen) { /* We use a bufq with SOFT_LIMIT, writing should always succeed */ DEBUGASSERT(0); - *err = CURLE_SEND_ERROR; - return -1; + return CURLE_SEND_ERROR; } - return (ssize_t)n; + return CURLE_OK; } -static ssize_t ws_enc_write_payload(struct ws_encoder *enc, - struct Curl_easy *data, - const unsigned char *buf, size_t buflen, - struct bufq *out, CURLcode *err) +static CURLcode ws_enc_write_head(struct Curl_easy *data, + struct websocket *ws, + struct ws_encoder *enc, + unsigned int flags, + curl_off_t payload_len, + struct bufq *out) +{ + /* starting a new frame, we want a clean sendbuf. + * Any pending control frame we can add now as part of the flush. */ + if(ws->pending.type) { + CURLcode result = ws_enc_add_pending(data, ws); + if(result) + return result; + } + return ws_enc_add_frame(data, enc, flags, payload_len, out); +} + +static CURLcode ws_enc_write_payload(struct ws_encoder *enc, + struct Curl_easy *data, + const unsigned char *buf, size_t buflen, + struct bufq *out, size_t *pnwritten) { + CURLcode result; size_t i, len, n; - if(Curl_bufq_is_full(out)) { - *err = CURLE_AGAIN; - return -1; - } + *pnwritten = 0; + if(Curl_bufq_is_full(out)) + return CURLE_AGAIN; /* not the most performant way to do this */ len = buflen; @@ -867,20 +940,274 @@ static ssize_t ws_enc_write_payload(struct ws_encoder *enc, for(i = 0; i < len; ++i) { unsigned char c = buf[i] ^ enc->mask[enc->xori]; - *err = Curl_bufq_write(out, &c, 1, &n); - if(*err) { - if((*err != CURLE_AGAIN) || !i) - return -1; + result = Curl_bufq_write(out, &c, 1, &n); + if(result) { + if((result != CURLE_AGAIN) || !i) + return result; break; } enc->xori++; enc->xori &= 3; } + *pnwritten = i; enc->payload_remain -= (curl_off_t)i; ws_enc_info(enc, data, "buffered"); - return (ssize_t)i; + return CURLE_OK; +} + +static CURLcode ws_enc_add_pending(struct Curl_easy *data, + struct websocket *ws) +{ + CURLcode result; + size_t n; + + if(!ws->pending.type) /* no pending frame here */ + return CURLE_OK; + if(ws->enc.payload_remain) /* in the middle of another frame */ + return CURLE_AGAIN; + + result = ws_enc_add_frame(data, &ws->enc, ws->pending.type, + (curl_off_t)ws->pending.payload_len, + &ws->sendbuf); + if(result) { + CURL_TRC_WS(data, "ws_enc_cntrl(), error addiong head: %d", + result); + goto out; + } + result = ws_enc_write_payload(&ws->enc, data, ws->pending.payload, + ws->pending.payload_len, + &ws->sendbuf, &n); + if(result) { + CURL_TRC_WS(data, "ws_enc_cntrl(), error adding payload: %d", + result); + goto out; + } + /* our buffer should always be able to take in a control frame */ + DEBUGASSERT(n == ws->pending.payload_len); + DEBUGASSERT(!ws->enc.payload_remain); + +out: + memset(&ws->pending, 0, sizeof(ws->pending)); + return result; +} + +static CURLcode ws_enc_send(struct Curl_easy *data, + struct websocket *ws, + const unsigned char *buffer, + size_t buflen, + curl_off_t fragsize, + unsigned int flags, + size_t *pnsent) +{ + size_t n; + CURLcode result = CURLE_OK; + + DEBUGASSERT(!data->set.ws_raw_mode); + *pnsent = 0; + + if(ws->enc.payload_remain || !Curl_bufq_is_empty(&ws->sendbuf)) { + /* a frame is ongoing with payload buffered or more payload + * that needs to be encoded into the buffer */ + if(buflen < ws->sendbuf_payload) { + /* We have been called with LESS buffer data than before. This + * is not how it's supposed too work. */ + failf(data, "[WS] curl_ws_send() called with smaller 'buflen' than " + "bytes already buffered in previous call, %zu vs %zu", + buflen, ws->sendbuf_payload); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if((curl_off_t)buflen > + (ws->enc.payload_remain + (curl_off_t)ws->sendbuf_payload)) { + /* too large buflen beyond payload length of frame */ + failf(data, "[WS] unaligned frame size (sending %zu instead of %" + FMT_OFF_T ")", + buflen, ws->enc.payload_remain + ws->sendbuf_payload); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + } + else { + result = ws_flush(data, ws, Curl_is_in_callback(data)); + if(result) + return result; + + result = ws_enc_write_head(data, ws, &ws->enc, flags, + (flags & CURLWS_OFFSET) ? + fragsize : (curl_off_t)buflen, + &ws->sendbuf); + if(result) { + CURL_TRC_WS(data, "curl_ws_send(), error writing frame head %d", result); + return result; + } + } + + /* While there is either sendbuf to flush OR more payload to encode... */ + while(!Curl_bufq_is_empty(&ws->sendbuf) || (buflen > ws->sendbuf_payload)) { + /* Try to add more payload to sendbuf */ + if(buflen > ws->sendbuf_payload) { + size_t prev_len = Curl_bufq_len(&ws->sendbuf); + result = ws_enc_write_payload(&ws->enc, data, + buffer + ws->sendbuf_payload, + buflen - ws->sendbuf_payload, + &ws->sendbuf, &n); + if(result && (result != CURLE_AGAIN)) + return result; + ws->sendbuf_payload += Curl_bufq_len(&ws->sendbuf) - prev_len; + if(!ws->sendbuf_payload) { + return CURLE_AGAIN; + } + } + + /* flush, blocking when in callback */ + result = ws_flush(data, ws, Curl_is_in_callback(data)); + if(!result && ws->sendbuf_payload > 0) { + *pnsent += ws->sendbuf_payload; + buffer += ws->sendbuf_payload; + buflen -= ws->sendbuf_payload; + ws->sendbuf_payload = 0; + } + else if(result == CURLE_AGAIN) { + if(ws->sendbuf_payload > Curl_bufq_len(&ws->sendbuf)) { + /* blocked, part of payload bytes remain, report length + * that we managed to send. */ + size_t flushed = (ws->sendbuf_payload - Curl_bufq_len(&ws->sendbuf)); + *pnsent += flushed; + ws->sendbuf_payload -= flushed; + return CURLE_OK; + } + else { + /* blocked before sending headers or 1st payload byte. We cannot report + * OK on 0-length send (caller counts only payload) and EAGAIN */ + CURL_TRC_WS(data, "EAGAIN flushing sendbuf, payload_encoded: %zu/%zu", + ws->sendbuf_payload, buflen); + DEBUGASSERT(*pnsent == 0); + return CURLE_AGAIN; + } + } + else + return result; /* real error sending the data */ + } + return CURLE_OK; +} + +struct cr_ws_ctx { + struct Curl_creader super; + BIT(read_eos); /* we read an EOS from the next reader */ + BIT(eos); /* we have returned an EOS */ +}; + +static CURLcode cr_ws_init(struct Curl_easy *data, struct Curl_creader *reader) +{ + (void)data; + (void)reader; + return CURLE_OK; +} + +static void cr_ws_close(struct Curl_easy *data, struct Curl_creader *reader) +{ + (void)data; + (void)reader; +} + +static CURLcode cr_ws_read(struct Curl_easy *data, + struct Curl_creader *reader, + char *buf, size_t blen, + size_t *pnread, bool *peos) +{ + struct cr_ws_ctx *ctx = reader->ctx; + CURLcode result = CURLE_OK; + size_t nread, n; + struct websocket *ws; + bool eos; + + *pnread = 0; + if(ctx->eos) { + *peos = TRUE; + return CURLE_OK; + } + + ws = Curl_conn_meta_get(data->conn, CURL_META_PROTO_WS_CONN); + if(!ws) { + failf(data, "[WS] not a websocket transfer"); + return CURLE_FAILED_INIT; + } + + if(Curl_bufq_is_empty(&ws->sendbuf)) { + if(ctx->read_eos) { + ctx->eos = TRUE; + *peos = TRUE; + return CURLE_OK; + } + + if(ws->enc.payload_remain) { + CURL_TRC_WS(data, "current frame, %" FMT_OFF_T " remaining", + ws->enc.payload_remain); + if(ws->enc.payload_remain < (curl_off_t)blen) + blen = (size_t)ws->enc.payload_remain; + } + + result = Curl_creader_read(data, reader->next, buf, blen, &nread, &eos); + if(result) + return result; + ctx->read_eos = eos; + + if(!Curl_bufq_is_empty(&ws->sendbuf)) { + /* client_read started a new frame, we disregard any eos reported */ + ctx->read_eos = FALSE; + Curl_creader_clear_eos(data, reader->next); + } + else if(!nread) { + /* nothing to convert, return this right away */ + if(ctx->read_eos) + ctx->eos = TRUE; + *pnread = nread; + *peos = ctx->eos; + goto out; + } + + if(!ws->enc.payload_remain && Curl_bufq_is_empty(&ws->sendbuf)) { + /* encode the data as a new BINARY frame */ + result = ws_enc_write_head(data, ws, &ws->enc, CURLWS_BINARY, nread, + &ws->sendbuf); + if(result) + goto out; + } + + result = ws_enc_write_payload(&ws->enc, data, (unsigned char *)buf, + nread, &ws->sendbuf, &n); + if(result) + goto out; + CURL_TRC_READ(data, "cr_ws_read, added %zu payload, len=%zu", nread, n); + } + + DEBUGASSERT(!Curl_bufq_is_empty(&ws->sendbuf)); + *peos = FALSE; + result = Curl_bufq_cread(&ws->sendbuf, buf, blen, pnread); + if(!result && ctx->read_eos && Curl_bufq_is_empty(&ws->sendbuf)) { + /* no more data, read all, done. */ + ctx->eos = TRUE; + *peos = TRUE; + } + +out: + CURL_TRC_READ(data, "cr_ws_read(len=%zu) -> %d, nread=%zu, eos=%d", + blen, result, *pnread, *peos); + return result; } +static const struct Curl_crtype ws_cr_encode = { + "ws-encode", + cr_ws_init, + cr_ws_read, + cr_ws_close, + Curl_creader_def_needs_rewind, + Curl_creader_def_total_length, + Curl_creader_def_resume_from, + Curl_creader_def_cntrl, + Curl_creader_def_is_paused, + Curl_creader_def_done, + sizeof(struct cr_ws_ctx) +}; + struct wsfield { const char *name; @@ -902,11 +1229,6 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req) MUST include the "websocket" keyword. */ "Upgrade", "websocket" }, - { - /* The request MUST contain a |Connection| header field whose value - MUST include the "Upgrade" token. */ - "Connection", "Upgrade", - }, { /* The request MUST include a header field with the name |Sec-WebSocket-Version|. The value of this header field MUST be @@ -922,7 +1244,7 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req) "Sec-WebSocket-Key", NULL, } }; - heads[3].val = &keyval[0]; + heads[2].val = &keyval[0]; /* 16 bytes random */ result = Curl_rand(data, (unsigned char *)rand, sizeof(rand)); @@ -944,6 +1266,7 @@ CURLcode Curl_ws_request(struct Curl_easy *data, struct dynbuf *req) heads[i].val); } } + data->state.http_hd_upgrade = TRUE; k->upgr101 = UPGR101_WS; return result; } @@ -967,7 +1290,8 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, { struct SingleRequest *k = &data->req; struct websocket *ws; - struct Curl_cwriter *ws_dec_writer; + struct Curl_cwriter *ws_dec_writer = NULL; + struct Curl_creader *ws_enc_reader = NULL; CURLcode result; DEBUGASSERT(data->conn); @@ -1023,33 +1347,17 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, subprotocol not requested by the client), the client MUST Fail the WebSocket Connection. */ - /* 4 bytes random */ - - result = Curl_rand(data, (unsigned char *)&ws->enc.mask, - sizeof(ws->enc.mask)); - if(result) - return result; - -#ifdef DEBUGBUILD - if(getenv("CURL_WS_FORCE_ZERO_MASK")) - /* force the bit mask to 0x00000000, effectively disabling masking */ - memset(ws->enc.mask, 0, sizeof(ws->enc.mask)); -#endif - - infof(data, "[WS] Received 101, switch to WebSocket; mask %02x%02x%02x%02x", - ws->enc.mask[0], ws->enc.mask[1], ws->enc.mask[2], ws->enc.mask[3]); + infof(data, "[WS] Received 101, switch to WebSocket"); /* Install our client writer that decodes WS frames payload */ result = Curl_cwriter_create(&ws_dec_writer, data, &ws_cw_decode, CURL_CW_CONTENT_DECODE); if(result) - return result; - + goto out; result = Curl_cwriter_add(data, ws_dec_writer); - if(result) { - Curl_cwriter_free(data, ws_dec_writer); - return result; - } + if(result) + goto out; + ws_dec_writer = NULL; /* owned by transfer now */ if(data->set.connect_only) { size_t nwritten; @@ -1059,23 +1367,62 @@ CURLcode Curl_ws_accept(struct Curl_easy *data, result = Curl_bufq_write(&ws->recvbuf, (const unsigned char *)mem, nread, &nwritten); if(result) - return result; + goto out; DEBUGASSERT(nread == nwritten); - infof(data, "%zu bytes websocket payload", nread); + k->keepon &= ~KEEP_RECV; /* read no more content */ } else { /* !connect_only */ + if(data->set.method == HTTPREQ_PUT) { + CURL_TRC_WS(data, "UPLOAD set, add ws-encode reader"); + result = Curl_creader_set_fread(data, -1); + if(result) + goto out; + + if(!data->set.ws_raw_mode) { + /* Add our client readerr encoding WS BINARY frames */ + result = Curl_creader_create(&ws_enc_reader, data, &ws_cr_encode, + CURL_CR_CONTENT_ENCODE); + if(result) + goto out; + result = Curl_creader_add(data, ws_enc_reader); + if(result) + goto out; + ws_enc_reader = NULL; /* owned by transfer now */ + } + + /* start over with sending */ + data->req.eos_read = FALSE; + data->req.upload_done = FALSE; + k->keepon |= KEEP_SEND; + } + /* And pass any additional data to the writers */ if(nread) { result = Curl_client_write(data, CLIENTWRITE_BODY, mem, nread); + if(result) + goto out; } } + k->upgr101 = UPGR101_RECEIVED; + k->header = FALSE; /* we will not get more responses */ +out: + if(ws_dec_writer) + Curl_cwriter_free(data, ws_dec_writer); + if(ws_enc_reader) + Curl_creader_free(data, ws_enc_reader); + if(result) + CURL_TRC_WS(data, "Curl_ws_accept() failed -> %d", result); + else + CURL_TRC_WS(data, "websocket established, %s mode", + data->set.connect_only ? "connect-only" : "callback"); return result; } struct ws_collect { struct Curl_easy *data; + struct websocket *ws; unsigned char *buffer; size_t buflen; size_t bufidx; @@ -1086,19 +1433,20 @@ struct ws_collect { bool written; }; -static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen, - int frame_age, int frame_flags, - curl_off_t payload_offset, - curl_off_t payload_len, - void *userp, - CURLcode *err) +static CURLcode ws_client_collect(const unsigned char *buf, size_t buflen, + int frame_age, int frame_flags, + curl_off_t payload_offset, + curl_off_t payload_len, + void *userp, + size_t *pnwritten) { struct ws_collect *ctx = userp; struct Curl_easy *data = ctx->data; bool auto_pong = !data->set.ws_no_auto_pong; - size_t nwritten; curl_off_t remain = (payload_len - (payload_offset + buflen)); + CURLcode result = CURLE_OK; + *pnwritten = 0; if(!ctx->bufidx) { /* first write */ ctx->frame_age = frame_age; @@ -1109,31 +1457,30 @@ static ssize_t ws_client_collect(const unsigned char *buf, size_t buflen, if(auto_pong && (frame_flags & CURLWS_PING) && !remain) { /* auto-respond to PINGs, only works for single-frame payloads atm */ - size_t bytes; - infof(ctx->data, "[WS] auto-respond to PING with a PONG"); + CURL_TRC_WS(data, "auto PONG to [PING payload=%" FMT_OFF_T + "/%" FMT_OFF_T "]", payload_offset, payload_len); /* send back the exact same content as a PONG */ - *err = curl_ws_send(ctx->data, buf, buflen, &bytes, 0, CURLWS_PONG); - if(*err) - return -1; - nwritten = bytes; + result = ws_enc_add_cntrl(ctx->data, ctx->ws, buf, buflen, CURLWS_PONG); + if(result) + return result; + *pnwritten = buflen; } else { + size_t write_len; + ctx->written = TRUE; DEBUGASSERT(ctx->buflen >= ctx->bufidx); - nwritten = CURLMIN(buflen, ctx->buflen - ctx->bufidx); - if(!nwritten) { - if(!buflen) { /* 0 length write, we accept that */ - *err = CURLE_OK; - return 0; - } - *err = CURLE_AGAIN; /* no more space */ - return -1; + write_len = CURLMIN(buflen, ctx->buflen - ctx->bufidx); + if(!write_len) { + if(!buflen) /* 0 length write, we accept that */ + return CURLE_OK; + return CURLE_AGAIN; /* no more space */ } - *err = CURLE_OK; - memcpy(ctx->buffer + ctx->bufidx, buf, nwritten); - ctx->bufidx += nwritten; + memcpy(ctx->buffer + ctx->bufidx, buf, write_len); + ctx->bufidx += write_len; + *pnwritten = write_len; } - return nwritten; + return result; } static CURLcode nw_in_recv(void *reader_ctx, @@ -1149,13 +1496,16 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, const struct curl_ws_frame **metap) { struct Curl_easy *data = d; - struct connectdata *conn = data->conn; + struct connectdata *conn; struct websocket *ws; struct ws_collect ctx; *nread = 0; *metap = NULL; + if(!GOOD_EASY_HANDLE(data)) + return CURLE_BAD_FUNCTION_ARGUMENT; + conn = data->conn; if(!conn) { /* Unhappy hack with lifetimes of transfers and connection */ if(!data->set.connect_only) { @@ -1178,6 +1528,7 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, memset(&ctx, 0, sizeof(ctx)); ctx.data = data; + ctx.ws = ws; ctx.buffer = buffer; ctx.buflen = buflen; @@ -1222,11 +1573,19 @@ CURLcode curl_ws_recv(CURL *d, void *buffer, /* update frame information to be passed back */ update_meta(ws, ctx.frame_age, ctx.frame_flags, ctx.payload_offset, ctx.payload_len, ctx.bufidx); - *metap = &ws->frame; - *nread = ws->frame.len; + *metap = &ws->recvframe; + *nread = ws->recvframe.len; CURL_TRC_WS(data, "curl_ws_recv(len=%zu) -> %zu bytes (frame at %" FMT_OFF_T ", %" FMT_OFF_T " left)", - buflen, *nread, ws->frame.offset, ws->frame.bytesleft); + buflen, *nread, ws->recvframe.offset, + ws->recvframe.bytesleft); + /* all's well, try to send any pending control. we do not know + * when the application will call `curl_ws_send()` again. */ + if(!data->set.ws_raw_mode && ws->pending.type) { + CURLcode r2 = ws_enc_add_pending(data, ws); + if(!r2) + (void)ws_flush(data, ws, Curl_is_in_callback(data)); + } return CURLE_OK; } @@ -1288,12 +1647,12 @@ static CURLcode ws_flush(struct Curl_easy *data, struct websocket *ws, return CURLE_OK; } -static CURLcode ws_send_raw_blocking(CURL *d, struct websocket *ws, +static CURLcode ws_send_raw_blocking(struct Curl_easy *data, + struct websocket *ws, const char *buffer, size_t buflen) { CURLcode result = CURLE_OK; size_t nwritten; - struct Curl_easy *data = d; (void)ws; while(buflen) { @@ -1374,14 +1733,25 @@ CURLcode curl_ws_send(CURL *d, const void *buffer_arg, { struct websocket *ws; const unsigned char *buffer = buffer_arg; - ssize_t n; CURLcode result = CURLE_OK; struct Curl_easy *data = d; + size_t ndummy; + size_t *pnsent = sent ? sent : &ndummy; + if(!GOOD_EASY_HANDLE(data)) + return CURLE_BAD_FUNCTION_ARGUMENT; CURL_TRC_WS(data, "curl_ws_send(len=%zu, fragsize=%" FMT_OFF_T ", flags=%x), raw=%d", buflen, fragsize, flags, data->set.ws_raw_mode); - *sent = 0; + + *pnsent = 0; + + if(!buffer && buflen) { + failf(data, "[WS] buffer is NULL when buflen is not"); + result = CURLE_BAD_FUNCTION_ARGUMENT; + goto out; + } + if(!data->conn && data->set.connect_only) { result = Curl_connect_only_attach(data); if(result) @@ -1406,106 +1776,30 @@ CURLcode curl_ws_send(CURL *d, const void *buffer_arg, if(result) goto out; + if(!buffer) { + failf(data, "[WS] buffer is NULL in raw mode"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } + if(!sent) { + failf(data, "[WS] sent is NULL in raw mode"); + return CURLE_BAD_FUNCTION_ARGUMENT; + } if(fragsize || flags) { failf(data, "[WS] fragsize and flags must be zero in raw mode"); return CURLE_BAD_FUNCTION_ARGUMENT; } - result = ws_send_raw(data, buffer, buflen, sent); + result = ws_send_raw(data, buffer, buflen, pnsent); goto out; } - /* Not RAW mode, buf we do the frame encoding */ - - if(ws->enc.payload_remain || !Curl_bufq_is_empty(&ws->sendbuf)) { - /* a frame is ongoing with payload buffered or more payload - * that needs to be encoded into the buffer */ - if(buflen < ws->sendbuf_payload) { - /* We have been called with LESS buffer data than before. This - * is not how it's supposed too work. */ - failf(data, "[WS] curl_ws_send() called with smaller 'buflen' than " - "bytes already buffered in previous call, %zu vs %zu", - buflen, ws->sendbuf_payload); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; - } - if((curl_off_t)buflen > - (ws->enc.payload_remain + (curl_off_t)ws->sendbuf_payload)) { - /* too large buflen beyond payload length of frame */ - failf(data, "[WS] unaligned frame size (sending %zu instead of %" - FMT_OFF_T ")", - buflen, ws->enc.payload_remain + ws->sendbuf_payload); - result = CURLE_BAD_FUNCTION_ARGUMENT; - goto out; - } - } - else { - /* starting a new frame, we want a clean sendbuf */ - curl_off_t payload_len = (flags & CURLWS_OFFSET) ? - fragsize : (curl_off_t)buflen; - result = ws_flush(data, ws, Curl_is_in_callback(data)); - if(result) - goto out; - - n = ws_enc_write_head(data, &ws->enc, flags, payload_len, - &ws->sendbuf, &result); - if(n < 0) - goto out; - } - - /* While there is either sendbuf to flush OR more payload to encode... */ - while(!Curl_bufq_is_empty(&ws->sendbuf) || (buflen > ws->sendbuf_payload)) { - /* Try to add more payload to sendbuf */ - if(buflen > ws->sendbuf_payload) { - size_t prev_len = Curl_bufq_len(&ws->sendbuf); - n = ws_enc_write_payload(&ws->enc, data, - buffer + ws->sendbuf_payload, - buflen - ws->sendbuf_payload, - &ws->sendbuf, &result); - if(n < 0 && (result != CURLE_AGAIN)) - goto out; - ws->sendbuf_payload += Curl_bufq_len(&ws->sendbuf) - prev_len; - if(!ws->sendbuf_payload) { - result = CURLE_AGAIN; - goto out; - } - } - - /* flush, blocking when in callback */ - result = ws_flush(data, ws, Curl_is_in_callback(data)); - if(!result && ws->sendbuf_payload > 0) { - *sent += ws->sendbuf_payload; - buffer += ws->sendbuf_payload; - buflen -= ws->sendbuf_payload; - ws->sendbuf_payload = 0; - } - else if(result == CURLE_AGAIN) { - if(ws->sendbuf_payload > Curl_bufq_len(&ws->sendbuf)) { - /* blocked, part of payload bytes remain, report length - * that we managed to send. */ - size_t flushed = (ws->sendbuf_payload - Curl_bufq_len(&ws->sendbuf)); - *sent += flushed; - ws->sendbuf_payload -= flushed; - result = CURLE_OK; - goto out; - } - else { - /* blocked before sending headers or 1st payload byte. We cannot report - * OK on 0-length send (caller counts only payload) and EAGAIN */ - CURL_TRC_WS(data, "EAGAIN flushing sendbuf, payload_encoded: %zu/%zu", - ws->sendbuf_payload, buflen); - DEBUGASSERT(*sent == 0); - result = CURLE_AGAIN; - goto out; - } - } - else - goto out; /* real error sending the data */ - } + /* Not RAW mode, we do the frame encoding */ + result = ws_enc_send(data, ws, buffer, buflen, fragsize, flags, pnsent); out: CURL_TRC_WS(data, "curl_ws_send(len=%zu, fragsize=%" FMT_OFF_T ", flags=%x, raw=%d) -> %d, %zu", - buflen, fragsize, flags, data->set.ws_raw_mode, result, *sent); + buflen, fragsize, flags, data->set.ws_raw_mode, result, + *pnsent); return result; } @@ -1531,12 +1825,64 @@ const struct curl_ws_frame *curl_ws_meta(CURL *d) struct websocket *ws; ws = Curl_conn_meta_get(data->conn, CURL_META_PROTO_WS_CONN); if(ws) - return &ws->frame; + return &ws->recvframe; } return NULL; } +CURL_EXTERN CURLcode curl_ws_start_frame(CURL *d, + unsigned int flags, + curl_off_t frame_len) +{ + struct websocket *ws; + CURLcode result = CURLE_OK; + struct Curl_easy *data = d; + + if(!GOOD_EASY_HANDLE(data)) + return CURLE_BAD_FUNCTION_ARGUMENT; + if(data->set.ws_raw_mode) { + failf(data, "cannot curl_ws_start_frame() with CURLWS_RAW_MODE enabled"); + return CURLE_FAILED_INIT; + } + + CURL_TRC_WS(data, "curl_ws_start_frame(flags=%x, frame_len=%" FMT_OFF_T, + flags, frame_len); + + if(!data->conn) { + failf(data, "[WS] No associated connection"); + result = CURLE_SEND_ERROR; + goto out; + } + ws = Curl_conn_meta_get(data->conn, CURL_META_PROTO_WS_CONN); + if(!ws) { + failf(data, "[WS] Not a websocket transfer"); + result = CURLE_SEND_ERROR; + goto out; + } + + if(data->set.ws_raw_mode) { + failf(data, "[WS] cannot start frame in raw mode"); + result = CURLE_SEND_ERROR; + goto out; + } + + if(ws->enc.payload_remain) { + failf(data, "[WS] previous frame not finished"); + result = CURLE_SEND_ERROR; + goto out; + } + + result = ws_enc_write_head(data, ws, &ws->enc, flags, frame_len, + &ws->sendbuf); + if(result) + CURL_TRC_WS(data, "curl_start_frame(), error adding frame head %d", + result); + +out: + return result; +} + const struct Curl_handler Curl_handler_ws = { "WS", /* scheme */ ws_setup_conn, /* setup_connection */ @@ -1546,10 +1892,10 @@ const struct Curl_handler Curl_handler_ws = { Curl_http_connect, /* connect_it */ ZERO_NULL, /* connecting */ ZERO_NULL, /* doing */ - ZERO_NULL, /* proto_getsock */ - Curl_http_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* proto_pollset */ + Curl_http_do_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ Curl_http_write_resp, /* write_resp */ Curl_http_write_resp_hd, /* write_resp_hd */ @@ -1573,10 +1919,10 @@ const struct Curl_handler Curl_handler_wss = { Curl_http_connect, /* connect_it */ NULL, /* connecting */ ZERO_NULL, /* doing */ - NULL, /* proto_getsock */ - Curl_http_getsock_do, /* doing_getsock */ - ZERO_NULL, /* domore_getsock */ - ZERO_NULL, /* perform_getsock */ + NULL, /* proto_pollset */ + Curl_http_do_pollset, /* doing_pollset */ + ZERO_NULL, /* domore_pollset */ + ZERO_NULL, /* perform_pollset */ ZERO_NULL, /* disconnect */ Curl_http_write_resp, /* write_resp */ Curl_http_write_resp_hd, /* write_resp_hd */ @@ -1625,4 +1971,15 @@ const struct curl_ws_frame *curl_ws_meta(CURL *data) (void)data; return NULL; } + +CURL_EXTERN CURLcode curl_ws_start_frame(CURL *curl, + unsigned int flags, + curl_off_t frame_len) +{ + (void)curl; + (void)flags; + (void)frame_len; + return CURLE_NOT_BUILT_IN; +} + #endif /* !CURL_DISABLE_WEBSOCKETS */