aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2020-07-10 20:17:42 -0700
committerHaibo Huang <hhb@google.com>2020-07-13 15:46:10 -0700
commitca2a80266834bba8f490fd9ac51f77d1b8606d93 (patch)
tree2c3eab943845aec3b36d6ea0e33ce0f5cc412033 /lib
parentea155d05e764c6543c0d6be01edf12dda123ed99 (diff)
downloadexternal_curl-ca2a80266834bba8f490fd9ac51f77d1b8606d93.tar.gz
external_curl-ca2a80266834bba8f490fd9ac51f77d1b8606d93.tar.bz2
external_curl-ca2a80266834bba8f490fd9ac51f77d1b8606d93.zip
Upgrade curl to curl-7_71_1
Change-Id: Ief1f908509a0dd7944004e102310c255e42e4803
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.inc22
-rw-r--r--lib/altsvc.c19
-rw-r--r--lib/altsvc.h1
-rw-r--r--lib/asyn-ares.c57
-rw-r--r--lib/asyn-thread.c43
-rw-r--r--lib/asyn.h10
-rwxr-xr-xlib/checksrc.pl41
-rw-r--r--lib/config-win32.h1
-rw-r--r--lib/conncache.c100
-rw-r--r--lib/conncache.h9
-rw-r--r--lib/connect.c124
-rw-r--r--lib/connect.h4
-rw-r--r--lib/content_encoding.c130
-rw-r--r--lib/content_encoding.h26
-rw-r--r--lib/cookie.c2
-rw-r--r--lib/curl_addrinfo.c97
-rw-r--r--lib/curl_addrinfo.h19
-rw-r--r--lib/curl_config.h9
-rw-r--r--lib/curl_config.h.cmake21
-rw-r--r--lib/curl_config.h.in9
-rw-r--r--lib/curl_hmac.h28
-rw-r--r--lib/curl_md5.h20
-rw-r--r--lib/curl_multibyte.c99
-rw-r--r--lib/curl_multibyte.h49
-rw-r--r--lib/curl_ntlm_core.c17
-rw-r--r--lib/curl_ntlm_core.h6
-rw-r--r--lib/curl_ntlm_wb.c67
-rw-r--r--lib/curl_path.c4
-rw-r--r--lib/curl_sasl.c18
-rw-r--r--lib/curl_setup.h23
-rw-r--r--lib/curl_setup_once.h4
-rw-r--r--lib/curl_sspi.c16
-rw-r--r--lib/curl_threads.c4
-rw-r--r--lib/curlx.h12
-rw-r--r--lib/dict.c3
-rw-r--r--lib/doh.c128
-rw-r--r--lib/doh.h21
-rw-r--r--lib/dotdot.c10
-rw-r--r--lib/dynbuf.c227
-rw-r--r--lib/dynbuf.h63
-rw-r--r--lib/easy.c50
-rw-r--r--lib/easyif.h2
-rw-r--r--lib/escape.c78
-rw-r--r--lib/escape.h11
-rw-r--r--lib/file.c2
-rw-r--r--lib/formdata.c20
-rw-r--r--lib/formdata.h6
-rw-r--r--lib/ftp.c82
-rw-r--r--lib/getinfo.c8
-rw-r--r--lib/gopher.c2
-rw-r--r--lib/hmac.c17
-rw-r--r--lib/hostasyn.c10
-rw-r--r--lib/hostip.c100
-rw-r--r--lib/hostip.h22
-rw-r--r--lib/hostip4.c16
-rw-r--r--lib/hostip6.c22
-rw-r--r--lib/http.c811
-rw-r--r--lib/http.h48
-rw-r--r--lib/http2.c223
-rw-r--r--lib/http2.h2
-rw-r--r--lib/http_chunks.c49
-rw-r--r--lib/http_digest.c10
-rw-r--r--lib/http_digest.h2
-rw-r--r--lib/http_negotiate.c19
-rw-r--r--lib/http_negotiate.h6
-rw-r--r--lib/http_ntlm.c14
-rw-r--r--lib/http_ntlm.h6
-rw-r--r--lib/http_proxy.c173
-rw-r--r--lib/http_proxy.h3
-rw-r--r--lib/idn_win32.c10
-rw-r--r--lib/if2ip.c13
-rw-r--r--lib/imap.c16
-rw-r--r--lib/ldap.c67
-rw-r--r--lib/libcurl.plist6
-rw-r--r--lib/md4.c15
-rw-r--r--lib/md5.c22
-rw-r--r--lib/mime.c30
-rw-r--r--lib/mime.h44
-rw-r--r--lib/mprintf.c85
-rw-r--r--lib/mqtt.c5
-rw-r--r--lib/multi.c151
-rw-r--r--lib/multiif.h2
-rw-r--r--lib/nwlib.c39
-rw-r--r--lib/openldap.c14
-rw-r--r--lib/pingpong.c22
-rw-r--r--lib/pingpong.h9
-rw-r--r--lib/pop3.c12
-rw-r--r--lib/progress.c6
-rw-r--r--lib/quic.h4
-rw-r--r--lib/rtsp.c135
-rw-r--r--lib/select.c136
-rw-r--r--lib/select.h8
-rw-r--r--lib/sendf.c38
-rw-r--r--lib/setopt.c128
-rw-r--r--lib/setopt.h4
-rw-r--r--lib/setup-os400.h8
-rw-r--r--lib/setup-vms.h8
-rw-r--r--lib/sha256.c12
-rw-r--r--lib/share.c8
-rw-r--r--lib/smb.c4
-rw-r--r--lib/smtp.c9
-rw-r--r--lib/socks.c63
-rw-r--r--lib/socks_gssapi.c4
-rw-r--r--lib/socks_sspi.c6
-rw-r--r--lib/strerror.c2
-rw-r--r--lib/strtok.c4
-rw-r--r--lib/telnet.c4
-rw-r--r--lib/tftp.c74
-rw-r--r--lib/transfer.c98
-rw-r--r--lib/url.c471
-rw-r--r--lib/url.h7
-rw-r--r--lib/urlapi.c15
-rw-r--r--lib/urldata.h193
-rw-r--r--lib/vauth/cleartext.c5
-rw-r--r--lib/vauth/cram.c4
-rw-r--r--lib/vauth/digest.c2
-rw-r--r--lib/vauth/digest_sspi.c21
-rw-r--r--lib/vauth/krb5_sspi.c11
-rw-r--r--lib/vauth/ntlm.c5
-rw-r--r--lib/vauth/ntlm_sspi.c8
-rw-r--r--lib/vauth/spnego_sspi.c8
-rw-r--r--lib/vauth/vauth.c6
-rw-r--r--lib/vquic/ngtcp2.c372
-rw-r--r--lib/vquic/ngtcp2.h1
-rw-r--r--lib/vquic/quiche.c70
-rw-r--r--lib/vquic/vquic.c85
-rw-r--r--lib/vquic/vquic.h34
-rw-r--r--lib/vssh/libssh2.c299
-rw-r--r--lib/vssh/ssh.h6
-rw-r--r--lib/vssh/wolfssh.c8
-rw-r--r--lib/vtls/bearssl.c2
-rw-r--r--lib/vtls/gskit.c12
-rw-r--r--lib/vtls/gtls.c25
-rw-r--r--lib/vtls/keylog.c156
-rw-r--r--lib/vtls/keylog.h56
-rw-r--r--lib/vtls/mbedtls.c16
-rw-r--r--lib/vtls/mesalink.c7
-rw-r--r--lib/vtls/nss.c6
-rw-r--r--lib/vtls/openssl.c700
-rw-r--r--lib/vtls/schannel.c465
-rw-r--r--lib/vtls/schannel_verify.c22
-rw-r--r--lib/vtls/sectransp.c70
-rw-r--r--lib/vtls/vtls.c88
-rw-r--r--lib/vtls/vtls.h35
-rw-r--r--lib/vtls/wolfssl.c174
-rw-r--r--lib/x509asn1.c75
-rw-r--r--lib/x509asn1.h71
147 files changed, 4840 insertions, 3473 deletions
diff --git a/lib/Makefile.inc b/lib/Makefile.inc
index e3cf4189..723b826e 100644
--- a/lib/Makefile.inc
+++ b/lib/Makefile.inc
@@ -27,18 +27,18 @@ LIB_VAUTH_CFILES = vauth/cleartext.c vauth/cram.c vauth/digest.c \
LIB_VAUTH_HFILES = vauth/digest.h vauth/ntlm.h vauth/vauth.h
-LIB_VTLS_CFILES = vtls/bearssl.c vtls/gskit.c vtls/gtls.c vtls/mbedtls.c \
- vtls/mbedtls_threadlock.c vtls/mesalink.c vtls/nss.c vtls/openssl.c \
- vtls/schannel.c vtls/schannel_verify.c vtls/sectransp.c vtls/vtls.c \
- vtls/wolfssl.c
+LIB_VTLS_CFILES = vtls/bearssl.c vtls/gskit.c vtls/gtls.c vtls/keylog.c \
+ vtls/mbedtls.c vtls/mbedtls_threadlock.c vtls/mesalink.c vtls/nss.c \
+ vtls/openssl.c vtls/schannel.c vtls/schannel_verify.c vtls/sectransp.c \
+ vtls/vtls.c vtls/wolfssl.c
-LIB_VTLS_HFILES = vtls/bearssl.h vtls/gskit.h vtls/gtls.h vtls/mbedtls.h \
- vtls/mbedtls_threadlock.h vtls/mesalink.h vtls/nssg.h vtls/openssl.h \
- vtls/schannel.h vtls/sectransp.h vtls/vtls.h vtls/wolfssl.h
+LIB_VTLS_HFILES = vtls/bearssl.h vtls/gskit.h vtls/gtls.h vtls/keylog.h \
+ vtls/mbedtls.h vtls/mbedtls_threadlock.h vtls/mesalink.h vtls/nssg.h \
+ vtls/openssl.h vtls/schannel.h vtls/sectransp.h vtls/vtls.h vtls/wolfssl.h
-LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c
+LIB_VQUIC_CFILES = vquic/ngtcp2.c vquic/quiche.c vquic/vquic.c
-LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h
+LIB_VQUIC_HFILES = vquic/ngtcp2.h vquic/quiche.h vquic/vquic.h
LIB_VSSH_CFILES = vssh/libssh.c vssh/libssh2.c vssh/wolfssh.c
@@ -60,7 +60,7 @@ LIB_CFILES = altsvc.c amigaos.c asyn-ares.c asyn-thread.c base64.c \
sendf.c setopt.c sha256.c share.c slist.c smb.c smtp.c socketpair.c socks.c \
socks_gssapi.c socks_sspi.c speedcheck.c splay.c strcase.c strdup.c \
strerror.c strtok.c strtoofft.c system_win32.c telnet.c tftp.c timeval.c \
- transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c
+ transfer.c urlapi.c version.c warnless.c wildcard.c x509asn1.c dynbuf.c
LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h \
content_encoding.h cookie.h curl_addrinfo.h curl_base64.h curl_ctype.h \
@@ -79,7 +79,7 @@ LIB_HFILES = altsvc.h amigaos.h arpa_telnet.h asyn.h conncache.h connect.h \
smb.h smtp.h sockaddr.h socketpair.h socks.h speedcheck.h splay.h strcase.h \
strdup.h strerror.h strtok.h strtoofft.h system_win32.h telnet.h tftp.h \
timeval.h transfer.h urlapi-int.h urldata.h warnless.h wildcard.h \
- x509asn1.h
+ x509asn1.h dynbuf.h
LIB_RCFILES = libcurl.rc
diff --git a/lib/altsvc.c b/lib/altsvc.c
index c39d86ea..c2ec489d 100644
--- a/lib/altsvc.c
+++ b/lib/altsvc.c
@@ -50,8 +50,10 @@
#define MAX_ALTSVC_ALPNLENSTR "10"
#define MAX_ALTSVC_ALPNLEN 10
-#if (defined(USE_QUICHE) || defined(USE_NGTCP2)) && !defined(UNITTESTS)
-#define H3VERSION "h3-27"
+#if defined(USE_QUICHE) && !defined(UNITTESTS)
+#define H3VERSION "h3-29"
+#elif defined(USE_NGTCP2) && !defined(UNITTESTS)
+#define H3VERSION "h3-29"
#else
#define H3VERSION "h3"
#endif
@@ -167,7 +169,6 @@ static CURLcode altsvc_add(struct altsvcinfo *asi, char *line)
as->prio = prio;
as->persist = persist ? 1 : 0;
Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
- asi->num++; /* one more entry */
}
}
@@ -408,7 +409,6 @@ static void altsvc_flush(struct altsvcinfo *asi, enum alpnid srcalpnid,
strcasecompare(srchost, as->src.host)) {
Curl_llist_remove(&asi->list, e, NULL);
altsvc_free(as);
- asi->num--;
}
}
}
@@ -429,6 +429,8 @@ static time_t debugtime(void *unused)
#define time(x) debugtime(x)
#endif
+#define ISNEWLINE(x) (((x) == '\n') || (x) == '\r')
+
/*
* Curl_altsvc_parse() takes an incoming alt-svc response header and stores
* the data correctly in the cache.
@@ -474,7 +476,7 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
dstalpnid = alpn2alpnid(alpnbuf);
p++;
if(*p == '\"') {
- const char *dsthost;
+ const char *dsthost = "";
const char *value_ptr;
char option[32];
unsigned long num;
@@ -518,12 +520,12 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
/* Handle the optional 'ma' and 'persist' flags. Unknown flags
are skipped. */
for(;;) {
- while(*p && ISBLANK(*p) && *p != ';' && *p != ',')
+ while(ISBLANK(*p))
p++;
- if(!*p || *p == ',')
+ if(*p != ';')
break;
p++; /* pass the semicolon */
- if(!*p)
+ if(!*p || ISNEWLINE(*p))
break;
result = getalnum(&p, option, sizeof(option));
if(result) {
@@ -573,7 +575,6 @@ CURLcode Curl_altsvc_parse(struct Curl_easy *data,
as->expires = maxage + time(NULL);
as->persist = persist;
Curl_llist_insert_next(&asi->list, asi->list.tail, as, &as->node);
- asi->num++; /* one more entry */
infof(data, "Added alt-svc: %s:%d over %s\n", dsthost, dstport,
Curl_alpnid2str(dstalpnid));
}
diff --git a/lib/altsvc.h b/lib/altsvc.h
index 248e71ee..578a4fbf 100644
--- a/lib/altsvc.h
+++ b/lib/altsvc.h
@@ -52,7 +52,6 @@ struct altsvc {
struct altsvcinfo {
char *filename;
struct curl_llist list; /* list of entries */
- size_t num; /* number of alt-svc entries */
long flags; /* the publicly set bitmask */
};
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c
index b76e6654..ba5160b2 100644
--- a/lib/asyn-ares.c
+++ b/lib/asyn-ares.c
@@ -87,7 +87,8 @@
struct ResolverResults {
int num_pending; /* number of ares_gethostbyname() requests */
- Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
+ struct Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares
+ parts */
int last_status;
struct curltime happy_eyeballs_dns_time; /* when this timer started, or 0 */
};
@@ -285,7 +286,7 @@ int Curl_resolver_getsock(struct connectdata *conn,
* return number of sockets it worked on
*/
-static int waitperform(struct connectdata *conn, int timeout_ms)
+static int waitperform(struct connectdata *conn, timediff_t timeout_ms)
{
struct Curl_easy *data = conn->data;
int nfds;
@@ -352,8 +353,8 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
conn->async.os_specific;
CURLcode result = CURLE_OK;
- if(dns)
- *dns = NULL;
+ DEBUGASSERT(dns);
+ *dns = NULL;
waitperform(conn, 0);
@@ -381,19 +382,18 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
}
if(res && !res->num_pending) {
- if(dns) {
- (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
- /* temp_ai ownership is moved to the connection, so we need not free-up
- them */
- res->temp_ai = NULL;
- }
+ (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
+ /* temp_ai ownership is moved to the connection, so we need not free-up
+ them */
+ res->temp_ai = NULL;
+
if(!conn->async.dns) {
failf(data, "Could not resolve: %s (%s)",
conn->async.hostname, ares_strerror(conn->async.status));
result = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY:
CURLE_COULDNT_RESOLVE_HOST;
}
- else if(dns)
+ else
*dns = conn->async.dns;
destroy_async_data(&conn->async);
@@ -408,7 +408,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
* Waits for a resolve to finish. This function should be avoided since using
* this risk getting the multi interface to "hang".
*
- * If 'entry' is non-NULL, make it point to the resolved dns entry
+ * 'entry' MUST be non-NULL.
*
* Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
* CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
@@ -420,10 +420,9 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
struct Curl_easy *data = conn->data;
timediff_t timeout;
struct curltime now = Curl_now();
- struct Curl_dns_entry *temp_entry;
- if(entry)
- *entry = NULL; /* clear on entry */
+ DEBUGASSERT(entry);
+ *entry = NULL; /* clear on entry */
timeout = Curl_timeleft(data, &now, TRUE);
if(timeout < 0) {
@@ -438,9 +437,13 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
while(!result) {
struct timeval *tvp, tv, store;
int itimeout;
- int timeout_ms;
+ timediff_t timeout_ms;
- itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
+#if TIMEDIFF_T_MAX > INT_MAX
+ itimeout = (timeout > INT_MAX) ? INT_MAX : (int)timeout;
+#else
+ itimeout = (int)timeout;
+#endif
store.tv_sec = itimeout/1000;
store.tv_usec = (itimeout%1000)*1000;
@@ -451,12 +454,12 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
second is left, otherwise just use 1000ms to make sure the progress
callback gets called frequent enough */
if(!tvp->tv_sec)
- timeout_ms = (int)(tvp->tv_usec/1000);
+ timeout_ms = (timediff_t)(tvp->tv_usec/1000);
else
timeout_ms = 1000;
waitperform(conn, timeout_ms);
- result = Curl_resolver_is_resolved(conn, entry?&temp_entry:NULL);
+ result = Curl_resolver_is_resolved(conn, entry);
if(result || conn->async.done)
break;
@@ -471,7 +474,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
else if(timediff > timeout)
timeout = -1;
else
- timeout -= (long)timediff;
+ timeout -= timediff;
now = now2; /* for next loop */
}
if(timeout < 0)
@@ -496,9 +499,9 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
/* Connects results to the list */
static void compound_results(struct ResolverResults *res,
- Curl_addrinfo *ai)
+ struct Curl_addrinfo *ai)
{
- Curl_addrinfo *ai_tail;
+ struct Curl_addrinfo *ai_tail;
if(!ai)
return;
ai_tail = ai;
@@ -540,7 +543,7 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
res->num_pending--;
if(CURL_ASYNC_SUCCESS == status) {
- Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
+ struct Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
if(ai) {
compound_results(res, ai);
}
@@ -619,10 +622,10 @@ static void query_completed_cb(void *arg, /* (struct connectdata *) */
* memory we need to free after use. That memory *MUST* be freed with
* Curl_freeaddrinfo(), nothing else.
*/
-Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
{
char *bufp;
struct Curl_easy *data = conn->data;
diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c
index 68dcbb3e..a60f4f06 100644
--- a/lib/asyn-thread.c
+++ b/lib/asyn-thread.c
@@ -158,7 +158,7 @@ static bool init_resolve_thread(struct connectdata *conn,
/* Data for synchronization between resolver thread and its parent */
struct thread_sync_data {
- curl_mutex_t * mtx;
+ curl_mutex_t *mtx;
int done;
char *hostname; /* hostname to resolve, Curl_async.hostname
@@ -169,7 +169,7 @@ struct thread_sync_data {
curl_socket_t sock_pair[2]; /* socket pair */
#endif
int sock_error;
- Curl_addrinfo *res;
+ struct Curl_addrinfo *res;
#ifdef HAVE_GETADDRINFO
struct addrinfo hints;
#endif
@@ -179,7 +179,7 @@ struct thread_sync_data {
struct thread_data {
curl_thread_t thread_hnd;
unsigned int poll_interval;
- time_t interval_end;
+ timediff_t interval_end;
struct thread_sync_data tsd;
};
@@ -190,7 +190,7 @@ static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
/* Destroy resolver thread synchronization data */
static
-void destroy_thread_sync_data(struct thread_sync_data * tsd)
+void destroy_thread_sync_data(struct thread_sync_data *tsd)
{
if(tsd->mtx) {
Curl_mutex_destroy(tsd->mtx);
@@ -216,7 +216,7 @@ void destroy_thread_sync_data(struct thread_sync_data * tsd)
/* Initialize resolver thread synchronization data */
static
-int init_thread_sync_data(struct thread_data * td,
+int init_thread_sync_data(struct thread_data *td,
const char *hostname,
int port,
const struct addrinfo *hints)
@@ -494,11 +494,14 @@ static CURLcode resolver_error(struct connectdata *conn)
const char *host_or_proxy;
CURLcode result;
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy) {
host_or_proxy = "proxy";
result = CURLE_COULDNT_RESOLVE_PROXY;
}
- else {
+ else
+#endif
+ {
host_or_proxy = "host";
result = CURLE_COULDNT_RESOLVE_HOST;
}
@@ -509,6 +512,9 @@ static CURLcode resolver_error(struct connectdata *conn)
return result;
}
+/*
+ * 'entry' may be NULL and then no data is returned
+ */
static CURLcode thread_wait_resolv(struct connectdata *conn,
struct Curl_dns_entry **entry,
bool report)
@@ -593,6 +599,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
struct thread_data *td = (struct thread_data*) conn->async.os_specific;
int done = 0;
+ DEBUGASSERT(entry);
*entry = NULL;
if(!td) {
@@ -618,8 +625,8 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
else {
/* poll for name lookup done with exponential backoff up to 250ms */
/* should be fine even if this converts to 32 bit */
- time_t elapsed = (time_t)Curl_timediff(Curl_now(),
- data->progress.t_startsingle);
+ timediff_t elapsed = Curl_timediff(Curl_now(),
+ data->progress.t_startsingle);
if(elapsed < 0)
elapsed = 0;
@@ -644,7 +651,7 @@ int Curl_resolver_getsock(struct connectdata *conn,
curl_socket_t *socks)
{
int ret_val = 0;
- time_t milli;
+ timediff_t milli;
timediff_t ms;
struct Curl_easy *data = conn->data;
struct resdata *reslv = (struct resdata *)data->state.resolver;
@@ -668,7 +675,7 @@ int Curl_resolver_getsock(struct connectdata *conn,
if(ms < 3)
milli = 0;
else if(ms <= 50)
- milli = (time_t)ms/3;
+ milli = ms/3;
else if(ms <= 250)
milli = 50;
else
@@ -686,10 +693,10 @@ int Curl_resolver_getsock(struct connectdata *conn,
/*
* Curl_getaddrinfo() - for platforms without getaddrinfo
*/
-Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
{
struct Curl_easy *data = conn->data;
struct resdata *reslv = (struct resdata *)data->state.resolver;
@@ -714,10 +721,10 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
/*
* Curl_resolver_getaddrinfo() - for getaddrinfo
*/
-Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
{
struct addrinfo hints;
int pf = PF_INET;
diff --git a/lib/asyn.h b/lib/asyn.h
index 081c3fef..be2796cf 100644
--- a/lib/asyn.h
+++ b/lib/asyn.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -153,10 +153,10 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
* Each resolver backend must of course make sure to return data in the
* correct format to comply with this.
*/
-Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp);
+struct Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp);
#ifndef CURLRES_ASYNCH
/* convert these functions if an asynch resolver isn't used */
diff --git a/lib/checksrc.pl b/lib/checksrc.pl
index b074f274..97b8f9e1 100755
--- a/lib/checksrc.pl
+++ b/lib/checksrc.pl
@@ -31,14 +31,14 @@ my $warnings = 0;
my $swarnings = 0;
my $errors = 0;
my $serrors = 0;
-my $suppressed; # whitelisted problems
+my $suppressed; # skipped problems
my $file;
my $dir=".";
my $wlist="";
my @alist;
my $windows_os = $^O eq 'MSWin32' || $^O eq 'cygwin' || $^O eq 'msys';
my $verbose;
-my %whitelist;
+my %skiplist;
my %ignore;
my %ignore_set;
@@ -81,14 +81,15 @@ my %warnings = (
'SIZEOFNOPAREN' => 'use of sizeof without parentheses',
'SNPRINTF' => 'use of snprintf',
'ONELINECONDITION' => 'conditional block on the same line as the if()',
+ 'TYPEDEFSTRUCT' => 'typedefed struct',
);
-sub readwhitelist {
- open(W, "<$dir/checksrc.whitelist") or return;
+sub readskiplist {
+ open(W, "<$dir/checksrc.skip") or return;
my @all=<W>;
for(@all) {
$windows_os ? $_ =~ s/\r?\n$// : chomp;
- $whitelist{$_}=1;
+ $skiplist{$_}=1;
}
close(W);
}
@@ -116,10 +117,19 @@ sub readlocalfile {
}
$warnings{$1} = $warnings_extended{$1};
}
+ elsif (/^\s*disable ([A-Z]+)$/) {
+ if(!defined($warnings{$1})) {
+ print STDERR "invalid warning specified in .checksrc: \"$1\"\n";
+ next;
+ }
+ # Accept-list
+ push @alist, $1;
+ }
else {
die "Invalid format in $dir/.checksrc on line $i\n";
}
}
+ close($rcfile);
}
sub checkwarn {
@@ -132,8 +142,8 @@ sub checkwarn {
# print STDERR "Dev! there's no description for $name!\n";
#}
- # checksrc.whitelist
- if($whitelist{$line}) {
+ # checksrc.skip
+ if($skiplist{$line}) {
$nowarn = 1;
}
# !checksrc! controlled
@@ -218,7 +228,7 @@ if(!$file) {
print " -A[rule] Accept this violation, can be used multiple times\n";
print " -D[DIR] Directory to prepend file names\n";
print " -h Show help output\n";
- print " -W[file] Whitelist the given file - ignore all its flaws\n";
+ print " -W[file] Skip the given file - ignore all its flaws\n";
print " -i<n> Indent spaces. Default: 2\n";
print " -m<n> Maximum line length. Default: 79\n";
print "\nDetects and warns for these problems:\n";
@@ -228,7 +238,7 @@ if(!$file) {
exit;
}
-readwhitelist();
+readskiplist();
readlocalfile();
do {
@@ -639,10 +649,10 @@ sub scanfile {
}
# check for 'char * name'
- if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost) *(\*+)) (\w+)/) && ($4 ne "const")) {
- checkwarn("ASTERISKNOSPACE",
+ if(($l =~ /(^.*(char|int|long|void|CURL|CURLM|CURLMsg|[cC]url_[A-Za-z_]+|struct [a-zA-Z_]+) *(\*+)) (\w+)/) && ($4 !~ /^(const|volatile)$/)) {
+ checkwarn("ASTERISKSPACE",
$line, length($1), $file, $ol,
- "no space after declarative asterisk");
+ "space after declarative asterisk");
}
# check for 'char*'
if(($l =~ /(^.*(char|int|long|void|curl_slist|CURL|CURLM|CURLMsg|curl_httppost|sockaddr_in|FILE)\*)/)) {
@@ -697,6 +707,13 @@ sub scanfile {
"no space after semicolon");
}
+ # typedef struct ... {
+ if($nostr =~ /^(.*)typedef struct.*{/) {
+ checkwarn("TYPEDEFSTRUCT",
+ $line, length($1)+1, $file, $ol,
+ "typedef'ed struct");
+ }
+
# check for more than one consecutive space before open brace or
# question mark. Skip lines containing strings since they make it hard
# due to artificially getting multiple spaces
diff --git a/lib/config-win32.h b/lib/config-win32.h
index 516baca0..76ee6b1a 100644
--- a/lib/config-win32.h
+++ b/lib/config-win32.h
@@ -724,6 +724,7 @@ Vista
/* Replicating logic present in afunix.h of newer Windows 10 SDK versions */
# define UNIX_PATH_MAX 108
# include <ws2tcpip.h>
+ /* !checksrc! disable TYPEDEFSTRUCT 1 */
typedef struct sockaddr_un {
ADDRESS_FAMILY sun_family;
char sun_path[UNIX_PATH_MAX];
diff --git a/lib/conncache.c b/lib/conncache.c
index cbd3bb1b..d21a00cf 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -49,53 +49,51 @@ static void conn_llist_dtor(void *user, void *element)
conn->bundle = NULL;
}
-static CURLcode bundle_create(struct Curl_easy *data,
- struct connectbundle **cb_ptr)
+static CURLcode bundle_create(struct connectbundle **bundlep)
{
- (void)data;
- DEBUGASSERT(*cb_ptr == NULL);
- *cb_ptr = malloc(sizeof(struct connectbundle));
- if(!*cb_ptr)
+ DEBUGASSERT(*bundlep == NULL);
+ *bundlep = malloc(sizeof(struct connectbundle));
+ if(!*bundlep)
return CURLE_OUT_OF_MEMORY;
- (*cb_ptr)->num_connections = 0;
- (*cb_ptr)->multiuse = BUNDLE_UNKNOWN;
+ (*bundlep)->num_connections = 0;
+ (*bundlep)->multiuse = BUNDLE_UNKNOWN;
- Curl_llist_init(&(*cb_ptr)->conn_list, (curl_llist_dtor) conn_llist_dtor);
+ Curl_llist_init(&(*bundlep)->conn_list, (curl_llist_dtor) conn_llist_dtor);
return CURLE_OK;
}
-static void bundle_destroy(struct connectbundle *cb_ptr)
+static void bundle_destroy(struct connectbundle *bundle)
{
- if(!cb_ptr)
+ if(!bundle)
return;
- Curl_llist_destroy(&cb_ptr->conn_list, NULL);
+ Curl_llist_destroy(&bundle->conn_list, NULL);
- free(cb_ptr);
+ free(bundle);
}
/* Add a connection to a bundle */
-static void bundle_add_conn(struct connectbundle *cb_ptr,
+static void bundle_add_conn(struct connectbundle *bundle,
struct connectdata *conn)
{
- Curl_llist_insert_next(&cb_ptr->conn_list, cb_ptr->conn_list.tail, conn,
+ Curl_llist_insert_next(&bundle->conn_list, bundle->conn_list.tail, conn,
&conn->bundle_node);
- conn->bundle = cb_ptr;
- cb_ptr->num_connections++;
+ conn->bundle = bundle;
+ bundle->num_connections++;
}
/* Remove a connection from a bundle */
-static int bundle_remove_conn(struct connectbundle *cb_ptr,
+static int bundle_remove_conn(struct connectbundle *bundle,
struct connectdata *conn)
{
struct curl_llist_element *curr;
- curr = cb_ptr->conn_list.head;
+ curr = bundle->conn_list.head;
while(curr) {
if(curr->ptr == conn) {
- Curl_llist_remove(&cb_ptr->conn_list, curr, NULL);
- cb_ptr->num_connections--;
+ Curl_llist_remove(&bundle->conn_list, curr, NULL);
+ bundle->num_connections--;
conn->bundle = NULL;
return 1; /* we removed a handle */
}
@@ -145,12 +143,15 @@ static void hashkey(struct connectdata *conn, char *buf,
const char *hostname;
long port = conn->remote_port;
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
hostname = conn->http_proxy.host.name;
port = conn->port;
}
- else if(conn->bits.conn_to_host)
- hostname = conn->conn_to_host.name;
+ else
+#endif
+ if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
else
hostname = conn->host.name;
@@ -162,20 +163,15 @@ static void hashkey(struct connectdata *conn, char *buf,
msnprintf(buf, len, "%ld%s", port, hostname);
}
-void Curl_conncache_unlock(struct Curl_easy *data)
-{
- CONN_UNLOCK(data);
-}
-
/* Returns number of connections currently held in the connection cache.
Locks/unlocks the cache itself!
*/
size_t Curl_conncache_size(struct Curl_easy *data)
{
size_t num;
- CONN_LOCK(data);
+ CONNCACHE_LOCK(data);
num = data->state.conn_cache->num_conn;
- CONN_UNLOCK(data);
+ CONNCACHE_UNLOCK(data);
return num;
}
@@ -188,7 +184,7 @@ struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
const char **hostp)
{
struct connectbundle *bundle = NULL;
- CONN_LOCK(conn->data);
+ CONNCACHE_LOCK(conn->data);
if(connc) {
char key[HASHKEY_SIZE];
hashkey(conn, key, sizeof(key), hostp);
@@ -235,8 +231,7 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
struct connectdata *conn)
{
CURLcode result = CURLE_OK;
- struct connectbundle *bundle;
- struct connectbundle *new_bundle = NULL;
+ struct connectbundle *bundle = NULL;
struct Curl_easy *data = conn->data;
/* *find_bundle() locks the connection cache */
@@ -245,20 +240,19 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
int rc;
char key[HASHKEY_SIZE];
- result = bundle_create(data, &new_bundle);
+ result = bundle_create(&bundle);
if(result) {
goto unlock;
}
hashkey(conn, key, sizeof(key), NULL);
- rc = conncache_add_bundle(data->state.conn_cache, key, new_bundle);
+ rc = conncache_add_bundle(data->state.conn_cache, key, bundle);
if(!rc) {
- bundle_destroy(new_bundle);
+ bundle_destroy(bundle);
result = CURLE_OUT_OF_MEMORY;
goto unlock;
}
- bundle = new_bundle;
}
bundle_add_conn(bundle, conn);
@@ -270,15 +264,17 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
conn->connection_id, connc->num_conn));
unlock:
- CONN_UNLOCK(data);
+ CONNCACHE_UNLOCK(data);
return result;
}
/*
- * Removes the connectdata object from the connection cache *and* clears the
- * ->data pointer association. Pass TRUE/FALSE in the 'lock' argument
- * depending on if the parent function already holds the lock or not.
+ * Removes the connectdata object from the connection cache, but does *not*
+ * clear the conn->data association. The transfer still owns this connection.
+ *
+ * Pass TRUE/FALSE in the 'lock' argument depending on if the parent function
+ * already holds the lock or not.
*/
void Curl_conncache_remove_conn(struct Curl_easy *data,
struct connectdata *conn, bool lock)
@@ -290,7 +286,7 @@ void Curl_conncache_remove_conn(struct Curl_easy *data,
due to a failed connection attempt, before being added to a bundle */
if(bundle) {
if(lock) {
- CONN_LOCK(data);
+ CONNCACHE_LOCK(data);
}
bundle_remove_conn(bundle, conn);
if(bundle->num_connections == 0)
@@ -301,9 +297,8 @@ void Curl_conncache_remove_conn(struct Curl_easy *data,
DEBUGF(infof(data, "The cache now contains %zu members\n",
connc->num_conn));
}
- conn->data = NULL; /* clear the association */
if(lock) {
- CONN_UNLOCK(data);
+ CONNCACHE_UNLOCK(data);
}
}
}
@@ -332,7 +327,7 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
if(!connc)
return FALSE;
- CONN_LOCK(data);
+ CONNCACHE_LOCK(data);
Curl_hash_start_iterate(&connc->hash, &iter);
he = Curl_hash_next_element(&iter);
@@ -350,12 +345,12 @@ bool Curl_conncache_foreach(struct Curl_easy *data,
curr = curr->next;
if(1 == func(conn, param)) {
- CONN_UNLOCK(data);
+ CONNCACHE_UNLOCK(data);
return TRUE;
}
}
}
- CONN_UNLOCK(data);
+ CONNCACHE_UNLOCK(data);
return FALSE;
}
@@ -494,7 +489,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
now = Curl_now();
- CONN_LOCK(data);
+ CONNCACHE_LOCK(data);
Curl_hash_start_iterate(&connc->hash, &iter);
he = Curl_hash_next_element(&iter);
@@ -531,7 +526,7 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
connc->num_conn));
conn_candidate->data = data; /* associate! */
}
- CONN_UNLOCK(data);
+ CONNCACHE_UNLOCK(data);
return conn_candidate;
}
@@ -539,6 +534,11 @@ Curl_conncache_extract_oldest(struct Curl_easy *data)
void Curl_conncache_close_all_connections(struct conncache *connc)
{
struct connectdata *conn;
+ char buffer[READBUFFER_MIN + 1];
+ if(!connc->closure_handle)
+ return;
+ connc->closure_handle->state.buffer = buffer;
+ connc->closure_handle->set.buffer_size = READBUFFER_MIN;
conn = conncache_find_first_connection(connc);
while(conn) {
@@ -548,12 +548,14 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
sigpipe_ignore(conn->data, &pipe_st);
/* This will remove the connection from the cache */
connclose(conn, "kill all");
+ Curl_conncache_remove_conn(conn->data, conn, TRUE);
(void)Curl_disconnect(connc->closure_handle, conn, FALSE);
sigpipe_restore(&pipe_st);
conn = conncache_find_first_connection(connc);
}
+ connc->closure_handle->state.buffer = NULL;
if(connc->closure_handle) {
SIGPIPE_VARIABLE(pipe_st);
sigpipe_ignore(connc->closure_handle, &pipe_st);
diff --git a/lib/conncache.h b/lib/conncache.h
index e3e4c9c2..3dda21cd 100644
--- a/lib/conncache.h
+++ b/lib/conncache.h
@@ -45,21 +45,21 @@ struct conncache {
#ifdef CURLDEBUG
/* the debug versions of these macros make extra certain that the lock is
never doubly locked or unlocked */
-#define CONN_LOCK(x) if((x)->share) { \
+#define CONNCACHE_LOCK(x) if((x)->share) { \
Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE); \
DEBUGASSERT(!(x)->state.conncache_lock); \
(x)->state.conncache_lock = TRUE; \
}
-#define CONN_UNLOCK(x) if((x)->share) { \
+#define CONNCACHE_UNLOCK(x) if((x)->share) { \
DEBUGASSERT((x)->state.conncache_lock); \
(x)->state.conncache_lock = FALSE; \
Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT); \
}
#else
-#define CONN_LOCK(x) if((x)->share) \
+#define CONNCACHE_LOCK(x) if((x)->share) \
Curl_share_lock((x), CURL_LOCK_DATA_CONNECT, CURL_LOCK_ACCESS_SINGLE)
-#define CONN_UNLOCK(x) if((x)->share) \
+#define CONNCACHE_UNLOCK(x) if((x)->share) \
Curl_share_unlock((x), CURL_LOCK_DATA_CONNECT)
#endif
@@ -77,7 +77,6 @@ void Curl_conncache_destroy(struct conncache *connc);
struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
struct conncache *connc,
const char **hostp);
-void Curl_conncache_unlock(struct Curl_easy *data);
/* returns number of connections currently held in the connection cache */
size_t Curl_conncache_size(struct Curl_easy *data);
diff --git a/lib/connect.c b/lib/connect.c
index 421f9041..29293f08 100644
--- a/lib/connect.c
+++ b/lib/connect.c
@@ -166,7 +166,7 @@ tcpkeepalive(struct Curl_easy *data,
static CURLcode
singleipconnect(struct connectdata *conn,
- const Curl_addrinfo *ai, /* start connecting to this */
+ const struct Curl_addrinfo *ai, /* start connecting to this */
int tempindex); /* 0 or 1 among the temp ones */
/*
@@ -558,11 +558,11 @@ static bool verifyconnect(curl_socket_t sockfd, int *error)
/* update tempaddr[tempindex] (to the next entry), makes sure to stick
to the correct family */
-static Curl_addrinfo *ainext(struct connectdata *conn,
- int tempindex,
- bool next) /* use current or next entry */
+static struct Curl_addrinfo *ainext(struct connectdata *conn,
+ int tempindex,
+ bool next) /* use next entry? */
{
- Curl_addrinfo *ai = conn->tempaddr[tempindex];
+ struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
if(ai && next)
ai = ai->ai_next;
while(ai && (ai->ai_family != conn->tempfamily[tempindex]))
@@ -571,7 +571,7 @@ static Curl_addrinfo *ainext(struct connectdata *conn,
return ai;
}
-/* Used within the multi interface. Try next IP address, return TRUE if no
+/* Used within the multi interface. Try next IP address, returns error if no
more address exists or error */
static CURLcode trynextip(struct connectdata *conn,
int sockindex,
@@ -587,7 +587,7 @@ static CURLcode trynextip(struct connectdata *conn,
conn->tempsock[tempindex] = CURL_SOCKET_BAD;
if(sockindex == FIRSTSOCKET) {
- Curl_addrinfo *ai = conn->tempaddr[tempindex];
+ struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
while(ai) {
if(ai) {
@@ -747,8 +747,8 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
{
CURLcode result = CURLE_OK;
- if(conn->bits.socksproxy) {
#ifndef CURL_DISABLE_PROXY
+ if(conn->bits.socksproxy) {
/* for the secondary socket (FTP), use the "connect to host"
* but ignore the "connect to port" (use the secondary port)
*/
@@ -781,11 +781,12 @@ static CURLcode connect_SOCKS(struct connectdata *conn, int sockindex,
failf(conn->data, "unknown proxytype option given");
result = CURLE_COULDNT_CONNECT;
} /* switch proxytype */
-#else
- (void)sockindex;
-#endif /* CURL_DISABLE_PROXY */
}
else
+#else
+ (void)conn;
+ (void)sockindex;
+#endif /* CURL_DISABLE_PROXY */
*done = TRUE; /* no SOCKS proxy, so consider us connected */
return result;
@@ -822,8 +823,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
timediff_t allow;
int error = 0;
struct curltime now;
- int rc;
- int i;
+ int rc = 0;
+ unsigned int i;
DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
@@ -858,49 +859,50 @@ CURLcode Curl_is_connected(struct connectdata *conn,
const int other = i ^ 1;
if(conn->tempsock[i] == CURL_SOCKET_BAD)
continue;
-
+ error = 0;
#ifdef ENABLE_QUIC
if(conn->transport == TRNSPRT_QUIC) {
result = Curl_quic_is_connected(conn, i, connected);
- if(result) {
- error = SOCKERRNO;
- goto error;
- }
- if(*connected) {
+ if(!result && *connected) {
/* use this socket from now on */
conn->sock[sockindex] = conn->tempsock[i];
conn->ip_addr = conn->tempaddr[i];
conn->tempsock[i] = CURL_SOCKET_BAD;
post_SOCKS(conn, sockindex, connected);
connkeep(conn, "HTTP/3 default");
+ return CURLE_OK;
}
- return result;
+ if(result)
+ error = SOCKERRNO;
}
+ else
#endif
-
+ {
#ifdef mpeix
- /* Call this function once now, and ignore the results. We do this to
- "clear" the error state on the socket so that we can later read it
- reliably. This is reported necessary on the MPE/iX operating system. */
- (void)verifyconnect(conn->tempsock[i], NULL);
+ /* Call this function once now, and ignore the results. We do this to
+ "clear" the error state on the socket so that we can later read it
+ reliably. This is reported necessary on the MPE/iX operating
+ system. */
+ (void)verifyconnect(conn->tempsock[i], NULL);
#endif
- /* check socket for connect */
- rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
+ /* check socket for connect */
+ rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
+ }
if(rc == 0) { /* no connection yet */
- error = 0;
- if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
+ if(Curl_timediff(now, conn->connecttime) >=
+ conn->timeoutms_per_addr[i]) {
infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
- "ms connect time, move on!\n", conn->timeoutms_per_addr);
+ "ms connect time, move on!\n", conn->timeoutms_per_addr[i]);
error = ETIMEDOUT;
}
/* should we try another protocol family? */
- if(i == 0 && !conn->parallel_connect &&
+ if(i == 0 && !conn->bits.parallel_connect &&
(Curl_timediff(now, conn->connecttime) >=
data->set.happy_eyeballs_timeout)) {
- conn->parallel_connect = TRUE; /* starting now */
+ conn->bits.parallel_connect = TRUE; /* starting now */
trynextip(conn, sockindex, 1);
}
}
@@ -937,9 +939,6 @@ CURLcode Curl_is_connected(struct connectdata *conn,
else if(rc & CURL_CSELECT_ERR)
(void)verifyconnect(conn->tempsock[i], &error);
-#ifdef ENABLE_QUIC
- error:
-#endif
/*
* The connection failed here, we should attempt to connect to the "next
* address" for the given host. But first remember the latest error.
@@ -952,13 +951,14 @@ CURLcode Curl_is_connected(struct connectdata *conn,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
char ipaddress[MAX_IPADR_LEN];
char buffer[STRERROR_LEN];
- Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
-#endif
+ Curl_printable_address(conn->tempaddr[i], ipaddress,
+ sizeof(ipaddress));
infof(data, "connect to %s port %ld failed: %s\n",
ipaddress, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
+#endif
- conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
+ conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ?
allow : allow / 2;
ainext(conn, i, TRUE);
status = trynextip(conn, sockindex, i);
@@ -970,25 +970,28 @@ CURLcode Curl_is_connected(struct connectdata *conn,
}
}
- if(result) {
+ if(result &&
+ (conn->tempsock[0] == CURL_SOCKET_BAD) &&
+ (conn->tempsock[1] == CURL_SOCKET_BAD)) {
/* no more addresses to try */
const char *hostname;
char buffer[STRERROR_LEN];
- /* if the first address family runs out of addresses to try before
- the happy eyeball timeout, go ahead and try the next family now */
- {
- result = trynextip(conn, sockindex, 1);
- if(!result)
- return result;
- }
+ /* if the first address family runs out of addresses to try before the
+ happy eyeball timeout, go ahead and try the next family now */
+ result = trynextip(conn, sockindex, 1);
+ if(!result)
+ return result;
+#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 if(conn->bits.conn_to_host)
- hostname = conn->conn_to_host.name;
+ else
+#endif
+ if(conn->bits.conn_to_host)
+ hostname = conn->conn_to_host.name;
else
hostname = conn->host.name;
@@ -996,6 +999,9 @@ CURLcode Curl_is_connected(struct connectdata *conn,
hostname, conn->port,
Curl_strerror(error, buffer, sizeof(buffer)));
+ Curl_quic_disconnect(conn, 0);
+ Curl_quic_disconnect(conn, 1);
+
#ifdef WSAETIMEDOUT
if(WSAETIMEDOUT == data->state.os_errno)
result = CURLE_OPERATION_TIMEDOUT;
@@ -1004,6 +1010,8 @@ CURLcode Curl_is_connected(struct connectdata *conn,
result = CURLE_OPERATION_TIMEDOUT;
#endif
}
+ else
+ result = CURLE_OK; /* still trying */
return result;
}
@@ -1105,7 +1113,7 @@ void Curl_sndbufset(curl_socket_t sockfd)
* having connected.
*/
static CURLcode singleipconnect(struct connectdata *conn,
- const Curl_addrinfo *ai,
+ const struct Curl_addrinfo *ai,
int tempindex)
{
struct Curl_sockaddr_ex addr;
@@ -1195,8 +1203,10 @@ static CURLcode singleipconnect(struct connectdata *conn,
(void)curlx_nonblock(sockfd, TRUE);
conn->connecttime = Curl_now();
- if(conn->num_addr > 1)
- Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
+ if(conn->num_addr > 1) {
+ Curl_expire(data, conn->timeoutms_per_addr[0], EXPIRE_DNS_PER_NAME);
+ Curl_expire(data, conn->timeoutms_per_addr[1], EXPIRE_DNS_PER_NAME2);
+ }
/* Connect TCP and QUIC sockets */
if(!isconnected && (conn->transport != TRNSPRT_UDP)) {
@@ -1319,8 +1329,10 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
conn->tempsock[0] = conn->tempsock[1] = CURL_SOCKET_BAD;
/* Max time for the next connection attempt */
- conn->timeoutms_per_addr =
+ conn->timeoutms_per_addr[0] =
conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
+ conn->timeoutms_per_addr[1] =
+ conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
conn->tempfamily[0] = conn->tempaddr[0]?
conn->tempaddr[0]->ai_family:0;
@@ -1443,11 +1455,11 @@ int Curl_closesocket(struct connectdata *conn,
curl_socket_t sock)
{
if(conn && conn->fclosesocket) {
- if((sock == conn->sock[SECONDARYSOCKET]) && conn->sock_accepted)
+ if((sock == conn->sock[SECONDARYSOCKET]) && conn->bits.sock_accepted)
/* if this socket matches the second socket, and that was created with
accept, then we MUST NOT call the callback but clear the accepted
status */
- conn->sock_accepted = FALSE;
+ conn->bits.sock_accepted = FALSE;
else {
int rc;
Curl_multi_closed(conn->data, sock);
@@ -1477,7 +1489,7 @@ int Curl_closesocket(struct connectdata *conn,
*
*/
CURLcode Curl_socket(struct connectdata *conn,
- const Curl_addrinfo *ai,
+ const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
curl_socket_t *sockfd)
{
@@ -1559,6 +1571,7 @@ void Curl_conncontrol(struct connectdata *conn,
/* close if a connection, or a stream that isn't multiplexed */
bool closeit = (ctrl == CONNCTRL_CONNECTION) ||
((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
+ DEBUGASSERT(conn);
if((ctrl == CONNCTRL_STREAM) &&
(conn->handler->flags & PROTOPT_STREAM))
DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
@@ -1574,6 +1587,7 @@ void Curl_conncontrol(struct connectdata *conn,
bool Curl_conn_data_pending(struct connectdata *conn, int sockindex)
{
int readable;
+ DEBUGASSERT(conn);
if(Curl_ssl_data_pending(conn, sockindex) ||
Curl_recv_has_postponed_data(conn, sockindex))
diff --git a/lib/connect.h b/lib/connect.h
index b23085a9..6fd9ea87 100644
--- a/lib/connect.h
+++ b/lib/connect.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -105,7 +105,7 @@ struct Curl_sockaddr_ex {
*
*/
CURLcode Curl_socket(struct connectdata *conn,
- const Curl_addrinfo *ai,
+ const struct Curl_addrinfo *ai,
struct Curl_sockaddr_ex *addr,
curl_socket_t *sockfd);
diff --git a/lib/content_encoding.c b/lib/content_encoding.c
index 6d475378..e2e68a11 100644
--- a/lib/content_encoding.c
+++ b/lib/content_encoding.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -81,11 +81,11 @@ typedef enum {
} zlibInitState;
/* Writer parameters. */
-typedef struct {
+struct zlib_params {
zlibInitState zlib_init; /* zlib init state */
uInt trailerlen; /* Remaining trailer byte count. */
z_stream z; /* State structure for zlib. */
-} zlib_params;
+};
static voidpf
@@ -133,7 +133,8 @@ exit_zlib(struct connectdata *conn,
return result;
}
-static CURLcode process_trailer(struct connectdata *conn, zlib_params *zp)
+static CURLcode process_trailer(struct connectdata *conn,
+ struct zlib_params *zp)
{
z_stream *z = &zp->z;
CURLcode result = CURLE_OK;
@@ -157,9 +158,10 @@ static CURLcode process_trailer(struct connectdata *conn, zlib_params *zp)
}
static CURLcode inflate_stream(struct connectdata *conn,
- contenc_writer *writer, zlibInitState started)
+ struct contenc_writer *writer,
+ zlibInitState started)
{
- zlib_params *zp = (zlib_params *) &writer->params;
+ struct zlib_params *zp = (struct zlib_params *) &writer->params;
z_stream *z = &zp->z; /* zlib state structure */
uInt nread = z->avail_in;
Bytef *orig_in = z->next_in;
@@ -259,9 +261,9 @@ static CURLcode inflate_stream(struct connectdata *conn,
/* Deflate handler. */
static CURLcode deflate_init_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
- zlib_params *zp = (zlib_params *) &writer->params;
+ struct zlib_params *zp = (struct zlib_params *) &writer->params;
z_stream *z = &zp->z; /* zlib state structure */
if(!writer->downstream)
@@ -278,10 +280,10 @@ static CURLcode deflate_init_writer(struct connectdata *conn,
}
static CURLcode deflate_unencode_write(struct connectdata *conn,
- contenc_writer *writer,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
- zlib_params *zp = (zlib_params *) &writer->params;
+ struct zlib_params *zp = (struct zlib_params *) &writer->params;
z_stream *z = &zp->z; /* zlib state structure */
/* Set the compressed input when this function is called */
@@ -296,29 +298,29 @@ static CURLcode deflate_unencode_write(struct connectdata *conn,
}
static void deflate_close_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
- zlib_params *zp = (zlib_params *) &writer->params;
+ struct zlib_params *zp = (struct zlib_params *) &writer->params;
z_stream *z = &zp->z; /* zlib state structure */
exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
}
-static const content_encoding deflate_encoding = {
+static const struct content_encoding deflate_encoding = {
"deflate",
NULL,
deflate_init_writer,
deflate_unencode_write,
deflate_close_writer,
- sizeof(zlib_params)
+ sizeof(struct zlib_params)
};
/* Gzip handler. */
static CURLcode gzip_init_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
- zlib_params *zp = (zlib_params *) &writer->params;
+ struct zlib_params *zp = (struct zlib_params *) &writer->params;
z_stream *z = &zp->z; /* zlib state structure */
if(!writer->downstream)
@@ -432,10 +434,10 @@ static enum {
#endif
static CURLcode gzip_unencode_write(struct connectdata *conn,
- contenc_writer *writer,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
- zlib_params *zp = (zlib_params *) &writer->params;
+ struct zlib_params *zp = (struct zlib_params *) &writer->params;
z_stream *z = &zp->z; /* zlib state structure */
if(zp->zlib_init == ZLIB_INIT_GZIP) {
@@ -560,33 +562,31 @@ static CURLcode gzip_unencode_write(struct connectdata *conn,
}
static void gzip_close_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
- zlib_params *zp = (zlib_params *) &writer->params;
+ struct zlib_params *zp = (struct zlib_params *) &writer->params;
z_stream *z = &zp->z; /* zlib state structure */
exit_zlib(conn, z, &zp->zlib_init, CURLE_OK);
}
-static const content_encoding gzip_encoding = {
+static const struct content_encoding gzip_encoding = {
"gzip",
"x-gzip",
gzip_init_writer,
gzip_unencode_write,
gzip_close_writer,
- sizeof(zlib_params)
+ sizeof(struct zlib_params)
};
#endif /* HAVE_LIBZ */
#ifdef HAVE_BROTLI
-
/* Writer parameters. */
-typedef struct {
+struct brotli_params {
BrotliDecoderState *br; /* State structure for brotli. */
-} brotli_params;
-
+};
static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
{
@@ -627,10 +627,9 @@ static CURLcode brotli_map_error(BrotliDecoderErrorCode be)
}
static CURLcode brotli_init_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
- brotli_params *bp = (brotli_params *) &writer->params;
-
+ struct brotli_params *bp = (struct brotli_params *) &writer->params;
(void) conn;
if(!writer->downstream)
@@ -641,10 +640,10 @@ static CURLcode brotli_init_writer(struct connectdata *conn,
}
static CURLcode brotli_unencode_write(struct connectdata *conn,
- contenc_writer *writer,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
- brotli_params *bp = (brotli_params *) &writer->params;
+ struct brotli_params *bp = (struct brotli_params *) &writer->params;
const uint8_t *src = (const uint8_t *) buf;
char *decomp;
uint8_t *dst;
@@ -689,10 +688,9 @@ static CURLcode brotli_unencode_write(struct connectdata *conn,
}
static void brotli_close_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
- brotli_params *bp = (brotli_params *) &writer->params;
-
+ struct brotli_params *bp = (struct brotli_params *) &writer->params;
(void) conn;
if(bp->br) {
@@ -701,40 +699,40 @@ static void brotli_close_writer(struct connectdata *conn,
}
}
-static const content_encoding brotli_encoding = {
+static const struct content_encoding brotli_encoding = {
"br",
NULL,
brotli_init_writer,
brotli_unencode_write,
brotli_close_writer,
- sizeof(brotli_params)
+ sizeof(struct brotli_params)
};
#endif
/* Identity handler. */
static CURLcode identity_init_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
(void) conn;
return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
}
static CURLcode identity_unencode_write(struct connectdata *conn,
- contenc_writer *writer,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
return Curl_unencode_write(conn, writer->downstream, buf, nbytes);
}
static void identity_close_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
(void) conn;
(void) writer;
}
-static const content_encoding identity_encoding = {
+static const struct content_encoding identity_encoding = {
"identity",
"none",
identity_init_writer,
@@ -745,7 +743,7 @@ static const content_encoding identity_encoding = {
/* supported content encodings table. */
-static const content_encoding * const encodings[] = {
+static const struct content_encoding * const encodings[] = {
&identity_encoding,
#ifdef HAVE_LIBZ
&deflate_encoding,
@@ -762,8 +760,8 @@ static const content_encoding * const encodings[] = {
char *Curl_all_content_encodings(void)
{
size_t len = 0;
- const content_encoding * const *cep;
- const content_encoding *ce;
+ const struct content_encoding * const *cep;
+ const struct content_encoding *ce;
char *ace;
for(cep = encodings; *cep; cep++) {
@@ -796,14 +794,14 @@ char *Curl_all_content_encodings(void)
/* Real client writer: no downstream. */
static CURLcode client_init_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
(void) conn;
return writer->downstream? CURLE_WRITE_ERROR: CURLE_OK;
}
static CURLcode client_unencode_write(struct connectdata *conn,
- contenc_writer *writer,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
struct Curl_easy *data = conn->data;
@@ -818,13 +816,13 @@ static CURLcode client_unencode_write(struct connectdata *conn,
}
static void client_close_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
(void) conn;
(void) writer;
}
-static const content_encoding client_encoding = {
+static const struct content_encoding client_encoding = {
NULL,
NULL,
client_init_writer,
@@ -836,14 +834,14 @@ static const content_encoding client_encoding = {
/* Deferred error dummy writer. */
static CURLcode error_init_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
(void) conn;
return writer->downstream? CURLE_OK: CURLE_WRITE_ERROR;
}
static CURLcode error_unencode_write(struct connectdata *conn,
- contenc_writer *writer,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
char *all = Curl_all_content_encodings();
@@ -861,13 +859,13 @@ static CURLcode error_unencode_write(struct connectdata *conn,
}
static void error_close_writer(struct connectdata *conn,
- contenc_writer *writer)
+ struct contenc_writer *writer)
{
(void) conn;
(void) writer;
}
-static const content_encoding error_encoding = {
+static const struct content_encoding error_encoding = {
NULL,
NULL,
error_init_writer,
@@ -877,12 +875,13 @@ static const content_encoding error_encoding = {
};
/* Create an unencoding writer stage using the given handler. */
-static contenc_writer *new_unencoding_writer(struct connectdata *conn,
- const content_encoding *handler,
- contenc_writer *downstream)
+static struct contenc_writer *
+new_unencoding_writer(struct connectdata *conn,
+ const struct content_encoding *handler,
+ struct contenc_writer *downstream)
{
- size_t sz = offsetof(contenc_writer, params) + handler->paramsize;
- contenc_writer *writer = (contenc_writer *) calloc(1, sz);
+ size_t sz = offsetof(struct contenc_writer, params) + handler->paramsize;
+ struct contenc_writer *writer = (struct contenc_writer *)calloc(1, sz);
if(writer) {
writer->handler = handler;
@@ -897,7 +896,8 @@ static contenc_writer *new_unencoding_writer(struct connectdata *conn,
}
/* Write data using an unencoding writer stack. */
-CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+CURLcode Curl_unencode_write(struct connectdata *conn,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
if(!nbytes)
@@ -910,7 +910,7 @@ void Curl_unencode_cleanup(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
struct SingleRequest *k = &data->req;
- contenc_writer *writer = k->writer_stack;
+ struct contenc_writer *writer = k->writer_stack;
while(writer) {
k->writer_stack = writer->downstream;
@@ -921,12 +921,13 @@ void Curl_unencode_cleanup(struct connectdata *conn)
}
/* Find the content encoding by name. */
-static const content_encoding *find_encoding(const char *name, size_t len)
+static const struct content_encoding *find_encoding(const char *name,
+ size_t len)
{
- const content_encoding * const *cep;
+ const struct content_encoding * const *cep;
for(cep = encodings; *cep; cep++) {
- const content_encoding *ce = *cep;
+ const struct content_encoding *ce = *cep;
if((strncasecompare(name, ce->name, len) && !ce->name[len]) ||
(ce->alias && strncasecompare(name, ce->alias, len) && !ce->alias[len]))
return ce;
@@ -962,8 +963,8 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
Curl_httpchunk_init(conn); /* init our chunky engine. */
}
else if(namelen) {
- const content_encoding *encoding = find_encoding(name, namelen);
- contenc_writer *writer;
+ const struct content_encoding *encoding = find_encoding(name, namelen);
+ struct contenc_writer *writer;
if(!k->writer_stack) {
k->writer_stack = new_unencoding_writer(conn, &client_encoding, NULL);
@@ -997,7 +998,8 @@ CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
return CURLE_NOT_BUILT_IN;
}
-CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+CURLcode Curl_unencode_write(struct connectdata *conn,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes)
{
(void) conn;
diff --git a/lib/content_encoding.h b/lib/content_encoding.h
index 4cd52be6..bdd3f1c8 100644
--- a/lib/content_encoding.h
+++ b/lib/content_encoding.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -23,31 +23,31 @@
***************************************************************************/
#include "curl_setup.h"
-/* Decoding writer. */
-typedef struct contenc_writer_s contenc_writer;
-typedef struct content_encoding_s content_encoding;
-
-struct contenc_writer_s {
- const content_encoding *handler; /* Encoding handler. */
- contenc_writer *downstream; /* Downstream writer. */
+struct contenc_writer {
+ const struct content_encoding *handler; /* Encoding handler. */
+ struct contenc_writer *downstream; /* Downstream writer. */
void *params; /* Encoding-specific storage (variable length). */
};
/* Content encoding writer. */
-struct content_encoding_s {
+struct content_encoding {
const char *name; /* Encoding name. */
const char *alias; /* Encoding name alias. */
- CURLcode (*init_writer)(struct connectdata *conn, contenc_writer *writer);
- CURLcode (*unencode_write)(struct connectdata *conn, contenc_writer *writer,
+ CURLcode (*init_writer)(struct connectdata *conn,
+ struct contenc_writer *writer);
+ CURLcode (*unencode_write)(struct connectdata *conn,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes);
- void (*close_writer)(struct connectdata *conn, contenc_writer *writer);
+ void (*close_writer)(struct connectdata *conn,
+ struct contenc_writer *writer);
size_t paramsize;
};
CURLcode Curl_build_unencoding_stack(struct connectdata *conn,
const char *enclist, int maybechunked);
-CURLcode Curl_unencode_write(struct connectdata *conn, contenc_writer *writer,
+CURLcode Curl_unencode_write(struct connectdata *conn,
+ struct contenc_writer *writer,
const char *buf, size_t nbytes);
void Curl_unencode_cleanup(struct connectdata *conn);
char *Curl_all_content_encodings(void);
diff --git a/lib/cookie.c b/lib/cookie.c
index 68054e1c..cb7d94b1 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -755,7 +755,7 @@ Curl_cookie_add(struct Curl_easy *data,
co->path = malloc(pathlen + 1); /* one extra for the zero byte */
if(co->path) {
memcpy(co->path, path, pathlen);
- co->path[pathlen] = 0; /* zero terminate */
+ co->path[pathlen] = 0; /* null-terminate */
co->spath = sanitize_cookie_path(co->path);
if(!co->spath)
badcookie = TRUE; /* out of memory bad */
diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c
index b2dd8342..947d0d37 100644
--- a/lib/curl_addrinfo.c
+++ b/lib/curl_addrinfo.c
@@ -78,16 +78,13 @@
#endif
void
-Curl_freeaddrinfo(Curl_addrinfo *cahead)
+Curl_freeaddrinfo(struct Curl_addrinfo *cahead)
{
- Curl_addrinfo *vqualifier canext;
- Curl_addrinfo *ca;
+ struct Curl_addrinfo *vqualifier canext;
+ struct Curl_addrinfo *ca;
- for(ca = cahead; ca != NULL; ca = canext) {
- free(ca->ai_addr);
- free(ca->ai_canonname);
+ for(ca = cahead; ca; ca = canext) {
canext = ca->ai_next;
-
free(ca);
}
}
@@ -112,13 +109,13 @@ int
Curl_getaddrinfo_ex(const char *nodename,
const char *servname,
const struct addrinfo *hints,
- Curl_addrinfo **result)
+ struct Curl_addrinfo **result)
{
const struct addrinfo *ai;
struct addrinfo *aihead;
- Curl_addrinfo *cafirst = NULL;
- Curl_addrinfo *calast = NULL;
- Curl_addrinfo *ca;
+ struct Curl_addrinfo *cafirst = NULL;
+ struct Curl_addrinfo *calast = NULL;
+ struct Curl_addrinfo *ca;
size_t ss_size;
int error;
@@ -131,7 +128,7 @@ Curl_getaddrinfo_ex(const char *nodename,
/* traverse the addrinfo list */
for(ai = aihead; ai != NULL; ai = ai->ai_next) {
-
+ size_t namelen = ai->ai_canonname ? strlen(ai->ai_canonname) + 1 : 0;
/* ignore elements with unsupported address family, */
/* settle family-specific sockaddr structure size. */
if(ai->ai_family == AF_INET)
@@ -151,7 +148,7 @@ Curl_getaddrinfo_ex(const char *nodename,
if((size_t)ai->ai_addrlen < ss_size)
continue;
- ca = malloc(sizeof(Curl_addrinfo));
+ ca = malloc(sizeof(struct Curl_addrinfo) + ss_size + namelen);
if(!ca) {
error = EAI_MEMORY;
break;
@@ -169,22 +166,12 @@ Curl_getaddrinfo_ex(const char *nodename,
ca->ai_canonname = NULL;
ca->ai_next = NULL;
- ca->ai_addr = malloc(ss_size);
- if(!ca->ai_addr) {
- error = EAI_MEMORY;
- free(ca);
- break;
- }
+ ca->ai_addr = (void *)((char *)ca + sizeof(struct Curl_addrinfo));
memcpy(ca->ai_addr, ai->ai_addr, ss_size);
- if(ai->ai_canonname != NULL) {
- ca->ai_canonname = strdup(ai->ai_canonname);
- if(!ca->ai_canonname) {
- error = EAI_MEMORY;
- free(ca->ai_addr);
- free(ca);
- break;
- }
+ if(namelen) {
+ ca->ai_canonname = (void *)((char *)ca->ai_addr + ss_size);
+ memcpy(ca->ai_canonname, ai->ai_canonname, namelen);
}
/* if the return list is empty, this becomes the first element */
@@ -252,7 +239,6 @@ Curl_getaddrinfo_ex(const char *nodename,
* struct sockaddr *ai_addr;
* struct Curl_addrinfo *ai_next;
* };
- * typedef struct Curl_addrinfo Curl_addrinfo;
*
* hostent defined in <netdb.h>
*
@@ -269,12 +255,12 @@ Curl_getaddrinfo_ex(const char *nodename,
* #define h_addr h_addr_list[0]
*/
-Curl_addrinfo *
+struct Curl_addrinfo *
Curl_he2ai(const struct hostent *he, int port)
{
- Curl_addrinfo *ai;
- Curl_addrinfo *prevai = NULL;
- Curl_addrinfo *firstai = NULL;
+ struct Curl_addrinfo *ai;
+ struct Curl_addrinfo *prevai = NULL;
+ struct Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
#ifdef ENABLE_IPV6
struct sockaddr_in6 *addr6;
@@ -290,8 +276,8 @@ Curl_he2ai(const struct hostent *he, int port)
DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
for(i = 0; (curr = he->h_addr_list[i]) != NULL; i++) {
-
size_t ss_size;
+ size_t namelen = strlen(he->h_name) + 1; /* include zero termination */
#ifdef ENABLE_IPV6
if(he->h_addrtype == AF_INET6)
ss_size = sizeof(struct sockaddr_in6);
@@ -299,24 +285,17 @@ Curl_he2ai(const struct hostent *he, int port)
#endif
ss_size = sizeof(struct sockaddr_in);
- ai = calloc(1, sizeof(Curl_addrinfo));
+ /* allocate memory to told the struct, the address and the name */
+ ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + namelen);
if(!ai) {
result = CURLE_OUT_OF_MEMORY;
break;
}
- ai->ai_canonname = strdup(he->h_name);
- if(!ai->ai_canonname) {
- result = CURLE_OUT_OF_MEMORY;
- free(ai);
- break;
- }
- ai->ai_addr = calloc(1, ss_size);
- if(!ai->ai_addr) {
- result = CURLE_OUT_OF_MEMORY;
- free(ai->ai_canonname);
- free(ai);
- break;
- }
+ /* put the address after the struct */
+ ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
+ /* then put the name after the address */
+ ai->ai_canonname = (char *)ai->ai_addr + ss_size;
+ memcpy(ai->ai_canonname, he->h_name, namelen);
if(!firstai)
/* store the pointer we want to return from this function */
@@ -389,10 +368,10 @@ struct namebuff {
* given address/host
*/
-Curl_addrinfo *
+struct Curl_addrinfo *
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
{
- Curl_addrinfo *ai;
+ struct Curl_addrinfo *ai;
#if defined(__VMS) && \
defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
@@ -465,7 +444,7 @@ Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
* Given an IPv4 or IPv6 dotted string address, this converts it to a proper
* allocated Curl_addrinfo struct and returns it.
*/
-Curl_addrinfo *Curl_str2addr(char *address, int port)
+struct Curl_addrinfo *Curl_str2addr(char *address, int port)
{
struct in_addr in;
if(Curl_inet_pton(AF_INET, address, &in) > 0)
@@ -488,22 +467,19 @@ Curl_addrinfo *Curl_str2addr(char *address, int port)
* struct initialized with this path.
* Set '*longpath' to TRUE if the error is a too long path.
*/
-Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract)
+struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
+ bool abstract)
{
- Curl_addrinfo *ai;
+ struct Curl_addrinfo *ai;
struct sockaddr_un *sa_un;
size_t path_len;
*longpath = FALSE;
- ai = calloc(1, sizeof(Curl_addrinfo));
+ ai = calloc(1, sizeof(struct Curl_addrinfo) + sizeof(struct sockaddr_un));
if(!ai)
return NULL;
- ai->ai_addr = calloc(1, sizeof(struct sockaddr_un));
- if(!ai->ai_addr) {
- free(ai);
- return NULL;
- }
+ ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
sa_un = (void *) ai->ai_addr;
sa_un->sun_family = AF_UNIX;
@@ -511,7 +487,6 @@ Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract)
/* sun_path must be able to store the NUL-terminated path */
path_len = strlen(path) + 1;
if(path_len > sizeof(sa_un->sun_path)) {
- free(ai->ai_addr);
free(ai);
*longpath = TRUE;
return NULL;
@@ -594,9 +569,9 @@ curl_dbg_getaddrinfo(const char *hostname,
* Work-arounds the sin6_port is always zero bug on iOS 9.3.2 and Mac OS X
* 10.11.5.
*/
-void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port)
+void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port)
{
- Curl_addrinfo *ca;
+ struct Curl_addrinfo *ca;
struct sockaddr_in *addr;
#ifdef ENABLE_IPV6
struct sockaddr_in6 *addr6;
diff --git a/lib/curl_addrinfo.h b/lib/curl_addrinfo.h
index 205e121e..a0cade61 100644
--- a/lib/curl_addrinfo.h
+++ b/lib/curl_addrinfo.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -40,7 +40,6 @@
# include <stdlib.h>
#endif
-
/*
* Curl_addrinfo is our internal struct definition that we use to allow
* consistent internal handling of this data. We use this even when the
@@ -58,29 +57,29 @@ struct Curl_addrinfo {
struct sockaddr *ai_addr;
struct Curl_addrinfo *ai_next;
};
-typedef struct Curl_addrinfo Curl_addrinfo;
void
-Curl_freeaddrinfo(Curl_addrinfo *cahead);
+Curl_freeaddrinfo(struct Curl_addrinfo *cahead);
#ifdef HAVE_GETADDRINFO
int
Curl_getaddrinfo_ex(const char *nodename,
const char *servname,
const struct addrinfo *hints,
- Curl_addrinfo **result);
+ struct Curl_addrinfo **result);
#endif
-Curl_addrinfo *
+struct Curl_addrinfo *
Curl_he2ai(const struct hostent *he, int port);
-Curl_addrinfo *
+struct Curl_addrinfo *
Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
-Curl_addrinfo *Curl_str2addr(char *dotted, int port);
+struct Curl_addrinfo *Curl_str2addr(char *dotted, int port);
#ifdef USE_UNIX_SOCKETS
-Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath, bool abstract);
+struct Curl_addrinfo *Curl_unix2addr(const char *path, bool *longpath,
+ bool abstract);
#endif
#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) && \
@@ -98,7 +97,7 @@ curl_dbg_getaddrinfo(const char *hostname, const char *service,
#ifdef HAVE_GETADDRINFO
#ifdef USE_RESOLVE_ON_IPS
-void Curl_addrinfo_set_port(Curl_addrinfo *addrinfo, int port);
+void Curl_addrinfo_set_port(struct Curl_addrinfo *addrinfo, int port);
#else
#define Curl_addrinfo_set_port(x,y)
#endif
diff --git a/lib/curl_config.h b/lib/curl_config.h
index 21cd2f89..576998a4 100644
--- a/lib/curl_config.h
+++ b/lib/curl_config.h
@@ -553,6 +553,9 @@
/* Define to 1 if you have the <pwd.h> header file. */
#define HAVE_PWD_H 1
+/* Define to 1 if you have the `quiche_conn_set_qlog_fd' function. */
+/* #undef HAVE_QUICHE_CONN_SET_QLOG_FD */
+
/* Define to 1 if you have the <quiche.h> header file. */
/* #undef HAVE_QUICHE_H */
@@ -691,6 +694,9 @@
/* Define to 1 if you have the timeval struct. */
#define HAVE_STRUCT_TIMEVAL 1
+/* Define to 1 if suseconds_t is an available type. */
+#define HAVE_SUSECONDS_T 1
+
/* Define to 1 if you have the <sys/filio.h> header file. */
/* #undef HAVE_SYS_FILIO_H */
@@ -793,6 +799,9 @@
/* Define to 1 if you have the `wolfSSLv3_client_method' function. */
/* #undef HAVE_WOLFSSLV3_CLIENT_METHOD */
+/* if you have wolfSSL_DES_set_odd_parity */
+/* #undef HAVE_WOLFSSL_DES_SET_ODD_PARITY */
+
/* Define to 1 if you have the `wolfSSL_get_peer_certificate' function. */
/* #undef HAVE_WOLFSSL_GET_PEER_CERTIFICATE */
diff --git a/lib/curl_config.h.cmake b/lib/curl_config.h.cmake
index 57a86e50..05a5acb0 100644
--- a/lib/curl_config.h.cmake
+++ b/lib/curl_config.h.cmake
@@ -428,6 +428,9 @@
/* Define to 1 if you have the <libssh2.h> header file. */
#cmakedefine HAVE_LIBSSH2_H 1
+/* Define to 1 if you have the <libssh/libssh.h> header file. */
+#cmakedefine HAVE_LIBSSH_LIBSSH_H 1
+
/* if zlib is available */
#cmakedefine HAVE_LIBZ 1
@@ -969,6 +972,9 @@ ${SIZEOF_TIME_T_CODE}
/* if WolfSSL is enabled */
#cmakedefine USE_WOLFSSL 1
+/* if libSSH is in use */
+#cmakedefine USE_LIBSSH 1
+
/* if libSSH2 is in use */
#cmakedefine USE_LIBSSH2 1
@@ -990,9 +996,24 @@ ${SIZEOF_TIME_T_CODE}
/* to enable NGHTTP2 */
#cmakedefine USE_NGHTTP2 1
+/* to enable NGTCP2 */
+#cmakedefine USE_NGTCP2 1
+
+/* to enable NGHTTP3 */
+#cmakedefine USE_NGHTTP3 1
+
+/* to enable quiche */
+#cmakedefine USE_QUICHE 1
+
+/* Define to 1 if you have the quiche_conn_set_qlog_fd function. */
+#cmakedefine HAVE_QUICHE_CONN_SET_QLOG_FD 1
+
/* if Unix domain sockets are enabled */
#cmakedefine USE_UNIX_SOCKETS
+/* to enable alt-svc */
+#cmakedefine USE_ALTSVC 1
+
/* Define to 1 if you are building a Windows target with large file support. */
#cmakedefine USE_WIN32_LARGE_FILES 1
diff --git a/lib/curl_config.h.in b/lib/curl_config.h.in
index abb6c078..dc792f4c 100644
--- a/lib/curl_config.h.in
+++ b/lib/curl_config.h.in
@@ -552,6 +552,9 @@
/* Define to 1 if you have the <pwd.h> header file. */
#undef HAVE_PWD_H
+/* Define to 1 if you have the `quiche_conn_set_qlog_fd' function. */
+#undef HAVE_QUICHE_CONN_SET_QLOG_FD
+
/* Define to 1 if you have the <quiche.h> header file. */
#undef HAVE_QUICHE_H
@@ -690,6 +693,9 @@
/* Define to 1 if you have the timeval struct. */
#undef HAVE_STRUCT_TIMEVAL
+/* Define to 1 if suseconds_t is an available type. */
+#undef HAVE_SUSECONDS_T
+
/* Define to 1 if you have the <sys/filio.h> header file. */
#undef HAVE_SYS_FILIO_H
@@ -792,6 +798,9 @@
/* Define to 1 if you have the `wolfSSLv3_client_method' function. */
#undef HAVE_WOLFSSLV3_CLIENT_METHOD
+/* if you have wolfSSL_DES_set_odd_parity */
+#undef HAVE_WOLFSSL_DES_SET_ODD_PARITY
+
/* Define to 1 if you have the `wolfSSL_get_peer_certificate' function. */
#undef HAVE_WOLFSSL_GET_PEER_CERTIFICATE
diff --git a/lib/curl_hmac.h b/lib/curl_hmac.h
index 3ff799bb..9b70c846 100644
--- a/lib/curl_hmac.h
+++ b/lib/curl_hmac.h
@@ -34,37 +34,35 @@ typedef void (* HMAC_hfinal_func)(unsigned char *result, void *context);
/* Per-hash function HMAC parameters. */
-
-typedef struct {
- HMAC_hinit_func hmac_hinit; /* Initialize context procedure. */
+struct HMAC_params {
+ HMAC_hinit_func
+ hmac_hinit; /* Initialize context procedure. */
HMAC_hupdate_func hmac_hupdate; /* Update context with data. */
HMAC_hfinal_func hmac_hfinal; /* Get final result procedure. */
unsigned int hmac_ctxtsize; /* Context structure size. */
unsigned int hmac_maxkeylen; /* Maximum key length (bytes). */
unsigned int hmac_resultlen; /* Result length (bytes). */
-} HMAC_params;
+};
/* HMAC computation context. */
-
-typedef struct {
- const HMAC_params *hmac_hash; /* Hash function definition. */
+struct HMAC_context {
+ const struct HMAC_params *hmac_hash; /* Hash function definition. */
void *hmac_hashctxt1; /* Hash function context 1. */
void *hmac_hashctxt2; /* Hash function context 2. */
-} HMAC_context;
+};
/* Prototypes. */
-
-HMAC_context * Curl_HMAC_init(const HMAC_params *hashparams,
- const unsigned char *key,
- unsigned int keylen);
-int Curl_HMAC_update(HMAC_context *context,
+struct HMAC_context *Curl_HMAC_init(const struct HMAC_params *hashparams,
+ const unsigned char *key,
+ unsigned int keylen);
+int Curl_HMAC_update(struct HMAC_context *context,
const unsigned char *data,
unsigned int len);
-int Curl_HMAC_final(HMAC_context *context, unsigned char *result);
+int Curl_HMAC_final(struct HMAC_context *context, unsigned char *result);
-CURLcode Curl_hmacit(const HMAC_params *hashparams,
+CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
const unsigned char *key, const size_t keylen,
const unsigned char *data, const size_t datalen,
unsigned char *output);
diff --git a/lib/curl_md5.h b/lib/curl_md5.h
index dd464416..e06c68ed 100644
--- a/lib/curl_md5.h
+++ b/lib/curl_md5.h
@@ -33,30 +33,30 @@ typedef void (* Curl_MD5_update_func)(void *context,
unsigned int len);
typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context);
-typedef struct {
+struct MD5_params {
Curl_MD5_init_func md5_init_func; /* Initialize context procedure */
Curl_MD5_update_func md5_update_func; /* Update context with data */
Curl_MD5_final_func md5_final_func; /* Get final result procedure */
unsigned int md5_ctxtsize; /* Context structure size */
unsigned int md5_resultlen; /* Result length (bytes) */
-} MD5_params;
+};
-typedef struct {
- const MD5_params *md5_hash; /* Hash function definition */
+struct MD5_context {
+ const struct MD5_params *md5_hash; /* Hash function definition */
void *md5_hashctx; /* Hash function context */
-} MD5_context;
+};
-extern const MD5_params Curl_DIGEST_MD5[1];
-extern const HMAC_params Curl_HMAC_MD5[1];
+extern const struct MD5_params Curl_DIGEST_MD5[1];
+extern const struct HMAC_params Curl_HMAC_MD5[1];
void Curl_md5it(unsigned char *output, const unsigned char *input,
const size_t len);
-MD5_context * Curl_MD5_init(const MD5_params *md5params);
-CURLcode Curl_MD5_update(MD5_context *context,
+struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params);
+CURLcode Curl_MD5_update(struct MD5_context *context,
const unsigned char *data,
unsigned int len);
-CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result);
+CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result);
#endif
diff --git a/lib/curl_multibyte.c b/lib/curl_multibyte.c
index e3843449..2c8925b5 100644
--- a/lib/curl_multibyte.c
+++ b/lib/curl_multibyte.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -20,24 +20,21 @@
*
***************************************************************************/
-#include "curl_setup.h"
-
-#include <curl/curl.h>
+/*
+ * This file is 'mem-include-scan' clean. See test 1132.
+ */
-#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \
- defined(USE_WIN32_LDAP)) && defined(UNICODE))
+#include "curl_setup.h"
- /*
- * MultiByte conversions using Windows kernel32 library.
- */
+#if defined(WIN32)
#include "curl_multibyte.h"
-#include "curl_memory.h"
-/* The last #include file should be: */
-#include "memdebug.h"
+/*
+ * MultiByte conversions using Windows kernel32 library.
+ */
-wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8)
+wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8)
{
wchar_t *str_w = NULL;
@@ -59,7 +56,7 @@ wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8)
return str_w;
}
-char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w)
+char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w)
{
char *str_utf8 = NULL;
@@ -81,4 +78,76 @@ char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w)
return str_utf8;
}
-#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */
+#endif /* WIN32 */
+
+#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES)
+
+FILE *curlx_win32_fopen(const char *filename, const char *mode)
+{
+#ifdef _UNICODE
+ FILE *result = NULL;
+ wchar_t *filename_w = curlx_convert_UTF8_to_wchar(filename);
+ wchar_t *mode_w = curlx_convert_UTF8_to_wchar(mode);
+ if(filename_w && mode_w)
+ result = _wfopen(filename_w, mode_w);
+ free(filename_w);
+ free(mode_w);
+ if(result)
+ return result;
+#endif
+
+ return (fopen)(filename, mode);
+}
+
+int curlx_win32_stat(const char *path, struct_stat *buffer)
+{
+ int result = -1;
+#ifdef _UNICODE
+ wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
+#endif /* _UNICODE */
+
+#if defined(USE_WIN32_SMALL_FILES)
+#if defined(_UNICODE)
+ if(path_w)
+ result = _wstat(path_w, buffer);
+ else
+#endif /* _UNICODE */
+ result = _stat(path, buffer);
+#else /* USE_WIN32_SMALL_FILES */
+#if defined(_UNICODE)
+ if(path_w)
+ result = _wstati64(path_w, buffer);
+ else
+#endif /* _UNICODE */
+ result = _stati64(path, buffer);
+#endif /* USE_WIN32_SMALL_FILES */
+
+#ifdef _UNICODE
+ free(path_w);
+#endif
+
+ return result;
+}
+
+int curlx_win32_access(const char *path, int mode)
+{
+ int result = -1;
+#ifdef _UNICODE
+ wchar_t *path_w = curlx_convert_UTF8_to_wchar(path);
+#endif /* _UNICODE */
+
+#if defined(_UNICODE)
+ if(path_w)
+ result = _waccess(path_w, mode);
+ else
+#endif /* _UNICODE */
+ result = _access(path, mode);
+
+#ifdef _UNICODE
+ free(path_w);
+#endif
+
+ return result;
+}
+
+#endif /* USE_WIN32_LARGE_FILES || USE_WIN32_SMALL_FILES */
diff --git a/lib/curl_multibyte.h b/lib/curl_multibyte.h
index 3becf41c..5f8c05af 100644
--- a/lib/curl_multibyte.h
+++ b/lib/curl_multibyte.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -23,48 +23,43 @@
***************************************************************************/
#include "curl_setup.h"
-#if defined(USE_WIN32_IDN) || ((defined(USE_WINDOWS_SSPI) || \
- defined(USE_WIN32_LDAP)) && defined(UNICODE))
+#if defined(WIN32)
/*
* MultiByte conversions using Windows kernel32 library.
*/
-wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8);
-char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w);
+wchar_t *curlx_convert_UTF8_to_wchar(const char *str_utf8);
+char *curlx_convert_wchar_to_UTF8(const wchar_t *str_w);
-#endif /* USE_WIN32_IDN || ((USE_WINDOWS_SSPI || USE_WIN32_LDAP) && UNICODE) */
-
-
-#if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI) || \
- defined(USE_WIN32_LDAP)
+#endif /* WIN32 */
/*
- * Macros Curl_convert_UTF8_to_tchar(), Curl_convert_tchar_to_UTF8()
- * and Curl_unicodefree() main purpose is to minimize the number of
+ * Macros curlx_convert_UTF8_to_tchar(), curlx_convert_tchar_to_UTF8()
+ * and curlx_unicodefree() main purpose is to minimize the number of
* preprocessor conditional directives needed by code using these
* to differentiate UNICODE from non-UNICODE builds.
*
- * When building with UNICODE defined, this two macros
- * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8()
+ * When building with UNICODE defined, these two macros
+ * curlx_convert_UTF8_to_tchar() and curlx_convert_tchar_to_UTF8()
* return a pointer to a newly allocated memory area holding result.
* When the result is no longer needed, allocated memory is intended
- * to be free'ed with Curl_unicodefree().
+ * to be free'ed with curlx_unicodefree().
*
* When building without UNICODE defined, this macros
- * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8()
- * return the pointer received as argument. Curl_unicodefree() does
+ * curlx_convert_UTF8_to_tchar() and curlx_convert_tchar_to_UTF8()
+ * return the pointer received as argument. curlx_unicodefree() does
* no actual free'ing of this pointer it is simply set to NULL.
*/
-#ifdef UNICODE
+#if defined(UNICODE) && defined(WIN32)
-#define Curl_convert_UTF8_to_tchar(ptr) Curl_convert_UTF8_to_wchar((ptr))
-#define Curl_convert_tchar_to_UTF8(ptr) Curl_convert_wchar_to_UTF8((ptr))
-#define Curl_unicodefree(ptr) \
+#define curlx_convert_UTF8_to_tchar(ptr) curlx_convert_UTF8_to_wchar((ptr))
+#define curlx_convert_tchar_to_UTF8(ptr) curlx_convert_wchar_to_UTF8((ptr))
+#define curlx_unicodefree(ptr) \
do { \
if(ptr) { \
- free(ptr); \
+ (free)(ptr); \
(ptr) = NULL; \
} \
} while(0)
@@ -78,9 +73,9 @@ typedef union {
#else
-#define Curl_convert_UTF8_to_tchar(ptr) (ptr)
-#define Curl_convert_tchar_to_UTF8(ptr) (ptr)
-#define Curl_unicodefree(ptr) \
+#define curlx_convert_UTF8_to_tchar(ptr) (ptr)
+#define curlx_convert_tchar_to_UTF8(ptr) (ptr)
+#define curlx_unicodefree(ptr) \
do {(ptr) = NULL;} while(0)
typedef union {
@@ -90,8 +85,6 @@ typedef union {
const unsigned char *const_tbyte_ptr;
} xcharp_u;
-#endif /* UNICODE */
-
-#endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI || USE_WIN32_LDAP */
+#endif /* UNICODE && WIN32 */
#endif /* HEADER_CURL_MULTIBYTE_H */
diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c
index 32e29a93..0eefb158 100644
--- a/lib/curl_ntlm_core.c
+++ b/lib/curl_ntlm_core.c
@@ -52,13 +52,18 @@
#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+
+#ifdef USE_WOLFSSL
+#include <wolfssl/options.h>
+#endif
# include <openssl/des.h>
# include <openssl/md5.h>
# include <openssl/ssl.h>
# include <openssl/rand.h>
-# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+# if (defined(OPENSSL_VERSION_NUMBER) && \
+ (OPENSSL_VERSION_NUMBER < 0x00907001L)) && !defined(USE_WOLFSSL)
# define DES_key_schedule des_key_schedule
# define DES_cblock des_cblock
# define DES_set_odd_parity des_set_odd_parity
@@ -78,14 +83,12 @@
#elif defined(USE_GNUTLS)
# include <gcrypt.h>
-# define MD5_DIGEST_LENGTH 16
#elif defined(USE_NSS)
# include <nss.h>
# include <pk11pub.h>
# include <hasht.h>
-# define MD5_DIGEST_LENGTH MD5_LENGTH
#elif defined(USE_MBEDTLS)
@@ -138,7 +141,7 @@ static void extend_key_56_to_64(const unsigned char *key_56, char *key)
key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
}
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
/*
* Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
* key schedule ks is also set.
@@ -387,7 +390,7 @@ void Curl_ntlm_core_lm_resp(const unsigned char *keys,
const unsigned char *plaintext,
unsigned char *results)
{
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
DES_key_schedule ks;
setup_des_key(keys, DESKEY(ks));
@@ -462,7 +465,7 @@ CURLcode Curl_ntlm_core_mk_lm_hash(struct Curl_easy *data,
{
/* Create LanManager hashed password. */
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
DES_key_schedule ks;
setup_des_key(pw, DESKEY(ks));
diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h
index e1643d62..7895b647 100644
--- a/lib/curl_ntlm_core.h
+++ b/lib/curl_ntlm_core.h
@@ -29,6 +29,7 @@
/* If NSS is the first available SSL backend (see order in curl_ntlm_core.c)
then it must be initialized to be used by NTLM. */
#if !defined(USE_OPENSSL) && \
+ !defined(USE_WOLFSSL) && \
!defined(USE_GNUTLS_NETTLE) && \
!defined(USE_GNUTLS) && \
defined(USE_NSS)
@@ -37,7 +38,10 @@
#if !defined(USE_WINDOWS_SSPI) || defined(USE_WIN32_CRYPTO)
-#ifdef USE_OPENSSL
+#if defined(USE_OPENSSL) || defined(USE_WOLFSSL)
+#ifdef USE_WOLFSSL
+# include <wolfssl/options.h>
+#endif
# include <openssl/ssl.h>
#endif
diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c
index f820b842..17a92f8c 100644
--- a/lib/curl_ntlm_wb.c
+++ b/lib/curl_ntlm_wb.c
@@ -261,15 +261,11 @@ done:
static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
const char *input, curlntlm state)
{
- char *buf = malloc(NTLM_BUFSIZE);
size_t len_in = strlen(input), len_out = 0;
-
-#if defined(CURL_DISABLE_VERBOSE_STRINGS)
- (void) data;
-#endif
-
- if(!buf)
- return CURLE_OUT_OF_MEMORY;
+ struct dynbuf b;
+ char *ptr = NULL;
+ unsigned char *buf = (unsigned char *)data->state.buffer;
+ Curl_dyn_init(&b, MAX_NTLM_WB_RESPONSE);
while(len_in > 0) {
ssize_t written = swrite(ntlm->ntlm_auth_hlpr_socket, input, len_in);
@@ -285,10 +281,8 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
}
/* Read one line */
while(1) {
- ssize_t size;
- char *newbuf;
-
- size = sread(ntlm->ntlm_auth_hlpr_socket, buf + len_out, NTLM_BUFSIZE);
+ ssize_t size =
+ sread(ntlm->ntlm_auth_hlpr_socket, buf, data->set.buffer_size);
if(size == -1) {
if(errno == EINTR)
continue;
@@ -297,48 +291,41 @@ static CURLcode ntlm_wb_response(struct Curl_easy *data, struct ntlmdata *ntlm,
else if(size == 0)
goto done;
- len_out += size;
- if(buf[len_out - 1] == '\n') {
- buf[len_out - 1] = '\0';
- break;
- }
+ if(Curl_dyn_addn(&b, buf, size))
+ goto done;
- if(len_out > MAX_NTLM_WB_RESPONSE) {
- failf(data, "too large ntlm_wb response!");
- free(buf);
- return CURLE_OUT_OF_MEMORY;
+ len_out = Curl_dyn_len(&b);
+ ptr = Curl_dyn_ptr(&b);
+ if(len_out && ptr[len_out - 1] == '\n') {
+ ptr[len_out - 1] = '\0';
+ break; /* done! */
}
-
- newbuf = Curl_saferealloc(buf, len_out + NTLM_BUFSIZE);
- if(!newbuf)
- return CURLE_OUT_OF_MEMORY;
-
- buf = newbuf;
+ /* loop */
}
/* Samba/winbind installed but not configured */
if(state == NTLMSTATE_TYPE1 &&
len_out == 3 &&
- buf[0] == 'P' && buf[1] == 'W')
+ ptr[0] == 'P' && ptr[1] == 'W')
goto done;
/* invalid response */
if(len_out < 4)
goto done;
if(state == NTLMSTATE_TYPE1 &&
- (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' '))
+ (ptr[0]!='Y' || ptr[1]!='R' || ptr[2]!=' '))
goto done;
if(state == NTLMSTATE_TYPE2 &&
- (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') &&
- (buf[0]!='A' || buf[1]!='F' || buf[2]!=' '))
+ (ptr[0]!='K' || ptr[1]!='K' || ptr[2]!=' ') &&
+ (ptr[0]!='A' || ptr[1]!='F' || ptr[2]!=' '))
goto done;
- ntlm->response = aprintf("%.*s", len_out - 4, buf + 3);
- free(buf);
+ ntlm->response = strdup(ptr + 3);
+ Curl_dyn_free(&b);
if(!ntlm->response)
return CURLE_OUT_OF_MEMORY;
return CURLE_OK;
done:
- free(buf);
+ Curl_dyn_free(&b);
return CURLE_REMOTE_ACCESS_DENIED;
}
@@ -389,8 +376,7 @@ CURLcode Curl_input_ntlm_wb(struct connectdata *conn,
* This is for creating ntlm header output by delegating challenge/response
* to Samba's winbind daemon helper ntlm_auth.
*/
-CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
- bool proxy)
+CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy)
{
/* point to the address of the pointer that holds the string to send to the
server, which is for a plain host or for a HTTP proxy */
@@ -400,6 +386,7 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
struct ntlmdata *ntlm;
curlntlm *state;
struct auth *authp;
+ struct Curl_easy *data = conn->data;
CURLcode res = CURLE_OK;
@@ -407,14 +394,18 @@ CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
DEBUGASSERT(conn->data);
if(proxy) {
- allocuserpwd = &conn->allocptr.proxyuserpwd;
+#ifndef CURL_DISABLE_PROXY
+ allocuserpwd = &data->state.aptr.proxyuserpwd;
userp = conn->http_proxy.user;
ntlm = &conn->proxyntlm;
state = &conn->proxy_ntlm_state;
authp = &conn->data->state.authproxy;
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
}
else {
- allocuserpwd = &conn->allocptr.userpwd;
+ allocuserpwd = &data->state.aptr.userpwd;
userp = conn->user;
ntlm = &conn->ntlm;
state = &conn->http_ntlm_state;
diff --git a/lib/curl_path.c b/lib/curl_path.c
index f4296346..fbd98cb3 100644
--- a/lib/curl_path.c
+++ b/lib/curl_path.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -42,7 +42,7 @@ CURLcode Curl_getworkingpath(struct connectdata *conn,
size_t working_path_len;
CURLcode result =
Curl_urldecode(data, data->state.up.path, 0, &working_path,
- &working_path_len, FALSE);
+ &working_path_len, REJECT_ZERO);
if(result)
return result;
diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c
index 8c1c8662..83fe896e 100644
--- a/lib/curl_sasl.c
+++ b/lib/curl_sasl.c
@@ -264,9 +264,14 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
size_t len = 0;
saslstate state1 = SASL_STOP;
saslstate state2 = SASL_FINAL;
+#ifndef CURL_DISABLE_PROXY
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+#else
+ const char * const hostname = conn->host.name;
+ const long int port = conn->remote_port;
+#endif
#if defined(USE_KERBEROS5) || defined(USE_NTLM)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
data->set.str[STRING_SERVICE_NAME] :
@@ -417,18 +422,23 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
struct Curl_easy *data = conn->data;
saslstate newstate = SASL_FINAL;
char *resp = NULL;
+#ifndef CURL_DISABLE_PROXY
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+#else
+ const char * const hostname = conn->host.name;
+ const long int port = conn->remote_port;
+#endif
#if !defined(CURL_DISABLE_CRYPTO_AUTH)
char *chlg = NULL;
size_t chlglen = 0;
#endif
-#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
- defined(USE_NTLM)
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
+ defined(USE_NTLM)
const char *service = data->set.str[STRING_SERVICE_NAME] ?
- data->set.str[STRING_SERVICE_NAME] :
- sasl->params->service;
+ data->set.str[STRING_SERVICE_NAME] :
+ sasl->params->service;
char *serverdata;
#endif
size_t len = 0;
diff --git a/lib/curl_setup.h b/lib/curl_setup.h
index 56e6db83..d76c630d 100644
--- a/lib/curl_setup.h
+++ b/lib/curl_setup.h
@@ -331,9 +331,14 @@
# undef fstat
# define fstat(fdes,stp) _fstati64(fdes, stp)
# undef stat
-# define stat(fname,stp) _stati64(fname, stp)
+# define stat(fname,stp) curlx_win32_stat(fname, stp)
# define struct_stat struct _stati64
# define LSEEK_ERROR (__int64)-1
+# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
+# define access(fname,mode) curlx_win32_access(fname, mode)
+ int curlx_win32_stat(const char *path, struct_stat *buffer);
+ FILE *curlx_win32_fopen(const char *filename, const char *mode);
+ int curlx_win32_access(const char *path, int mode);
#endif
/*
@@ -348,8 +353,13 @@
# undef lseek
# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
# define fstat(fdes,stp) _fstat(fdes, stp)
-# define stat(fname,stp) _stat(fname, stp)
+# define stat(fname,stp) curlx_win32_stat(fname, stp)
# define struct_stat struct _stat
+# define fopen(fname,mode) curlx_win32_fopen(fname, mode)
+# define access(fname,mode) curlx_win32_access(fname, mode)
+ int curlx_win32_stat(const char *path, struct_stat *buffer);
+ FILE *curlx_win32_fopen(const char *filename, const char *mode);
+ int curlx_win32_access(const char *path, int mode);
# endif
# define LSEEK_ERROR (long)-1
#endif
@@ -627,10 +637,11 @@ int netware_init(void);
/* Single point where USE_NTLM definition might be defined */
#if !defined(CURL_DISABLE_NTLM) && !defined(CURL_DISABLE_CRYPTO_AUTH)
-#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \
- defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) || \
- defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \
- defined(USE_MBEDTLS)
+#if defined(USE_OPENSSL) || defined(USE_WINDOWS_SSPI) || \
+ defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_SECTRANSP) || \
+ defined(USE_OS400CRYPTO) || defined(USE_WIN32_CRYPTO) || \
+ defined(USE_MBEDTLS) || \
+ (defined(USE_WOLFSSL) && defined(HAVE_WOLFSSL_DES_SET_ODD_PARITY))
#define USE_NTLM
diff --git a/lib/curl_setup_once.h b/lib/curl_setup_once.h
index 8890f389..e7c00dea 100644
--- a/lib/curl_setup_once.h
+++ b/lib/curl_setup_once.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -481,6 +481,8 @@ typedef int sig_atomic_t;
#ifdef __VMS
#define argv_item_t __char_ptr32
+#elif defined(_UNICODE)
+#define argv_item_t wchar_t *
#else
#define argv_item_t char *
#endif
diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c
index f7cc10f8..83ece9af 100644
--- a/lib/curl_sspi.c
+++ b/lib/curl_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -151,7 +151,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
/* Initialize the identity */
memset(identity, 0, sizeof(*identity));
- useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp);
+ useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)userp);
if(!useranddomain.tchar_ptr)
return CURLE_OUT_OF_MEMORY;
@@ -173,7 +173,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
/* Setup the identity's user and length */
dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
if(!dup_user.tchar_ptr) {
- Curl_unicodefree(useranddomain.tchar_ptr);
+ curlx_unicodefree(useranddomain.tchar_ptr);
return CURLE_OUT_OF_MEMORY;
}
identity->User = dup_user.tbyte_ptr;
@@ -183,7 +183,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
/* Setup the identity's domain and length */
dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
if(!dup_domain.tchar_ptr) {
- Curl_unicodefree(useranddomain.tchar_ptr);
+ curlx_unicodefree(useranddomain.tchar_ptr);
return CURLE_OUT_OF_MEMORY;
}
_tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
@@ -192,22 +192,22 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp,
identity->DomainLength = curlx_uztoul(domlen);
dup_domain.tchar_ptr = NULL;
- Curl_unicodefree(useranddomain.tchar_ptr);
+ curlx_unicodefree(useranddomain.tchar_ptr);
/* Setup the identity's password and length */
- passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp);
+ passwd.tchar_ptr = curlx_convert_UTF8_to_tchar((char *)passwdp);
if(!passwd.tchar_ptr)
return CURLE_OUT_OF_MEMORY;
dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
if(!dup_passwd.tchar_ptr) {
- Curl_unicodefree(passwd.tchar_ptr);
+ curlx_unicodefree(passwd.tchar_ptr);
return CURLE_OUT_OF_MEMORY;
}
identity->Password = dup_passwd.tbyte_ptr;
identity->PasswordLength = curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
dup_passwd.tchar_ptr = NULL;
- Curl_unicodefree(passwd.tchar_ptr);
+ curlx_unicodefree(passwd.tchar_ptr);
/* Setup the identity's flags */
identity->Flags = SECFLAG_WINNT_AUTH_IDENTITY;
diff --git a/lib/curl_threads.c b/lib/curl_threads.c
index 064c075d..b5f10a20 100644
--- a/lib/curl_threads.c
+++ b/lib/curl_threads.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -48,7 +48,7 @@ struct curl_actual_call {
static void *curl_thread_create_thunk(void *arg)
{
- struct curl_actual_call * ac = arg;
+ struct curl_actual_call *ac = arg;
unsigned int (*func)(void *) = ac->func;
void *real_arg = ac->arg;
diff --git a/lib/curlx.h b/lib/curlx.h
index 3e9b516f..a8bae14b 100644
--- a/lib/curlx.h
+++ b/lib/curlx.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -53,6 +53,16 @@
curlx_uztosi()
*/
+#include "curl_multibyte.h"
+/* "curl_multibyte.h" provides these functions and macros:
+
+ curlx_convert_UTF8_to_wchar()
+ curlx_convert_wchar_to_UTF8()
+ curlx_convert_UTF8_to_tchar()
+ curlx_convert_tchar_to_UTF8()
+ curlx_unicodefree()
+*/
+
/* Now setup curlx_ * names for the functions that are to become curlx_ and
be removed from a future libcurl official API:
curlx_getenv
diff --git a/lib/dict.c b/lib/dict.c
index c802deef..f529b48f 100644
--- a/lib/dict.c
+++ b/lib/dict.c
@@ -99,7 +99,8 @@ static char *unescape_word(struct Curl_easy *data, const char *inputbuff)
char *dictp;
size_t len;
- CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len, FALSE);
+ CURLcode result = Curl_urldecode(data, inputbuff, 0, &newp, &len,
+ REJECT_NADA);
if(!newp || result)
return NULL;
diff --git a/lib/doh.c b/lib/doh.c
index 10867cc3..ebb2c243 100644
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -35,13 +35,13 @@
#include "curl_base64.h"
#include "connect.h"
#include "strdup.h"
+#include "dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
#include "memdebug.h"
#define DNS_CLASS_IN 0x01
-#define DOH_MAX_RESPONSE_SIZE 3000 /* bytes */
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static const char * const errors[]={
@@ -177,20 +177,11 @@ static size_t
doh_write_cb(const void *contents, size_t size, size_t nmemb, void *userp)
{
size_t realsize = size * nmemb;
- struct dohresponse *mem = (struct dohresponse *)userp;
+ struct dynbuf *mem = (struct dynbuf *)userp;
- if((mem->size + realsize) > DOH_MAX_RESPONSE_SIZE)
- /* suspiciously much for us */
+ if(Curl_dyn_addn(mem, contents, realsize))
return 0;
- mem->memory = Curl_saferealloc(mem->memory, mem->size + realsize);
- if(!mem->memory)
- /* out of memory! */
- return 0;
-
- memcpy(&(mem->memory[mem->size]), contents, realsize);
- mem->size += realsize;
-
return realsize;
}
@@ -238,10 +229,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
}
p->dnstype = dnstype;
- p->serverdoh.memory = NULL;
- /* the memory will be grown as needed by realloc in the doh_write_cb
- function */
- p->serverdoh.size = 0;
+ Curl_dyn_init(&p->serverdoh, DYN_DOH_RESPONSE);
/* Note: this is code for sending the DoH request with GET but there's still
no logic that actually enables this. We should either add that ability or
@@ -272,7 +260,7 @@ static CURLcode dohprobe(struct Curl_easy *data,
if(!result) {
/* pass in the struct pointer via a local variable to please coverity and
the gcc typecheck helpers */
- struct dohresponse *resp = &p->serverdoh;
+ struct dynbuf *resp = &p->serverdoh;
ERROR_CHECK_SETOPT(CURLOPT_URL, url);
ERROR_CHECK_SETOPT(CURLOPT_WRITEFUNCTION, doh_write_cb);
ERROR_CHECK_SETOPT(CURLOPT_WRITEDATA, resp);
@@ -385,10 +373,10 @@ static CURLcode dohprobe(struct Curl_easy *data,
* 'Curl_addrinfo *' with the address information.
*/
-Curl_addrinfo *Curl_doh(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
+struct Curl_addrinfo *Curl_doh(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
{
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
@@ -401,6 +389,7 @@ Curl_addrinfo *Curl_doh(struct connectdata *conn,
/* start clean, consider allocating this struct on demand */
memset(&data->req.doh, 0, sizeof(struct dohdata));
+ conn->bits.doh = TRUE;
data->req.doh.host = hostname;
data->req.doh.port = port;
data->req.doh.headers =
@@ -506,38 +495,12 @@ static DOHcode store_aaaa(const unsigned char *doh,
return DOH_OK;
}
-static DOHcode cnameappend(struct cnamestore *c,
- const unsigned char *src,
- size_t len)
-{
- if(!c->alloc) {
- c->allocsize = len + 1;
- c->alloc = malloc(c->allocsize);
- if(!c->alloc)
- return DOH_OUT_OF_MEM;
- }
- else if(c->allocsize < (c->allocsize + len + 1)) {
- char *ptr;
- c->allocsize += len + 1;
- ptr = realloc(c->alloc, c->allocsize);
- if(!ptr) {
- free(c->alloc);
- return DOH_OUT_OF_MEM;
- }
- c->alloc = ptr;
- }
- memcpy(&c->alloc[c->len], src, len);
- c->len += len;
- c->alloc[c->len] = 0; /* keep it zero terminated */
- return DOH_OK;
-}
-
static DOHcode store_cname(const unsigned char *doh,
size_t dohlen,
unsigned int index,
struct dohentry *d)
{
- struct cnamestore *c;
+ struct dynbuf *c;
unsigned int loop = 128; /* a valid DNS name can never loop this much */
unsigned char length;
@@ -566,18 +529,15 @@ static DOHcode store_cname(const unsigned char *doh,
index++;
if(length) {
- DOHcode rc;
- if(c->len) {
- rc = cnameappend(c, (unsigned char *)".", 1);
- if(rc)
- return rc;
+ if(Curl_dyn_len(c)) {
+ if(Curl_dyn_add(c, "."))
+ return DOH_OUT_OF_MEM;
}
if((index + length) > dohlen)
return DOH_DNS_BAD_LABEL;
- rc = cnameappend(c, &doh[index], length);
- if(rc)
- return rc;
+ if(Curl_dyn_addn(c, &doh[index], length))
+ return DOH_OUT_OF_MEM;
index += length;
}
} while(length && --loop);
@@ -630,10 +590,13 @@ static DOHcode rdata(const unsigned char *doh,
return DOH_OK;
}
-static void init_dohentry(struct dohentry *de)
+UNITTEST void de_init(struct dohentry *de)
{
+ int i;
memset(de, 0, sizeof(*de));
de->ttl = INT_MAX;
+ for(i = 0; i < DOH_MAX_CNAME; i++)
+ Curl_dyn_init(&de->cname[i], DYN_DOH_CNAME);
}
@@ -808,7 +771,7 @@ static void showdoh(struct Curl_easy *data,
}
}
for(i = 0; i < d->numcname; i++) {
- infof(data, "CNAME: %s\n", d->cname[i].alloc);
+ infof(data, "CNAME: %s\n", Curl_dyn_ptr(&d->cname[i]));
}
}
#else
@@ -828,18 +791,19 @@ static void showdoh(struct Curl_easy *data,
* must be an associated call later to Curl_freeaddrinfo().
*/
-static Curl_addrinfo *
+static struct Curl_addrinfo *
doh2ai(const struct dohentry *de, const char *hostname, int port)
{
- Curl_addrinfo *ai;
- Curl_addrinfo *prevai = NULL;
- Curl_addrinfo *firstai = NULL;
+ struct Curl_addrinfo *ai;
+ struct Curl_addrinfo *prevai = NULL;
+ struct Curl_addrinfo *firstai = NULL;
struct sockaddr_in *addr;
#ifdef ENABLE_IPV6
struct sockaddr_in6 *addr6;
#endif
CURLcode result = CURLE_OK;
int i;
+ size_t hostlen = strlen(hostname) + 1; /* include zero terminator */
if(!de)
/* no input == no output! */
@@ -862,24 +826,14 @@ doh2ai(const struct dohentry *de, const char *hostname, int port)
addrtype = AF_INET;
}
- ai = calloc(1, sizeof(Curl_addrinfo));
+ ai = calloc(1, sizeof(struct Curl_addrinfo) + ss_size + hostlen);
if(!ai) {
result = CURLE_OUT_OF_MEMORY;
break;
}
- ai->ai_canonname = strdup(hostname);
- if(!ai->ai_canonname) {
- result = CURLE_OUT_OF_MEMORY;
- free(ai);
- break;
- }
- ai->ai_addr = calloc(1, ss_size);
- if(!ai->ai_addr) {
- result = CURLE_OUT_OF_MEMORY;
- free(ai->ai_canonname);
- free(ai);
- break;
- }
+ ai->ai_addr = (void *)((char *)ai + sizeof(struct Curl_addrinfo));
+ ai->ai_canonname = (void *)((char *)ai->ai_addr + ss_size);
+ memcpy(ai->ai_canonname, hostname, hostlen);
if(!firstai)
/* store the pointer we want to return from this function */
@@ -941,7 +895,7 @@ UNITTEST void de_cleanup(struct dohentry *d)
{
int i = 0;
for(i = 0; i < d->numcname; i++) {
- free(d->cname[i].alloc);
+ Curl_dyn_free(&d->cname[i]);
}
}
@@ -959,7 +913,9 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
CURLE_COULDNT_RESOLVE_HOST;
}
else if(!data->req.doh.pending) {
- DOHcode rc[DOH_PROBE_SLOTS];
+ DOHcode rc[DOH_PROBE_SLOTS] = {
+ DOH_OK, DOH_OK
+ };
struct dohentry de;
int slot;
/* remove DOH handles from multi handle and close them */
@@ -968,17 +924,19 @@ CURLcode Curl_doh_is_resolved(struct connectdata *conn,
Curl_close(&data->req.doh.probe[slot].easy);
}
/* parse the responses, create the struct and return it! */
- init_dohentry(&de);
+ de_init(&de);
for(slot = 0; slot < DOH_PROBE_SLOTS; slot++) {
- rc[slot] = doh_decode(data->req.doh.probe[slot].serverdoh.memory,
- data->req.doh.probe[slot].serverdoh.size,
- data->req.doh.probe[slot].dnstype,
+ struct dnsprobe *p = &data->req.doh.probe[slot];
+ if(!p->dnstype)
+ continue;
+ rc[slot] = doh_decode(Curl_dyn_uptr(&p->serverdoh),
+ Curl_dyn_len(&p->serverdoh),
+ p->dnstype,
&de);
- Curl_safefree(data->req.doh.probe[slot].serverdoh.memory);
+ Curl_dyn_free(&p->serverdoh);
if(rc[slot]) {
infof(data, "DOH: %s type %s for %s\n", doh_strerror(rc[slot]),
- type2name(data->req.doh.probe[slot].dnstype),
- data->req.doh.host);
+ type2name(p->dnstype), data->req.doh.host);
}
} /* next slot */
diff --git a/lib/doh.h b/lib/doh.h
index f6154ffd..bbd4c1a6 100644
--- a/lib/doh.h
+++ b/lib/doh.h
@@ -32,10 +32,10 @@
* and returns a 'Curl_addrinfo *' with the address information.
*/
-Curl_addrinfo *Curl_doh(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp);
+struct Curl_addrinfo *Curl_doh(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp);
CURLcode Curl_doh_is_resolved(struct connectdata *conn,
struct Curl_dns_entry **dns);
@@ -70,12 +70,6 @@ typedef enum {
#define DOH_MAX_ADDR 24
#define DOH_MAX_CNAME 4
-struct cnamestore {
- size_t len; /* length of cname */
- char *alloc; /* allocated pointer */
- size_t allocsize; /* allocated size */
-};
-
struct dohaddr {
int type;
union {
@@ -85,11 +79,11 @@ struct dohaddr {
};
struct dohentry {
- unsigned int ttl;
- int numaddr;
+ struct dynbuf cname[DOH_MAX_CNAME];
struct dohaddr addr[DOH_MAX_ADDR];
+ int numaddr;
+ unsigned int ttl;
int numcname;
- struct cnamestore cname[DOH_MAX_CNAME];
};
@@ -103,6 +97,7 @@ DOHcode doh_decode(const unsigned char *doh,
size_t dohlen,
DNStype dnstype,
struct dohentry *d);
+void de_init(struct dohentry *d);
void de_cleanup(struct dohentry *d);
#endif
diff --git a/lib/dotdot.c b/lib/dotdot.c
index fe4f4971..ce9a0521 100644
--- a/lib/dotdot.c
+++ b/lib/dotdot.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -39,7 +39,7 @@
* Curl_dedotdotify()
* @unittest: 1395
*
- * This function gets a zero-terminated path with dot and dotdot sequences
+ * This function gets a null-terminated path with dot and dotdot sequences
* passed in and strips them off according to the rules in RFC 3986 section
* 5.2.4.
*
@@ -62,7 +62,7 @@ char *Curl_dedotdotify(const char *input)
if(!out)
return NULL; /* out of memory */
- *out = 0; /* zero terminates, for inputs like "./" */
+ *out = 0; /* null-terminates, for inputs like "./" */
/* get a cloned copy of the input */
clone = strdup(input);
@@ -129,7 +129,7 @@ char *Curl_dedotdotify(const char *input)
if(*outptr == '/')
break;
}
- *outptr = 0; /* zero-terminate where it stops */
+ *outptr = 0; /* null-terminate where it stops */
}
else if(!strcmp("/..", clone)) {
clone[2]='/';
@@ -141,7 +141,7 @@ char *Curl_dedotdotify(const char *input)
if(*outptr == '/')
break;
}
- *outptr = 0; /* zero-terminate where it stops */
+ *outptr = 0; /* null-terminate where it stops */
}
/* D. if the input buffer consists only of "." or "..", then remove
diff --git a/lib/dynbuf.c b/lib/dynbuf.c
new file mode 100644
index 00000000..38d370b0
--- /dev/null
+++ b/lib/dynbuf.c
@@ -0,0 +1,227 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+#include "strdup.h"
+#include "dynbuf.h"
+
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define MIN_FIRST_ALLOC 32
+
+#define DYNINIT 0xbee51da /* random pattern */
+
+/*
+ * Init a dynbuf struct.
+ */
+void Curl_dyn_init(struct dynbuf *s, size_t toobig)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(toobig);
+ s->bufr = NULL;
+ s->leng = 0;
+ s->allc = 0;
+ s->toobig = toobig;
+#ifdef DEBUGBUILD
+ s->init = DYNINIT;
+#endif
+}
+
+/*
+ * free the buffer and re-init the necessary fields. It doesn't touch the
+ * 'init' field and thus this buffer can be reused to add data to again.
+ */
+void Curl_dyn_free(struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ Curl_safefree(s->bufr);
+ s->leng = s->allc = 0;
+}
+
+/*
+ * Store/append an chunk of memory to the dynbuf.
+ */
+static CURLcode dyn_nappend(struct dynbuf *s,
+ const unsigned char *mem, size_t len)
+{
+ size_t indx = s->leng;
+ size_t a = s->allc;
+ size_t fit = len + indx + 1; /* new string + old string + zero byte */
+
+ /* try to detect if there's rubbish in the struct */
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(s->toobig);
+ DEBUGASSERT(indx < s->toobig);
+ DEBUGASSERT(!s->leng || s->bufr);
+
+ if(fit > s->toobig) {
+ Curl_dyn_free(s);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else if(!a) {
+ DEBUGASSERT(!indx);
+ /* first invoke */
+ if(fit < MIN_FIRST_ALLOC)
+ a = MIN_FIRST_ALLOC;
+ else
+ a = fit;
+ }
+ else {
+ while(a < fit)
+ a *= 2;
+ }
+
+ if(a != s->allc) {
+ s->bufr = Curl_saferealloc(s->bufr, a);
+ if(!s->bufr) {
+ s->leng = s->allc = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ s->allc = a;
+ }
+
+ if(len)
+ memcpy(&s->bufr[indx], mem, len);
+ s->leng = indx + len;
+ s->bufr[s->leng] = 0;
+ return CURLE_OK;
+}
+
+/*
+ * Clears the string, keeps the allocation. This can also be called on a
+ * buffer that already was freed.
+ */
+void Curl_dyn_reset(struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ if(s->leng)
+ s->bufr[0] = 0;
+ s->leng = 0;
+}
+
+#ifdef USE_NGTCP2
+/*
+ * Specify the size of the tail to keep (number of bytes from the end of the
+ * buffer). The rest will be dropped.
+ */
+CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ if(trail > s->leng)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ else if(trail == s->leng)
+ return CURLE_OK;
+ else if(!trail) {
+ Curl_dyn_reset(s);
+ }
+ else {
+ memmove(&s->bufr[0], &s->bufr[s->leng - trail], trail);
+ s->leng = trail;
+ }
+ return CURLE_OK;
+
+}
+#endif
+
+/*
+ * Appends a buffer with length.
+ */
+CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return dyn_nappend(s, mem, len);
+}
+
+/*
+ * Append a null-terminated string at the end.
+ */
+CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
+{
+ size_t n = strlen(str);
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return dyn_nappend(s, (unsigned char *)str, n);
+}
+
+/*
+ * Append a string printf()-style
+ */
+CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+{
+ char *str;
+ va_list ap;
+ va_start(ap, fmt);
+ str = vaprintf(fmt, ap); /* this allocs a new string to append */
+ va_end(ap);
+
+ if(str) {
+ CURLcode result = dyn_nappend(s, (unsigned char *)str, strlen(str));
+ free(str);
+ return result;
+ }
+ /* If we failed, we cleanup the whole buffer and return error */
+ Curl_dyn_free(s);
+ return CURLE_OUT_OF_MEMORY;
+}
+
+/*
+ * Returns a pointer to the buffer.
+ */
+char *Curl_dyn_ptr(const struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return s->bufr;
+}
+
+/*
+ * Returns an unsigned pointer to the buffer.
+ */
+unsigned char *Curl_dyn_uptr(const struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return (unsigned char *)s->bufr;
+}
+
+/*
+ * Returns the length of the buffer.
+ */
+size_t Curl_dyn_len(const struct dynbuf *s)
+{
+ DEBUGASSERT(s);
+ DEBUGASSERT(s->init == DYNINIT);
+ DEBUGASSERT(!s->leng || s->bufr);
+ return s->leng;
+}
diff --git a/lib/dynbuf.h b/lib/dynbuf.h
new file mode 100644
index 00000000..c80239e2
--- /dev/null
+++ b/lib/dynbuf.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_DYNBUF_H
+#define HEADER_CURL_DYNBUF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+struct dynbuf {
+ char *bufr; /* point to a null-terminated allocated buffer */
+ size_t leng; /* number of bytes *EXCLUDING* the zero terminator */
+ size_t allc; /* size of the current allocation */
+ size_t toobig; /* size limit for the buffer */
+#ifdef DEBUGBUILD
+ int init; /* detect API usage mistakes */
+#endif
+};
+
+void Curl_dyn_init(struct dynbuf *s, size_t toobig);
+void Curl_dyn_free(struct dynbuf *s);
+CURLcode Curl_dyn_addn(struct dynbuf *s, const void *mem, size_t len)
+ WARN_UNUSED_RESULT;
+CURLcode Curl_dyn_add(struct dynbuf *s, const char *str)
+ WARN_UNUSED_RESULT;
+CURLcode Curl_dyn_addf(struct dynbuf *s, const char *fmt, ...)
+ WARN_UNUSED_RESULT;
+void Curl_dyn_reset(struct dynbuf *s);
+CURLcode Curl_dyn_tail(struct dynbuf *s, size_t trail);
+char *Curl_dyn_ptr(const struct dynbuf *s);
+unsigned char *Curl_dyn_uptr(const struct dynbuf *s);
+size_t Curl_dyn_len(const struct dynbuf *s);
+
+/* Dynamic buffer max sizes */
+#define DYN_DOH_RESPONSE 3000
+#define DYN_DOH_CNAME 256
+#define DYN_PAUSE_BUFFER (64 * 1024 * 1024)
+#define DYN_HAXPROXY 2048
+#define DYN_HTTP_REQUEST (128*1024)
+#define DYN_H2_HEADERS (128*1024)
+#define DYN_H2_TRAILER 4096
+#define DYN_APRINTF 8000000
+#define DYN_RTSP_REQ_HEADER (64*1024)
+#define DYN_TRAILERS (64*1024)
+#define DYN_PROXY_CONNECT_HEADERS 16384
+#define DYN_QLOG_NAME 1024
+#define DYN_H1_TRAILER DYN_H2_TRAILER
+#endif
diff --git a/lib/easy.c b/lib/easy.c
index d08c6066..292cca7f 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -77,6 +77,7 @@
#include "http_digest.h"
#include "system_win32.h"
#include "http2.h"
+#include "dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -509,7 +510,7 @@ static CURLcode wait_or_timeout(struct Curl_multi *multi, struct events *ev)
before = Curl_now();
/* wait for activity or timeout */
- pollrc = Curl_poll(fds, numfds, (int)ev->ms);
+ pollrc = Curl_poll(fds, numfds, ev->ms);
after = Curl_now();
@@ -680,6 +681,7 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
mcode = curl_multi_add_handle(multi, data);
if(mcode) {
curl_multi_cleanup(multi);
+ data->multi_easy = NULL;
if(mcode == CURLM_OUT_OF_MEMORY)
return CURLE_OUT_OF_MEMORY;
return CURLE_FAILED_INIT;
@@ -762,6 +764,7 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
{
CURLcode result = CURLE_OK;
enum dupstring i;
+ enum dupblob j;
/* Copy src->set into dst->set first, then deal with the strings
afterwards */
@@ -778,6 +781,16 @@ static CURLcode dupset(struct Curl_easy *dst, struct Curl_easy *src)
return result;
}
+ /* clear all blob pointers first */
+ memset(dst->set.blobs, 0, BLOB_LAST * sizeof(struct curl_blob *));
+ /* duplicate all blobs */
+ for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
+ result = Curl_setblobopt(&dst->set.blobs[j], src->set.blobs[j]);
+ /* Curl_setstropt return CURLE_BAD_FUNCTION_ARGUMENT with blob */
+ if(result)
+ return result;
+ }
+
/* duplicate memory areas pointed to */
i = STRING_COPYPOSTFIELDS;
if(src->set.postfieldsize && src->set.str[i]) {
@@ -816,19 +829,13 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
* the likeliness of us forgetting to init a buffer here in the future.
*/
outcurl->set.buffer_size = data->set.buffer_size;
- outcurl->state.buffer = malloc(outcurl->set.buffer_size + 1);
- if(!outcurl->state.buffer)
- goto fail;
-
- outcurl->state.headerbuff = malloc(HEADERSIZE);
- if(!outcurl->state.headerbuff)
- goto fail;
- outcurl->state.headersize = HEADERSIZE;
/* copy all userdefined values */
if(dupset(outcurl, data))
goto fail;
+ Curl_dyn_init(&outcurl->state.headerb, CURL_MAX_HTTP_HEADER);
+
/* the connection cache is setup on demand */
outcurl->state.conn_cache = NULL;
@@ -921,7 +928,7 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
curl_slist_free_all(outcurl->change.cookielist);
outcurl->change.cookielist = NULL;
Curl_safefree(outcurl->state.buffer);
- Curl_safefree(outcurl->state.headerbuff);
+ Curl_dyn_free(&outcurl->state.headerb);
Curl_safefree(outcurl->change.url);
Curl_safefree(outcurl->change.referer);
Curl_freeset(outcurl);
@@ -937,8 +944,6 @@ struct Curl_easy *curl_easy_duphandle(struct Curl_easy *data)
*/
void curl_easy_reset(struct Curl_easy *data)
{
- long old_buffer_size = data->set.buffer_size;
-
Curl_free_request_state(data);
/* zero out UserDefined data: */
@@ -962,18 +967,6 @@ void curl_easy_reset(struct Curl_easy *data)
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
Curl_http_auth_cleanup_digest(data);
#endif
-
- /* resize receive buffer */
- if(old_buffer_size != data->set.buffer_size) {
- char *newbuff = realloc(data->state.buffer, data->set.buffer_size + 1);
- if(!newbuff) {
- DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
- /* nothing we can do here except use the old size */
- data->set.buffer_size = old_buffer_size;
- }
- else
- data->state.buffer = newbuff;
- }
}
/*
@@ -1040,7 +1033,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
/* copy the structs to allow for immediate re-pausing */
for(i = 0; i < data->state.tempcount; i++) {
writebuf[i] = data->state.tempwrite[i];
- data->state.tempwrite[i].buf = NULL;
+ Curl_dyn_init(&data->state.tempwrite[i].b, DYN_PAUSE_BUFFER);
}
data->state.tempcount = 0;
@@ -1054,9 +1047,10 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
/* even if one function returns error, this loops through and frees
all buffers */
if(!result)
- result = Curl_client_write(conn, writebuf[i].type, writebuf[i].buf,
- writebuf[i].len);
- free(writebuf[i].buf);
+ result = Curl_client_write(conn, writebuf[i].type,
+ Curl_dyn_ptr(&writebuf[i].b),
+ Curl_dyn_len(&writebuf[i].b));
+ Curl_dyn_free(&writebuf[i].b);
}
/* recover previous owner of the connection */
diff --git a/lib/easyif.h b/lib/easyif.h
index 8a309c55..eda0d62e 100644
--- a/lib/easyif.h
+++ b/lib/easyif.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/lib/escape.c b/lib/escape.c
index 7121db31..2bea145f 100644
--- a/lib/escape.c
+++ b/lib/escape.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -79,82 +79,83 @@ char *curl_unescape(const char *string, int length)
char *curl_easy_escape(struct Curl_easy *data, const char *string,
int inlength)
{
- size_t alloc;
- char *ns;
- char *testing_ptr = NULL;
- size_t newlen;
- size_t strindex = 0;
size_t length;
CURLcode result;
+ struct dynbuf d;
if(inlength < 0)
return NULL;
- alloc = (inlength?(size_t)inlength:strlen(string)) + 1;
- newlen = alloc;
+ Curl_dyn_init(&d, CURL_MAX_INPUT_LENGTH);
- ns = malloc(alloc);
- if(!ns)
- return NULL;
+ length = (inlength?(size_t)inlength:strlen(string));
+ if(!length)
+ return strdup("");
- length = alloc-1;
while(length--) {
unsigned char in = *string; /* we need to treat the characters unsigned */
- if(Curl_isunreserved(in))
- /* just copy this */
- ns[strindex++] = in;
+ if(Curl_isunreserved(in)) {
+ /* append this */
+ if(Curl_dyn_addn(&d, &in, 1))
+ return NULL;
+ }
else {
/* encode it */
- newlen += 2; /* the size grows with two, since this'll become a %XX */
- if(newlen > alloc) {
- alloc *= 2;
- testing_ptr = Curl_saferealloc(ns, alloc);
- if(!testing_ptr)
- return NULL;
- ns = testing_ptr;
- }
-
+ char encoded[4];
result = Curl_convert_to_network(data, (char *)&in, 1);
if(result) {
/* Curl_convert_to_network calls failf if unsuccessful */
- free(ns);
+ Curl_dyn_free(&d);
return NULL;
}
- msnprintf(&ns[strindex], 4, "%%%02X", in);
-
- strindex += 3;
+ msnprintf(encoded, sizeof(encoded), "%%%02X", in);
+ if(Curl_dyn_add(&d, encoded))
+ return NULL;
}
string++;
}
- ns[strindex] = 0; /* terminate it */
- return ns;
+
+ return Curl_dyn_ptr(&d);
}
/*
* Curl_urldecode() URL decodes the given string.
*
- * Optionally detects control characters (byte codes lower than 32) in the
- * data and rejects such data.
- *
* Returns a pointer to a malloced string in *ostring with length given in
* *olen. If length == 0, the length is assumed to be strlen(string).
*
* 'data' can be set to NULL but then this function can't convert network
* data to host for non-ascii.
+ *
+ * ctrl options:
+ * - REJECT_NADA: accept everything
+ * - REJECT_CTRL: rejects control characters (byte codes lower than 32) in
+ * the data
+ * - REJECT_ZERO: rejects decoded zero bytes
+ *
+ * The values for the enum starts at 2, to make the assert detect legacy
+ * invokes that used TRUE/FALSE (0 and 1).
*/
+
CURLcode Curl_urldecode(struct Curl_easy *data,
const char *string, size_t length,
char **ostring, size_t *olen,
- bool reject_ctrl)
+ enum urlreject ctrl)
{
- size_t alloc = (length?length:strlen(string)) + 1;
- char *ns = malloc(alloc);
+ size_t alloc;
+ char *ns;
size_t strindex = 0;
unsigned long hex;
CURLcode result = CURLE_OK;
+ DEBUGASSERT(string);
+ DEBUGASSERT(ctrl >= REJECT_NADA); /* crash on TRUE/FALSE */
+
+ alloc = (length?length:strlen(string)) + 1;
+ ns = malloc(alloc);
+
if(!ns)
return CURLE_OUT_OF_MEMORY;
@@ -186,7 +187,8 @@ CURLcode Curl_urldecode(struct Curl_easy *data,
alloc -= 2;
}
- if(reject_ctrl && (in < 0x20)) {
+ if(((ctrl == REJECT_CTRL) && (in < 0x20)) ||
+ ((ctrl == REJECT_ZERO) && (in == 0))) {
free(ns);
return CURLE_URL_MALFORMAT;
}
@@ -220,7 +222,7 @@ char *curl_easy_unescape(struct Curl_easy *data, const char *string,
size_t inputlen = length;
size_t outputlen;
CURLcode res = Curl_urldecode(data, string, inputlen, &str, &outputlen,
- FALSE);
+ REJECT_NADA);
if(res)
return NULL;
diff --git a/lib/escape.h b/lib/escape.h
index d8bbe5cb..586db7e6 100644
--- a/lib/escape.h
+++ b/lib/escape.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -25,9 +25,16 @@
* allocated string or NULL if an error occurred. */
bool Curl_isunreserved(unsigned char in);
+
+enum urlreject {
+ REJECT_NADA = 2,
+ REJECT_CTRL,
+ REJECT_ZERO
+};
+
CURLcode Curl_urldecode(struct Curl_easy *data,
const char *string, size_t length,
char **ostring, size_t *olen,
- bool reject_crlf);
+ enum urlreject ctrl);
#endif /* HEADER_CURL_ESCAPE_H */
diff --git a/lib/file.c b/lib/file.c
index 576a7946..cd3e49c3 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -144,7 +144,7 @@ static CURLcode file_connect(struct connectdata *conn, bool *done)
size_t real_path_len;
CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &real_path,
- &real_path_len, FALSE);
+ &real_path_len, REJECT_ZERO);
if(result)
return result;
diff --git a/lib/formdata.c b/lib/formdata.c
index 57ec6ad2..1cab2c5c 100644
--- a/lib/formdata.c
+++ b/lib/formdata.c
@@ -123,11 +123,11 @@ AddHttpPost(char *name, size_t namelength,
* parent_form_info is NULL.
*
***************************************************************************/
-static FormInfo * AddFormInfo(char *value,
- char *contenttype,
- FormInfo *parent_form_info)
+static struct FormInfo *AddFormInfo(char *value,
+ char *contenttype,
+ struct FormInfo *parent_form_info)
{
- FormInfo *form_info;
+ struct FormInfo *form_info;
form_info = calloc(1, sizeof(struct FormInfo));
if(form_info) {
if(value)
@@ -204,7 +204,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
struct curl_httppost **last_post,
va_list params)
{
- FormInfo *first_form, *current_form, *form = NULL;
+ struct FormInfo *first_form, *current_form, *form = NULL;
CURLFORMcode return_value = CURL_FORMADD_OK;
const char *prevtype = NULL;
struct curl_httppost *post = NULL;
@@ -521,7 +521,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
if(CURL_FORMADD_OK != return_value) {
/* On error, free allocated fields for all nodes of the FormInfo linked
list without deallocating nodes. List nodes are deallocated later on */
- FormInfo *ptr;
+ struct FormInfo *ptr;
for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
if(ptr->name_alloc) {
Curl_safefree(ptr->name);
@@ -602,7 +602,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
/* Note that there's small risk that form->name is NULL here if the
app passed in a bad combo, so we better check for that first. */
if(form->name) {
- /* copy name (without strdup; possibly not nul-terminated) */
+ /* copy name (without strdup; possibly not null-terminated) */
form->name = Curl_memdup(form->name, form->namelength?
form->namelength:
strlen(form->name) + 1);
@@ -650,7 +650,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
/* On error, free allocated fields for nodes of the FormInfo linked
list which are not already owned by the httppost linked list
without deallocating nodes. List nodes are deallocated later on */
- FormInfo *ptr;
+ struct FormInfo *ptr;
for(ptr = form; ptr != NULL; ptr = ptr->more) {
if(ptr->name_alloc) {
Curl_safefree(ptr->name);
@@ -676,7 +676,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost,
fields given that these have either been deallocated or are owned
now by the httppost linked list */
while(first_form) {
- FormInfo *ptr = first_form->more;
+ struct FormInfo *ptr = first_form->more;
free(first_form);
first_form = ptr;
}
@@ -771,7 +771,7 @@ void curl_formfree(struct curl_httppost *form)
}
-/* Set mime part name, taking care of non nul-terminated name string. */
+/* Set mime part name, taking care of non null-terminated name string. */
static CURLcode setname(curl_mimepart *part, const char *name, size_t len)
{
char *zname;
diff --git a/lib/formdata.h b/lib/formdata.h
index cb20805f..3766d38f 100644
--- a/lib/formdata.h
+++ b/lib/formdata.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -27,7 +27,7 @@
#ifndef CURL_DISABLE_MIME
/* used by FormAdd for temporary storage */
-typedef struct FormInfo {
+struct FormInfo {
char *name;
bool name_alloc;
size_t namelength;
@@ -45,7 +45,7 @@ typedef struct FormInfo {
char *userp; /* pointer for the read callback */
struct curl_slist *contentheader;
struct FormInfo *more;
-} FormInfo;
+};
CURLcode Curl_getformdata(struct Curl_easy *data,
curl_mimepart *,
diff --git a/lib/ftp.c b/lib/ftp.c
index 57b22ade..20351ff8 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -113,7 +113,7 @@ static CURLcode ftp_parse_url_path(struct connectdata *conn);
static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void ftp_pasv_verbose(struct connectdata *conn,
- Curl_addrinfo *ai,
+ struct Curl_addrinfo *ai,
char *newhost, /* ascii version */
int port);
#endif
@@ -136,7 +136,7 @@ static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks);
static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks);
static CURLcode ftp_doing(struct connectdata *conn,
bool *dophase_done);
-static CURLcode ftp_setup_connection(struct connectdata * conn);
+static CURLcode ftp_setup_connection(struct connectdata *conn);
static CURLcode init_wc_data(struct connectdata *conn);
static CURLcode wc_statemach(struct connectdata *conn);
@@ -221,6 +221,9 @@ static void close_secondarysocket(struct connectdata *conn)
conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
}
conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
+#ifndef CURL_DISABLE_PROXY
+ conn->bits.proxy_ssl_connected[SECONDARYSOCKET] = FALSE;
+#endif
}
/*
@@ -291,7 +294,7 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
conn->sock[SECONDARYSOCKET] = s;
(void)curlx_nonblock(s, TRUE); /* enable non-blocking */
- conn->sock_accepted = TRUE;
+ conn->bits.sock_accepted = TRUE;
if(data->set.fsockopt) {
int error = 0;
@@ -334,7 +337,7 @@ static timediff_t ftp_timeleft_accept(struct Curl_easy *data)
now = Curl_now();
/* check if the generic timeout possibly is set shorter */
- other = Curl_timeleft(data, &now, FALSE);
+ other = Curl_timeleft(data, &now, FALSE);
if(other && (other < timeout_ms))
/* note that this also works fine for when other happens to be negative
due to it already having elapsed */
@@ -386,7 +389,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
/* Data connection could not be established, let's return */
infof(data, "There is negative response in cache while serv connect\n");
- Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ (void)Curl_GetFTPResponse(&nread, conn, &ftpcode);
return CURLE_FTP_ACCEPT_FAILED;
}
@@ -408,7 +411,7 @@ static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
}
else if(result & CURL_CSELECT_IN) {
infof(data, "Ctrl conn has data while waiting for data conn\n");
- Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ (void)Curl_GetFTPResponse(&nread, conn, &ftpcode);
if(ftpcode/100 > 3)
return CURLE_FTP_ACCEPT_FAILED;
@@ -632,8 +635,8 @@ CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
while(!*ftpcode && !result) {
/* check and reset timeout value every lap */
- time_t timeout = Curl_pp_state_timeout(pp, FALSE);
- time_t interval_ms;
+ timediff_t timeout = Curl_pp_state_timeout(pp, FALSE);
+ timediff_t interval_ms;
if(timeout <= 0) {
failf(data, "FTP response timeout");
@@ -815,6 +818,7 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks)
if(FTP_STOP == ftpc->state) {
int bits = GETSOCK_READSOCK(0);
+ bool any = FALSE;
/* if stopped and still in this state, then we're also waiting for a
connect on the secondary connection */
@@ -829,10 +833,11 @@ static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks)
if(conn->tempsock[i] != CURL_SOCKET_BAD) {
socks[s] = conn->tempsock[i];
bits |= GETSOCK_WRITESOCK(s++);
+ any = TRUE;
}
}
}
- else {
+ if(!any) {
socks[1] = conn->sock[SECONDARYSOCKET];
bits |= GETSOCK_WRITESOCK(1) | GETSOCK_READSOCK(1);
}
@@ -913,7 +918,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
char myhost[MAX_IPADR_LEN + 1] = "";
struct Curl_sockaddr_storage ss;
- Curl_addrinfo *res, *ai;
+ struct Curl_addrinfo *res, *ai;
curl_socklen_t sslen;
char hbuf[NI_MAXHOST];
struct sockaddr *sa = (struct sockaddr *)&ss;
@@ -1038,6 +1043,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
} /* data->set.ftpport */
if(!host) {
+ const char *r;
/* not an interface and not a host name, get default by extracting
the IP from the control connection */
sslen = sizeof(ss);
@@ -1050,13 +1056,15 @@ static CURLcode ftp_state_use_port(struct connectdata *conn,
switch(sa->sa_family) {
#ifdef ENABLE_IPV6
case AF_INET6:
- Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
+ r = Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
break;
#endif
default:
- Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
+ r = Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
break;
}
+ if(!r)
+ return CURLE_FTP_PORT_FAILED;
host = hbuf; /* use this host name */
possibly_non_local = FALSE; /* we know it is local now */
}
@@ -1293,7 +1301,7 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn)
struct ftp_conn *ftpc = &conn->proto.ftpc;
CURLcode result = CURLE_OK;
/*
- Here's the excecutive summary on what to do:
+ Here's the executive summary on what to do:
PASV is RFC959, expect:
227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
@@ -1444,7 +1452,7 @@ static CURLcode ftp_state_list(struct connectdata *conn)
/* url-decode before evaluation: e.g. paths starting/ending with %2f */
const char *slashPos = NULL;
char *rawPath = NULL;
- result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, TRUE);
+ result = Curl_urldecode(data, ftp->path, 0, &rawPath, NULL, REJECT_CTRL);
if(result)
return result;
@@ -1759,7 +1767,11 @@ static CURLcode ftp_epsv_disable(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
- if(conn->bits.ipv6 && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)) {
+ if(conn->bits.ipv6
+#ifndef CURL_DISABLE_PROXY
+ && !(conn->bits.tunnel_proxy || conn->bits.socksproxy)
+#endif
+ ) {
/* We can't disable EPSV when doing IPv6, so this is instead a fail */
failf(conn->data, "Failed EPSV attempt, exiting\n");
return CURLE_WEIRD_SERVER_REPLY;
@@ -1784,9 +1796,10 @@ static char *control_address(struct connectdata *conn)
If a proxy tunnel is used, returns the original host name 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;
-
+#endif
return conn->ip_addr_str;
}
@@ -1903,6 +1916,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
return CURLE_FTP_WEIRD_PASV_REPLY;
}
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy) {
/*
* This connection uses a proxy and we need to connect to the proxy again
@@ -1925,7 +1939,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
return CURLE_COULDNT_RESOLVE_PROXY;
}
}
- else {
+ else
+#endif
+ {
/* normal, direct, ftp connection */
rc = Curl_resolv(conn, ftpc->newhost, ftpc->newport, FALSE, &addr);
if(rc == CURLRESOLV_PENDING)
@@ -2634,9 +2650,12 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
#endif
if(data->set.use_ssl &&
- (!conn->ssl[FIRSTSOCKET].use ||
- (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
- !conn->proxy_ssl[FIRSTSOCKET].use))) {
+ (!conn->ssl[FIRSTSOCKET].use
+#ifndef CURL_DISABLE_PROXY
+ || (conn->bits.proxy_ssl_connected[FIRSTSOCKET] &&
+ !conn->proxy_ssl[FIRSTSOCKET].use)
+#endif
+ )) {
/* We don't have a SSL/TLS connection yet, but FTPS is
requested. Try a FTPS connection now */
@@ -2808,7 +2827,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
store++;
ptr++;
}
- *store = '\0'; /* zero terminate */
+ *store = '\0'; /* null-terminate */
}
if(entry_extracted) {
/* If the path name does not look like an absolute path (i.e.: it
@@ -2872,7 +2891,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn)
ptr++;
for(store = os; *ptr && *ptr != ' ';)
*store++ = *ptr++;
- *store = '\0'; /* zero terminate */
+ *store = '\0'; /* null-terminate */
/* Check for special servers here. */
@@ -3175,7 +3194,8 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
if(!result)
/* get the url-decoded "raw" path */
- result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, TRUE);
+ result = Curl_urldecode(data, 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) */
@@ -3231,9 +3251,9 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
}
if(conn->ssl[SECONDARYSOCKET].use) {
- /* The secondary socket is using SSL so we must close down that part
- first before we close the socket for real */
- Curl_ssl_close(conn, SECONDARYSOCKET);
+ /* The secondary socket used SSL so we must close down that part first
+ before we close the socket for real */
+ result = Curl_ssl_shutdown(conn, SECONDARYSOCKET);
/* Note that we keep "use" set to TRUE since that (next) connection is
still requested to use SSL */
@@ -3249,7 +3269,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
* data has been transferred. This happens when doing through NATs etc that
* abandon old silent connections.
*/
- long old_time = pp->response_time;
+ timediff_t old_time = pp->response_time;
pp->response_time = 60*1000; /* give it only a minute for now */
pp->response = Curl_now(); /* timeout relative now */
@@ -3442,7 +3462,7 @@ static CURLcode ftp_nb_type(struct connectdata *conn,
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void
ftp_pasv_verbose(struct connectdata *conn,
- Curl_addrinfo *ai,
+ struct Curl_addrinfo *ai,
char *newhost, /* ascii version */
int port)
{
@@ -3500,6 +3520,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
}
}
+#ifndef CURL_DISABLE_PROXY
result = Curl_proxy_connect(conn, SECONDARYSOCKET);
if(result)
return result;
@@ -3510,7 +3531,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, int *completep)
if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
Curl_connect_ongoing(conn))
return result;
-
+#endif
if(ftpc->state) {
/* already in a state so skip the initial commands.
@@ -4090,7 +4111,7 @@ CURLcode ftp_parse_url_path(struct connectdata *conn)
ftpc->cwdfail = FALSE;
/* url-decode ftp path before further evaluation */
- result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, TRUE);
+ result = Curl_urldecode(data, ftp->path, 0, &rawPath, &pathLen, REJECT_CTRL);
if(result)
return result;
@@ -4337,7 +4358,6 @@ static CURLcode ftp_setup_connection(struct connectdata *conn)
char command;
*type = 0; /* it was in the middle of the hostname */
command = Curl_raw_toupper(type[6]);
- conn->bits.type_set = TRUE;
switch(command) {
case 'A': /* ASCII mode */
diff --git a/lib/getinfo.c b/lib/getinfo.c
index 84d9fc1c..6d5bd5fc 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -198,9 +198,11 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
case CURLINFO_SSL_VERIFYRESULT:
*param_longp = data->set.ssl.certverifyresult;
break;
+#ifndef CURL_DISABLE_PROXY
case CURLINFO_PROXY_SSL_VERIFYRESULT:
*param_longp = data->set.proxy_ssl.certverifyresult;
break;
+#endif
case CURLINFO_REDIRECT_COUNT:
*param_longp = data->set.followlocation;
break;
@@ -320,7 +322,7 @@ static CURLcode getinfo_offt(struct Curl_easy *data, CURLINFO info,
*param_offt = data->progress.downloaded;
break;
case CURLINFO_SPEED_DOWNLOAD_T:
- *param_offt = data->progress.dlspeed;
+ *param_offt = data->progress.dlspeed;
break;
case CURLINFO_SPEED_UPLOAD_T:
*param_offt = data->progress.ulspeed;
@@ -408,13 +410,13 @@ static CURLcode getinfo_double(struct Curl_easy *data, CURLINFO info,
*param_doublep = DOUBLE_SECS(data->progress.t_starttransfer);
break;
case CURLINFO_SIZE_UPLOAD:
- *param_doublep = (double)data->progress.uploaded;
+ *param_doublep = (double)data->progress.uploaded;
break;
case CURLINFO_SIZE_DOWNLOAD:
*param_doublep = (double)data->progress.downloaded;
break;
case CURLINFO_SPEED_DOWNLOAD:
- *param_doublep = (double)data->progress.dlspeed;
+ *param_doublep = (double)data->progress.dlspeed;
break;
case CURLINFO_SPEED_UPLOAD:
*param_doublep = (double)data->progress.ulspeed;
diff --git a/lib/gopher.c b/lib/gopher.c
index c48098f7..b4811b28 100644
--- a/lib/gopher.c
+++ b/lib/gopher.c
@@ -116,7 +116,7 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
newp += 2;
/* ... and finally unescape */
- result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE);
+ result = Curl_urldecode(data, newp, 0, &sel, &len, REJECT_ZERO);
free(gopherpath);
if(result)
return result;
diff --git a/lib/hmac.c b/lib/hmac.c
index ae68827b..e4fea8a5 100644
--- a/lib/hmac.c
+++ b/lib/hmac.c
@@ -48,13 +48,13 @@ static const unsigned char hmac_opad = 0x5C;
-HMAC_context *
-Curl_HMAC_init(const HMAC_params * hashparams,
+struct HMAC_context *
+Curl_HMAC_init(const struct HMAC_params *hashparams,
const unsigned char *key,
unsigned int keylen)
{
size_t i;
- HMAC_context *ctxt;
+ struct HMAC_context *ctxt;
unsigned char *hkey;
unsigned char b;
@@ -101,7 +101,7 @@ Curl_HMAC_init(const HMAC_params * hashparams,
return ctxt;
}
-int Curl_HMAC_update(HMAC_context * ctxt,
+int Curl_HMAC_update(struct HMAC_context *ctxt,
const unsigned char *data,
unsigned int len)
{
@@ -111,9 +111,9 @@ int Curl_HMAC_update(HMAC_context * ctxt,
}
-int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result)
+int Curl_HMAC_final(struct HMAC_context *ctxt, unsigned char *result)
{
- const HMAC_params * hashparams = ctxt->hmac_hash;
+ const struct HMAC_params *hashparams = ctxt->hmac_hash;
/* Do not get result if called with a null parameter: only release
storage. */
@@ -147,12 +147,13 @@ int Curl_HMAC_final(HMAC_context *ctxt, unsigned char *result)
*
* Returns CURLE_OK on success.
*/
-CURLcode Curl_hmacit(const HMAC_params *hashparams,
+CURLcode Curl_hmacit(const struct HMAC_params *hashparams,
const unsigned char *key, const size_t keylen,
const unsigned char *data, const size_t datalen,
unsigned char *output)
{
- HMAC_context *ctxt = Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen));
+ struct HMAC_context *ctxt =
+ Curl_HMAC_init(hashparams, key, curlx_uztoui(keylen));
if(!ctxt)
return CURLE_OUT_OF_MEMORY;
diff --git a/lib/hostasyn.c b/lib/hostasyn.c
index 99d872b3..ed9190f4 100644
--- a/lib/hostasyn.c
+++ b/lib/hostasyn.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -117,10 +117,10 @@ CURLcode Curl_addrinfo_callback(struct connectdata *conn,
* name resolve layers (selected at build-time). They all take this same set
* of arguments
*/
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
+struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
{
return Curl_resolver_getaddrinfo(conn, hostname, port, waitp);
}
diff --git a/lib/hostip.c b/lib/hostip.c
index c0feb79f..dd5916e3 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -120,7 +120,7 @@ static void freednsentry(void *freethis);
/*
* Return # of addresses in a Curl_addrinfo struct
*/
-int Curl_num_addresses(const Curl_addrinfo *addr)
+int Curl_num_addresses(const struct Curl_addrinfo *addr)
{
int i = 0;
while(addr) {
@@ -131,39 +131,36 @@ int Curl_num_addresses(const Curl_addrinfo *addr)
}
/*
- * Curl_printable_address() returns a printable version of the 1st address
+ * Curl_printable_address() stores a printable version of the 1st address
* given in the 'ai' argument. The result will be stored in the buf that is
* bufsize bytes big.
*
- * If the conversion fails, it returns NULL.
+ * If the conversion fails, the target buffer is empty.
*/
-const char *
-Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
+void Curl_printable_address(const struct Curl_addrinfo *ai, char *buf,
+ size_t bufsize)
{
- const struct sockaddr_in *sa4;
- const struct in_addr *ipaddr4;
-#ifdef ENABLE_IPV6
- const struct sockaddr_in6 *sa6;
- const struct in6_addr *ipaddr6;
-#endif
+ DEBUGASSERT(bufsize);
+ buf[0] = 0;
switch(ai->ai_family) {
- case AF_INET:
- sa4 = (const void *)ai->ai_addr;
- ipaddr4 = &sa4->sin_addr;
- return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
- bufsize);
+ case AF_INET: {
+ const struct sockaddr_in *sa4 = (const void *)ai->ai_addr;
+ const struct in_addr *ipaddr4 = &sa4->sin_addr;
+ (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf, bufsize);
+ break;
+ }
#ifdef ENABLE_IPV6
- case AF_INET6:
- sa6 = (const void *)ai->ai_addr;
- ipaddr6 = &sa6->sin6_addr;
- return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
- bufsize);
+ case AF_INET6: {
+ const struct sockaddr_in6 *sa6 = (const void *)ai->ai_addr;
+ const struct in6_addr *ipaddr6 = &sa6->sin6_addr;
+ (void)Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf, bufsize);
+ break;
+ }
#endif
- default:
- break;
+ default:
+ break;
}
- return NULL;
}
/*
@@ -337,7 +334,7 @@ Curl_fetch_addr(struct connectdata *conn,
#ifndef CURL_DISABLE_SHUFFLE_DNS
UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
- Curl_addrinfo **addr);
+ struct Curl_addrinfo **addr);
/*
* Curl_shuffle_addr() shuffles the order of addresses in a 'Curl_addrinfo'
* struct by re-linking its linked list.
@@ -351,13 +348,13 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
* @unittest: 1608
*/
UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
- Curl_addrinfo **addr)
+ struct Curl_addrinfo **addr)
{
CURLcode result = CURLE_OK;
const int num_addrs = Curl_num_addresses(*addr);
if(num_addrs > 1) {
- Curl_addrinfo **nodes;
+ struct Curl_addrinfo **nodes;
infof(data, "Shuffling %i addresses", num_addrs);
nodes = malloc(num_addrs*sizeof(*nodes));
@@ -376,7 +373,7 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
if(rnd) {
/* Fisher-Yates shuffle */
if(Curl_rand(data, (unsigned char *)rnd, rnd_size) == CURLE_OK) {
- Curl_addrinfo *swap_tmp;
+ struct Curl_addrinfo *swap_tmp;
for(i = num_addrs - 1; i > 0; i--) {
swap_tmp = nodes[rnd[i] % (i + 1)];
nodes[rnd[i] % (i + 1)] = nodes[i];
@@ -415,7 +412,7 @@ UNITTEST CURLcode Curl_shuffle_addr(struct Curl_easy *data,
*/
struct Curl_dns_entry *
Curl_cache_addr(struct Curl_easy *data,
- Curl_addrinfo *addr,
+ struct Curl_addrinfo *addr,
const char *hostname,
int port)
{
@@ -495,6 +492,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
enum resolve_t rc = CURLRESOLV_ERROR; /* default to failure */
*entry = NULL;
+ conn->bits.doh = FALSE; /* default is not */
if(data->share)
Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
@@ -513,11 +511,13 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
if(!dns) {
/* The entry was not in the cache. Resolve it to IP address */
- Curl_addrinfo *addr = NULL;
+ struct Curl_addrinfo *addr = NULL;
int respwait = 0;
-#ifndef USE_RESOLVE_ON_IPS
struct in_addr in;
+#ifndef USE_RESOLVE_ON_IPS
+ const
#endif
+ bool ipnum = FALSE;
/* notify the resolver start callback */
if(data->set.resolver_start) {
@@ -544,6 +544,22 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
addr = Curl_ip2addr(AF_INET6, &in6, hostname, port);
}
#endif /* ENABLE_IPV6 */
+
+#else /* if USE_RESOLVE_ON_IPS */
+ /* First check if this is an IPv4 address string */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ ipnum = TRUE;
+#ifdef ENABLE_IPV6
+ else {
+ struct in6_addr in6;
+ /* check if this is an IPv6 address string */
+ if(Curl_inet_pton(AF_INET6, hostname, &in6) > 0)
+ /* This is an IPv6 address literal */
+ ipnum = TRUE;
+ }
+#endif /* ENABLE_IPV6 */
+
#endif /* !USE_RESOLVE_ON_IPS */
if(!addr) {
@@ -552,7 +568,7 @@ enum resolve_t Curl_resolv(struct connectdata *conn,
if(!Curl_ipvalid(conn))
return CURLRESOLV_ERROR;
- if(allowDOH && data->set.doh) {
+ if(allowDOH && data->set.doh && !ipnum) {
addr = Curl_doh(conn, hostname, port, &respwait);
}
else {
@@ -890,7 +906,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
}
else {
struct Curl_dns_entry *dns;
- Curl_addrinfo *head = NULL, *tail = NULL;
+ struct Curl_addrinfo *head = NULL, *tail = NULL;
size_t entry_len;
char address[64];
#if !defined(CURL_DISABLE_VERBOSE_STRINGS)
@@ -924,7 +940,7 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
while(*end_ptr) {
size_t alen;
- Curl_addrinfo *ai;
+ struct Curl_addrinfo *ai;
addr_begin = end_ptr + 1;
addr_end = strchr(addr_begin, ',');
@@ -1047,7 +1063,7 @@ CURLcode Curl_resolv_check(struct connectdata *conn,
(void)dns;
#endif
- if(conn->data->set.doh)
+ if(conn->bits.doh)
return Curl_doh_is_resolved(conn, dns);
return Curl_resolver_is_resolved(conn, dns);
}
@@ -1056,7 +1072,7 @@ int Curl_resolv_getsock(struct connectdata *conn,
curl_socket_t *socks)
{
#ifdef CURLRES_ASYNCH
- if(conn->data->set.doh)
+ if(conn->bits.doh)
/* nothing to wait for during DOH resolve, those handles have their own
sockets */
return GETSOCK_BLANK;
@@ -1085,10 +1101,12 @@ CURLcode Curl_once_resolved(struct connectdata *conn,
result = Curl_setup_conn(conn, protocol_done);
- if(result)
- /* We're not allowed to return failure with memory left allocated
- in the connectdata struct, free those here */
- Curl_disconnect(conn->data, conn, TRUE); /* close the connection */
-
+ if(result) {
+ struct Curl_easy *data = conn->data;
+ DEBUGASSERT(data);
+ Curl_detach_connnection(data);
+ Curl_conncache_remove_conn(data, conn, TRUE);
+ Curl_disconnect(data, conn, TRUE);
+ }
return result;
}
diff --git a/lib/hostip.h b/lib/hostip.h
index baf1e586..374b06c8 100644
--- a/lib/hostip.h
+++ b/lib/hostip.h
@@ -64,7 +64,7 @@ struct connectdata;
struct curl_hash *Curl_global_host_cache_init(void);
struct Curl_dns_entry {
- Curl_addrinfo *addr;
+ struct Curl_addrinfo *addr;
/* timestamp == 0 -- CURLOPT_RESOLVE entry, doesn't timeout */
time_t timestamp;
/* use-counter, use Curl_resolv_unlock to release reference */
@@ -117,10 +117,10 @@ bool Curl_ipvalid(struct connectdata *conn);
* name resolve layers (selected at build-time). They all take this same set
* of arguments
*/
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp);
+struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp);
/* unlock a previously resolved dns entry */
@@ -134,7 +134,7 @@ int Curl_mk_dnscache(struct curl_hash *hash);
void Curl_hostcache_prune(struct Curl_easy *data);
/* Return # of addresses in a Curl_addrinfo struct */
-int Curl_num_addresses(const Curl_addrinfo *addr);
+int Curl_num_addresses(const struct Curl_addrinfo *addr);
#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
@@ -146,7 +146,7 @@ int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
#endif
/* IPv4 threadsafe resolve function used for synch and asynch builds */
-Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
+struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname, int port);
CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect);
@@ -158,15 +158,15 @@ CURLcode Curl_once_resolved(struct connectdata *conn, bool *protocol_connect);
*/
CURLcode Curl_addrinfo_callback(struct connectdata *conn,
int status,
- Curl_addrinfo *ai);
+ struct Curl_addrinfo *ai);
/*
* Curl_printable_address() returns a printable version of the 1st address
* given in the 'ip' argument. The result will be stored in the buf that is
* bufsize bytes big.
*/
-const char *Curl_printable_address(const Curl_addrinfo *ip,
- char *buf, size_t bufsize);
+void Curl_printable_address(const struct Curl_addrinfo *ip,
+ char *buf, size_t bufsize);
/*
* Curl_fetch_addr() fetches a 'Curl_dns_entry' already in the DNS cache.
@@ -187,7 +187,7 @@ Curl_fetch_addr(struct connectdata *conn,
* Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
*/
struct Curl_dns_entry *
-Curl_cache_addr(struct Curl_easy *data, Curl_addrinfo *addr,
+Curl_cache_addr(struct Curl_easy *data, struct Curl_addrinfo *addr,
const char *hostname, int port);
#ifndef INADDR_NONE
diff --git a/lib/hostip4.c b/lib/hostip4.c
index d5009a3e..eae94167 100644
--- a/lib/hostip4.c
+++ b/lib/hostip4.c
@@ -88,12 +88,12 @@ bool Curl_ipvalid(struct connectdata *conn)
* flavours have thread-safe versions of the plain gethostbyname() etc.
*
*/
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
+struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
{
- Curl_addrinfo *ai = NULL;
+ struct Curl_addrinfo *ai = NULL;
#ifdef CURL_DISABLE_VERBOSE_STRINGS
(void)conn;
@@ -119,13 +119,13 @@ Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
* implying that only threadsafe code and function calls may be used.
*
*/
-Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
- int port)
+struct Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
+ int port)
{
#if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3)
int res;
#endif
- Curl_addrinfo *ai = NULL;
+ struct Curl_addrinfo *ai = NULL;
struct hostent *h = NULL;
struct hostent *buf = NULL;
diff --git a/lib/hostip6.c b/lib/hostip6.c
index 41ff9869..11215758 100644
--- a/lib/hostip6.c
+++ b/lib/hostip6.c
@@ -103,20 +103,16 @@ bool Curl_ipvalid(struct connectdata *conn)
#if defined(CURLRES_SYNCH)
#ifdef DEBUG_ADDRINFO
-static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
+static void dump_addrinfo(struct connectdata *conn,
+ const struct Curl_addrinfo *ai)
{
printf("dump_addrinfo:\n");
for(; ai; ai = ai->ai_next) {
char buf[INET6_ADDRSTRLEN];
printf(" fam %2d, CNAME %s, ",
ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
- if(Curl_printable_address(ai, buf, sizeof(buf)))
- printf("%s\n", buf);
- else {
- char buffer[STRERROR_LEN];
- printf("failed; %s\n",
- Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
- }
+ Curl_printable_address(ai, buf, sizeof(buf));
+ printf("%s\n", buf);
}
}
#else
@@ -132,13 +128,13 @@ static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
* memory we need to free after use. That memory *MUST* be freed with
* Curl_freeaddrinfo(), nothing else.
*/
-Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
- const char *hostname,
- int port,
- int *waitp)
+struct Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
{
struct addrinfo hints;
- Curl_addrinfo *res;
+ struct Curl_addrinfo *res;
int error;
char sbuf[12];
char *sbufptr = NULL;
diff --git a/lib/http.c b/lib/http.c
index c3f7c350..28d66c28 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -125,7 +125,8 @@ const struct Curl_handler Curl_handler_http = {
ZERO_NULL, /* connection_check */
PORT_HTTP, /* defport */
CURLPROTO_HTTP, /* protocol */
- PROTOPT_CREDSPERREQUEST /* flags */
+ PROTOPT_CREDSPERREQUEST | /* flags */
+ PROTOPT_USERPWDCTRL
};
#ifdef USE_SSL
@@ -150,7 +151,8 @@ const struct Curl_handler Curl_handler_https = {
ZERO_NULL, /* connection_check */
PORT_HTTPS, /* defport */
CURLPROTO_HTTPS, /* protocol */
- PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */
+ PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN | /* flags */
+ PROTOPT_USERPWDCTRL
};
#endif
@@ -268,7 +270,7 @@ char *Curl_copy_header_value(const char *header)
return NULL;
memcpy(value, start, len);
- value[len] = 0; /* zero terminate */
+ value[len] = 0; /* null-terminate */
return value;
}
@@ -292,17 +294,21 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
char *out;
if(proxy) {
- userp = &conn->allocptr.proxyuserpwd;
+#ifndef CURL_DISABLE_PROXY
+ userp = &data->state.aptr.proxyuserpwd;
user = conn->http_proxy.user;
pwd = conn->http_proxy.passwd;
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
}
else {
- userp = &conn->allocptr.userpwd;
+ userp = &data->state.aptr.userpwd;
user = conn->user;
pwd = conn->passwd;
}
- out = aprintf("%s:%s", user, pwd);
+ out = aprintf("%s:%s", user, pwd ? pwd : "");
if(!out)
return CURLE_OUT_OF_MEMORY;
@@ -340,8 +346,9 @@ static CURLcode http_output_bearer(struct connectdata *conn)
{
char **userp;
CURLcode result = CURLE_OK;
+ struct Curl_easy *data = conn->data;
- userp = &conn->allocptr.userpwd;
+ userp = &data->state.aptr.userpwd;
free(*userp);
*userp = aprintf("Authorization: Bearer %s\r\n",
conn->data->set.str[STRING_BEARER]);
@@ -427,7 +434,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
skip this rewinding stuff */
return CURLE_OK;
- switch(data->set.httpreq) {
+ switch(data->state.httpreq) {
case HTTPREQ_GET:
case HTTPREQ_HEAD:
return CURLE_OK;
@@ -448,7 +455,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
}
else {
/* figure out how much data we are expected to send */
- switch(data->set.httpreq) {
+ switch(data->state.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_PUT:
if(data->state.infilesize != -1)
@@ -578,6 +585,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
conn->data->set.httpversion = CURL_HTTP_VERSION_1_1;
}
}
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy_user_passwd &&
((data->req.httpcode == 407) ||
(conn->bits.authneg && data->req.httpcode < 300))) {
@@ -586,10 +594,11 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
if(!pickproxy)
data->state.authproblem = TRUE;
}
+#endif
if(pickhost || pickproxy) {
- if((data->set.httpreq != HTTPREQ_GET) &&
- (data->set.httpreq != HTTPREQ_HEAD) &&
+ if((data->state.httpreq != HTTPREQ_GET) &&
+ (data->state.httpreq != HTTPREQ_HEAD) &&
!conn->bits.rewindaftersend) {
result = http_perhapsrewind(conn);
if(result)
@@ -610,8 +619,8 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
authentication is not "done" yet and
no authentication seems to be required and
we didn't try HEAD or GET */
- if((data->set.httpreq != HTTPREQ_GET) &&
- (data->set.httpreq != HTTPREQ_HEAD)) {
+ if((data->state.httpreq != HTTPREQ_GET) &&
+ (data->state.httpreq != HTTPREQ_HEAD)) {
data->req.newurl = strdup(data->change.url); /* clone URL */
if(!data->req.newurl)
return CURLE_OUT_OF_MEMORY;
@@ -689,10 +698,13 @@ output_auth_headers(struct connectdata *conn,
#endif
if(authstatus->picked == CURLAUTH_BASIC) {
/* Basic */
- if((proxy && conn->bits.proxy_user_passwd &&
- !Curl_checkProxyheaders(conn, "Proxy-authorization")) ||
- (!proxy && conn->bits.user_passwd &&
- !Curl_checkheaders(conn, "Authorization"))) {
+ if(
+#ifndef CURL_DISABLE_PROXY
+ (proxy && conn->bits.proxy_user_passwd &&
+ !Curl_checkProxyheaders(conn, "Proxy-authorization")) ||
+#endif
+ (!proxy && conn->bits.user_passwd &&
+ !Curl_checkheaders(conn, "Authorization"))) {
auth = "Basic";
result = http_output_basic(conn, proxy);
if(result)
@@ -719,10 +731,15 @@ output_auth_headers(struct connectdata *conn,
}
if(auth) {
+#ifndef CURL_DISABLE_PROXY
infof(data, "%s auth using %s with user '%s'\n",
proxy ? "Proxy" : "Server", auth,
proxy ? (conn->http_proxy.user ? conn->http_proxy.user : "") :
- (conn->user ? conn->user : ""));
+ (conn->user ? conn->user : ""));
+#else
+ infof(data, "Server auth using %s with user '%s'\n",
+ auth, conn->user ? conn->user : "");
+#endif
authstatus->multipass = (!authstatus->done) ? TRUE : FALSE;
}
else
@@ -762,7 +779,10 @@ Curl_http_output_auth(struct connectdata *conn,
authhost = &data->state.authhost;
authproxy = &data->state.authproxy;
- if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+ if(
+#ifndef CURL_DISABLE_PROXY
+ (conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+#endif
conn->bits.user_passwd || data->set.str[STRING_BEARER])
/* continue please */;
else {
@@ -1067,8 +1087,10 @@ static int http_should_fail(struct connectdata *conn)
*/
if((httpcode == 401) && !conn->bits.user_passwd)
return TRUE;
+#ifndef CURL_DISABLE_PROXY
if((httpcode == 407) && !conn->bits.proxy_user_passwd)
return TRUE;
+#endif
return data->state.authproblem;
}
@@ -1125,49 +1147,20 @@ static size_t readmoredata(char *buffer,
return fullsize;
}
-/* ------------------------------------------------------------------------- */
-/* add_buffer functions */
-
-/*
- * Curl_add_buffer_init() sets up and returns a fine buffer struct
- */
-Curl_send_buffer *Curl_add_buffer_init(void)
-{
- return calloc(1, sizeof(Curl_send_buffer));
-}
-
-/*
- * Curl_add_buffer_free() frees all associated resources.
- */
-void Curl_add_buffer_free(Curl_send_buffer **inp)
-{
- Curl_send_buffer *in;
- if(!inp)
- return;
- in = *inp;
- if(in) { /* deal with NULL input */
- free(in->buffer);
- free(in);
- }
- *inp = NULL;
-}
-
/*
- * Curl_add_buffer_send() sends a header buffer and frees all associated
+ * Curl_buffer_send() sends a header buffer and frees all associated
* memory. Body data may be appended to the header data if desired.
*
* Returns CURLcode
*/
-CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
- struct connectdata *conn,
-
- /* add the number of sent bytes to this
- counter */
- curl_off_t *bytes_written,
-
- /* how much of the buffer contains body data */
- size_t included_body_bytes,
- int socketindex)
+CURLcode Curl_buffer_send(struct dynbuf *in,
+ struct connectdata *conn,
+ /* add the number of sent bytes to this
+ counter */
+ curl_off_t *bytes_written,
+ /* how much of the buffer contains body data */
+ size_t included_body_bytes,
+ int socketindex)
{
ssize_t amount;
CURLcode result;
@@ -1178,7 +1171,6 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
size_t sendsize;
curl_socket_t sockfd;
size_t headersize;
- Curl_send_buffer *in = *inp;
DEBUGASSERT(socketindex <= SECONDARYSOCKET);
@@ -1187,8 +1179,8 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
/* The looping below is required since we use non-blocking sockets, but due
to the circumstances we will just loop and try again and again etc */
- ptr = in->buffer;
- size = in->size_used;
+ ptr = Curl_dyn_ptr(in);
+ size = Curl_dyn_len(in);
headersize = size - included_body_bytes; /* the initial part that isn't body
is header */
@@ -1199,12 +1191,15 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
/* Curl_convert_to_network calls failf if unsuccessful */
if(result) {
/* conversion failed, free memory and return to the caller */
- Curl_add_buffer_free(inp);
+ Curl_dyn_free(in);
return result;
}
- if((conn->handler->flags & PROTOPT_SSL ||
- conn->http_proxy.proxytype == CURLPROXY_HTTPS)
+ if((conn->handler->flags & PROTOPT_SSL
+#ifndef CURL_DISABLE_PROXY
+ || conn->http_proxy.proxytype == CURLPROXY_HTTPS
+#endif
+ )
&& conn->httpversion != 20) {
/* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
when we speak HTTPS, as if only a fraction of it is sent now, this data
@@ -1223,7 +1218,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
result = Curl_get_upload_buffer(data);
if(result) {
/* malloc failed, free memory and return to the caller */
- Curl_add_buffer_free(&in);
+ Curl_dyn_free(in);
return result;
}
memcpy(data->state.ulbuf, ptr, sendsize);
@@ -1286,7 +1281,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
size -= amount;
- ptr = in->buffer + amount;
+ ptr = Curl_dyn_ptr(in) + amount;
/* backup the currently set pointers */
http->backup.fread_func = data->state.fread_func;
@@ -1300,7 +1295,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
http->postdata = ptr;
http->postsize = (curl_off_t)size;
- http->send_buffer = in;
+ http->send_buffer = *in; /* copy the whole struct */
http->sending = HTTPSEND_REQUEST;
return CURLE_OK;
@@ -1320,87 +1315,11 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
return CURLE_SEND_ERROR;
}
}
- Curl_add_buffer_free(&in);
+ Curl_dyn_free(in);
return result;
}
-
-/*
- * add_bufferf() add the formatted input to the buffer.
- */
-CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...)
-{
- char *s;
- va_list ap;
- va_start(ap, fmt);
- s = vaprintf(fmt, ap); /* this allocs a new string to append */
- va_end(ap);
-
- if(s) {
- CURLcode result = Curl_add_buffer(inp, s, strlen(s));
- free(s);
- return result;
- }
- /* If we failed, we cleanup the whole buffer and return error */
- Curl_add_buffer_free(inp);
- return CURLE_OUT_OF_MEMORY;
-}
-
-/*
- * Curl_add_buffer() appends a memory chunk to the existing buffer
- */
-CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr,
- size_t size)
-{
- char *new_rb;
- Curl_send_buffer *in = *inp;
-
- if(~size < in->size_used) {
- /* If resulting used size of send buffer would wrap size_t, cleanup
- the whole buffer and return error. Otherwise the required buffer
- size will fit into a single allocatable memory chunk */
- Curl_add_buffer_free(inp);
- return CURLE_OUT_OF_MEMORY;
- }
-
- if(!in->buffer ||
- ((in->size_used + size) > (in->size_max - 1))) {
- /* If current buffer size isn't enough to hold the result, use a
- buffer size that doubles the required size. If this new size
- would wrap size_t, then just use the largest possible one */
- size_t new_size;
-
- if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) ||
- (~(size * 2) < (in->size_used * 2)))
- new_size = (size_t)-1;
- else
- new_size = (in->size_used + size) * 2;
-
- if(in->buffer)
- /* we have a buffer, enlarge the existing one */
- new_rb = Curl_saferealloc(in->buffer, new_size);
- else
- /* create a new buffer */
- new_rb = malloc(new_size);
-
- if(!new_rb) {
- /* If we failed, we cleanup the whole buffer and return error */
- free(in);
- *inp = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
-
- in->buffer = new_rb;
- in->size_max = new_size;
- }
- memcpy(&in->buffer[in->size_used], inptr, size);
-
- in->size_used += size;
-
- return CURLE_OK;
-}
-
/* end of the add_buffer functions */
/* ------------------------------------------------------------------------- */
@@ -1473,6 +1392,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
function to make the re-use checks properly be able to check this bit. */
connkeep(conn, "HTTP default");
+#ifndef CURL_DISABLE_PROXY
/* the CONNECT procedure might not have been completed */
result = Curl_proxy_connect(conn, FIRSTSOCKET);
if(result)
@@ -1489,7 +1409,6 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
/* nothing else to do except wait right now - we're not done here. */
return CURLE_OK;
-#ifndef CURL_DISABLE_PROXY
if(conn->data->set.haproxyprotocol) {
/* add HAProxy PROXY protocol header */
result = add_haproxy_protocol_header(conn);
@@ -1525,7 +1444,7 @@ static int http_getsock_do(struct connectdata *conn,
static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
{
char proxy_header[128];
- Curl_send_buffer *req_buffer;
+ struct dynbuf req;
CURLcode result;
char tcp_version[5];
@@ -1546,19 +1465,14 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
conn->data->info.conn_local_port,
conn->data->info.conn_primary_port);
- req_buffer = Curl_add_buffer_init();
- if(!req_buffer)
- return CURLE_OUT_OF_MEMORY;
+ Curl_dyn_init(&req, DYN_HAXPROXY);
- result = Curl_add_bufferf(&req_buffer, proxy_header);
+ result = Curl_dyn_add(&req, proxy_header);
if(result)
return result;
- result = Curl_add_buffer_send(&req_buffer,
- conn,
- &conn->data->info.request_size,
- 0,
- FIRSTSOCKET);
+ result = Curl_buffer_send(&req, conn, &conn->data->info.request_size,
+ 0, FIRSTSOCKET);
return result;
}
@@ -1619,14 +1533,11 @@ CURLcode Curl_http_done(struct connectdata *conn,
if(!http)
return CURLE_OK;
- if(http->send_buffer) {
- Curl_add_buffer_free(&http->send_buffer);
- }
-
+ Curl_dyn_free(&http->send_buffer);
Curl_http2_done(data, premature);
Curl_quic_done(data, premature);
-
Curl_mime_cleanpart(&http->form);
+ Curl_dyn_reset(&data->state.headerb);
if(status)
return status;
@@ -1692,7 +1603,7 @@ static const char *get_http_string(const struct Curl_easy *data,
/* check and possibly add an Expect: header */
static CURLcode expect100(struct Curl_easy *data,
struct connectdata *conn,
- Curl_send_buffer *req_buffer)
+ struct dynbuf *req)
{
CURLcode result = CURLE_OK;
data->state.expect100header = FALSE; /* default to false unless it is set
@@ -1708,8 +1619,7 @@ static CURLcode expect100(struct Curl_easy *data,
Curl_compareheader(ptr, "Expect:", "100-continue");
}
else {
- result = Curl_add_bufferf(&req_buffer,
- "Expect: 100-continue\r\n");
+ result = Curl_dyn_add(req, "Expect: 100-continue\r\n");
if(!result)
data->state.expect100header = TRUE;
}
@@ -1728,7 +1638,7 @@ enum proxy_use {
will return an error code if one of the headers is
not formatted correctly */
CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
- Curl_send_buffer **buffer,
+ struct dynbuf *b,
struct Curl_easy *handle)
{
char *ptr = NULL;
@@ -1754,8 +1664,10 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
/* only add correctly formatted trailers */
ptr = strchr(trailers->data, ':');
if(ptr && *(ptr + 1) == ' ') {
- result = Curl_add_bufferf(buffer, "%s%s", trailers->data,
- endofline_native);
+ result = Curl_dyn_add(b, trailers->data);
+ if(result)
+ return result;
+ result = Curl_dyn_add(b, endofline_native);
if(result)
return result;
}
@@ -1763,14 +1675,13 @@ CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
infof(handle, "Malformatted trailing header ! Skipping trailer.");
trailers = trailers->next;
}
- result = Curl_add_buffer(buffer, endofline_network,
- strlen(endofline_network));
+ result = Curl_dyn_add(b, endofline_network);
return result;
}
CURLcode Curl_add_custom_headers(struct connectdata *conn,
bool is_connect,
- Curl_send_buffer *req_buffer)
+ struct dynbuf *req)
{
char *ptr;
struct curl_slist *h[2];
@@ -1779,6 +1690,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
struct Curl_easy *data = conn->data;
int i;
+#ifndef CURL_DISABLE_PROXY
enum proxy_use proxy;
if(is_connect)
@@ -1805,6 +1717,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
h[0] = data->set.headers;
break;
}
+#else
+ (void)is_connect;
+ h[0] = data->set.headers;
+#endif
/* loop through one or two lists */
for(i = 0; i < numlists; i++) {
@@ -1832,7 +1748,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
/* copy the source */
semicolonp = strdup(headers->data);
if(!semicolonp) {
- Curl_add_buffer_free(&req_buffer);
+ Curl_dyn_free(req);
return CURLE_OUT_OF_MEMORY;
}
/* put a colon where the semicolon is */
@@ -1856,16 +1772,16 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
CURLcode result = CURLE_OK;
char *compare = semicolonp ? semicolonp : headers->data;
- if(conn->allocptr.host &&
+ if(data->state.aptr.host &&
/* a Host: header was sent already, don't pass on any custom Host:
header as that will produce *two* in the same request! */
checkprefix("Host:", compare))
;
- else if(data->set.httpreq == HTTPREQ_POST_FORM &&
+ else if(data->state.httpreq == HTTPREQ_POST_FORM &&
/* this header (extended by formdata.c) is sent later */
checkprefix("Content-Type:", compare))
;
- else if(data->set.httpreq == HTTPREQ_POST_MIME &&
+ else if(data->state.httpreq == HTTPREQ_POST_MIME &&
/* this header is sent later */
checkprefix("Content-Type:", compare))
;
@@ -1874,7 +1790,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
we will force length zero then */
checkprefix("Content-Length:", compare))
;
- else if(conn->allocptr.te &&
+ else if(data->state.aptr.te &&
/* when asking for Transfer-Encoding, don't pass on a custom
Connection: */
checkprefix("Connection:", compare))
@@ -1893,7 +1809,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
!strcasecompare(data->state.first_host, conn->host.name)))
;
else {
- result = Curl_add_bufferf(&req_buffer, "%s\r\n", compare);
+ result = Curl_dyn_addf(req, "%s\r\n", compare);
}
if(semicolonp)
free(semicolonp);
@@ -1910,7 +1826,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
#ifndef CURL_DISABLE_PARSEDATE
CURLcode Curl_add_timecondition(const struct connectdata *conn,
- Curl_send_buffer *req_buffer)
+ struct dynbuf *req)
{
struct Curl_easy *data = conn->data;
const struct tm *tm;
@@ -1969,17 +1885,17 @@ CURLcode Curl_add_timecondition(const struct connectdata *conn,
tm->tm_min,
tm->tm_sec);
- result = Curl_add_buffer(&req_buffer, datestr, strlen(datestr));
+ result = Curl_dyn_add(req, datestr);
return result;
}
#else
/* disabled */
CURLcode Curl_add_timecondition(const struct connectdata *conn,
- Curl_send_buffer *req_buffer)
+ struct dynbuf *req)
{
(void)conn;
- (void)req_buffer;
+ (void)req;
return CURLE_OK;
}
#endif
@@ -2002,13 +1918,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
const char *te = ""; /* transfer-encoding */
const char *ptr;
const char *request;
- Curl_HttpReq httpreq = data->set.httpreq;
+ Curl_HttpReq httpreq = data->state.httpreq;
#if !defined(CURL_DISABLE_COOKIES)
char *addcookies = NULL;
#endif
curl_off_t included_body = 0;
const char *httpstring;
- Curl_send_buffer *req_buffer;
+ struct dynbuf req;
curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
char *altused = NULL;
@@ -2036,13 +1952,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
#ifdef USE_NGHTTP2
if(conn->data->set.httpversion ==
CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
/* We don't support HTTP/2 proxies yet. Also it's debatable
whether or not this setting should apply to HTTP/2 proxies. */
infof(data, "Ignoring HTTP/2 prior knowledge due to proxy\n");
break;
}
-
+#endif
DEBUGF(infof(data, "HTTP/2 over clean TCP\n"));
conn->httpversion = 20;
@@ -2116,8 +2033,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
with the user-agent string specified, we erase the previously made string
here. */
if(Curl_checkheaders(conn, "User-Agent")) {
- free(conn->allocptr.uagent);
- conn->allocptr.uagent = NULL;
+ free(data->state.aptr.uagent);
+ data->state.aptr.uagent = NULL;
}
/* setup the authentication headers */
@@ -2145,14 +2062,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
else
conn->bits.authneg = FALSE;
- Curl_safefree(conn->allocptr.ref);
+ Curl_safefree(data->state.aptr.ref);
if(data->change.referer && !Curl_checkheaders(conn, "Referer")) {
- conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
- if(!conn->allocptr.ref)
+ data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ if(!data->state.aptr.ref)
return CURLE_OUT_OF_MEMORY;
}
else
- conn->allocptr.ref = NULL;
+ data->state.aptr.ref = NULL;
#if !defined(CURL_DISABLE_COOKIES)
if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie"))
@@ -2161,15 +2078,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(!Curl_checkheaders(conn, "Accept-Encoding") &&
data->set.str[STRING_ENCODING]) {
- Curl_safefree(conn->allocptr.accept_encoding);
- conn->allocptr.accept_encoding =
+ Curl_safefree(data->state.aptr.accept_encoding);
+ data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
- if(!conn->allocptr.accept_encoding)
+ if(!data->state.aptr.accept_encoding)
return CURLE_OUT_OF_MEMORY;
}
else {
- Curl_safefree(conn->allocptr.accept_encoding);
- conn->allocptr.accept_encoding = NULL;
+ Curl_safefree(data->state.aptr.accept_encoding);
+ data->state.aptr.accept_encoding = NULL;
}
#ifdef HAVE_LIBZ
@@ -2185,7 +2102,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
char *cptr = Curl_checkheaders(conn, "Connection");
#define TE_HEADER "TE: gzip\r\n"
- Curl_safefree(conn->allocptr.te);
+ Curl_safefree(data->state.aptr.te);
if(cptr) {
cptr = Curl_copy_header_value(cptr);
@@ -2194,11 +2111,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
/* Create the (updated) Connection: header */
- conn->allocptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
+ data->state.aptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER,
cptr ? cptr : "", (cptr && *cptr) ? ", ":"");
free(cptr);
- if(!conn->allocptr.te)
+ if(!data->state.aptr.te)
return CURLE_OUT_OF_MEMORY;
}
#endif
@@ -2281,7 +2198,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
te = "Transfer-Encoding: chunked\r\n";
}
- Curl_safefree(conn->allocptr.host);
+ Curl_safefree(data->state.aptr.host);
ptr = Curl_checkheaders(conn, "Host");
if(ptr && (!data->state.this_is_a_follow ||
@@ -2316,19 +2233,19 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(colon)
*colon = 0; /* The host must not include an embedded port number */
}
- Curl_safefree(conn->allocptr.cookiehost);
- conn->allocptr.cookiehost = cookiehost;
+ Curl_safefree(data->state.aptr.cookiehost);
+ data->state.aptr.cookiehost = cookiehost;
}
#endif
if(strcmp("Host:", ptr)) {
- conn->allocptr.host = aprintf("Host:%s\r\n", &ptr[5]);
- if(!conn->allocptr.host)
+ data->state.aptr.host = aprintf("Host:%s\r\n", &ptr[5]);
+ if(!data->state.aptr.host)
return CURLE_OUT_OF_MEMORY;
}
else
/* when clearing the header */
- conn->allocptr.host = NULL;
+ data->state.aptr.host = NULL;
}
else {
/* When building Host: headers, we must put the host name within
@@ -2340,18 +2257,18 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
(conn->remote_port == PORT_HTTP)) )
/* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
the port number in the host string */
- conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
+ data->state.aptr.host = aprintf("Host: %s%s%s\r\n",
conn->bits.ipv6_ip?"[":"",
host,
conn->bits.ipv6_ip?"]":"");
else
- conn->allocptr.host = aprintf("Host: %s%s%s:%d\r\n",
+ data->state.aptr.host = aprintf("Host: %s%s%s:%d\r\n",
conn->bits.ipv6_ip?"[":"",
host,
conn->bits.ipv6_ip?"]":"",
conn->remote_port);
- if(!conn->allocptr.host)
+ if(!data->state.aptr.host)
/* without Host: we can't make a nice request */
return CURLE_OUT_OF_MEMORY;
}
@@ -2432,7 +2349,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
data->set.prefer_ascii ? 'a' : 'i');
}
}
- if(conn->bits.user_passwd && !conn->bits.userpwd_in_url)
+ if(conn->bits.user_passwd)
paste_ftp_userpwd = TRUE;
}
}
@@ -2522,21 +2439,21 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
!Curl_checkheaders(conn, "Range")) {
/* if a line like this was already allocated, free the previous one */
- free(conn->allocptr.rangeline);
- conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
+ free(data->state.aptr.rangeline);
+ data->state.aptr.rangeline = aprintf("Range: bytes=%s\r\n",
data->state.range);
}
else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) &&
!Curl_checkheaders(conn, "Content-Range")) {
/* if a line like this was already allocated, free the previous one */
- free(conn->allocptr.rangeline);
+ free(data->state.aptr.rangeline);
if(data->set.set_resume_from < 0) {
/* Upload resume was asked for, but we don't know the size of the
remote part so we tell the server (and act accordingly) that we
upload the whole file (again) */
- conn->allocptr.rangeline =
+ data->state.aptr.rangeline =
aprintf("Content-Range: bytes 0-%" CURL_FORMAT_CURL_OFF_T
"/%" CURL_FORMAT_CURL_OFF_T "\r\n",
data->state.infilesize - 1, data->state.infilesize);
@@ -2546,7 +2463,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* This is because "resume" was selected */
curl_off_t total_expected_size =
data->state.resume_from + data->state.infilesize;
- conn->allocptr.rangeline =
+ data->state.aptr.rangeline =
aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T
"/%" CURL_FORMAT_CURL_OFF_T "\r\n",
data->state.range, total_expected_size-1,
@@ -2555,11 +2472,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
else {
/* Range was selected and then we just pass the incoming range and
append total size */
- conn->allocptr.rangeline =
+ data->state.aptr.rangeline =
aprintf("Content-Range: bytes %s/%" CURL_FORMAT_CURL_OFF_T "\r\n",
data->state.range, data->state.infilesize);
}
- if(!conn->allocptr.rangeline)
+ if(!data->state.aptr.rangeline)
return CURLE_OUT_OF_MEMORY;
}
}
@@ -2567,14 +2484,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
httpstring = get_http_string(data, conn);
/* initialize a dynamic send-buffer */
- req_buffer = Curl_add_buffer_init();
-
- if(!req_buffer)
- return CURLE_OUT_OF_MEMORY;
+ Curl_dyn_init(&req, DYN_HTTP_REQUEST);
/* add the main request stuff */
/* GET/HEAD/POST/PUT */
- result = Curl_add_bufferf(&req_buffer, "%s ", request);
+ result = Curl_dyn_addf(&req, "%s ", request);
if(result)
return result;
@@ -2587,21 +2501,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* url */
if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
char *url = data->set.str[STRING_TEMP_URL];
- result = Curl_add_buffer(&req_buffer, url, strlen(url));
+ result = Curl_dyn_add(&req, url);
Curl_safefree(data->set.str[STRING_TEMP_URL]);
}
else
#endif
if(paste_ftp_userpwd)
- result = Curl_add_bufferf(&req_buffer, "ftp://%s:%s@%s",
- conn->user, conn->passwd,
- path + sizeof("ftp://") - 1);
+ result = Curl_dyn_addf(&req, "ftp://%s:%s@%s", conn->user, conn->passwd,
+ path + sizeof("ftp://") - 1);
else {
- result = Curl_add_buffer(&req_buffer, path, strlen(path));
+ result = Curl_dyn_add(&req, path);
if(result)
return result;
if(query)
- result = Curl_add_bufferf(&req_buffer, "?%s", query);
+ result = Curl_dyn_addf(&req, "?%s", query);
}
if(result)
return result;
@@ -2611,60 +2524,64 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
altused = aprintf("Alt-Used: %s:%d\r\n",
conn->conn_to_host.name, conn->conn_to_port);
if(!altused) {
- Curl_add_buffer_free(&req_buffer);
+ Curl_dyn_free(&req);
return CURLE_OUT_OF_MEMORY;
}
}
#endif
result =
- Curl_add_bufferf(&req_buffer,
- "%s" /* ftp typecode (;type=x) */
- " 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 */
-
- ftp_typecode,
- httpstring,
- (conn->allocptr.host?conn->allocptr.host:""),
- conn->allocptr.proxyuserpwd?
- conn->allocptr.proxyuserpwd:"",
- conn->allocptr.userpwd?conn->allocptr.userpwd:"",
- (data->state.use_range && conn->allocptr.rangeline)?
- conn->allocptr.rangeline:"",
- (data->set.str[STRING_USERAGENT] &&
- *data->set.str[STRING_USERAGENT] &&
- conn->allocptr.uagent)?
- conn->allocptr.uagent:"",
- http->p_accept?http->p_accept:"",
- conn->allocptr.te?conn->allocptr.te:"",
- (data->set.str[STRING_ENCODING] &&
- *data->set.str[STRING_ENCODING] &&
- conn->allocptr.accept_encoding)?
- conn->allocptr.accept_encoding:"",
- (data->change.referer && conn->allocptr.ref)?
- conn->allocptr.ref:"" /* Referer: <data> */,
- (conn->bits.httpproxy &&
- !conn->bits.tunnel_proxy &&
- !Curl_checkProxyheaders(conn, "Proxy-Connection"))?
- "Proxy-Connection: Keep-Alive\r\n":"",
- te,
- altused ? altused : ""
+ Curl_dyn_addf(&req,
+ "%s" /* ftp typecode (;type=x) */
+ " 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 */
+
+ ftp_typecode,
+ httpstring,
+ (data->state.aptr.host?data->state.aptr.host:""),
+ data->state.aptr.proxyuserpwd?
+ data->state.aptr.proxyuserpwd:"",
+ 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:"",
+ http->p_accept?http->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->change.referer && data->state.aptr.ref)?
+ data->state.aptr.ref:"" /* Referer: <data> */,
+#ifndef CURL_DISABLE_PROXY
+ (conn->bits.httpproxy &&
+ !conn->bits.tunnel_proxy &&
+ !Curl_checkProxyheaders(conn, "Proxy-Connection"))?
+ "Proxy-Connection: Keep-Alive\r\n":"",
+#else
+ "",
+#endif
+ te,
+ altused ? altused : ""
);
/* clear userpwd and proxyuserpwd to avoid re-using old credentials
* from re-used connections */
- Curl_safefree(conn->allocptr.userpwd);
- Curl_safefree(conn->allocptr.proxyuserpwd);
+ Curl_safefree(data->state.aptr.userpwd);
+ Curl_safefree(data->state.aptr.proxyuserpwd);
free(altused);
if(result)
@@ -2675,7 +2592,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
(data->set.httpversion == CURL_HTTP_VERSION_2)) {
/* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
over SSL */
- result = Curl_http2_request_upgrade(req_buffer, conn);
+ result = Curl_http2_request_upgrade(&req, conn);
if(result)
return result;
}
@@ -2688,8 +2605,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(data->cookies && data->state.cookie_engine) {
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
co = Curl_cookie_getlist(data->cookies,
- conn->allocptr.cookiehost?
- conn->allocptr.cookiehost:host,
+ data->state.aptr.cookiehost?
+ data->state.aptr.cookiehost:host,
data->state.up.path,
(conn->handler->protocol&CURLPROTO_HTTPS)?
TRUE:FALSE);
@@ -2701,13 +2618,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
while(co) {
if(co->value) {
if(0 == count) {
- result = Curl_add_bufferf(&req_buffer, "Cookie: ");
+ result = Curl_dyn_add(&req, "Cookie: ");
if(result)
break;
}
- result = Curl_add_bufferf(&req_buffer,
- "%s%s=%s", count?"; ":"",
- co->name, co->value);
+ result = Curl_dyn_addf(&req, "%s%s=%s", count?"; ":"",
+ co->name, co->value);
if(result)
break;
count++;
@@ -2718,26 +2634,25 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
if(addcookies && !result) {
if(!count)
- result = Curl_add_bufferf(&req_buffer, "Cookie: ");
+ result = Curl_dyn_add(&req, "Cookie: ");
if(!result) {
- result = Curl_add_bufferf(&req_buffer, "%s%s", count?"; ":"",
- addcookies);
+ result = Curl_dyn_addf(&req, "%s%s", count?"; ":"", addcookies);
count++;
}
}
if(count && !result)
- result = Curl_add_buffer(&req_buffer, "\r\n", 2);
+ result = Curl_dyn_add(&req, "\r\n");
if(result)
return result;
}
#endif
- result = Curl_add_timecondition(conn, req_buffer);
+ result = Curl_add_timecondition(conn, &req);
if(result)
return result;
- result = Curl_add_custom_headers(conn, FALSE, req_buffer);
+ result = Curl_add_custom_headers(conn, FALSE, &req);
if(result)
return result;
@@ -2760,20 +2675,20 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if((postsize != -1) && !data->req.upload_chunky &&
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
/* only add Content-Length if not uploading chunked */
- result = Curl_add_bufferf(&req_buffer,
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T
- "\r\n", postsize);
+ result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", postsize);
if(result)
return result;
}
if(postsize != 0) {
- result = expect100(data, conn, req_buffer);
+ result = expect100(data, conn, &req);
if(result)
return result;
}
- result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers */
+ /* end of headers */
+ result = Curl_dyn_add(&req, "\r\n");
if(result)
return result;
@@ -2781,8 +2696,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_pgrsSetUploadSize(data, postsize);
/* this sends the buffer and frees all the buffer resources */
- result = Curl_add_buffer_send(&req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
+ result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
+ FIRSTSOCKET);
if(result)
failf(data, "Failed sending PUT request");
else
@@ -2798,12 +2713,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* This is form posting using mime data. */
if(conn->bits.authneg) {
/* nothing to post! */
- result = Curl_add_bufferf(&req_buffer, "Content-Length: 0\r\n\r\n");
+ result = Curl_dyn_add(&req, "Content-Length: 0\r\n\r\n");
if(result)
return result;
- result = Curl_add_buffer_send(&req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
+ result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
+ FIRSTSOCKET);
if(result)
failf(data, "Failed sending POST request");
else
@@ -2821,9 +2736,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
/* we allow replacing this header if not during auth negotiation,
although it isn't very wise to actually set your own */
- result = Curl_add_bufferf(&req_buffer,
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T
- "\r\n", postsize);
+ result = Curl_dyn_addf(&req,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", postsize);
if(result)
return result;
}
@@ -2834,7 +2749,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
struct curl_slist *hdr;
for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) {
- result = Curl_add_bufferf(&req_buffer, "%s\r\n", hdr->data);
+ result = Curl_dyn_addf(&req, "%s\r\n", hdr->data);
if(result)
return result;
}
@@ -2851,7 +2766,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_compareheader(ptr, "Expect:", "100-continue");
}
else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) {
- result = expect100(data, conn, req_buffer);
+ result = expect100(data, conn, &req);
if(result)
return result;
}
@@ -2859,7 +2774,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
data->state.expect100header = FALSE;
/* make the request end in a true CRLF */
- result = Curl_add_buffer(&req_buffer, "\r\n", 2);
+ result = Curl_dyn_add(&req, "\r\n");
if(result)
return result;
@@ -2872,8 +2787,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
http->sending = HTTPSEND_BODY;
/* this sends the buffer and frees all the buffer resources */
- result = Curl_add_buffer_send(&req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
+ result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
+ FIRSTSOCKET);
if(result)
failf(data, "Failed sending POST request");
else
@@ -2901,17 +2816,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
(conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) {
/* we allow replacing this header if not during auth negotiation,
although it isn't very wise to actually set your own */
- result = Curl_add_bufferf(&req_buffer,
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T
- "\r\n", postsize);
+ result = Curl_dyn_addf(&req, "Content-Length: %" CURL_FORMAT_CURL_OFF_T
+ "\r\n", postsize);
if(result)
return result;
}
if(!Curl_checkheaders(conn, "Content-Type")) {
- result = Curl_add_bufferf(&req_buffer,
- "Content-Type: application/"
- "x-www-form-urlencoded\r\n");
+ result = Curl_dyn_add(&req, "Content-Type: application/"
+ "x-www-form-urlencoded\r\n");
if(result)
return result;
}
@@ -2926,7 +2839,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_compareheader(ptr, "Expect:", "100-continue");
}
else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) {
- result = expect100(data, conn, req_buffer);
+ result = expect100(data, conn, &req);
if(result)
return result;
}
@@ -2947,31 +2860,32 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
is no magic limit but only set to prevent really huge POSTs to
get the data duplicated with malloc() and family. */
- result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
+ /* end of headers! */
+ result = Curl_dyn_add(&req, "\r\n");
if(result)
return result;
if(!data->req.upload_chunky) {
/* We're not sending it 'chunked', append it to the request
already now to reduce the number if send() calls */
- result = Curl_add_buffer(&req_buffer, data->set.postfields,
- (size_t)postsize);
+ result = Curl_dyn_addn(&req, data->set.postfields,
+ (size_t)postsize);
included_body = postsize;
}
else {
if(postsize) {
/* Append the POST data chunky-style */
- result = Curl_add_bufferf(&req_buffer, "%x\r\n", (int)postsize);
+ result = Curl_dyn_addf(&req, "%x\r\n", (int)postsize);
if(!result) {
- result = Curl_add_buffer(&req_buffer, data->set.postfields,
- (size_t)postsize);
+ result = Curl_dyn_addn(&req, data->set.postfields,
+ (size_t)postsize);
if(!result)
- result = Curl_add_buffer(&req_buffer, "\r\n", 2);
+ result = Curl_dyn_add(&req, "\r\n");
included_body = postsize + 2;
}
}
if(!result)
- result = Curl_add_buffer(&req_buffer, "\x30\x0d\x0a\x0d\x0a", 5);
+ result = Curl_dyn_add(&req, "\x30\x0d\x0a\x0d\x0a");
/* 0 CR LF CR LF */
included_body += 5;
}
@@ -2993,21 +2907,22 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
- result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
+ /* end of headers! */
+ result = Curl_dyn_add(&req, "\r\n");
if(result)
return result;
}
}
else {
- result = Curl_add_buffer(&req_buffer, "\r\n", 2); /* end of headers! */
+ /* end of headers! */
+ result = Curl_dyn_add(&req, "\r\n");
if(result)
return result;
if(data->req.upload_chunky && conn->bits.authneg) {
/* Chunky upload is selected and we're negotiating auth still, send
end-of-data only */
- result = Curl_add_buffer(&req_buffer,
- "\x30\x0d\x0a\x0d\x0a", 5);
+ result = Curl_dyn_add(&req, (char *)"\x30\x0d\x0a\x0d\x0a");
/* 0 CR LF CR LF */
if(result)
return result;
@@ -3027,8 +2942,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
}
/* issue the request */
- result = Curl_add_buffer_send(&req_buffer, conn, &data->info.request_size,
- (size_t)included_body, FIRSTSOCKET);
+ result = Curl_buffer_send(&req, conn, &data->info.request_size,
+ (size_t)included_body, FIRSTSOCKET);
if(result)
failf(data, "Failed sending HTTP POST request");
@@ -3038,13 +2953,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
break;
default:
- result = Curl_add_buffer(&req_buffer, "\r\n", 2);
+ result = Curl_dyn_add(&req, "\r\n");
if(result)
return result;
/* issue the request */
- result = Curl_add_buffer_send(&req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
+ result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
+ FIRSTSOCKET);
if(result)
failf(data, "Failed sending HTTP request");
@@ -3189,55 +3104,10 @@ checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
return checkhttpprefix(data, s, len);
}
-/*
- * header_append() copies a chunk of data to the end of the already received
- * header. We make sure that the full string fit in the allocated header
- * buffer, or else we enlarge it.
- */
-static CURLcode header_append(struct Curl_easy *data,
- struct SingleRequest *k,
- size_t length)
-{
- /* length is at most the size of a full read buffer, for which the upper
- bound is CURL_MAX_READ_SIZE. There is thus no chance of overflow in this
- calculation. */
- size_t newsize = k->hbuflen + length;
- if(newsize > CURL_MAX_HTTP_HEADER) {
- /* The reason to have a max limit for this is to avoid the risk of a bad
- server feeding libcurl with a never-ending header that will cause
- reallocs infinitely */
- failf(data, "Rejected %zu bytes header (max is %d)!", newsize,
- CURL_MAX_HTTP_HEADER);
- return CURLE_OUT_OF_MEMORY;
- }
- if(newsize >= data->state.headersize) {
- /* We enlarge the header buffer as it is too small */
- char *newbuff;
- size_t hbufp_index;
-
- newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2);
- hbufp_index = k->hbufp - data->state.headerbuff;
- newbuff = realloc(data->state.headerbuff, newsize);
- if(!newbuff) {
- failf(data, "Failed to alloc memory for big header!");
- return CURLE_OUT_OF_MEMORY;
- }
- data->state.headersize = newsize;
- data->state.headerbuff = newbuff;
- k->hbufp = data->state.headerbuff + hbufp_index;
- }
- memcpy(k->hbufp, k->str_start, length);
- k->hbufp += length;
- k->hbuflen += length;
- *k->hbufp = 0;
-
- return CURLE_OK;
-}
-
static void print_http_error(struct Curl_easy *data)
{
struct SingleRequest *k = &data->req;
- char *beg = k->p;
+ char *beg = Curl_dyn_ptr(&data->state.headerb);
/* make sure that data->req.p points to the HTTP status line */
if(!strncmp(beg, "HTTP", 4)) {
@@ -3275,14 +3145,17 @@ static void print_http_error(struct Curl_easy *data)
* Read any HTTP header lines from the server and pass them to the client app.
*/
CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
- struct connectdata *conn,
- ssize_t *nread,
- bool *stop_reading)
+ struct connectdata *conn,
+ ssize_t *nread,
+ bool *stop_reading)
{
CURLcode result;
struct SingleRequest *k = &data->req;
ssize_t onread = *nread;
char *ostr = k->str;
+ char *headp;
+ char *str_start;
+ char *end_ptr;
/* header line within buffer loop */
do {
@@ -3291,22 +3164,25 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
int writetype;
/* str_start is start of line within buf */
- k->str_start = k->str;
+ str_start = k->str;
/* data is in network encoding so use 0x0a instead of '\n' */
- k->end_ptr = memchr(k->str_start, 0x0a, *nread);
+ end_ptr = memchr(str_start, 0x0a, *nread);
- if(!k->end_ptr) {
+ if(!end_ptr) {
/* Not a complete header line within buffer, append the data to
the end of the headerbuff. */
- result = header_append(data, k, *nread);
+ result = Curl_dyn_addn(&data->state.headerb, str_start, *nread);
if(result)
return result;
if(!k->headerline) {
/* check if this looks like a protocol header */
- statusline st = checkprotoprefix(data, conn, data->state.headerbuff,
- k->hbuflen);
+ statusline st =
+ checkprotoprefix(data, conn,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
+
if(st == STATUS_BAD) {
/* this is not the beginning of a protocol first header line */
k->header = FALSE;
@@ -3324,28 +3200,26 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
/* decrease the size of the remaining (supposed) header line */
- rest_length = (k->end_ptr - k->str) + 1;
+ rest_length = (end_ptr - k->str) + 1;
*nread -= (ssize_t)rest_length;
- k->str = k->end_ptr + 1; /* move past new line */
+ k->str = end_ptr + 1; /* move past new line */
- full_length = k->str - k->str_start;
+ full_length = k->str - str_start;
- result = header_append(data, k, full_length);
+ result = Curl_dyn_addn(&data->state.headerb, str_start, full_length);
if(result)
return result;
- k->end_ptr = k->hbufp;
- k->p = data->state.headerbuff;
-
/****
- * We now have a FULL header line that p points to
+ * We now have a FULL header line in 'headerb'.
*****/
if(!k->headerline) {
/* the first read header */
- statusline st = checkprotoprefix(data, conn, data->state.headerbuff,
- k->hbuflen);
+ statusline st = checkprotoprefix(data, conn,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
if(st == STATUS_BAD) {
streamclose(conn, "bad HTTP: No end-of-message indicator");
/* this is not the beginning of a protocol first header line */
@@ -3368,26 +3242,27 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
- /* headers are in network encoding so
- use 0x0a and 0x0d instead of '\n' and '\r' */
- if((0x0a == *k->p) || (0x0d == *k->p)) {
+ /* headers are in network encoding so use 0x0a and 0x0d instead of '\n'
+ and '\r' */
+ headp = Curl_dyn_ptr(&data->state.headerb);
+ if((0x0a == *headp) || (0x0d == *headp)) {
size_t headerlen;
/* Zero-length header line means end of headers! */
#ifdef CURL_DOES_CONVERSIONS
- if(0x0d == *k->p) {
- *k->p = '\r'; /* replace with CR in host encoding */
- k->p++; /* pass the CR byte */
+ if(0x0d == *headp) {
+ *headp = '\r'; /* replace with CR in host encoding */
+ headp++; /* pass the CR byte */
}
- if(0x0a == *k->p) {
- *k->p = '\n'; /* replace with LF in host encoding */
- k->p++; /* pass the LF byte */
+ if(0x0a == *headp) {
+ *headp = '\n'; /* replace with LF in host encoding */
+ headp++; /* pass the LF byte */
}
#else
- if('\r' == *k->p)
- k->p++; /* pass the \r byte */
- if('\n' == *k->p)
- k->p++; /* pass the \n byte */
+ if('\r' == *headp)
+ headp++; /* pass the \r byte */
+ if('\n' == *headp)
+ headp++; /* pass the \n byte */
#endif /* CURL_DOES_CONVERSIONS */
if(100 <= k->httpcode && 199 >= k->httpcode) {
@@ -3448,7 +3323,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if((k->size == -1) && !k->chunk && !conn->bits.close &&
(conn->httpversion == 11) &&
!(conn->handler->protocol & CURLPROTO_RTSP) &&
- data->set.httpreq != HTTPREQ_HEAD) {
+ data->state.httpreq != HTTPREQ_HEAD) {
/* On HTTP 1.1, when connection is not to get closed, but no
Content-Length nor Transfer-Encoding chunked have been
received, according to RFC2616 section 4.4 point 5, we
@@ -3506,10 +3381,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(data->set.include_header)
writetype |= CLIENTWRITE_BODY;
- headerlen = k->p - data->state.headerbuff;
-
+ headerlen = Curl_dyn_len(&data->state.headerb);
result = Curl_client_write(conn, writetype,
- data->state.headerbuff,
+ Curl_dyn_ptr(&data->state.headerb),
headerlen);
if(result)
return result;
@@ -3544,7 +3418,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* continue sending even if it gets discarded
*/
- switch(data->set.httpreq) {
+ switch(data->state.httpreq) {
case HTTPREQ_PUT:
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
@@ -3662,14 +3536,12 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(data->set.verbose)
Curl_debug(data, CURLINFO_HEADER_IN,
- k->str_start, headerlen);
+ str_start, headerlen);
break; /* exit header line loop */
}
- /* We continue reading headers, so reset the line-based
- header parsing variables hbufp && hbuflen */
- k->hbufp = data->state.headerbuff;
- k->hbuflen = 0;
+ /* We continue reading headers, reset the line-based header */
+ Curl_dyn_reset(&data->state.headerb);
continue;
}
@@ -3688,12 +3560,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
#define SCRATCHSIZE 21
CURLcode res;
char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */
- /* We can't really convert this yet because we
- don't know if it's the 1st header line or the body.
- So we do a partial conversion into a scratch area,
- leaving the data at k->p as-is.
+ /* We can't really convert this yet because we don't know if it's the
+ 1st header line or the body. So we do a partial conversion into a
+ scratch area, leaving the data at 'headp' as-is.
*/
- strncpy(&scratch[0], k->p, SCRATCHSIZE);
+ strncpy(&scratch[0], headp, SCRATCHSIZE);
scratch[SCRATCHSIZE] = 0; /* null terminate */
res = Curl_convert_from_network(data,
&scratch[0],
@@ -3702,7 +3573,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* Curl_convert_from_network calls failf if unsuccessful */
return res;
#else
-#define HEADER1 k->p /* no conversion needed, just use k->p */
+#define HEADER1 headp /* no conversion needed, just use headp */
#endif /* CURL_DOES_CONVERSIONS */
if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
@@ -3753,7 +3624,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
compare header line against list of aliases
*/
if(!nc) {
- if(checkhttpprefix(data, k->p, k->hbuflen) == STATUS_DONE) {
+ statusline check =
+ checkhttpprefix(data,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
+ if(check == STATUS_DONE) {
nc = 1;
k->httpcode = 200;
conn->httpversion = 10;
@@ -3799,15 +3674,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* depending on how authentication is working. Other codes
* are definitely errors, so give up here.
*/
- if(data->state.resume_from && data->set.httpreq == HTTPREQ_GET &&
+ if(data->state.resume_from && data->state.httpreq == HTTPREQ_GET &&
k->httpcode == 416) {
/* "Requested Range Not Satisfiable", just proceed and
pretend this is no error */
k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
}
else if(data->set.http_fail_on_error && (k->httpcode >= 400) &&
- ((k->httpcode != 401) || !conn->bits.user_passwd) &&
- ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
+ ((k->httpcode != 401) || !conn->bits.user_passwd)
+#ifndef CURL_DISABLE_PROXY
+ && ((k->httpcode != 407) || !conn->bits.proxy_user_passwd)
+#endif
+ ) {
/* serious error, go home! */
print_http_error(data);
return CURLE_HTTP_RETURNED_ERROR;
@@ -3823,9 +3701,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
else if(conn->httpversion == 20 ||
(k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n"));
-
- /* HTTP/2 cannot blacklist multiplexing since it is a core
- functionality of the protocol */
+ /* HTTP/2 cannot avoid multiplexing since it is a core functionality
+ of the protocol */
conn->bundle->multiuse = BUNDLE_MULTIPLEX;
}
else if(conn->httpversion >= 11 &&
@@ -3865,16 +3742,16 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
- result = Curl_convert_from_network(data, k->p, strlen(k->p));
+ result = Curl_convert_from_network(data, headp, strlen(headp));
/* Curl_convert_from_network calls failf if unsuccessful */
if(result)
return result;
/* Check for Content-Length: header lines to get size */
if(!k->http_bodyless &&
- !data->set.ignorecl && checkprefix("Content-Length:", k->p)) {
+ !data->set.ignorecl && checkprefix("Content-Length:", headp)) {
curl_off_t contentlength;
- CURLofft offt = curlx_strtoofft(k->p + 15, NULL, 10, &contentlength);
+ CURLofft offt = curlx_strtoofft(headp + 15, NULL, 10, &contentlength);
if(offt == CURL_OFFT_OK) {
if(data->set.max_filesize &&
@@ -3905,8 +3782,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
}
/* check for Content-Type: header lines to get the MIME-type */
- else if(checkprefix("Content-Type:", k->p)) {
- char *contenttype = Curl_copy_header_value(k->p);
+ else if(checkprefix("Content-Type:", headp)) {
+ char *contenttype = Curl_copy_header_value(headp);
if(!contenttype)
return CURLE_OUT_OF_MEMORY;
if(!*contenttype)
@@ -3917,10 +3794,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
data->info.contenttype = contenttype;
}
}
+#ifndef CURL_DISABLE_PROXY
else if((conn->httpversion == 10) &&
conn->bits.httpproxy &&
- Curl_compareheader(k->p,
- "Proxy-Connection:", "keep-alive")) {
+ Curl_compareheader(headp, "Proxy-Connection:", "keep-alive")) {
/*
* When a HTTP/1.0 reply comes when using a proxy, the
* 'Proxy-Connection: keep-alive' line tells us the
@@ -3932,8 +3809,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
else if((conn->httpversion == 11) &&
conn->bits.httpproxy &&
- Curl_compareheader(k->p,
- "Proxy-Connection:", "close")) {
+ Curl_compareheader(headp, "Proxy-Connection:", "close")) {
/*
* We get a HTTP/1.1 response from a proxy and it says it'll
* close down after this transfer.
@@ -3941,8 +3817,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
connclose(conn, "Proxy-Connection: asked to close after done");
infof(data, "HTTP/1.1 proxy connection set close!\n");
}
+#endif
else if((conn->httpversion == 10) &&
- Curl_compareheader(k->p, "Connection:", "keep-alive")) {
+ Curl_compareheader(headp, "Connection:", "keep-alive")) {
/*
* A HTTP/1.0 reply with the 'Connection: keep-alive' line
* tells us the connection will be kept alive for our
@@ -3952,7 +3829,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
connkeep(conn, "Connection keep-alive");
infof(data, "HTTP/1.0 connection set to keep alive!\n");
}
- else if(Curl_compareheader(k->p, "Connection:", "close")) {
+ else if(Curl_compareheader(headp, "Connection:", "close")) {
/*
* [RFC 2616, section 8.1.2.1]
* "Connection: close" is HTTP/1.1 language and means that
@@ -3961,7 +3838,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
*/
streamclose(conn, "Connection: close used");
}
- else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", k->p)) {
+ else if(!k->http_bodyless && checkprefix("Transfer-Encoding:", headp)) {
/* One or more encodings. We check for chunked and/or a compression
algorithm. */
/*
@@ -3973,11 +3850,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* of chunks, and a chunk-data set to zero signals the
* end-of-chunks. */
- result = Curl_build_unencoding_stack(conn, k->p + 18, TRUE);
+ result = Curl_build_unencoding_stack(conn, headp + 18, TRUE);
if(result)
return result;
}
- else if(!k->http_bodyless && checkprefix("Content-Encoding:", k->p) &&
+ else if(!k->http_bodyless && checkprefix("Content-Encoding:", headp) &&
data->set.str[STRING_ENCODING]) {
/*
* Process Content-Encoding. Look for the values: identity,
@@ -3986,24 +3863,24 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
* 2616). zlib cannot handle compress. However, errors are
* handled further down when the response body is processed
*/
- result = Curl_build_unencoding_stack(conn, k->p + 17, FALSE);
+ result = Curl_build_unencoding_stack(conn, headp + 17, FALSE);
if(result)
return result;
}
- else if(checkprefix("Retry-After:", k->p)) {
+ else if(checkprefix("Retry-After:", headp)) {
/* Retry-After = HTTP-date / delay-seconds */
curl_off_t retry_after = 0; /* zero for unknown or "now" */
- time_t date = Curl_getdate_capped(&k->p[12]);
+ time_t date = Curl_getdate_capped(&headp[12]);
if(-1 == date) {
/* not a date, try it as a decimal number */
- (void)curlx_strtoofft(&k->p[12], NULL, 10, &retry_after);
+ (void)curlx_strtoofft(&headp[12], NULL, 10, &retry_after);
}
else
/* convert date to number of seconds into the future */
retry_after = date - time(NULL);
data->info.retry_after = retry_after; /* store it */
}
- else if(!k->http_bodyless && checkprefix("Content-Range:", k->p)) {
+ else if(!k->http_bodyless && checkprefix("Content-Range:", headp)) {
/* Content-Range: bytes [num]-
Content-Range: bytes: [num]-
Content-Range: [num]-
@@ -4015,7 +3892,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
The forth means the requested range was unsatisfied.
*/
- char *ptr = k->p + 14;
+ char *ptr = headp + 14;
/* Move forward until first digit or asterisk */
while(*ptr && !ISDIGIT(*ptr) && *ptr != '*')
@@ -4034,34 +3911,34 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
#if !defined(CURL_DISABLE_COOKIES)
else if(data->cookies && data->state.cookie_engine &&
- checkprefix("Set-Cookie:", k->p)) {
+ checkprefix("Set-Cookie:", headp)) {
Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
CURL_LOCK_ACCESS_SINGLE);
Curl_cookie_add(data,
- data->cookies, TRUE, FALSE, k->p + 11,
+ data->cookies, TRUE, FALSE, headp + 11,
/* If there is a custom-set Host: name, use it
here, or else use real peer host name. */
- conn->allocptr.cookiehost?
- conn->allocptr.cookiehost:conn->host.name,
+ data->state.aptr.cookiehost?
+ data->state.aptr.cookiehost:conn->host.name,
data->state.up.path,
(conn->handler->protocol&CURLPROTO_HTTPS)?
TRUE:FALSE);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
#endif
- else if(!k->http_bodyless && checkprefix("Last-Modified:", k->p) &&
+ else if(!k->http_bodyless && checkprefix("Last-Modified:", headp) &&
(data->set.timecondition || data->set.get_filetime) ) {
- k->timeofdoc = Curl_getdate_capped(k->p + strlen("Last-Modified:"));
+ k->timeofdoc = Curl_getdate_capped(headp + strlen("Last-Modified:"));
if(data->set.get_filetime)
data->info.filetime = k->timeofdoc;
}
- else if((checkprefix("WWW-Authenticate:", k->p) &&
+ else if((checkprefix("WWW-Authenticate:", headp) &&
(401 == k->httpcode)) ||
- (checkprefix("Proxy-authenticate:", k->p) &&
+ (checkprefix("Proxy-authenticate:", headp) &&
(407 == k->httpcode))) {
bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
- char *auth = Curl_copy_header_value(k->p);
+ char *auth = Curl_copy_header_value(headp);
if(!auth)
return CURLE_OUT_OF_MEMORY;
@@ -4073,11 +3950,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
return result;
}
#ifdef USE_SPNEGO
- else if(checkprefix("Persistent-Auth", k->p)) {
+ else if(checkprefix("Persistent-Auth", headp)) {
struct negotiatedata *negdata = &conn->negotiate;
struct auth *authp = &data->state.authhost;
if(authp->picked == CURLAUTH_NEGOTIATE) {
- char *persistentauth = Curl_copy_header_value(k->p);
+ char *persistentauth = Curl_copy_header_value(headp);
if(!persistentauth)
return CURLE_OUT_OF_MEMORY;
negdata->noauthpersist = checkprefix("false", persistentauth)?
@@ -4090,10 +3967,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
#endif
else if((k->httpcode >= 300 && k->httpcode < 400) &&
- checkprefix("Location:", k->p) &&
+ checkprefix("Location:", headp) &&
!data->req.location) {
/* this is the URL that the server advises us to use instead */
- char *location = Curl_copy_header_value(k->p);
+ char *location = Curl_copy_header_value(headp);
if(!location)
return CURLE_OUT_OF_MEMORY;
if(!*location)
@@ -4118,7 +3995,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
#ifdef USE_ALTSVC
/* If enabled, the header is incoming and this is over HTTPS */
- else if(data->asi && checkprefix("Alt-Svc:", k->p) &&
+ else if(data->asi && checkprefix("Alt-Svc:", headp) &&
((conn->handler->flags & PROTOPT_SSL) ||
#ifdef CURLDEBUG
/* allow debug builds to circumvent the HTTPS restriction */
@@ -4130,7 +4007,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
/* the ALPN of the current request */
enum alpnid id = (conn->httpversion == 20) ? ALPN_h2 : ALPN_h1;
result = Curl_altsvc_parse(data, data->asi,
- &k->p[ strlen("Alt-Svc:") ],
+ &headp[ strlen("Alt-Svc:") ],
id, conn->host.name,
curlx_uitous(conn->remote_port));
if(result)
@@ -4138,7 +4015,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
}
#endif
else if(conn->handler->protocol & CURLPROTO_RTSP) {
- result = Curl_rtsp_parseheader(conn, k->p);
+ result = Curl_rtsp_parseheader(conn, headp);
if(result)
return result;
}
@@ -4152,18 +4029,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
writetype |= CLIENTWRITE_BODY;
if(data->set.verbose)
- Curl_debug(data, CURLINFO_HEADER_IN, k->p, (size_t)k->hbuflen);
+ Curl_debug(data, CURLINFO_HEADER_IN, headp,
+ Curl_dyn_len(&data->state.headerb));
- result = Curl_client_write(conn, writetype, k->p, k->hbuflen);
+ result = Curl_client_write(conn, writetype, headp,
+ Curl_dyn_len(&data->state.headerb));
if(result)
return result;
- data->info.header_size += (long)k->hbuflen;
- data->req.headerbytecount += (long)k->hbuflen;
+ data->info.header_size += Curl_dyn_len(&data->state.headerb);
+ data->req.headerbytecount += Curl_dyn_len(&data->state.headerb);
- /* reset hbufp pointer && hbuflen */
- k->hbufp = data->state.headerbuff;
- k->hbuflen = 0;
+ Curl_dyn_reset(&data->state.headerb);
}
while(*k->str); /* header line within buffer */
diff --git a/lib/http.h b/lib/http.h
index 4c1825f6..641bc0b9 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -44,38 +44,19 @@ char *Curl_copy_header_value(const char *header);
char *Curl_checkProxyheaders(const struct connectdata *conn,
const char *thisheader);
-/* ------------------------------------------------------------------------- */
-/*
- * The add_buffer series of functions are used to build one large memory chunk
- * from repeated function invokes. Used so that the entire HTTP request can
- * be sent in one go.
- */
-struct Curl_send_buffer {
- char *buffer;
- size_t size_max;
- size_t size_used;
-};
-typedef struct Curl_send_buffer Curl_send_buffer;
-
-Curl_send_buffer *Curl_add_buffer_init(void);
-void Curl_add_buffer_free(Curl_send_buffer **inp);
-CURLcode Curl_add_bufferf(Curl_send_buffer **inp, const char *fmt, ...)
- WARN_UNUSED_RESULT;
-CURLcode Curl_add_buffer(Curl_send_buffer **inp, const void *inptr,
- size_t size) WARN_UNUSED_RESULT;
-CURLcode Curl_add_buffer_send(Curl_send_buffer **inp,
- struct connectdata *conn,
- curl_off_t *bytes_written,
- size_t included_body_bytes,
- int socketindex);
+CURLcode Curl_buffer_send(struct dynbuf *in,
+ struct connectdata *conn,
+ curl_off_t *bytes_written,
+ size_t included_body_bytes,
+ int socketindex);
CURLcode Curl_add_timecondition(const struct connectdata *conn,
- Curl_send_buffer *buf);
+ struct dynbuf *buf);
CURLcode Curl_add_custom_headers(struct connectdata *conn,
bool is_connect,
- Curl_send_buffer *req_buffer);
+ struct dynbuf *req_buffer);
CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
- Curl_send_buffer **buffer,
+ struct dynbuf *buf,
struct Curl_easy *handle);
/* protocol-specific functions set up to be called by the main engine */
@@ -154,9 +135,9 @@ struct HTTP {
} sending;
#ifndef CURL_DISABLE_HTTP
- Curl_send_buffer *send_buffer; /* used if the request couldn't be sent in
- one chunk, points to an allocated
- send_buffer struct */
+ struct dynbuf send_buffer; /* used if the request couldn't be sent in one
+ chunk, points to an allocated send_buffer
+ struct */
#endif
#ifdef USE_NGHTTP2
/*********** for HTTP/2 we store stream-local data here *************/
@@ -164,10 +145,9 @@ struct HTTP {
bool bodystarted;
/* We store non-final and final response headers here, per-stream */
- Curl_send_buffer *header_recvbuf;
+ struct dynbuf header_recvbuf;
size_t nread_header_recvbuf; /* number of bytes in header_recvbuf fed into
upper layer */
- Curl_send_buffer *trailer_recvbuf;
int status_code; /* HTTP status code */
const uint8_t *pausedata; /* pointer to data received in on_data_chunk */
size_t pauselen; /* the number of bytes left in data */
@@ -201,9 +181,7 @@ struct HTTP {
#ifdef USE_NGHTTP3
size_t unacked_window;
struct h3out *h3out; /* per-stream buffers for upload */
- char *overflow_buf; /* excess data received during a single Curl_read */
- size_t overflow_buflen; /* amount of data currently in overflow_buf */
- size_t overflow_bufsize; /* size of the overflow_buf allocation */
+ struct dynbuf overflow; /* excess data received during a single Curl_read */
#endif
};
diff --git a/lib/http2.c b/lib/http2.c
index 93dfbdb7..6cf651f0 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -36,6 +36,7 @@
#include "connect.h"
#include "strtoofft.h"
#include "strdup.h"
+#include "dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
@@ -124,8 +125,7 @@ static int http2_getsock(struct connectdata *conn,
static void http2_stream_free(struct HTTP *http)
{
if(http) {
- Curl_add_buffer_free(&http->header_recvbuf);
- Curl_add_buffer_free(&http->trailer_recvbuf);
+ Curl_dyn_free(&http->header_recvbuf);
for(; http->push_headers_used > 0; --http->push_headers_used) {
free(http->push_headers[http->push_headers_used - 1]);
}
@@ -258,16 +258,14 @@ static unsigned int http2_conncheck(struct connectdata *check,
void Curl_http2_setup_req(struct Curl_easy *data)
{
struct HTTP *http = data->req.protop;
-
- http->nread_header_recvbuf = 0;
http->bodystarted = FALSE;
http->status_code = -1;
http->pausedata = NULL;
http->pauselen = 0;
http->closed = FALSE;
http->close_handled = FALSE;
- http->mem = data->state.buffer;
- http->len = data->set.buffer_size;
+ http->mem = NULL;
+ http->len = 0;
http->memlen = 0;
}
@@ -463,20 +461,54 @@ static struct Curl_easy *duphandle(struct Curl_easy *data)
}
else {
second->req.protop = http;
- http->header_recvbuf = Curl_add_buffer_init();
- if(!http->header_recvbuf) {
- free(http);
- (void)Curl_close(&second);
- }
- else {
- Curl_http2_setup_req(second);
- second->state.stream_weight = data->state.stream_weight;
- }
+ Curl_dyn_init(&http->header_recvbuf, DYN_H2_HEADERS);
+ Curl_http2_setup_req(second);
+ second->state.stream_weight = data->state.stream_weight;
}
}
return second;
}
+static int set_transfer_url(struct Curl_easy *data,
+ struct curl_pushheaders *hp)
+{
+ const char *v;
+ CURLU *u = curl_url();
+ CURLUcode uc;
+ char *url;
+
+ v = curl_pushheader_byname(hp, ":scheme");
+ if(v) {
+ uc = curl_url_set(u, CURLUPART_SCHEME, v, 0);
+ if(uc)
+ return 1;
+ }
+
+ v = curl_pushheader_byname(hp, ":authority");
+ if(v) {
+ uc = curl_url_set(u, CURLUPART_HOST, v, 0);
+ if(uc)
+ return 2;
+ }
+
+ v = curl_pushheader_byname(hp, ":path");
+ if(v) {
+ uc = curl_url_set(u, CURLUPART_PATH, v, 0);
+ if(uc)
+ return 3;
+ }
+
+ uc = curl_url_get(u, CURLUPART_URL, &url, 0);
+ if(uc)
+ return 4;
+ curl_url_cleanup(u);
+
+ if(data->change.url_alloc)
+ free(data->change.url);
+ data->change.url_alloc = TRUE;
+ data->change.url = url;
+ return 0;
+}
static int push_promise(struct Curl_easy *data,
struct connectdata *conn,
@@ -513,6 +545,10 @@ static int push_promise(struct Curl_easy *data,
goto fail;
}
+ rv = set_transfer_url(newhandle, &heads);
+ if(rv)
+ goto fail;
+
Curl_set_in_callback(data, true);
rv = data->multi->push_cb(data, newhandle,
stream->push_headers_used, &heads,
@@ -668,15 +704,17 @@ static int on_frame_recv(nghttp2_session *session, const nghttp2_frame *frame,
stream->status_code = -1;
}
- result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2);
+ result = Curl_dyn_add(&stream->header_recvbuf, "\r\n");
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- left = stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
+ left = Curl_dyn_len(&stream->header_recvbuf) -
+ stream->nread_header_recvbuf;
ncopy = CURLMIN(stream->len, left);
memcpy(&stream->mem[stream->memlen],
- stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
+ Curl_dyn_ptr(&stream->header_recvbuf) +
+ stream->nread_header_recvbuf,
ncopy);
stream->nread_header_recvbuf += ncopy;
@@ -852,12 +890,6 @@ static int on_begin_headers(nghttp2_session *session,
return 0;
}
- if(!stream->trailer_recvbuf) {
- stream->trailer_recvbuf = Curl_add_buffer_init();
- if(!stream->trailer_recvbuf) {
- return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
- }
- }
return 0;
}
@@ -973,26 +1005,19 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
}
if(stream->bodystarted) {
- /* This is trailer fields. */
- /* 4 is for ": " and "\r\n". */
- uint32_t n = (uint32_t)(namelen + valuelen + 4);
-
+ /* This is a trailer */
+ struct dynbuf trail;
H2BUGF(infof(data_s, "h2 trailer: %.*s: %.*s\n", namelen, name, valuelen,
value));
-
- result = Curl_add_buffer(&stream->trailer_recvbuf, &n, sizeof(n));
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_add_buffer(&stream->trailer_recvbuf, name, namelen);
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_add_buffer(&stream->trailer_recvbuf, ": ", 2);
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_add_buffer(&stream->trailer_recvbuf, value, valuelen);
- if(result)
- return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_add_buffer(&stream->trailer_recvbuf, "\r\n\0", 3);
+ Curl_dyn_init(&trail, DYN_H2_TRAILER);
+ result = Curl_dyn_addf(&trail,
+ "%.*s: %.*s\r\n", namelen, name,
+ valuelen, value);
+ if(!result)
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+ Curl_dyn_ptr(&trail),
+ Curl_dyn_len(&trail));
+ Curl_dyn_free(&trail);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
@@ -1007,14 +1032,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
stream->status_code = decode_status_code(value, valuelen);
DEBUGASSERT(stream->status_code != -1);
- result = Curl_add_buffer(&stream->header_recvbuf, "HTTP/2 ", 7);
+ result = Curl_dyn_add(&stream->header_recvbuf, "HTTP/2 ");
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen);
+ result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* the space character after the status code is mandatory */
- result = Curl_add_buffer(&stream->header_recvbuf, " \r\n", 3);
+ result = Curl_dyn_add(&stream->header_recvbuf, " \r\n");
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
@@ -1029,16 +1054,16 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
/* nghttp2 guarantees that namelen > 0, and :status was already
received, and this is not pseudo-header field . */
/* convert to a HTTP1-style header */
- result = Curl_add_buffer(&stream->header_recvbuf, name, namelen);
+ result = Curl_dyn_addn(&stream->header_recvbuf, name, namelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_add_buffer(&stream->header_recvbuf, ": ", 2);
+ result = Curl_dyn_add(&stream->header_recvbuf, ": ");
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_add_buffer(&stream->header_recvbuf, value, valuelen);
+ result = Curl_dyn_addn(&stream->header_recvbuf, value, valuelen);
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
- result = Curl_add_buffer(&stream->header_recvbuf, "\r\n", 2);
+ result = Curl_dyn_add(&stream->header_recvbuf, "\r\n");
if(result)
return NGHTTP2_ERR_CALLBACK_FAILURE;
/* if we receive data for another handle, wake that up */
@@ -1139,17 +1164,14 @@ void Curl_http2_done(struct Curl_easy *data, bool premature)
/* there might be allocated resources done before this got the 'h2' pointer
setup */
- if(http->header_recvbuf) {
- Curl_add_buffer_free(&http->header_recvbuf);
- Curl_add_buffer_free(&http->trailer_recvbuf);
- if(http->push_headers) {
- /* if they weren't used and then freed before */
- for(; http->push_headers_used > 0; --http->push_headers_used) {
- free(http->push_headers[http->push_headers_used - 1]);
- }
- free(http->push_headers);
- http->push_headers = NULL;
+ Curl_dyn_free(&http->header_recvbuf);
+ if(http->push_headers) {
+ /* if they weren't used and then freed before */
+ for(; http->push_headers_used > 0; --http->push_headers_used) {
+ free(http->push_headers[http->push_headers_used - 1]);
}
+ free(http->push_headers);
+ http->push_headers = NULL;
}
if(!httpc->h2) /* not HTTP/2 ? */
@@ -1238,7 +1260,7 @@ static CURLcode http2_init(struct connectdata *conn)
/*
* Append headers to ask for a HTTP1.1 to HTTP2 upgrade.
*/
-CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
+CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
struct connectdata *conn)
{
CURLcode result;
@@ -1257,7 +1279,7 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
httpc->local_settings_num);
if(!binlen) {
failf(conn->data, "nghttp2 unexpectedly failed on pack_settings_payload");
- Curl_add_buffer_free(&req);
+ Curl_dyn_free(req);
return CURLE_FAILED_INIT;
}
conn->proto.httpc.binlen = binlen;
@@ -1265,15 +1287,15 @@ CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
result = Curl_base64url_encode(conn->data, (const char *)binsettings, binlen,
&base64, &blen);
if(result) {
- Curl_add_buffer_free(&req);
+ Curl_dyn_free(req);
return result;
}
- result = Curl_add_bufferf(&req,
- "Connection: Upgrade, HTTP2-Settings\r\n"
- "Upgrade: %s\r\n"
- "HTTP2-Settings: %s\r\n",
- NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
+ result = Curl_dyn_addf(req,
+ "Connection: Upgrade, HTTP2-Settings\r\n"
+ "Upgrade: %s\r\n"
+ "HTTP2-Settings: %s\r\n",
+ NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, base64);
free(base64);
k->upgr101 = UPGR101_REQUESTED;
@@ -1367,10 +1389,11 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
struct HTTP *stream = conn->data->req.protop;
+ struct http_conn *httpc = &conn->proto.httpc;
+ nghttp2_session *h2 = httpc->h2;
+
if(stream->upload_left) {
/* If the stream still thinks there's data left to upload. */
- struct http_conn *httpc = &conn->proto.httpc;
- nghttp2_session *h2 = httpc->h2;
stream->upload_left = 0; /* DONE! */
@@ -1380,6 +1403,23 @@ CURLcode Curl_http2_done_sending(struct connectdata *conn)
(void)h2_process_pending_input(conn, httpc, &result);
}
+
+ /* If nghttp2 still has pending frames unsent */
+ if(nghttp2_session_want_write(h2)) {
+ struct Curl_easy *data = conn->data;
+ struct SingleRequest *k = &data->req;
+ int rv;
+
+ H2BUGF(infof(data, "HTTP/2 still wants to send data (easy %p)\n", data));
+
+ /* re-set KEEP_SEND to make sure we are called again */
+ k->keepon |= KEEP_SEND;
+
+ /* and attempt to send the pending frames */
+ rv = h2_session_send(data, h2);
+ if(rv != 0)
+ result = CURLE_SEND_ERROR;
+ }
}
return result;
}
@@ -1388,8 +1428,6 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
struct Curl_easy *data,
struct HTTP *stream, CURLcode *err)
{
- char *trailer_pos, *trailer_end;
- CURLcode result;
struct http_conn *httpc = &conn->proto.httpc;
if(httpc->pause_stream_id == stream->stream_id) {
@@ -1432,25 +1470,6 @@ static ssize_t http2_handle_stream_close(struct connectdata *conn,
return -1;
}
- if(stream->trailer_recvbuf && stream->trailer_recvbuf->buffer) {
- trailer_pos = stream->trailer_recvbuf->buffer;
- trailer_end = trailer_pos + stream->trailer_recvbuf->size_used;
-
- for(; trailer_pos < trailer_end;) {
- uint32_t n;
- memcpy(&n, trailer_pos, sizeof(n));
- trailer_pos += sizeof(n);
-
- result = Curl_client_write(conn, CLIENTWRITE_HEADER, trailer_pos, n);
- if(result) {
- *err = result;
- return -1;
- }
-
- trailer_pos += n + 1;
- }
- }
-
stream->close_handled = TRUE;
H2BUGF(infof(data, "http2_recv returns 0, http2_handle_stream_close\n"));
@@ -1541,13 +1560,13 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
*/
if(stream->bodystarted &&
- stream->nread_header_recvbuf < stream->header_recvbuf->size_used) {
- /* If there is body data pending for this stream to return, do that */
+ stream->nread_header_recvbuf < Curl_dyn_len(&stream->header_recvbuf)) {
+ /* If there is header data pending for this stream to return, do that */
size_t left =
- stream->header_recvbuf->size_used - stream->nread_header_recvbuf;
+ Curl_dyn_len(&stream->header_recvbuf) - stream->nread_header_recvbuf;
size_t ncopy = CURLMIN(len, left);
- memcpy(mem, stream->header_recvbuf->buffer + stream->nread_header_recvbuf,
- ncopy);
+ memcpy(mem, Curl_dyn_ptr(&stream->header_recvbuf) +
+ stream->nread_header_recvbuf, ncopy);
stream->nread_header_recvbuf += ncopy;
H2BUGF(infof(data, "http2_recv: Got %d bytes from header_recvbuf\n",
@@ -2056,7 +2075,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
h2_pri_spec(conn->data, &pri_spec);
- switch(conn->data->set.httpreq) {
+ switch(conn->data->state.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
case HTTPREQ_POST_MIME:
@@ -2127,13 +2146,11 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
struct http_conn *httpc = &conn->proto.httpc;
struct HTTP *stream = conn->data->req.protop;
+ DEBUGASSERT(conn->data->state.buffer);
+
stream->stream_id = -1;
- if(!stream->header_recvbuf) {
- stream->header_recvbuf = Curl_add_buffer_init();
- if(!stream->header_recvbuf)
- return CURLE_OUT_OF_MEMORY;
- }
+ Curl_dyn_init(&stream->header_recvbuf, DYN_H2_HEADERS);
if((conn->handler == &Curl_handler_http2_ssl) ||
(conn->handler == &Curl_handler_http2))
@@ -2146,7 +2163,7 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
result = http2_init(conn);
if(result) {
- Curl_add_buffer_free(&stream->header_recvbuf);
+ Curl_dyn_free(&stream->header_recvbuf);
return result;
}
@@ -2154,6 +2171,8 @@ CURLcode Curl_http2_setup(struct connectdata *conn)
stream->upload_left = 0;
stream->upload_mem = NULL;
stream->upload_len = 0;
+ stream->mem = conn->data->state.buffer;
+ stream->len = conn->data->set.buffer_size;
httpc->inbuflen = 0;
httpc->nread_inbuf = 0;
diff --git a/lib/http2.h b/lib/http2.h
index 1989aff8..e82b2128 100644
--- a/lib/http2.h
+++ b/lib/http2.h
@@ -42,7 +42,7 @@ const char *Curl_http2_strerror(uint32_t err);
CURLcode Curl_http2_init(struct connectdata *conn);
void Curl_http2_init_state(struct UrlState *state);
void Curl_http2_init_userset(struct UserDefined *set);
-CURLcode Curl_http2_request_upgrade(Curl_send_buffer *req,
+CURLcode Curl_http2_request_upgrade(struct dynbuf *req,
struct connectdata *conn);
CURLcode Curl_http2_setup(struct connectdata *conn);
CURLcode Curl_http2_switched(struct connectdata *conn,
diff --git a/lib/http_chunks.c b/lib/http_chunks.c
index b6ffa418..767f806c 100644
--- a/lib/http_chunks.c
+++ b/lib/http_chunks.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -26,7 +26,7 @@
#include "urldata.h" /* it includes http_chunks.h */
#include "sendf.h" /* for the client write stuff */
-
+#include "dynbuf.h"
#include "content_encoding.h"
#include "http.h"
#include "non-ascii.h" /* for Curl_convert_to_network prototype */
@@ -93,6 +93,7 @@ void Curl_httpchunk_init(struct connectdata *conn)
chunk->hexindex = 0; /* start at 0 */
chunk->dataleft = 0; /* no data left yet! */
chunk->state = CHUNK_HEX; /* we get hex first! */
+ Curl_dyn_init(&conn->trailer, DYN_H1_TRAILER);
}
/*
@@ -177,7 +178,6 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
/* we're now expecting data to come, unless size was zero! */
if(0 == ch->datasize) {
ch->state = CHUNK_TRAILER; /* now check for trailers */
- conn->trlPos = 0;
}
else
ch->state = CHUNK_DATA;
@@ -229,32 +229,33 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
case CHUNK_TRAILER:
if((*datap == 0x0d) || (*datap == 0x0a)) {
+ char *tr = Curl_dyn_ptr(&conn->trailer);
/* this is the end of a trailer, but if the trailer was zero bytes
there was no trailer and we move on */
- if(conn->trlPos) {
- /* we allocate trailer with 3 bytes extra room to fit this */
- conn->trailer[conn->trlPos++] = 0x0d;
- conn->trailer[conn->trlPos++] = 0x0a;
- conn->trailer[conn->trlPos] = 0;
+ if(tr) {
+ size_t trlen;
+ result = Curl_dyn_add(&conn->trailer, (char *)"\x0d\x0a");
+ if(result)
+ return CHUNKE_OUT_OF_MEMORY;
+ tr = Curl_dyn_ptr(&conn->trailer);
+ trlen = Curl_dyn_len(&conn->trailer);
/* Convert to host encoding before calling Curl_client_write */
- result = Curl_convert_from_network(conn->data, conn->trailer,
- conn->trlPos);
+ result = Curl_convert_from_network(conn->data, tr, trlen);
if(result)
/* Curl_convert_from_network calls failf if unsuccessful */
/* Treat it as a bad chunk */
return CHUNKE_BAD_CHUNK;
if(!data->set.http_te_skip) {
- result = Curl_client_write(conn, CLIENTWRITE_HEADER,
- conn->trailer, conn->trlPos);
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, tr, trlen);
if(result) {
*extrap = result;
return CHUNKE_PASSTHRU_ERROR;
}
}
- conn->trlPos = 0;
+ Curl_dyn_reset(&conn->trailer);
ch->state = CHUNK_TRAILER_CR;
if(*datap == 0x0a)
/* already on the LF */
@@ -267,25 +268,9 @@ CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
}
}
else {
- /* conn->trailer is assumed to be freed in url.c on a
- connection basis */
- if(conn->trlPos >= conn->trlMax) {
- /* we always allocate three extra bytes, just because when the full
- header has been received we append CRLF\0 */
- char *ptr;
- if(conn->trlMax) {
- conn->trlMax *= 2;
- ptr = realloc(conn->trailer, conn->trlMax + 3);
- }
- else {
- conn->trlMax = 128;
- ptr = malloc(conn->trlMax + 3);
- }
- if(!ptr)
- return CHUNKE_OUT_OF_MEMORY;
- conn->trailer = ptr;
- }
- conn->trailer[conn->trlPos++]=*datap;
+ result = Curl_dyn_addn(&conn->trailer, datap, 1);
+ if(result)
+ return CHUNKE_OUT_OF_MEMORY;
}
datap++;
length--;
diff --git a/lib/http_digest.c b/lib/http_digest.c
index 9616c30e..b06dc0d8 100644
--- a/lib/http_digest.c
+++ b/lib/http_digest.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -94,15 +94,19 @@ CURLcode Curl_output_digest(struct connectdata *conn,
struct auth *authp;
if(proxy) {
+#ifdef CURL_DISABLE_PROXY
+ return CURLE_NOT_BUILT_IN;
+#else
digest = &data->state.proxydigest;
- allocuserpwd = &conn->allocptr.proxyuserpwd;
+ allocuserpwd = &data->state.aptr.proxyuserpwd;
userp = conn->http_proxy.user;
passwdp = conn->http_proxy.passwd;
authp = &data->state.authproxy;
+#endif
}
else {
digest = &data->state.digest;
- allocuserpwd = &conn->allocptr.userpwd;
+ allocuserpwd = &data->state.aptr.userpwd;
userp = conn->user;
passwdp = conn->passwd;
authp = &data->state.authhost;
diff --git a/lib/http_digest.h b/lib/http_digest.h
index 73410ae8..96e39a7d 100644
--- a/lib/http_digest.h
+++ b/lib/http_digest.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c
index 8e1f3bf6..0a19ec2a 100644
--- a/lib/http_negotiate.c
+++ b/lib/http_negotiate.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -52,6 +52,7 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
curlnegotiate state;
if(proxy) {
+#ifndef CURL_DISABLE_PROXY
userp = conn->http_proxy.user;
passwdp = conn->http_proxy.passwd;
service = data->set.str[STRING_PROXY_SERVICE_NAME] ?
@@ -59,6 +60,9 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
host = conn->http_proxy.host.name;
neg_ctx = &conn->proxyneg;
state = conn->proxy_negotiate_state;
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
}
else {
userp = conn->user;
@@ -119,7 +123,8 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
struct auth *authp = proxy ? &conn->data->state.authproxy :
&conn->data->state.authhost;
curlnegotiate *state = proxy ? &conn->proxy_negotiate_state :
- &conn->http_negotiate_state;
+ &conn->http_negotiate_state;
+ struct Curl_easy *data = conn->data;
char *base64 = NULL;
size_t len = 0;
char *userp;
@@ -164,15 +169,15 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
return result;
userp = aprintf("%sAuthorization: Negotiate %s\r\n", proxy ? "Proxy-" : "",
- base64);
+ base64);
if(proxy) {
- Curl_safefree(conn->allocptr.proxyuserpwd);
- conn->allocptr.proxyuserpwd = userp;
+ Curl_safefree(data->state.aptr.proxyuserpwd);
+ data->state.aptr.proxyuserpwd = userp;
}
else {
- Curl_safefree(conn->allocptr.userpwd);
- conn->allocptr.userpwd = userp;
+ Curl_safefree(data->state.aptr.userpwd);
+ data->state.aptr.userpwd = userp;
}
free(base64);
diff --git a/lib/http_negotiate.h b/lib/http_negotiate.h
index 4f0ac168..a737f6f7 100644
--- a/lib/http_negotiate.h
+++ b/lib/http_negotiate.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -33,6 +33,8 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
void Curl_http_auth_cleanup_negotiate(struct connectdata *conn);
-#endif /* !CURL_DISABLE_HTTP && USE_SPNEGO */
+#else /* !CURL_DISABLE_HTTP && USE_SPNEGO */
+#define Curl_http_auth_cleanup_negotiate(x)
+#endif
#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
index 342b2424..cab543c7 100644
--- a/lib/http_ntlm.c
+++ b/lib/http_ntlm.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -131,12 +131,15 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
struct ntlmdata *ntlm;
curlntlm *state;
struct auth *authp;
+ struct Curl_easy *data = conn->data;
+
DEBUGASSERT(conn);
- DEBUGASSERT(conn->data);
+ DEBUGASSERT(data);
if(proxy) {
- allocuserpwd = &conn->allocptr.proxyuserpwd;
+#ifndef CURL_DISABLE_PROXY
+ allocuserpwd = &data->state.aptr.proxyuserpwd;
userp = conn->http_proxy.user;
passwdp = conn->http_proxy.passwd;
service = conn->data->set.str[STRING_PROXY_SERVICE_NAME] ?
@@ -145,9 +148,12 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
ntlm = &conn->proxyntlm;
state = &conn->proxy_ntlm_state;
authp = &conn->data->state.authproxy;
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
}
else {
- allocuserpwd = &conn->allocptr.userpwd;
+ allocuserpwd = &data->state.aptr.userpwd;
userp = conn->user;
passwdp = conn->passwd;
service = conn->data->set.str[STRING_SERVICE_NAME] ?
diff --git a/lib/http_ntlm.h b/lib/http_ntlm.h
index 003714db..3ebdf979 100644
--- a/lib/http_ntlm.h
+++ b/lib/http_ntlm.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -35,6 +35,8 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
void Curl_http_auth_cleanup_ntlm(struct connectdata *conn);
-#endif /* !CURL_DISABLE_HTTP && USE_NTLM */
+#else /* !CURL_DISABLE_HTTP && USE_NTLM */
+#define Curl_http_auth_cleanup_ntlm(x)
+#endif
#endif /* HEADER_CURL_HTTP_NTLM_H */
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index 75c7a60c..f188cbfc 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -72,6 +72,7 @@ static CURLcode https_proxy_connect(struct connectdata *conn, int sockindex)
CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
{
+ struct Curl_easy *data = conn->data;
if(conn->http_proxy.proxytype == CURLPROXY_HTTPS) {
const CURLcode result = https_proxy_connect(conn, sockindex);
if(result)
@@ -127,7 +128,7 @@ CURLcode Curl_proxy_connect(struct connectdata *conn, int sockindex)
conn->data->req.protop = prot_save;
if(CURLE_OK != result)
return result;
- Curl_safefree(conn->allocptr.proxyuserpwd);
+ Curl_safefree(data->state.aptr.proxyuserpwd);
#else
return CURLE_NOT_BUILT_IN;
#endif
@@ -158,15 +159,15 @@ static CURLcode connect_init(struct connectdata *conn, bool reinit)
return CURLE_OUT_OF_MEMORY;
infof(conn->data, "allocate connect buffer!\n");
conn->connect_state = s;
+ Curl_dyn_init(&s->rcvbuf, DYN_PROXY_CONNECT_HEADERS);
}
else {
DEBUGASSERT(conn->connect_state);
s = conn->connect_state;
+ Curl_dyn_reset(&s->rcvbuf);
}
s->tunnel_state = TUNNEL_INIT;
s->keepon = TRUE;
- s->line_start = s->connect_buffer;
- s->ptr = s->line_start;
s->cl = 0;
s->close_connection = FALSE;
return CURLE_OK;
@@ -176,6 +177,7 @@ static void connect_done(struct connectdata *conn)
{
struct http_connect_state *s = conn->connect_state;
s->tunnel_state = TUNNEL_COMPLETE;
+ Curl_dyn_free(&s->rcvbuf);
infof(conn->data, "CONNECT phase completed!\n");
}
@@ -190,6 +192,8 @@ static CURLcode CONNECT(struct connectdata *conn,
CURLcode result;
curl_socket_t tunnelsocket = conn->sock[sockindex];
struct http_connect_state *s = conn->connect_state;
+ char *linep;
+ size_t perline;
#define SELECT_OK 0
#define SELECT_ERROR 1
@@ -204,7 +208,7 @@ static CURLcode CONNECT(struct connectdata *conn,
if(TUNNEL_INIT == s->tunnel_state) {
/* BEGIN CONNECT PHASE */
char *host_port;
- Curl_send_buffer *req_buffer;
+ struct dynbuf req;
infof(data, "Establish HTTP proxy tunnel to %s:%d\n",
hostname, remote_port);
@@ -215,17 +219,12 @@ static CURLcode CONNECT(struct connectdata *conn,
free(data->req.newurl);
data->req.newurl = NULL;
- /* initialize a dynamic send-buffer */
- req_buffer = Curl_add_buffer_init();
-
- if(!req_buffer)
- return CURLE_OUT_OF_MEMORY;
-
host_port = aprintf("%s:%d", hostname, remote_port);
- if(!host_port) {
- Curl_add_buffer_free(&req_buffer);
+ if(!host_port)
return CURLE_OUT_OF_MEMORY;
- }
+
+ /* initialize a dynamic send-buffer */
+ Curl_dyn_init(&req, DYN_HTTP_REQUEST);
/* Setup the proxy-authorization header, if any */
result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE);
@@ -236,8 +235,8 @@ static CURLcode CONNECT(struct connectdata *conn,
char *host = NULL;
const char *proxyconn = "";
const char *useragent = "";
- const char *http = (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ?
- "1.0" : "1.1";
+ const char *httpv =
+ (conn->http_proxy.proxytype == CURLPROXY_HTTP_1_0) ? "1.0" : "1.1";
bool ipv6_ip = conn->bits.ipv6_ip;
char *hostheader;
@@ -248,7 +247,7 @@ static CURLcode CONNECT(struct connectdata *conn,
aprintf("%s%s%s:%d", ipv6_ip?"[":"", hostname, ipv6_ip?"]":"",
remote_port);
if(!hostheader) {
- Curl_add_buffer_free(&req_buffer);
+ Curl_dyn_free(&req);
return CURLE_OUT_OF_MEMORY;
}
@@ -256,7 +255,7 @@ static CURLcode CONNECT(struct connectdata *conn,
host = aprintf("Host: %s\r\n", hostheader);
if(!host) {
free(hostheader);
- Curl_add_buffer_free(&req_buffer);
+ Curl_dyn_free(&req);
return CURLE_OUT_OF_MEMORY;
}
}
@@ -265,52 +264,49 @@ static CURLcode CONNECT(struct connectdata *conn,
if(!Curl_checkProxyheaders(conn, "User-Agent") &&
data->set.str[STRING_USERAGENT])
- useragent = conn->allocptr.uagent;
+ useragent = data->state.aptr.uagent;
result =
- Curl_add_bufferf(&req_buffer,
- "CONNECT %s HTTP/%s\r\n"
- "%s" /* Host: */
- "%s" /* Proxy-Authorization */
- "%s" /* User-Agent */
- "%s", /* Proxy-Connection */
- hostheader,
- http,
- host?host:"",
- conn->allocptr.proxyuserpwd?
- conn->allocptr.proxyuserpwd:"",
- useragent,
- proxyconn);
+ Curl_dyn_addf(&req,
+ "CONNECT %s HTTP/%s\r\n"
+ "%s" /* Host: */
+ "%s" /* Proxy-Authorization */
+ "%s" /* User-Agent */
+ "%s", /* Proxy-Connection */
+ hostheader,
+ httpv,
+ host?host:"",
+ data->state.aptr.proxyuserpwd?
+ data->state.aptr.proxyuserpwd:"",
+ useragent,
+ proxyconn);
if(host)
free(host);
free(hostheader);
if(!result)
- result = Curl_add_custom_headers(conn, TRUE, req_buffer);
+ result = Curl_add_custom_headers(conn, TRUE, &req);
if(!result)
/* CRLF terminate the request */
- result = Curl_add_bufferf(&req_buffer, "\r\n");
+ result = Curl_dyn_add(&req, "\r\n");
if(!result) {
/* Send the connect request to the proxy */
/* BLOCKING */
- result =
- Curl_add_buffer_send(&req_buffer, conn,
- &data->info.request_size, 0, sockindex);
+ result = Curl_buffer_send(&req, conn, &data->info.request_size, 0,
+ sockindex);
}
- req_buffer = NULL;
if(result)
failf(data, "Failed sending CONNECT to proxy");
}
- Curl_add_buffer_free(&req_buffer);
+ Curl_dyn_free(&req);
if(result)
return result;
s->tunnel_state = TUNNEL_CONNECT;
- s->perline = 0;
} /* END CONNECT PHASE */
check = Curl_timeleft(data, NULL, TRUE);
@@ -330,16 +326,11 @@ static CURLcode CONNECT(struct connectdata *conn,
while(s->keepon) {
ssize_t gotbytes;
-
- /* make sure we have space to read more data */
- if(s->ptr >= &s->connect_buffer[CONNECT_BUFFER_SIZE]) {
- failf(data, "CONNECT response too large!");
- return CURLE_RECV_ERROR;
- }
+ char byte;
/* Read one byte at a time to avoid a race condition. Wait at most one
second before looping to ensure continuous pgrsUpdates. */
- result = Curl_read(conn, tunnelsocket, s->ptr, 1, &gotbytes);
+ result = Curl_read(conn, tunnelsocket, &byte, 1, &gotbytes);
if(result == CURLE_AGAIN)
/* socket buffer drained, return */
return CURLE_OK;
@@ -366,11 +357,9 @@ static CURLcode CONNECT(struct connectdata *conn,
break;
}
-
if(s->keepon > TRUE) {
/* This means we are currently ignoring a response-body */
- s->ptr = s->connect_buffer;
if(s->cl) {
/* A Content-Length based body: simply count down the counter
and make sure to break out of the loop when we're done! */
@@ -390,7 +379,7 @@ static CURLcode CONNECT(struct connectdata *conn,
/* now parse the chunked piece of data so that we can
properly tell when the stream ends */
- r = Curl_httpchunk_read(conn, s->ptr, 1, &tookcareof, &extra);
+ r = Curl_httpchunk_read(conn, &byte, 1, &tookcareof, &extra);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
infof(data, "chunk reading DONE\n");
@@ -402,25 +391,27 @@ static CURLcode CONNECT(struct connectdata *conn,
continue;
}
- s->perline++; /* amount of bytes in this line so far */
+ if(Curl_dyn_addn(&s->rcvbuf, &byte, 1)) {
+ failf(data, "CONNECT response too large!");
+ return CURLE_RECV_ERROR;
+ }
/* if this is not the end of a header line then continue */
- if(*s->ptr != 0x0a) {
- s->ptr++;
+ if(byte != 0x0a)
continue;
- }
+
+ linep = Curl_dyn_ptr(&s->rcvbuf);
+ perline = Curl_dyn_len(&s->rcvbuf); /* amount of bytes in this line */
/* convert from the network encoding */
- result = Curl_convert_from_network(data, s->line_start,
- (size_t)s->perline);
+ result = Curl_convert_from_network(data, linep, perline);
/* Curl_convert_from_network calls failf if unsuccessful */
if(result)
return result;
/* output debug if that is requested */
if(data->set.verbose)
- Curl_debug(data, CURLINFO_HEADER_IN,
- s->line_start, (size_t)s->perline);
+ Curl_debug(data, CURLINFO_HEADER_IN, linep, perline);
if(!data->set.suppress_connect_headers) {
/* send the header to the callback */
@@ -428,23 +419,22 @@ static CURLcode CONNECT(struct connectdata *conn,
if(data->set.include_header)
writetype |= CLIENTWRITE_BODY;
- result = Curl_client_write(conn, writetype,
- s->line_start, s->perline);
+ result = Curl_client_write(conn, writetype, linep, perline);
if(result)
return result;
}
- data->info.header_size += (long)s->perline;
- data->req.headerbytecount += (long)s->perline;
+ data->info.header_size += (long)perline;
+ data->req.headerbytecount += (long)perline;
/* Newlines are CRLF, so the CR is ignored as the line isn't
really terminated until the LF comes. Treat a following CR
as end-of-headers as well.*/
- if(('\r' == s->line_start[0]) ||
- ('\n' == s->line_start[0])) {
+ if(('\r' == linep[0]) ||
+ ('\n' == linep[0])) {
/* end of response-headers from the proxy */
- s->ptr = s->connect_buffer;
+
if((407 == k->httpcode) && !data->state.authproblem) {
/* If we get a 407 response code with content length
when we have no auth problem, we must ignore the
@@ -461,21 +451,18 @@ static CURLcode CONNECT(struct connectdata *conn,
infof(data, "Ignore chunked response-body\n");
- /* We set ignorebody true here since the chunked
- decoder function will acknowledge that. Pay
- attention so that this is cleared again when this
- function returns! */
+ /* We set ignorebody true here since the chunked decoder
+ function will acknowledge that. Pay attention so that this is
+ cleared again when this function returns! */
k->ignorebody = TRUE;
- if(s->line_start[1] == '\n') {
- /* this can only be a LF if the letter at index 0
- was a CR */
- s->line_start++;
- }
+ if(linep[1] == '\n')
+ /* this can only be a LF if the letter at index 0 was a CR */
+ linep++;
- /* now parse the chunked piece of data so that we can
- properly tell when the stream ends */
- r = Curl_httpchunk_read(conn, s->line_start + 1, 1, &gotbytes,
+ /* now parse the chunked piece of data so that we can properly
+ tell when the stream ends */
+ r = Curl_httpchunk_read(conn, linep + 1, 1, &gotbytes,
&extra);
if(r == CHUNKE_STOP) {
/* we're done reading chunks! */
@@ -500,14 +487,13 @@ static CURLcode CONNECT(struct connectdata *conn,
continue;
}
- s->line_start[s->perline] = 0; /* zero terminate the buffer */
- if((checkprefix("WWW-Authenticate:", s->line_start) &&
+ if((checkprefix("WWW-Authenticate:", linep) &&
(401 == k->httpcode)) ||
- (checkprefix("Proxy-authenticate:", s->line_start) &&
+ (checkprefix("Proxy-authenticate:", linep) &&
(407 == k->httpcode))) {
bool proxy = (k->httpcode == 407) ? TRUE : FALSE;
- char *auth = Curl_copy_header_value(s->line_start);
+ char *auth = Curl_copy_header_value(linep);
if(!auth)
return CURLE_OUT_OF_MEMORY;
@@ -518,7 +504,7 @@ static CURLcode CONNECT(struct connectdata *conn,
if(result)
return result;
}
- else if(checkprefix("Content-Length:", s->line_start)) {
+ else if(checkprefix("Content-Length:", linep)) {
if(k->httpcode/100 == 2) {
/* A client MUST ignore any Content-Length or Transfer-Encoding
header fields received in a successful response to CONNECT.
@@ -527,13 +513,13 @@ static CURLcode CONNECT(struct connectdata *conn,
k->httpcode);
}
else {
- (void)curlx_strtoofft(s->line_start +
+ (void)curlx_strtoofft(linep +
strlen("Content-Length:"), NULL, 10, &s->cl);
}
}
- else if(Curl_compareheader(s->line_start, "Connection:", "close"))
+ else if(Curl_compareheader(linep, "Connection:", "close"))
s->close_connection = TRUE;
- else if(checkprefix("Transfer-Encoding:", s->line_start)) {
+ else if(checkprefix("Transfer-Encoding:", linep)) {
if(k->httpcode/100 == 2) {
/* A client MUST ignore any Content-Length or Transfer-Encoding
header fields received in a successful response to CONNECT.
@@ -541,7 +527,7 @@ static CURLcode CONNECT(struct connectdata *conn,
infof(data, "Ignoring Transfer-Encoding in "
"CONNECT %03d response\n", k->httpcode);
}
- else if(Curl_compareheader(s->line_start,
+ else if(Curl_compareheader(linep,
"Transfer-Encoding:", "chunked")) {
infof(data, "CONNECT responded chunked\n");
s->chunked_encoding = TRUE;
@@ -549,19 +535,16 @@ static CURLcode CONNECT(struct connectdata *conn,
Curl_httpchunk_init(conn);
}
}
- else if(Curl_compareheader(s->line_start,
- "Proxy-Connection:", "close"))
+ else if(Curl_compareheader(linep, "Proxy-Connection:", "close"))
s->close_connection = TRUE;
- else if(2 == sscanf(s->line_start, "HTTP/1.%d %d",
+ else if(2 == sscanf(linep, "HTTP/1.%d %d",
&subversion,
&k->httpcode)) {
/* store the HTTP code from the proxy */
data->info.httpproxycode = k->httpcode;
}
- s->perline = 0; /* line starts over here */
- s->ptr = s->connect_buffer;
- s->line_start = s->ptr;
+ Curl_dyn_reset(&s->rcvbuf);
} /* while there's buffer left and loop is requested */
if(Curl_pgrsUpdate(conn))
@@ -622,6 +605,7 @@ static CURLcode CONNECT(struct connectdata *conn,
if(conn->bits.proxy_connect_closed)
/* this is not an error, just part of the connection negotiation */
return CURLE_OK;
+ Curl_dyn_free(&s->rcvbuf);
failf(data, "Received HTTP code %d from proxy after CONNECT",
data->req.httpcode);
return CURLE_RECV_ERROR;
@@ -632,8 +616,8 @@ static CURLcode CONNECT(struct connectdata *conn,
/* If a proxy-authorization header was used for the proxy, then we should
make sure that it isn't accidentally used for the document request
after we've connected. So let's free and clear it here. */
- Curl_safefree(conn->allocptr.proxyuserpwd);
- conn->allocptr.proxyuserpwd = NULL;
+ Curl_safefree(data->state.aptr.proxyuserpwd);
+ data->state.aptr.proxyuserpwd = NULL;
data->state.authproxy.done = TRUE;
data->state.authproxy.multipass = FALSE;
@@ -643,6 +627,7 @@ static CURLcode CONNECT(struct connectdata *conn,
data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
document request */
+ Curl_dyn_free(&s->rcvbuf);
return CURLE_OK;
}
diff --git a/lib/http_proxy.h b/lib/http_proxy.h
index e19fa859..29988a69 100644
--- a/lib/http_proxy.h
+++ b/lib/http_proxy.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -47,5 +47,6 @@ bool Curl_connect_ongoing(struct connectdata *conn);
#endif
void Curl_connect_free(struct Curl_easy *data);
+void Curl_connect_done(struct Curl_easy *data);
#endif /* HEADER_CURL_HTTP_PROXY_H */
diff --git a/lib/idn_win32.c b/lib/idn_win32.c
index 8dc300b3..2f5850dd 100644
--- a/lib/idn_win32.c
+++ b/lib/idn_win32.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -72,13 +72,13 @@ bool curl_win32_idn_to_ascii(const char *in, char **out)
{
bool success = FALSE;
- wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
+ wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
if(in_w) {
wchar_t punycode[IDN_MAX_LENGTH];
int chars = IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH);
free(in_w);
if(chars) {
- *out = Curl_convert_wchar_to_UTF8(punycode);
+ *out = curlx_convert_wchar_to_UTF8(punycode);
if(*out)
success = TRUE;
}
@@ -91,7 +91,7 @@ bool curl_win32_ascii_to_idn(const char *in, char **out)
{
bool success = FALSE;
- wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
+ wchar_t *in_w = curlx_convert_UTF8_to_wchar(in);
if(in_w) {
size_t in_len = wcslen(in_w) + 1;
wchar_t unicode[IDN_MAX_LENGTH];
@@ -99,7 +99,7 @@ bool curl_win32_ascii_to_idn(const char *in, char **out)
unicode, IDN_MAX_LENGTH);
free(in_w);
if(chars) {
- *out = Curl_convert_wchar_to_UTF8(unicode);
+ *out = curlx_convert_wchar_to_UTF8(unicode);
if(*out)
success = TRUE;
}
diff --git a/lib/if2ip.c b/lib/if2ip.c
index b283f67f..39388692 100644
--- a/lib/if2ip.c
+++ b/lib/if2ip.c
@@ -118,7 +118,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
if(iface->ifa_addr->sa_family == af) {
if(strcasecompare(iface->ifa_name, interf)) {
void *addr;
- char *ip;
+ const char *ip;
char scope[12] = "";
char ipstr[64];
#ifdef ENABLE_IPV6
@@ -153,15 +153,15 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
}
if(scopeid)
- msnprintf(scope, sizeof(scope), "%%%u", scopeid);
+ msnprintf(scope, sizeof(scope), "%%%u", scopeid);
#endif
}
else
#endif
addr =
- &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
+ &((struct sockaddr_in *)(void *)iface->ifa_addr)->sin_addr;
res = IF2IP_FOUND;
- ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
+ ip = Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
msnprintf(buf, buf_size, "%s%s", ip, scope);
break;
}
@@ -190,6 +190,7 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
struct sockaddr_in *s;
curl_socket_t dummy;
size_t len;
+ const char *r;
(void)remote_scope;
(void)local_scope_id;
@@ -219,9 +220,11 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
s = (struct sockaddr_in *)(void *)&req.ifr_addr;
memcpy(&in, &s->sin_addr, sizeof(in));
- Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
+ r = Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
sclose(dummy);
+ if(!r)
+ return IF2IP_NOT_FOUND;
return IF2IP_FOUND;
}
diff --git a/lib/imap.c b/lib/imap.c
index 66172bdd..cad0e590 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -187,7 +187,7 @@ static void imap_to_imaps(struct connectdata *conn)
conn->handler = &Curl_handler_imaps;
/* Set the connection's upgraded to TLS flag */
- conn->tls_upgraded = TRUE;
+ conn->bits.tls_upgraded = TRUE;
}
#else
#define imap_to_imaps(x) Curl_nop_stmt
@@ -1710,7 +1710,7 @@ static CURLcode imap_setup_connection(struct connectdata *conn)
return result;
/* Clear the TLS upgraded flag */
- conn->tls_upgraded = FALSE;
+ conn->bits.tls_upgraded = FALSE;
return CURLE_OK;
}
@@ -1957,7 +1957,7 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
end--;
result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL,
- TRUE);
+ REJECT_CTRL);
if(result)
return result;
}
@@ -1979,7 +1979,8 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
return CURLE_URL_MALFORMAT;
/* Decode the name parameter */
- result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE);
+ result = Curl_urldecode(data, begin, ptr - begin, &name, NULL,
+ REJECT_CTRL);
if(result)
return result;
@@ -1989,7 +1990,8 @@ static CURLcode imap_parse_url_path(struct connectdata *conn)
ptr++;
/* Decode the value parameter */
- result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE);
+ result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen,
+ REJECT_CTRL);
if(result) {
free(name);
return result;
@@ -2077,7 +2079,7 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn)
if(custom) {
/* URL decode the custom request */
- result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE);
+ result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, REJECT_CTRL);
/* Extract the parameters if specified */
if(!result) {
diff --git a/lib/ldap.c b/lib/ldap.c
index 771edb4e..512def65 100644
--- a/lib/ldap.c
+++ b/lib/ldap.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -75,7 +75,7 @@
/* Use our own implementation. */
-typedef struct {
+struct ldap_urldesc {
char *lud_host;
int lud_port;
#if defined(USE_WIN32_LDAP)
@@ -95,10 +95,10 @@ typedef struct {
size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the
"real" struct so can only be used in code
without HAVE_LDAP_URL_PARSE defined */
-} CURL_LDAPURLDesc;
+};
#undef LDAPURLDesc
-#define LDAPURLDesc CURL_LDAPURLDesc
+#define LDAPURLDesc struct ldap_urldesc
static int _ldap_url_parse(const struct connectdata *conn,
LDAPURLDesc **ludp);
@@ -239,13 +239,13 @@ static int ldap_win_bind(struct connectdata *conn, LDAP *server,
PTCHAR inpass = NULL;
if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) {
- inuser = Curl_convert_UTF8_to_tchar((char *) user);
- inpass = Curl_convert_UTF8_to_tchar((char *) passwd);
+ inuser = curlx_convert_UTF8_to_tchar((char *) user);
+ inpass = curlx_convert_UTF8_to_tchar((char *) passwd);
rc = ldap_simple_bind_s(server, inuser, inpass);
- Curl_unicodefree(inuser);
- Curl_unicodefree(inpass);
+ curlx_unicodefree(inuser);
+ curlx_unicodefree(inpass);
}
#if defined(USE_WINDOWS_SSPI)
else {
@@ -306,7 +306,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
ldap_ssl ? "encrypted" : "cleartext");
#if defined(USE_WIN32_LDAP)
- host = Curl_convert_UTF8_to_tchar(conn->host.name);
+ host = curlx_convert_UTF8_to_tchar(conn->host.name);
if(!host) {
result = CURLE_OUT_OF_MEMORY;
@@ -517,7 +517,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
size_t name_len;
#if defined(USE_WIN32_LDAP)
TCHAR *dn = ldap_get_dn(server, entryIterator);
- name = Curl_convert_tchar_to_UTF8(dn);
+ name = curlx_convert_tchar_to_UTF8(dn);
if(!name) {
ldap_memfree(dn);
@@ -533,7 +533,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
if(result) {
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(name);
+ curlx_unicodefree(name);
#endif
ldap_memfree(dn);
@@ -544,7 +544,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
name_len);
if(result) {
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(name);
+ curlx_unicodefree(name);
#endif
ldap_memfree(dn);
@@ -554,7 +554,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
if(result) {
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(name);
+ curlx_unicodefree(name);
#endif
ldap_memfree(dn);
@@ -564,7 +564,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
dlsize += name_len + 5;
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(name);
+ curlx_unicodefree(name);
#endif
ldap_memfree(dn);
}
@@ -576,7 +576,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
BerValue **vals;
size_t attr_len;
#if defined(USE_WIN32_LDAP)
- char *attr = Curl_convert_tchar_to_UTF8(attribute);
+ char *attr = curlx_convert_tchar_to_UTF8(attribute);
if(!attr) {
if(ber)
ber_free(ber, 0);
@@ -597,7 +597,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
if(result) {
ldap_value_free_len(vals);
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(attr);
+ curlx_unicodefree(attr);
#endif
ldap_memfree(attribute);
if(ber)
@@ -611,7 +611,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
if(result) {
ldap_value_free_len(vals);
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(attr);
+ curlx_unicodefree(attr);
#endif
ldap_memfree(attribute);
if(ber)
@@ -624,7 +624,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
if(result) {
ldap_value_free_len(vals);
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(attr);
+ curlx_unicodefree(attr);
#endif
ldap_memfree(attribute);
if(ber)
@@ -646,7 +646,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
if(result) {
ldap_value_free_len(vals);
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(attr);
+ curlx_unicodefree(attr);
#endif
ldap_memfree(attribute);
if(ber)
@@ -662,7 +662,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
if(result) {
ldap_value_free_len(vals);
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(attr);
+ curlx_unicodefree(attr);
#endif
ldap_memfree(attribute);
if(ber)
@@ -680,7 +680,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
if(result) {
ldap_value_free_len(vals);
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(attr);
+ curlx_unicodefree(attr);
#endif
ldap_memfree(attribute);
if(ber)
@@ -696,7 +696,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
if(result) {
ldap_value_free_len(vals);
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(attr);
+ curlx_unicodefree(attr);
#endif
ldap_memfree(attribute);
if(ber)
@@ -714,7 +714,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
/* Free the attribute as we are done with it */
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(attr);
+ curlx_unicodefree(attr);
#endif
ldap_memfree(attribute);
@@ -746,7 +746,7 @@ quit:
#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
#if defined(USE_WIN32_LDAP)
- Curl_unicodefree(host);
+ curlx_unicodefree(host);
#endif
/* no data to transfer */
@@ -883,7 +883,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
LDAP_TRACE(("DN '%s'\n", dn));
/* Unescape the DN */
- result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE);
+ result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, REJECT_ZERO);
if(result) {
rc = LDAP_NO_MEMORY;
@@ -892,10 +892,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
#if defined(USE_WIN32_LDAP)
/* Convert the unescaped string to a tchar */
- ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped);
+ ludp->lud_dn = curlx_convert_UTF8_to_tchar(unescaped);
/* Free the unescaped string as we are done with it */
- Curl_unicodefree(unescaped);
+ curlx_unicodefree(unescaped);
if(!ludp->lud_dn) {
rc = LDAP_NO_MEMORY;
@@ -949,7 +949,7 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
/* Unescape the attribute */
result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL,
- FALSE);
+ REJECT_ZERO);
if(result) {
free(attributes);
@@ -960,10 +960,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
#if defined(USE_WIN32_LDAP)
/* Convert the unescaped string to a tchar */
- ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped);
+ ludp->lud_attrs[i] = curlx_convert_UTF8_to_tchar(unescaped);
/* Free the unescaped string as we are done with it */
- Curl_unicodefree(unescaped);
+ curlx_unicodefree(unescaped);
if(!ludp->lud_attrs[i]) {
free(attributes);
@@ -1018,7 +1018,8 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
LDAP_TRACE(("filter '%s'\n", filter));
/* Unescape the filter */
- result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE);
+ result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL,
+ REJECT_ZERO);
if(result) {
rc = LDAP_NO_MEMORY;
@@ -1027,10 +1028,10 @@ static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
#if defined(USE_WIN32_LDAP)
/* Convert the unescaped string to a tchar */
- ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped);
+ ludp->lud_filter = curlx_convert_UTF8_to_tchar(unescaped);
/* Free the unescaped string as we are done with it */
- Curl_unicodefree(unescaped);
+ curlx_unicodefree(unescaped);
if(!ludp->lud_filter) {
rc = LDAP_NO_MEMORY;
diff --git a/lib/libcurl.plist b/lib/libcurl.plist
index a02dfaa7..f206ea8f 100644
--- a/lib/libcurl.plist
+++ b/lib/libcurl.plist
@@ -15,7 +15,7 @@
<string>se.haxx.curl.libcurl</string>
<key>CFBundleVersion</key>
- <string>7.70.0</string>
+ <string>7.71.1</string>
<key>CFBundleName</key>
<string>libcurl</string>
@@ -27,9 +27,9 @@
<string>????</string>
<key>CFBundleShortVersionString</key>
- <string>libcurl 7.70.0</string>
+ <string>libcurl 7.71.1</string>
<key>CFBundleGetInfoString</key>
- <string>libcurl.plist 7.70.0</string>
+ <string>libcurl.plist 7.71.1</string>
</dict>
</plist>
diff --git a/lib/md4.c b/lib/md4.c
index 10e6fc53..0fab52de 100644
--- a/lib/md4.c
+++ b/lib/md4.c
@@ -139,10 +139,11 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
/* The last #include file should be: */
#include "memdebug.h"
-typedef struct {
+struct md4_ctx {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
-} MD4_CTX;
+};
+typedef struct md4_ctx MD4_CTX;
static void MD4_Init(MD4_CTX *ctx)
{
@@ -184,10 +185,11 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
/* The last #include file should be: */
#include "memdebug.h"
-typedef struct {
+struct md4_ctx {
void *data;
unsigned long size;
-} MD4_CTX;
+};
+typedef struct md4_ctx MD4_CTX;
static void MD4_Init(MD4_CTX *ctx)
{
@@ -266,12 +268,13 @@ static void MD4_Final(unsigned char *result, MD4_CTX *ctx)
/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD4_u32plus;
-typedef struct {
+struct md4_ctx {
MD4_u32plus lo, hi;
MD4_u32plus a, b, c, d;
unsigned char buffer[64];
MD4_u32plus block[16];
-} MD4_CTX;
+};
+typedef struct md4_ctx MD4_CTX;
static void MD4_Init(MD4_CTX *ctx);
static void MD4_Update(MD4_CTX *ctx, const void *data, unsigned long size);
diff --git a/lib/md5.c b/lib/md5.c
index 76615878..557a51e6 100644
--- a/lib/md5.c
+++ b/lib/md5.c
@@ -179,10 +179,11 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
/* The last #include file should be: */
#include "memdebug.h"
-typedef struct {
+struct md5_ctx {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
-} MD5_CTX;
+};
+typedef struct md5_ctx MD5_CTX;
static void MD5_Init(MD5_CTX *ctx)
{
@@ -261,12 +262,13 @@ static void MD5_Final(unsigned char *digest, MD5_CTX *ctx)
/* Any 32-bit or wider unsigned integer data type will do */
typedef unsigned int MD5_u32plus;
-typedef struct {
+struct md5_ctx {
MD5_u32plus lo, hi;
MD5_u32plus a, b, c, d;
unsigned char buffer[64];
MD5_u32plus block[16];
-} MD5_CTX;
+};
+typedef struct md5_ctx MD5_CTX;
static void MD5_Init(MD5_CTX *ctx);
static void MD5_Update(MD5_CTX *ctx, const void *data, unsigned long size);
@@ -528,7 +530,7 @@ static void MD5_Final(unsigned char *result, MD5_CTX *ctx)
#endif /* CRYPTO LIBS */
-const HMAC_params Curl_HMAC_MD5[] = {
+const struct HMAC_params Curl_HMAC_MD5[] = {
{
/* Hash initialization function. */
CURLX_FUNCTION_CAST(HMAC_hinit_func, MD5_Init),
@@ -545,7 +547,7 @@ const HMAC_params Curl_HMAC_MD5[] = {
}
};
-const MD5_params Curl_DIGEST_MD5[] = {
+const struct MD5_params Curl_DIGEST_MD5[] = {
{
/* Digest initialization function */
CURLX_FUNCTION_CAST(Curl_MD5_init_func, MD5_Init),
@@ -573,9 +575,9 @@ void Curl_md5it(unsigned char *outbuffer, const unsigned char *input,
MD5_Final(outbuffer, &ctx);
}
-MD5_context *Curl_MD5_init(const MD5_params *md5params)
+struct MD5_context *Curl_MD5_init(const struct MD5_params *md5params)
{
- MD5_context *ctxt;
+ struct MD5_context *ctxt;
/* Create MD5 context */
ctxt = malloc(sizeof(*ctxt));
@@ -597,7 +599,7 @@ MD5_context *Curl_MD5_init(const MD5_params *md5params)
return ctxt;
}
-CURLcode Curl_MD5_update(MD5_context *context,
+CURLcode Curl_MD5_update(struct MD5_context *context,
const unsigned char *data,
unsigned int len)
{
@@ -606,7 +608,7 @@ CURLcode Curl_MD5_update(MD5_context *context,
return CURLE_OK;
}
-CURLcode Curl_MD5_final(MD5_context *context, unsigned char *result)
+CURLcode Curl_MD5_final(struct MD5_context *context, unsigned char *result)
{
(*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
diff --git a/lib/mime.c b/lib/mime.c
index e13d92e9..6a9b64a2 100644
--- a/lib/mime.c
+++ b/lib/mime.c
@@ -71,7 +71,7 @@ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
curl_mimepart *part);
static curl_off_t encoder_qp_size(curl_mimepart *part);
-static const mime_encoder encoders[] = {
+static const struct mime_encoder encoders[] = {
{"binary", encoder_nop_read, encoder_nop_size},
{"8bit", encoder_nop_read, encoder_nop_size},
{"7bit", encoder_7bit_read, encoder_nop_size},
@@ -269,7 +269,8 @@ static char *Curl_basename(char *path)
/* Set readback state. */
-static void mimesetstate(mime_state *state, enum mimestate tok, void *ptr)
+static void mimesetstate(struct mime_state *state,
+ enum mimestate tok, void *ptr)
{
state->state = tok;
state->ptr = ptr;
@@ -342,7 +343,7 @@ static char *strippath(const char *fullfile)
}
/* Initialize data encoder state. */
-static void cleanup_encoder_state(mime_encoder_state *p)
+static void cleanup_encoder_state(struct mime_encoder_state *p)
{
p->pos = 0;
p->bufbeg = 0;
@@ -352,9 +353,9 @@ static void cleanup_encoder_state(mime_encoder_state *p)
/* Dummy encoder. This is used for 8bit and binary content encodings. */
static size_t encoder_nop_read(char *buffer, size_t size, bool ateof,
- curl_mimepart *part)
+ struct curl_mimepart *part)
{
- mime_encoder_state *st = &part->encstate;
+ struct mime_encoder_state *st = &part->encstate;
size_t insize = st->bufend - st->bufbeg;
(void) ateof;
@@ -382,7 +383,7 @@ static curl_off_t encoder_nop_size(curl_mimepart *part)
static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
curl_mimepart *part)
{
- mime_encoder_state *st = &part->encstate;
+ struct mime_encoder_state *st = &part->encstate;
size_t cursize = st->bufend - st->bufbeg;
(void) ateof;
@@ -408,7 +409,7 @@ static size_t encoder_7bit_read(char *buffer, size_t size, bool ateof,
static size_t encoder_base64_read(char *buffer, size_t size, bool ateof,
curl_mimepart *part)
{
- mime_encoder_state *st = &part->encstate;
+ struct mime_encoder_state *st = &part->encstate;
size_t cursize = 0;
int i;
char *ptr = buffer;
@@ -512,7 +513,7 @@ static curl_off_t encoder_base64_size(curl_mimepart *part)
* Check if a CRLF or end of data is in input buffer at current position + n.
* Return -1 if more data needed, 1 if CRLF or end of data, else 0.
*/
-static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n)
+static int qp_lookahead_eol(struct mime_encoder_state *st, int ateof, size_t n)
{
n += st->bufbeg;
if(n >= st->bufend && ateof)
@@ -529,7 +530,7 @@ static int qp_lookahead_eol(mime_encoder_state *st, int ateof, size_t n)
static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
curl_mimepart *part)
{
- mime_encoder_state *st = &part->encstate;
+ struct mime_encoder_state *st = &part->encstate;
char *ptr = buffer;
size_t cursize = 0;
int softlinebreak;
@@ -594,7 +595,6 @@ static size_t encoder_qp_read(char *buffer, size_t size, bool ateof,
switch(qp_lookahead_eol(st, ateof, consumed)) {
case -1: /* Need more data. */
return cursize;
- break;
case 0: /* Not followed by a CRLF. */
softlinebreak = 1;
break;
@@ -685,7 +685,7 @@ static void mime_mem_free(void *ptr)
/* Named file callbacks. */
/* Argument is a pointer to the mime part. */
-static int mime_open_file(curl_mimepart * part)
+static int mime_open_file(curl_mimepart *part)
{
/* Open a MIMEKIND_FILE part. */
@@ -740,7 +740,7 @@ static void mime_file_free(void *ptr)
/* Argument is a pointer to the mime structure. */
/* Readback a byte string segment. */
-static size_t readback_bytes(mime_state *state,
+static size_t readback_bytes(struct mime_state *state,
char *buffer, size_t bufsize,
const char *bytes, size_t numbytes,
const char *trail)
@@ -839,7 +839,7 @@ static size_t read_part_content(curl_mimepart *part,
static size_t read_encoded_part_content(curl_mimepart *part, char *buffer,
size_t bufsize, bool *hasread)
{
- mime_encoder_state *st = &part->encstate;
+ struct mime_encoder_state *st = &part->encstate;
size_t cursize = 0;
size_t sz;
bool ateof = FALSE;
@@ -1419,7 +1419,7 @@ CURLcode curl_mime_data(curl_mimepart *part,
if(datasize)
memcpy(part->data, data, datasize);
- part->data[datasize] = '\0'; /* Set a nul terminator as sentinel. */
+ part->data[datasize] = '\0'; /* Set a null terminator as sentinel. */
part->readfunc = mime_mem_read;
part->seekfunc = mime_mem_seek;
@@ -1502,7 +1502,7 @@ CURLcode curl_mime_type(curl_mimepart *part, const char *mimetype)
CURLcode curl_mime_encoder(curl_mimepart *part, const char *encoding)
{
CURLcode result = CURLE_BAD_FUNCTION_ARGUMENT;
- const mime_encoder *mep;
+ const struct mime_encoder *mep;
if(!part)
return result;
diff --git a/lib/mime.h b/lib/mime.h
index d7f25132..50b7ea6b 100644
--- a/lib/mime.h
+++ b/lib/mime.h
@@ -69,43 +69,43 @@ enum mimestrategy {
};
/* Content transfer encoder. */
-typedef struct {
+struct mime_encoder {
const char * name; /* Encoding name. */
size_t (*encodefunc)(char *buffer, size_t size, bool ateof,
curl_mimepart *part); /* Encoded read. */
curl_off_t (*sizefunc)(curl_mimepart *part); /* Encoded size. */
-} mime_encoder;
+};
/* Content transfer encoder state. */
-typedef struct {
+struct mime_encoder_state {
size_t pos; /* Position on output line. */
size_t bufbeg; /* Next data index in input buffer. */
size_t bufend; /* First unused byte index in input buffer. */
char buf[ENCODING_BUFFER_SIZE]; /* Input buffer. */
-} mime_encoder_state;
+};
/* Mime readback state. */
-typedef struct {
+struct mime_state {
enum mimestate state; /* Current state token. */
void *ptr; /* State-dependent pointer. */
curl_off_t offset; /* State-dependent offset. */
-} mime_state;
+};
/* minimum buffer size for the boundary string */
#define MIME_BOUNDARY_LEN (24 + MIME_RAND_BOUNDARY_CHARS + 1)
/* A mime multipart. */
-struct curl_mime_s {
+struct curl_mime {
struct Curl_easy *easy; /* The associated easy handle. */
curl_mimepart *parent; /* Parent part. */
curl_mimepart *firstpart; /* First part. */
curl_mimepart *lastpart; /* Last part. */
char boundary[MIME_BOUNDARY_LEN]; /* The part boundary. */
- mime_state state; /* Current readback state. */
+ struct mime_state state; /* Current readback state. */
};
/* A mime part. */
-struct curl_mimepart_s {
+struct curl_mimepart {
struct Curl_easy *easy; /* The associated easy handle. */
curl_mime *parent; /* Parent mime structure. */
curl_mimepart *nextpart; /* Forward linked list. */
@@ -123,9 +123,9 @@ struct curl_mimepart_s {
char *name; /* Data name. */
curl_off_t datasize; /* Expected data size. */
unsigned int flags; /* Flags. */
- mime_state state; /* Current readback state. */
- const mime_encoder *encoder; /* Content data encoder. */
- mime_encoder_state encstate; /* Data encoder state. */
+ struct mime_state state; /* Current readback state. */
+ const struct mime_encoder *encoder; /* Content data encoder. */
+ struct mime_encoder_state encstate; /* Data encoder state. */
size_t lastreadstatus; /* Last read callback returned status. */
};
@@ -135,21 +135,23 @@ CURLcode Curl_mime_add_header(struct curl_slist **slp, const char *fmt, ...);
!defined(CURL_DISABLE_SMTP) || !defined(CURL_DISABLE_IMAP)
/* Prototypes. */
-void Curl_mime_initpart(curl_mimepart *part, struct Curl_easy *easy);
-void Curl_mime_cleanpart(curl_mimepart *part);
-CURLcode Curl_mime_duppart(curl_mimepart *dst, const curl_mimepart *src);
-CURLcode Curl_mime_set_subparts(curl_mimepart *part,
- curl_mime *subparts, int take_ownership);
-CURLcode Curl_mime_prepare_headers(curl_mimepart *part,
+void Curl_mime_initpart(struct curl_mimepart *part, struct Curl_easy *easy);
+void Curl_mime_cleanpart(struct curl_mimepart *part);
+CURLcode Curl_mime_duppart(struct curl_mimepart *dst,
+ const curl_mimepart *src);
+CURLcode Curl_mime_set_subparts(struct curl_mimepart *part,
+ struct curl_mime *subparts,
+ int take_ownership);
+CURLcode Curl_mime_prepare_headers(struct curl_mimepart *part,
const char *contenttype,
const char *disposition,
enum mimestrategy strategy);
-curl_off_t Curl_mime_size(curl_mimepart *part);
+curl_off_t Curl_mime_size(struct curl_mimepart *part);
size_t Curl_mime_read(char *buffer, size_t size, size_t nitems,
void *instream);
-CURLcode Curl_mime_rewind(curl_mimepart *part);
+CURLcode Curl_mime_rewind(struct curl_mimepart *part);
const char *Curl_mime_contenttype(const char *filename);
-void Curl_mime_unpause(curl_mimepart *part);
+void Curl_mime_unpause(struct curl_mimepart *part);
#else
/* if disabled */
diff --git a/lib/mprintf.c b/lib/mprintf.c
index bc009135..63c9d11a 100644
--- a/lib/mprintf.c
+++ b/lib/mprintf.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1999 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1999 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -36,6 +36,7 @@
*/
#include "curl_setup.h"
+#include "dynbuf.h"
#include <curl/mprintf.h>
#include "curl_memory.h"
@@ -145,7 +146,7 @@ enum {
FLAGS_FLOATG = 1<<19 /* %g or %G */
};
-typedef struct {
+struct va_stack {
FormatType type;
int flags;
long width; /* width OR width parameter number */
@@ -159,7 +160,7 @@ typedef struct {
} num;
double dnum;
} data;
-} va_stack_t;
+};
struct nsprintf {
char *buffer;
@@ -168,11 +169,9 @@ struct nsprintf {
};
struct asprintf {
- char *buffer; /* allocated buffer */
- size_t len; /* length of string */
- size_t alloc; /* length of alloc */
- int fail; /* (!= 0) if an alloc has failed and thus
- the output is not the complete data */
+ struct dynbuf b;
+ bool fail; /* if an alloc has failed and thus the output is not the complete
+ data */
};
static long dprintf_DollarString(char *input, char **end)
@@ -224,8 +223,8 @@ static bool dprintf_IsQualifierNoDollar(const char *fmt)
*
******************************************************************/
-static int dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
- va_list arglist)
+static int dprintf_Pass1(const char *format, struct va_stack *vto,
+ char **endpos, va_list arglist)
{
char *fmt = (char *)format;
int param_num = 0;
@@ -571,13 +570,11 @@ static int dprintf_formatf(
long param; /* current parameter to read */
long param_num = 0; /* parameter counter */
- va_stack_t vto[MAX_PARAMETERS];
+ struct va_stack vto[MAX_PARAMETERS];
char *endpos[MAX_PARAMETERS];
char **end;
-
char work[BUFFSIZE];
-
- va_stack_t *p;
+ struct va_stack *p;
/* 'workend' points to the final buffer byte position, but with an extra
byte as margin to avoid the (false?) warning Coverity gives us
@@ -1031,35 +1028,10 @@ static int alloc_addbyter(int output, FILE *data)
struct asprintf *infop = (struct asprintf *)data;
unsigned char outc = (unsigned char)output;
- if(!infop->buffer) {
- infop->buffer = malloc(32);
- if(!infop->buffer) {
- infop->fail = 1;
- return -1; /* fail */
- }
- infop->alloc = 32;
- infop->len = 0;
- }
- else if(infop->len + 1 >= infop->alloc) {
- char *newptr = NULL;
- size_t newsize = infop->alloc*2;
-
- /* detect wrap-around or other overflow problems */
- if(newsize > infop->alloc)
- newptr = realloc(infop->buffer, newsize);
-
- if(!newptr) {
- infop->fail = 1;
- return -1; /* fail */
- }
- infop->buffer = newptr;
- infop->alloc = newsize;
+ if(Curl_dyn_addn(&infop->b, &outc, 1)) {
+ infop->fail = 1;
+ return -1; /* fail */
}
-
- infop->buffer[ infop->len ] = outc;
-
- infop->len++;
-
return outc; /* fputc() returns like this on success */
}
@@ -1068,24 +1040,18 @@ char *curl_maprintf(const char *format, ...)
va_list ap_save; /* argument pointer */
int retcode;
struct asprintf info;
-
- info.buffer = NULL;
- info.len = 0;
- info.alloc = 0;
+ Curl_dyn_init(&info.b, DYN_APRINTF);
info.fail = 0;
va_start(ap_save, format);
retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
va_end(ap_save);
if((-1 == retcode) || info.fail) {
- if(info.alloc)
- free(info.buffer);
+ Curl_dyn_free(&info.b);
return NULL;
}
- if(info.alloc) {
- info.buffer[info.len] = 0; /* we terminate this with a zero byte */
- return info.buffer;
- }
+ if(Curl_dyn_len(&info.b))
+ return Curl_dyn_ptr(&info.b);
return strdup("");
}
@@ -1093,23 +1059,16 @@ char *curl_mvaprintf(const char *format, va_list ap_save)
{
int retcode;
struct asprintf info;
-
- info.buffer = NULL;
- info.len = 0;
- info.alloc = 0;
+ Curl_dyn_init(&info.b, DYN_APRINTF);
info.fail = 0;
retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
if((-1 == retcode) || info.fail) {
- if(info.alloc)
- free(info.buffer);
+ Curl_dyn_free(&info.b);
return NULL;
}
-
- if(info.alloc) {
- info.buffer[info.len] = 0; /* we terminate this with a zero byte */
- return info.buffer;
- }
+ if(Curl_dyn_len(&info.b))
+ return Curl_dyn_ptr(&info.b);
return strdup("");
}
diff --git a/lib/mqtt.c b/lib/mqtt.c
index 43a3b6e5..f6f44161 100644
--- a/lib/mqtt.c
+++ b/lib/mqtt.c
@@ -211,7 +211,8 @@ static CURLcode mqtt_get_topic(struct connectdata *conn,
char *path = conn->data->state.up.path;
if(strlen(path) > 1) {
- result = Curl_urldecode(conn->data, path + 1, 0, topic, topiclen, FALSE);
+ result = Curl_urldecode(conn->data, path + 1, 0, topic, topiclen,
+ REJECT_NADA);
}
else {
failf(conn->data, "Error: No topic specified.");
@@ -591,7 +592,7 @@ static CURLcode mqtt_doing(struct connectdata *conn, bool *done)
if(result)
break;
- if(conn->data->set.httpreq == HTTPREQ_POST) {
+ if(conn->data->state.httpreq == HTTPREQ_POST) {
result = mqtt_publish(conn);
if(!result) {
result = mqtt_disconnect(conn);
diff --git a/lib/multi.c b/lib/multi.c
index d4f03187..249e3607 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -79,7 +79,6 @@ static CURLMcode add_next_timeout(struct curltime now,
static CURLMcode multi_timeout(struct Curl_multi *multi,
long *timeout_ms);
static void process_pending_handles(struct Curl_multi *multi);
-static void detach_connnection(struct Curl_easy *data);
#ifdef DEBUGBUILD
static const char * const statename[]={
@@ -112,7 +111,7 @@ static void Curl_init_completed(struct Curl_easy *data)
/* Important: reset the conn pointer so that we don't point to memory
that could be freed anytime */
- detach_connnection(data);
+ Curl_detach_connnection(data);
Curl_expire_clear(data); /* stop all timers */
}
@@ -169,9 +168,11 @@ static void mstate(struct Curl_easy *data, CURLMstate state
}
#endif
- if(state == CURLM_STATE_COMPLETED)
+ if(state == CURLM_STATE_COMPLETED) {
/* changing to COMPLETED means there's one less easy handle 'alive' */
+ DEBUGASSERT(data->multi->num_alive > 0);
data->multi->num_alive--;
+ }
/* if this state has an init-function, run it */
if(finit[state])
@@ -506,6 +507,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
easy handle is added */
memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+ CONNCACHE_LOCK(data);
/* The closure handle only ever has default timeouts set. To improve the
state somewhat we clone the timeouts from each added handle so that the
closure handle always has the same timeouts as the most recently added
@@ -515,6 +517,7 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
data->set.server_response_timeout;
data->state.conn_cache->closure_handle->set.no_signal =
data->set.no_signal;
+ CONNCACHE_UNLOCK(data);
Curl_update_timer(multi);
return CURLM_OK;
@@ -589,14 +592,14 @@ static CURLcode multi_done(struct Curl_easy *data,
process_pending_handles(data->multi); /* connection / multiplex */
- CONN_LOCK(data);
- detach_connnection(data);
+ CONNCACHE_LOCK(data);
+ Curl_detach_connnection(data);
if(CONN_INUSE(conn)) {
/* Stop if still used. */
/* conn->data must not remain pointing to this transfer since it is going
away! Find another to own it! */
conn->data = conn->easyq.head->ptr;
- CONN_UNLOCK(data);
+ CONNCACHE_UNLOCK(data);
DEBUGF(infof(data, "Connection still in use %zu, "
"no more multi_done now!\n",
conn->easyq.size));
@@ -615,7 +618,7 @@ static CURLcode multi_done(struct Curl_easy *data,
/* if the transfer was completed in a paused state there can be buffered
data left to free */
for(i = 0; i < data->state.tempcount; i++) {
- free(data->state.tempwrite[i].buf);
+ Curl_dyn_free(&data->state.tempwrite[i].b);
}
data->state.tempcount = 0;
@@ -647,7 +650,8 @@ static CURLcode multi_done(struct Curl_easy *data,
|| (premature && !(conn->handler->flags & PROTOPT_STREAM))) {
CURLcode res2;
connclose(conn, "disconnecting");
- CONN_UNLOCK(data);
+ Curl_conncache_remove_conn(data, conn, FALSE);
+ CONNCACHE_UNLOCK(data);
res2 = Curl_disconnect(data, conn, premature);
/* If we had an error already, make sure we return that one. But
@@ -657,16 +661,20 @@ static CURLcode multi_done(struct Curl_easy *data,
}
else {
char buffer[256];
+ 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;
/* create string before returning the connection */
msnprintf(buffer, sizeof(buffer),
"Connection #%ld to host %s left intact",
- conn->connection_id,
- conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
- conn->bits.httpproxy ? conn->http_proxy.host.dispname :
- conn->bits.conn_to_host ? conn->conn_to_host.dispname :
- conn->host.dispname);
+ conn->connection_id, host);
/* the connection is no longer in use by this transfer */
- CONN_UNLOCK(data);
+ CONNCACHE_UNLOCK(data);
if(Curl_conncache_return_conn(data, conn)) {
/* remember the most recently used connection */
data->state.lastconnect = conn;
@@ -676,6 +684,7 @@ static CURLcode multi_done(struct Curl_easy *data,
data->state.lastconnect = NULL;
}
+ Curl_safefree(data->state.buffer);
Curl_free_request_state(data);
return result;
}
@@ -778,8 +787,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
vanish with this handle */
/* Remove the association between the connection and the handle */
- if(data->conn)
- detach_connnection(data);
+ Curl_detach_connnection(data);
#ifdef USE_LIBPSL
/* Remove the PSL association. */
@@ -828,9 +836,13 @@ bool Curl_multiplex_wanted(const struct Curl_multi *multi)
return (multi && (multi->multiplexing));
}
-/* This is the only function that should clear data->conn. This will
- occasionally be called with the pointer already cleared. */
-static void detach_connnection(struct Curl_easy *data)
+/*
+ * Curl_detach_connnection() removes the given transfer from the connection.
+ *
+ * This is the only function that should clear data->conn. This will
+ * occasionally be called with the data->conn pointer already cleared.
+ */
+void Curl_detach_connnection(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
if(conn)
@@ -838,7 +850,11 @@ static void detach_connnection(struct Curl_easy *data)
data->conn = NULL;
}
-/* This is the only function that should assign data->conn */
+/*
+ * Curl_attach_connnection() attaches this transfer to this connection.
+ *
+ * This is the only function that should assign data->conn
+ */
void Curl_attach_connnection(struct Curl_easy *data,
struct connectdata *conn)
{
@@ -857,9 +873,11 @@ static int waitconnect_getsock(struct connectdata *conn,
int rc = 0;
#ifdef USE_SSL
+#ifndef CURL_DISABLE_PROXY
if(CONNECT_FIRSTSOCKET_PROXY_SSL())
return Curl_ssl_getsock(conn, sock);
#endif
+#endif
if(SOCKS_STATE(conn->cnnct.state))
return Curl_SOCKS_getsock(conn, sock, FIRSTSOCKET);
@@ -1239,7 +1257,7 @@ static CURLMcode Curl_multi_wait(struct Curl_multi *multi,
timeout */
else if((sleep_ms < 0) && extrawait)
sleep_ms = timeout_ms;
- Curl_wait_ms((int)sleep_ms);
+ Curl_wait_ms(sleep_ms);
}
}
@@ -1480,7 +1498,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
}
if(!conn->bits.protoconnstart) {
-
+#ifndef CURL_DISABLE_PROXY
result = Curl_proxy_connect(conn, FIRSTSOCKET);
if(result)
return result;
@@ -1494,7 +1512,7 @@ static CURLcode protocol_connect(struct connectdata *conn,
/* when using an HTTP tunnel proxy, await complete tunnel establishment
before proceeding further. Return CURLE_OK so we'll be called again */
return CURLE_OK;
-
+#endif
if(conn->handler->connect_it) {
/* is there a protocol-specific connect() procedure? */
@@ -1513,6 +1531,21 @@ static CURLcode protocol_connect(struct connectdata *conn,
return result; /* pass back status */
}
+/*
+ * Curl_preconnect() is called immediately before a connect starts. When a
+ * redirect is followed, this is then called multiple times during a single
+ * transfer.
+ */
+CURLcode Curl_preconnect(struct Curl_easy *data)
+{
+ if(!data->state.buffer) {
+ data->state.buffer = malloc(data->set.buffer_size + 1);
+ if(!data->state.buffer)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ return CURLE_OK;
+}
+
static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct curltime now,
@@ -1540,19 +1573,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool stream_error = FALSE;
rc = CURLM_OK;
- DEBUGASSERT((data->mstate <= CURLM_STATE_CONNECT) ||
- (data->mstate >= CURLM_STATE_DONE) ||
- data->conn);
- if(!data->conn &&
- data->mstate > CURLM_STATE_CONNECT &&
- data->mstate < CURLM_STATE_DONE) {
- /* In all these states, the code will blindly access 'data->conn'
- so this is precaution that it isn't NULL. And it silences static
- analyzers. */
- failf(data, "In state %d with no conn, bail out!\n", data->mstate);
- return CURLM_INTERNAL_ERROR;
- }
-
if(multi_ischanged(multi, TRUE)) {
DEBUGF(infof(data, "multi changed, check CONNECT_PEND queue!\n"));
process_pending_handles(multi); /* multiplexed */
@@ -1633,6 +1653,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_CONNECT:
/* Connect. We want to get a connection identifier filled in. */
+ /* init this transfer. */
+ result = Curl_preconnect(data);
+ if(result)
+ break;
+
Curl_pgrsTime(data, TIMER_STARTSINGLE);
if(data->set.timeout)
Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
@@ -1690,9 +1715,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
const char *hostname;
DEBUGASSERT(conn);
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy)
hostname = conn->http_proxy.host.name;
- else if(conn->bits.conn_to_host)
+ else
+#endif
+ if(conn->bits.conn_to_host)
hostname = conn->conn_to_host.name;
else
hostname = conn->host.name;
@@ -1758,7 +1786,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
DEBUGASSERT(data->conn);
result = Curl_http_connect(data->conn, &protocol_connected);
-
+#ifndef CURL_DISABLE_PROXY
if(data->conn->bits.proxy_connect_closed) {
rc = CURLM_CALL_MULTI_PERFORM;
/* connect back to proxy again */
@@ -1766,15 +1794,20 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
multi_done(data, CURLE_OK, FALSE);
multistate(data, CURLM_STATE_CONNECT);
}
- else if(!result) {
- if((data->conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
- data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
- Curl_connect_complete(data->conn)) {
- rc = CURLM_CALL_MULTI_PERFORM;
- /* initiate protocol connect phase */
- multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+ else
+#endif
+ if(!result) {
+ if(
+#ifndef CURL_DISABLE_PROXY
+ (data->conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
+ data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
+#endif
+ Curl_connect_complete(data->conn)) {
+ rc = CURLM_CALL_MULTI_PERFORM;
+ /* initiate protocol connect phase */
+ multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+ }
}
- }
else if(result)
stream_error = TRUE;
break;
@@ -1786,17 +1819,25 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
if(connected && !result) {
#ifndef CURL_DISABLE_HTTP
- if((data->conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
- !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
- Curl_connect_ongoing(data->conn)) {
+ if(
+#ifndef CURL_DISABLE_PROXY
+ (data->conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
+ !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
+#endif
+ Curl_connect_ongoing(data->conn)) {
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
break;
}
#endif
rc = CURLM_CALL_MULTI_PERFORM;
- multistate(data, data->conn->bits.tunnel_proxy?
+#ifndef CURL_DISABLE_PROXY
+ multistate(data,
+ data->conn->bits.tunnel_proxy?
CURLM_STATE_WAITPROXYCONNECT:
CURLM_STATE_SENDPROTOCONNECT);
+#else
+ multistate(data, CURLM_STATE_SENDPROTOCONNECT);
+#endif
}
else if(result) {
/* failure detected */
@@ -2062,7 +2103,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
char *newurl = NULL;
bool retry = FALSE;
bool comeback = FALSE;
-
+ DEBUGASSERT(data->state.buffer);
/* check if over send speed */
send_timeout_ms = 0;
if(data->set.max_send_speed > 0)
@@ -2235,8 +2276,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* access free'd data, if the connection is free'd and the handle
* removed before we perform the processing in CURLM_STATE_COMPLETED
*/
- if(data->conn)
- detach_connnection(data);
+ Curl_detach_connnection(data);
}
#ifndef CURL_DISABLE_FTP
@@ -2288,7 +2328,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* This is where we make sure that the conn pointer is reset.
We don't have to do this in every case block above where a
failure is detected */
- detach_connnection(data);
+ Curl_detach_connnection(data);
+
+ /* remove connection from cache */
+ Curl_conncache_remove_conn(data, conn, TRUE);
/* disconnect properly */
Curl_disconnect(data, conn, dead_connection);
diff --git a/lib/multiif.h b/lib/multiif.h
index bde755ee..7d574df9 100644
--- a/lib/multiif.h
+++ b/lib/multiif.h
@@ -33,9 +33,11 @@ void Curl_expire_done(struct Curl_easy *data, expire_id id);
void Curl_update_timer(struct Curl_multi *multi);
void Curl_attach_connnection(struct Curl_easy *data,
struct connectdata *conn);
+void Curl_detach_connnection(struct Curl_easy *data);
bool Curl_multiplex_wanted(const struct Curl_multi *multi);
void Curl_set_in_callback(struct Curl_easy *data, bool value);
bool Curl_is_in_callback(struct Curl_easy *easy);
+CURLcode Curl_preconnect(struct Curl_easy *data);
/* Internal version of curl_multi_init() accepts size parameters for the
socket and connection hashes */
diff --git a/lib/nwlib.c b/lib/nwlib.c
index 7bf5f51c..beec0b38 100644
--- a/lib/nwlib.c
+++ b/lib/nwlib.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -36,21 +36,19 @@
/* The last #include file should be: */
#include "memdebug.h"
-typedef struct
-{
+struct libthreaddata {
int _errno;
void *twentybytes;
-} libthreaddata_t;
+};
-typedef struct
-{
+struct libdata {
int x;
int y;
int z;
void *tenbytes;
NXKey_t perthreadkey; /* if -1, no key obtained... */
NXMutex_t *lock;
-} libdata_t;
+};
int gLibId = -1;
void *gLibHandle = (void *) NULL;
@@ -60,7 +58,8 @@ NXMutex_t *gLibLock = (NXMutex_t *) NULL;
/* internal library function prototypes... */
int DisposeLibraryData(void *);
void DisposeThreadData(void *);
-int GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata);
+int GetOrSetUpData(int id, struct libdata **data,
+ struct libthreaddata **threaddata);
int _NonAppStart(void *NLMHandle,
@@ -154,24 +153,24 @@ int _NonAppCheckUnload(void)
return 0;
}
-int GetOrSetUpData(int id, libdata_t **appData,
- libthreaddata_t **threadData)
+int GetOrSetUpData(int id, struct libdata **appData,
+ struct libthreaddata **threadData)
{
int err;
- libdata_t *app_data;
- libthreaddata_t *thread_data;
+ struct libdata *app_data;
+ struct libthreaddata *thread_data;
NXKey_t key;
NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
err = 0;
- thread_data = (libthreaddata_t *) NULL;
+ thread_data = (struct libthreaddata_t *) NULL;
/*
* Attempt to get our data for the application calling us. This is where we
* store whatever application-specific information we need to carry in
* support of calling applications.
*/
- app_data = (libdata_t *) get_app_data(id);
+ app_data = (struct libdata *) get_app_data(id);
if(!app_data) {
/*
@@ -184,9 +183,9 @@ int GetOrSetUpData(int id, libdata_t **appData,
*/
NXLock(gLibLock);
- app_data = (libdata_t *) get_app_data(id);
+ app_data = (struct libdata *) get_app_data(id);
if(!app_data) {
- app_data = calloc(1, sizeof(libdata_t));
+ app_data = calloc(1, sizeof(struct libdata));
if(app_data) {
app_data->tenbytes = malloc(10);
@@ -249,7 +248,7 @@ int GetOrSetUpData(int id, libdata_t **appData,
* a pointer is not very important, this just helps to demonstrate that
* we can have arbitrarily complex per-thread data.
*/
- thread_data = malloc(sizeof(libthreaddata_t));
+ thread_data = malloc(sizeof(struct libthreaddata));
if(thread_data) {
thread_data->_errno = 0;
@@ -257,7 +256,7 @@ int GetOrSetUpData(int id, libdata_t **appData,
if(!thread_data->twentybytes) {
free(thread_data);
- thread_data = (libthreaddata_t *) NULL;
+ thread_data = (struct libthreaddata *) NULL;
err = ENOMEM;
}
@@ -265,7 +264,7 @@ int GetOrSetUpData(int id, libdata_t **appData,
if(err) {
free(thread_data->twentybytes);
free(thread_data);
- thread_data = (libthreaddata_t *) NULL;
+ thread_data = (struct libthreaddata *) NULL;
}
}
}
@@ -295,7 +294,7 @@ int DisposeLibraryData(void *data)
void DisposeThreadData(void *data)
{
if(data) {
- void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
+ void *twentybytes = ((struct libthreaddata *) data)->twentybytes;
free(twentybytes);
free(data);
diff --git a/lib/openldap.c b/lib/openldap.c
index 734ca5fa..782d6a08 100644
--- a/lib/openldap.c
+++ b/lib/openldap.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
- * Copyright (C) 2011 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2011 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -162,10 +162,10 @@ struct ldapconninfo {
bool didbind;
};
-typedef struct ldapreqinfo {
+struct ldapreqinfo {
int msgid;
int nument;
-} ldapreqinfo;
+};
static CURLcode ldap_setup_connection(struct connectdata *conn)
{
@@ -374,7 +374,7 @@ static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
static CURLcode ldap_do(struct connectdata *conn, bool *done)
{
struct ldapconninfo *li = conn->proto.ldapc;
- ldapreqinfo *lr;
+ struct ldapreqinfo *lr;
CURLcode status = CURLE_OK;
int rc = 0;
LDAPURLDesc *ludp = NULL;
@@ -406,7 +406,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
return CURLE_LDAP_SEARCH_FAILED;
}
- lr = calloc(1, sizeof(ldapreqinfo));
+ lr = calloc(1, sizeof(struct ldapreqinfo));
if(!lr)
return CURLE_OUT_OF_MEMORY;
lr->msgid = msgid;
@@ -419,7 +419,7 @@ static CURLcode ldap_do(struct connectdata *conn, bool *done)
static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
bool premature)
{
- ldapreqinfo *lr = conn->data->req.protop;
+ struct ldapreqinfo *lr = conn->data->req.protop;
(void)res;
(void)premature;
@@ -443,7 +443,7 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
{
struct ldapconninfo *li = conn->proto.ldapc;
struct Curl_easy *data = conn->data;
- ldapreqinfo *lr = data->req.protop;
+ struct ldapreqinfo *lr = data->req.protop;
int rc, ret;
LDAPMessage *msg = NULL;
LDAPMessage *ent;
diff --git a/lib/pingpong.c b/lib/pingpong.c
index d0710053..31433152 100644
--- a/lib/pingpong.c
+++ b/lib/pingpong.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -44,12 +44,12 @@
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */
-time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
+timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
{
struct connectdata *conn = pp->conn;
struct Curl_easy *data = conn->data;
- time_t timeout_ms; /* in milliseconds */
- long response_time = (data->set.server_response_timeout)?
+ timediff_t timeout_ms; /* in milliseconds */
+ timediff_t response_time = (data->set.server_response_timeout)?
data->set.server_response_timeout: pp->response_time;
/* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
@@ -60,12 +60,12 @@ time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
/* Without a requested timeout, we only wait 'response_time' seconds for the
full response to arrive before we bail out */
timeout_ms = response_time -
- (time_t)Curl_timediff(Curl_now(), pp->response); /* spent time */
+ Curl_timediff(Curl_now(), pp->response); /* spent time */
if(data->set.timeout && !disconnecting) {
/* if timeout is requested, find out how much remaining time we have */
- time_t timeout2_ms = data->set.timeout - /* timeout time */
- (time_t)Curl_timediff(Curl_now(), conn->now); /* spent time */
+ timediff_t timeout2_ms = data->set.timeout - /* timeout time */
+ Curl_timediff(Curl_now(), conn->now); /* spent time */
/* pick the lowest number */
timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
@@ -83,8 +83,8 @@ CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
struct connectdata *conn = pp->conn;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc;
- time_t interval_ms;
- time_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
+ timediff_t interval_ms;
+ timediff_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
@@ -384,10 +384,10 @@ CURLcode Curl_pp_readresp(curl_socket_t sockfd,
if(pp->endofresp(conn, pp->linestart_resp, perline, code)) {
/* This is the end of the last line, copy the last line to the
- start of the buffer and zero terminate, for old times sake */
+ start of the buffer and null-terminate, for old times sake */
size_t n = ptr - pp->linestart_resp;
memmove(buf, pp->linestart_resp, n);
- buf[n] = 0; /* zero terminate */
+ buf[n] = 0; /* null-terminate */
keepon = FALSE;
pp->linestart_resp = ptr + 1; /* advance pointer */
i++; /* skip this before getting out */
diff --git a/lib/pingpong.h b/lib/pingpong.h
index 849a7c0f..e874799d 100644
--- a/lib/pingpong.h
+++ b/lib/pingpong.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -60,9 +60,8 @@ struct pingpong {
size_t sendsize; /* total size of the sendthis buffer */
struct curltime response; /* set to Curl_now() when a command has been sent
off, used to time-out response reading */
- long response_time; /* When no timeout is given, this is the amount of
- milliseconds we await for a server response. */
-
+ timediff_t response_time; /* When no timeout is given, this is the amount of
+ milliseconds we await for a server response. */
struct connectdata *conn; /* points to the connectdata struct that this
belongs to */
@@ -89,7 +88,7 @@ void Curl_pp_init(struct pingpong *pp);
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */
-time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
+timediff_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
/***********************************************************************
diff --git a/lib/pop3.c b/lib/pop3.c
index 57c1373a..9ff5c78f 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -178,7 +178,7 @@ static void pop3_to_pop3s(struct connectdata *conn)
conn->handler = &Curl_handler_pop3s;
/* Set the connection's upgraded to TLS flag */
- conn->tls_upgraded = TRUE;
+ conn->bits.tls_upgraded = TRUE;
}
#else
#define pop3_to_pop3s(x) Curl_nop_stmt
@@ -412,7 +412,7 @@ static CURLcode pop3_perform_apop(struct connectdata *conn)
CURLcode result = CURLE_OK;
struct pop3_conn *pop3c = &conn->proto.pop3c;
size_t i;
- MD5_context *ctxt;
+ struct MD5_context *ctxt;
unsigned char digest[MD5_DIGEST_LEN];
char secret[2 * MD5_DIGEST_LEN + 1];
@@ -1312,7 +1312,7 @@ static CURLcode pop3_setup_connection(struct connectdata *conn)
return result;
/* Clear the TLS upgraded flag */
- conn->tls_upgraded = FALSE;
+ conn->bits.tls_upgraded = FALSE;
return CURLE_OK;
}
@@ -1390,7 +1390,7 @@ static CURLcode pop3_parse_url_path(struct connectdata *conn)
const char *path = &data->state.up.path[1]; /* skip leading path */
/* URL decode the path for the message ID */
- return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
+ return Curl_urldecode(data, path, 0, &pop3->id, NULL, REJECT_CTRL);
}
/***********************************************************************
@@ -1408,7 +1408,7 @@ static CURLcode pop3_parse_custom_request(struct connectdata *conn)
/* URL decode the custom request */
if(custom)
- result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
+ result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, REJECT_CTRL);
return result;
}
diff --git a/lib/progress.c b/lib/progress.c
index 60a941ab..89513844 100644
--- a/lib/progress.c
+++ b/lib/progress.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -282,9 +282,9 @@ timediff_t Curl_pgrsLimitWaitTime(curl_off_t cursize,
* stay below 'limit'.
*/
if(size < CURL_OFF_T_MAX/1000)
- minimum = (time_t) (CURL_OFF_T_C(1000) * size / limit);
+ minimum = (timediff_t) (CURL_OFF_T_C(1000) * size / limit);
else {
- minimum = (time_t) (size / limit);
+ minimum = (timediff_t) (size / limit);
if(minimum < TIMEDIFF_T_MAX/1000)
minimum *= 1000;
else
diff --git a/lib/quic.h b/lib/quic.h
index 1eb23e97..8e7df90e 100644
--- a/lib/quic.h
+++ b/lib/quic.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -47,11 +47,13 @@ int Curl_quic_ver(char *p, size_t len);
CURLcode Curl_quic_done_sending(struct connectdata *conn);
void Curl_quic_done(struct Curl_easy *data, bool premature);
bool Curl_quic_data_pending(const struct Curl_easy *data);
+void Curl_quic_disconnect(struct connectdata *conn, int tempindex);
#else /* ENABLE_QUIC */
#define Curl_quic_done_sending(x)
#define Curl_quic_done(x,y)
#define Curl_quic_data_pending(x)
+#define Curl_quic_disconnect(x,y)
#endif /* !ENABLE_QUIC */
#endif /* HEADER_CURL_QUIC_H */
diff --git a/lib/rtsp.c b/lib/rtsp.c
index bba4c16a..dbd7dc6a 100644
--- a/lib/rtsp.c
+++ b/lib/rtsp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -233,7 +233,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
CURLcode result = CURLE_OK;
Curl_RtspReq rtspreq = data->set.rtspreq;
struct RTSP *rtsp = data->req.protop;
- Curl_send_buffer *req_buffer;
+ struct dynbuf req_buffer;
curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
@@ -333,12 +333,12 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_SETUP && !p_transport) {
/* New Transport: setting? */
if(data->set.str[STRING_RTSP_TRANSPORT]) {
- Curl_safefree(conn->allocptr.rtsp_transport);
+ Curl_safefree(data->state.aptr.rtsp_transport);
- conn->allocptr.rtsp_transport =
+ data->state.aptr.rtsp_transport =
aprintf("Transport: %s\r\n",
data->set.str[STRING_RTSP_TRANSPORT]);
- if(!conn->allocptr.rtsp_transport)
+ if(!data->state.aptr.rtsp_transport)
return CURLE_OUT_OF_MEMORY;
}
else {
@@ -347,7 +347,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- p_transport = conn->allocptr.rtsp_transport;
+ p_transport = data->state.aptr.rtsp_transport;
}
/* Accept Headers for DESCRIBE requests */
@@ -359,14 +359,14 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/* Accept-Encoding header */
if(!Curl_checkheaders(conn, "Accept-Encoding") &&
data->set.str[STRING_ENCODING]) {
- Curl_safefree(conn->allocptr.accept_encoding);
- conn->allocptr.accept_encoding =
+ Curl_safefree(data->state.aptr.accept_encoding);
+ data->state.aptr.accept_encoding =
aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
- if(!conn->allocptr.accept_encoding)
+ if(!data->state.aptr.accept_encoding)
return CURLE_OUT_OF_MEMORY;
- p_accept_encoding = conn->allocptr.accept_encoding;
+ p_accept_encoding = data->state.aptr.accept_encoding;
}
}
@@ -374,13 +374,13 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
it might have been used in the proxy connect, but if we have got a header
with the user-agent string specified, we erase the previously made string
here. */
- if(Curl_checkheaders(conn, "User-Agent") && conn->allocptr.uagent) {
- Curl_safefree(conn->allocptr.uagent);
- conn->allocptr.uagent = NULL;
+ if(Curl_checkheaders(conn, "User-Agent") && data->state.aptr.uagent) {
+ Curl_safefree(data->state.aptr.uagent);
+ data->state.aptr.uagent = NULL;
}
else if(!Curl_checkheaders(conn, "User-Agent") &&
data->set.str[STRING_USERAGENT]) {
- p_uagent = conn->allocptr.uagent;
+ p_uagent = data->state.aptr.uagent;
}
/* setup the authentication headers */
@@ -388,17 +388,17 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(result)
return result;
- p_proxyuserpwd = conn->allocptr.proxyuserpwd;
- p_userpwd = conn->allocptr.userpwd;
+ p_proxyuserpwd = data->state.aptr.proxyuserpwd;
+ p_userpwd = data->state.aptr.userpwd;
/* Referrer */
- Curl_safefree(conn->allocptr.ref);
+ Curl_safefree(data->state.aptr.ref);
if(data->change.referer && !Curl_checkheaders(conn, "Referer"))
- conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ data->state.aptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
else
- conn->allocptr.ref = NULL;
+ data->state.aptr.ref = NULL;
- p_referrer = conn->allocptr.ref;
+ p_referrer = data->state.aptr.ref;
/*
* Range Header
@@ -411,9 +411,9 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/* Check to see if there is a range set in the custom headers */
if(!Curl_checkheaders(conn, "Range") && data->state.range) {
- Curl_safefree(conn->allocptr.rangeline);
- conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
- p_range = conn->allocptr.rangeline;
+ Curl_safefree(data->state.aptr.rangeline);
+ data->state.aptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
+ p_range = data->state.aptr.rangeline;
}
}
@@ -430,16 +430,13 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
}
/* Initialize a dynamic send buffer */
- req_buffer = Curl_add_buffer_init();
-
- if(!req_buffer)
- return CURLE_OUT_OF_MEMORY;
+ Curl_dyn_init(&req_buffer, DYN_RTSP_REQ_HEADER);
result =
- Curl_add_bufferf(&req_buffer,
- "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
- "CSeq: %ld\r\n", /* CSeq */
- p_request, p_stream_uri, rtsp->CSeq_sent);
+ Curl_dyn_addf(&req_buffer,
+ "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
+ "CSeq: %ld\r\n", /* CSeq */
+ p_request, p_stream_uri, rtsp->CSeq_sent);
if(result)
return result;
@@ -448,7 +445,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
* to make comparison easier
*/
if(p_session_id) {
- result = Curl_add_bufferf(&req_buffer, "Session: %s\r\n", p_session_id);
+ result = Curl_dyn_addf(&req_buffer, "Session: %s\r\n", p_session_id);
if(result)
return result;
}
@@ -456,42 +453,42 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/*
* Shared HTTP-like options
*/
- result = Curl_add_bufferf(&req_buffer,
- "%s" /* transport */
- "%s" /* accept */
- "%s" /* accept-encoding */
- "%s" /* range */
- "%s" /* referrer */
- "%s" /* user-agent */
- "%s" /* proxyuserpwd */
- "%s" /* userpwd */
- ,
- p_transport ? p_transport : "",
- p_accept ? p_accept : "",
- p_accept_encoding ? p_accept_encoding : "",
- p_range ? p_range : "",
- p_referrer ? p_referrer : "",
- p_uagent ? p_uagent : "",
- p_proxyuserpwd ? p_proxyuserpwd : "",
- p_userpwd ? p_userpwd : "");
+ result = Curl_dyn_addf(&req_buffer,
+ "%s" /* transport */
+ "%s" /* accept */
+ "%s" /* accept-encoding */
+ "%s" /* range */
+ "%s" /* referrer */
+ "%s" /* user-agent */
+ "%s" /* proxyuserpwd */
+ "%s" /* userpwd */
+ ,
+ p_transport ? p_transport : "",
+ p_accept ? p_accept : "",
+ p_accept_encoding ? p_accept_encoding : "",
+ p_range ? p_range : "",
+ p_referrer ? p_referrer : "",
+ p_uagent ? p_uagent : "",
+ p_proxyuserpwd ? p_proxyuserpwd : "",
+ p_userpwd ? p_userpwd : "");
/*
* Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
* with basic and digest, it will be freed anyway by the next request
*/
- Curl_safefree(conn->allocptr.userpwd);
- conn->allocptr.userpwd = NULL;
+ Curl_safefree(data->state.aptr.userpwd);
+ data->state.aptr.userpwd = NULL;
if(result)
return result;
if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
- result = Curl_add_timecondition(conn, req_buffer);
+ result = Curl_add_timecondition(conn, &req_buffer);
if(result)
return result;
}
- result = Curl_add_custom_headers(conn, FALSE, req_buffer);
+ result = Curl_add_custom_headers(conn, FALSE, &req_buffer);
if(result)
return result;
@@ -501,14 +498,14 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(data->set.upload) {
putsize = data->state.infilesize;
- data->set.httpreq = HTTPREQ_PUT;
+ data->state.httpreq = HTTPREQ_PUT;
}
else {
postsize = (data->state.infilesize != -1)?
data->state.infilesize:
(data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
- data->set.httpreq = HTTPREQ_POST;
+ data->state.httpreq = HTTPREQ_POST;
}
if(putsize > 0 || postsize > 0) {
@@ -516,9 +513,9 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
* actually set a custom Content-Length in the headers */
if(!Curl_checkheaders(conn, "Content-Length")) {
result =
- Curl_add_bufferf(&req_buffer,
- "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
- (data->set.upload ? putsize : postsize));
+ Curl_dyn_addf(&req_buffer,
+ "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
+ (data->set.upload ? putsize : postsize));
if(result)
return result;
}
@@ -526,8 +523,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_SET_PARAMETER ||
rtspreq == RTSPREQ_GET_PARAMETER) {
if(!Curl_checkheaders(conn, "Content-Type")) {
- result = Curl_add_bufferf(&req_buffer,
- "Content-Type: text/parameters\r\n");
+ result = Curl_dyn_addf(&req_buffer,
+ "Content-Type: text/parameters\r\n");
if(result)
return result;
}
@@ -535,8 +532,8 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_ANNOUNCE) {
if(!Curl_checkheaders(conn, "Content-Type")) {
- result = Curl_add_bufferf(&req_buffer,
- "Content-Type: application/sdp\r\n");
+ result = Curl_dyn_addf(&req_buffer,
+ "Content-Type: application/sdp\r\n");
if(result)
return result;
}
@@ -546,7 +543,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
}
else if(rtspreq == RTSPREQ_GET_PARAMETER) {
/* Check for an empty GET_PARAMETER (heartbeat) request */
- data->set.httpreq = HTTPREQ_HEAD;
+ data->state.httpreq = HTTPREQ_HEAD;
data->set.opt_no_body = TRUE;
}
}
@@ -554,20 +551,20 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/* RTSP never allows chunked transfer */
data->req.forbidchunk = TRUE;
/* Finish the request buffer */
- result = Curl_add_buffer(&req_buffer, "\r\n", 2);
+ result = Curl_dyn_add(&req_buffer, "\r\n");
if(result)
return result;
if(postsize > 0) {
- result = Curl_add_buffer(&req_buffer, data->set.postfields,
- (size_t)postsize);
+ result = Curl_dyn_addn(&req_buffer, data->set.postfields,
+ (size_t)postsize);
if(result)
return result;
}
/* issue the request */
- result = Curl_add_buffer_send(&req_buffer, conn,
- &data->info.request_size, 0, FIRSTSOCKET);
+ result = Curl_buffer_send(&req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
if(result) {
failf(data, "Failed sending RTSP request");
return result;
diff --git a/lib/select.c b/lib/select.c
index d91b20a4..abb124ae 100644
--- a/lib/select.c
+++ b/lib/select.c
@@ -22,6 +22,8 @@
#include "curl_setup.h"
+#include <limits.h>
+
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#elif defined(HAVE_UNISTD_H)
@@ -50,11 +52,9 @@
#include "urldata.h"
#include "connect.h"
#include "select.h"
+#include "timeval.h"
#include "warnless.h"
-/* Convenience local macros */
-#define ELAPSED_MS() (int)Curl_timediff(Curl_now(), initial_tv)
-
/*
* Internal function used for waiting a specific amount of ms
* in Curl_socket_check() and Curl_poll() when no file descriptor
@@ -71,7 +71,7 @@
* -1 = system call error, invalid timeout value, or interrupted
* 0 = specified timeout has elapsed
*/
-int Curl_wait_ms(int timeout_ms)
+int Curl_wait_ms(timediff_t timeout_ms)
{
int r = 0;
@@ -83,16 +83,44 @@ int Curl_wait_ms(int timeout_ms)
}
#if defined(MSDOS)
delay(timeout_ms);
-#elif defined(USE_WINSOCK)
- Sleep(timeout_ms);
+#elif defined(WIN32)
+ /* prevent overflow, timeout_ms is typecast to ULONG/DWORD. */
+#if TIMEDIFF_T_MAX >= ULONG_MAX
+ if(timeout_ms >= ULONG_MAX)
+ timeout_ms = ULONG_MAX-1;
+ /* don't use ULONG_MAX, because that is equal to INFINITE */
+#endif
+ Sleep((ULONG)timeout_ms);
#else
#if defined(HAVE_POLL_FINE)
- r = poll(NULL, 0, timeout_ms);
+ /* prevent overflow, timeout_ms is typecast to int. */
+#if TIMEDIFF_T_MAX > INT_MAX
+ if(timeout_ms > INT_MAX)
+ timeout_ms = INT_MAX;
+#endif
+ r = poll(NULL, 0, (int)timeout_ms);
#else
{
struct timeval pending_tv;
- pending_tv.tv_sec = timeout_ms / 1000;
- pending_tv.tv_usec = (timeout_ms % 1000) * 1000;
+ timediff_t tv_sec = timeout_ms / 1000;
+ timediff_t tv_usec = (timeout_ms % 1000) * 1000; /* max=999999 */
+#ifdef HAVE_SUSECONDS_T
+#if TIMEDIFF_T_MAX > TIME_T_MAX
+ /* tv_sec overflow check in case time_t is signed */
+ if(tv_sec > TIME_T_MAX)
+ tv_sec = TIME_T_MAX;
+#endif
+ pending_tv.tv_sec = (time_t)tv_sec;
+ pending_tv.tv_usec = (suseconds_t)tv_usec;
+#else
+#if TIMEDIFF_T_MAX > INT_MAX
+ /* tv_sec overflow check in case time_t is signed */
+ if(tv_sec > INT_MAX)
+ tv_sec = INT_MAX;
+#endif
+ pending_tv.tv_sec = (int)tv_sec;
+ pending_tv.tv_usec = (int)tv_usec;
+#endif
r = select(0, NULL, NULL, NULL, &pending_tv);
}
#endif /* HAVE_POLL_FINE */
@@ -113,44 +141,60 @@ int Curl_wait_ms(int timeout_ms)
* 0 = timeout
* N = number of signalled file descriptors
*/
-int Curl_select(curl_socket_t maxfd,
- fd_set *fds_read,
- fd_set *fds_write,
- fd_set *fds_err,
- time_t timeout_ms) /* milliseconds to wait */
+int Curl_select(curl_socket_t maxfd, /* highest socket number */
+ fd_set *fds_read, /* sockets ready for reading */
+ fd_set *fds_write, /* sockets ready for writing */
+ fd_set *fds_err, /* sockets with errors */
+ timediff_t timeout_ms) /* milliseconds to wait */
{
struct timeval pending_tv;
struct timeval *ptimeout;
- int pending_ms;
int r;
-#if SIZEOF_TIME_T != SIZEOF_INT
- /* wrap-around precaution */
- if(timeout_ms >= INT_MAX)
- timeout_ms = INT_MAX;
-#endif
-
#ifdef USE_WINSOCK
/* WinSock select() can't handle zero events. See the comment below. */
if((!fds_read || fds_read->fd_count == 0) &&
(!fds_write || fds_write->fd_count == 0) &&
(!fds_err || fds_err->fd_count == 0)) {
- r = Curl_wait_ms((int)timeout_ms);
+ r = Curl_wait_ms(timeout_ms);
return r;
}
#endif
ptimeout = &pending_tv;
-
if(timeout_ms < 0) {
ptimeout = NULL;
}
else if(timeout_ms > 0) {
- pending_ms = (int)timeout_ms;
- pending_tv.tv_sec = pending_ms / 1000;
- pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+ timediff_t tv_sec = timeout_ms / 1000;
+ timediff_t tv_usec = (timeout_ms % 1000) * 1000; /* max=999999 */
+#ifdef HAVE_SUSECONDS_T
+#if TIMEDIFF_T_MAX > TIME_T_MAX
+ /* tv_sec overflow check in case time_t is signed */
+ if(tv_sec > TIME_T_MAX)
+ tv_sec = TIME_T_MAX;
+#endif
+ pending_tv.tv_sec = (time_t)tv_sec;
+ pending_tv.tv_usec = (suseconds_t)tv_usec;
+#elif defined(WIN32) /* maybe also others in the future */
+#if TIMEDIFF_T_MAX > LONG_MAX
+ /* tv_sec overflow check on Windows there we know it is long */
+ if(tv_sec > LONG_MAX)
+ tv_sec = LONG_MAX;
+#endif
+ pending_tv.tv_sec = (long)tv_sec;
+ pending_tv.tv_usec = (long)tv_usec;
+#else
+#if TIMEDIFF_T_MAX > INT_MAX
+ /* tv_sec overflow check in case time_t is signed */
+ if(tv_sec > INT_MAX)
+ tv_sec = INT_MAX;
+#endif
+ pending_tv.tv_sec = (int)tv_sec;
+ pending_tv.tv_usec = (int)tv_usec;
+#endif
}
- else if(!timeout_ms) {
+ else {
pending_tv.tv_sec = 0;
pending_tv.tv_usec = 0;
}
@@ -201,11 +245,10 @@ int Curl_select(curl_socket_t maxfd,
int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
curl_socket_t readfd1,
curl_socket_t writefd, /* socket to write to */
- timediff_t timeout_ms) /* milliseconds to wait */
+ timediff_t timeout_ms) /* milliseconds to wait */
{
#ifdef HAVE_POLL_FINE
struct pollfd pfd[3];
- int pending_ms;
int num;
#else
fd_set fds_read;
@@ -216,16 +259,10 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
int r;
int ret;
-#if SIZEOF_TIME_T != SIZEOF_INT
- /* wrap-around precaution */
- if(timeout_ms >= INT_MAX)
- timeout_ms = INT_MAX;
-#endif
-
if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
(writefd == CURL_SOCKET_BAD)) {
/* no sockets, just wait */
- r = Curl_wait_ms((int)timeout_ms);
+ r = Curl_wait_ms(timeout_ms);
return r;
}
@@ -256,18 +293,9 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
num++;
}
- if(timeout_ms > 0)
- pending_ms = (int)timeout_ms;
- else if(timeout_ms < 0)
- pending_ms = -1;
- else
- pending_ms = 0;
- r = poll(pfd, num, pending_ms);
-
- if(r < 0)
- return -1;
- if(r == 0)
- return 0;
+ r = Curl_poll(pfd, num, timeout_ms);
+ if(r <= 0)
+ return r;
ret = 0;
num = 0;
@@ -333,7 +361,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
curl_socket_t is unsigned in such cases and thus -1 is the largest
value).
*/
- r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, (time_t)timeout_ms);
+ r = Curl_select(maxfd, &fds_read, &fds_write, &fds_err, timeout_ms);
if(r < 0)
return -1;
@@ -379,7 +407,7 @@ int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
* 0 = timeout
* N = number of structures with non zero revent fields
*/
-int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms)
{
#ifdef HAVE_POLL_FINE
int pending_ms;
@@ -402,6 +430,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
}
}
if(fds_none) {
+ /* no sockets, just wait */
r = Curl_wait_ms(timeout_ms);
return r;
}
@@ -413,8 +442,13 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
#ifdef HAVE_POLL_FINE
+ /* prevent overflow, timeout_ms is typecast to int. */
+#if TIMEDIFF_T_MAX > INT_MAX
+ if(timeout_ms > INT_MAX)
+ timeout_ms = INT_MAX;
+#endif
if(timeout_ms > 0)
- pending_ms = timeout_ms;
+ pending_ms = (int)timeout_ms;
else if(timeout_ms < 0)
pending_ms = -1;
else
diff --git a/lib/select.h b/lib/select.h
index 0fd8ed51..95181f46 100644
--- a/lib/select.h
+++ b/lib/select.h
@@ -76,7 +76,7 @@ int Curl_select(curl_socket_t maxfd,
fd_set *fds_read,
fd_set *fds_write,
fd_set *fds_err,
- time_t timeout_ms);
+ timediff_t timeout_ms);
int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2,
curl_socket_t writefd,
@@ -86,12 +86,12 @@ int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2,
#define SOCKET_WRITABLE(x,z) \
Curl_socket_check(CURL_SOCKET_BAD, CURL_SOCKET_BAD, x, z)
-int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms);
-int Curl_wait_ms(int timeout_ms);
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms);
+int Curl_wait_ms(timediff_t timeout_ms);
#ifdef TPF
int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
- fd_set* excepts, struct timeval* tv);
+ fd_set* excepts, struct timeval *tv);
#endif
/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which
diff --git a/lib/sendf.c b/lib/sendf.c
index 6ef47aa8..6943fa84 100644
--- a/lib/sendf.c
+++ b/lib/sendf.c
@@ -267,7 +267,7 @@ void Curl_failf(struct Curl_easy *data, const char *fmt, ...)
size_t len;
char error[CURL_ERROR_SIZE + 2];
va_start(ap, fmt);
- mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
+ (void)mvsnprintf(error, CURL_ERROR_SIZE, fmt, ap);
len = strlen(error);
if(data->set.errorbuffer && !data->state.errorbuf) {
@@ -498,7 +498,6 @@ static CURLcode pausewrite(struct Curl_easy *data,
is again enabled */
struct SingleRequest *k = &data->req;
struct UrlState *s = &data->state;
- char *dupl;
unsigned int i;
bool newtype = TRUE;
@@ -518,44 +517,21 @@ static CURLcode pausewrite(struct Curl_easy *data,
else
i = 0;
- if(!newtype) {
- /* append new data to old data */
-
- /* figure out the new size of the data to save */
- size_t newlen = len + s->tempwrite[i].len;
- /* allocate the new memory area */
- char *newptr = realloc(s->tempwrite[i].buf, newlen);
- if(!newptr)
- return CURLE_OUT_OF_MEMORY;
- /* copy the new data to the end of the new area */
- memcpy(newptr + s->tempwrite[i].len, ptr, len);
-
- /* update the pointer and the size */
- s->tempwrite[i].buf = newptr;
- s->tempwrite[i].len = newlen;
-
- len = newlen; /* for the debug output below */
- }
- else {
- dupl = Curl_memdup(ptr, len);
- if(!dupl)
- return CURLE_OUT_OF_MEMORY;
-
+ if(newtype) {
/* store this information in the state struct for later use */
- s->tempwrite[i].buf = dupl;
- s->tempwrite[i].len = len;
+ Curl_dyn_init(&s->tempwrite[i].b, DYN_PAUSE_BUFFER);
s->tempwrite[i].type = type;
if(newtype)
s->tempcount++;
}
+ if(Curl_dyn_addn(&s->tempwrite[i].b, (unsigned char *)ptr, len))
+ return CURLE_OUT_OF_MEMORY;
+
/* mark the connection as RECV paused */
k->keepon |= KEEP_RECV_PAUSE;
- DEBUGF(infof(data, "Paused %zu bytes in buffer for type %02x\n",
- len, type));
-
return CURLE_OK;
}
@@ -617,7 +593,7 @@ static CURLcode chop_write(struct connectdata *conn,
return pausewrite(data, type, ptr, len);
}
if(wrote != chunklen) {
- failf(data, "Failed writing body (%zu != %zu)", wrote, chunklen);
+ failf(data, "Failure writing output to destination");
return CURLE_WRITE_ERROR;
}
}
diff --git a/lib/setopt.c b/lib/setopt.c
index 04785a68..90edf6aa 100644
--- a/lib/setopt.c
+++ b/lib/setopt.c
@@ -77,6 +77,37 @@ CURLcode Curl_setstropt(char **charp, const char *s)
return CURLE_OK;
}
+CURLcode Curl_setblobopt(struct curl_blob **blobp,
+ const struct curl_blob *blob)
+{
+ /* free the previous storage at `blobp' and replace by a dynamic storage
+ copy of blob. If CURL_BLOB_COPY is set, the data is copied. */
+
+ Curl_safefree(*blobp);
+
+ if(blob) {
+ struct curl_blob *nblob;
+ if(blob->len > CURL_MAX_INPUT_LENGTH)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ nblob = (struct curl_blob *)
+ malloc(sizeof(struct curl_blob) +
+ ((blob->flags & CURL_BLOB_COPY) ? blob->len : 0));
+ if(!nblob)
+ return CURLE_OUT_OF_MEMORY;
+ *nblob = *blob;
+ if(blob->flags & CURL_BLOB_COPY) {
+ /* put the data after the blob struct in memory */
+ nblob->data = (char *)nblob + sizeof(struct curl_blob);
+ memcpy(nblob->data, blob->data, blob->len);
+ }
+
+ *blobp = nblob;
+ return CURLE_OK;
+ }
+
+ return CURLE_OK;
+}
+
static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
{
CURLcode result = CURLE_OK;
@@ -240,6 +271,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Do not include the body part in the output data stream.
*/
data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ if(data->set.opt_no_body)
+ /* in HTTP lingo, no body means using the HEAD request... */
+ data->set.method = HTTPREQ_HEAD;
break;
case CURLOPT_FAILONERROR:
/*
@@ -261,13 +295,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE;
if(data->set.upload) {
/* If this is HTTP, PUT is what's needed to "upload" */
- data->set.httpreq = HTTPREQ_PUT;
+ data->set.method = HTTPREQ_PUT;
data->set.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.httpreq = HTTPREQ_GET;
+ data->set.method = HTTPREQ_GET;
break;
case CURLOPT_REQUEST_TARGET:
result = Curl_setstropt(&data->set.str[STRING_TARGET],
@@ -363,7 +397,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
break;
case CURLOPT_SSLVERSION:
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLVERSION:
+#endif
/*
* Set explicit SSL version to try to connect with, as some SSL
* implementations are lame.
@@ -371,9 +407,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
#ifdef USE_SSL
{
long version, version_max;
- struct ssl_primary_config *primary = (option == CURLOPT_SSLVERSION ?
- &data->set.ssl.primary :
- &data->set.proxy_ssl.primary);
+ struct ssl_primary_config *primary = &data->set.ssl.primary;
+#ifndef CURL_DISABLE_PROXY
+ if(option != CURLOPT_SSLVERSION)
+ primary = &data->set.proxy_ssl.primary;
+#endif
arg = va_arg(param, long);
@@ -481,11 +519,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
CURLOPT_POSTFIELDS isn't used and the POST data is read off the
callback! */
if(va_arg(param, long)) {
- data->set.httpreq = HTTPREQ_POST;
+ data->set.method = HTTPREQ_POST;
data->set.opt_no_body = FALSE; /* this is implied */
}
else
- data->set.httpreq = HTTPREQ_GET;
+ data->set.method = HTTPREQ_GET;
break;
case CURLOPT_COPYPOSTFIELDS:
@@ -532,7 +570,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
}
data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
- data->set.httpreq = HTTPREQ_POST;
+ data->set.method = HTTPREQ_POST;
break;
case CURLOPT_POSTFIELDS:
@@ -542,7 +580,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.postfields = va_arg(param, void *);
/* Release old copied data. */
(void) Curl_setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
- data->set.httpreq = HTTPREQ_POST;
+ data->set.method = HTTPREQ_POST;
break;
case CURLOPT_POSTFIELDSIZE:
@@ -588,7 +626,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set to make us do HTTP POST
*/
data->set.httppost = va_arg(param, struct curl_httppost *);
- data->set.httpreq = HTTPREQ_POST_FORM;
+ data->set.method = HTTPREQ_POST_FORM;
data->set.opt_no_body = FALSE; /* this is implied */
break;
#endif /* CURL_DISABLE_HTTP */
@@ -600,7 +638,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_mime_set_subparts(&data->set.mimepost,
va_arg(param, curl_mime *), FALSE);
if(!result) {
- data->set.httpreq = HTTPREQ_POST_MIME;
+ data->set.method = HTTPREQ_POST_MIME;
data->set.opt_no_body = FALSE; /* this is implied */
}
break;
@@ -795,7 +833,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
* Set to force us do HTTP GET
*/
if(va_arg(param, long)) {
- data->set.httpreq = HTTPREQ_GET;
+ data->set.method = HTTPREQ_GET;
data->set.upload = FALSE; /* switch off upload */
data->set.opt_no_body = FALSE; /* this is implied */
}
@@ -905,7 +943,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
va_arg(param, char *));
/* we don't set
- data->set.httpreq = HTTPREQ_CUSTOM;
+ data->set.method = HTTPREQ_CUSTOM;
here, we continue as if we were using the already set type
and this just changes the actual request keyword */
break;
@@ -1606,6 +1644,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_CERT_ORIG],
va_arg(param, char *));
break;
+ case CURLOPT_SSLCERT_BLOB:
+ /*
+ * Blob that holds file name of the SSL certificate to use
+ */
+ result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_ORIG],
+ va_arg(param, struct curl_blob *));
+ break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLCERT:
/*
@@ -1614,6 +1659,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_CERT_PROXY],
va_arg(param, char *));
break;
+ case CURLOPT_PROXY_SSLCERT_BLOB:
+ /*
+ * Blob that holds file name of the SSL certificate to use for proxy
+ */
+ result = Curl_setblobopt(&data->set.blobs[BLOB_CERT_PROXY],
+ va_arg(param, struct curl_blob *));
+ break;
#endif
case CURLOPT_SSLCERTTYPE:
/*
@@ -1638,6 +1690,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_KEY_ORIG],
va_arg(param, char *));
break;
+ case CURLOPT_SSLKEY_BLOB:
+ /*
+ * Blob that holds file name of the SSL key to use
+ */
+ result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_ORIG],
+ va_arg(param, struct curl_blob *));
+ break;
#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_SSLKEY:
/*
@@ -1646,6 +1705,13 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_KEY_PROXY],
va_arg(param, char *));
break;
+ case CURLOPT_PROXY_SSLKEY_BLOB:
+ /*
+ * Blob that holds file name of the SSL key to use for proxy
+ */
+ result = Curl_setblobopt(&data->set.blobs[BLOB_KEY_PROXY],
+ va_arg(param, struct curl_blob *));
+ break;
#endif
case CURLOPT_SSLKEYTYPE:
/*
@@ -1970,6 +2036,30 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_ORIG],
va_arg(param, char *));
break;
+ case CURLOPT_ISSUERCERT_BLOB:
+ /*
+ * Blob that holds Issuer certificate to check certificates issuer
+ */
+ result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG],
+ va_arg(param, struct curl_blob *));
+ break;
+#ifndef CURL_DISABLE_PROXY
+ case CURLOPT_PROXY_ISSUERCERT:
+ /*
+ * Set Issuer certificate file
+ * to check certificates issuer
+ */
+ result = Curl_setstropt(&data->set.str[STRING_SSL_ISSUERCERT_PROXY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXY_ISSUERCERT_BLOB:
+ /*
+ * Blob that holds Issuer certificate to check certificates issuer
+ */
+ result = Curl_setblobopt(&data->set.blobs[BLOB_SSL_ISSUERCERT_PROXY],
+ va_arg(param, struct curl_blob *));
+ break;
+#endif
#ifndef CURL_DISABLE_TELNET
case CURLOPT_TELNETOPTIONS:
/*
@@ -1993,7 +2083,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
arg = READBUFFER_MIN;
/* Resize if new size */
- if(arg != data->set.buffer_size) {
+ if((arg != data->set.buffer_size) && data->state.buffer) {
char *newbuff = realloc(data->state.buffer, arg + 1);
if(!newbuff) {
DEBUGF(fprintf(stderr, "Error: realloc of buffer failed\n"));
@@ -2135,6 +2225,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
data->set.ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
data->set.ssl.revoke_best_effort = !!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
+ data->set.ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
break;
#ifndef CURL_DISABLE_PROXY
@@ -2144,6 +2235,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
(bool)((arg&CURLSSLOPT_ALLOW_BEAST) ? TRUE : FALSE);
data->set.proxy_ssl.no_revoke = !!(arg & CURLSSLOPT_NO_REVOKE);
data->set.proxy_ssl.no_partialchain = !!(arg & CURLSSLOPT_NO_PARTIALCHAIN);
+ data->set.proxy_ssl.native_ca_store = !!(arg & CURLSSLOPT_NATIVE_CA);
data->set.proxy_ssl.revoke_best_effort =
!!(arg & CURLSSLOPT_REVOKE_BEST_EFFORT);
break;
@@ -2248,7 +2340,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_SSL_SESSIONID_CACHE:
data->set.ssl.primary.sessionid = (0 != va_arg(param, long)) ?
TRUE : FALSE;
+#ifndef CURL_DISABLE_PROXY
data->set.proxy_ssl.primary.sessionid = data->set.ssl.primary.sessionid;
+#endif
break;
#ifdef USE_SSH
@@ -2550,9 +2644,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_PROXY_TLSAUTH_USERNAME:
result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_USERNAME_PROXY],
va_arg(param, char *));
+#ifndef CURL_DISABLE_PROXY
if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
!data->set.proxy_ssl.authtype)
data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+#endif
break;
case CURLOPT_TLSAUTH_PASSWORD:
result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_ORIG],
@@ -2563,9 +2659,11 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_PROXY_TLSAUTH_PASSWORD:
result = Curl_setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD_PROXY],
va_arg(param, char *));
+#ifndef CURL_DISABLE_PROXY
if(data->set.str[STRING_TLSAUTH_USERNAME_PROXY] &&
!data->set.proxy_ssl.authtype)
data->set.proxy_ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+#endif
break;
case CURLOPT_TLSAUTH_TYPE:
argptr = va_arg(param, char *);
@@ -2575,6 +2673,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
else
data->set.ssl.authtype = CURL_TLSAUTH_NONE;
break;
+#ifndef CURL_DISABLE_PROXY
case CURLOPT_PROXY_TLSAUTH_TYPE:
argptr = va_arg(param, char *);
if(!argptr ||
@@ -2584,6 +2683,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->set.proxy_ssl.authtype = CURL_TLSAUTH_NONE;
break;
#endif
+#endif
#ifdef USE_ARES
case CURLOPT_DNS_SERVERS:
result = Curl_setstropt(&data->set.str[STRING_DNS_SERVERS],
diff --git a/lib/setopt.h b/lib/setopt.h
index 5e347dd6..5fc4368d 100644
--- a/lib/setopt.h
+++ b/lib/setopt.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -23,6 +23,8 @@
***************************************************************************/
CURLcode Curl_setstropt(char **charp, const char *s);
+CURLcode Curl_setblobopt(struct curl_blob **blobp,
+ const struct curl_blob *blob);
CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list arg);
#endif /* HEADER_CURL_SETOPT_H */
diff --git a/lib/setup-os400.h b/lib/setup-os400.h
index 629fd94c..b693cb3b 100644
--- a/lib/setup-os400.h
+++ b/lib/setup-os400.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -200,10 +200,10 @@ extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,
/* Some socket functions must be wrapped to process textual addresses
like AF_UNIX. */
-extern int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen);
-extern int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen);
+extern int Curl_os400_connect(int sd, struct sockaddr *destaddr, int addrlen);
+extern int Curl_os400_bind(int sd, struct sockaddr *localaddr, int addrlen);
extern int Curl_os400_sendto(int sd, char *buffer, int buflen, int flags,
- struct sockaddr * dstaddr, int addrlen);
+ struct sockaddr *dstaddr, int addrlen);
extern int Curl_os400_recvfrom(int sd, char *buffer, int buflen, int flags,
struct sockaddr *fromaddr, int *addrlen);
extern int Curl_os400_getpeername(int sd, struct sockaddr *addr, int *addrlen);
diff --git a/lib/setup-vms.h b/lib/setup-vms.h
index 6c454aee..0e39c9f6 100644
--- a/lib/setup-vms.h
+++ b/lib/setup-vms.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -73,7 +73,7 @@ char *decc$getenv(const char *__name);
# endif
#endif
- struct passwd * decc_getpwuid(uid_t uid);
+ struct passwd *decc_getpwuid(uid_t uid);
#ifdef __DECC
# if __INITIAL_POINTER_SIZE == 32
@@ -138,9 +138,9 @@ static char *vms_getenv(const char *envvar)
static struct passwd vms_passwd_cache;
-static struct passwd * vms_getpwuid(uid_t uid)
+static struct passwd *vms_getpwuid(uid_t uid)
{
- struct passwd * my_passwd;
+ struct passwd *my_passwd;
/* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */
#ifdef __DECC
diff --git a/lib/sha256.c b/lib/sha256.c
index 00d98ce4..ee5d273c 100644
--- a/lib/sha256.c
+++ b/lib/sha256.c
@@ -196,10 +196,11 @@ static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
#include <wincrypt.h>
-typedef struct {
+struct sha256_ctx {
HCRYPTPROV hCryptProv;
HCRYPTHASH hHash;
-} SHA256_CTX;
+};
+typedef struct sha256_ctx SHA256_CTX;
#if !defined(CALG_SHA_256)
#define CALG_SHA_256 0x0000800c
@@ -222,7 +223,7 @@ static void SHA256_Update(SHA256_CTX *ctx,
static void SHA256_Final(unsigned char *digest, SHA256_CTX *ctx)
{
- unsigned long length;
+ unsigned long length = 0;
CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
if(length == SHA256_DIGEST_LENGTH)
@@ -280,7 +281,7 @@ do { \
} while(0)
#endif
-typedef struct sha256_state {
+struct sha256_state {
#ifdef HAVE_LONGLONG
unsigned long long length;
#else
@@ -288,7 +289,8 @@ typedef struct sha256_state {
#endif
unsigned long state[8], curlen;
unsigned char buf[64];
-} SHA256_CTX;
+};
+typedef struct sha256_state SHA256_CTX;
/* The K array */
static const unsigned long K[64] = {
diff --git a/lib/share.c b/lib/share.c
index 3d510861..a2d89604 100644
--- a/lib/share.c
+++ b/lib/share.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -70,7 +70,7 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
case CURLSHOPT_SHARE:
/* this is a type this share will share */
type = va_arg(param, int);
- share->specifier |= (1<<type);
+
switch(type) {
case CURL_LOCK_DATA_DNS:
break;
@@ -102,7 +102,7 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
#endif
break;
- case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
+ case CURL_LOCK_DATA_CONNECT:
if(Curl_conncache_init(&share->conn_cache, 103))
res = CURLSHE_NOMEM;
break;
@@ -116,6 +116,8 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
default:
res = CURLSHE_BAD_OPTION;
}
+ if(!res)
+ share->specifier |= (1<<type);
break;
case CURLSHOPT_UNSHARE:
diff --git a/lib/smb.c b/lib/smb.c
index 12f99257..d493adcc 100644
--- a/lib/smb.c
+++ b/lib/smb.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014, Bill Nagel <wnagel@tycoint.com>, Exacq Technologies
- * Copyright (C) 2016-2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2016-2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -964,7 +964,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
/* URL decode the path */
CURLcode result = Curl_urldecode(data, data->state.up.path, 0, &path, NULL,
- TRUE);
+ REJECT_CTRL);
if(result)
return result;
diff --git a/lib/smtp.c b/lib/smtp.c
index bf65f246..685513b3 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -183,7 +183,7 @@ static void smtp_to_smtps(struct connectdata *conn)
conn->handler = &Curl_handler_smtps;
/* Set the connection's upgraded to TLS flag */
- conn->tls_upgraded = TRUE;
+ conn->bits.tls_upgraded = TRUE;
}
#else
#define smtp_to_smtps(x) Curl_nop_stmt
@@ -1617,7 +1617,7 @@ static CURLcode smtp_setup_connection(struct connectdata *conn)
CURLcode result;
/* Clear the TLS upgraded flag */
- conn->tls_upgraded = FALSE;
+ conn->bits.tls_upgraded = FALSE;
/* Initialise the SMTP layer */
result = smtp_init(conn);
@@ -1689,7 +1689,8 @@ static CURLcode smtp_parse_url_path(struct connectdata *conn)
}
/* URL decode the path and use it as the domain in our EHLO */
- return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
+ return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL,
+ REJECT_CTRL);
}
/***********************************************************************
@@ -1707,7 +1708,7 @@ static CURLcode smtp_parse_custom_request(struct connectdata *conn)
/* URL decode the custom request */
if(custom)
- result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, TRUE);
+ result = Curl_urldecode(data, custom, 0, &smtp->custom, NULL, REJECT_CTRL);
return result;
}
diff --git a/lib/socks.c b/lib/socks.c
index 18affbc9..b2215fef 100644
--- a/lib/socks.c
+++ b/lib/socks.c
@@ -69,7 +69,7 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */
break;
}
if(!timeout_ms)
- timeout_ms = TIME_T_MAX;
+ timeout_ms = TIMEDIFF_T_MAX;
if(SOCKET_READABLE(sockfd, timeout_ms) <= 0) {
result = ~CURLE_OK;
break;
@@ -271,7 +271,7 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
/* FALLTHROUGH */
CONNECT_RESOLVED:
case CONNECT_RESOLVED: {
- Curl_addrinfo *hp = NULL;
+ struct Curl_addrinfo *hp = NULL;
char buf[64];
/*
* We cannot use 'hostent' as a struct that Curl_resolv() returns. It
@@ -382,6 +382,11 @@ CURLcode Curl_SOCKS4(const char *proxy_user,
curl_easy_strerror(result));
return CURLE_COULDNT_CONNECT;
}
+ else if(!result && !actualread) {
+ /* connection closed */
+ failf(data, "connection to proxy closed");
+ return CURLE_COULDNT_CONNECT;
+ }
else if(actualread != sx->outstanding) {
/* remain in reading state */
sx->outstanding -= actualread;
@@ -592,6 +597,11 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
failf(data, "Unable to receive initial SOCKS5 response.");
return CURLE_COULDNT_CONNECT;
}
+ else if(!result && !actualread) {
+ /* connection closed */
+ failf(data, "Connection to proxy closed");
+ return CURLE_COULDNT_CONNECT;
+ }
else if(actualread != sx->outstanding) {
/* remain in reading state */
sx->outstanding -= actualread;
@@ -633,11 +643,10 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
failf(data, "No authentication method was acceptable.");
return CURLE_COULDNT_CONNECT;
}
- failf(data,
- "Undocumented SOCKS5 mode attempted to be used by server.");
- return CURLE_COULDNT_CONNECT;
}
- break;
+ failf(data,
+ "Undocumented SOCKS5 mode attempted to be used by server.");
+ return CURLE_COULDNT_CONNECT;
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
case CONNECT_GSSAPI_INIT:
/* GSSAPI stuff done non-blocking */
@@ -718,15 +727,19 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
return CURLE_COULDNT_CONNECT;
}
- if(actualread != sx->outstanding) {
+ else if(!result && !actualread) {
+ /* connection closed */
+ failf(data, "connection to proxy closed");
+ return CURLE_COULDNT_CONNECT;
+ }
+ else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
sx->outp += actualread;
return CURLE_OK;
}
-
/* ignore the first (VER) byte */
- if(socksreq[1] != 0) { /* status */
+ else if(socksreq[1] != 0) { /* status */
failf(data, "User was rejected by the SOCKS5 server (%d %d).",
socksreq[0], socksreq[1]);
return CURLE_COULDNT_CONNECT;
@@ -773,7 +786,8 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
/* FALLTHROUGH */
CONNECT_RESOLVED:
case CONNECT_RESOLVED: {
- Curl_addrinfo *hp = NULL;
+ struct Curl_addrinfo *hp = NULL;
+ size_t destlen;
if(dns)
hp = dns->addr;
if(!hp) {
@@ -782,13 +796,9 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
return CURLE_COULDNT_RESOLVE_HOST;
}
- if(Curl_printable_address(hp, dest, sizeof(dest))) {
- size_t destlen = strlen(dest);
- msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port);
- }
- else {
- strcpy(dest, "unknown");
- }
+ Curl_printable_address(hp, dest, sizeof(dest));
+ destlen = strlen(dest);
+ msnprintf(dest + destlen, sizeof(dest) - destlen, ":%d", remote_port);
len = 0;
socksreq[len++] = 5; /* version (SOCKS5) */
@@ -894,6 +904,11 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
failf(data, "Failed to receive SOCKS5 connect request ack.");
return CURLE_COULDNT_CONNECT;
}
+ else if(!result && !actualread) {
+ /* connection closed */
+ failf(data, "connection to proxy closed");
+ return CURLE_COULDNT_CONNECT;
+ }
else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
@@ -938,6 +953,13 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
/* IPv6 */
len = 4 + 16 + 2;
}
+ else if(socksreq[3] == 1) {
+ len = 4 + 4 + 2;
+ }
+ else {
+ failf(data, "SOCKS5 reply has wrong address type.");
+ return CURLE_COULDNT_CONNECT;
+ }
/* At this point we already read first 10 bytes */
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
@@ -964,7 +986,12 @@ CURLcode Curl_SOCKS5(const char *proxy_user,
failf(data, "Failed to receive SOCKS5 connect request ack.");
return CURLE_COULDNT_CONNECT;
}
- if(actualread != sx->outstanding) {
+ else if(!result && !actualread) {
+ /* connection closed */
+ failf(data, "connection to proxy closed");
+ return CURLE_COULDNT_CONNECT;
+ }
+ else if(actualread != sx->outstanding) {
/* remain in state */
sx->outstanding -= actualread;
sx->outp += actualread;
diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c
index 7f66675f..2e36b994 100644
--- a/lib/socks_gssapi.c
+++ b/lib/socks_gssapi.c
@@ -115,7 +115,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER;
gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER;
- gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
+ gss_buffer_desc *gss_token = GSS_C_NO_BUFFER;
gss_name_t server = GSS_C_NO_NAME;
gss_name_t gss_client_name = GSS_C_NO_NAME;
unsigned short us_length;
@@ -328,7 +328,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
user[gss_send_token.length] = '\0';
gss_release_name(&gss_status, &gss_client_name);
gss_release_buffer(&gss_status, &gss_send_token);
- infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",user);
+ infof(data, "SOCKS5 server authenticated user %s with GSS-API.\n",user);
free(user);
user = NULL;
diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c
index d5be64a3..2f1fd36f 100644
--- a/lib/socks_sspi.c
+++ b/lib/socks_sspi.c
@@ -160,7 +160,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
for(;;) {
TCHAR *sname;
- sname = Curl_convert_UTF8_to_tchar(service_name);
+ sname = curlx_convert_UTF8_to_tchar(service_name);
if(!sname)
return CURLE_OUT_OF_MEMORY;
@@ -180,7 +180,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
&sspi_ret_flags,
&expiry);
- Curl_unicodefree(sname);
+ curlx_unicodefree(sname);
if(sspi_recv_token.pvBuffer) {
s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
@@ -327,7 +327,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
failf(data, "Failed to determine user name.");
return CURLE_COULDNT_CONNECT;
}
- infof(data, "SOCKS5 server authencticated user %s with GSS-API.\n",
+ infof(data, "SOCKS5 server authenticated user %s with GSS-API.\n",
names.sUserName);
s_pSecFn->FreeContextBuffer(names.sUserName);
diff --git a/lib/strerror.c b/lib/strerror.c
index 1a166bf0..015e588c 100644
--- a/lib/strerror.c
+++ b/lib/strerror.c
@@ -795,7 +795,7 @@ const char *Curl_strerror(int err, char *buf, size_t buflen)
#endif /* end of not Windows */
- buf[max] = '\0'; /* make sure the string is zero terminated */
+ buf[max] = '\0'; /* make sure the string is null-terminated */
/* strip trailing '\r\n' or '\n'. */
p = strrchr(buf, '\n');
diff --git a/lib/strtok.c b/lib/strtok.c
index be8f4812..ba6e0258 100644
--- a/lib/strtok.c
+++ b/lib/strtok.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -52,7 +52,7 @@ Curl_strtok_r(char *ptr, const char *sep, char **end)
if(**end) {
/* the end is not a null byte */
- **end = '\0'; /* zero terminate it! */
+ **end = '\0'; /* null-terminate it! */
++*end; /* advance the last pointer to beyond the null byte */
}
diff --git a/lib/telnet.c b/lib/telnet.c
index 4bf4c652..c3b58e54 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -1315,7 +1315,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done)
DWORD readfile_read;
int err;
#else
- int interval_ms;
+ timediff_t interval_ms;
struct pollfd pfd[2];
int poll_cnt;
curl_off_t total_dl = 0;
diff --git a/lib/tftp.c b/lib/tftp.c
index 346f293d..378d9560 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -115,11 +115,11 @@ typedef enum {
TFTP_ERR_NORESPONSE
} tftp_error_t;
-typedef struct tftp_packet {
+struct tftp_packet {
unsigned char *data;
-} tftp_packet_t;
+};
-typedef struct tftp_state_data {
+struct tftp_state_data {
tftp_state_t state;
tftp_mode_t mode;
tftp_error_t error;
@@ -140,21 +140,21 @@ typedef struct tftp_state_data {
int sbytes;
int blksize;
int requested_blksize;
- tftp_packet_t rpacket;
- tftp_packet_t spacket;
-} tftp_state_data_t;
+ struct tftp_packet rpacket;
+ struct tftp_packet spacket;
+};
/* Forward declarations */
-static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event);
-static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event);
+static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event);
+static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event);
static CURLcode tftp_connect(struct connectdata *conn, bool *done);
static CURLcode tftp_disconnect(struct connectdata *conn,
bool dead_connection);
static CURLcode tftp_do(struct connectdata *conn, bool *done);
static CURLcode tftp_done(struct connectdata *conn,
CURLcode, bool premature);
-static CURLcode tftp_setup_connection(struct connectdata * conn);
+static CURLcode tftp_setup_connection(struct connectdata *conn);
static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks);
@@ -196,7 +196,7 @@ const struct Curl_handler Curl_handler_tftp = {
*
*
**********************************************************/
-static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
+static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
{
time_t maxtime, timeout;
timediff_t timeout_ms;
@@ -279,25 +279,25 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
*
**********************************************************/
-static void setpacketevent(tftp_packet_t *packet, unsigned short num)
+static void setpacketevent(struct tftp_packet *packet, unsigned short num)
{
packet->data[0] = (unsigned char)(num >> 8);
packet->data[1] = (unsigned char)(num & 0xff);
}
-static void setpacketblock(tftp_packet_t *packet, unsigned short num)
+static void setpacketblock(struct tftp_packet *packet, unsigned short num)
{
packet->data[2] = (unsigned char)(num >> 8);
packet->data[3] = (unsigned char)(num & 0xff);
}
-static unsigned short getrpacketevent(const tftp_packet_t *packet)
+static unsigned short getrpacketevent(const struct tftp_packet *packet)
{
return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
}
-static unsigned short getrpacketblock(const tftp_packet_t *packet)
+static unsigned short getrpacketblock(const struct tftp_packet *packet)
{
return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
}
@@ -330,7 +330,7 @@ static const char *tftp_option_get(const char *buf, size_t len,
return &buf[loc];
}
-static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
+static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
const char *ptr, int len)
{
const char *tmp = ptr;
@@ -403,7 +403,7 @@ static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
return CURLE_OK;
}
-static CURLcode tftp_option_add(tftp_state_data_t *state, size_t *csize,
+static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
char *buf, const char *option)
{
if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
@@ -413,7 +413,7 @@ static CURLcode tftp_option_add(tftp_state_data_t *state, size_t *csize,
return CURLE_OK;
}
-static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
+static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
tftp_event_t event)
{
CURLcode result;
@@ -429,7 +429,7 @@ static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
return tftp_tx(state, event);
}
-static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
+static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
tftp_event_t event)
{
CURLcode result;
@@ -445,7 +445,8 @@ static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
return tftp_rx(state, event);
}
-static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
+static CURLcode tftp_send_first(struct tftp_state_data *state,
+ tftp_event_t event)
{
size_t sbytes;
ssize_t senddata;
@@ -486,7 +487,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
file name so we skip the always-present first letter of the path
string. */
result = Curl_urldecode(data, &state->conn->data->state.up.path[1], 0,
- &filename, NULL, FALSE);
+ &filename, NULL, REJECT_ZERO);
if(result)
return result;
@@ -598,7 +599,8 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
* Event handler for the RX state
*
**********************************************************/
-static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
+static CURLcode tftp_rx(struct tftp_state_data *state,
+ tftp_event_t event)
{
ssize_t sbytes;
int rblock;
@@ -720,7 +722,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
* Event handler for the TX state
*
**********************************************************/
-static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
+static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
{
struct Curl_easy *data = state->conn->data;
ssize_t sbytes;
@@ -920,7 +922,7 @@ static CURLcode tftp_translate_code(tftp_error_t error)
* The tftp state machine event dispatcher
*
**********************************************************/
-static CURLcode tftp_state_machine(tftp_state_data_t *state,
+static CURLcode tftp_state_machine(struct tftp_state_data *state,
tftp_event_t event)
{
CURLcode result = CURLE_OK;
@@ -961,7 +963,7 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state,
**********************************************************/
static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
{
- tftp_state_data_t *state = conn->proto.tftpc;
+ struct tftp_state_data *state = conn->proto.tftpc;
(void) dead_connection;
/* done, free dynamically allocated pkt buffers */
@@ -983,13 +985,13 @@ static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
**********************************************************/
static CURLcode tftp_connect(struct connectdata *conn, bool *done)
{
- tftp_state_data_t *state;
+ struct tftp_state_data *state;
int blksize;
int need_blksize;
blksize = TFTP_BLKSIZE_DEFAULT;
- state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
+ state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data));
if(!state)
return CURLE_OUT_OF_MEMORY;
@@ -1078,7 +1080,7 @@ static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
bool premature)
{
CURLcode result = CURLE_OK;
- tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ struct tftp_state_data *state = conn->proto.tftpc;
(void)status; /* unused */
(void)premature; /* not used */
@@ -1119,7 +1121,7 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
curl_socklen_t fromlen;
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
- tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ struct tftp_state_data *state = conn->proto.tftpc;
struct SingleRequest *k = &data->req;
/* Receive the packet */
@@ -1206,8 +1208,8 @@ static CURLcode tftp_receive_packet(struct connectdata *conn)
**********************************************************/
static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
{
- time_t current;
- tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ time_t current;
+ struct tftp_state_data *state = conn->proto.tftpc;
if(event)
*event = TFTP_EVENT_NONE;
@@ -1244,7 +1246,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
tftp_event_t event;
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
- tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ struct tftp_state_data *state = conn->proto.tftpc;
long timeout_ms = tftp_state_timeout(conn, &event);
*done = FALSE;
@@ -1328,7 +1330,7 @@ static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
{
CURLcode result = CURLE_OK;
- tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ struct tftp_state_data *state = conn->proto.tftpc;
*dophase_done = FALSE;
@@ -1358,7 +1360,7 @@ static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
static CURLcode tftp_do(struct connectdata *conn, bool *done)
{
- tftp_state_data_t *state;
+ struct tftp_state_data *state;
CURLcode result;
*done = FALSE;
@@ -1369,7 +1371,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
return result;
}
- state = (tftp_state_data_t *)conn->proto.tftpc;
+ state = conn->proto.tftpc;
if(!state)
return CURLE_TFTP_ILLEGAL;
@@ -1384,7 +1386,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
return result;
}
-static CURLcode tftp_setup_connection(struct connectdata * conn)
+static CURLcode tftp_setup_connection(struct connectdata *conn)
{
struct Curl_easy *data = conn->data;
char *type;
diff --git a/lib/transfer.c b/lib/transfer.c
index b9581d7a..133a4783 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -128,12 +128,13 @@ static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems,
void *raw)
{
struct Curl_easy *data = (struct Curl_easy *)raw;
- Curl_send_buffer *trailers_buf = data->state.trailers_buf;
- size_t bytes_left = trailers_buf->size_used-data->state.trailers_bytes_sent;
+ struct dynbuf *trailers_buf = &data->state.trailers_buf;
+ size_t bytes_left = Curl_dyn_len(trailers_buf) -
+ data->state.trailers_bytes_sent;
size_t to_copy = (size*nitems < bytes_left) ? size*nitems : bytes_left;
if(to_copy) {
memcpy(buffer,
- &trailers_buf->buffer[data->state.trailers_bytes_sent],
+ Curl_dyn_ptr(trailers_buf) + data->state.trailers_bytes_sent,
to_copy);
data->state.trailers_bytes_sent += to_copy;
}
@@ -143,8 +144,8 @@ static size_t Curl_trailers_read(char *buffer, size_t size, size_t nitems,
static size_t Curl_trailers_left(void *raw)
{
struct Curl_easy *data = (struct Curl_easy *)raw;
- Curl_send_buffer *trailers_buf = data->state.trailers_buf;
- return trailers_buf->size_used - data->state.trailers_bytes_sent;
+ struct dynbuf *trailers_buf = &data->state.trailers_buf;
+ return Curl_dyn_len(trailers_buf) - data->state.trailers_bytes_sent;
}
#endif
@@ -186,11 +187,8 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
infof(data,
"Moving trailers state machine from initialized to sending.\n");
data->state.trailers_state = TRAILERS_SENDING;
- data->state.trailers_buf = Curl_add_buffer_init();
- if(!data->state.trailers_buf) {
- failf(data, "Unable to allocate trailing headers buffer !");
- return CURLE_OUT_OF_MEMORY;
- }
+ Curl_dyn_init(&data->state.trailers_buf, DYN_TRAILERS);
+
data->state.trailers_bytes_sent = 0;
Curl_set_in_callback(data, true);
trailers_ret_code = data->set.trailer_callback(&trailers,
@@ -206,7 +204,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
result = CURLE_ABORTED_BY_CALLBACK;
}
if(result) {
- Curl_add_buffer_free(&data->state.trailers_buf);
+ Curl_dyn_free(&data->state.trailers_buf);
curl_slist_free_all(trailers);
return result;
}
@@ -369,7 +367,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
#ifndef CURL_DISABLE_HTTP
if(data->state.trailers_state == TRAILERS_SENDING &&
!Curl_trailers_left(data)) {
- Curl_add_buffer_free(&data->state.trailers_buf);
+ Curl_dyn_free(&data->state.trailers_buf);
data->state.trailers_state = TRAILERS_DONE;
data->set.trailer_data = NULL;
data->set.trailer_callback = NULL;
@@ -435,8 +433,8 @@ CURLcode Curl_readrewind(struct connectdata *conn)
}
if(data->set.postfields)
; /* do nothing */
- else if(data->set.httpreq == HTTPREQ_POST_MIME ||
- data->set.httpreq == HTTPREQ_POST_FORM) {
+ else if(data->state.httpreq == HTTPREQ_POST_MIME ||
+ data->state.httpreq == HTTPREQ_POST_FORM) {
if(Curl_mime_rewind(mimepart)) {
failf(data, "Cannot rewind mime/post data");
return CURLE_SEND_FAIL_REWIND;
@@ -560,6 +558,8 @@ static CURLcode readwrite_data(struct Curl_easy *data,
size_t excess = 0; /* excess bytes read */
bool readmore = FALSE; /* used by RTP to signal for more data */
int maxloops = 100;
+ char *buf = data->state.buffer;
+ DEBUGASSERT(buf);
*done = FALSE;
*comeback = FALSE;
@@ -594,7 +594,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if(bytestoread) {
/* receive data from the network! */
- result = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread);
+ result = Curl_read(conn, conn->sockfd, buf, bytestoread, &nread);
/* read would've blocked */
if(CURLE_AGAIN == result)
@@ -621,9 +621,8 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* indicates data of zero size, i.e. empty file */
is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE;
- /* NUL terminate, allowing string ops to be used */
if(0 < nread || is_empty_data) {
- k->buf[nread] = 0;
+ buf[nread] = 0;
}
else {
/* if we receive 0 or less here, either the http2 stream is closed or the
@@ -640,7 +639,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* Default buffer to use when we write the buffer, it may be changed
in the flow below before the actual storing is done. */
- k->str = k->buf;
+ k->str = buf;
if(conn->handler->readwrite) {
result = conn->handler->readwrite(data, conn, &nread, &readmore);
@@ -689,7 +688,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* This is not an 'else if' since it may be a rest from the header
parsing, where the beginning of the buffer is headers and the end
is non-headers. */
- if(k->str && !k->header && (nread > 0 || is_empty_data)) {
+ if(!k->header && (nread > 0 || is_empty_data)) {
if(data->set.opt_no_body) {
/* data arrives although we want none, bail out */
@@ -720,7 +719,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
infof(data, "Ignoring the response-body\n");
}
if(data->state.resume_from && !k->content_range &&
- (data->set.httpreq == HTTPREQ_GET) &&
+ (data->state.httpreq == HTTPREQ_GET) &&
!k->ignorebody) {
if(k->size == data->state.resume_from) {
@@ -770,8 +769,9 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* pass data to the debug function before it gets "dechunked" */
if(data->set.verbose) {
if(k->badheader) {
- Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
- (size_t)k->hbuflen);
+ Curl_debug(data, CURLINFO_DATA_IN,
+ Curl_dyn_ptr(&data->state.headerb),
+ Curl_dyn_len(&data->state.headerb));
if(k->badheader == HEADER_PARTHEADER)
Curl_debug(data, CURLINFO_DATA_IN,
k->str, (size_t)nread);
@@ -822,9 +822,9 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* Account for body content stored in the header buffer */
if((k->badheader == HEADER_PARTHEADER) && !k->ignorebody) {
- DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n",
- k->hbuflen));
- k->bytecount += k->hbuflen;
+ size_t headlen = Curl_dyn_len(&data->state.headerb);
+ DEBUGF(infof(data, "Increasing bytecount by %zu\n", headlen));
+ k->bytecount += headlen;
}
if((-1 != k->maxdownload) &&
@@ -839,6 +839,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
", maxdownload = %" CURL_FORMAT_CURL_OFF_T
", bytecount = %" CURL_FORMAT_CURL_OFF_T "\n",
excess, k->size, k->maxdownload, k->bytecount);
+ connclose(conn, "excess found in a read");
}
nread = (ssize_t) (k->maxdownload - k->bytecount);
@@ -858,15 +859,16 @@ static CURLcode readwrite_data(struct Curl_easy *data,
if(k->badheader && !k->ignorebody) {
/* we parsed a piece of data wrongly assuming it was a header
and now we output it as body instead */
+ size_t headlen = Curl_dyn_len(&data->state.headerb);
/* Don't let excess data pollute body writes */
- if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload)
+ if(k->maxdownload == -1 || (curl_off_t)headlen <= k->maxdownload)
result = Curl_client_write(conn, CLIENTWRITE_BODY,
- data->state.headerbuff,
- k->hbuflen);
+ Curl_dyn_ptr(&data->state.headerb),
+ headlen);
else
result = Curl_client_write(conn, CLIENTWRITE_BODY,
- data->state.headerbuff,
+ Curl_dyn_ptr(&data->state.headerb),
(size_t)k->maxdownload);
if(result)
@@ -904,10 +906,10 @@ static CURLcode readwrite_data(struct Curl_easy *data,
/* Parse the excess data */
k->str += nread;
- if(&k->str[excess] > &k->buf[data->set.buffer_size]) {
+ if(&k->str[excess] > &buf[data->set.buffer_size]) {
/* the excess amount was too excessive(!), make sure
it doesn't read out of buffer */
- excess = &k->buf[data->set.buffer_size] - k->str;
+ excess = &buf[data->set.buffer_size] - k->str;
}
nread = (ssize_t)excess;
@@ -1447,6 +1449,7 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
}
}
+ data->state.httpreq = data->set.method;
data->change.url = data->set.str[STRING_SET_URL];
/* Init the SSL session ID cache here. We do it here since we want to do it
@@ -1466,12 +1469,11 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
data->state.authhost.want = data->set.httpauth;
data->state.authproxy.want = data->set.proxyauth;
Curl_safefree(data->info.wouldredirect);
- data->info.wouldredirect = NULL;
- if(data->set.httpreq == HTTPREQ_PUT)
+ if(data->state.httpreq == HTTPREQ_PUT)
data->state.infilesize = data->set.filesize;
- else if((data->set.httpreq != HTTPREQ_GET) &&
- (data->set.httpreq != HTTPREQ_HEAD)) {
+ else if((data->state.httpreq != HTTPREQ_GET) &&
+ (data->state.httpreq != HTTPREQ_HEAD)) {
data->state.infilesize = data->set.postfieldsize;
if(data->set.postfields && (data->state.infilesize == -1))
data->state.infilesize = (curl_off_t)strlen(data->set.postfields);
@@ -1682,12 +1684,12 @@ CURLcode Curl_follow(struct Curl_easy *data,
* This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and
* can be overridden with CURLOPT_POSTREDIR.
*/
- if((data->set.httpreq == HTTPREQ_POST
- || data->set.httpreq == HTTPREQ_POST_FORM
- || data->set.httpreq == HTTPREQ_POST_MIME)
+ if((data->state.httpreq == HTTPREQ_POST
+ || data->state.httpreq == HTTPREQ_POST_FORM
+ || data->state.httpreq == HTTPREQ_POST_MIME)
&& !(data->set.keep_post & CURL_REDIR_POST_301)) {
infof(data, "Switch from POST to GET\n");
- data->set.httpreq = HTTPREQ_GET;
+ data->state.httpreq = HTTPREQ_GET;
}
break;
case 302: /* Found */
@@ -1707,12 +1709,12 @@ CURLcode Curl_follow(struct Curl_easy *data,
* This behaviour is forbidden by RFC1945 and the obsolete RFC2616, and
* can be overridden with CURLOPT_POSTREDIR.
*/
- if((data->set.httpreq == HTTPREQ_POST
- || data->set.httpreq == HTTPREQ_POST_FORM
- || data->set.httpreq == HTTPREQ_POST_MIME)
+ if((data->state.httpreq == HTTPREQ_POST
+ || data->state.httpreq == HTTPREQ_POST_FORM
+ || data->state.httpreq == HTTPREQ_POST_MIME)
&& !(data->set.keep_post & CURL_REDIR_POST_302)) {
infof(data, "Switch from POST to GET\n");
- data->set.httpreq = HTTPREQ_GET;
+ data->state.httpreq = HTTPREQ_GET;
}
break;
@@ -1722,12 +1724,12 @@ CURLcode Curl_follow(struct Curl_easy *data,
* method is POST and the user specified to keep it as POST.
* https://github.com/curl/curl/issues/5237#issuecomment-614641049
*/
- if(data->set.httpreq != HTTPREQ_GET &&
- ((data->set.httpreq != HTTPREQ_POST &&
- data->set.httpreq != HTTPREQ_POST_FORM &&
- data->set.httpreq != HTTPREQ_POST_MIME) ||
+ if(data->state.httpreq != HTTPREQ_GET &&
+ ((data->state.httpreq != HTTPREQ_POST &&
+ data->state.httpreq != HTTPREQ_POST_FORM &&
+ data->state.httpreq != HTTPREQ_POST_MIME) ||
!(data->set.keep_post & CURL_REDIR_POST_303))) {
- data->set.httpreq = HTTPREQ_GET;
+ data->state.httpreq = HTTPREQ_GET;
data->set.upload = false;
infof(data, "Switch to %s\n",
data->set.opt_no_body?"HEAD":"GET");
diff --git a/lib/url.c b/lib/url.c
index 03c27443..a1a6b691 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -122,6 +122,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "strdup.h"
#include "setopt.h"
#include "altsvc.h"
+#include "dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -141,19 +142,21 @@ static unsigned int get_protocol_family(unsigned int protocol);
/*
- * Protocol table.
+ * Protocol table. Schemes (roughly) in 2019 popularity order:
+ *
+ * HTTPS, HTTP, FTP, FTPS, SFTP, FILE, SCP, SMTP, LDAP, IMAPS, TELNET, IMAP,
+ * LDAPS, SMTPS, TFTP, SMB, POP3, GOPHER POP3S, RTSP, RTMP, SMBS, DICT
*/
-
static const struct Curl_handler * const protocols[] = {
-#ifndef CURL_DISABLE_HTTP
- &Curl_handler_http,
-#endif
-
#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
&Curl_handler_https,
#endif
+#ifndef CURL_DISABLE_HTTP
+ &Curl_handler_http,
+#endif
+
#ifndef CURL_DISABLE_FTP
&Curl_handler_ftp,
#endif
@@ -162,12 +165,23 @@ static const struct Curl_handler * const protocols[] = {
&Curl_handler_ftps,
#endif
-#ifndef CURL_DISABLE_TELNET
- &Curl_handler_telnet,
+#if defined(USE_SSH)
+ &Curl_handler_sftp,
#endif
-#ifndef CURL_DISABLE_DICT
- &Curl_handler_dict,
+#ifndef CURL_DISABLE_FILE
+ &Curl_handler_file,
+#endif
+
+#if defined(USE_SSH) && !defined(USE_WOLFSSH)
+ &Curl_handler_scp,
+#endif
+
+#ifndef CURL_DISABLE_SMTP
+ &Curl_handler_smtp,
+#ifdef USE_SSL
+ &Curl_handler_smtps,
+#endif
#endif
#ifndef CURL_DISABLE_LDAP
@@ -179,22 +193,6 @@ static const struct Curl_handler * const protocols[] = {
#endif
#endif
-#ifndef CURL_DISABLE_FILE
- &Curl_handler_file,
-#endif
-
-#ifndef CURL_DISABLE_TFTP
- &Curl_handler_tftp,
-#endif
-
-#if defined(USE_SSH) && !defined(USE_WOLFSSH)
- &Curl_handler_scp,
-#endif
-
-#if defined(USE_SSH)
- &Curl_handler_sftp,
-#endif
-
#ifndef CURL_DISABLE_IMAP
&Curl_handler_imap,
#ifdef USE_SSL
@@ -202,6 +200,14 @@ static const struct Curl_handler * const protocols[] = {
#endif
#endif
+#ifndef CURL_DISABLE_TELNET
+ &Curl_handler_telnet,
+#endif
+
+#ifndef CURL_DISABLE_TFTP
+ &Curl_handler_tftp,
+#endif
+
#ifndef CURL_DISABLE_POP3
&Curl_handler_pop3,
#ifdef USE_SSL
@@ -218,25 +224,18 @@ static const struct Curl_handler * const protocols[] = {
#endif
#endif
-#ifndef CURL_DISABLE_SMTP
- &Curl_handler_smtp,
-#ifdef USE_SSL
- &Curl_handler_smtps,
-#endif
-#endif
-
#ifndef CURL_DISABLE_RTSP
&Curl_handler_rtsp,
#endif
-#ifndef CURL_DISABLE_GOPHER
- &Curl_handler_gopher,
-#endif
-
#ifdef CURL_ENABLE_MQTT
&Curl_handler_mqtt,
#endif
+#ifndef CURL_DISABLE_GOPHER
+ &Curl_handler_gopher,
+#endif
+
#ifdef USE_LIBRTMP
&Curl_handler_rtmp,
&Curl_handler_rtmpt,
@@ -246,6 +245,10 @@ static const struct Curl_handler * const protocols[] = {
&Curl_handler_rtmpts,
#endif
+#ifndef CURL_DISABLE_DICT
+ &Curl_handler_dict,
+#endif
+
(struct Curl_handler *) NULL
};
@@ -278,10 +281,16 @@ void Curl_freeset(struct Curl_easy *data)
{
/* Free all dynamic strings stored in the data->set substructure. */
enum dupstring i;
+ enum dupblob j;
+
for(i = (enum dupstring)0; i < STRING_LAST; i++) {
Curl_safefree(data->set.str[i]);
}
+ for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
+ Curl_safefree(data->set.blobs[j]);
+ }
+
if(data->change.referer_alloc) {
Curl_safefree(data->change.referer);
data->change.referer_alloc = FALSE;
@@ -380,7 +389,7 @@ CURLcode Curl_close(struct Curl_easy **datap)
up_free(data);
Curl_safefree(data->state.buffer);
- Curl_safefree(data->state.headerbuff);
+ Curl_dyn_free(&data->state.headerb);
Curl_safefree(data->state.ulbuf);
Curl_flush_cookies(data, TRUE);
#ifdef USE_ALTSVC
@@ -407,9 +416,20 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
+ Curl_safefree(data->state.aptr.proxyuserpwd);
+ 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);
+ Curl_safefree(data->state.aptr.cookiehost);
+ Curl_safefree(data->state.aptr.rtsp_transport);
+
#ifndef CURL_DISABLE_DOH
- free(data->req.doh.probe[0].serverdoh.memory);
- free(data->req.doh.probe[1].serverdoh.memory);
+ Curl_dyn_free(&data->req.doh.probe[0].serverdoh);
+ Curl_dyn_free(&data->req.doh.probe[1].serverdoh);
curl_slist_free_all(data->req.doh.headers);
#endif
@@ -453,7 +473,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->postfieldsize = -1; /* unknown size */
set->maxredirs = -1; /* allow any amount by default */
- set->httpreq = HTTPREQ_GET; /* Default HTTP request */
+ set->method = HTTPREQ_GET; /* Default HTTP request */
set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
#ifndef CURL_DISABLE_FTP
set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
@@ -492,7 +512,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
type */
set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by
default */
+#ifndef CURL_DISABLE_PROXY
set->proxy_ssl = set->ssl;
+#endif
set->new_file_perms = 0644; /* Default permissions */
set->new_directory_perms = 0755; /* Default permissions */
@@ -601,38 +623,22 @@ CURLcode Curl_open(struct Curl_easy **curl)
return result;
}
- /* We do some initial setup here, all those fields that can't be just 0 */
-
- data->state.buffer = malloc(READBUFFER_SIZE + 1);
- if(!data->state.buffer) {
- DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n"));
- result = CURLE_OUT_OF_MEMORY;
- }
- else {
- data->state.headerbuff = malloc(HEADERSIZE);
- if(!data->state.headerbuff) {
- DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
- result = CURLE_OUT_OF_MEMORY;
- }
- else {
- result = Curl_init_userdefined(data);
-
- data->state.headersize = HEADERSIZE;
- Curl_convert_init(data);
- Curl_initinfo(data);
+ result = Curl_init_userdefined(data);
+ if(!result) {
+ Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
+ Curl_convert_init(data);
+ Curl_initinfo(data);
- /* most recent connection is not yet defined */
- data->state.lastconnect = NULL;
+ /* most recent connection is not yet defined */
+ data->state.lastconnect = NULL;
- data->progress.flags |= PGRS_HIDE;
- data->state.current_speed = -1; /* init to negative == impossible */
- }
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
}
if(result) {
Curl_resolver_cleanup(data->state.resolver);
- free(data->state.buffer);
- free(data->state.headerbuff);
+ Curl_dyn_free(&data->state.headerb);
Curl_freeset(data);
free(data);
data = NULL;
@@ -684,9 +690,7 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
static void conn_shutdown(struct connectdata *conn)
{
- if(!conn)
- return;
-
+ DEBUGASSERT(conn);
infof(conn->data, "Closing connection %ld\n", conn->connection_id);
DEBUGASSERT(conn->data);
@@ -707,54 +711,40 @@ static void conn_shutdown(struct connectdata *conn)
Curl_closesocket(conn, conn->tempsock[0]);
if(CURL_SOCKET_BAD != conn->tempsock[1])
Curl_closesocket(conn, conn->tempsock[1]);
-
- /* unlink ourselves. this should be called last since other shutdown
- procedures need a valid conn->data and this may clear it. */
- Curl_conncache_remove_conn(conn->data, conn, TRUE);
}
static void conn_free(struct connectdata *conn)
{
- if(!conn)
- return;
+ DEBUGASSERT(conn);
Curl_free_idnconverted_hostname(&conn->host);
Curl_free_idnconverted_hostname(&conn->conn_to_host);
+#ifndef CURL_DISABLE_PROXY
Curl_free_idnconverted_hostname(&conn->http_proxy.host);
Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
-
- Curl_safefree(conn->user);
- Curl_safefree(conn->passwd);
- Curl_safefree(conn->sasl_authzid);
- Curl_safefree(conn->options);
Curl_safefree(conn->http_proxy.user);
Curl_safefree(conn->socks_proxy.user);
Curl_safefree(conn->http_proxy.passwd);
Curl_safefree(conn->socks_proxy.passwd);
- Curl_safefree(conn->allocptr.proxyuserpwd);
- Curl_safefree(conn->allocptr.uagent);
- Curl_safefree(conn->allocptr.userpwd);
- Curl_safefree(conn->allocptr.accept_encoding);
- Curl_safefree(conn->allocptr.te);
- Curl_safefree(conn->allocptr.rangeline);
- Curl_safefree(conn->allocptr.ref);
- Curl_safefree(conn->allocptr.host);
- Curl_safefree(conn->allocptr.cookiehost);
- Curl_safefree(conn->allocptr.rtsp_transport);
- Curl_safefree(conn->trailer);
+ Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
+ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
+ Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
+#endif
+ Curl_safefree(conn->user);
+ Curl_safefree(conn->passwd);
+ Curl_safefree(conn->sasl_authzid);
+ Curl_safefree(conn->options);
+ Curl_dyn_free(&conn->trailer);
Curl_safefree(conn->host.rawalloc); /* host name buffer */
Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
- Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
- Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
Curl_safefree(conn->connect_state);
conn_reset_all_postponed_data(conn);
Curl_llist_destroy(&conn->easyq, NULL);
Curl_safefree(conn->localdev);
Curl_free_primary_ssl_config(&conn->ssl_config);
- Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
#ifdef USE_UNIX_SOCKETS
Curl_safefree(conn->unix_domain_socket);
@@ -783,13 +773,17 @@ static void conn_free(struct connectdata *conn)
CURLcode Curl_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead_connection)
{
- if(!conn)
- return CURLE_OK; /* this is closed and fine already */
+ /* there must be a connection to close */
+ DEBUGASSERT(conn);
- if(!data) {
- DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n"));
- return CURLE_OK;
- }
+ /* it must be removed from the connection cache */
+ DEBUGASSERT(!conn->bundle);
+
+ /* there must be an associated transfer */
+ DEBUGASSERT(data);
+
+ /* the transfer must be detached from the connection */
+ DEBUGASSERT(!data->conn);
/*
* If this connection isn't marked to force-close, leave it open if there
@@ -805,16 +799,11 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
conn->dns_entry = NULL;
}
- Curl_hostcache_prune(data); /* kill old DNS cache entries */
-
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
/* Cleanup NTLM connection-related data */
Curl_http_auth_cleanup_ntlm(conn);
-#endif
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+
/* Cleanup NEGOTIATE connection-related data */
Curl_http_auth_cleanup_negotiate(conn);
-#endif
/* the protocol specific disconnect handler and conn_shutdown need a transfer
for the connection! */
@@ -876,8 +865,8 @@ static int IsMultiplexingPossible(const struct Curl_easy *handle,
#ifndef CURL_DISABLE_PROXY
static bool
-proxy_info_matches(const struct proxy_info* data,
- const struct proxy_info* needle)
+proxy_info_matches(const struct proxy_info *data,
+ const struct proxy_info *needle)
{
if((data->proxytype == needle->proxytype) &&
(data->port == needle->port) &&
@@ -888,8 +877,8 @@ proxy_info_matches(const struct proxy_info* data,
}
static bool
-socks_proxy_info_matches(const struct proxy_info* data,
- const struct proxy_info* needle)
+socks_proxy_info_matches(const struct proxy_info *data,
+ const struct proxy_info *needle)
{
if(!proxy_info_matches(data, needle))
return FALSE;
@@ -1011,8 +1000,12 @@ static int call_extract_if_dead(struct connectdata *conn, void *param)
static void prune_dead_connections(struct Curl_easy *data)
{
struct curltime now = Curl_now();
- timediff_t elapsed =
+ timediff_t elapsed;
+
+ CONNCACHE_LOCK(data);
+ elapsed =
Curl_timediff(now, data->state.conn_cache->last_cleanup);
+ CONNCACHE_UNLOCK(data);
if(elapsed >= 1000L) {
struct prunedead prune;
@@ -1020,10 +1013,17 @@ static void prune_dead_connections(struct Curl_easy *data)
prune.extracted = NULL;
while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
call_extract_if_dead)) {
+ /* unlocked */
+
+ /* remove connection from cache */
+ Curl_conncache_remove_conn(data, prune.extracted, TRUE);
+
/* disconnect it */
(void)Curl_disconnect(data, prune.extracted, /* dead_connection */TRUE);
}
+ CONNCACHE_LOCK(data);
data->state.conn_cache->last_cleanup = now;
+ CONNCACHE_UNLOCK(data);
}
}
@@ -1056,10 +1056,14 @@ ConnectionExists(struct Curl_easy *data,
bool wantNTLMhttp = ((data->state.authhost.want &
(CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
(needle->handler->protocol & PROTO_FAMILY_HTTP));
+#ifndef CURL_DISABLE_PROXY
bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
((data->state.authproxy.want &
(CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
(needle->handler->protocol & PROTO_FAMILY_HTTP)));
+#else
+ bool wantProxyNTLMhttp = FALSE;
+#endif
#endif
*force_reuse = FALSE;
@@ -1083,7 +1087,7 @@ ConnectionExists(struct Curl_easy *data,
if(data->set.pipewait) {
infof(data, "Server doesn't support multiplex yet, wait\n");
*waitpipe = TRUE;
- Curl_conncache_unlock(data);
+ CONNCACHE_UNLOCK(data);
return FALSE; /* no re-use */
}
@@ -1156,7 +1160,8 @@ ConnectionExists(struct Curl_easy *data,
continue;
if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
continue;
- if(needle->abstract_unix_socket != check->abstract_unix_socket)
+ if(needle->bits.abstract_unix_socket !=
+ check->bits.abstract_unix_socket)
continue;
}
else if(check->unix_domain_socket)
@@ -1167,10 +1172,11 @@ ConnectionExists(struct Curl_easy *data,
(check->handler->flags&PROTOPT_SSL))
/* don't do mixed SSL and non-SSL connections */
if(get_protocol_family(check->handler->protocol) !=
- needle->handler->protocol || !check->tls_upgraded)
+ needle->handler->protocol || !check->bits.tls_upgraded)
/* except protocols that have been upgraded via TLS */
continue;
+#ifndef CURL_DISABLE_PROXY
if(needle->bits.httpproxy != check->bits.httpproxy ||
needle->bits.socksproxy != check->bits.socksproxy)
continue;
@@ -1179,7 +1185,7 @@ ConnectionExists(struct Curl_easy *data,
!socks_proxy_info_matches(&needle->socks_proxy,
&check->socks_proxy))
continue;
-
+#endif
if(needle->bits.conn_to_host != check->bits.conn_to_host)
/* don't mix connections that use the "connect to host" feature and
* connections that don't use this feature */
@@ -1190,6 +1196,7 @@ ConnectionExists(struct Curl_easy *data,
* connections that don't use this feature */
continue;
+#ifndef CURL_DISABLE_PROXY
if(needle->bits.httpproxy) {
if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
continue;
@@ -1216,6 +1223,7 @@ ConnectionExists(struct Curl_easy *data,
}
}
}
+#endif
DEBUGASSERT(!check->data || GOOD_EASY_HANDLE(check->data));
@@ -1258,15 +1266,18 @@ ConnectionExists(struct Curl_easy *data,
}
}
- if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) ||
- needle->bits.tunnel_proxy) {
+ if((needle->handler->flags&PROTOPT_SSL)
+#ifndef CURL_DISABLE_PROXY
+ || !needle->bits.httpproxy || needle->bits.tunnel_proxy
+#endif
+ ) {
/* The requested connection does not use a HTTP proxy or it uses SSL or
it is a non-SSL protocol tunneled or it is a non-SSL protocol which
is allowed to be upgraded via TLS */
if((strcasecompare(needle->handler->scheme, check->handler->scheme) ||
(get_protocol_family(check->handler->protocol) ==
- needle->handler->protocol && check->tls_upgraded)) &&
+ needle->handler->protocol && check->bits.tls_upgraded)) &&
(!needle->bits.conn_to_host || strcasecompare(
needle->conn_to_host.name, check->conn_to_host.name)) &&
(!needle->bits.conn_to_port ||
@@ -1328,6 +1339,7 @@ ConnectionExists(struct Curl_easy *data,
continue;
}
+#ifndef CURL_DISABLE_PROXY
/* Same for Proxy NTLM authentication */
if(wantProxyNTLMhttp) {
/* Both check->http_proxy.user and check->http_proxy.passwd can be
@@ -1343,7 +1355,7 @@ ConnectionExists(struct Curl_easy *data,
/* Proxy connection is using NTLM auth but we don't want NTLM */
continue;
}
-
+#endif
if(wantNTLMhttp || wantProxyNTLMhttp) {
/* Credentials are already checked, we can use this connection */
chosen = check;
@@ -1407,11 +1419,12 @@ ConnectionExists(struct Curl_easy *data,
if(chosen) {
/* mark it as used before releasing the lock */
chosen->data = data; /* own it! */
- Curl_conncache_unlock(data);
+ Curl_attach_connnection(data, chosen);
+ CONNCACHE_UNLOCK(data);
*usethis = chosen;
return TRUE; /* yes, we found one to use! */
}
- Curl_conncache_unlock(data);
+ CONNCACHE_UNLOCK(data);
if(foundPendingCandidate && data->set.pipewait) {
infof(data,
@@ -1430,8 +1443,10 @@ void Curl_verboseconnect(struct connectdata *conn)
{
if(conn->data->set.verbose)
infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n",
+#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,
conn->ip_addr_str, conn->port, conn->connection_id);
@@ -1578,8 +1593,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->ssl_extra = ssl;
conn->ssl[0].backend = (void *)ssl;
conn->ssl[1].backend = (void *)(ssl + sslsize);
+#ifndef CURL_DISABLE_PROXY
conn->proxy_ssl[0].backend = (void *)(ssl + 2 * sslsize);
conn->proxy_ssl[1].backend = (void *)(ssl + 3 * sslsize);
+#endif
}
#endif
@@ -1618,10 +1635,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->data = data; /* Setup the association between this connection
and the Curl_easy */
+#ifndef CURL_DISABLE_PROXY
conn->http_proxy.proxytype = data->set.proxytype;
conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
-#if !defined(CURL_DISABLE_PROXY)
/* note that these two proxy bits are now just on what looks to be
requested, they may be altered down the road */
conn->bits.proxy = (data->set.str[STRING_PROXY] &&
@@ -1652,10 +1669,12 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus;
conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer;
conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost;
+#ifndef CURL_DISABLE_PROXY
conn->proxy_ssl_config.verifystatus =
data->set.proxy_ssl.primary.verifystatus;
conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer;
conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost;
+#endif
conn->ip_version = data->set.ipver;
conn->bits.connect_only = data->set.connect_only;
conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
@@ -1875,23 +1894,32 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
if(result)
return result;
- uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user,
- CURLU_URLDECODE);
+ /* we don't use the URL API's URL decoder option here since it rejects
+ control codes and we want to allow them for some schemes in the user and
+ password fields */
+ uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
if(!uc) {
- conn->user = strdup(data->state.up.user);
- if(!conn->user)
- return CURLE_OUT_OF_MEMORY;
+ char *decoded;
+ result = Curl_urldecode(NULL, data->state.up.user, 0, &decoded, NULL,
+ conn->handler->flags&PROTOPT_USERPWDCTRL ?
+ REJECT_ZERO : REJECT_CTRL);
+ if(result)
+ return result;
+ conn->user = decoded;
conn->bits.user_passwd = TRUE;
}
else if(uc != CURLUE_NO_USER)
return Curl_uc_to_curlcode(uc);
- uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password,
- CURLU_URLDECODE);
+ uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
if(!uc) {
- conn->passwd = strdup(data->state.up.password);
- if(!conn->passwd)
- return CURLE_OUT_OF_MEMORY;
+ char *decoded;
+ result = Curl_urldecode(NULL, data->state.up.password, 0, &decoded, NULL,
+ conn->handler->flags&PROTOPT_USERPWDCTRL ?
+ REJECT_ZERO : REJECT_CTRL);
+ if(result)
+ return result;
+ conn->passwd = decoded;
conn->bits.user_passwd = TRUE;
}
else if(uc != CURLUE_NO_PASSWORD)
@@ -2001,7 +2029,7 @@ static CURLcode setup_range(struct Curl_easy *data)
*/
static CURLcode setup_connection_internals(struct connectdata *conn)
{
- const struct Curl_handler * p;
+ const struct Curl_handler *p;
CURLcode result;
/* Perform setup complement if some. */
@@ -2348,26 +2376,16 @@ static CURLcode parse_proxy(struct Curl_easy *data,
static CURLcode parse_proxy_auth(struct Curl_easy *data,
struct connectdata *conn)
{
- char proxyuser[MAX_CURL_USER_LENGTH]="";
- char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
- CURLcode result;
-
- if(data->set.str[STRING_PROXYUSERNAME] != NULL) {
- strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME],
- MAX_CURL_USER_LENGTH);
- proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/
- }
- if(data->set.str[STRING_PROXYPASSWORD] != NULL) {
- strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD],
- MAX_CURL_PASSWORD_LENGTH);
- proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
- }
+ char *proxyuser = data->set.str[STRING_PROXYUSERNAME];
+ char *proxypasswd = data->set.str[STRING_PROXYPASSWORD];
+ CURLcode result = CURLE_OK;
- result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL,
- FALSE);
- if(!result)
+ if(proxyuser)
+ result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL,
+ REJECT_ZERO);
+ if(!result && proxypasswd)
result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd,
- NULL, FALSE);
+ NULL, REJECT_ZERO);
return result;
}
@@ -2585,6 +2603,12 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
size_t plen;
size_t olen;
+ /* the input length check is because this is called directcly from setopt
+ and isn't going through the regular string length check */
+ size_t llen = strlen(login);
+ if(llen > CURL_MAX_INPUT_LENGTH)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
/* Attempt to find the password separator */
if(passwdp) {
psep = strchr(login, ':');
@@ -2781,12 +2805,14 @@ static CURLcode override_login(struct Curl_easy *data,
/* for updated strings, we update them in the URL */
if(user_changed) {
- uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0);
+ uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp,
+ CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
}
if(passwd_changed) {
- uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0);
+ uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp,
+ CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
}
@@ -3159,7 +3185,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
else {
bool longpath = FALSE;
hostaddr->addr = Curl_unix2addr(path, &longpath,
- conn->abstract_unix_socket);
+ conn->bits.abstract_unix_socket);
if(hostaddr->addr)
hostaddr->inuse++;
else {
@@ -3177,6 +3203,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
}
else
#endif
+
if(!conn->bits.proxy) {
struct hostname *connhost;
if(conn->bits.conn_to_host)
@@ -3205,10 +3232,11 @@ static CURLcode resolve_server(struct Curl_easy *data,
else if(!hostaddr) {
failf(data, "Couldn't resolve host '%s'", connhost->dispname);
- result = CURLE_COULDNT_RESOLVE_HOST;
+ result = CURLE_COULDNT_RESOLVE_HOST;
/* don't return yet, we need to clean up the timeout first */
}
}
+#ifndef CURL_DISABLE_PROXY
else {
/* This is a proxy that hasn't been resolved yet. */
@@ -3234,6 +3262,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
/* don't return yet, we need to clean up the timeout first */
}
}
+#endif
DEBUGASSERT(conn->dns_entry == NULL);
conn->dns_entry = hostaddr;
}
@@ -3249,16 +3278,17 @@ static CURLcode resolve_server(struct Curl_easy *data,
static void reuse_conn(struct connectdata *old_conn,
struct connectdata *conn)
{
+#ifndef CURL_DISABLE_PROXY
Curl_free_idnconverted_hostname(&old_conn->http_proxy.host);
Curl_free_idnconverted_hostname(&old_conn->socks_proxy.host);
free(old_conn->http_proxy.host.rawalloc);
free(old_conn->socks_proxy.host.rawalloc);
-
+ Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config);
+#endif
/* free the SSL config struct from this connection struct as this was
allocated in vain and is targeted for destruction */
Curl_free_primary_ssl_config(&old_conn->ssl_config);
- Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config);
conn->data = old_conn->data;
@@ -3275,6 +3305,7 @@ static void reuse_conn(struct connectdata *old_conn,
old_conn->passwd = NULL;
}
+#ifndef CURL_DISABLE_PROXY
conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
if(conn->bits.proxy_user_passwd) {
/* use the new proxy user name and proxy password though */
@@ -3291,6 +3322,11 @@ static void reuse_conn(struct connectdata *old_conn,
old_conn->http_proxy.passwd = NULL;
old_conn->socks_proxy.passwd = NULL;
}
+ Curl_safefree(old_conn->http_proxy.user);
+ Curl_safefree(old_conn->socks_proxy.user);
+ Curl_safefree(old_conn->http_proxy.passwd);
+ Curl_safefree(old_conn->socks_proxy.passwd);
+#endif
/* host can change, when doing keepalive with a proxy or if the case is
different this time etc */
@@ -3318,10 +3354,6 @@ static void reuse_conn(struct connectdata *old_conn,
Curl_safefree(old_conn->user);
Curl_safefree(old_conn->passwd);
Curl_safefree(old_conn->options);
- Curl_safefree(old_conn->http_proxy.user);
- Curl_safefree(old_conn->socks_proxy.user);
- Curl_safefree(old_conn->http_proxy.passwd);
- Curl_safefree(old_conn->socks_proxy.passwd);
Curl_safefree(old_conn->localdev);
Curl_llist_destroy(&old_conn->easyq, NULL);
@@ -3406,7 +3438,7 @@ static CURLcode create_conn(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- conn->abstract_unix_socket = data->set.abstract_unix_socket;
+ conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
}
#endif
@@ -3416,7 +3448,6 @@ static CURLcode create_conn(struct Curl_easy *data,
result = create_conn_helper_init_proxy(conn);
if(result)
goto out;
-#endif
/*************************************************************
* If the protocol is using SSL and HTTP proxy is used, we set
@@ -3424,6 +3455,7 @@ static CURLcode create_conn(struct Curl_easy *data,
*************************************************************/
if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
conn->bits.tunnel_proxy = TRUE;
+#endif
/*************************************************************
* Figure out the remote port number and fix it in the URL
@@ -3462,6 +3494,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
}
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy) {
result = Curl_idnconvert_hostname(conn, &conn->http_proxy.host);
if(result)
@@ -3472,6 +3505,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
}
+#endif
/*************************************************************
* Check whether the host and the "connect to host" are equal.
@@ -3490,6 +3524,7 @@ static CURLcode create_conn(struct Curl_easy *data,
conn->bits.conn_to_port = FALSE;
}
+#ifndef CURL_DISABLE_PROXY
/*************************************************************
* If the "connect to" feature is used with an HTTP proxy,
* we set the tunnel_proxy bit.
@@ -3497,6 +3532,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
conn->bits.httpproxy)
conn->bits.tunnel_proxy = TRUE;
+#endif
/*************************************************************
* Setup internals depending on protocol. Needs to be done after
@@ -3529,6 +3565,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(!result) {
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
+ Curl_attach_connnection(data, conn);
result = Curl_conncache_add_conn(data->state.conn_cache, conn);
if(result)
goto out;
@@ -3543,7 +3580,6 @@ static CURLcode create_conn(struct Curl_easy *data,
(void)conn->handler->done(conn, result, FALSE);
goto out;
}
- Curl_attach_connnection(data, conn);
Curl_setup_transfer(data, -1, -1, FALSE, -1);
}
@@ -3564,61 +3600,75 @@ static CURLcode create_conn(struct Curl_easy *data,
copies will be separately allocated.
*/
data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG];
- data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG];
- data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
- data->set.proxy_ssl.primary.random_file =
- data->set.str[STRING_SSL_RANDOM_FILE];
data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
- data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
data->set.ssl.primary.cipher_list =
data->set.str[STRING_SSL_CIPHER_LIST_ORIG];
- data->set.proxy_ssl.primary.cipher_list =
- data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
data->set.ssl.primary.cipher_list13 =
data->set.str[STRING_SSL_CIPHER13_LIST_ORIG];
- data->set.proxy_ssl.primary.cipher_list13 =
- data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
data->set.ssl.primary.pinned_key =
data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
+
+#ifndef CURL_DISABLE_PROXY
+ data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
+ data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
+ data->set.proxy_ssl.primary.random_file =
+ data->set.str[STRING_SSL_RANDOM_FILE];
+ data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
+ data->set.proxy_ssl.primary.cipher_list =
+ data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
+ data->set.proxy_ssl.primary.cipher_list13 =
+ data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
data->set.proxy_ssl.primary.pinned_key =
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
-
- data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
+ data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
- data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG];
data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
- data->set.ssl.cert = data->set.str[STRING_CERT_ORIG];
data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY];
- data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG];
data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
- data->set.ssl.key = data->set.str[STRING_KEY_ORIG];
data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
- data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG];
data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
- data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG];
data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
- data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG];
data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
+ data->set.proxy_ssl.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
+ data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
+#endif
+ data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
+ data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG];
+ data->set.ssl.cert = data->set.str[STRING_CERT_ORIG];
+ data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG];
+ data->set.ssl.key = data->set.str[STRING_KEY_ORIG];
+ data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG];
+ data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG];
+ data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG];
#ifdef USE_TLS_SRP
data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG];
- data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG];
+#ifndef CURL_DISABLE_PROXY
+ data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
#endif
+#endif
+
+ data->set.ssl.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
+ data->set.ssl.key_blob = data->set.blobs[BLOB_KEY_ORIG];
+ data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG];
if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
- &conn->ssl_config)) {
+ &conn->ssl_config)) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+#ifndef CURL_DISABLE_PROXY
if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary,
&conn->proxy_ssl_config)) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+#endif
prune_dead_connections(data);
@@ -3656,12 +3706,17 @@ static CURLcode create_conn(struct Curl_easy *data,
conn = conn_temp;
*in_connect = conn;
+#ifndef CURL_DISABLE_PROXY
infof(data, "Re-using existing connection! (#%ld) with %s %s\n",
conn->connection_id,
conn->bits.proxy?"proxy":"host",
conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
- conn->host.dispname);
+ conn->host.dispname);
+#else
+ infof(data, "Re-using existing connection! (#%ld) with host %s\n",
+ conn->connection_id, conn->host.dispname);
+#endif
}
else {
/* We have decided that we want a new connection. However, we may not
@@ -3693,7 +3748,7 @@ static CURLcode create_conn(struct Curl_easy *data,
/* The bundle is full. Extract the oldest connection. */
conn_candidate = Curl_conncache_extract_bundle(data, bundle);
- Curl_conncache_unlock(data);
+ CONNCACHE_UNLOCK(data);
if(conn_candidate)
(void)Curl_disconnect(data, conn_candidate,
@@ -3705,7 +3760,7 @@ static CURLcode create_conn(struct Curl_easy *data,
}
}
else
- Curl_conncache_unlock(data);
+ CONNCACHE_UNLOCK(data);
}
@@ -3739,6 +3794,8 @@ static CURLcode create_conn(struct Curl_easy *data,
* This is a brand new connection, so let's store it in the connection
* cache of ours!
*/
+ Curl_attach_connnection(data, conn);
+
result = Curl_conncache_add_conn(data->state.conn_cache, conn);
if(result)
goto out;
@@ -3790,10 +3847,12 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Strip trailing dots. resolve_server copied the name. */
strip_trailing_dot(&conn->host);
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy)
strip_trailing_dot(&conn->http_proxy.host);
if(conn->bits.socksproxy)
strip_trailing_dot(&conn->socks_proxy.host);
+#endif
if(conn->bits.conn_to_host)
strip_trailing_dot(&conn->conn_to_host);
@@ -3824,22 +3883,23 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
}
*protocol_done = FALSE; /* default to not done */
+#ifndef CURL_DISABLE_PROXY
/* set proxy_connect_closed to false unconditionally already here since it
is used strictly to provide extra information to a parent function in the
case of proxy CONNECT failures and we must make sure we don't have it
lingering set from a previous invoke */
conn->bits.proxy_connect_closed = FALSE;
-
+#endif
/*
* Set user-agent. Used for HTTP, but since we can attempt to tunnel
* basically anything through a http proxy we can't limit this based on
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
- Curl_safefree(conn->allocptr.uagent);
- conn->allocptr.uagent =
+ Curl_safefree(data->state.aptr.uagent);
+ data->state.aptr.uagent =
aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
- if(!conn->allocptr.uagent)
+ if(!data->state.aptr.uagent)
return CURLE_OUT_OF_MEMORY;
}
@@ -3893,7 +3953,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
result = create_conn(data, &conn, asyncp);
if(!result) {
- if(CONN_INUSE(conn))
+ if(CONN_INUSE(conn) > 1)
/* multiplexed */
*protocol_done = TRUE;
else if(!*asyncp) {
@@ -3910,11 +3970,10 @@ CURLcode Curl_connect(struct Curl_easy *data,
else if(result && conn) {
/* We're not allowed to return failure with memory left allocated in the
connectdata struct, free those here */
+ Curl_detach_connnection(data);
+ Curl_conncache_remove_conn(data, conn, TRUE);
Curl_disconnect(data, conn, TRUE);
}
- else if(!result && !data->conn)
- /* FILE: transfers already have the connection attached */
- Curl_attach_connnection(data, conn);
return result;
}
@@ -3933,6 +3992,11 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
struct SingleRequest *k = &data->req;
+ /* if this is a pushed stream, we need this: */
+ CURLcode result = Curl_preconnect(data);
+ if(result)
+ return result;
+
if(conn) {
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
use */
@@ -3945,30 +4009,17 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
data->state.done = FALSE; /* *_done() is not called yet */
data->state.expect100header = FALSE;
-
if(data->set.opt_no_body)
/* in HTTP lingo, no body means using the HEAD request... */
- data->set.httpreq = HTTPREQ_HEAD;
- else if(HTTPREQ_HEAD == data->set.httpreq)
- /* ... but if unset there really is no perfect method that is the
- "opposite" of HEAD but in reality most people probably think GET
- then. The important thing is that we can't let it remain HEAD if the
- opt_no_body is set FALSE since then we'll behave wrong when getting
- HTTP. */
- data->set.httpreq = HTTPREQ_GET;
+ data->state.httpreq = HTTPREQ_HEAD;
k->start = Curl_now(); /* start time */
k->now = k->start; /* current time is now */
k->header = TRUE; /* assume header */
-
k->bytecount = 0;
-
- k->buf = data->state.buffer;
- k->hbufp = data->state.headerbuff;
k->ignorebody = FALSE;
Curl_speedinit(data);
-
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
diff --git a/lib/url.h b/lib/url.h
index 5000c512..1941dc6a 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -47,7 +47,7 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn);
CURLcode Curl_open(struct Curl_easy **curl);
CURLcode Curl_init_userdefined(struct Curl_easy *data);
-void Curl_freeset(struct Curl_easy * data);
+void Curl_freeset(struct Curl_easy *data);
CURLcode Curl_uc_to_curlcode(CURLUcode uc);
CURLcode Curl_close(struct Curl_easy **datap); /* opposite of curl_open() */
CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
@@ -77,6 +77,10 @@ void Curl_free_idnconverted_hostname(struct hostname *host);
void Curl_verboseconnect(struct connectdata *conn);
#endif
+#ifdef CURL_DISABLE_PROXY
+#define CONNECT_PROXY_SSL() FALSE
+#else
+
#define CONNECT_PROXY_SSL()\
(conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\
!conn->bits.proxy_ssl_connected[sockindex])
@@ -88,5 +92,6 @@ void Curl_verboseconnect(struct connectdata *conn);
#define CONNECT_SECONDARYSOCKET_PROXY_SSL()\
(conn->http_proxy.proxytype == CURLPROXY_HTTPS &&\
!conn->bits.proxy_ssl_connected[SECONDARYSOCKET])
+#endif /* !CURL_DISABLE_PROXY */
#endif /* HEADER_CURL_URL_H */
diff --git a/lib/urlapi.c b/lib/urlapi.c
index 506e244d..acbfb828 100644
--- a/lib/urlapi.c
+++ b/lib/urlapi.c
@@ -225,7 +225,7 @@ static void strcpy_url(char *output, const char *url, bool relative)
break;
}
}
- *optr = 0; /* zero terminate output buffer */
+ *optr = 0; /* null-terminate output buffer */
}
@@ -584,7 +584,7 @@ static CURLUcode junkscan(const char *part)
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x7f,
- 0x00 /* zero terminate */
+ 0x00 /* null-terminate */
};
size_t n = strlen(part);
size_t nfine = strcspn(part, badbytes);
@@ -606,7 +606,7 @@ static CURLUcode hostname_check(struct Curl_URL *u, char *hostname)
char dest[16]; /* fits a binary IPv6 address */
#endif
const char *l = "0123456789abcdefABCDEF:.";
- if(hlen < 5) /* '[::1]' is the shortest possible valid string */
+ if(hlen < 4) /* '[::]' is the shortest possible valid string */
return CURLUE_MALFORMED_INPUT;
hostname++;
hlen -= 2;
@@ -1185,7 +1185,10 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
if(urldecode) {
char *decoded;
size_t dlen;
- CURLcode res = Curl_urldecode(NULL, *part, 0, &decoded, &dlen, TRUE);
+ /* this unconditional rejection of control bytes is documented
+ API behavior */
+ CURLcode res = Curl_urldecode(NULL, *part, 0, &decoded, &dlen,
+ REJECT_CTRL);
free(*part);
if(res) {
*part = NULL;
@@ -1395,7 +1398,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
i = (const unsigned char *)part;
for(o = enc; *i; ++o, ++i)
*o = (*i == ' ') ? '+' : *i;
- *o = 0; /* zero terminate */
+ *o = 0; /* null-terminate */
part = strdup(enc);
if(!part) {
free(enc);
@@ -1419,7 +1422,7 @@ CURLUcode curl_url_set(CURLU *u, CURLUPart what,
o += 3;
}
}
- *o = 0; /* zero terminate */
+ *o = 0; /* null-terminate */
newp = enc;
if(free_part)
free((char *)part);
diff --git a/lib/urldata.h b/lib/urldata.h
index 50d8b84a..f80a02de 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -81,7 +81,7 @@
*/
#define RESP_TIMEOUT (120*1000)
-/* Max string intput length is a precaution against abuse and to detect junk
+/* Max string input length is a precaution against abuse and to detect junk
input easier and better. */
#define CURL_MAX_INPUT_LENGTH 8000000
@@ -104,6 +104,7 @@
#include "hostip.h"
#include "hash.h"
#include "splay.h"
+#include "dynbuf.h"
/* return the count of bytes sent, or -1 on error */
typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */
@@ -152,10 +153,6 @@ typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
#include <libssh2_sftp.h>
#endif /* HAVE_LIBSSH2_H */
-/* Initial size of the buffer to store headers in, it'll be enlarged in case
- of need. */
-#define HEADERSIZE 256
-
#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
#define GOOD_EASY_HANDLE(x) \
((x) && ((x)->magic == CURLEASY_MAGIC_NUMBER))
@@ -232,6 +229,7 @@ struct ssl_primary_config {
char *cipher_list; /* list of ciphers to use */
char *cipher_list13; /* list of TLS 1.3 cipher suites to use */
char *pinned_key;
+ struct curl_blob *cert_blob;
BIT(verifypeer); /* set TRUE if this is desired */
BIT(verifyhost); /* set TRUE if CN/SAN must match hostname */
BIT(verifystatus); /* set TRUE if certificate status must be checked */
@@ -243,11 +241,14 @@ struct ssl_config_data {
long certverifyresult; /* result from the certificate verification */
char *CRLfile; /* CRL to check certificate revocation */
char *issuercert;/* optional issuer certificate filename */
+ struct curl_blob *issuercert_blob;
curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
void *fsslctxp; /* parameter for call back */
char *cert; /* client certificate file name */
+ struct curl_blob *cert_blob;
char *cert_type; /* format for certificate (default: PEM)*/
char *key; /* private key file name */
+ struct curl_blob *key_blob;
char *key_type; /* format for private key (default: PEM) */
char *key_passwd; /* plain text private key password */
#ifdef USE_TLS_SRP
@@ -262,6 +263,7 @@ struct ssl_config_data {
BIT(no_partialchain); /* don't accept partial certificate chains */
BIT(revoke_best_effort); /* ignore SSL revocation offline/missing revocation
list errors */
+ BIT(native_ca_store); /* use the native ca store of operating system */
};
struct ssl_general_config {
@@ -419,11 +421,23 @@ struct negotiatedata {
* Boolean values that concerns this connection.
*/
struct ConnectBits {
- /* always modify bits.close with the connclose() and connkeep() macros! */
- bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy
- is complete */
bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set
the first time on the first connect function call */
+#ifndef CURL_DISABLE_PROXY
+ bool proxy_ssl_connected[2]; /* TRUE when SSL initialization for HTTPS proxy
+ is complete */
+ BIT(httpproxy); /* if set, this transfer is done through a http proxy */
+ BIT(socksproxy); /* if set, this transfer is done through a socks proxy */
+ BIT(proxy_user_passwd); /* user+password for the proxy? */
+ BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy.
+ This is implicit when SSL-protocols are used through
+ proxies, but can also be enabled explicitly by
+ apps */
+ BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection
+ in a CONNECT request with auth, so that
+ libcurl should reconnect and continue. */
+#endif
+ /* always modify bits.close with the connclose() and connkeep() macros! */
BIT(close); /* if set, we close the connection after this request */
BIT(reuse); /* if set, this is a re-used connection */
BIT(altused); /* this is an alt-svc "redirect" */
@@ -432,10 +446,7 @@ struct ConnectBits {
BIT(conn_to_port); /* if set, this connection has a "connect to port"
that overrides the port in the URL (remote port) */
BIT(proxy); /* if set, this transfer is done through a proxy - any type */
- BIT(httpproxy); /* if set, this transfer is done through a http proxy */
- BIT(socksproxy); /* if set, this transfer is done through a socks proxy */
BIT(user_passwd); /* do we use user+password for this connection? */
- BIT(proxy_user_passwd); /* user+password for the proxy? */
BIT(ipv6_ip); /* we communicate with a remote site specified with pure IPv6
IP address */
BIT(ipv6); /* we communicate with a site using an IPv6 address */
@@ -445,10 +456,6 @@ struct ConnectBits {
the TCP layer connect */
BIT(retry); /* this connection is about to get closed and then
re-attempted at another connection. */
- BIT(tunnel_proxy); /* if CONNECT is used to "tunnel" through the proxy.
- This is implicit when SSL-protocols are used through
- proxies, but can also be enabled explicitly by
- apps */
BIT(authneg); /* TRUE when the auth phase has started, which means
that we are creating a request with an auth header,
but it is not the final request in the auth
@@ -467,18 +474,22 @@ struct ConnectBits {
BIT(ftp_use_data_ssl); /* Enabled SSL for the data connection */
#endif
BIT(netrc); /* name+password provided by netrc */
- BIT(userpwd_in_url); /* name+password found in url */
- BIT(proxy_connect_closed); /* TRUE if a proxy disconnected the connection
- in a CONNECT request with auth, so that
- libcurl should reconnect and continue. */
BIT(bound); /* set true if bind() has already been done on this socket/
connection */
- BIT(type_set); /* type= was used in the URL */
BIT(multiplex); /* connection is multiplexed */
BIT(tcp_fastopen); /* use TCP Fast Open */
BIT(tls_enable_npn); /* TLS NPN extension? */
BIT(tls_enable_alpn); /* TLS ALPN extension? */
BIT(connect_only);
+ BIT(doh);
+#ifdef USE_UNIX_SOCKETS
+ BIT(abstract_unix_socket);
+#endif
+ BIT(tls_upgraded);
+ BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with
+ accept() */
+ BIT(parallel_connect); /* set TRUE when a parallel connect attempt has
+ started (happy eyeballs) */
};
struct hostname {
@@ -556,18 +567,13 @@ enum doh_slots {
DOH_PROBE_SLOTS
};
-struct dohresponse {
- unsigned char *memory;
- size_t size;
-};
-
/* one of these for each DoH request */
struct dnsprobe {
CURL *easy;
int dnstype;
unsigned char dohbuffer[512];
size_t dohlen;
- struct dohresponse serverdoh;
+ struct dynbuf serverdoh;
};
struct dohdata {
@@ -611,12 +617,7 @@ struct SingleRequest {
written as body */
int headerline; /* counts header lines to better track the
first one */
- char *hbufp; /* points at *end* of header line */
- size_t hbuflen;
char *str; /* within buf */
- char *str_start; /* within buf */
- char *end_ptr; /* within buf */
- char *p; /* within headerbuff */
curl_off_t offset; /* possible resume offset read from the
Content-Range: header */
int httpcode; /* error code from the 'HTTP/1.? XXX' or
@@ -625,11 +626,10 @@ struct SingleRequest {
enum expect100 exp100; /* expect 100 continue state */
enum upgrade101 upgr101; /* 101 upgrade state */
- struct contenc_writer_s *writer_stack; /* Content unencoding stack. */
- /* See sec 3.5, RFC2616. */
+ /* Content unencoding stack. See sec 3.5, RFC2616. */
+ struct contenc_writer *writer_stack;
time_t timeofdoc;
long bodywrites;
- char *buf;
int keepon;
char *location; /* This points to an allocated version of the Location:
header data */
@@ -767,6 +767,8 @@ struct Curl_handler {
HTTP proxy as HTTP proxies may know
this protocol and act as a gateway */
#define PROTOPT_WILDCARD (1<<12) /* protocol supports wildcard matching */
+#define PROTOPT_USERPWDCTRL (1<<13) /* Allow "control bytes" (< 32 ascii) in
+ user name and password */
#define CONNCHECK_NONE 0 /* No checks */
#define CONNCHECK_ISDEAD (1<<0) /* Check if the connection is dead. */
@@ -797,15 +799,10 @@ struct proxy_info {
char *passwd; /* proxy password string, allocated */
};
-#define CONNECT_BUFFER_SIZE 16384
-
/* struct for HTTP CONNECT state data */
struct http_connect_state {
- char connect_buffer[CONNECT_BUFFER_SIZE];
- int perline; /* count bytes per line */
+ struct dynbuf rcvbuf;
int keepon;
- char *line_start;
- char *ptr; /* where to store more data */
curl_off_t cl; /* size of content to read and ignore */
enum {
TUNNEL_INIT, /* init/default/no tunnel state */
@@ -885,15 +882,15 @@ struct connectdata {
/* 'dns_entry' is the particular host we use. This points to an entry in the
DNS cache and it will not get pruned while locked. It gets unlocked in
- Curl_done(). This entry will be NULL if the connection is re-used as then
+ multi_done(). This entry will be NULL if the connection is re-used as then
there is no name resolve done. */
struct Curl_dns_entry *dns_entry;
/* 'ip_addr' is the particular IP we connected to. It points to a struct
within the DNS cache, so this pointer is only valid as long as the DNS
- cache entry remains locked. It gets unlocked in Curl_done() */
- Curl_addrinfo *ip_addr;
- Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */
+ cache entry remains locked. It gets unlocked in multi_done() */
+ struct Curl_addrinfo *ip_addr;
+ struct Curl_addrinfo *tempaddr[2]; /* for happy eyeballs */
/* 'ip_addr_str' is the ip_addr data as a human readable string.
It remains available as long as the connection does, which is longer than
@@ -918,10 +915,10 @@ struct connectdata {
char *secondaryhostname; /* secondary socket host name (ftp) */
struct hostname conn_to_host; /* the host to connect to. valid only if
bits.conn_to_host is set */
-
+#ifndef CURL_DISABLE_PROXY
struct proxy_info socks_proxy;
struct proxy_info http_proxy;
-
+#endif
long port; /* which port to use locally */
int remote_port; /* the remote port, not the proxy port! */
int conn_to_port; /* the remote port to connect to. valid only if
@@ -969,12 +966,16 @@ struct connectdata {
struct postponed_data postponed[2]; /* two buffers for two sockets */
#endif /* USE_RECV_BEFORE_SEND_WORKAROUND */
struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */
+#ifndef CURL_DISABLE_PROXY
struct ssl_connect_data proxy_ssl[2]; /* this is for proxy ssl-stuff */
+#endif
#ifdef USE_SSL
void *ssl_extra; /* separately allocated backend-specific data */
#endif
struct ssl_primary_config ssl_config;
+#ifndef CURL_DISABLE_PROXY
struct ssl_primary_config proxy_ssl_config;
+#endif
struct ConnectBits bits; /* various state-flags for this connection */
/* connecttime: when connect() is called on the current IP address. Used to
@@ -983,8 +984,10 @@ struct connectdata {
struct curltime connecttime;
/* The two fields below get set in Curl_connecthost */
int num_addr; /* number of addresses to try to connect to */
- timediff_t timeoutms_per_addr; /* how long time in milliseconds to spend on
- trying to connect to each IP address */
+
+ /* how long time in milliseconds to spend on trying to connect to each IP
+ address, per family */
+ timediff_t timeoutms_per_addr[2];
const struct Curl_handler *handler; /* Connection's protocol handler */
const struct Curl_handler *given; /* The protocol first given */
@@ -1005,21 +1008,6 @@ struct connectdata {
well be the same we read from.
CURL_SOCKET_BAD disables */
- /** Dynamically allocated strings, MUST be freed before this **/
- /** struct is killed. **/
- struct dynamically_allocated_data {
- char *proxyuserpwd;
- char *uagent;
- char *accept_encoding;
- char *userpwd;
- char *rangeline;
- char *ref;
- char *host;
- char *cookiehost;
- char *rtsp_transport;
- char *te; /* TE: request header */
- } allocptr;
-
#ifdef HAVE_GSSAPI
BIT(sec_complete); /* if Kerberos is enabled for this connection */
enum protection_level command_prot;
@@ -1066,10 +1054,8 @@ struct connectdata {
/* data used for the asynch name resolve callback */
struct Curl_async async;
- /* These three are used for chunked-encoding trailer support */
- char *trailer; /* allocated buffer to store trailer in */
- int trlMax; /* allocated buffer size */
- int trlPos; /* index of where to store data */
+ /* for chunked-encoded trailer */
+ struct dynbuf trailer;
union {
struct ftp_conn ftpc;
@@ -1107,20 +1093,7 @@ struct connectdata {
int retrycount; /* number of retries on a new connection */
#ifdef USE_UNIX_SOCKETS
char *unix_domain_socket;
- BIT(abstract_unix_socket);
#endif
- BIT(tls_upgraded);
- /* the two following *_inuse fields are only flags, not counters in any way.
- If TRUE it means the channel is in use, and if FALSE it means the channel
- is up for grabs by one. */
- BIT(readchannel_inuse); /* whether the read channel is in use by an easy
- handle */
- BIT(writechannel_inuse); /* whether the write channel is in use by an easy
- handle */
- BIT(sock_accepted); /* TRUE if the SECONDARYSOCKET was created with
- accept() */
- BIT(parallel_connect); /* set TRUE when a parallel connect attempt has
- started (happy eyeballs) */
};
/* The end of connectdata. */
@@ -1242,17 +1215,6 @@ typedef enum {
RTSPREQ_LAST /* last in list */
} Curl_RtspReq;
-/*
- * Values that are generated, temporary or calculated internally for a
- * "session handle" must be defined within the 'struct UrlState'. This struct
- * will be used within the Curl_easy struct. When the 'Curl_easy'
- * struct is cloned, this data MUST NOT be copied.
- *
- * Remember that any "state" information goes globally for the curl handle.
- * Session-data MUST be put in the connectdata struct and here. */
-#define MAX_CURL_USER_LENGTH 256
-#define MAX_CURL_PASSWORD_LENGTH 256
-
struct auth {
unsigned long want; /* Bitmask set to the authentication methods wanted by
app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */
@@ -1278,9 +1240,7 @@ struct Curl_http2_dep {
* BODY).
*/
struct tempbuf {
- char *buf; /* allocated buffer to keep data in when a write callback
- returns to make the connection paused */
- size_t len; /* size of the 'tempwrite' allocated buffer */
+ struct dynbuf b;
int type; /* type of the 'tempwrite' buffer as a bitmask that is used with
Curl_client_write() */
};
@@ -1290,7 +1250,8 @@ typedef enum {
EXPIRE_100_TIMEOUT,
EXPIRE_ASYNC_NAME,
EXPIRE_CONNECTTIMEOUT,
- EXPIRE_DNS_PER_NAME,
+ EXPIRE_DNS_PER_NAME, /* family1 */
+ EXPIRE_DNS_PER_NAME2, /* family2 */
EXPIRE_HAPPY_EYEBALLS_DNS, /* See asyn-ares.c */
EXPIRE_HAPPY_EYEBALLS,
EXPIRE_MULTI_PENDING,
@@ -1340,9 +1301,7 @@ struct UrlState {
struct curltime keeps_speed; /* for the progress meter really */
struct connectdata *lastconnect; /* The last connection, NULL if undefined */
-
- char *headerbuff; /* allocated buffer to store headers in */
- size_t headersize; /* size of the allocation */
+ struct dynbuf headerb; /* buffer to store headers in */
char *buffer; /* download buffer */
char *ulbuf; /* allocated upload buffer or NULL */
@@ -1420,13 +1379,30 @@ struct UrlState {
int stream_weight;
CURLU *uh; /* URL handle for the current parsed URL */
struct urlpieces up;
+ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
#ifndef CURL_DISABLE_HTTP
size_t trailers_bytes_sent;
- Curl_send_buffer *trailers_buf; /* a buffer containing the compiled trailing
- headers */
+ struct dynbuf trailers_buf; /* a buffer containing the compiled trailing
+ headers */
#endif
trailers_state trailers_state; /* whether we are sending trailers
and what stage are we at */
+
+ /* Dynamically allocated strings, MUST be freed before this struct is
+ killed. */
+ struct dynamically_allocated_data {
+ char *proxyuserpwd;
+ char *uagent;
+ char *accept_encoding;
+ char *userpwd;
+ char *rangeline;
+ char *ref;
+ char *host;
+ char *cookiehost;
+ char *rtsp_transport;
+ char *te; /* TE: request header */
+ } aptr;
+
#ifdef CURLDEBUG
BIT(conncache_lock);
#endif
@@ -1589,7 +1565,7 @@ enum dupstring {
STRING_DNS_LOCAL_IP4,
STRING_DNS_LOCAL_IP6,
- /* -- end of zero-terminated strings -- */
+ /* -- end of null-terminated strings -- */
STRING_LASTZEROTERMINATED,
@@ -1601,6 +1577,16 @@ enum dupstring {
STRING_LAST /* not used, just an end-of-list marker */
};
+enum dupblob {
+ BLOB_CERT_ORIG,
+ BLOB_CERT_PROXY,
+ BLOB_KEY_ORIG,
+ BLOB_KEY_PROXY,
+ BLOB_SSL_ISSUERCERT_ORIG,
+ BLOB_SSL_ISSUERCERT_PROXY,
+ BLOB_LAST
+};
+
/* callback that gets called when this easy handle is completed within a multi
handle. Only used for internally created transfers, like for example
DoH. */
@@ -1698,11 +1684,13 @@ struct UserDefined {
the hostname and port to connect to */
curl_TimeCond timecondition; /* kind of time/date comparison */
time_t timevalue; /* what time to compare with */
- Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
+ Curl_HttpReq method; /* what kind of HTTP request (if any) is this */
long httpversion; /* when non-zero, a specific HTTP version requested to
be used in the library's request(s) */
struct ssl_config_data ssl; /* user defined SSL stuff */
+#ifndef CURL_DISABLE_PROXY
struct ssl_config_data proxy_ssl; /* user defined SSL stuff for proxy */
+#endif
struct ssl_general_config general_ssl; /* general user defined SSL stuff */
curl_proxytype proxytype; /* what kind of proxy that is in use */
long dns_cache_timeout; /* DNS cache timeout */
@@ -1732,6 +1720,7 @@ struct UserDefined {
long new_directory_perms; /* Permissions to use when creating remote dirs */
long ssh_auth_types; /* allowed SSH auth types */
char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
+ struct curl_blob *blobs[BLOB_LAST];
unsigned int scope_id; /* Scope id for IPv6 */
long allowed_protocols;
long redir_protocols;
diff --git a/lib/vauth/cleartext.c b/lib/vauth/cleartext.c
index 6f452c16..3a5c9430 100644
--- a/lib/vauth/cleartext.c
+++ b/lib/vauth/cleartext.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -81,7 +81,8 @@ CURLcode Curl_auth_create_plain_message(struct Curl_easy *data,
plen = strlen(passwd);
/* Compute binary message length. Check for overflows. */
- if(((zlen + clen) > SIZE_T_MAX/4) || (plen > (SIZE_T_MAX/2 - 2)))
+ if((zlen > SIZE_T_MAX/4) || (clen > SIZE_T_MAX/4) ||
+ (plen > (SIZE_T_MAX/2 - 2)))
return CURLE_OUT_OF_MEMORY;
plainlen = zlen + clen + plen + 2;
diff --git a/lib/vauth/cram.c b/lib/vauth/cram.c
index 04438fa7..717d7f09 100644
--- a/lib/vauth/cram.c
+++ b/lib/vauth/cram.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -96,7 +96,7 @@ CURLcode Curl_auth_create_cram_md5_message(struct Curl_easy *data,
{
CURLcode result = CURLE_OK;
size_t chlglen = 0;
- HMAC_context *ctxt;
+ struct HMAC_context *ctxt;
unsigned char digest[MD5_DIGEST_LEN];
char *response;
diff --git a/lib/vauth/digest.c b/lib/vauth/digest.c
index a8835705..b9210a8f 100644
--- a/lib/vauth/digest.c
+++ b/lib/vauth/digest.c
@@ -358,7 +358,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
char **outptr, size_t *outlen)
{
size_t i;
- MD5_context *ctxt;
+ struct MD5_context *ctxt;
char *response = NULL;
unsigned char digest[MD5_DIGEST_LEN];
char HA1_hex[2 * MD5_DIGEST_LEN + 1];
diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c
index a1090568..4998306c 100644
--- a/lib/vauth/digest_sspi.c
+++ b/lib/vauth/digest_sspi.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2014 - 2016, Steve Holme, <steve_holme@hotmail.com>.
- * Copyright (C) 2015 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -134,7 +134,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
if(status != SEC_E_OK) {
free(input_token);
- return CURLE_NOT_BUILT_IN;
+ failf(data, "SSPI: couldn't get auth info\n");
+ return CURLE_AUTH_ERROR;
}
token_max = SecurityPackage->cbMaxToken;
@@ -288,13 +289,13 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg,
if(strcasecompare(value, "realm")) {
/* Setup identity's domain and length */
- domain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *) content);
+ domain.tchar_ptr = curlx_convert_UTF8_to_tchar((char *) content);
if(!domain.tchar_ptr)
return CURLE_OUT_OF_MEMORY;
dup_domain.tchar_ptr = _tcsdup(domain.tchar_ptr);
if(!dup_domain.tchar_ptr) {
- Curl_unicodefree(domain.tchar_ptr);
+ curlx_unicodefree(domain.tchar_ptr);
return CURLE_OUT_OF_MEMORY;
}
@@ -303,7 +304,7 @@ CURLcode Curl_override_sspi_http_realm(const char *chlg,
identity->DomainLength = curlx_uztoul(_tcslen(dup_domain.tchar_ptr));
dup_domain.tchar_ptr = NULL;
- Curl_unicodefree(domain.tchar_ptr);
+ curlx_unicodefree(domain.tchar_ptr);
}
else {
/* Unknown specifier, ignore it! */
@@ -431,8 +432,10 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
/* Query the security package for DigestSSP */
status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_DIGEST),
&SecurityPackage);
- if(status != SEC_E_OK)
- return CURLE_NOT_BUILT_IN;
+ if(status != SEC_E_OK) {
+ failf(data, "SSPI: couldn't get auth info\n");
+ return CURLE_AUTH_ERROR;
+ }
token_max = SecurityPackage->cbMaxToken;
@@ -580,7 +583,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
resp_buf.pvBuffer = output_token;
resp_buf.cbBuffer = curlx_uztoul(token_max);
- spn = Curl_convert_UTF8_to_tchar((char *) uripath);
+ spn = curlx_convert_UTF8_to_tchar((char *) uripath);
if(!spn) {
s_pSecFn->FreeCredentialsHandle(&credentials);
@@ -602,7 +605,7 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data,
&chlg_desc, 0,
digest->http_context,
&resp_desc, &attrs, &expiry);
- Curl_unicodefree(spn);
+ curlx_unicodefree(spn);
if(status == SEC_I_COMPLETE_NEEDED ||
status == SEC_I_COMPLETE_AND_CONTINUE)
diff --git a/lib/vauth/krb5_sspi.c b/lib/vauth/krb5_sspi.c
index 98041d91..1fb6257e 100644
--- a/lib/vauth/krb5_sspi.c
+++ b/lib/vauth/krb5_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2019, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 2020, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -125,7 +125,8 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data,
TEXT(SP_NAME_KERBEROS),
&SecurityPackage);
if(status != SEC_E_OK) {
- return CURLE_NOT_BUILT_IN;
+ failf(data, "SSPI: couldn't get auth info\n");
+ return CURLE_AUTH_ERROR;
}
krb5->token_max = SecurityPackage->cbMaxToken;
@@ -395,7 +396,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
return CURLE_OUT_OF_MEMORY;
/* Convert the user name to UTF8 when operating with Unicode */
- user_name = Curl_convert_tchar_to_UTF8(names.sUserName);
+ user_name = curlx_convert_tchar_to_UTF8(names.sUserName);
if(!user_name) {
free(trailer);
@@ -407,7 +408,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
message = malloc(messagelen);
if(!message) {
free(trailer);
- Curl_unicodefree(user_name);
+ curlx_unicodefree(user_name);
return CURLE_OUT_OF_MEMORY;
}
@@ -420,7 +421,7 @@ CURLcode Curl_auth_create_gssapi_security_message(struct Curl_easy *data,
outdata = htonl(max_size) | sec_layer;
memcpy(message, &outdata, sizeof(outdata));
strcpy((char *) message + sizeof(outdata), user_name);
- Curl_unicodefree(user_name);
+ curlx_unicodefree(user_name);
/* Allocate the padding */
padding = malloc(sizes.cbBlockSize);
diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c
index 8f910380..3b46e1a4 100644
--- a/lib/vauth/ntlm.c
+++ b/lib/vauth/ntlm.c
@@ -600,11 +600,14 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
#endif
#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
+
+#define CURL_MD5_DIGEST_LENGTH 16 /* fixed size */
+
/* We don't support NTLM2 if we don't have USE_NTRESPONSES */
if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) {
unsigned char ntbuffer[0x18];
unsigned char tmp[0x18];
- unsigned char md5sum[MD5_DIGEST_LENGTH];
+ unsigned char md5sum[CURL_MD5_DIGEST_LENGTH];
unsigned char entropy[8];
/* Need to create 8 bytes random data */
diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c
index cd6cb79c..84ea51da 100644
--- a/lib/vauth/ntlm_sspi.c
+++ b/lib/vauth/ntlm_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -105,8 +105,10 @@ CURLcode Curl_auth_create_ntlm_type1_message(struct Curl_easy *data,
/* Query the security package for NTLM */
status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT(SP_NAME_NTLM),
&SecurityPackage);
- if(status != SEC_E_OK)
- return CURLE_NOT_BUILT_IN;
+ if(status != SEC_E_OK) {
+ failf(data, "SSPI: couldn't get auth info\n");
+ return CURLE_AUTH_ERROR;
+ }
ntlm->token_max = SecurityPackage->cbMaxToken;
diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c
index b9c2cf7d..194f250f 100644
--- a/lib/vauth/spnego_sspi.c
+++ b/lib/vauth/spnego_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -129,8 +129,10 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
nego->status = s_pSecFn->QuerySecurityPackageInfo((TCHAR *)
TEXT(SP_NAME_NEGOTIATE),
&SecurityPackage);
- if(nego->status != SEC_E_OK)
- return CURLE_NOT_BUILT_IN;
+ if(nego->status != SEC_E_OK) {
+ failf(data, "SSPI: couldn't get auth info\n");
+ return CURLE_AUTH_ERROR;
+ }
nego->token_max = SecurityPackage->cbMaxToken;
diff --git a/lib/vauth/vauth.c b/lib/vauth/vauth.c
index a9c5c9c4..d98e66c6 100644
--- a/lib/vauth/vauth.c
+++ b/lib/vauth/vauth.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2014 - 2019, Steve Holme, <steve_holme@hotmail.com>.
+ * Copyright (C) 2014 - 2020, Steve Holme, <steve_holme@hotmail.com>.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -89,7 +89,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
}
/* Allocate our TCHAR based SPN */
- tchar_spn = Curl_convert_UTF8_to_tchar(utf8_spn);
+ tchar_spn = curlx_convert_UTF8_to_tchar(utf8_spn);
if(!tchar_spn) {
free(utf8_spn);
@@ -97,7 +97,7 @@ TCHAR *Curl_auth_build_spn(const char *service, const char *host,
}
/* Release the UTF8 variant when operating with Unicode */
- Curl_unicodefree(utf8_spn);
+ curlx_unicodefree(utf8_spn);
/* Return our newly allocated SPN */
return tchar_spn;
diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c
index 5f7b6e2e..d29cb378 100644
--- a/lib/vquic/ngtcp2.c
+++ b/lib/vquic/ngtcp2.c
@@ -38,6 +38,9 @@
#include "strcase.h"
#include "connect.h"
#include "strerror.h"
+#include "dynbuf.h"
+#include "vquic.h"
+#include "vtls/keylog.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -147,21 +150,24 @@ quic_from_gtls_level(gnutls_record_encryption_level_t gtls_level)
}
#endif
-static int setup_initial_crypto_context(struct quicsocket *qs)
+static void qlog_callback(void *user_data, const void *data, size_t datalen)
{
- const ngtcp2_cid *dcid = ngtcp2_conn_get_dcid(qs->qconn);
-
- if(ngtcp2_crypto_derive_and_install_initial_key(
- qs->qconn, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
- dcid) != 0)
- return -1;
+ struct quicsocket *qs = (struct quicsocket *)user_data;
+ if(qs->qlogfd != -1) {
+ ssize_t rc = write(qs->qlogfd, data, datalen);
+ if(rc == -1) {
+ /* on write error, stop further write attempts */
+ close(qs->qlogfd);
+ qs->qlogfd = -1;
+ }
+ }
- return 0;
}
-static void quic_settings(ngtcp2_settings *s,
+static void quic_settings(struct quicsocket *qs,
uint64_t stream_buffer_size)
{
+ ngtcp2_settings *s = &qs->settings;
ngtcp2_settings_default(s);
#ifdef DEBUG_NGTCP2
s->log_printf = quic_printf;
@@ -176,16 +182,16 @@ static void quic_settings(ngtcp2_settings *s,
s->transport_params.initial_max_streams_bidi = 1;
s->transport_params.initial_max_streams_uni = 3;
s->transport_params.max_idle_timeout = QUIC_IDLE_TIMEOUT;
+ if(qs->qlogfd != -1) {
+ s->qlog.write = qlog_callback;
+ }
}
-static FILE *keylog_file; /* not thread-safe */
#ifdef USE_OPENSSL
static void keylog_callback(const SSL *ssl, const char *line)
{
(void)ssl;
- fputs(line, keylog_file);
- fputc('\n', keylog_file);
- fflush(keylog_file);
+ Curl_tls_keylog_write_line(line);
}
#elif defined(USE_GNUTLS)
static int keylog_callback(gnutls_session_t session, const char *label,
@@ -193,36 +199,14 @@ static int keylog_callback(gnutls_session_t session, const char *label,
{
gnutls_datum_t crandom;
gnutls_datum_t srandom;
- gnutls_datum_t crandom_hex = { NULL, 0 };
- gnutls_datum_t secret_hex = { NULL, 0 };
- int rc = 0;
gnutls_session_get_random(session, &crandom, &srandom);
if(crandom.size != 32) {
return -1;
}
- rc = gnutls_hex_encode2(&crandom, &crandom_hex);
- if(rc < 0) {
- fprintf(stderr, "gnutls_hex_encode2 failed: %s\n",
- gnutls_strerror(rc));
- goto out;
- }
-
- rc = gnutls_hex_encode2(secret, &secret_hex);
- if(rc < 0) {
- fprintf(stderr, "gnutls_hex_encode2 failed: %s\n",
- gnutls_strerror(rc));
- goto out;
- }
-
- fprintf(keylog_file, "%s %s %s\n", label, crandom_hex.data, secret_hex.data);
- fflush(keylog_file);
-
- out:
- gnutls_free(crandom_hex.data);
- gnutls_free(secret_hex.data);
- return rc;
+ Curl_tls_keylog_write(label, crandom.data, secret->data, secret->size);
+ return 0;
}
#endif
@@ -271,13 +255,12 @@ static int quic_set_encryption_secrets(SSL *ssl,
struct quicsocket *qs = (struct quicsocket *)SSL_get_app_data(ssl);
int level = quic_from_ossl_level(ossl_level);
- if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
- ngtcp2_crypto_derive_and_install_rx_key(
- qs->qconn, ssl, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
+ if(ngtcp2_crypto_derive_and_install_rx_key(
+ qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
return 0;
if(ngtcp2_crypto_derive_and_install_tx_key(
- qs->qconn, ssl, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
+ qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
return 0;
if(level == NGTCP2_CRYPTO_LEVEL_APP) {
@@ -320,7 +303,6 @@ static SSL_QUIC_METHOD quic_method = {quic_set_encryption_secrets,
static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
{
SSL_CTX *ssl_ctx = SSL_CTX_new(TLS_method());
- const char *keylog_filename;
SSL_CTX_set_min_proto_version(ssl_ctx, TLS1_3_VERSION);
SSL_CTX_set_max_proto_version(ssl_ctx, TLS1_3_VERSION);
@@ -341,12 +323,10 @@ static SSL_CTX *quic_ssl_ctx(struct Curl_easy *data)
SSL_CTX_set_quic_method(ssl_ctx, &quic_method);
- keylog_filename = getenv("SSLKEYLOGFILE");
- if(keylog_filename) {
- keylog_file = fopen(keylog_filename, "wb");
- if(keylog_file) {
- SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
- }
+ /* Open the file if a TLS or QUIC backend has not done this before. */
+ Curl_tls_keylog_open();
+ if(Curl_tls_keylog_enabled()) {
+ SSL_CTX_set_keylog_callback(ssl_ctx, keylog_callback);
}
return ssl_ctx;
@@ -361,9 +341,7 @@ static int quic_init_ssl(struct quicsocket *qs)
/* this will need some attention when HTTPS proxy over QUIC get fixed */
const char * const hostname = qs->conn->host.name;
- if(qs->ssl)
- SSL_free(qs->ssl);
-
+ DEBUGASSERT(!qs->ssl);
qs->ssl = SSL_new(qs->sslctx);
SSL_set_app_data(qs->ssl, qs);
@@ -372,8 +350,8 @@ static int quic_init_ssl(struct quicsocket *qs)
switch(qs->version) {
#ifdef NGTCP2_PROTO_VER
case NGTCP2_PROTO_VER:
- alpn = (const uint8_t *)NGTCP2_ALPN_H3;
- alpnlen = sizeof(NGTCP2_ALPN_H3) - 1;
+ alpn = (const uint8_t *)NGHTTP3_ALPN_H3;
+ alpnlen = sizeof(NGHTTP3_ALPN_H3) - 1;
break;
#endif
}
@@ -395,11 +373,11 @@ static int secret_func(gnutls_session_t ssl,
if(level != NGTCP2_CRYPTO_LEVEL_EARLY &&
ngtcp2_crypto_derive_and_install_rx_key(
- qs->qconn, ssl, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
+ qs->qconn, NULL, NULL, NULL, level, rx_secret, secretlen) != 0)
return 0;
if(ngtcp2_crypto_derive_and_install_tx_key(
- qs->qconn, ssl, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
+ qs->qconn, NULL, NULL, NULL, level, tx_secret, secretlen) != 0)
return 0;
if(level == NGTCP2_CRYPTO_LEVEL_APP) {
@@ -449,8 +427,8 @@ static int tp_recv_func(gnutls_session_t ssl, const uint8_t *data,
ngtcp2_transport_params params;
if(ngtcp2_decode_transport_params(
- &params, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS,
- data, data_size) != 0)
+ &params, NGTCP2_TRANSPORT_PARAMS_TYPE_ENCRYPTED_EXTENSIONS,
+ data, data_size) != 0)
return -1;
if(ngtcp2_conn_set_remote_transport_params(qs->qconn, &params) != 0)
@@ -472,8 +450,8 @@ static int tp_send_func(gnutls_session_t ssl, gnutls_buffer_t extdata)
paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
&params);
if(nwrite < 0) {
- fprintf(stderr, "ngtcp2_encode_transport_params: %s\n",
- ngtcp2_strerror((int)nwrite));
+ H3BUGF(fprintf(stderr, "ngtcp2_encode_transport_params: %s\n",
+ ngtcp2_strerror((int)nwrite)));
return -1;
}
@@ -489,19 +467,17 @@ static int quic_init_ssl(struct quicsocket *qs)
gnutls_datum_t alpn = {NULL, 0};
/* this will need some attention when HTTPS proxy over QUIC get fixed */
const char * const hostname = qs->conn->host.name;
- const char *keylog_filename;
int rc;
- if(qs->ssl)
- gnutls_deinit(qs->ssl);
+ DEBUGASSERT(!qs->ssl);
gnutls_init(&qs->ssl, GNUTLS_CLIENT);
gnutls_session_set_ptr(qs->ssl, qs);
rc = gnutls_priority_set_direct(qs->ssl, QUIC_PRIORITY, NULL);
if(rc < 0) {
- fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
- gnutls_strerror(rc));
+ H3BUGF(fprintf(stderr, "gnutls_priority_set_direct failed: %s\n",
+ gnutls_strerror(rc)));
return 1;
}
@@ -517,17 +493,15 @@ static int quic_init_ssl(struct quicsocket *qs)
GNUTLS_EXT_FLAG_CLIENT_HELLO |
GNUTLS_EXT_FLAG_EE);
if(rc < 0) {
- fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
- gnutls_strerror(rc));
+ H3BUGF(fprintf(stderr, "gnutls_session_ext_register failed: %s\n",
+ gnutls_strerror(rc)));
return 1;
}
- keylog_filename = getenv("SSLKEYLOGFILE");
- if(keylog_filename) {
- keylog_file = fopen(keylog_filename, "wb");
- if(keylog_file) {
- gnutls_session_set_keylog_function(qs->ssl, keylog_callback);
- }
+ /* 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(qs->ssl, keylog_callback);
}
if(qs->cred)
@@ -535,31 +509,33 @@ static int quic_init_ssl(struct quicsocket *qs)
rc = gnutls_certificate_allocate_credentials(&qs->cred);
if(rc < 0) {
- fprintf(stderr, "gnutls_certificate_allocate_credentials failed: %s\n",
- gnutls_strerror(rc));
+ H3BUGF(fprintf(stderr,
+ "gnutls_certificate_allocate_credentials failed: %s\n",
+ gnutls_strerror(rc)));
return 1;
}
rc = gnutls_certificate_set_x509_system_trust(qs->cred);
if(rc < 0) {
- fprintf(stderr, "gnutls_certificate_set_x509_system_trust failed: %s\n",
- gnutls_strerror(rc));
+ H3BUGF(fprintf(stderr,
+ "gnutls_certificate_set_x509_system_trust failed: %s\n",
+ gnutls_strerror(rc)));
return 1;
}
rc = gnutls_credentials_set(qs->ssl, GNUTLS_CRD_CERTIFICATE, qs->cred);
if(rc < 0) {
- fprintf(stderr, "gnutls_credentials_set failed: %s\n",
- gnutls_strerror(rc));
+ H3BUGF(fprintf(stderr, "gnutls_credentials_set failed: %s\n",
+ gnutls_strerror(rc)));
return 1;
}
switch(qs->version) {
#ifdef NGTCP2_PROTO_VER
case NGTCP2_PROTO_VER:
- /* strip the first byte from NGTCP2_ALPN_H3 */
- alpn.data = (unsigned char *)NGTCP2_ALPN_H3 + 1;
- alpn.size = sizeof(NGTCP2_ALPN_H3) - 2;
+ /* strip the first byte (the length) from NGHTTP3_ALPN_H3 */
+ alpn.data = (unsigned char *)NGHTTP3_ALPN_H3 + 1;
+ alpn.size = sizeof(NGHTTP3_ALPN_H3) - 2;
break;
#endif
}
@@ -572,27 +548,16 @@ static int quic_init_ssl(struct quicsocket *qs)
}
#endif
-static int cb_initial(ngtcp2_conn *quic, void *user_data)
-{
- struct quicsocket *qs = (struct quicsocket *)user_data;
-
- if(ngtcp2_crypto_read_write_crypto_data(
- quic, qs->ssl, NGTCP2_CRYPTO_LEVEL_INITIAL, NULL, 0) != 0)
- return NGTCP2_ERR_CALLBACK_FAILURE;
-
- return 0;
-}
-
static int
cb_recv_crypto_data(ngtcp2_conn *tconn, ngtcp2_crypto_level crypto_level,
uint64_t offset,
const uint8_t *data, size_t datalen,
void *user_data)
{
- struct quicsocket *qs = (struct quicsocket *)user_data;
(void)offset;
+ (void)user_data;
- if(ngtcp2_crypto_read_write_crypto_data(tconn, qs->ssl, crypto_level, data,
+ if(ngtcp2_crypto_read_write_crypto_data(tconn, crypto_level, data,
datalen) != 0)
return NGTCP2_ERR_CRYPTO;
@@ -618,13 +583,14 @@ static void extend_stream_window(ngtcp2_conn *tconn,
}
-static int cb_recv_stream_data(ngtcp2_conn *tconn, int64_t stream_id,
- int fin, uint64_t offset,
+static int cb_recv_stream_data(ngtcp2_conn *tconn, uint32_t flags,
+ int64_t stream_id, uint64_t offset,
const uint8_t *buf, size_t buflen,
void *user_data, void *stream_user_data)
{
struct quicsocket *qs = (struct quicsocket *)user_data;
ssize_t nconsumed;
+ int fin = flags & NGTCP2_STREAM_DATA_FLAG_FIN ? 1 : 0;
(void)offset;
(void)stream_user_data;
@@ -710,20 +676,6 @@ static int cb_stream_reset(ngtcp2_conn *tconn, int64_t stream_id,
return 0;
}
-static int cb_recv_retry(ngtcp2_conn *tconn, const ngtcp2_pkt_hd *hd,
- const ngtcp2_pkt_retry *retry, void *user_data)
-{
- /* Re-generate handshake secrets here because connection ID might change. */
- struct quicsocket *qs = (struct quicsocket *)user_data;
- (void)tconn;
- (void)hd;
- (void)retry;
-
- setup_initial_crypto_context(qs);
-
- return 0;
-}
-
static int cb_extend_max_local_streams_bidi(ngtcp2_conn *tconn,
uint64_t max_streams,
void *user_data)
@@ -776,7 +728,7 @@ static int cb_get_new_connection_id(ngtcp2_conn *tconn, ngtcp2_cid *cid,
}
static ngtcp2_conn_callbacks ng_callbacks = {
- cb_initial,
+ ngtcp2_crypto_client_initial_cb,
NULL, /* recv_client_initial */
cb_recv_crypto_data,
cb_handshake_completed,
@@ -790,7 +742,7 @@ static ngtcp2_conn_callbacks ng_callbacks = {
NULL, /* stream_open */
cb_stream_close,
NULL, /* recv_stateless_reset */
- cb_recv_retry,
+ ngtcp2_crypto_recv_retry_cb,
cb_extend_max_local_streams_bidi,
NULL, /* extend_max_local_streams_uni */
NULL, /* rand */
@@ -804,7 +756,10 @@ static ngtcp2_conn_callbacks ng_callbacks = {
NULL, /* extend_max_remote_streams_uni */
cb_extend_max_stream_data,
NULL, /* dcid_status */
- NULL /* handshake_confirmed */
+ NULL, /* handshake_confirmed */
+ NULL, /* recv_new_token */
+ ngtcp2_crypto_delete_crypto_aead_ctx_cb,
+ ngtcp2_crypto_delete_crypto_cipher_ctx_cb
};
/*
@@ -824,12 +779,10 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
struct quicsocket *qs = &conn->hequic[sockindex];
char ipbuf[40];
long port;
-#ifdef USE_OPENSSL
- uint8_t paramsbuf[64];
- ngtcp2_transport_params params;
- ssize_t nwrite;
-#endif
+ int qfd;
+ if(qs->conn)
+ Curl_quic_disconnect(conn, sockindex);
qs->conn = conn;
/* extract the used address as a string */
@@ -863,7 +816,9 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
if(result)
return result;
- quic_settings(&qs->settings, data->set.buffer_size);
+ (void)Curl_qlogdir(data, qs->scid.data, NGTCP2_MAX_CIDLEN, &qfd);
+ qs->qlogfd = qfd; /* -1 if failure above */
+ quic_settings(qs, data->set.buffer_size);
qs->local_addrlen = sizeof(qs->local_addr);
rv = getsockname(sockfd, (struct sockaddr *)&qs->local_addr,
@@ -885,24 +840,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn,
if(rc)
return CURLE_QUIC_CONNECT_ERROR;
-#ifdef USE_OPENSSL
- ngtcp2_conn_get_local_transport_params(qs->qconn, &params);
- nwrite = ngtcp2_encode_transport_params(
- paramsbuf, sizeof(paramsbuf), NGTCP2_TRANSPORT_PARAMS_TYPE_CLIENT_HELLO,
- &params);
- if(nwrite < 0) {
- failf(data, "ngtcp2_encode_transport_params: %s\n",
- ngtcp2_strerror((int)nwrite));
- return CURLE_QUIC_CONNECT_ERROR;
- }
-
- if(!SSL_set_quic_transport_params(qs->ssl, paramsbuf, nwrite))
- return CURLE_QUIC_CONNECT_ERROR;
-#endif
-
- rc = setup_initial_crypto_context(qs);
- if(rc)
- return CURLE_QUIC_CONNECT_ERROR;
+ ngtcp2_conn_set_tls_native_handle(qs->qconn, qs->ssl);
return CURLE_OK;
}
@@ -943,29 +881,49 @@ static int ng_perform_getsock(const struct connectdata *conn,
return ng_getsock((struct connectdata *)conn, socks);
}
-static CURLcode ng_disconnect(struct connectdata *conn,
- bool dead_connection)
+static void qs_disconnect(struct quicsocket *qs)
{
int i;
- struct quicsocket *qs = &conn->hequic[0];
- (void)dead_connection;
+ if(!qs->conn) /* already closed */
+ return;
+ qs->conn = NULL;
+ if(qs->qlogfd != -1) {
+ close(qs->qlogfd);
+ qs->qlogfd = -1;
+ }
if(qs->ssl)
#ifdef USE_OPENSSL
SSL_free(qs->ssl);
#elif defined(USE_GNUTLS)
gnutls_deinit(qs->ssl);
#endif
+ qs->ssl = NULL;
#ifdef USE_GNUTLS
if(qs->cred)
gnutls_certificate_free_credentials(qs->cred);
#endif
for(i = 0; i < 3; i++)
- free(qs->crypto_data[i].buf);
+ Curl_safefree(qs->crypto_data[i].buf);
nghttp3_conn_del(qs->h3conn);
ngtcp2_conn_del(qs->qconn);
#ifdef USE_OPENSSL
SSL_CTX_free(qs->sslctx);
#endif
+}
+
+void Curl_quic_disconnect(struct connectdata *conn,
+ int tempindex)
+{
+ if(conn->transport == TRNSPRT_QUIC)
+ qs_disconnect(&conn->hequic[tempindex]);
+}
+
+static CURLcode ng_disconnect(struct connectdata *conn,
+ bool dead_connection)
+{
+ (void)dead_connection;
+ Curl_quic_disconnect(conn, 0);
+ Curl_quic_disconnect(conn, 1);
return CURLE_OK;
}
@@ -1018,57 +976,12 @@ static int cb_h3_stream_close(nghttp3_conn *conn, int64_t stream_id,
return 0;
}
-/* Minimum size of the overflow buffer */
-#define OVERFLOWSIZE 1024
-
-/*
- * allocate_overflow() ensures that there is room for incoming data in the
- * overflow buffer, growing it to accommodate the new data if necessary. We
- * may need to use the overflow buffer because we can't precisely limit the
- * amount of HTTP/3 header data we receive using QUIC flow control mechanisms.
- */
-static CURLcode allocate_overflow(struct Curl_easy *data,
- struct HTTP *stream,
- size_t length)
-{
- size_t maxleft;
- size_t newsize;
- /* length can be arbitrarily large, so take care not to overflow newsize */
- maxleft = CURL_MAX_READ_SIZE - stream->overflow_buflen;
- if(length > maxleft) {
- /* The reason to have a max limit for this is to avoid the risk of a bad
- server feeding libcurl with a highly compressed list of headers that
- will cause our overflow buffer to grow too large */
- failf(data, "Rejected %zu bytes of overflow data (max is %d)!",
- stream->overflow_buflen + length, CURL_MAX_READ_SIZE);
- return CURLE_OUT_OF_MEMORY;
- }
- newsize = stream->overflow_buflen + length;
- if(newsize > stream->overflow_bufsize) {
- /* We enlarge the overflow buffer as it is too small */
- char *newbuff;
- newsize = CURLMAX(newsize * 3 / 2, stream->overflow_bufsize*2);
- newsize = CURLMIN(CURLMAX(OVERFLOWSIZE, newsize), CURL_MAX_READ_SIZE);
- newbuff = realloc(stream->overflow_buf, newsize);
- if(!newbuff) {
- failf(data, "Failed to alloc memory for overflow buffer!");
- return CURLE_OUT_OF_MEMORY;
- }
- stream->overflow_buf = newbuff;
- stream->overflow_bufsize = newsize;
- infof(data, "Grew HTTP/3 overflow buffer to %zu bytes\n", newsize);
- }
- return CURLE_OK;
-}
-
/*
* write_data() copies data to the stream's receive buffer. If not enough
* space is available in the receive buffer, it copies the rest to the
* stream's overflow buffer.
*/
-static CURLcode write_data(struct Curl_easy *data,
- struct HTTP *stream,
- const void *mem, size_t memlen)
+static CURLcode write_data(struct HTTP *stream, const void *mem, size_t memlen)
{
CURLcode result = CURLE_OK;
const char *buf = mem;
@@ -1076,10 +989,6 @@ static CURLcode write_data(struct Curl_easy *data,
/* copy as much as possible to the receive buffer */
if(stream->len) {
size_t len = CURLMIN(ncopy, stream->len);
-#if 0 /* extra debugging of incoming h3 data */
- fprintf(stderr, "!! Copies %zd bytes to %p (total %zd)\n",
- len, stream->mem, stream->memlen);
-#endif
memcpy(stream->mem, buf, len);
stream->len -= len;
stream->memlen += len;
@@ -1088,26 +997,8 @@ static CURLcode write_data(struct Curl_easy *data,
ncopy -= len;
}
/* copy the rest to the overflow buffer */
- if(ncopy) {
- result = allocate_overflow(data, stream, ncopy);
- if(result) {
- return result;
- }
-#if 0 /* extra debugging of incoming h3 data */
- fprintf(stderr, "!! Copies %zd overflow bytes to %p (total %zd)\n",
- ncopy, stream->overflow_buf, stream->overflow_buflen);
-#endif
- memcpy(stream->overflow_buf + stream->overflow_buflen, buf, ncopy);
- stream->overflow_buflen += ncopy;
- }
-#if 0 /* extra debugging of incoming h3 data */
- {
- size_t i;
- for(i = 0; i < memlen; i++) {
- fprintf(stderr, "!! data[%d]: %02x '%c'\n", i, buf[i], buf[i]);
- }
- }
-#endif
+ if(ncopy)
+ result = Curl_dyn_addn(&stream->overflow, buf, ncopy);
return result;
}
@@ -1120,7 +1011,7 @@ static int cb_h3_recv_data(nghttp3_conn *conn, int64_t stream_id,
CURLcode result = CURLE_OK;
(void)conn;
- result = write_data(data, stream, buf, buflen);
+ result = write_data(stream, buf, buflen);
if(result) {
return -1;
}
@@ -1183,7 +1074,7 @@ static int cb_h3_end_headers(nghttp3_conn *conn, int64_t stream_id,
/* add a CRLF only if we've received some headers */
if(stream->firstheader) {
- result = write_data(data, stream, "\r\n", 2);
+ result = write_data(stream, "\r\n", 2);
if(result) {
return -1;
}
@@ -1214,26 +1105,26 @@ static int cb_h3_recv_header(nghttp3_conn *conn, int64_t stream_id,
int status = decode_status_code(h3val.base, h3val.len);
DEBUGASSERT(status != -1);
ncopy = msnprintf(line, sizeof(line), "HTTP/3 %03d \r\n", status);
- result = write_data(data, stream, line, ncopy);
+ result = write_data(stream, line, ncopy);
if(result) {
return -1;
}
}
else {
/* store as a HTTP1-style header */
- result = write_data(data, stream, h3name.base, h3name.len);
+ result = write_data(stream, h3name.base, h3name.len);
if(result) {
return -1;
}
- result = write_data(data, stream, ": ", 2);
+ result = write_data(stream, ": ", 2);
if(result) {
return -1;
}
- result = write_data(data, stream, h3val.base, h3val.len);
+ result = write_data(stream, h3val.base, h3val.len);
if(result) {
return -1;
}
- result = write_data(data, stream, "\r\n", 2);
+ result = write_data(stream, "\r\n", 2);
if(result) {
return -1;
}
@@ -1341,15 +1232,16 @@ static Curl_send ngh3_stream_send;
static size_t drain_overflow_buffer(struct HTTP *stream)
{
- size_t ncopy = CURLMIN(stream->overflow_buflen, stream->len);
+ size_t overlen = Curl_dyn_len(&stream->overflow);
+ size_t ncopy = CURLMIN(overlen, stream->len);
if(ncopy > 0) {
- memcpy(stream->mem, stream->overflow_buf, ncopy);
+ memcpy(stream->mem, Curl_dyn_ptr(&stream->overflow), ncopy);
stream->len -= ncopy;
stream->mem += ncopy;
stream->memlen += ncopy;
- stream->overflow_buflen -= ncopy;
- memmove(stream->overflow_buf, stream->overflow_buf + ncopy,
- stream->overflow_buflen);
+ if(ncopy != overlen)
+ /* make the buffer only keep the tail */
+ (void)Curl_dyn_tail(&stream->overflow, overlen - ncopy);
}
return ncopy;
}
@@ -1528,6 +1420,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
stream->stream3_id = stream3_id;
stream->h3req = TRUE; /* senf off! */
+ Curl_dyn_init(&stream->overflow, CURL_MAX_READ_SIZE);
/* Calculate number of headers contained in [mem, mem + len). Assumes a
correctly generated HTTP header field block. */
@@ -1684,7 +1577,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
}
}
- switch(data->set.httpreq) {
+ switch(data->state.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
case HTTPREQ_POST_MIME:
@@ -1806,11 +1699,11 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn,
result = ng_process_ingress(conn, sockfd, qs);
if(result)
- return result;
+ goto error;
result = ng_flush_egress(conn, sockfd, qs);
if(result)
- return result;
+ goto error;
if(ngtcp2_conn_get_handshake_completed(qs->qconn)) {
*done = TRUE;
@@ -1818,6 +1711,10 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn,
}
return result;
+ error:
+ (void)qs_disconnect(qs);
+ return result;
+
}
static CURLcode ng_process_ingress(struct connectdata *conn, int sockfd,
@@ -1914,11 +1811,12 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
return CURLE_SEND_ERROR;
}
else if(veccnt > 0) {
+ uint32_t flags = NGTCP2_WRITE_STREAM_FLAG_MORE |
+ (fin ? NGTCP2_WRITE_STREAM_FLAG_FIN : 0);
outlen =
ngtcp2_conn_writev_stream(qs->qconn, &ps.path,
out, pktlen, &ndatalen,
- NGTCP2_WRITE_STREAM_FLAG_MORE,
- stream_id, fin,
+ flags, stream_id,
(const ngtcp2_vec *)vec, veccnt, ts);
if(outlen == 0) {
break;
@@ -1926,6 +1824,7 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
if(outlen < 0) {
if(outlen == NGTCP2_ERR_STREAM_DATA_BLOCKED ||
outlen == NGTCP2_ERR_STREAM_SHUT_WR) {
+ assert(ndatalen == -1);
rv = nghttp3_conn_block_stream(qs->h3conn, stream_id);
if(rv != 0) {
failf(conn->data,
@@ -1948,19 +1847,14 @@ static CURLcode ng_flush_egress(struct connectdata *conn, int sockfd,
continue;
}
else {
+ assert(ndatalen == -1);
failf(conn->data, "ngtcp2_conn_writev_stream returned error: %s\n",
ngtcp2_strerror((int)outlen));
return CURLE_SEND_ERROR;
}
}
- else if(ndatalen >= 0) {
- rv = nghttp3_conn_add_write_offset(qs->h3conn, stream_id, ndatalen);
- if(rv != 0) {
- failf(conn->data,
- "nghttp3_conn_add_write_offset returned error: %s\n",
- nghttp3_strerror(rv));
- return CURLE_SEND_ERROR;
- }
+ else {
+ assert(ndatalen == -1);
}
}
}
@@ -2032,7 +1926,7 @@ void Curl_quic_done(struct Curl_easy *data, bool premature)
if(data->conn->handler == &Curl_handler_http3) {
/* only for HTTP/3 transfers */
struct HTTP *stream = data->req.protop;
- Curl_safefree(stream->overflow_buf);
+ Curl_dyn_free(&stream->overflow);
}
}
@@ -2047,7 +1941,7 @@ bool Curl_quic_data_pending(const struct Curl_easy *data)
there's no more data coming on the socket, we need to keep reading
until the overflow buffer is empty. */
const struct HTTP *stream = data->req.protop;
- return stream->overflow_buflen > 0;
+ return Curl_dyn_len(&stream->overflow) > 0;
}
#endif
diff --git a/lib/vquic/ngtcp2.h b/lib/vquic/ngtcp2.h
index 06337f6f..e2f8b560 100644
--- a/lib/vquic/ngtcp2.h
+++ b/lib/vquic/ngtcp2.h
@@ -63,6 +63,7 @@ struct quicsocket {
nghttp3_conn *h3conn;
nghttp3_conn_settings h3settings;
+ int qlogfd;
};
#include "urldata.h"
diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c
index c40e5e93..be6f15c1 100644
--- a/lib/vquic/quiche.c
+++ b/lib/vquic/quiche.c
@@ -34,6 +34,7 @@
#include "multiif.h"
#include "connect.h"
#include "strerror.h"
+#include "vquic.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -64,7 +65,6 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
static Curl_recv h3_stream_recv;
static Curl_send h3_stream_send;
-
static int quiche_getsock(struct connectdata *conn, curl_socket_t *socks)
{
struct SingleRequest *k = &conn->data->req;
@@ -89,16 +89,30 @@ static int quiche_perform_getsock(const struct connectdata *conn,
return quiche_getsock((struct connectdata *)conn, socks);
}
+static CURLcode qs_disconnect(struct quicsocket *qs)
+{
+ if(qs->h3config)
+ quiche_h3_config_free(qs->h3config);
+ if(qs->h3c)
+ quiche_h3_conn_free(qs->h3c);
+ quiche_config_free(qs->cfg);
+ quiche_conn_free(qs->conn);
+ return CURLE_OK;
+}
+
static CURLcode quiche_disconnect(struct connectdata *conn,
bool dead_connection)
{
struct quicsocket *qs = conn->quic;
(void)dead_connection;
- quiche_h3_config_free(qs->h3config);
- quiche_h3_conn_free(qs->h3c);
- quiche_config_free(qs->cfg);
- quiche_conn_free(qs->conn);
- return CURLE_OK;
+ return qs_disconnect(qs);
+}
+
+void Curl_quic_disconnect(struct connectdata *conn,
+ int tempindex)
+{
+ if(conn->transport == TRNSPRT_QUIC)
+ qs_disconnect(&conn->hequic[tempindex]);
}
static unsigned int quiche_conncheck(struct connectdata *conn,
@@ -152,6 +166,7 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
CURLcode result;
struct quicsocket *qs = &conn->hequic[sockindex];
struct Curl_easy *data = conn->data;
+ char *keylog_file = NULL;
#ifdef DEBUG_QUICHE
/* initialize debug log callback only once */
@@ -189,7 +204,9 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
if(result)
return result;
- if(getenv("SSLKEYLOGFILE"))
+ keylog_file = getenv("SSLKEYLOGFILE");
+
+ if(keylog_file)
quiche_config_log_keys(qs->cfg);
qs->conn = quiche_connect(conn->host.name, (const uint8_t *) qs->scid,
@@ -199,6 +216,20 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
return CURLE_OUT_OF_MEMORY;
}
+ if(keylog_file)
+ quiche_conn_set_keylog_path(qs->conn, keylog_file);
+
+ /* Known to not work on Windows */
+#if !defined(WIN32) && defined(HAVE_QUICHE_CONN_SET_QLOG_FD)
+ {
+ int qfd;
+ (void)Curl_qlogdir(data, qs->scid, sizeof(qs->scid), &qfd);
+ if(qfd != -1)
+ quiche_conn_set_qlog_fd(qs->conn, qfd,
+ "qlog title", "curl qlog");
+ }
+#endif
+
result = flush_egress(conn, sockfd, qs);
if(result)
return result;
@@ -217,8 +248,20 @@ CURLcode Curl_quic_connect(struct connectdata *conn, curl_socket_t sockfd,
/* for connection reuse purposes: */
conn->ssl[FIRSTSOCKET].state = ssl_connection_complete;
- infof(data, "Sent QUIC client Initial, ALPN: %s\n",
- QUICHE_H3_APPLICATION_PROTOCOL + 1);
+ {
+ unsigned char alpn_protocols[] = QUICHE_H3_APPLICATION_PROTOCOL;
+ unsigned alpn_len, offset = 0;
+
+ /* Replace each ALPN length prefix by a comma. */
+ while(offset < sizeof(alpn_protocols) - 1) {
+ alpn_len = alpn_protocols[offset];
+ alpn_protocols[offset] = ',';
+ offset += 1 + alpn_len;
+ }
+
+ infof(data, "Sent QUIC client Initial, ALPN: %s\n",
+ alpn_protocols + 1);
+ }
return CURLE_OK;
}
@@ -273,11 +316,11 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex,
result = process_ingress(conn, sockfd, qs);
if(result)
- return result;
+ goto error;
result = flush_egress(conn, sockfd, qs);
if(result)
- return result;
+ goto error;
if(quiche_conn_is_established(qs->conn)) {
*done = TRUE;
@@ -286,6 +329,9 @@ CURLcode Curl_quic_is_connected(struct connectdata *conn, int sockindex,
}
return result;
+ error:
+ qs_disconnect(qs);
+ return result;
}
static CURLcode process_ingress(struct connectdata *conn, int sockfd,
@@ -714,7 +760,7 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
}
}
- switch(data->set.httpreq) {
+ switch(data->state.httpreq) {
case HTTPREQ_POST:
case HTTPREQ_POST_FORM:
case HTTPREQ_POST_MIME:
diff --git a/lib/vquic/vquic.c b/lib/vquic/vquic.c
new file mode 100644
index 00000000..aae8e095
--- /dev/null
+++ b/lib/vquic/vquic.c
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef ENABLE_QUIC
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#include "urldata.h"
+#include "dynbuf.h"
+#include "curl_printf.h"
+#include "vquic.h"
+
+#ifdef O_BINARY
+#define QLOGMODE O_WRONLY|O_CREAT|O_BINARY
+#else
+#define QLOGMODE O_WRONLY|O_CREAT
+#endif
+
+/*
+ * If the QLOGDIR environment variable is set, open and return a file
+ * descriptor to write the log to.
+ *
+ * This function returns error if something failed outside of failing to
+ * create the file. Open file success is deemed by seeing if the returned fd
+ * is != -1.
+ */
+CURLcode Curl_qlogdir(struct Curl_easy *data,
+ unsigned char *scid,
+ size_t scidlen,
+ int *qlogfdp)
+{
+ const char *qlog_dir = getenv("QLOGDIR");
+ *qlogfdp = -1;
+ if(qlog_dir) {
+ struct dynbuf fname;
+ CURLcode result;
+ unsigned int i;
+ Curl_dyn_init(&fname, DYN_QLOG_NAME);
+ result = Curl_dyn_add(&fname, qlog_dir);
+ if(!result)
+ result = Curl_dyn_add(&fname, "/");
+ for(i = 0; (i < scidlen) && !result; i++) {
+ char hex[3];
+ msnprintf(hex, 3, "%02x", scid[i]);
+ result = Curl_dyn_add(&fname, hex);
+ }
+ if(!result)
+ result = Curl_dyn_add(&fname, ".qlog");
+
+ if(!result) {
+ int qlogfd = open(Curl_dyn_ptr(&fname), QLOGMODE,
+ data->set.new_file_perms);
+ if(qlogfd != -1)
+ *qlogfdp = qlogfd;
+ }
+ Curl_dyn_free(&fname);
+ if(result)
+ return result;
+ }
+
+ return CURLE_OK;
+}
+#endif
diff --git a/lib/vquic/vquic.h b/lib/vquic/vquic.h
new file mode 100644
index 00000000..ecff0edf
--- /dev/null
+++ b/lib/vquic/vquic.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_VQUIC_QUIC_H
+#define HEADER_CURL_VQUIC_QUIC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifdef ENABLE_QUIC
+CURLcode Curl_qlogdir(struct Curl_easy *data,
+ unsigned char *scid,
+ size_t scidlen,
+ int *qlogfdp);
+#endif
+
+#endif /* HEADER_CURL_VQUIC_QUIC_H */
diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c
index c487ccab..555afc9e 100644
--- a/lib/vssh/libssh2.c
+++ b/lib/vssh/libssh2.c
@@ -93,15 +93,12 @@
#define HAS_STATVFS_SUPPORT 1
#endif
-#define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s))
-
-#define sftp_libssh2_realpath(s,p,t,m) \
- libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \
- (t), (m), LIBSSH2_SFTP_REALPATH)
-
+#define sftp_libssh2_realpath(s,p,t,m) \
+ libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \
+ (t), (m), LIBSSH2_SFTP_REALPATH)
/* Local functions: */
-static const char *sftp_libssh2_strerror(int err);
+static const char *sftp_libssh2_strerror(unsigned long err);
static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
static LIBSSH2_FREE_FUNC(my_libssh2_free);
@@ -213,7 +210,7 @@ kbd_callback(const char *name, int name_len, const char *instruction,
(void)abstract;
} /* kbd_callback */
-static CURLcode sftp_libssh2_error_to_CURLE(int err)
+static CURLcode sftp_libssh2_error_to_CURLE(unsigned long err)
{
switch(err) {
case LIBSSH2_FX_OK:
@@ -795,10 +792,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
struct SSHPROTO *sftp_scp = data->req.protop;
struct ssh_conn *sshc = &conn->proto.sshc;
curl_socket_t sock = conn->sock[FIRSTSOCKET];
- char *new_readdir_line;
int rc = LIBSSH2_ERROR_NONE;
- int err;
+ int ssherr;
+ unsigned long sftperr;
int seekerr = CURL_SEEKFUNC_OK;
+ size_t readdir_len;
*block = 0; /* we're not blocking by default */
do {
@@ -874,12 +872,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
state(conn, SSH_AUTH_DONE);
break;
}
- err = libssh2_session_last_errno(sshc->ssh_session);
- if(err == LIBSSH2_ERROR_EAGAIN)
+ ssherr = libssh2_session_last_errno(sshc->ssh_session);
+ if(ssherr == LIBSSH2_ERROR_EAGAIN)
rc = LIBSSH2_ERROR_EAGAIN;
else {
state(conn, SSH_SESSION_FREE);
- sshc->actualcode = libssh2_session_error_to_CURLE(err);
+ sshc->actualcode = libssh2_session_error_to_CURLE(ssherr);
}
break;
}
@@ -1249,16 +1247,16 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
else {
/* Return the error type */
- err = sftp_libssh2_last_error(sshc->sftp_session);
- if(err)
- result = sftp_libssh2_error_to_CURLE(err);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+ if(sftperr)
+ result = sftp_libssh2_error_to_CURLE(sftperr);
else
/* in this case, the error wasn't in the SFTP level but for example
a time-out or similar */
result = CURLE_SSH;
sshc->actualcode = result;
DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
- err, (int)result));
+ ssherr, (int)result));
state(conn, SSH_STOP);
break;
}
@@ -1360,7 +1358,8 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
*/
cp = strchr(cmd, ' ');
if(cp == NULL) {
- failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
+ failf(data, "Syntax error command '%s'. Missing parameter!",
+ cmd);
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1376,7 +1375,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
if(result == CURLE_OUT_OF_MEMORY)
failf(data, "Out of memory");
else
- failf(data, "Syntax error: Bad first parameter");
+ failf(data, "Syntax error: Bad first parameter to '%s'", cmd);
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = result;
@@ -1401,8 +1400,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
if(result == CURLE_OUT_OF_MEMORY)
failf(data, "Out of memory");
else
- failf(data, "Syntax error in chgrp/chmod/chown: "
- "Bad second parameter");
+ failf(data, "Syntax error in %s: Bad second parameter", cmd);
Curl_safefree(sshc->quote_path1);
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
@@ -1533,11 +1531,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc != 0 && !sshc->acceptfail) { /* get those attributes */
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to get SFTP stats failed: %s",
- sftp_libssh2_strerror(err));
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1604,11 +1602,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc != 0 && !sshc->acceptfail) {
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "Attempt to set SFTP stats failed: %s",
- sftp_libssh2_strerror(err));
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1627,11 +1625,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc != 0 && !sshc->acceptfail) {
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
failf(data, "symlink command failed: %s",
- sftp_libssh2_strerror(err));
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1648,9 +1646,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc != 0 && !sshc->acceptfail) {
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
- failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
+ failf(data, "mkdir command failed: %s",
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1672,10 +1671,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc != 0 && !sshc->acceptfail) {
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
- failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
+ failf(data, "rename command failed: %s",
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1691,9 +1691,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc != 0 && !sshc->acceptfail) {
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
- failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
+ failf(data, "rmdir command failed: %s",
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1709,9 +1710,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc != 0 && !sshc->acceptfail) {
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
- failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
+ failf(data, "rm command failed: %s", sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1732,9 +1733,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc != 0 && !sshc->acceptfail) {
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
Curl_safefree(sshc->quote_path1);
- failf(data, "statvfs command failed: %s", sftp_libssh2_strerror(err));
+ failf(data, "statvfs command failed: %s",
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
sshc->nextstate = SSH_NO_STATE;
sshc->actualcode = CURLE_QUOTE_ERROR;
@@ -1871,21 +1873,21 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
/* only when there was an SFTP protocol error can we extract
the sftp error! */
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
else
- err = -1; /* not an sftp error at all */
+ sftperr = LIBSSH2_FX_OK; /* not an sftp error at all */
if(sshc->secondCreateDirs) {
state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = err>= LIBSSH2_FX_OK?
- sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+ sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
+ sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
failf(data, "Creating the dir/file failed: %s",
- sftp_libssh2_strerror(err));
+ sftp_libssh2_strerror(sftperr));
break;
}
- if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
- (err == LIBSSH2_FX_FAILURE) ||
- (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
+ if(((sftperr == LIBSSH2_FX_NO_SUCH_FILE) ||
+ (sftperr == LIBSSH2_FX_FAILURE) ||
+ (sftperr == LIBSSH2_FX_NO_SUCH_PATH)) &&
(data->set.ftp_create_missing_dirs &&
(strlen(sftp_scp->path) > 1))) {
/* try to create the path remotely */
@@ -1895,18 +1897,19 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = err>= LIBSSH2_FX_OK?
- sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+ sshc->actualcode = sftperr != LIBSSH2_FX_OK ?
+ sftp_libssh2_error_to_CURLE(sftperr):CURLE_SSH;
if(!sshc->actualcode) {
- /* Sometimes, for some reason libssh2_sftp_last_error() returns
- zero even though libssh2_sftp_open() failed previously! We need
- to work around that! */
+ /* Sometimes, for some reason libssh2_sftp_last_error() returns zero
+ even though libssh2_sftp_open() failed previously! We need to
+ work around that! */
sshc->actualcode = CURLE_SSH;
- err = -1;
+ sftperr = LIBSSH2_FX_OK;
}
failf(data, "Upload failed: %s (%d/%d)",
- err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
- err, rc);
+ sftperr != LIBSSH2_FX_OK ?
+ sftp_libssh2_strerror(sftperr):"ssh error",
+ sftperr, rc);
break;
}
@@ -2033,11 +2036,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
* permission was denied (creation might succeed further down the
* path) - retry on unspecific FAILURE also
*/
- err = sftp_libssh2_last_error(sshc->sftp_session);
- if((err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
- (err != LIBSSH2_FX_FAILURE) &&
- (err != LIBSSH2_FX_PERMISSION_DENIED)) {
- result = sftp_libssh2_error_to_CURLE(err);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+ if((sftperr != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
+ (sftperr != LIBSSH2_FX_FAILURE) &&
+ (sftperr != LIBSSH2_FX_PERMISSION_DENIED)) {
+ result = sftp_libssh2_error_to_CURLE(sftperr);
state(conn, SSH_SFTP_CLOSE);
sshc->actualcode = result?result:CURLE_SSH;
break;
@@ -2069,11 +2072,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
rc = LIBSSH2_ERROR_EAGAIN;
break;
}
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
failf(data, "Could not open directory for reading: %s",
- sftp_libssh2_strerror(err));
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
- result = sftp_libssh2_error_to_CURLE(err);
+ result = sftp_libssh2_error_to_CURLE(sftperr);
sshc->actualcode = result?result:CURLE_SSH;
break;
}
@@ -2090,6 +2093,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
sshc->actualcode = CURLE_OUT_OF_MEMORY;
break;
}
+ Curl_dyn_init(&sshc->readdir, PATH_MAX * 2);
state(conn, SSH_SFTP_READDIR);
break;
@@ -2104,68 +2108,51 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc > 0) {
- sshc->readdir_len = (size_t) rc;
- sshc->readdir_filename[sshc->readdir_len] = '\0';
+ readdir_len = (size_t) rc;
+ sshc->readdir_filename[readdir_len] = '\0';
if(data->set.ftp_list_only) {
- char *tmpLine;
-
- tmpLine = aprintf("%s\n", sshc->readdir_filename);
- if(tmpLine == NULL) {
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
- break;
- }
result = Curl_client_write(conn, CLIENTWRITE_BODY,
- tmpLine, sshc->readdir_len + 1);
- free(tmpLine);
-
+ sshc->readdir_filename,
+ readdir_len);
+ if(!result)
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ (char *)"\n", 1);
if(result) {
state(conn, SSH_STOP);
break;
}
/* since this counts what we send to the client, we include the
newline in this counter */
- data->req.bytecount += sshc->readdir_len + 1;
+ data->req.bytecount += readdir_len + 1;
/* output debug output if that is requested */
if(data->set.verbose) {
- Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
- sshc->readdir_len);
+ Curl_debug(data, CURLINFO_DATA_IN, sshc->readdir_filename,
+ readdir_len);
+ Curl_debug(data, CURLINFO_DATA_IN, (char *)"\n", 1);
}
}
else {
- sshc->readdir_currLen = strlen(sshc->readdir_longentry);
- sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
- sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
- if(!sshc->readdir_line) {
- Curl_safefree(sshc->readdir_filename);
- Curl_safefree(sshc->readdir_longentry);
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
- break;
- }
-
- memcpy(sshc->readdir_line, sshc->readdir_longentry,
- sshc->readdir_currLen);
- if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
- ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
- LIBSSH2_SFTP_S_IFLNK)) {
- sshc->readdir_linkPath = malloc(PATH_MAX + 1);
- if(sshc->readdir_linkPath == NULL) {
- Curl_safefree(sshc->readdir_filename);
- Curl_safefree(sshc->readdir_longentry);
- state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ result = Curl_dyn_add(&sshc->readdir, sshc->readdir_longentry);
+
+ if(!result) {
+ if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+ ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+ LIBSSH2_SFTP_S_IFLNK)) {
+ Curl_dyn_init(&sshc->readdir_link, PATH_MAX);
+ result = Curl_dyn_add(&sshc->readdir_link, sftp_scp->path);
+ state(conn, SSH_SFTP_READDIR_LINK);
+ if(!result)
+ break;
+ }
+ else {
+ state(conn, SSH_SFTP_READDIR_BOTTOM);
break;
}
-
- msnprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
- sshc->readdir_filename);
- state(conn, SSH_SFTP_READDIR_LINK);
- break;
}
- state(conn, SSH_SFTP_READDIR_BOTTOM);
+ sshc->actualcode = result;
+ state(conn, SSH_SFTP_CLOSE);
break;
}
}
@@ -2176,11 +2163,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
else if(rc < 0) {
- err = sftp_libssh2_last_error(sshc->sftp_session);
- result = sftp_libssh2_error_to_CURLE(err);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
+ result = sftp_libssh2_error_to_CURLE(sftperr);
sshc->actualcode = result?result:CURLE_SSH;
failf(data, "Could not open remote file for reading: %s :: %d",
- sftp_libssh2_strerror(err),
+ sftp_libssh2_strerror(sftperr),
libssh2_session_last_errno(sshc->ssh_session));
Curl_safefree(sshc->readdir_filename);
Curl_safefree(sshc->readdir_longentry);
@@ -2192,64 +2179,56 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
case SSH_SFTP_READDIR_LINK:
rc =
libssh2_sftp_symlink_ex(sshc->sftp_session,
- sshc->readdir_linkPath,
- curlx_uztoui(strlen(sshc->readdir_linkPath)),
+ Curl_dyn_ptr(&sshc->readdir_link),
+ (int)Curl_dyn_len(&sshc->readdir_link),
sshc->readdir_filename,
PATH_MAX, LIBSSH2_SFTP_READLINK);
if(rc == LIBSSH2_ERROR_EAGAIN) {
break;
}
- sshc->readdir_len = (size_t) rc;
- Curl_safefree(sshc->readdir_linkPath);
+ readdir_len = (size_t) rc;
+ Curl_dyn_free(&sshc->readdir_link);
+
+ /* append filename and extra output */
+ result = Curl_dyn_addf(&sshc->readdir, " -> %s", sshc->readdir_filename);
- /* get room for the filename and extra output */
- sshc->readdir_totalLen += 4 + sshc->readdir_len;
- new_readdir_line = Curl_saferealloc(sshc->readdir_line,
- sshc->readdir_totalLen);
- if(!new_readdir_line) {
+ if(result) {
sshc->readdir_line = NULL;
Curl_safefree(sshc->readdir_filename);
Curl_safefree(sshc->readdir_longentry);
state(conn, SSH_SFTP_CLOSE);
- sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ sshc->actualcode = result;
break;
}
- sshc->readdir_line = new_readdir_line;
-
- sshc->readdir_currLen += msnprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen,
- " -> %s",
- sshc->readdir_filename);
state(conn, SSH_SFTP_READDIR_BOTTOM);
break;
case SSH_SFTP_READDIR_BOTTOM:
- sshc->readdir_currLen += msnprintf(sshc->readdir_line +
- sshc->readdir_currLen,
- sshc->readdir_totalLen -
- sshc->readdir_currLen, "\n");
- result = Curl_client_write(conn, CLIENTWRITE_BODY,
- sshc->readdir_line,
- sshc->readdir_currLen);
+ result = Curl_dyn_addn(&sshc->readdir, "\n", 1);
+ if(!result)
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ Curl_dyn_ptr(&sshc->readdir),
+ Curl_dyn_len(&sshc->readdir));
if(!result) {
/* output debug output if that is requested */
if(data->set.verbose) {
- Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
- sshc->readdir_currLen);
+ Curl_debug(data, CURLINFO_DATA_IN,
+ Curl_dyn_ptr(&sshc->readdir),
+ Curl_dyn_len(&sshc->readdir));
}
- data->req.bytecount += sshc->readdir_currLen;
+ data->req.bytecount += Curl_dyn_len(&sshc->readdir);
}
- Curl_safefree(sshc->readdir_line);
if(result) {
+ Curl_dyn_free(&sshc->readdir);
state(conn, SSH_STOP);
}
- else
+ else {
+ Curl_dyn_reset(&sshc->readdir);
state(conn, SSH_SFTP_READDIR);
+ }
break;
case SSH_SFTP_READDIR_DONE:
@@ -2282,11 +2261,11 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
rc = LIBSSH2_ERROR_EAGAIN;
break;
}
- err = sftp_libssh2_last_error(sshc->sftp_session);
+ sftperr = libssh2_sftp_last_error(sshc->sftp_session);
failf(data, "Could not open remote file for reading: %s",
- sftp_libssh2_strerror(err));
+ sftp_libssh2_strerror(sftperr));
state(conn, SSH_SFTP_CLOSE);
- result = sftp_libssh2_error_to_CURLE(err);
+ result = sftp_libssh2_error_to_CURLE(sftperr);
sshc->actualcode = result?result:CURLE_SSH;
break;
}
@@ -2551,7 +2530,9 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
}
/* upload data */
- Curl_setup_transfer(data, -1, data->req.size, FALSE, FIRSTSOCKET);
+ data->req.size = data->state.infilesize;
+ Curl_pgrsSetUploadSize(data, data->state.infilesize);
+ Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
/* not set by Curl_setup_transfer to preserve keepon bits */
conn->sockfd = conn->writesockfd;
@@ -2621,7 +2602,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
/* download data */
bytecount = (curl_off_t)sb.st_size;
- data->req.maxdownload = (curl_off_t)sb.st_size;
+ data->req.maxdownload = (curl_off_t)sb.st_size;
Curl_setup_transfer(data, FIRSTSOCKET, bytecount, FALSE, -1);
/* not set by Curl_setup_transfer to preserve keepon bits */
@@ -2828,7 +2809,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
Curl_safefree(sshc->readdir_filename);
Curl_safefree(sshc->readdir_longentry);
Curl_safefree(sshc->readdir_line);
- Curl_safefree(sshc->readdir_linkPath);
+ Curl_dyn_free(&sshc->readdir);
/* the code we are about to return */
result = sshc->actualcode;
@@ -2952,7 +2933,7 @@ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
}
static CURLcode ssh_block_statemach(struct connectdata *conn,
- bool disconnect)
+ bool duringconnect)
{
struct ssh_conn *sshc = &conn->proto.sshc;
CURLcode result = CURLE_OK;
@@ -2967,19 +2948,17 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
if(result)
break;
- if(!disconnect) {
- if(Curl_pgrsUpdate(conn))
- return CURLE_ABORTED_BY_CALLBACK;
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
- result = Curl_speedcheck(data, now);
- if(result)
- break;
+ result = Curl_speedcheck(data, now);
+ if(result)
+ break;
- left = Curl_timeleft(data, NULL, FALSE);
- if(left < 0) {
- failf(data, "Operation timed out");
- return CURLE_OPERATION_TIMEDOUT;
- }
+ left = Curl_timeleft(data, NULL, duringconnect);
+ if(left < 0) {
+ failf(data, "Operation timed out");
+ return CURLE_OPERATION_TIMEDOUT;
}
#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
@@ -2994,7 +2973,7 @@ static CURLcode ssh_block_statemach(struct connectdata *conn,
fd_write = sock;
/* wait for the socket to become ready */
(void)Curl_socket_check(fd_read, CURL_SOCKET_BAD, fd_write,
- left>1000?1000:(time_t)left);
+ left>1000?1000:left);
}
#endif
@@ -3202,7 +3181,7 @@ static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
state(conn, SSH_SESSION_DISCONNECT);
- result = ssh_block_statemach(conn, TRUE);
+ result = ssh_block_statemach(conn, FALSE);
}
return result;
@@ -3351,7 +3330,7 @@ static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
if(conn->proto.sshc.ssh_session) {
/* only if there's a session still around to use! */
state(conn, SSH_SFTP_SHUTDOWN);
- result = ssh_block_statemach(conn, TRUE);
+ result = ssh_block_statemach(conn, FALSE);
}
DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
@@ -3426,7 +3405,7 @@ static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
return nread;
}
-static const char *sftp_libssh2_strerror(int err)
+static const char *sftp_libssh2_strerror(unsigned long err)
{
switch(err) {
case LIBSSH2_FX_NO_SUCH_FILE:
diff --git a/lib/vssh/ssh.h b/lib/vssh/ssh.h
index 0d4ee521..9e49993e 100644
--- a/lib/vssh/ssh.h
+++ b/lib/vssh/ssh.h
@@ -134,9 +134,7 @@ struct ssh_conn {
quote command fails) */
char *homedir; /* when doing SFTP we figure out home dir in the
connect phase */
- size_t readdir_len, readdir_totalLen, readdir_currLen;
char *readdir_line;
- char *readdir_linkPath;
/* end of READDIR stuff */
int secondCreateDirs; /* counter use by the code to see if the
@@ -147,6 +145,8 @@ struct ssh_conn {
int orig_waitfor; /* default READ/WRITE bits wait for */
#if defined(USE_LIBSSH)
+ char *readdir_linkPath;
+ size_t readdir_len, readdir_totalLen, readdir_currLen;
/* our variables */
unsigned kbd_state; /* 0 or 1 */
ssh_key privkey;
@@ -168,6 +168,8 @@ struct ssh_conn {
const char *readdir_longentry;
char *readdir_tmp;
#elif defined(USE_LIBSSH2)
+ struct dynbuf readdir_link;
+ struct dynbuf readdir;
char *readdir_filename;
char *readdir_longentry;
diff --git a/lib/vssh/wolfssh.c b/lib/vssh/wolfssh.c
index 363a52c7..dcbbab6c 100644
--- a/lib/vssh/wolfssh.c
+++ b/lib/vssh/wolfssh.c
@@ -241,8 +241,8 @@ static ssize_t wsftp_send(struct connectdata *conn, int sockindex,
int rc;
(void)sockindex;
- offset[0] = (word32)sshc->offset&0xFFFFFFFF;
- offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
+ offset[0] = (word32)sshc->offset&0xFFFFFFFF;
+ offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
rc = wolfSSH_SFTP_SendWritePacket(sshc->ssh_session, sshc->handle,
sshc->handleSz,
@@ -284,8 +284,8 @@ static ssize_t wsftp_recv(struct connectdata *conn, int sockindex,
word32 offset[2];
(void)sockindex;
- offset[0] = (word32)sshc->offset&0xFFFFFFFF;
- offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
+ offset[0] = (word32)sshc->offset&0xFFFFFFFF;
+ offset[1] = (word32)(sshc->offset>>32)&0xFFFFFFFF;
rc = wolfSSH_SFTP_SendReadPacket(sshc->ssh_session, sshc->handle,
sshc->handleSz,
diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c
index 1a6530c8..628e16a1 100644
--- a/lib/vtls/bearssl.c
+++ b/lib/vtls/bearssl.c
@@ -642,7 +642,7 @@ static CURLcode bearssl_connect_common(struct connectdata *conn,
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
- time_t timeout_ms;
+ timediff_t timeout_ms;
int what;
/* check if the connection has already been established */
diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c
index b0864b5f..0538e4a4 100644
--- a/lib/vtls/gskit.c
+++ b/lib/vtls/gskit.c
@@ -108,13 +108,13 @@ struct ssl_backend_data {
#define BACKEND connssl->backend
/* Supported ciphers. */
-typedef struct {
+struct gskit_cipher {
const char *name; /* Cipher name. */
const char *gsktoken; /* Corresponding token for GSKit String. */
unsigned int versions; /* SSL version flags. */
-} gskit_cipher;
+};
-static const gskit_cipher ciphertable[] = {
+static const struct gskit_cipher ciphertable[] = {
{ "null-md5", "01",
CURL_GSKPROTO_SSLV3_MASK | CURL_GSKPROTO_TLSV10_MASK |
CURL_GSKPROTO_TLSV11_MASK | CURL_GSKPROTO_TLSV12_MASK },
@@ -307,7 +307,7 @@ static CURLcode set_ciphers(struct connectdata *conn,
struct Curl_easy *data = conn->data;
const char *cipherlist = SSL_CONN_CONFIG(cipher_list);
const char *clp;
- const gskit_cipher *ctp;
+ const struct gskit_cipher *ctp;
int i;
int l;
bool unsupported;
@@ -819,7 +819,7 @@ static CURLcode gskit_connect_step1(struct connectdata *conn, int sockindex)
if(!result) {
/* Compute the handshake timeout. Since GSKit granularity is 1 second,
we round up the required value. */
- long timeout = Curl_timeleft(data, NULL, TRUE);
+ timediff_t timeout = Curl_timeleft(data, NULL, TRUE);
if(timeout < 0)
result = CURLE_OPERATION_TIMEDOUT;
else
@@ -932,7 +932,7 @@ static CURLcode gskit_connect_step2(struct connectdata *conn, int sockindex,
/* Poll or wait for end of SSL asynchronous handshake. */
for(;;) {
- long timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
+ timediff_t timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0)
timeout_ms = 0;
stmv.tv_sec = timeout_ms / 1000;
diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
index 4ed3ea5c..9b4c3659 100644
--- a/lib/vtls/gtls.c
+++ b/lib/vtls/gtls.c
@@ -235,7 +235,7 @@ static CURLcode handshake(struct connectdata *conn,
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
nonblocking?0:
- timeout_ms?(time_t)timeout_ms:1000);
+ timeout_ms?timeout_ms:1000);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -401,6 +401,8 @@ gtls_connect_step1(struct connectdata *conn,
const char *err = NULL;
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
if(connssl->state == ssl_connection_complete)
/* to make us tolerant against being called more than once for the
@@ -410,6 +412,9 @@ gtls_connect_step1(struct connectdata *conn,
if(!gtls_inited)
Curl_gtls_init();
+ /* Initialize certverifyresult to OK */
+ *certverifyresult = 0;
+
if(SSL_CONN_CONFIG(version) == CURL_SSLVERSION_SSLv2) {
failf(data, "GnuTLS does not support SSLv2");
return CURLE_SSL_CONNECT_ERROR;
@@ -458,8 +463,10 @@ gtls_connect_step1(struct connectdata *conn,
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)\n",
SSL_CONN_CONFIG(CAfile), gnutls_strerror(rc));
- if(SSL_CONN_CONFIG(verifypeer))
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ *certverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
+ }
}
else
infof(data, "found %d certificates in %s\n", rc,
@@ -474,8 +481,10 @@ gtls_connect_step1(struct connectdata *conn,
if(rc < 0) {
infof(data, "error reading ca cert file %s (%s)\n",
SSL_CONN_CONFIG(CApath), gnutls_strerror(rc));
- if(SSL_CONN_CONFIG(verifypeer))
+ if(SSL_CONN_CONFIG(verifypeer)) {
+ *certverifyresult = rc;
return CURLE_SSL_CACERT_BADFILE;
+ }
}
else
infof(data, "found %d certificates in %s\n",
@@ -821,6 +830,8 @@ gtls_connect_step3(struct connectdata *conn,
#endif
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+ long * const certverifyresult = SSL_IS_PROXY() ?
+ &data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
/* the name of the cipher suite used, e.g. ECDHE_RSA_AES_256_GCM_SHA384. */
ptr = gnutls_cipher_suite_get_name(gnutls_kx_get(session),
@@ -852,6 +863,7 @@ gtls_connect_step3(struct connectdata *conn,
else {
#endif
failf(data, "failed to get server cert");
+ *certverifyresult = GNUTLS_E_NO_CERTIFICATE_FOUND;
return CURLE_PEER_FAILED_VERIFICATION;
#ifdef USE_TLS_SRP
}
@@ -888,9 +900,12 @@ gtls_connect_step3(struct connectdata *conn,
rc = gnutls_certificate_verify_peers2(session, &verify_status);
if(rc < 0) {
failf(data, "server cert verify failed: %d", rc);
+ *certverifyresult = rc;
return CURLE_SSL_CONNECT_ERROR;
}
+ *certverifyresult = verify_status;
+
/* verify_status is a bitmask of gnutls_certificate_status bits */
if(verify_status & GNUTLS_CERT_INVALID) {
if(SSL_CONN_CONFIG(verifypeer)) {
@@ -1119,6 +1134,7 @@ gtls_connect_step3(struct connectdata *conn,
if(certclock == (time_t)-1) {
if(SSL_CONN_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;
}
@@ -1129,6 +1145,7 @@ gtls_connect_step3(struct connectdata *conn,
if(certclock < time(NULL)) {
if(SSL_CONN_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;
}
@@ -1144,6 +1161,7 @@ gtls_connect_step3(struct connectdata *conn,
if(certclock == (time_t)-1) {
if(SSL_CONN_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;
}
@@ -1154,6 +1172,7 @@ gtls_connect_step3(struct connectdata *conn,
if(certclock > time(NULL)) {
if(SSL_CONN_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;
}
diff --git a/lib/vtls/keylog.c b/lib/vtls/keylog.c
new file mode 100644
index 00000000..70d22ecf
--- /dev/null
+++ b/lib/vtls/keylog.c
@@ -0,0 +1,156 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#include "keylog.h"
+
+/* The last #include files should be: */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1)
+
+#define CLIENT_RANDOM_SIZE 32
+
+/*
+ * The master secret in TLS 1.2 and before is always 48 bytes. In TLS 1.3, the
+ * secret size depends on the cipher suite's hash function which is 32 bytes
+ * for SHA-256 and 48 bytes for SHA-384.
+ */
+#define SECRET_MAXLEN 48
+
+
+/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
+static FILE *keylog_file_fp;
+
+void
+Curl_tls_keylog_open(void)
+{
+ char *keylog_file_name;
+
+ if(!keylog_file_fp) {
+ keylog_file_name = curl_getenv("SSLKEYLOGFILE");
+ if(keylog_file_name) {
+ keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT);
+ if(keylog_file_fp) {
+#ifdef WIN32
+ if(setvbuf(keylog_file_fp, NULL, _IONBF, 0))
+#else
+ if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096))
+#endif
+ {
+ fclose(keylog_file_fp);
+ keylog_file_fp = NULL;
+ }
+ }
+ Curl_safefree(keylog_file_name);
+ }
+ }
+}
+
+void
+Curl_tls_keylog_close(void)
+{
+ if(keylog_file_fp) {
+ fclose(keylog_file_fp);
+ keylog_file_fp = NULL;
+ }
+}
+
+bool
+Curl_tls_keylog_enabled(void)
+{
+ return keylog_file_fp != NULL;
+}
+
+bool
+Curl_tls_keylog_write_line(const char *line)
+{
+ /* The current maximum valid keylog line length LF and NUL is 195. */
+ size_t linelen;
+ char buf[256];
+
+ if(!keylog_file_fp || !line) {
+ return false;
+ }
+
+ linelen = strlen(line);
+ if(linelen == 0 || linelen > sizeof(buf) - 2) {
+ /* Empty line or too big to fit in a LF and NUL. */
+ return false;
+ }
+
+ memcpy(buf, line, linelen);
+ if(line[linelen - 1] != '\n') {
+ buf[linelen++] = '\n';
+ }
+ buf[linelen] = '\0';
+
+ /* Using fputs here instead of fprintf since libcurl's fprintf replacement
+ may not be thread-safe. */
+ fputs(buf, keylog_file_fp);
+ return true;
+}
+
+bool
+Curl_tls_keylog_write(const char *label,
+ const unsigned char client_random[CLIENT_RANDOM_SIZE],
+ const unsigned char *secret, size_t secretlen)
+{
+ const char *hex = "0123456789ABCDEF";
+ size_t pos, i;
+ char line[KEYLOG_LABEL_MAXLEN + 1 + 2 * CLIENT_RANDOM_SIZE + 1 +
+ 2 * SECRET_MAXLEN + 1 + 1];
+
+ if(!keylog_file_fp) {
+ return false;
+ }
+
+ pos = strlen(label);
+ if(pos > KEYLOG_LABEL_MAXLEN || !secretlen || secretlen > SECRET_MAXLEN) {
+ /* Should never happen - sanity check anyway. */
+ return false;
+ }
+
+ memcpy(line, label, pos);
+ line[pos++] = ' ';
+
+ /* Client Random */
+ for(i = 0; i < CLIENT_RANDOM_SIZE; i++) {
+ line[pos++] = hex[client_random[i] >> 4];
+ line[pos++] = hex[client_random[i] & 0xF];
+ }
+ line[pos++] = ' ';
+
+ /* Secret */
+ for(i = 0; i < secretlen; i++) {
+ line[pos++] = hex[secret[i] >> 4];
+ line[pos++] = hex[secret[i] & 0xF];
+ }
+ line[pos++] = '\n';
+ line[pos] = '\0';
+
+ /* Using fputs here instead of fprintf since libcurl's fprintf replacement
+ may not be thread-safe. */
+ fputs(line, keylog_file_fp);
+ return true;
+}
diff --git a/lib/vtls/keylog.h b/lib/vtls/keylog.h
new file mode 100644
index 00000000..c6b99db9
--- /dev/null
+++ b/lib/vtls/keylog.h
@@ -0,0 +1,56 @@
+#ifndef HEADER_CURL_KEYLOG_H
+#define HEADER_CURL_KEYLOG_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+/*
+ * Opens the TLS key log file if requested by the user. The SSLKEYLOGFILE
+ * environment variable specifies the output file.
+ */
+void Curl_tls_keylog_open(void);
+
+/*
+ * Closes the TLS key log file if not already.
+ */
+void Curl_tls_keylog_close(void);
+
+/*
+ * Returns true if the user successfully enabled the TLS key log file.
+ */
+bool Curl_tls_keylog_enabled(void);
+
+/*
+ * Appends a key log file entry.
+ * Returns true iff the key log file is open and a valid entry was provided.
+ */
+bool Curl_tls_keylog_write(const char *label,
+ const unsigned char client_random[32],
+ const unsigned char *secret, size_t secretlen);
+
+/*
+ * Appends a line to the key log file, ensure it is terminated by a LF.
+ * Returns true iff the key log file is open and a valid line was provided.
+ */
+bool Curl_tls_keylog_write_line(const char *line);
+
+#endif /* HEADER_CURL_KEYLOG_H */
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
index cbf3d3de..545f824c 100644
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
@@ -239,16 +239,21 @@ mbed_connect_step1(struct connectdata *conn,
int sockindex)
{
struct Curl_easy *data = conn->data;
- struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
char * const ssl_cert = SSL_SET_OPTION(cert);
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
+#ifndef CURL_DISABLE_PROXY
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+#else
+ const char * const hostname = conn->host.name;
+ const long int port = conn->remote_port;
+#endif
int ret = -1;
char errorbuf[128];
errorbuf[0] = 0;
@@ -535,12 +540,17 @@ mbed_connect_step2(struct connectdata *conn,
{
int ret;
struct Curl_easy *data = conn->data;
- struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
const mbedtls_x509_crt *peercert;
+#ifndef CURL_DISABLE_PROXY
const char * const pinnedpubkey = SSL_IS_PROXY() ?
data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+#else
+ const char * const pinnedpubkey =
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+#endif
conn->recv[sockindex] = mbed_recv;
conn->send[sockindex] = mbed_send;
@@ -938,7 +948,7 @@ mbed_connect_common(struct connectdata *conn,
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- nonblocking ? 0 : (time_t)timeout_ms);
+ nonblocking ? 0 : timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
diff --git a/lib/vtls/mesalink.c b/lib/vtls/mesalink.c
index cab1e390..7132bdfd 100644
--- a/lib/vtls/mesalink.c
+++ b/lib/vtls/mesalink.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2017 - 2018, Yiming Jing, <jingyiming@baidu.com>
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -542,9 +542,8 @@ mesalink_connect_common(struct connectdata *conn, int sockindex,
? sockfd
: CURL_SOCKET_BAD;
- what = Curl_socket_check(
- readfd, CURL_SOCKET_BAD, writefd,
- nonblocking ? 0 : (time_t)timeout_ms);
+ what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
+ nonblocking ? 0 : timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c
index 16ec409e..fca29261 100644
--- a/lib/vtls/nss.c
+++ b/lib/vtls/nss.c
@@ -101,10 +101,10 @@ struct ptr_list_wrap {
struct curl_llist_element node;
};
-typedef struct {
+struct cipher_s {
const char *name;
int num;
-} cipher_s;
+};
#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \
CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \
@@ -116,7 +116,7 @@ typedef struct {
#define CERT_NewTempCertificate __CERT_NewTempCertificate
#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
-static const cipher_s cipherlist[] = {
+static const struct cipher_s cipherlist[] = {
/* SSL2 cipher suites */
{"rc4", SSL_EN_RC4_128_WITH_MD5},
{"rc4-md5", SSL_EN_RC4_128_WITH_MD5},
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 176fa522..2e9f900d 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -31,6 +31,11 @@
#include <limits.h>
+/* Wincrypt must be included before anything that could include OpenSSL. */
+#if defined(USE_WIN32_CRYPTO)
+#include <wincrypt.h>
+#endif
+
#include "urldata.h"
#include "sendf.h"
#include "formdata.h" /* for the boundary function */
@@ -41,11 +46,13 @@
#include "slist.h"
#include "select.h"
#include "vtls.h"
+#include "keylog.h"
#include "strcase.h"
#include "hostcheck.h"
#include "multiif.h"
#include "strerror.h"
#include "curl_printf.h"
+
#include <openssl/ssl.h>
#include <openssl/rand.h>
#include <openssl/x509v3.h>
@@ -207,24 +214,14 @@
"ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH"
#endif
-#define ENABLE_SSLKEYLOGFILE
-
-#ifdef ENABLE_SSLKEYLOGFILE
-typedef struct ssl_tap_state {
- int master_key_length;
- unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
- unsigned char client_random[SSL3_RANDOM_SIZE];
-} ssl_tap_state_t;
-#endif /* ENABLE_SSLKEYLOGFILE */
-
struct ssl_backend_data {
/* these ones requires specific SSL-types */
SSL_CTX* ctx;
SSL* handle;
X509* server_cert;
-#ifdef ENABLE_SSLKEYLOGFILE
- /* tap_state holds the last seen master key if we're logging them */
- ssl_tap_state_t tap_state;
+#ifndef HAVE_KEYLOG_CALLBACK
+ /* Set to true once a valid keylog entry has been created to avoid dupes. */
+ bool keylog_done;
#endif
};
@@ -236,57 +233,27 @@ struct ssl_backend_data {
*/
#define RAND_LOAD_LENGTH 1024
-#ifdef ENABLE_SSLKEYLOGFILE
-/* The fp for the open SSLKEYLOGFILE, or NULL if not open */
-static FILE *keylog_file_fp;
-
#ifdef HAVE_KEYLOG_CALLBACK
static void ossl_keylog_callback(const SSL *ssl, const char *line)
{
(void)ssl;
- /* Using fputs here instead of fprintf since libcurl's fprintf replacement
- may not be thread-safe. */
- if(keylog_file_fp && line && *line) {
- char stackbuf[256];
- char *buf;
- size_t linelen = strlen(line);
-
- if(linelen <= sizeof(stackbuf) - 2)
- buf = stackbuf;
- else {
- buf = malloc(linelen + 2);
- if(!buf)
- return;
- }
- memcpy(buf, line, linelen);
- buf[linelen] = '\n';
- buf[linelen + 1] = '\0';
-
- fputs(buf, keylog_file_fp);
- if(buf != stackbuf)
- free(buf);
- }
+ Curl_tls_keylog_write_line(line);
}
#else
-#define KEYLOG_PREFIX "CLIENT_RANDOM "
-#define KEYLOG_PREFIX_LEN (sizeof(KEYLOG_PREFIX) - 1)
/*
- * tap_ssl_key is called by libcurl to make the CLIENT_RANDOMs if the OpenSSL
- * being used doesn't have native support for doing that.
+ * ossl_log_tls12_secret is called by libcurl to make the CLIENT_RANDOMs if the
+ * OpenSSL being used doesn't have native support for doing that.
*/
-static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state)
+static void
+ossl_log_tls12_secret(const SSL *ssl, bool *keylog_done)
{
- const char *hex = "0123456789ABCDEF";
- int pos, i;
- char line[KEYLOG_PREFIX_LEN + 2 * SSL3_RANDOM_SIZE + 1 +
- 2 * SSL_MAX_MASTER_KEY_LENGTH + 1 + 1];
const SSL_SESSION *session = SSL_get_session(ssl);
unsigned char client_random[SSL3_RANDOM_SIZE];
unsigned char master_key[SSL_MAX_MASTER_KEY_LENGTH];
int master_key_length = 0;
- if(!session || !keylog_file_fp)
+ if(!session || *keylog_done)
return;
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && \
@@ -305,44 +272,17 @@ static void tap_ssl_key(const SSL *ssl, ssl_tap_state_t *state)
}
#endif
+ /* 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). */
if(master_key_length <= 0)
return;
- /* Skip writing keys if there is no key or it did not change. */
- if(state->master_key_length == master_key_length &&
- !memcmp(state->master_key, master_key, master_key_length) &&
- !memcmp(state->client_random, client_random, SSL3_RANDOM_SIZE)) {
- return;
- }
-
- state->master_key_length = master_key_length;
- memcpy(state->master_key, master_key, master_key_length);
- memcpy(state->client_random, client_random, SSL3_RANDOM_SIZE);
-
- memcpy(line, KEYLOG_PREFIX, KEYLOG_PREFIX_LEN);
- pos = KEYLOG_PREFIX_LEN;
-
- /* Client Random for SSLv3/TLS */
- for(i = 0; i < SSL3_RANDOM_SIZE; i++) {
- line[pos++] = hex[client_random[i] >> 4];
- line[pos++] = hex[client_random[i] & 0xF];
- }
- line[pos++] = ' ';
-
- /* Master Secret (size is at most SSL_MAX_MASTER_KEY_LENGTH) */
- for(i = 0; i < master_key_length; i++) {
- line[pos++] = hex[master_key[i] >> 4];
- line[pos++] = hex[master_key[i] & 0xF];
- }
- line[pos++] = '\n';
- line[pos] = '\0';
-
- /* Using fputs here instead of fprintf since libcurl's fprintf replacement
- may not be thread-safe. */
- fputs(line, keylog_file_fp);
+ *keylog_done = true;
+ Curl_tls_keylog_write("CLIENT_RANDOM", client_random,
+ master_key, master_key_length);
}
#endif /* !HAVE_KEYLOG_CALLBACK */
-#endif /* ENABLE_SSLKEYLOGFILE */
static const char *SSL_ERROR_to_str(int err)
{
@@ -616,12 +556,136 @@ static bool is_pkcs11_uri(const char *string)
static CURLcode Curl_ossl_set_engine(struct Curl_easy *data,
const char *engine);
+static int
+SSL_CTX_use_certificate_bio(SSL_CTX *ctx, BIO *in, int type,
+ const char *key_passwd)
+{
+ int ret = 0;
+ X509 *x = NULL;
+
+ if(type == SSL_FILETYPE_ASN1) {
+ /* j = ERR_R_ASN1_LIB; */
+ x = d2i_X509_bio(in, NULL);
+ }
+ else if(type == SSL_FILETYPE_PEM) {
+ /* ERR_R_PEM_LIB; */
+ x = PEM_read_bio_X509(in, NULL,
+ passwd_callback, (void *)key_passwd);
+ }
+ else {
+ ret = 0;
+ goto end;
+ }
+
+ if(x == NULL) {
+ ret = 0;
+ goto end;
+ }
+
+ ret = SSL_CTX_use_certificate(ctx, x);
+ end:
+ X509_free(x);
+ return ret;
+}
+
+static int
+SSL_CTX_use_PrivateKey_bio(SSL_CTX *ctx, BIO* in, int type,
+ const char *key_passwd)
+{
+ int ret = 0;
+ EVP_PKEY *pkey = NULL;
+
+ if(type == SSL_FILETYPE_PEM)
+ pkey = PEM_read_bio_PrivateKey(in, NULL, passwd_callback,
+ (void *)key_passwd);
+ else if(type == SSL_FILETYPE_ASN1)
+ pkey = d2i_PrivateKey_bio(in, NULL);
+ else {
+ ret = 0;
+ goto end;
+ }
+ if(pkey == NULL) {
+ ret = 0;
+ goto end;
+ }
+ ret = SSL_CTX_use_PrivateKey(ctx, pkey);
+ EVP_PKEY_free(pkey);
+ end:
+ return ret;
+}
+
+static int
+SSL_CTX_use_certificate_chain_bio(SSL_CTX *ctx, BIO* in,
+ const char *key_passwd)
+{
+/* SSL_CTX_add1_chain_cert introduced in OpenSSL 1.0.2 */
+#if (OPENSSL_VERSION_NUMBER >= 0x1000200fL) /* 1.0.2 or later */
+ int ret = 0;
+ X509 *x = NULL;
+ void *passwd_callback_userdata = (void *)key_passwd;
+
+ ERR_clear_error();
+
+ x = PEM_read_bio_X509_AUX(in, NULL,
+ passwd_callback, (void *)key_passwd);
+
+ if(x == NULL) {
+ ret = 0;
+ goto end;
+ }
+
+ ret = SSL_CTX_use_certificate(ctx, x);
+
+ if(ERR_peek_error() != 0)
+ ret = 0;
+
+ if(ret) {
+ X509 *ca;
+ unsigned long err;
+
+ if(!SSL_CTX_clear_chain_certs(ctx)) {
+ ret = 0;
+ goto end;
+ }
+
+ while((ca = PEM_read_bio_X509(in, NULL, passwd_callback,
+ passwd_callback_userdata))
+ != NULL) {
+
+ if(!SSL_CTX_add0_chain_cert(ctx, ca)) {
+ X509_free(ca);
+ ret = 0;
+ goto end;
+ }
+ }
+
+ err = ERR_peek_last_error();
+ if((ERR_GET_LIB(err) == ERR_LIB_PEM) &&
+ (ERR_GET_REASON(err) == PEM_R_NO_START_LINE))
+ ERR_clear_error();
+ else
+ ret = 0;
+ }
+
+ end:
+ X509_free(x);
+ return ret;
+#else
+ (void)ctx; /* unused */
+ (void)in; /* unused */
+ (void)key_passwd; /* unused */
+ return 0;
+#endif
+}
+
static
int cert_stuff(struct connectdata *conn,
SSL_CTX* ctx,
char *cert_file,
+ BIO *cert_bio,
const char *cert_type,
char *key_file,
+ BIO* key_bio,
const char *key_type,
char *key_passwd)
{
@@ -631,10 +695,11 @@ int cert_stuff(struct connectdata *conn,
int file_type = do_file_type(cert_type);
- if(cert_file || (file_type == SSL_FILETYPE_ENGINE)) {
+ if(cert_file || cert_bio || (file_type == SSL_FILETYPE_ENGINE)) {
SSL *ssl;
X509 *x509;
int cert_done = 0;
+ int cert_use_result;
if(key_passwd) {
/* set the password in the callback userdata */
@@ -647,8 +712,10 @@ int cert_stuff(struct connectdata *conn,
switch(file_type) {
case SSL_FILETYPE_PEM:
/* SSL_CTX_use_certificate_chain_file() only works on PEM files */
- if(SSL_CTX_use_certificate_chain_file(ctx,
- cert_file) != 1) {
+ cert_use_result = cert_bio ?
+ SSL_CTX_use_certificate_chain_bio(ctx, cert_bio, key_passwd) :
+ SSL_CTX_use_certificate_chain_file(ctx, cert_file);
+ if(cert_use_result != 1) {
failf(data,
"could not load PEM client certificate, " OSSL_PACKAGE
" error %s, "
@@ -663,9 +730,12 @@ int cert_stuff(struct connectdata *conn,
/* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
we use the case above for PEM so this can only be performed with
ASN1 files. */
- if(SSL_CTX_use_certificate_file(ctx,
- cert_file,
- file_type) != 1) {
+
+ cert_use_result = cert_bio ?
+ SSL_CTX_use_certificate_bio(ctx, cert_bio,
+ file_type, key_passwd) :
+ SSL_CTX_use_certificate_file(ctx, cert_file, file_type);
+ if(cert_use_result != 1) {
failf(data,
"could not load ASN1 client certificate, " OSSL_PACKAGE
" error %s, "
@@ -745,27 +815,31 @@ int cert_stuff(struct connectdata *conn,
PKCS12 *p12 = NULL;
EVP_PKEY *pri;
STACK_OF(X509) *ca = NULL;
+ if(!cert_bio) {
+ fp = BIO_new(BIO_s_file());
+ if(fp == NULL) {
+ failf(data,
+ "BIO_new return NULL, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ return 0;
+ }
- fp = BIO_new(BIO_s_file());
- if(fp == NULL) {
- 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(fp, cert_file) <= 0) {
+ failf(data, "could not open PKCS12 file '%s'", cert_file);
+ BIO_free(fp);
+ return 0;
+ }
}
- if(BIO_read_filename(fp, cert_file) <= 0) {
- failf(data, "could not open PKCS12 file '%s'", cert_file);
+ p12 = d2i_PKCS12_bio(cert_bio ? cert_bio : fp, NULL);
+ if(fp)
BIO_free(fp);
- return 0;
- }
- p12 = d2i_PKCS12_bio(fp, NULL);
- BIO_free(fp);
if(!p12) {
- failf(data, "error reading PKCS12 file '%s'", cert_file);
+ failf(data, "error reading PKCS12 file '%s'",
+ cert_bio ? "(memory blob)" : cert_file);
return 0;
}
@@ -846,8 +920,10 @@ int cert_stuff(struct connectdata *conn,
return 0;
}
- if(!key_file)
+ if((!key_file) && (!key_bio)) {
key_file = cert_file;
+ key_bio = cert_bio;
+ }
else
file_type = do_file_type(key_type);
@@ -857,9 +933,12 @@ int cert_stuff(struct connectdata *conn,
break;
/* FALLTHROUGH */
case SSL_FILETYPE_ASN1:
- if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
+ cert_use_result = key_bio ?
+ SSL_CTX_use_PrivateKey_bio(ctx, key_bio, file_type, key_passwd) :
+ SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type);
+ if(cert_use_result != 1) {
failf(data, "unable to set private key file: '%s' type %s",
- key_file, key_type?key_type:"PEM");
+ key_file?key_file:"(memory blob)", key_type?key_type:"PEM");
return 0;
}
break;
@@ -1019,10 +1098,6 @@ static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
*/
static int Curl_ossl_init(void)
{
-#ifdef ENABLE_SSLKEYLOGFILE
- char *keylog_file_name;
-#endif
-
OPENSSL_load_builtin_modules();
#ifdef USE_OPENSSL_ENGINE
@@ -1055,26 +1130,7 @@ static int Curl_ossl_init(void)
OpenSSL_add_all_algorithms();
#endif
-#ifdef ENABLE_SSLKEYLOGFILE
- if(!keylog_file_fp) {
- keylog_file_name = curl_getenv("SSLKEYLOGFILE");
- if(keylog_file_name) {
- keylog_file_fp = fopen(keylog_file_name, FOPEN_APPENDTEXT);
- if(keylog_file_fp) {
-#ifdef WIN32
- if(setvbuf(keylog_file_fp, NULL, _IONBF, 0))
-#else
- if(setvbuf(keylog_file_fp, NULL, _IOLBF, 4096))
-#endif
- {
- fclose(keylog_file_fp);
- keylog_file_fp = NULL;
- }
- }
- Curl_safefree(keylog_file_name);
- }
- }
-#endif
+ Curl_tls_keylog_open();
/* Initialize the extra data indexes */
if(ossl_get_ssl_conn_index() < 0 || ossl_get_ssl_sockindex_index() < 0)
@@ -1117,12 +1173,7 @@ static void Curl_ossl_cleanup(void)
#endif
#endif
-#ifdef ENABLE_SSLKEYLOGFILE
- if(keylog_file_fp) {
- fclose(keylog_file_fp);
- keylog_file_fp = NULL;
- }
-#endif
+ Curl_tls_keylog_close();
}
/*
@@ -1289,7 +1340,9 @@ static void ossl_close(struct ssl_connect_data *connssl)
static void Curl_ossl_close(struct connectdata *conn, int sockindex)
{
ossl_close(&conn->ssl[sockindex]);
+#ifndef CURL_DISABLE_PROXY
ossl_close(&conn->proxy_ssl[sockindex]);
+#endif
}
/*
@@ -1516,10 +1569,16 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
CURLcode result = CURLE_OK;
bool dNSName = FALSE; /* if a dNSName field exists in the cert */
bool iPAddress = FALSE; /* if a iPAddress field exists in the cert */
- const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
- conn->host.name;
+#ifndef CURL_DISABLE_PROXY
+ const char * const hostname = SSL_IS_PROXY() ?
+ conn->http_proxy.host.name : conn->host.name;
const char * const dispname = SSL_IS_PROXY() ?
conn->http_proxy.host.dispname : conn->host.dispname;
+#else
+ /* disabled proxy support */
+ const char * const hostname = conn->host.name;
+ const char * const dispname = conn->host.dispname;
+#endif
#ifdef ENABLE_IPV6
if(conn->bits.ipv6_ip &&
@@ -1577,7 +1636,7 @@ static CURLcode verifyhost(struct connectdata *conn, X509 *server_cert)
type itself: for example for an IA5String the data will be ASCII"
It has been however verified that in 0.9.6 and 0.9.7, IA5String
- is always zero-terminated.
+ is always null-terminated.
*/
if((altlen == strlen(altptr)) &&
/* if this isn't true, there was an embedded zero in the name
@@ -2398,21 +2457,31 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
bool sni;
+#ifndef CURL_DISABLE_PROXY
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+#else
+ const char * const hostname = conn->host.name;
+#endif
+
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
struct in_addr addr;
#endif
#endif
+#ifndef CURL_DISABLE_PROXY
long * const certverifyresult = SSL_IS_PROXY() ?
&data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+#else
+ long * const certverifyresult = &data->set.ssl.certverifyresult;
+#endif
const long int ssl_version = SSL_CONN_CONFIG(version);
#ifdef USE_TLS_SRP
const enum CURL_TLSAUTH ssl_authtype = SSL_SET_OPTION(authtype);
#endif
char * const ssl_cert = SSL_SET_OPTION(cert);
+ const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(cert_blob);
const char * const ssl_cert_type = SSL_SET_OPTION(cert_type);
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
const char * const ssl_capath = SSL_CONN_CONFIG(CApath);
@@ -2420,6 +2489,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
const char * const ssl_crlfile = SSL_SET_OPTION(CRLfile);
char error_buffer[256];
struct ssl_backend_data *backend = connssl->backend;
+ bool imported_native_ca = false;
DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
@@ -2634,8 +2704,11 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
unsigned char protocols[128];
#ifdef USE_NGHTTP2
- if(data->set.httpversion >= CURL_HTTP_VERSION_2 &&
- (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)) {
+ if(data->set.httpversion >= CURL_HTTP_VERSION_2
+#ifndef CURL_DISABLE_PROXY
+ && (!SSL_IS_PROXY() || !conn->bits.tunnel_proxy)
+#endif
+ ) {
protocols[cur++] = NGHTTP2_PROTO_VERSION_ID_LEN;
memcpy(&protocols[cur], NGHTTP2_PROTO_VERSION_ID,
@@ -2657,10 +2730,33 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
#endif
- if(ssl_cert || ssl_cert_type) {
- if(!cert_stuff(conn, backend->ctx, ssl_cert, ssl_cert_type,
- SSL_SET_OPTION(key), SSL_SET_OPTION(key_type),
- SSL_SET_OPTION(key_passwd))) {
+ if(ssl_cert || ssl_cert_blob || ssl_cert_type) {
+ BIO *ssl_cert_bio = NULL;
+ BIO *ssl_key_bio = NULL;
+ int result_cert_stuff;
+ if(ssl_cert_blob) {
+ /* the typecast of blob->len is fine since it is guaranteed to never be
+ larger than CURL_MAX_INPUT_LENGTH */
+ ssl_cert_bio = BIO_new_mem_buf(ssl_cert_blob->data,
+ (int)ssl_cert_blob->len);
+ if(!ssl_cert_bio)
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ if(SSL_SET_OPTION(key_blob)) {
+ ssl_key_bio = BIO_new_mem_buf(SSL_SET_OPTION(key_blob)->data,
+ (int)SSL_SET_OPTION(key_blob)->len);
+ if(!ssl_key_bio)
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ result_cert_stuff = cert_stuff(conn, backend->ctx,
+ ssl_cert, ssl_cert_bio, ssl_cert_type,
+ SSL_SET_OPTION(key), ssl_key_bio,
+ SSL_SET_OPTION(key_type), SSL_SET_OPTION(key_passwd));
+ if(ssl_cert_bio)
+ BIO_free(ssl_cert_bio);
+ if(ssl_key_bio)
+ BIO_free(ssl_key_bio);
+ if(!result_cert_stuff) {
/* failf() is already done in cert_stuff() */
return CURLE_SSL_CERTPROBLEM;
}
@@ -2720,38 +2816,186 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
}
#endif
+
+#if defined(USE_WIN32_CRYPTO)
+ /* Import certificates from the Windows root certificate store if requested.
+ https://stackoverflow.com/questions/9507184/
+ https://github.com/d3x0r/SACK/blob/master/src/netlib/ssl_layer.c#L1037
+ https://tools.ietf.org/html/rfc5280 */
+ if((SSL_CONN_CONFIG(verifypeer) || SSL_CONN_CONFIG(verifyhost)) &&
+ (SSL_SET_OPTION(native_ca_store))) {
+ X509_STORE *store = SSL_CTX_get_cert_store(backend->ctx);
+ HCERTSTORE hStore = CertOpenSystemStoreA((HCRYPTPROV_LEGACY)NULL, "ROOT");
+
+ if(hStore) {
+ PCCERT_CONTEXT pContext = NULL;
+ /* The array of enhanced key usage OIDs will vary per certificate and is
+ declared outside of the loop so that rather than malloc/free each
+ iteration we can grow it with realloc, when necessary. */
+ CERT_ENHKEY_USAGE *enhkey_usage = NULL;
+ DWORD enhkey_usage_size = 0;
+
+ /* This loop makes a best effort to import all valid certificates from
+ the MS root store. If a certificate cannot be imported it is skipped.
+ 'result' is used to store only hard-fail conditions (such as out of
+ memory) that cause an early break. */
+ result = CURLE_OK;
+ for(;;) {
+ X509 *x509;
+ FILETIME now;
+ BYTE key_usage[2];
+ DWORD req_size;
+ const unsigned char *encoded_cert;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ char cert_name[256];
+#endif
+
+ pContext = CertEnumCertificatesInStore(hStore, pContext);
+ if(!pContext)
+ break;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ if(!CertGetNameStringA(pContext, CERT_NAME_SIMPLE_DISPLAY_TYPE, 0,
+ NULL, cert_name, sizeof(cert_name))) {
+ strcpy(cert_name, "Unknown");
+ }
+ infof(data, "SSL: Checking cert \"%s\"\n", cert_name);
+#endif
+
+ encoded_cert = (const unsigned char *)pContext->pbCertEncoded;
+ if(!encoded_cert)
+ continue;
+
+ GetSystemTimeAsFileTime(&now);
+ if(CompareFileTime(&pContext->pCertInfo->NotBefore, &now) > 0 ||
+ CompareFileTime(&now, &pContext->pCertInfo->NotAfter) > 0)
+ continue;
+
+ /* If key usage exists check for signing attribute */
+ if(CertGetIntendedKeyUsage(pContext->dwCertEncodingType,
+ pContext->pCertInfo,
+ key_usage, sizeof(key_usage))) {
+ if(!(key_usage[0] & CERT_KEY_CERT_SIGN_KEY_USAGE))
+ continue;
+ }
+ else if(GetLastError())
+ continue;
+
+ /* If enhanced key usage exists check for server auth attribute.
+ *
+ * Note "In a Microsoft environment, a certificate might also have EKU
+ * extended properties that specify valid uses for the certificate."
+ * The call below checks both, and behavior varies depending on what is
+ * found. For more details see CertGetEnhancedKeyUsage doc.
+ */
+ if(CertGetEnhancedKeyUsage(pContext, 0, NULL, &req_size)) {
+ if(req_size && req_size > enhkey_usage_size) {
+ void *tmp = realloc(enhkey_usage, req_size);
+
+ if(!tmp) {
+ failf(data, "SSL: Out of memory allocating for OID list");
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ enhkey_usage = (CERT_ENHKEY_USAGE *)tmp;
+ enhkey_usage_size = req_size;
+ }
+
+ if(CertGetEnhancedKeyUsage(pContext, 0, enhkey_usage, &req_size)) {
+ if(!enhkey_usage->cUsageIdentifier) {
+ /* "If GetLastError returns CRYPT_E_NOT_FOUND, the certificate is
+ good for all uses. If it returns zero, the certificate has no
+ valid uses." */
+ if(GetLastError() != CRYPT_E_NOT_FOUND)
+ continue;
+ }
+ else {
+ DWORD i;
+ bool found = false;
+
+ for(i = 0; i < enhkey_usage->cUsageIdentifier; ++i) {
+ if(!strcmp("1.3.6.1.5.5.7.3.1" /* OID server auth */,
+ enhkey_usage->rgpszUsageIdentifier[i])) {
+ found = true;
+ break;
+ }
+ }
+
+ if(!found)
+ continue;
+ }
+ }
+ else
+ continue;
+ }
+ else
+ continue;
+
+ x509 = d2i_X509(NULL, &encoded_cert, pContext->cbCertEncoded);
+ if(!x509)
+ continue;
+
+ /* Try to import the certificate. This may fail for legitimate reasons
+ such as duplicate certificate, which is allowed by MS but not
+ OpenSSL. */
+ if(X509_STORE_add_cert(store, x509) == 1) {
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ infof(data, "SSL: Imported cert \"%s\"\n", cert_name);
+#endif
+ imported_native_ca = true;
+ }
+ X509_free(x509);
+ }
+
+ free(enhkey_usage);
+ CertFreeCertificateContext(pContext);
+ CertCloseStore(hStore, 0);
+
+ if(result)
+ return result;
+ }
+ if(imported_native_ca)
+ infof(data, "successfully imported windows ca store\n");
+ else
+ infof(data, "error importing windows ca store, continuing anyway\n");
+ }
+#endif
+
#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3)
/* OpenSSL 3.0.0 has deprecated SSL_CTX_load_verify_locations */
- if(ssl_cafile) {
- if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
- if(verifypeer) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate file: %s", ssl_cafile);
- return CURLE_SSL_CACERT_BADFILE;
+ {
+ if(ssl_cafile) {
+ if(!SSL_CTX_load_verify_file(backend->ctx, ssl_cafile)) {
+ if(verifypeer) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate file: %s", ssl_cafile);
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ /* Continue with a warning if no certificate verif is required. */
+ infof(data, "error setting certificate file, continuing anyway\n");
}
- /* Continue with a warning if no certificate verification is required. */
- infof(data, "error setting certificate file, continuing anyway\n");
+ infof(data, " CAfile: %s\n", ssl_cafile);
}
- infof(data, " CAfile: %s\n", ssl_cafile);
- }
- if(ssl_capath) {
- if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
- if(verifypeer) {
- /* Fail if we insist on successfully verifying the server. */
- failf(data, "error setting certificate path: %s", ssl_capath);
- return CURLE_SSL_CACERT_BADFILE;
+ if(ssl_capath) {
+ if(!SSL_CTX_load_verify_dir(backend->ctx, ssl_capath)) {
+ if(verifypeer) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data, "error setting certificate path: %s", ssl_capath);
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ /* Continue with a warning if no certificate verif is required. */
+ infof(data, "error setting certificate path, continuing anyway\n");
}
- /* Continue with a warning if no certificate verification is required. */
- infof(data, "error setting certificate path, continuing anyway\n");
+ infof(data, " CApath: %s\n", ssl_capath);
}
- infof(data, " CApath: %s\n", ssl_capath);
}
#else
if(ssl_cafile || ssl_capath) {
/* tell SSL where to find CA certificates that are used to verify
the servers certificate. */
if(!SSL_CTX_load_verify_locations(backend->ctx, ssl_cafile, ssl_capath)) {
- if(verifypeer) {
+ if(verifypeer && !imported_native_ca) {
/* Fail if we insist on successfully verifying the server. */
failf(data, "error setting certificate verify locations:\n"
" CAfile: %s\n CApath: %s",
@@ -2759,7 +3003,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
ssl_capath ? ssl_capath : "none");
return CURLE_SSL_CACERT_BADFILE;
}
- /* Just continue with a warning if no strict certificate verification
+ /* Just continue with a warning if no strict certificate verification
is required. */
infof(data, "error setting certificate verify locations,"
" continuing anyway:\n");
@@ -2777,7 +3021,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
#endif
#ifdef CURL_CA_FALLBACK
- else if(verifypeer) {
+ if(verifypeer && !ssl_cafile && !ssl_capath && !imported_native_ca) {
/* verifying the peer without any CA certificates won't
work so use openssl's built in default as fallback */
SSL_CTX_set_default_verify_paths(backend->ctx);
@@ -2805,21 +3049,24 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
if(verifypeer) {
/* Try building a chain using issuers in the trusted store first to avoid
problems with server-sent legacy intermediates. Newer versions of
- OpenSSL do alternate chain checking by default which gives us the same
- fix without as much of a performance hit (slight), so we prefer that if
- available.
+ OpenSSL do alternate chain checking by default but we do not know how to
+ determine that in a reliable manner.
https://rt.openssl.org/Ticket/Display.html?id=3621&user=guest&pass=guest
*/
-#if defined(X509_V_FLAG_TRUSTED_FIRST) && !defined(X509_V_FLAG_NO_ALT_CHAINS)
+#if defined(X509_V_FLAG_TRUSTED_FIRST)
X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
X509_V_FLAG_TRUSTED_FIRST);
#endif
#ifdef X509_V_FLAG_PARTIAL_CHAIN
- if(!SSL_SET_OPTION(no_partialchain)) {
+ if(!SSL_SET_OPTION(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
are. This allows users to verify servers using the intermediate cert
- only, instead of needing the whole chain. */
+ only, instead of needing the whole chain.
+
+ Due to OpenSSL bug https://github.com/openssl/openssl/issues/5081 we
+ cannot do partial chains with CRL check.
+ */
X509_STORE_set_flags(SSL_CTX_get_cert_store(backend->ctx),
X509_V_FLAG_PARTIAL_CHAIN);
}
@@ -2834,8 +3081,8 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
verifypeer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE, NULL);
/* Enable logging of secrets to the file specified in env SSLKEYLOGFILE. */
-#if defined(ENABLE_SSLKEYLOGFILE) && defined(HAVE_KEYLOG_CALLBACK)
- if(keylog_file_fp) {
+#ifdef HAVE_KEYLOG_CALLBACK
+ if(Curl_tls_keylog_enabled()) {
SSL_CTX_set_keylog_callback(backend->ctx, ossl_keylog_callback);
}
#endif
@@ -2922,6 +3169,7 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
Curl_ssl_sessionid_unlock(conn);
}
+#ifndef CURL_DISABLE_PROXY
if(conn->proxy_ssl[sockindex].use) {
BIO *const bio = BIO_new(BIO_f_ssl());
SSL *handle = conn->proxy_ssl[sockindex].backend->handle;
@@ -2931,7 +3179,9 @@ static CURLcode ossl_connect_step1(struct connectdata *conn, int sockindex)
BIO_set_ssl(bio, handle, FALSE);
SSL_set_bio(backend->handle, bio, bio);
}
- else if(!SSL_set_fd(backend->handle, (int)sockfd)) {
+ else
+#endif
+ if(!SSL_set_fd(backend->handle, (int)sockfd)) {
/* pass the raw socket into the SSL layers */
failf(data, "SSL: SSL_set_fd failed: %s",
ossl_strerror(ERR_get_error(), error_buffer, sizeof(error_buffer)));
@@ -2948,8 +3198,12 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
struct Curl_easy *data = conn->data;
int err;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+#ifndef CURL_DISABLE_PROXY
long * const certverifyresult = SSL_IS_PROXY() ?
&data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+#else
+ long * const certverifyresult = &data->set.ssl.certverifyresult;
+#endif
struct ssl_backend_data *backend = connssl->backend;
DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
|| ssl_connect_2_reading == connssl->connecting_state
@@ -2958,10 +3212,13 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
ERR_clear_error();
err = SSL_connect(backend->handle);
- /* If keylogging is enabled but the keylog callback is not supported then log
- secrets here, immediately after SSL_connect by using tap_ssl_key. */
-#if defined(ENABLE_SSLKEYLOGFILE) && !defined(HAVE_KEYLOG_CALLBACK)
- tap_ssl_key(backend->handle, &backend->tap_state);
+#ifndef HAVE_KEYLOG_CALLBACK
+ if(Curl_tls_keylog_enabled()) {
+ /* If key logging is enabled, wait for the handshake to complete and then
+ * proceed with logging secrets (for TLS 1.2 or older).
+ */
+ ossl_log_tls12_secret(backend->handle, &backend->keylog_done);
+ }
#endif
/* 1 is fine
@@ -3032,9 +3289,14 @@ static CURLcode ossl_connect_step2(struct connectdata *conn, int sockindex)
* the SO_ERROR is also lost.
*/
if(CURLE_SSL_CONNECT_ERROR == result && errdetail == 0) {
+#ifndef CURL_DISABLE_PROXY
const char * const hostname = SSL_IS_PROXY() ?
conn->http_proxy.host.name : conn->host.name;
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
+#else
+ const char * const hostname = conn->host.name;
+ const long int port = conn->remote_port;
+#endif
char extramsg[80]="";
int sockerr = SOCKERRNO;
if(sockerr && detail == SSL_ERROR_SYSCALL)
@@ -3487,8 +3749,12 @@ static CURLcode servercert(struct connectdata *conn,
char error_buffer[256]="";
char buffer[2048];
const char *ptr;
+#ifndef CURL_DISABLE_PROXY
long * const certverifyresult = SSL_IS_PROXY() ?
&data->set.proxy_ssl.certverifyresult : &data->set.ssl.certverifyresult;
+#else
+ long * const certverifyresult = &data->set.ssl.certverifyresult;
+#endif
BIO *mem = BIO_new(BIO_s_mem());
struct ssl_backend_data *backend = connssl->backend;
@@ -3552,27 +3818,32 @@ static CURLcode servercert(struct connectdata *conn,
deallocating the certificate. */
/* e.g. match issuer name with provided issuer certificate */
- if(SSL_SET_OPTION(issuercert)) {
- fp = BIO_new(BIO_s_file());
- if(fp == NULL) {
- failf(data,
- "BIO_new return NULL, " OSSL_PACKAGE
- " error %s",
- ossl_strerror(ERR_get_error(), error_buffer,
- sizeof(error_buffer)) );
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
- return CURLE_OUT_OF_MEMORY;
- }
+ if(SSL_SET_OPTION(issuercert) || SSL_SET_OPTION(issuercert_blob)) {
+ if(SSL_SET_OPTION(issuercert_blob))
+ fp = BIO_new_mem_buf(SSL_SET_OPTION(issuercert_blob)->data,
+ (int)SSL_SET_OPTION(issuercert_blob)->len);
+ else {
+ fp = BIO_new(BIO_s_file());
+ if(fp == NULL) {
+ failf(data,
+ "BIO_new return NULL, " OSSL_PACKAGE
+ " error %s",
+ ossl_strerror(ERR_get_error(), error_buffer,
+ sizeof(error_buffer)) );
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
- if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
- if(strict)
- failf(data, "SSL: Unable to open issuer cert (%s)",
- SSL_SET_OPTION(issuercert));
- BIO_free(fp);
- X509_free(backend->server_cert);
- backend->server_cert = NULL;
- return CURLE_SSL_ISSUER_ERROR;
+ if(BIO_read_filename(fp, SSL_SET_OPTION(issuercert)) <= 0) {
+ if(strict)
+ failf(data, "SSL: Unable to open issuer cert (%s)",
+ SSL_SET_OPTION(issuercert));
+ BIO_free(fp);
+ X509_free(backend->server_cert);
+ backend->server_cert = NULL;
+ return CURLE_SSL_ISSUER_ERROR;
+ }
}
issuer = PEM_read_bio_X509(fp, NULL, ZERO_NULL, NULL);
@@ -3690,7 +3961,6 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
- timediff_t timeout_ms;
int what;
/* check if the connection has already been established */
@@ -3701,7 +3971,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
if(ssl_connect_1 == connssl->connecting_state) {
/* Find out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
/* no need to continue if time already is up */
@@ -3719,7 +3989,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
/* no need to continue if time already is up */
@@ -3737,7 +4007,7 @@ static CURLcode ossl_connect_common(struct connectdata *conn,
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- nonblocking?0:(time_t)timeout_ms);
+ nonblocking?0:timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
@@ -3816,14 +4086,15 @@ static bool Curl_ossl_data_pending(const struct connectdata *conn,
int connindex)
{
const struct ssl_connect_data *connssl = &conn->ssl[connindex];
- const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex];
-
if(connssl->backend->handle && SSL_pending(connssl->backend->handle))
return TRUE;
-
- if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle))
- return TRUE;
-
+#ifndef CURL_DISABLE_PROXY
+ {
+ const struct ssl_connect_data *proxyssl = &conn->proxy_ssl[connindex];
+ if(proxyssl->backend->handle && SSL_pending(proxyssl->backend->handle))
+ return TRUE;
+ }
+#endif
return FALSE;
}
@@ -3884,8 +4155,11 @@ static ssize_t ossl_send(struct connectdata *conn,
sslerror = ERR_get_error();
if(ERR_GET_LIB(sslerror) == ERR_LIB_SSL &&
ERR_GET_REASON(sslerror) == SSL_R_BIO_NOT_SET &&
- conn->ssl[sockindex].state == ssl_connection_complete &&
- conn->proxy_ssl[sockindex].state == ssl_connection_complete) {
+ conn->ssl[sockindex].state == ssl_connection_complete
+#ifndef CURL_DISABLE_PROXY
+ && conn->proxy_ssl[sockindex].state == ssl_connection_complete
+#endif
+ ) {
char ver[120];
Curl_ossl_version(ver, 120);
failf(conn->data, "Error: %s does not support double SSL tunneling.",
@@ -4109,7 +4383,7 @@ static CURLcode Curl_ossl_sha256sum(const unsigned char *tmp, /* input */
unsigned int len = 0;
(void) unused;
- mdctx = EVP_MD_CTX_create();
+ mdctx = EVP_MD_CTX_create();
EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL);
EVP_DigestUpdate(mdctx, tmp, tmplen);
EVP_DigestFinal_ex(mdctx, sha256sum, &len);
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 49659bb7..19965260 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -39,10 +39,11 @@
#include "schannel.h"
#include "vtls.h"
+#include "strcase.h"
#include "sendf.h"
#include "connect.h" /* for the connect timeout */
#include "strerror.h"
-#include "select.h" /* for the socket readyness */
+#include "select.h" /* for the socket readiness */
#include "inet_pton.h" /* for IP addr SNI check */
#include "curl_multibyte.h"
#include "warnless.h"
@@ -51,7 +52,7 @@
#include "multiif.h"
#include "system_win32.h"
- /* The last #include file should be: */
+/* The last #include file should be: */
#include "curl_memory.h"
#include "memdebug.h"
@@ -169,25 +170,25 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
long i = ssl_version;
switch(ssl_version_max) {
- case CURL_SSLVERSION_MAX_NONE:
- case CURL_SSLVERSION_MAX_DEFAULT:
- ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
- break;
+ case CURL_SSLVERSION_MAX_NONE:
+ case CURL_SSLVERSION_MAX_DEFAULT:
+ ssl_version_max = CURL_SSLVERSION_MAX_TLSv1_2;
+ break;
}
for(; i <= (ssl_version_max >> 16); ++i) {
switch(i) {
- case CURL_SSLVERSION_TLSv1_0:
- schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
- break;
- case CURL_SSLVERSION_TLSv1_1:
- schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
- break;
- case CURL_SSLVERSION_TLSv1_2:
- schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
- break;
- case CURL_SSLVERSION_TLSv1_3:
- failf(data, "schannel: TLS 1.3 is not yet supported");
- return CURLE_SSL_CONNECT_ERROR;
+ case CURL_SSLVERSION_TLSv1_0:
+ schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_0_CLIENT;
+ break;
+ case CURL_SSLVERSION_TLSv1_1:
+ schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_1_CLIENT;
+ break;
+ case CURL_SSLVERSION_TLSv1_2:
+ schannel_cred->grbitEnabledProtocols |= SP_PROT_TLS1_2_CLIENT;
+ break;
+ case CURL_SSLVERSION_TLSv1_3:
+ failf(data, "schannel: TLS 1.3 is not yet supported");
+ return CURLE_SSL_CONNECT_ERROR;
}
}
return CURLE_OK;
@@ -195,9 +196,9 @@ set_ssl_version_min_max(SCHANNEL_CRED *schannel_cred, struct connectdata *conn)
/*longest is 26, buffer is slightly bigger*/
#define LONGEST_ALG_ID 32
-#define CIPHEROPTION(X) \
-if(strcmp(#X, tmp) == 0) \
- return X
+#define CIPHEROPTION(X) \
+ if(strcmp(#X, tmp) == 0) \
+ return X
static int
get_alg_id_by_name(char *name)
@@ -273,11 +274,11 @@ get_alg_id_by_name(char *name)
#ifdef CALG_HMAC
CIPHEROPTION(CALG_HMAC);
#endif
-#if !defined(__W32API_MAJOR_VERSION) || \
- !defined(__W32API_MINOR_VERSION) || \
- defined(__MINGW64_VERSION_MAJOR) || \
- (__W32API_MAJOR_VERSION > 5) || \
- ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0))
+#if !defined(__W32API_MAJOR_VERSION) || \
+ !defined(__W32API_MINOR_VERSION) || \
+ defined(__MINGW64_VERSION_MAJOR) || \
+ (__W32API_MAJOR_VERSION > 5) || \
+ ((__W32API_MAJOR_VERSION == 5) && (__W32API_MINOR_VERSION > 0))
/* CALG_TLS1PRF has a syntax error in MinGW's w32api up to version 5.0,
see https://osdn.net/projects/mingw/ticket/38391 */
CIPHEROPTION(CALG_TLS1PRF);
@@ -339,7 +340,7 @@ set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers)
if(startCur)
startCur++;
}
- schannel_cred->palgSupportedAlgs = algIds;
+ schannel_cred->palgSupportedAlgs = algIds;
schannel_cred->cSupportedAlgs = algCount;
return CURLE_OK;
}
@@ -424,8 +425,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
#endif
TCHAR *host_name;
CURLcode result;
+#ifndef CURL_DISABLE_PROXY
char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+#else
+ char * const hostname = conn->host.name;
+#endif
DEBUGF(infof(data,
"schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
@@ -433,20 +438,20 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
if(Curl_verify_windows_version(5, 1, PLATFORM_WINNT,
VERSION_LESS_THAN_EQUAL)) {
- /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
- algorithms that may not be supported by all servers. */
- infof(data, "schannel: Windows version is old and may not be able to "
- "connect to some servers due to lack of SNI, algorithms, etc.\n");
+ /* Schannel in Windows XP (OS version 5.1) uses legacy handshakes and
+ algorithms that may not be supported by all servers. */
+ infof(data, "schannel: Windows version is old and may not be able to "
+ "connect to some servers due to lack of SNI, algorithms, etc.\n");
}
#ifdef HAS_ALPN
/* ALPN is only supported on Windows 8.1 / Server 2012 R2 and above.
Also it doesn't seem to be supported for Wine, see curl bug #983. */
BACKEND->use_alpn = conn->bits.tls_enable_alpn &&
- !GetProcAddress(GetModuleHandleA("ntdll"),
- "wine_get_version") &&
- Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
- VERSION_GREATER_THAN_EQUAL);
+ !GetProcAddress(GetModuleHandleA("ntdll"),
+ "wine_get_version") &&
+ Curl_verify_windows_version(6, 3, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL);
#else
BACKEND->use_alpn = false;
#endif
@@ -555,12 +560,12 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
case CURL_SSLVERSION_TLSv1_3:
- {
- result = set_ssl_version_min_max(&schannel_cred, conn);
- if(result != CURLE_OK)
- return result;
- break;
- }
+ {
+ result = set_ssl_version_min_max(&schannel_cred, conn);
+ if(result != CURLE_OK)
+ return result;
+ break;
+ }
case CURL_SSLVERSION_SSLv3:
schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
break;
@@ -583,105 +588,133 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
#ifdef HAS_CLIENT_CERT_PATH
/* client certificate */
- if(data->set.ssl.cert) {
- DWORD cert_store_name;
+ if(data->set.ssl.cert || data->set.ssl.cert_blob) {
+ DWORD cert_store_name = 0;
TCHAR *cert_store_path = NULL;
- TCHAR *cert_thumbprint_str;
+ TCHAR *cert_thumbprint_str = NULL;
CRYPT_HASH_BLOB cert_thumbprint;
BYTE cert_thumbprint_data[CERT_THUMBPRINT_DATA_LEN];
- HCERTSTORE cert_store;
+ HCERTSTORE cert_store = NULL;
FILE *fInCert = NULL;
+ void *certdata = NULL;
+ size_t certsize = 0;
+ bool blob = data->set.ssl.cert_blob != NULL;
+ TCHAR *cert_path = NULL;
+ if(blob) {
+ certdata = data->set.ssl.cert_blob->data;
+ certsize = data->set.ssl.cert_blob->len;
+ }
+ else {
+ cert_path = curlx_convert_UTF8_to_tchar(data->set.ssl.cert);
+ if(!cert_path)
+ return CURLE_OUT_OF_MEMORY;
- TCHAR *cert_path = Curl_convert_UTF8_to_tchar(data->set.ssl.cert);
- if(!cert_path)
- return CURLE_OUT_OF_MEMORY;
+ result = get_cert_location(cert_path, &cert_store_name,
+ &cert_store_path, &cert_thumbprint_str);
- result = get_cert_location(cert_path, &cert_store_name,
- &cert_store_path, &cert_thumbprint_str);
- if((result != CURLE_OK) && (data->set.ssl.cert[0]!='\0'))
- fInCert = fopen(data->set.ssl.cert, "rb");
+ if(result && (data->set.ssl.cert[0]!='\0'))
+ fInCert = fopen(data->set.ssl.cert, "rb");
- if((result != CURLE_OK) && (fInCert == NULL)) {
- failf(data, "schannel: Failed to get certificate location"
- " or file for %s",
- data->set.ssl.cert);
- Curl_unicodefree(cert_path);
- return result;
+ if(result && !fInCert) {
+ failf(data, "schannel: Failed to get certificate location"
+ " or file for %s",
+ data->set.ssl.cert);
+ curlx_unicodefree(cert_path);
+ return result;
+ }
}
- if(fInCert) {
+ if((fInCert || blob) && (data->set.ssl.cert_type) &&
+ (!strcasecompare(data->set.ssl.cert_type, "P12"))) {
+ failf(data, "schannel: certificate format compatibility error "
+ " for %s",
+ blob ? "(memory blob)" : data->set.ssl.cert);
+ curlx_unicodefree(cert_path);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+
+ if(fInCert || blob) {
/* Reading a .P12 or .pfx file, like the example at bottom of
- https://social.msdn.microsoft.com/Forums/windowsdesktop/
- en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
+ https://social.msdn.microsoft.com/Forums/windowsdesktop/
+ en-US/3e7bc95f-b21a-4bcd-bd2c-7f996718cae5
*/
- void *certdata = NULL;
- long filesize = 0;
CRYPT_DATA_BLOB datablob;
WCHAR* pszPassword;
size_t pwd_len = 0;
int str_w_len = 0;
- int continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
- if(continue_reading)
- filesize = ftell(fInCert);
- if(filesize < 0)
- continue_reading = 0;
- if(continue_reading)
- continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
- if(continue_reading)
- certdata = malloc(((size_t)filesize) + 1);
- if((certdata == NULL) ||
- ((int) fread(certdata, (size_t)filesize, 1, fInCert) != 1))
- continue_reading = 0;
- fclose(fInCert);
- Curl_unicodefree(cert_path);
-
- if(!continue_reading) {
- failf(data, "schannel: Failed to read cert file %s",
+ const char *cert_showfilename_error = blob ?
+ "(memory blob)" : data->set.ssl.cert;
+ curlx_unicodefree(cert_path);
+ if(fInCert) {
+ long cert_tell = 0;
+ bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0;
+ if(continue_reading)
+ cert_tell = ftell(fInCert);
+ if(cert_tell < 0)
+ continue_reading = FALSE;
+ else
+ certsize = (size_t)cert_tell;
+ if(continue_reading)
+ continue_reading = fseek(fInCert, 0, SEEK_SET) == 0;
+ if(continue_reading)
+ certdata = malloc(certsize + 1);
+ if((!certdata) ||
+ ((int) fread(certdata, certsize, 1, fInCert) != 1))
+ continue_reading = FALSE;
+ fclose(fInCert);
+ if(!continue_reading) {
+ failf(data, "schannel: Failed to read cert file %s",
data->set.ssl.cert);
- free(certdata);
- return CURLE_SSL_CERTPROBLEM;
+ free(certdata);
+ return CURLE_SSL_CERTPROBLEM;
+ }
}
/* Convert key-pair data to the in-memory certificate store */
datablob.pbData = (BYTE*)certdata;
- datablob.cbData = (DWORD)filesize;
+ datablob.cbData = (DWORD)certsize;
if(data->set.ssl.key_passwd != NULL)
pwd_len = strlen(data->set.ssl.key_passwd);
pszPassword = (WCHAR*)malloc(sizeof(WCHAR)*(pwd_len + 1));
- if(pwd_len > 0)
- str_w_len =
- MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
- data->set.ssl.key_passwd, (int)pwd_len,
- pszPassword, (int)(pwd_len + 1));
-
- if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
- pszPassword[str_w_len] = 0;
- else
- pszPassword[0] = 0;
-
- cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
- free(pszPassword);
- free(certdata);
+ if(pszPassword) {
+ if(pwd_len > 0)
+ str_w_len = MultiByteToWideChar(CP_UTF8,
+ MB_ERR_INVALID_CHARS,
+ data->set.ssl.key_passwd, (int)pwd_len,
+ pszPassword, (int)(pwd_len + 1));
+
+ if((str_w_len >= 0) && (str_w_len <= (int)pwd_len))
+ pszPassword[str_w_len] = 0;
+ else
+ pszPassword[0] = 0;
+
+ cert_store = PFXImportCertStore(&datablob, pszPassword, 0);
+ free(pszPassword);
+ }
+ if(!blob)
+ free(certdata);
if(cert_store == NULL) {
DWORD errorcode = GetLastError();
if(errorcode == ERROR_INVALID_PASSWORD)
failf(data, "schannel: Failed to import cert file %s, "
- "password is bad", data->set.ssl.cert);
+ "password is bad",
+ cert_showfilename_error);
else
failf(data, "schannel: Failed to import cert file %s, "
- "last error is 0x%x", data->set.ssl.cert, errorcode);
+ "last error is 0x%x",
+ cert_showfilename_error, errorcode);
return CURLE_SSL_CERTPROBLEM;
}
client_certs[0] = CertFindCertificateInStore(
- cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
- CERT_FIND_ANY, NULL, NULL);
+ cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
+ CERT_FIND_ANY, NULL, NULL);
if(client_certs[0] == NULL) {
failf(data, "schannel: Failed to get certificate from file %s"
", last error is 0x%x",
- data->set.ssl.cert, GetLastError());
+ cert_showfilename_error, GetLastError());
CertCloseStore(cert_store, 0);
return CURLE_SSL_CERTPROBLEM;
}
@@ -700,7 +733,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
"last error is 0x%x",
cert_store_name, cert_store_path, GetLastError());
free(cert_store_path);
- Curl_unicodefree(cert_path);
+ curlx_unicodefree(cert_path);
return CURLE_SSL_CERTPROBLEM;
}
free(cert_store_path);
@@ -714,7 +747,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
cert_thumbprint_data,
&cert_thumbprint.cbData,
NULL, NULL)) {
- Curl_unicodefree(cert_path);
+ curlx_unicodefree(cert_path);
CertCloseStore(cert_store, 0);
return CURLE_SSL_CERTPROBLEM;
}
@@ -723,7 +756,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
cert_store, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0,
CERT_FIND_HASH, &cert_thumbprint, NULL);
- Curl_unicodefree(cert_path);
+ curlx_unicodefree(cert_path);
if(client_certs[0]) {
schannel_cred.cCreds = 1;
@@ -758,7 +791,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
BACKEND->cred->refcount = 1;
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx
- */
+ */
sspi_status =
s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
SECPKG_CRED_OUTBOUND, NULL,
@@ -775,15 +808,15 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
Curl_safefree(BACKEND->cred);
switch(sspi_status) {
- case SEC_E_INSUFFICIENT_MEMORY:
- return CURLE_OUT_OF_MEMORY;
- case SEC_E_NO_CREDENTIALS:
- case SEC_E_SECPKG_NOT_FOUND:
- case SEC_E_NOT_OWNER:
- case SEC_E_UNKNOWN_CREDENTIALS:
- case SEC_E_INTERNAL_ERROR:
- default:
- return CURLE_SSL_CONNECT_ERROR;
+ case SEC_E_INSUFFICIENT_MEMORY:
+ return CURLE_OUT_OF_MEMORY;
+ case SEC_E_NO_CREDENTIALS:
+ case SEC_E_SECPKG_NOT_FOUND:
+ case SEC_E_NOT_OWNER:
+ case SEC_E_UNKNOWN_CREDENTIALS:
+ case SEC_E_INTERNAL_ERROR:
+ default:
+ return CURLE_SSL_CONNECT_ERROR;
}
}
}
@@ -867,7 +900,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
return CURLE_OUT_OF_MEMORY;
}
- host_name = Curl_convert_UTF8_to_tchar(hostname);
+ host_name = curlx_convert_UTF8_to_tchar(hostname);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
@@ -884,35 +917,35 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
0, &BACKEND->ctxt->ctxt_handle,
&outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
- Curl_unicodefree(host_name);
+ curlx_unicodefree(host_name);
if(sspi_status != SEC_I_CONTINUE_NEEDED) {
char buffer[STRERROR_LEN];
Curl_safefree(BACKEND->ctxt);
switch(sspi_status) {
- case SEC_E_INSUFFICIENT_MEMORY:
- failf(data, "schannel: initial InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
- return CURLE_OUT_OF_MEMORY;
- case SEC_E_WRONG_PRINCIPAL:
- 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:
- */
- default:
- failf(data, "schannel: initial InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
- return CURLE_SSL_CONNECT_ERROR;
+ case SEC_E_INSUFFICIENT_MEMORY:
+ failf(data, "schannel: initial InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ return CURLE_OUT_OF_MEMORY;
+ case SEC_E_WRONG_PRINCIPAL:
+ 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:
+ */
+ default:
+ failf(data, "schannel: initial InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -958,8 +991,12 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
SECURITY_STATUS sspi_status = SEC_E_OK;
CURLcode result;
bool doread;
+#ifndef CURL_DISABLE_PROXY
char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+#else
+ char * const hostname = conn->host.name;
+#endif
const char *pubkey_ptr;
doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
@@ -1067,18 +1104,18 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
memcpy(inbuf[0].pvBuffer, BACKEND->encdata_buffer,
BACKEND->encdata_offset);
- host_name = Curl_convert_UTF8_to_tchar(hostname);
+ host_name = curlx_convert_UTF8_to_tchar(hostname);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx
- */
+ */
sspi_status = s_pSecFn->InitializeSecurityContext(
&BACKEND->cred->cred_handle, &BACKEND->ctxt->ctxt_handle,
host_name, BACKEND->req_flags, 0, 0, &inbuf_desc, 0, NULL,
&outbuf_desc, &BACKEND->ret_flags, &BACKEND->ctxt->time_stamp);
- Curl_unicodefree(host_name);
+ curlx_unicodefree(host_name);
/* free buffer for received handshake data */
Curl_safefree(inbuf[0].pvBuffer);
@@ -1133,29 +1170,29 @@ schannel_connect_step2(struct connectdata *conn, int sockindex)
else {
char buffer[STRERROR_LEN];
switch(sspi_status) {
- case SEC_E_INSUFFICIENT_MEMORY:
- failf(data, "schannel: next InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
- return CURLE_OUT_OF_MEMORY;
- case SEC_E_WRONG_PRINCIPAL:
- 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:
- */
- default:
- failf(data, "schannel: next InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
- return CURLE_SSL_CONNECT_ERROR;
+ case SEC_E_INSUFFICIENT_MEMORY:
+ failf(data, "schannel: next InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ return CURLE_OUT_OF_MEMORY;
+ case SEC_E_WRONG_PRINCIPAL:
+ 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:
+ */
+ default:
+ failf(data, "schannel: next InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
+ return CURLE_SSL_CONNECT_ERROR;
}
}
@@ -1324,8 +1361,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
#ifdef HAS_ALPN
if(BACKEND->use_alpn) {
- sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
- SECPKG_ATTR_APPLICATION_PROTOCOL, &alpn_result);
+ sspi_status =
+ s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ SECPKG_ATTR_APPLICATION_PROTOCOL,
+ &alpn_result);
if(sspi_status != SEC_E_OK) {
failf(data, "schannel: failed to retrieve ALPN result");
@@ -1336,21 +1375,21 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
SecApplicationProtocolNegotiationStatus_Success) {
infof(data, "schannel: ALPN, server accepted to use %.*s\n",
- alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
+ alpn_result.ProtocolIdSize, alpn_result.ProtocolId);
#ifdef USE_NGHTTP2
if(alpn_result.ProtocolIdSize == NGHTTP2_PROTO_VERSION_ID_LEN &&
!memcmp(NGHTTP2_PROTO_VERSION_ID, alpn_result.ProtocolId,
- NGHTTP2_PROTO_VERSION_ID_LEN)) {
+ NGHTTP2_PROTO_VERSION_ID_LEN)) {
conn->negnpn = CURL_HTTP_VERSION_2;
}
else
#endif
- if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
- !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
- ALPN_HTTP_1_1_LENGTH)) {
- conn->negnpn = CURL_HTTP_VERSION_1_1;
- }
+ if(alpn_result.ProtocolIdSize == ALPN_HTTP_1_1_LENGTH &&
+ !memcmp(ALPN_HTTP_1_1, alpn_result.ProtocolId,
+ ALPN_HTTP_1_1_LENGTH)) {
+ conn->negnpn = CURL_HTTP_VERSION_1_1;
+ }
}
else
infof(data, "ALPN, server did not agree to a protocol\n");
@@ -1397,8 +1436,10 @@ schannel_connect_step3(struct connectdata *conn, int sockindex)
if(data->set.ssl.certinfo) {
int certs_count = 0;
- sspi_status = s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
- SECPKG_ATTR_REMOTE_CERT_CONTEXT, &ccert_context);
+ sspi_status =
+ s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &ccert_context);
if((sspi_status != SEC_E_OK) || (ccert_context == NULL)) {
failf(data, "schannel: failed to retrieve remote cert context");
@@ -1481,7 +1522,7 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- nonblocking ? 0 : (time_t)timeout_ms);
+ nonblocking ? 0 : timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
@@ -1630,13 +1671,9 @@ schannel_send(struct connectdata *conn, int sockindex,
/* send entire message or fail */
while(len > (size_t)written) {
- ssize_t this_write;
- timediff_t timeout_ms;
+ ssize_t this_write = 0;
int what;
-
- this_write = 0;
-
- timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
+ timediff_t timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
if(timeout_ms < 0) {
/* we already got the timeout */
failf(conn->data, "schannel: timed out sending data "
@@ -1645,7 +1682,7 @@ schannel_send(struct connectdata *conn, int sockindex,
written = -1;
break;
}
- if(!timeout_ms)
+ else if(!timeout_ms)
timeout_ms = TIMEDIFF_T_MAX;
what = SOCKET_WRITABLE(conn->sock[sockindex], timeout_ms);
if(what < 0) {
@@ -1741,8 +1778,8 @@ schannel_recv(struct connectdata *conn, int sockindex,
}
else if(!len) {
/* It's debatable what to return when !len. Regardless we can't return
- immediately because there may be data to decrypt (in the case we want to
- decrypt all encrypted cached data) so handle !len later in cleanup.
+ immediately because there may be data to decrypt (in the case we want to
+ decrypt all encrypted cached data) so handle !len later in cleanup.
*/
; /* do nothing */
}
@@ -1752,7 +1789,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
if(size < CURL_SCHANNEL_BUFFER_FREE_SIZE ||
BACKEND->encdata_length < min_encdata_length) {
reallocated_length = BACKEND->encdata_offset +
- CURL_SCHANNEL_BUFFER_FREE_SIZE;
+ CURL_SCHANNEL_BUFFER_FREE_SIZE;
if(reallocated_length < min_encdata_length) {
reallocated_length = min_encdata_length;
}
@@ -1820,7 +1857,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
InitSecBufferDesc(&inbuf_desc, inbuf, 4);
/* https://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx
- */
+ */
sspi_status = s_pSecFn->DecryptMessage(&BACKEND->ctxt->ctxt_handle,
&inbuf_desc, 0, NULL);
@@ -1836,7 +1873,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
/* increase buffer in order to fit the received amount of data */
size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
- inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
+ inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
if(BACKEND->decdata_length - BACKEND->decdata_offset < size ||
BACKEND->decdata_length < len) {
/* increase internal decrypted data buffer */
@@ -1906,7 +1943,7 @@ schannel_recv(struct connectdata *conn, int sockindex,
if(BACKEND->encdata_offset) {
*err = CURLE_RECV_ERROR;
infof(data, "schannel: can't renogotiate, "
- "encrypted data available\n");
+ "encrypted data available\n");
goto cleanup;
}
/* begin renegotiation */
@@ -1961,17 +1998,20 @@ schannel_recv(struct connectdata *conn, int sockindex,
"schannel: decrypted data buffer: offset %zu length %zu\n",
BACKEND->decdata_offset, BACKEND->decdata_length));
-cleanup:
+ cleanup:
/* Warning- there is no guarantee the encdata state is valid at this point */
DEBUGF(infof(data, "schannel: schannel_recv cleanup\n"));
/* Error if the connection has closed without a close_notify.
- Behavior here is a matter of debate. We don't want to be vulnerable to a
- truncation attack however there's some browser precedent for ignoring the
- close_notify for compatibility reasons.
- Additionally, Windows 2000 (v5.0) is a special case since it seems it doesn't
- return close_notify. In that case if the connection was closed we assume it
- was graceful (close_notify) since there doesn't seem to be a way to tell.
+
+ The behavior here is a matter of debate. We don't want to be vulnerable
+ to a truncation attack however there's some browser precedent for
+ ignoring the close_notify for compatibility reasons.
+
+ Additionally, Windows 2000 (v5.0) is a special case since it seems it
+ doesn't return close_notify. In that case if the connection was closed we
+ assume it was graceful (close_notify) since there doesn't seem to be a
+ way to tell.
*/
if(len && !BACKEND->decdata_offset && BACKEND->recv_connection_closed &&
!BACKEND->recv_sspi_close_notify) {
@@ -1988,7 +2028,7 @@ cleanup:
/* Any error other than CURLE_AGAIN is an unrecoverable error. */
if(*err && *err != CURLE_AGAIN)
- BACKEND->recv_unrecoverable_err = *err;
+ BACKEND->recv_unrecoverable_err = *err;
size = len < BACKEND->decdata_offset ? len : BACKEND->decdata_offset;
if(size) {
@@ -2005,10 +2045,11 @@ cleanup:
}
if(!*err && !BACKEND->recv_connection_closed)
- *err = CURLE_AGAIN;
+ *err = CURLE_AGAIN;
- /* It's debatable what to return when !len. We could return whatever error we
- got from decryption but instead we override here so the return is consistent.
+ /* It's debatable what to return when !len. We could return whatever error
+ we got from decryption but instead we override here so the return is
+ consistent.
*/
if(!len)
*err = CURLE_OK;
@@ -2074,8 +2115,12 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
*/
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+#ifndef CURL_DISABLE_PROXY
char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+#else
+ char * const hostname = conn->host.name;
+#endif
DEBUGASSERT(data);
@@ -2104,7 +2149,7 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
Curl_sspi_strerror(sspi_status, buffer, sizeof(buffer)));
}
- host_name = Curl_convert_UTF8_to_tchar(hostname);
+ host_name = curlx_convert_UTF8_to_tchar(hostname);
if(!host_name)
return CURLE_OUT_OF_MEMORY;
@@ -2126,7 +2171,7 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
&BACKEND->ret_flags,
&BACKEND->ctxt->time_stamp);
- Curl_unicodefree(host_name);
+ curlx_unicodefree(host_name);
if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
/* send close message which is in output buffer */
@@ -2235,8 +2280,8 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
SECURITY_STATUS sspi_status;
const char *x509_der;
DWORD x509_der_len;
- curl_X509certificate x509_parsed;
- curl_asn1Element *pubkey;
+ struct Curl_X509certificate x509_parsed;
+ struct Curl_asn1Element *pubkey;
sspi_status =
s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
@@ -2252,7 +2297,7 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
if(!(((pCertContextServer->dwCertEncodingType & X509_ASN_ENCODING) != 0) &&
- (pCertContextServer->cbCertEncoded > 0)))
+ (pCertContextServer->cbCertEncoded > 0)))
break;
x509_der = (const char *)pCertContextServer->pbCertEncoded;
@@ -2343,9 +2388,9 @@ static CURLcode Curl_schannel_md5sum(unsigned char *input,
}
static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
- size_t inputlen,
- unsigned char *sha256sum,
- size_t sha256len)
+ size_t inputlen,
+ unsigned char *sha256sum,
+ size_t sha256len)
{
Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
PROV_RSA_AES, CALG_SHA_256);
diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c
index 3dbc11f0..bdd7199e 100644
--- a/lib/vtls/schannel_verify.c
+++ b/lib/vtls/schannel_verify.c
@@ -57,7 +57,7 @@
#define BEGIN_CERT "-----BEGIN CERTIFICATE-----"
#define END_CERT "\n-----END CERTIFICATE-----"
-typedef struct {
+struct cert_chain_engine_config_win7 {
DWORD cbSize;
HCERTSTORE hRestrictedRoot;
HCERTSTORE hRestrictedTrust;
@@ -70,7 +70,7 @@ typedef struct {
DWORD CycleDetectionModulus;
HCERTSTORE hExclusiveRoot;
HCERTSTORE hExclusiveTrustedPeople;
-} CERT_CHAIN_ENGINE_CONFIG_WIN7, *PCERT_CHAIN_ENGINE_CONFIG_WIN7;
+};
static int is_cr_or_lf(char c)
{
@@ -94,7 +94,7 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
int num_certs = 0;
size_t END_CERT_LEN;
- ca_file_tstr = Curl_convert_UTF8_to_tchar((char *)ca_file);
+ ca_file_tstr = curlx_convert_UTF8_to_tchar((char *)ca_file);
if(!ca_file_tstr) {
char buffer[STRERROR_LEN];
failf(data,
@@ -288,7 +288,7 @@ cleanup:
CloseHandle(ca_file_handle);
}
Curl_safefree(ca_file_buffer);
- Curl_unicodefree(ca_file_tstr);
+ curlx_unicodefree(ca_file_tstr);
return result;
}
@@ -361,7 +361,7 @@ static DWORD cert_get_name_string(struct Curl_easy *data,
return actual_length;
}
- decode_para.cbSize = sizeof(CRYPT_DECODE_PARA);
+ decode_para.cbSize = sizeof(CRYPT_DECODE_PARA);
ret_val =
CryptDecodeObjectEx(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
@@ -476,7 +476,7 @@ static CURLcode verify_host(struct Curl_easy *data,
* is acceptable since both values are assumed to use ASCII
* (or some equivalent) encoding
*/
- cert_hostname = Curl_convert_tchar_to_UTF8(
+ cert_hostname = curlx_convert_tchar_to_UTF8(
&cert_hostname_buff[cert_hostname_buff_index]);
if(!cert_hostname) {
result = CURLE_OUT_OF_MEMORY;
@@ -508,7 +508,7 @@ static CURLcode verify_host(struct Curl_easy *data,
result = CURLE_PEER_FAILED_VERIFICATION;
}
- Curl_unicodefree(cert_hostname);
+ curlx_unicodefree(cert_hostname);
}
}
@@ -522,7 +522,7 @@ static CURLcode verify_host(struct Curl_easy *data,
failf(data, "schannel: server certificate name verification failed");
cleanup:
- Curl_unicodefree(cert_hostname_buff);
+ curlx_unicodefree(cert_hostname_buff);
return result;
}
@@ -537,9 +537,13 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex)
const CERT_CHAIN_CONTEXT *pChainContext = NULL;
HCERTCHAINENGINE cert_chain_engine = NULL;
HCERTSTORE trust_store = NULL;
+#ifndef CURL_DISABLE_PROXY
const char * const conn_hostname = SSL_IS_PROXY() ?
conn->http_proxy.host.name :
conn->host.name;
+#else
+ const char * const conn_hostname = conn->host.name;
+#endif
sspi_status =
s_pSecFn->QueryContextAttributes(&BACKEND->ctxt->ctxt_handle,
@@ -585,7 +589,7 @@ CURLcode Curl_verify_certificate(struct connectdata *conn, int sockindex)
}
if(result == CURLE_OK) {
- CERT_CHAIN_ENGINE_CONFIG_WIN7 engine_config;
+ struct cert_chain_engine_config_win7 engine_config;
BOOL create_engine_result;
memset(&engine_config, 0, sizeof(engine_config));
diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c
index 6b2d436f..2627aff1 100644
--- a/lib/vtls/sectransp.c
+++ b/lib/vtls/sectransp.c
@@ -1126,12 +1126,12 @@ static OSStatus CopyIdentityWithLabel(char *label,
}
static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
+ const struct curl_blob *blob,
const char *cPassword,
SecIdentityRef *out_cert_and_key)
{
OSStatus status = errSecItemNotFound;
- CFURLRef pkcs_url = CFURLCreateFromFileSystemRepresentation(NULL,
- (const UInt8 *)cPath, strlen(cPath), false);
+ CFURLRef pkcs_url = NULL;
CFStringRef password = cPassword ? CFStringCreateWithCString(NULL,
cPassword, kCFStringEncodingUTF8) : NULL;
CFDataRef pkcs_data = NULL;
@@ -1140,8 +1140,26 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
/* These constants are documented as having first appeared in 10.6 but they
raise linker errors when used on that cat for some reason. */
#if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
- if(CFURLCreateDataAndPropertiesFromResource(NULL, pkcs_url, &pkcs_data,
- NULL, NULL, &status)) {
+ bool resource_imported;
+
+ if(blob) {
+ pkcs_data = CFDataCreate(kCFAllocatorDefault,
+ (const unsigned char *)blob->data, blob->len);
+ status = (pkcs_data != NULL) ? errSecSuccess : errSecAllocate;
+ resource_imported = (pkcs_data != NULL);
+ }
+ else {
+ pkcs_url =
+ CFURLCreateFromFileSystemRepresentation(NULL,
+ (const UInt8 *)cPath,
+ strlen(cPath), false);
+ resource_imported =
+ CFURLCreateDataAndPropertiesFromResource(NULL,
+ pkcs_url, &pkcs_data,
+ NULL, NULL, &status);
+ }
+
+ if(resource_imported) {
CFArrayRef items = NULL;
/* On iOS SecPKCS12Import will never add the client certificate to the
@@ -1219,7 +1237,8 @@ static OSStatus CopyIdentityFromPKCS12File(const char *cPath,
#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
if(password)
CFRelease(password);
- CFRelease(pkcs_url);
+ if(pkcs_url)
+ CFRelease(pkcs_url);
return status;
}
@@ -1376,8 +1395,10 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
const char * const ssl_cafile = SSL_CONN_CONFIG(CAfile);
+ const struct curl_blob *ssl_cablob = NULL;
const bool verifypeer = SSL_CONN_CONFIG(verifypeer);
char * const ssl_cert = SSL_SET_OPTION(cert);
+ const struct curl_blob *ssl_cert_blob = SSL_SET_OPTION(cert_blob);
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
const long int port = SSL_IS_PROXY() ? conn->port : conn->remote_port;
@@ -1612,15 +1633,16 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
"Transport. The private key must be in the Keychain.\n");
}
- if(ssl_cert) {
+ if(ssl_cert || ssl_cert_blob) {
+ bool is_cert_data = ssl_cert_blob != NULL;
+ bool is_cert_file = (!is_cert_data) && is_file(ssl_cert);
SecIdentityRef cert_and_key = NULL;
- bool is_cert_file = is_file(ssl_cert);
/* User wants to authenticate with a client cert. Look for it:
If we detect that this is a file on disk, then let's load it.
Otherwise, assume that the user wants to use an identity loaded
from the Keychain. */
- if(is_cert_file) {
+ if(is_cert_file || is_cert_data) {
if(!SSL_SET_OPTION(cert_type))
infof(data, "WARNING: SSL: Certificate type not set, assuming "
"PKCS#12 format.\n");
@@ -1629,7 +1651,7 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
infof(data, "WARNING: SSL: The Security framework only supports "
"loading identities that are in PKCS#12 format.\n");
- err = CopyIdentityFromPKCS12File(ssl_cert,
+ err = CopyIdentityFromPKCS12File(ssl_cert, ssl_cert_blob,
SSL_SET_OPTION(key_passwd), &cert_and_key);
}
else
@@ -1669,27 +1691,30 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
CFRelease(cert_and_key);
}
else {
+ const char *cert_showfilename_error =
+ is_cert_data ? "(memory blob)" : ssl_cert;
+
switch(err) {
case errSecAuthFailed: case -25264: /* errSecPkcs12VerifyFailure */
failf(data, "SSL: Incorrect password for the certificate \"%s\" "
- "and its private key.", ssl_cert);
+ "and its private key.", cert_showfilename_error);
break;
case -26275: /* errSecDecode */ case -25257: /* errSecUnknownFormat */
failf(data, "SSL: Couldn't make sense of the data in the "
"certificate \"%s\" and its private key.",
- ssl_cert);
+ cert_showfilename_error);
break;
case -25260: /* errSecPassphraseRequired */
failf(data, "SSL The certificate \"%s\" requires a password.",
- ssl_cert);
+ cert_showfilename_error);
break;
case errSecItemNotFound:
failf(data, "SSL: Can't find the certificate \"%s\" and its private "
- "key in the Keychain.", ssl_cert);
+ "key in the Keychain.", cert_showfilename_error);
break;
default:
failf(data, "SSL: Can't load the certificate \"%s\" and its private "
- "key: OSStatus %d", ssl_cert, err);
+ "key: OSStatus %d", cert_showfilename_error, err);
break;
}
return CURLE_SSL_CERTPROBLEM;
@@ -1721,7 +1746,8 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
#else
if(SSLSetSessionOption != NULL) {
#endif /* CURL_BUILD_MAC */
- bool break_on_auth = !conn->ssl_config.verifypeer || ssl_cafile;
+ bool break_on_auth = !conn->ssl_config.verifypeer ||
+ ssl_cafile || ssl_cablob;
err = SSLSetSessionOption(backend->ssl_ctx,
kSSLSessionOptionBreakOnServerAuth,
break_on_auth);
@@ -1749,10 +1775,11 @@ static CURLcode sectransp_connect_step1(struct connectdata *conn,
}
#endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */
- if(ssl_cafile && verifypeer) {
- bool is_cert_file = is_file(ssl_cafile);
+ if((ssl_cafile || ssl_cablob) && verifypeer) {
+ bool is_cert_data = ssl_cablob != NULL;
+ bool is_cert_file = (!is_cert_data) && is_file(ssl_cafile);
- if(!is_cert_file) {
+ if(!(is_cert_file || is_cert_data)) {
failf(data, "SSL: can't load CA certificate file %s", ssl_cafile);
return CURLE_SSL_CACERT_BADFILE;
}
@@ -2809,7 +2836,6 @@ sectransp_connect_common(struct connectdata *conn,
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
- timediff_t timeout_ms;
int what;
/* check if the connection has already been established */
@@ -2820,7 +2846,7 @@ sectransp_connect_common(struct connectdata *conn,
if(ssl_connect_1 == connssl->connecting_state) {
/* Find out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
/* no need to continue if time already is up */
@@ -2838,7 +2864,7 @@ sectransp_connect_common(struct connectdata *conn,
ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
/* no need to continue if time already is up */
@@ -2856,7 +2882,7 @@ sectransp_connect_common(struct connectdata *conn,
connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
what = Curl_socket_check(readfd, CURL_SOCKET_BAD, writefd,
- nonblocking?0:(time_t)timeout_ms);
+ nonblocking ? 0 : timeout_ms);
if(what < 0) {
/* fatal error */
failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c
index f1b52522..c3a55fb1 100644
--- a/lib/vtls/vtls.c
+++ b/lib/vtls/vtls.c
@@ -63,6 +63,7 @@
#include "warnless.h"
#include "curl_base64.h"
#include "curl_printf.h"
+#include "strdup.h"
/* The last #include files should be: */
#include "curl_memory.h"
@@ -82,15 +83,54 @@
else \
dest->var = NULL;
+#define CLONE_BLOB(var) \
+ if(blobdup(&dest->var, source->var)) \
+ return FALSE;
+
+static CURLcode blobdup(struct curl_blob **dest,
+ struct curl_blob *src)
+{
+ DEBUGASSERT(dest);
+ DEBUGASSERT(!*dest);
+ if(src) {
+ /* only if there's data to dupe! */
+ struct curl_blob *d;
+ d = malloc(sizeof(struct curl_blob) + src->len);
+ if(!d)
+ return CURLE_OUT_OF_MEMORY;
+ d->len = src->len;
+ /* Always duplicate because the connection may survive longer than the
+ handle that passed in the blob. */
+ d->flags = CURL_BLOB_COPY;
+ d->data = (void *)((char *)d + sizeof(struct curl_blob));
+ memcpy(d->data, src->data, src->len);
+ *dest = d;
+ }
+ return CURLE_OK;
+}
+
+/* returns TRUE if the blobs are identical */
+static bool blobcmp(struct curl_blob *first, struct curl_blob *second)
+{
+ if(!first && !second) /* both are NULL */
+ return TRUE;
+ if(!first || !second) /* one is NULL */
+ return FALSE;
+ if(first->len != second->len) /* different sizes */
+ return FALSE;
+ return !memcmp(first->data, second->data, first->len); /* same data */
+}
+
bool
-Curl_ssl_config_matches(struct ssl_primary_config* data,
- struct ssl_primary_config* needle)
+Curl_ssl_config_matches(struct ssl_primary_config *data,
+ struct ssl_primary_config *needle)
{
if((data->version == needle->version) &&
(data->version_max == needle->version_max) &&
(data->verifypeer == needle->verifypeer) &&
(data->verifyhost == needle->verifyhost) &&
(data->verifystatus == needle->verifystatus) &&
+ blobcmp(data->cert_blob, needle->cert_blob) &&
Curl_safe_strcasecompare(data->CApath, needle->CApath) &&
Curl_safe_strcasecompare(data->CAfile, needle->CAfile) &&
Curl_safe_strcasecompare(data->clientcert, needle->clientcert) &&
@@ -115,6 +155,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
dest->verifystatus = source->verifystatus;
dest->sessionid = source->sessionid;
+ CLONE_BLOB(cert_blob);
CLONE_STRING(CApath);
CLONE_STRING(CAfile);
CLONE_STRING(clientcert);
@@ -127,7 +168,7 @@ Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
return TRUE;
}
-void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
+void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc)
{
Curl_safefree(sslc->CApath);
Curl_safefree(sslc->CAfile);
@@ -137,6 +178,7 @@ void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc)
Curl_safefree(sslc->cipher_list);
Curl_safefree(sslc->cipher_list13);
Curl_safefree(sslc->pinned_key);
+ Curl_safefree(sslc->cert_blob);
}
#ifdef USE_SSL
@@ -215,6 +257,7 @@ static bool ssl_prefs_check(struct Curl_easy *data)
return TRUE;
}
+#ifndef CURL_DISABLE_PROXY
static CURLcode
ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
{
@@ -238,17 +281,20 @@ ssl_connect_init_proxy(struct connectdata *conn, int sockindex)
}
return CURLE_OK;
}
+#endif
CURLcode
Curl_ssl_connect(struct connectdata *conn, int sockindex)
{
CURLcode result;
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy_ssl_connected[sockindex]) {
result = ssl_connect_init_proxy(conn, sockindex);
if(result)
return result;
}
+#endif
if(!ssl_prefs_check(conn->data))
return CURLE_SSL_CONNECT_ERROR;
@@ -270,12 +316,13 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
bool *done)
{
CURLcode result;
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.proxy_ssl_connected[sockindex]) {
result = ssl_connect_init_proxy(conn, sockindex);
if(result)
return result;
}
-
+#endif
if(!ssl_prefs_check(conn->data))
return CURLE_SSL_CONNECT_ERROR;
@@ -321,13 +368,21 @@ bool Curl_ssl_getsessionid(struct connectdata *conn,
long *general_age;
bool no_match = TRUE;
+#ifndef CURL_DISABLE_PROXY
const bool isProxy = CONNECT_PROXY_SSL();
struct ssl_primary_config * const ssl_config = isProxy ?
&conn->proxy_ssl_config :
&conn->ssl_config;
- const char * const name = isProxy ? conn->http_proxy.host.name :
- conn->host.name;
+ const char * const name = isProxy ?
+ conn->http_proxy.host.name : conn->host.name;
int port = isProxy ? (int)conn->port : conn->remote_port;
+#else
+ /* no proxy support */
+ struct ssl_primary_config * const ssl_config = &conn->ssl_config;
+ const char * const name = conn->host.name;
+ int port = conn->remote_port;
+ (void)sockindex;
+#endif
*ssl_sessionid = NULL;
DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
@@ -429,14 +484,23 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
char *clone_conn_to_host;
int conn_to_port;
long *general_age;
+#ifndef CURL_DISABLE_PROXY
const bool isProxy = CONNECT_PROXY_SSL();
struct ssl_primary_config * const ssl_config = isProxy ?
&conn->proxy_ssl_config :
&conn->ssl_config;
-
+ const char *hostname = isProxy ? conn->http_proxy.host.name :
+ conn->host.name;
+#else
+ /* proxy support disabled */
+ const bool isProxy = FALSE;
+ struct ssl_primary_config * const ssl_config = &conn->ssl_config;
+ const char *hostname = conn->host.name;
+ (void)sockindex;
+#endif
DEBUGASSERT(SSL_SET_OPTION(primary.sessionid));
- clone_host = strdup(isProxy ? conn->http_proxy.host.name : conn->host.name);
+ clone_host = strdup(hostname);
if(!clone_host)
return CURLE_OUT_OF_MEMORY; /* bail out */
@@ -684,7 +748,7 @@ CURLcode Curl_ssl_init_certinfo(struct Curl_easy *data, int num)
}
/*
- * 'value' is NOT a zero terminated string
+ * 'value' is NOT a null-terminated string
*/
CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
int certnum,
@@ -706,10 +770,10 @@ CURLcode Curl_ssl_push_certinfo_len(struct Curl_easy *data,
/* sprintf the label and colon */
msnprintf(output, outlen, "%s:", label);
- /* memcpy the value (it might not be zero terminated) */
+ /* memcpy the value (it might not be null-terminated) */
memcpy(&output[labellen + 1], value, valuelen);
- /* zero terminate the output */
+ /* null-terminate the output */
output[labellen + 1 + valuelen] = 0;
nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
@@ -1084,7 +1148,7 @@ bool Curl_none_false_start(void)
CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
unsigned char *md5sum, size_t md5len UNUSED_PARAM)
{
- MD5_context *MD5pw;
+ struct MD5_context *MD5pw;
(void)md5len;
diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h
index a81b2f22..bcc84441 100644
--- a/lib/vtls/vtls.h
+++ b/lib/vtls/vtls.h
@@ -113,12 +113,6 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
#define MAX_PINNED_PUBKEY_SIZE 1048576 /* 1MB */
#endif
-#ifndef MD5_DIGEST_LENGTH
-#ifndef LIBWOLFSSL_VERSION_HEX /* because WolfSSL borks this */
-#define MD5_DIGEST_LENGTH 16 /* fixed size */
-#endif
-#endif
-
#ifndef CURL_SHA256_DIGEST_LENGTH
#define CURL_SHA256_DIGEST_LENGTH 32 /* fixed size */
#endif
@@ -129,20 +123,27 @@ CURLcode Curl_none_md5sum(unsigned char *input, size_t inputlen,
/* set of helper macros for the backends to access the correct fields. For the
proxy or for the remote host - to properly support HTTPS proxy */
+#ifndef CURL_DISABLE_PROXY
+#define SSL_IS_PROXY() \
+ (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \
+ ssl_connection_complete != \
+ conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \
+ CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
+#define SSL_SET_OPTION(var) \
+ (SSL_IS_PROXY() ? data->set.proxy_ssl.var : data->set.ssl.var)
+#define SSL_CONN_CONFIG(var) \
+ (SSL_IS_PROXY() ? conn->proxy_ssl_config.var : conn->ssl_config.var)
+#else
+#define SSL_IS_PROXY() FALSE
+#define SSL_SET_OPTION(var) data->set.ssl.var
+#define SSL_CONN_CONFIG(var) conn->ssl_config.var
+#endif
-#define SSL_IS_PROXY() (CURLPROXY_HTTPS == conn->http_proxy.proxytype && \
- ssl_connection_complete != conn->proxy_ssl[conn->sock[SECONDARYSOCKET] == \
- CURL_SOCKET_BAD ? FIRSTSOCKET : SECONDARYSOCKET].state)
-#define SSL_SET_OPTION(var) (SSL_IS_PROXY() ? data->set.proxy_ssl.var : \
- data->set.ssl.var)
-#define SSL_CONN_CONFIG(var) (SSL_IS_PROXY() ? \
- conn->proxy_ssl_config.var : conn->ssl_config.var)
-
-bool Curl_ssl_config_matches(struct ssl_primary_config* data,
- struct ssl_primary_config* needle);
+bool Curl_ssl_config_matches(struct ssl_primary_config *data,
+ struct ssl_primary_config *needle);
bool Curl_clone_primary_ssl_config(struct ssl_primary_config *source,
struct ssl_primary_config *dest);
-void Curl_free_primary_ssl_config(struct ssl_primary_config* sslc);
+void Curl_free_primary_ssl_config(struct ssl_primary_config *sslc);
int Curl_ssl_getsock(struct connectdata *conn, curl_socket_t *socks);
int Curl_ssl_backend(void);
diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c
index 5040b059..7b2a124e 100644
--- a/lib/vtls/wolfssl.c
+++ b/lib/vtls/wolfssl.c
@@ -63,6 +63,7 @@
#include "sendf.h"
#include "inet_pton.h"
#include "vtls.h"
+#include "keylog.h"
#include "parsedate.h"
#include "connect.h" /* for the connect timeout */
#include "select.h"
@@ -99,6 +100,107 @@ struct ssl_backend_data {
static Curl_recv wolfssl_recv;
static Curl_send wolfssl_send;
+#ifdef OPENSSL_EXTRA
+/*
+ * Availability note:
+ * The TLS 1.3 secret callback (wolfSSL_set_tls13_secret_cb) was added in
+ * WolfSSL 4.4.0, but requires the -DHAVE_SECRET_CALLBACK build option. If that
+ * option is not set, then TLS 1.3 will not be logged.
+ * For TLS 1.2 and before, we use wolfSSL_get_keys().
+ * SSL_get_client_random and wolfSSL_get_keys require OPENSSL_EXTRA
+ * (--enable-opensslextra or --enable-all).
+ */
+#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
+static int
+wolfssl_tls13_secret_callback(SSL *ssl, int id, const unsigned char *secret,
+ int secretSz, void *ctx)
+{
+ const char *label;
+ unsigned char client_random[SSL3_RANDOM_SIZE];
+ (void)ctx;
+
+ if(!ssl || !Curl_tls_keylog_enabled()) {
+ return 0;
+ }
+
+ switch(id) {
+ case CLIENT_EARLY_TRAFFIC_SECRET:
+ label = "CLIENT_EARLY_TRAFFIC_SECRET";
+ break;
+ case CLIENT_HANDSHAKE_TRAFFIC_SECRET:
+ label = "CLIENT_HANDSHAKE_TRAFFIC_SECRET";
+ break;
+ case SERVER_HANDSHAKE_TRAFFIC_SECRET:
+ label = "SERVER_HANDSHAKE_TRAFFIC_SECRET";
+ break;
+ case CLIENT_TRAFFIC_SECRET:
+ label = "CLIENT_TRAFFIC_SECRET_0";
+ break;
+ case SERVER_TRAFFIC_SECRET:
+ label = "SERVER_TRAFFIC_SECRET_0";
+ break;
+ case EARLY_EXPORTER_SECRET:
+ label = "EARLY_EXPORTER_SECRET";
+ break;
+ case EXPORTER_SECRET:
+ label = "EXPORTER_SECRET";
+ break;
+ default:
+ return 0;
+ }
+
+ if(SSL_get_client_random(ssl, client_random, SSL3_RANDOM_SIZE) == 0) {
+ /* Should never happen as wolfSSL_KeepArrays() was called before. */
+ return 0;
+ }
+
+ Curl_tls_keylog_write(label, client_random, secret, secretSz);
+ return 0;
+}
+#endif /* defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13) */
+
+static void
+wolfssl_log_tls12_secret(SSL *ssl)
+{
+ unsigned char *ms, *sr, *cr;
+ unsigned int msLen, srLen, crLen, i, x = 0;
+
+#if LIBWOLFSSL_VERSION_HEX >= 0x0300d000 /* >= 3.13.0 */
+ /* wolfSSL_GetVersion is available since 3.13, we use it instead of
+ * SSL_version since the latter relies on OPENSSL_ALL (--enable-opensslall or
+ * --enable-all). Failing to perform this check could result in an unusable
+ * key log line when TLS 1.3 is actually negotiated. */
+ switch(wolfSSL_GetVersion(ssl)) {
+ case WOLFSSL_SSLV3:
+ case WOLFSSL_TLSV1:
+ case WOLFSSL_TLSV1_1:
+ case WOLFSSL_TLSV1_2:
+ break;
+ default:
+ /* TLS 1.3 does not use this mechanism, the "master secret" returned below
+ * is not directly usable. */
+ return;
+ }
+#endif
+
+ if(SSL_get_keys(ssl, &ms, &msLen, &sr, &srLen, &cr, &crLen) != SSL_SUCCESS) {
+ return;
+ }
+
+ /* Check for a missing master secret and skip logging. That can happen if
+ * curl rejects the server certificate and aborts the handshake.
+ */
+ for(i = 0; i < msLen; i++) {
+ x |= ms[i];
+ }
+ if(x == 0) {
+ return;
+ }
+
+ Curl_tls_keylog_write("CLIENT_RANDOM", cr, ms, msLen);
+}
+#endif /* OPENSSL_EXTRA */
+
static int do_file_type(const char *type)
{
if(!type || !type[0])
@@ -120,7 +222,7 @@ wolfssl_connect_step1(struct connectdata *conn,
{
char *ciphers;
struct Curl_easy *data = conn->data;
- struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
SSL_METHOD* req_method = NULL;
curl_socket_t sockfd = conn->sock[sockindex];
@@ -314,8 +416,12 @@ wolfssl_connect_step1(struct connectdata *conn,
#ifdef ENABLE_IPV6
struct in6_addr addr6;
#endif
+#ifndef CURL_DISABLE_PROXY
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
+#else
+ const char * const hostname = conn->host.name;
+#endif
size_t hostname_len = strlen(hostname);
if((hostname_len < USHRT_MAX) &&
(0 == Curl_inet_pton(AF_INET, hostname, &addr4)) &&
@@ -385,6 +491,17 @@ wolfssl_connect_step1(struct connectdata *conn,
}
#endif /* HAVE_ALPN */
+#ifdef OPENSSL_EXTRA
+ if(Curl_tls_keylog_enabled()) {
+ /* Ensure the Client Random is preserved. */
+ wolfSSL_KeepArrays(backend->handle);
+#if defined(HAVE_SECRET_CALLBACK) && defined(WOLFSSL_TLS13)
+ wolfSSL_set_tls13_secret_cb(backend->handle,
+ wolfssl_tls13_secret_callback, NULL);
+#endif
+ }
+#endif /* OPENSSL_EXTRA */
+
/* Check if there's a cached ID we can/should use here! */
if(SSL_SET_OPTION(primary.sessionid)) {
void *ssl_sessionid = NULL;
@@ -423,15 +540,22 @@ wolfssl_connect_step2(struct connectdata *conn,
{
int ret = -1;
struct Curl_easy *data = conn->data;
- struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
struct ssl_backend_data *backend = connssl->backend;
+#ifndef CURL_DISABLE_PROXY
const char * const hostname = SSL_IS_PROXY() ? conn->http_proxy.host.name :
conn->host.name;
const char * const dispname = SSL_IS_PROXY() ?
conn->http_proxy.host.dispname : conn->host.dispname;
const char * const pinnedpubkey = SSL_IS_PROXY() ?
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
- data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY] :
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+#else
+ const char * const hostname = conn->host.name;
+ const char * const dispname = conn->host.dispname;
+ const char * const pinnedpubkey =
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+#endif
conn->recv[sockindex] = wolfssl_recv;
conn->send[sockindex] = wolfssl_send;
@@ -444,6 +568,31 @@ wolfssl_connect_step2(struct connectdata *conn,
}
ret = SSL_connect(backend->handle);
+
+#ifdef OPENSSL_EXTRA
+ if(Curl_tls_keylog_enabled()) {
+ /* If key logging is enabled, wait for the handshake to complete and then
+ * proceed with logging secrets (for TLS 1.2 or older).
+ *
+ * During the handshake (ret==-1), wolfSSL_want_read() is true as it waits
+ * for the server response. At that point the master secret is not yet
+ * available, so we must not try to read it.
+ * To log the secret on completion with a handshake failure, detect
+ * completion via the observation that there is nothing to read or write.
+ * Note that OpenSSL SSL_want_read() is always true here. If wolfSSL ever
+ * changes, the worst case is that no key is logged on error.
+ */
+ if(ret == SSL_SUCCESS ||
+ (!wolfSSL_want_read(backend->handle) &&
+ !wolfSSL_want_write(backend->handle))) {
+ wolfssl_log_tls12_secret(backend->handle);
+ /* Client Random and master secrets are no longer needed, erase these.
+ * Ignored while the handshake is still in progress. */
+ wolfSSL_FreeArrays(backend->handle);
+ }
+ }
+#endif /* OPENSSL_EXTRA */
+
if(ret != 1) {
char error_buffer[WOLFSSL_MAX_ERROR_SZ];
int detail = SSL_get_error(backend->handle, ret);
@@ -511,8 +660,8 @@ wolfssl_connect_step2(struct connectdata *conn,
X509 *x509;
const char *x509_der;
int x509_der_len;
- curl_X509certificate x509_parsed;
- curl_asn1Element *pubkey;
+ struct Curl_X509certificate x509_parsed;
+ struct Curl_asn1Element *pubkey;
CURLcode result;
x509 = SSL_get_peer_certificate(backend->handle);
@@ -750,6 +899,9 @@ static size_t Curl_wolfssl_version(char *buffer, size_t size)
static int Curl_wolfssl_init(void)
{
+#ifdef OPENSSL_EXTRA
+ Curl_tls_keylog_open();
+#endif
return (wolfSSL_Init() == SSL_SUCCESS);
}
@@ -757,10 +909,13 @@ static int Curl_wolfssl_init(void)
static void Curl_wolfssl_cleanup(void)
{
wolfSSL_Cleanup();
+#ifdef OPENSSL_EXTRA
+ Curl_tls_keylog_close();
+#endif
}
-static bool Curl_wolfssl_data_pending(const struct connectdata* conn,
+static bool Curl_wolfssl_data_pending(const struct connectdata *conn,
int connindex)
{
const struct ssl_connect_data *connssl = &conn->ssl[connindex];
@@ -800,7 +955,6 @@ wolfssl_connect_common(struct connectdata *conn,
struct Curl_easy *data = conn->data;
struct ssl_connect_data *connssl = &conn->ssl[sockindex];
curl_socket_t sockfd = conn->sock[sockindex];
- time_t timeout_ms;
int what;
/* check if the connection has already been established */
@@ -811,7 +965,7 @@ wolfssl_connect_common(struct connectdata *conn,
if(ssl_connect_1 == connssl->connecting_state) {
/* Find out how much more time we're allowed */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
/* no need to continue if time already is up */
@@ -829,7 +983,7 @@ wolfssl_connect_common(struct connectdata *conn,
ssl_connect_2_writing == connssl->connecting_state) {
/* check allowed time left */
- timeout_ms = Curl_timeleft(data, NULL, TRUE);
+ const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
if(timeout_ms < 0) {
/* no need to continue if time already is up */
diff --git a/lib/x509asn1.c b/lib/x509asn1.c
index ece5364d..52747d57 100644
--- a/lib/x509asn1.c
+++ b/lib/x509asn1.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -44,7 +44,7 @@
static const char cnOID[] = "2.5.4.3"; /* Common name. */
static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */
-static const curl_OID OIDtable[] = {
+static const struct Curl_OID OIDtable[] = {
{ "1.2.840.10040.4.1", "dsa" },
{ "1.2.840.10040.4.3", "dsa-with-sha1" },
{ "1.2.840.10045.2.1", "ecPublicKey" },
@@ -103,16 +103,16 @@ static const curl_OID OIDtable[] = {
* Please note there is no pretention here to rewrite a full SSL library.
*/
-static const char *getASN1Element(curl_asn1Element *elem,
+static const char *getASN1Element(struct Curl_asn1Element *elem,
const char *beg, const char *end)
WARN_UNUSED_RESULT;
-static const char *getASN1Element(curl_asn1Element *elem,
+static const char *getASN1Element(struct Curl_asn1Element *elem,
const char *beg, const char *end)
{
unsigned char b;
unsigned long len;
- curl_asn1Element lelem;
+ struct Curl_asn1Element lelem;
/* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
ending at `end'.
@@ -176,9 +176,9 @@ static const char *getASN1Element(curl_asn1Element *elem,
* Search the null terminated OID or OID identifier in local table.
* Return the table entry pointer or NULL if not found.
*/
-static const curl_OID * searchOID(const char *oid)
+static const struct Curl_OID *searchOID(const char *oid)
{
- const curl_OID *op;
+ const struct Curl_OID *op;
for(op = OIDtable; op->numoid; op++)
if(!strcmp(op->numoid, oid) || strcasecompare(op->textoid, oid))
return op;
@@ -445,7 +445,7 @@ static const char *OID2str(const char *beg, const char *end, bool symbolic)
buf[buflen] = '\0';
if(symbolic) {
- const curl_OID *op = searchOID(buf);
+ const struct Curl_OID *op = searchOID(buf);
if(op) {
free(buf);
buf = strdup(op->textoid);
@@ -565,7 +565,7 @@ static const char *UTime2str(const char *beg, const char *end)
* Convert an ASN.1 element to a printable string.
* Return the dynamically allocated string, or NULL if an error occurs.
*/
-static const char *ASN1tostr(curl_asn1Element *elem, int type)
+static const char *ASN1tostr(struct Curl_asn1Element *elem, int type)
{
if(elem->constructed)
return NULL; /* No conversion of structured elements. */
@@ -609,12 +609,12 @@ static const char *ASN1tostr(curl_asn1Element *elem, int type)
* ASCII encode distinguished name at `dn' into the `buflen'-sized buffer at
* `buf'. Return the total string length, even if larger than `buflen'.
*/
-static ssize_t encodeDN(char *buf, size_t buflen, curl_asn1Element *dn)
+static ssize_t encodeDN(char *buf, size_t buflen, struct Curl_asn1Element *dn)
{
- curl_asn1Element rdn;
- curl_asn1Element atv;
- curl_asn1Element oid;
- curl_asn1Element value;
+ struct Curl_asn1Element rdn;
+ struct Curl_asn1Element atv;
+ struct Curl_asn1Element oid;
+ struct Curl_asn1Element value;
size_t l = 0;
const char *p1;
const char *p2;
@@ -683,7 +683,7 @@ static ssize_t encodeDN(char *buf, size_t buflen, curl_asn1Element *dn)
* Convert an ASN.1 distinguished name into a printable string.
* Return the dynamically allocated string, or NULL if an error occurs.
*/
-static const char *DNtostr(curl_asn1Element *dn)
+static const char *DNtostr(struct Curl_asn1Element *dn)
{
char *buf = NULL;
ssize_t buflen = encodeDN(NULL, 0, dn);
@@ -703,11 +703,11 @@ static const char *DNtostr(curl_asn1Element *dn)
* Syntax is assumed to have already been checked by the SSL backend.
* See RFC 5280.
*/
-int Curl_parseX509(curl_X509certificate *cert,
+int Curl_parseX509(struct Curl_X509certificate *cert,
const char *beg, const char *end)
{
- curl_asn1Element elem;
- curl_asn1Element tbsCertificate;
+ struct Curl_asn1Element elem;
+ struct Curl_asn1Element tbsCertificate;
const char *ccp;
static const char defaultVersion = 0; /* v1. */
@@ -835,10 +835,10 @@ static size_t copySubstring(char *to, const char *from)
return i;
}
-static const char *dumpAlgo(curl_asn1Element *param,
+static const char *dumpAlgo(struct Curl_asn1Element *param,
const char *beg, const char *end)
{
- curl_asn1Element oid;
+ struct Curl_asn1Element oid;
/* Get algorithm parameters and return algorithm name. */
@@ -855,7 +855,7 @@ static const char *dumpAlgo(curl_asn1Element *param,
}
static void do_pubkey_field(struct Curl_easy *data, int certnum,
- const char *label, curl_asn1Element *elem)
+ const char *label, struct Curl_asn1Element *elem)
{
const char *output;
@@ -872,11 +872,11 @@ static void do_pubkey_field(struct Curl_easy *data, int certnum,
}
static void do_pubkey(struct Curl_easy *data, int certnum,
- const char *algo, curl_asn1Element *param,
- curl_asn1Element *pubkey)
+ const char *algo, struct Curl_asn1Element *param,
+ struct Curl_asn1Element *pubkey)
{
- curl_asn1Element elem;
- curl_asn1Element pk;
+ struct Curl_asn1Element elem;
+ struct Curl_asn1Element pk;
const char *p;
/* Generate all information records for the public key. */
@@ -950,9 +950,9 @@ CURLcode Curl_extract_certinfo(struct connectdata *conn,
const char *beg,
const char *end)
{
- curl_X509certificate cert;
+ struct Curl_X509certificate cert;
struct Curl_easy *data = conn->data;
- curl_asn1Element param;
+ struct Curl_asn1Element param;
const char *ccp;
char *cp1;
size_t cl1;
@@ -1111,7 +1111,7 @@ CURLcode Curl_extract_certinfo(struct connectdata *conn,
static const char *checkOID(const char *beg, const char *end,
const char *oid)
{
- curl_asn1Element e;
+ struct Curl_asn1Element e;
const char *ccp;
const char *p;
bool matched;
@@ -1136,22 +1136,21 @@ CURLcode Curl_verifyhost(struct connectdata *conn,
const char *beg, const char *end)
{
struct Curl_easy *data = conn->data;
- curl_X509certificate cert;
- curl_asn1Element dn;
- curl_asn1Element elem;
- curl_asn1Element ext;
- curl_asn1Element name;
+ struct Curl_X509certificate cert;
+ struct Curl_asn1Element dn;
+ struct Curl_asn1Element elem;
+ struct Curl_asn1Element ext;
+ struct Curl_asn1Element name;
const char *p;
const char *q;
char *dnsname;
int matched = -1;
size_t addrlen = (size_t) -1;
ssize_t len;
- const char * const hostname = SSL_IS_PROXY()? conn->http_proxy.host.name:
- conn->host.name;
- const char * const dispname = SSL_IS_PROXY()?
- conn->http_proxy.host.dispname:
- conn->host.dispname;
+ const char *const hostname = SSL_IS_PROXY()?
+ conn->http_proxy.host.name : conn->host.name;
+ const char *const dispname = SSL_IS_PROXY()?
+ conn->http_proxy.host.dispname : conn->host.dispname;
#ifdef ENABLE_IPV6
struct in6_addr addr;
#else
diff --git a/lib/x509asn1.h b/lib/x509asn1.h
index 205fdc0d..0b7fb881 100644
--- a/lib/x509asn1.h
+++ b/lib/x509asn1.h
@@ -8,7 +8,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -79,52 +79,51 @@
*/
/* ASN.1 parsed element. */
-typedef struct {
- const char * header; /* Pointer to header byte. */
- const char * beg; /* Pointer to element data. */
- const char * end; /* Pointer to 1st byte after element. */
- unsigned char class; /* ASN.1 element class. */
- unsigned char tag; /* ASN.1 element tag. */
- bool constructed; /* Element is constructed. */
-} curl_asn1Element;
+struct Curl_asn1Element {
+ const char *header; /* Pointer to header byte. */
+ const char *beg; /* Pointer to element data. */
+ const char *end; /* Pointer to 1st byte after element. */
+ unsigned char class; /* ASN.1 element class. */
+ unsigned char tag; /* ASN.1 element tag. */
+ bool constructed; /* Element is constructed. */
+};
/* ASN.1 OID table entry. */
-typedef struct {
- const char * numoid; /* Dotted-numeric OID. */
- const char * textoid; /* OID name. */
-} curl_OID;
+struct Curl_OID {
+ const char *numoid; /* Dotted-numeric OID. */
+ const char *textoid; /* OID name. */
+};
/* X509 certificate: RFC 5280. */
-typedef struct {
- curl_asn1Element certificate;
- curl_asn1Element version;
- curl_asn1Element serialNumber;
- curl_asn1Element signatureAlgorithm;
- curl_asn1Element signature;
- curl_asn1Element issuer;
- curl_asn1Element notBefore;
- curl_asn1Element notAfter;
- curl_asn1Element subject;
- curl_asn1Element subjectPublicKeyInfo;
- curl_asn1Element subjectPublicKeyAlgorithm;
- curl_asn1Element subjectPublicKey;
- curl_asn1Element issuerUniqueID;
- curl_asn1Element subjectUniqueID;
- curl_asn1Element extensions;
-} curl_X509certificate;
-
+struct Curl_X509certificate {
+ struct Curl_asn1Element certificate;
+ struct Curl_asn1Element version;
+ struct Curl_asn1Element serialNumber;
+ struct Curl_asn1Element signatureAlgorithm;
+ struct Curl_asn1Element signature;
+ struct Curl_asn1Element issuer;
+ struct Curl_asn1Element notBefore;
+ struct Curl_asn1Element notAfter;
+ struct Curl_asn1Element subject;
+ struct Curl_asn1Element subjectPublicKeyInfo;
+ struct Curl_asn1Element subjectPublicKeyAlgorithm;
+ struct Curl_asn1Element subjectPublicKey;
+ struct Curl_asn1Element issuerUniqueID;
+ struct Curl_asn1Element subjectUniqueID;
+ struct Curl_asn1Element extensions;
+};
/*
* Prototypes.
*/
-const char *Curl_getASN1Element(curl_asn1Element *elem,
- const char *beg, const char *end);
-const char *Curl_ASN1tostr(curl_asn1Element *elem, int type);
-const char *Curl_DNtostr(curl_asn1Element *dn);
-int Curl_parseX509(curl_X509certificate *cert,
+const char *Curl_getASN1Element(struct Curl_asn1Element *elem,
+ const char *beg, const char *end);
+const char *Curl_ASN1tostr(struct Curl_asn1Element *elem, int type);
+const char *Curl_DNtostr(struct Curl_asn1Element *dn);
+int Curl_parseX509(struct Curl_X509certificate *cert,
const char *beg, const char *end);
CURLcode Curl_extract_certinfo(struct connectdata *conn, int certnum,
const char *beg, const char *end);