summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorng0 <ng0@n0.is>2019-02-25 11:15:00 +0000
committerng0 <ng0@n0.is>2019-02-25 11:15:00 +0000
commit2a251478463006d1deacf1610987d75054ba4fb8 (patch)
tree41bfad1ee4f0d2cee35c88d7de02ce0356307379 /lib
parent810ed5cbb8e14bd8c1f9bfed76b3811a1cdd0207 (diff)
parentf3294d9d86e6a7915a967efff2842089b8b0d071 (diff)
downloadgnurl-2a251478463006d1deacf1610987d75054ba4fb8.tar.gz
gnurl-2a251478463006d1deacf1610987d75054ba4fb8.tar.bz2
gnurl-2a251478463006d1deacf1610987d75054ba4fb8.zip
Merge tag 'curl-7_64_0'
curl 7.64.0
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile.am9
-rw-r--r--lib/asyn-ares.c19
-rw-r--r--lib/asyn-thread.c25
-rw-r--r--lib/asyn.h27
-rw-r--r--lib/conncache.c18
-rw-r--r--lib/conncache.h5
-rw-r--r--lib/cookie.c72
-rw-r--r--lib/cookie.h5
-rw-r--r--lib/curl_sasl.c7
-rw-r--r--lib/doh.c4
-rw-r--r--lib/easy.c4
-rw-r--r--lib/ftp.c6
-rw-r--r--lib/getinfo.c4
-rw-r--r--lib/gopher.c18
-rw-r--r--lib/hostip.c30
-rw-r--r--lib/http.c64
-rw-r--r--lib/http.h3
-rw-r--r--lib/http2.c10
-rw-r--r--lib/http_negotiate.c15
-rw-r--r--lib/http_ntlm.c3
-rw-r--r--lib/http_proxy.c4
-rw-r--r--lib/if2ip.c34
-rw-r--r--lib/if2ip.h4
-rw-r--r--lib/imap.c15
-rw-r--r--lib/multi.c545
-rw-r--r--lib/multiif.h6
-rwxr-xr-xlib/objnames-test08.sh217
-rwxr-xr-xlib/objnames-test10.sh217
-rw-r--r--lib/objnames.inc107
-rw-r--r--lib/pingpong.c9
-rw-r--r--lib/pingpong.h7
-rw-r--r--lib/pop3.c15
-rw-r--r--lib/setopt.c45
-rw-r--r--lib/sigpipe.h5
-rw-r--r--lib/smb.c9
-rw-r--r--lib/smtp.c19
-rw-r--r--lib/ssh-libssh.c22
-rw-r--r--lib/ssh.c5
-rw-r--r--lib/timeval.c52
-rw-r--r--lib/timeval.h4
-rw-r--r--lib/transfer.c184
-rw-r--r--lib/url.c55
-rw-r--r--lib/url.h5
-rw-r--r--lib/urlapi.c45
-rw-r--r--lib/urldata.h41
-rw-r--r--lib/vauth/digest_sspi.c4
-rw-r--r--lib/vauth/ntlm.c26
-rw-r--r--lib/vauth/ntlm_sspi.c43
-rw-r--r--lib/vauth/spnego_sspi.c45
-rw-r--r--lib/vtls/cyassl.c8
-rw-r--r--lib/vtls/darwinssl.c3
-rw-r--r--lib/vtls/mbedtls.c16
-rw-r--r--lib/vtls/openssl.c16
-rw-r--r--lib/vtls/schannel.c62
-rw-r--r--lib/vtls/schannel_verify.c6
55 files changed, 1102 insertions, 1146 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am
index d4fca4d47..8905e7107 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
-# Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+# Copyright (C) 1998 - 2019, 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
@@ -29,8 +29,7 @@ EXTRA_DIST = Makefile.m32 config-win32.h \
makefile.amiga Makefile.netware nwlib.c nwos.c config-win32ce.h \
config-os400.h setup-os400.h config-symbian.h Makefile.Watcom \
config-tpf.h mk-ca-bundle.pl mk-ca-bundle.vbs $(CMAKE_DIST) \
- firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl \
- objnames-test08.sh objnames-test10.sh objnames.inc
+ firefox-db2pem.sh config-vxworks.h Makefile.vxworks checksrc.pl
lib_LTLIBRARIES = libgnurl.la
@@ -88,10 +87,6 @@ libgnurl_la_CPPFLAGS_EXTRA =
libgnurl_la_LDFLAGS_EXTRA =
libgnurl_la_CFLAGS_EXTRA =
-@CODE_COVERAGE_RULES@
-libgnurl_la_LDFLAGS_EXTRA += $(CODE_COVERAGE_LDFLAGS)
-libgnurl_la_CFLAGS_EXTRA += $(CODE_COVERAGE_CFLAGS)
-
if CURL_LT_SHLIB_USE_VERSION_INFO
libgnurl_la_LDFLAGS_EXTRA += $(VERSIONINFO)
endif
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c
index 6a49566c8..04a25b321 100644
--- a/lib/asyn-ares.c
+++ b/lib/asyn-ares.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -199,6 +199,17 @@ void Curl_resolver_cancel(struct connectdata *conn)
}
/*
+ * We're equivalent to Curl_resolver_cancel() for the c-ares resolver. We
+ * never block.
+ */
+void Curl_resolver_kill(struct connectdata *conn)
+{
+ /* We don't need to check the resolver state because we can be called safely
+ at any time and we always do the same thing. */
+ Curl_resolver_cancel(conn);
+}
+
+/*
* destroy_async_data() cleans up async resolver data.
*/
static void destroy_async_data(struct Curl_async *async)
@@ -361,13 +372,13 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
/*
* Curl_resolver_wait_resolv()
*
- * waits for a resolve to finish. This function should be avoided since using
+ * 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
*
- * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
- * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
*/
CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
struct Curl_dns_entry **entry)
diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c
index 74208d7ec..a9679d062 100644
--- a/lib/asyn-thread.c
+++ b/lib/asyn-thread.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -462,13 +462,33 @@ static CURLcode resolver_error(struct connectdata *conn)
}
/*
+ * Until we gain a way to signal the resolver threads to stop early, we must
+ * simply wait for them and ignore their results.
+ */
+void Curl_resolver_kill(struct connectdata *conn)
+{
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+
+ /* If we're still resolving, we must wait for the threads to fully clean up,
+ unfortunately. Otherwise, we can simply cancel to clean up any resolver
+ data. */
+ if(td && td->thread_hnd != curl_thread_t_null)
+ (void)Curl_resolver_wait_resolv(conn, NULL);
+ else
+ Curl_resolver_cancel(conn);
+}
+
+/*
* Curl_resolver_wait_resolv()
*
- * waits for a resolve to finish. This function should be avoided since using
+ * 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
*
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
+ *
* This is the version for resolves-in-a-thread.
*/
CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
@@ -478,6 +498,7 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
CURLcode result = CURLE_OK;
DEBUGASSERT(conn && td);
+ DEBUGASSERT(td->thread_hnd != curl_thread_t_null);
/* wait for the thread to resolve the name */
if(Curl_thread_join(&td->thread_hnd)) {
diff --git a/lib/asyn.h b/lib/asyn.h
index 43625bc3b..ccd4b1f7e 100644
--- a/lib/asyn.h
+++ b/lib/asyn.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -87,10 +87,25 @@ CURLcode Curl_resolver_duphandle(struct Curl_easy *easy, void **to,
*
* It is called from inside other functions to cancel currently performing
* resolver request. Should also free any temporary resources allocated to
- * perform a request.
+ * perform a request. This never waits for resolver threads to complete.
+ *
+ * It is safe to call this when conn is in any state.
*/
void Curl_resolver_cancel(struct connectdata *conn);
+/*
+ * Curl_resolver_kill().
+ *
+ * This acts like Curl_resolver_cancel() except it will block until any threads
+ * associated with the resolver are complete. This never blocks for resolvers
+ * that do not use threads. This is intended to be the "last chance" function
+ * that cleans up an in-progress resolver completely (before its owner is about
+ * to die).
+ *
+ * It is safe to call this when conn is in any state.
+ */
+void Curl_resolver_kill(struct connectdata *conn);
+
/* Curl_resolver_getsock()
*
* This function is called from the multi_getsock() function. 'sock' is a
@@ -117,14 +132,13 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
/*
* Curl_resolver_wait_resolv()
*
- * waits for a resolve to finish. This function should be avoided since using
+ * 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
*
- * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
- * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
-
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved,
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred, or other errors.
*/
CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
struct Curl_dns_entry **dnsentry);
@@ -148,6 +162,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
#ifndef CURLRES_ASYNCH
/* convert these functions if an asynch resolver isn't used */
#define Curl_resolver_cancel(x) Curl_nop_stmt
+#define Curl_resolver_kill(x) Curl_nop_stmt
#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
#define Curl_resolver_getsock(x,y,z) 0
diff --git a/lib/conncache.c b/lib/conncache.c
index 737e396e9..463c57a3d 100644
--- a/lib/conncache.c
+++ b/lib/conncache.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2012 - 2016, Linus Nielsen Feltzing, <linus@haxx.se>
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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,9 +178,9 @@ static void hashkey(struct connectdata *conn, char *buf,
msnprintf(buf, len, "%ld%s", conn->port, hostname);
}
-void Curl_conncache_unlock(struct connectdata *conn)
+void Curl_conncache_unlock(struct Curl_easy *data)
{
- CONN_UNLOCK(conn->data);
+ CONN_UNLOCK(data);
}
/* Returns number of connections currently held in the connection cache.
@@ -302,9 +302,14 @@ CURLcode Curl_conncache_add_conn(struct conncache *connc,
return result;
}
-void Curl_conncache_remove_conn(struct connectdata *conn, bool lock)
+/*
+ * 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.
+ */
+void Curl_conncache_remove_conn(struct Curl_easy *data,
+ struct connectdata *conn, bool lock)
{
- struct Curl_easy *data = conn->data;
struct connectbundle *bundle = conn->bundle;
struct conncache *connc = data->state.conn_cache;
@@ -323,6 +328,7 @@ void Curl_conncache_remove_conn(struct connectdata *conn, bool lock)
DEBUGF(infof(data, "The cache now contains %zu members\n",
connc->num_conn));
}
+ conn->data = NULL; /* clear the association */
if(lock) {
CONN_UNLOCK(data);
}
@@ -566,8 +572,6 @@ void Curl_conncache_close_all_connections(struct conncache *connc)
conn->data = connc->closure_handle;
sigpipe_ignore(conn->data, &pipe_st);
- conn->data->easy_conn = NULL; /* clear the easy handle's connection
- pointer */
/* This will remove the connection from the cache */
connclose(conn, "kill all");
(void)Curl_disconnect(connc->closure_handle, conn, FALSE);
diff --git a/lib/conncache.h b/lib/conncache.h
index eedd7a800..0df6d4715 100644
--- a/lib/conncache.h
+++ b/lib/conncache.h
@@ -56,7 +56,7 @@ void Curl_conncache_destroy(struct conncache *connc);
/* return the correct bundle, to a host or a proxy */
struct connectbundle *Curl_conncache_find_bundle(struct connectdata *conn,
struct conncache *connc);
-void Curl_conncache_unlock(struct connectdata *conn);
+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);
size_t Curl_conncache_bundle_size(struct connectdata *conn);
@@ -64,7 +64,8 @@ size_t Curl_conncache_bundle_size(struct connectdata *conn);
bool Curl_conncache_return_conn(struct connectdata *conn);
CURLcode Curl_conncache_add_conn(struct conncache *connc,
struct connectdata *conn) WARN_UNUSED_RESULT;
-void Curl_conncache_remove_conn(struct connectdata *conn,
+void Curl_conncache_remove_conn(struct Curl_easy *data,
+ struct connectdata *conn,
bool lock);
bool Curl_conncache_foreach(struct Curl_easy *data,
struct conncache *connc,
diff --git a/lib/cookie.c b/lib/cookie.c
index 3dc85ee5c..4fb992ac9 100644
--- a/lib/cookie.c
+++ b/lib/cookie.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -223,7 +223,7 @@ static bool pathmatch(const char *cookie_path, const char *request_uri)
goto pathmatched;
}
- /* here, cookie_path_len < url_path_len */
+ /* here, cookie_path_len < uri_path_len */
if(uri_path[cookie_path_len] == '/') {
ret = TRUE;
goto pathmatched;
@@ -433,9 +433,10 @@ Curl_cookie_add(struct Curl_easy *data,
bool noexpire, /* if TRUE, skip remove_expired() */
char *lineptr, /* first character of the line */
const char *domain, /* default domain */
- const char *path) /* full path used when this cookie is set,
+ const char *path, /* full path used when this cookie is set,
used to get default path for the cookie
unless set */
+ bool secure) /* TRUE if connection is over secure origin */
{
struct Cookie *clist;
struct Cookie *co;
@@ -546,8 +547,20 @@ Curl_cookie_add(struct Curl_easy *data,
/* this was a "<name>=" with no content, and we must allow
'secure' and 'httponly' specified this weirdly */
done = TRUE;
- if(strcasecompare("secure", name))
- co->secure = TRUE;
+ /*
+ * secure cookies are only allowed to be set when the connection is
+ * using a secure protocol, or when the cookie is being set by
+ * reading from file
+ */
+ if(strcasecompare("secure", name)) {
+ if(secure || !c->running) {
+ co->secure = TRUE;
+ }
+ else {
+ badcookie = TRUE;
+ break;
+ }
+ }
else if(strcasecompare("httponly", name))
co->httponly = TRUE;
else if(sep)
@@ -790,6 +803,8 @@ Curl_cookie_add(struct Curl_easy *data,
co->domain = strdup(ptr);
if(!co->domain)
badcookie = TRUE;
+ else if(bad_domain(co->domain))
+ badcookie = TRUE;
break;
case 1:
/* This field got its explanation on the 23rd of May 2001 by
@@ -831,7 +846,13 @@ Curl_cookie_add(struct Curl_easy *data,
fields++; /* add a field and fall down to secure */
/* FALLTHROUGH */
case 3:
- co->secure = strcasecompare(ptr, "TRUE")?TRUE:FALSE;
+ co->secure = FALSE;
+ if(strcasecompare(ptr, "TRUE")) {
+ if(secure || c->running)
+ co->secure = TRUE;
+ else
+ badcookie = TRUE;
+ }
break;
case 4:
if(curlx_strtoofft(ptr, NULL, 10, &co->expires))
@@ -887,18 +908,20 @@ Curl_cookie_add(struct Curl_easy *data,
if(!noexpire)
remove_expired(c);
-#ifdef USE_LIBPSL
- /* Check if the domain is a Public Suffix and if yes, ignore the cookie. */
if(domain && co->domain && !isip(co->domain)) {
- const psl_ctx_t *psl = Curl_psl_use(data);
int acceptable;
+#ifdef USE_LIBPSL
+ const psl_ctx_t *psl = Curl_psl_use(data);
+ /* Check if the domain is a Public Suffix and if yes, ignore the cookie. */
if(psl) {
acceptable = psl_is_cookie_domain_acceptable(psl, domain, co->domain);
Curl_psl_release(data);
}
else
- acceptable = !bad_domain(domain);
+#endif
+ /* Without libpsl, do the best we can. */
+ acceptable = !bad_domain(co->domain);
if(!acceptable) {
infof(data, "cookie '%s' dropped, domain '%s' must not "
@@ -907,7 +930,6 @@ Curl_cookie_add(struct Curl_easy *data,
return NULL;
}
}
-#endif
myhash = cookiehash(co->domain);
clist = c->cookies[myhash];
@@ -929,9 +951,31 @@ Curl_cookie_add(struct Curl_easy *data,
/* the domains were identical */
if(clist->spath && co->spath) {
- if(strcasecompare(clist->spath, co->spath)) {
- replace_old = TRUE;
+ if(clist->secure && !co->secure && !secure) {
+ size_t cllen;
+ const char *sep;
+
+ /*
+ * A non-secure cookie may not overlay an existing secure cookie.
+ * For an existing cookie "a" with path "/login", refuse a new
+ * cookie "a" with for example path "/login/en", while the path
+ * "/loginhelper" is ok.
+ */
+
+ sep = strchr(clist->spath + 1, '/');
+
+ if(sep)
+ cllen = sep - clist->spath;
+ else
+ cllen = strlen(clist->spath);
+
+ if(strncasecompare(clist->spath, co->spath, cllen)) {
+ freecookie(co);
+ return NULL;
+ }
}
+ else if(strcasecompare(clist->spath, co->spath))
+ replace_old = TRUE;
else
replace_old = FALSE;
}
@@ -1103,7 +1147,7 @@ struct CookieInfo *Curl_cookie_init(struct Curl_easy *data,
while(*lineptr && ISBLANK(*lineptr))
lineptr++;
- Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL);
+ Curl_cookie_add(data, c, headerline, TRUE, lineptr, NULL, NULL, TRUE);
}
free(line); /* free the line buffer */
remove_expired(c); /* run this once, not on every cookie */
diff --git a/lib/cookie.h b/lib/cookie.h
index b2ec17a35..609c30b1e 100644
--- a/lib/cookie.h
+++ b/lib/cookie.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -85,7 +85,8 @@ struct Curl_easy;
struct Cookie *Curl_cookie_add(struct Curl_easy *data,
struct CookieInfo *, bool header, bool noexpiry,
char *lineptr,
- const char *domain, const char *path);
+ const char *domain, const char *path,
+ bool secure);
struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
const char *, bool);
diff --git a/lib/curl_sasl.c b/lib/curl_sasl.c
index 894e16c3d..437a9f66a 100644
--- a/lib/curl_sasl.c
+++ b/lib/curl_sasl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -300,8 +300,7 @@ CURLcode Curl_sasl_start(struct SASL *sasl, struct connectdata *conn,
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
- data->easy_conn->
- host.name,
+ data->conn->host.name,
sasl->mutual_auth,
NULL, &conn->krb5,
&resp, &len);
@@ -517,7 +516,7 @@ CURLcode Curl_sasl_continue(struct SASL *sasl, struct connectdata *conn,
result = Curl_auth_create_gssapi_user_message(data, conn->user,
conn->passwd,
service,
- data->easy_conn->host.name,
+ data->conn->host.name,
sasl->mutual_auth, NULL,
&conn->krb5,
&resp, &len);
diff --git a/lib/doh.c b/lib/doh.c
index 1e76c96f9..f06ed3311 100644
--- a/lib/doh.c
+++ b/lib/doh.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2018 - 2019, 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
@@ -160,7 +160,7 @@ static int Curl_doh_done(struct Curl_easy *doh, CURLcode result)
struct Curl_easy *data = doh->set.dohfor;
/* so one of the DOH request done for the 'data' transfer is now complete! */
data->req.doh.pending--;
- infof(data, "a DOH request is completed, %d to go\n", data->req.doh.pending);
+ infof(data, "a DOH request is completed, %u to go\n", data->req.doh.pending);
if(result)
infof(data, "DOH request %s\n", curl_easy_strerror(result));
diff --git a/lib/easy.c b/lib/easy.c
index 887b47729..0574372f8 100644
--- a/lib/easy.c
+++ b/lib/easy.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -1060,7 +1060,7 @@ CURLcode curl_easy_pause(struct Curl_easy *data, int action)
unsigned int i;
unsigned int count = data->state.tempcount;
struct tempbuf writebuf[3]; /* there can only be three */
- struct connectdata *conn = data->easy_conn;
+ struct connectdata *conn = data->conn;
struct Curl_easy *saved_data = NULL;
/* copy the structs to allow for immediate re-pausing */
diff --git a/lib/ftp.c b/lib/ftp.c
index f95535b1c..820da228f 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -655,7 +655,7 @@ 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); /* timeout in milliseconds */
+ time_t timeout = Curl_pp_state_timeout(pp, FALSE);
time_t interval_ms;
if(timeout <= 0) {
@@ -3054,7 +3054,7 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn,
bool *done)
{
struct ftp_conn *ftpc = &conn->proto.ftpc;
- CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
+ CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE, FALSE);
/* Check for the state outside of the Curl_socket_check() return code checks
since at times we are in fact already in this state when this function
@@ -3071,7 +3071,7 @@ static CURLcode ftp_block_statemach(struct connectdata *conn)
CURLcode result = CURLE_OK;
while(ftpc->state != FTP_STOP) {
- result = Curl_pp_statemach(pp, TRUE);
+ result = Curl_pp_statemach(pp, TRUE, TRUE /* disconnecting */);
if(result)
break;
}
diff --git a/lib/getinfo.c b/lib/getinfo.c
index d9bd64129..a883bb497 100644
--- a/lib/getinfo.c
+++ b/lib/getinfo.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -390,7 +390,7 @@ static CURLcode getinfo_slist(struct Curl_easy *data, CURLINFO info,
param_slistp;
struct curl_tlssessioninfo *tsi = &data->tsi;
#ifdef USE_SSL
- struct connectdata *conn = data->easy_conn;
+ struct connectdata *conn = data->conn;
#endif
*tsip = tsi;
diff --git a/lib/gopher.c b/lib/gopher.c
index d8a8ff86d..d1bcadf5b 100644
--- a/lib/gopher.c
+++ b/lib/gopher.c
@@ -31,9 +31,11 @@
#include "progress.h"
#include "gopher.h"
#include "select.h"
+#include "strdup.h"
#include "url.h"
#include "escape.h"
#include "warnless.h"
+#include "curl_printf.h"
#include "curl_memory.h"
/* The last #include file should be: */
#include "memdebug.h"
@@ -78,7 +80,9 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
curl_off_t *bytecount = &data->req.bytecount;
+ char *gopherpath;
char *path = data->state.up.path;
+ char *query = data->state.up.query;
char *sel = NULL;
char *sel_org = NULL;
ssize_t amount, k;
@@ -86,20 +90,30 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
*done = TRUE; /* unconditionally */
+ if(path && query)
+ gopherpath = aprintf("%s?%s", path, query);
+ else
+ gopherpath = strdup(path);
+
+ if(!gopherpath)
+ return CURLE_OUT_OF_MEMORY;
+
/* Create selector. Degenerate cases: / and /1 => convert to "" */
- if(strlen(path) <= 2) {
+ if(strlen(gopherpath) <= 2) {
sel = (char *)"";
len = strlen(sel);
+ free(gopherpath);
}
else {
char *newp;
/* Otherwise, drop / and the first character (i.e., item type) ... */
- newp = path;
+ newp = gopherpath;
newp += 2;
/* ... and finally unescape */
result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE);
+ free(gopherpath);
if(result)
return result;
sel_org = sel;
diff --git a/lib/hostip.c b/lib/hostip.c
index f589a0b2c..89b88e932 100644
--- a/lib/hostip.c
+++ b/lib/hostip.c
@@ -312,6 +312,26 @@ fetch_addr(struct connectdata *conn,
/* See if its already in our dns cache */
dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
+ /* No entry found in cache, check if we might have a wildcard entry */
+ if(!dns && data->change.wildcard_resolve) {
+ /*
+ * Free the previous entry_id before requesting a new one to avoid leaking
+ * memory
+ */
+ free(entry_id);
+
+ entry_id = create_hostcache_id("*", port);
+
+ /* If we can't create the entry id, fail */
+ if(!entry_id)
+ return dns;
+
+ entry_len = strlen(entry_id);
+
+ /* See if it's already in our dns cache */
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len + 1);
+ }
+
if(dns && (data->set.dns_cache_timeout != -1)) {
/* See whether the returned entry is stale. Done before we release lock */
struct hostcache_prune_data user;
@@ -872,6 +892,9 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
char hostname[256];
int port = 0;
+ /* Default is no wildcard found */
+ data->change.wildcard_resolve = false;
+
for(hostp = data->change.resolve; hostp; hostp = hostp->next) {
if(!hostp->data)
continue;
@@ -1052,6 +1075,13 @@ CURLcode Curl_loadhostpairs(struct Curl_easy *data)
}
infof(data, "Added %s:%d:%s to DNS cache\n",
hostname, port, addresses);
+
+ /* Wildcard hostname */
+ if(hostname[0] == '*' && hostname[1] == '\0') {
+ infof(data, "RESOLVE %s:%d is wildcard, enabling wildcard checks\n",
+ hostname, port);
+ data->change.wildcard_resolve = true;
+ }
}
}
data->change.resolve = NULL; /* dealt with now */
diff --git a/lib/http.c b/lib/http.c
index 10104a26d..83d23c258 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -616,6 +616,7 @@ output_auth_headers(struct connectdata *conn,
result = Curl_output_negotiate(conn, proxy);
if(result)
return result;
+ authstatus->done = TRUE;
negdata->state = GSS_AUTHSENT;
}
else
@@ -1681,6 +1682,52 @@ enum proxy_use {
HEADER_CONNECT /* sending CONNECT to a proxy */
};
+/* used to compile the provided trailers into one buffer
+ 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 Curl_easy *handle)
+{
+ char *ptr = NULL;
+ CURLcode result = CURLE_OK;
+ const char *endofline_native = NULL;
+ const char *endofline_network = NULL;
+
+ /* TODO: Maybe split Curl_add_custom_headers to make it reusable here */
+
+ if(
+#ifdef CURL_DO_LINEEND_CONV
+ (handle->set.prefer_ascii) ||
+#endif
+ (handle->set.crlf)) {
+ /* \n will become \r\n later on */
+ endofline_native = "\n";
+ endofline_network = "\x0a";
+ }
+ else {
+ endofline_native = "\r\n";
+ endofline_network = "\x0d\x0a";
+ }
+
+ while(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);
+ if(result)
+ return result;
+ }
+ else
+ infof(handle, "Malformatted trailing header ! Skipping trailer.");
+ trailers = trailers->next;
+ }
+ result = Curl_add_buffer(&buffer, endofline_network,
+ strlen(endofline_network));
+ return result;
+}
+
CURLcode Curl_add_custom_headers(struct connectdata *conn,
bool is_connect,
Curl_send_buffer *req_buffer)
@@ -1788,7 +1835,8 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn,
checkprefix("Transfer-Encoding:", headers->data))
/* HTTP/2 doesn't support chunked requests */
;
- else if(checkprefix("Authorization:", headers->data) &&
+ else if((checkprefix("Authorization:", headers->data) ||
+ checkprefix("Cookie:", headers->data)) &&
/* be careful of sending this potentially sensitive header to
other hosts */
(data->state.this_is_a_follow &&
@@ -3175,6 +3223,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
k->header = FALSE;
k->badheader = HEADER_ALLBAD;
streamclose(conn, "bad HTTP: No end-of-message indicator");
+ if(!data->set.http09_allowed) {
+ failf(data, "Received HTTP/0.9 when not allowed\n");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
break;
}
}
@@ -3208,6 +3260,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
if(st == STATUS_BAD) {
streamclose(conn, "bad HTTP: No end-of-message indicator");
/* this is not the beginning of a protocol first header line */
+ if(!data->set.http09_allowed) {
+ failf(data, "Received HTTP/0.9 when not allowed\n");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
k->header = FALSE;
if(*nread)
/* since there's more, this is a partial bad header */
@@ -3873,7 +3929,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
here, or else use real peer host name. */
conn->allocptr.cookiehost?
conn->allocptr.cookiehost:conn->host.name,
- data->state.up.path);
+ data->state.up.path,
+ (conn->handler->protocol&CURLPROTO_HTTPS)?
+ TRUE:FALSE);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
}
#endif
diff --git a/lib/http.h b/lib/http.h
index b0dd1fe7d..c265cb71c 100644
--- a/lib/http.h
+++ b/lib/http.h
@@ -74,6 +74,9 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
CURLcode Curl_add_custom_headers(struct connectdata *conn,
bool is_connect,
Curl_send_buffer *req_buffer);
+CURLcode Curl_http_compile_trailers(struct curl_slist *trailers,
+ Curl_send_buffer *buffer,
+ struct Curl_easy *handle);
/* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http(struct connectdata *conn, bool *done);
diff --git a/lib/http2.c b/lib/http2.c
index 3e31cfe55..d8030b6fe 100644
--- a/lib/http2.c
+++ b/lib/http2.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -800,7 +800,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
H2BUGF(infof(data_s, "NGHTTP2_ERR_PAUSE - %zu bytes out of buffer"
", stream %u\n",
len - nread, stream_id));
- data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
+ data_s->conn->proto.httpc.pause_stream_id = stream_id;
return NGHTTP2_ERR_PAUSE;
}
@@ -808,7 +808,7 @@ static int on_data_chunk_recv(nghttp2_session *session, uint8_t flags,
/* pause execution of nghttp2 if we received data for another handle
in order to process them first. */
if(conn->data != data_s) {
- data_s->easy_conn->proto.httpc.pause_stream_id = stream_id;
+ data_s->conn->proto.httpc.pause_stream_id = stream_id;
return NGHTTP2_ERR_PAUSE;
}
@@ -854,6 +854,10 @@ static int on_stream_close(nghttp2_session *session, int32_t stream_id,
stream_id);
DEBUGASSERT(0);
}
+ if(stream_id == httpc->pause_stream_id) {
+ H2BUGF(infof(data_s, "Stopped the pause stream!\n"));
+ httpc->pause_stream_id = 0;
+ }
H2BUGF(infof(data_s, "Removed stream %u hash!\n", stream_id));
stream->stream_id = 0; /* cleared */
}
diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c
index 444265d11..2a97707eb 100644
--- a/lib/http_negotiate.c
+++ b/lib/http_negotiate.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -49,7 +49,6 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
/* Point to the correct struct with this */
struct negotiatedata *neg_ctx;
- struct auth *authp;
if(proxy) {
userp = conn->http_proxy.user;
@@ -58,7 +57,6 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
data->set.str[STRING_PROXY_SERVICE_NAME] : "HTTP";
host = conn->http_proxy.host.name;
neg_ctx = &data->state.proxyneg;
- authp = &conn->data->state.authproxy;
}
else {
userp = conn->user;
@@ -67,7 +65,6 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
data->set.str[STRING_SERVICE_NAME] : "HTTP";
host = conn->host.name;
neg_ctx = &data->state.negotiate;
- authp = &conn->data->state.authhost;
}
/* Not set means empty */
@@ -92,17 +89,17 @@ CURLcode Curl_input_negotiate(struct connectdata *conn, bool proxy,
}
}
+ /* Supports SSL channel binding for Windows ISS extended protection */
+#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
+ neg_ctx->sslContext = conn->sslContext;
+#endif
+
/* Initialize the security context and decode our challenge */
result = Curl_auth_decode_spnego_message(data, userp, passwdp, service,
host, header, neg_ctx);
if(result)
Curl_auth_spnego_cleanup(neg_ctx);
- else
- /* If the status is different than 0 and we encountered no errors
- it means we have to continue. 0 is the OK value for both GSSAPI
- (GSS_S_COMPLETE) and SSPI (SEC_E_OK) */
- authp->done = !neg_ctx->status;
return result;
}
diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c
index a9b33f98e..aaf8a3deb 100644
--- a/lib/http_ntlm.c
+++ b/lib/http_ntlm.c
@@ -175,6 +175,9 @@ CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy)
if(s_hSecDll == NULL)
return err;
}
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ ntlm->sslContext = conn->sslContext;
+#endif
#endif
switch(ntlm->state) {
diff --git a/lib/http_proxy.c b/lib/http_proxy.c
index 56b57b172..1b4294a3c 100644
--- a/lib/http_proxy.c
+++ b/lib/http_proxy.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -643,7 +643,7 @@ static CURLcode CONNECT(struct connectdata *conn,
void Curl_connect_free(struct Curl_easy *data)
{
- struct connectdata *conn = data->easy_conn;
+ struct connectdata *conn = data->conn;
struct http_connect_state *s = conn->connect_state;
if(s) {
free(s);
diff --git a/lib/if2ip.c b/lib/if2ip.c
index 566061a56..acbcff71e 100644
--- a/lib/if2ip.c
+++ b/lib/if2ip.c
@@ -96,24 +96,6 @@ unsigned int Curl_ipv6_scope(const struct sockaddr *sa)
#if defined(HAVE_GETIFADDRS)
-bool Curl_if_is_interface_name(const char *interf)
-{
- bool result = FALSE;
-
- struct ifaddrs *iface, *head;
-
- if(getifaddrs(&head) >= 0) {
- for(iface = head; iface != NULL; iface = iface->ifa_next) {
- if(strcasecompare(iface->ifa_name, interf)) {
- result = TRUE;
- break;
- }
- }
- freeifaddrs(head);
- }
- return result;
-}
-
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
unsigned int remote_scope_id, const char *interf,
char *buf, int buf_size)
@@ -196,15 +178,6 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
#elif defined(HAVE_IOCTL_SIOCGIFADDR)
-bool Curl_if_is_interface_name(const char *interf)
-{
- /* This is here just to support the old interfaces */
- char buf[256];
-
- return (Curl_if2ip(AF_INET, 0 /* unused */, 0, interf, buf, sizeof(buf)) ==
- IF2IP_NOT_FOUND) ? FALSE : TRUE;
-}
-
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
unsigned int remote_scope_id, const char *interf,
char *buf, int buf_size)
@@ -251,13 +224,6 @@ if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
#else
-bool Curl_if_is_interface_name(const char *interf)
-{
- (void) interf;
-
- return FALSE;
-}
-
if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
unsigned int remote_scope_id, const char *interf,
char *buf, int buf_size)
diff --git a/lib/if2ip.h b/lib/if2ip.h
index a90e66216..a11b1c222 100644
--- a/lib/if2ip.h
+++ b/lib/if2ip.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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
@@ -32,8 +32,6 @@
unsigned int Curl_ipv6_scope(const struct sockaddr *sa);
-bool Curl_if_is_interface_name(const char *interf);
-
typedef enum {
IF2IP_NOT_FOUND = 0, /* Interface not found */
IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */
diff --git a/lib/imap.c b/lib/imap.c
index 8d1849df3..dab893cf7 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -316,7 +316,7 @@ static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
some e-mail servers ignore this and only send a single + instead. */
- if(imap && !imap->custom && ((len == 3 && !memcmp("+", line, 1)) ||
+ if(imap && !imap->custom && ((len == 3 && line[0] == '+') ||
(len >= 2 && !memcmp("+ ", line, 2)))) {
switch(imapc->state) {
/* States which are interested in continuation responses */
@@ -1362,19 +1362,20 @@ static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done)
return result;
}
- result = Curl_pp_statemach(&imapc->pp, FALSE);
+ result = Curl_pp_statemach(&imapc->pp, FALSE, FALSE);
*done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
return result;
}
-static CURLcode imap_block_statemach(struct connectdata *conn)
+static CURLcode imap_block_statemach(struct connectdata *conn,
+ bool disconnecting)
{
CURLcode result = CURLE_OK;
struct imap_conn *imapc = &conn->proto.imapc;
while(imapc->state != IMAP_STOP && !result)
- result = Curl_pp_statemach(&imapc->pp, TRUE);
+ result = Curl_pp_statemach(&imapc->pp, TRUE, disconnecting);
return result;
}
@@ -1497,7 +1498,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status,
non-blocking DONE operations!
*/
if(!result)
- result = imap_block_statemach(conn);
+ result = imap_block_statemach(conn, FALSE);
}
/* Cleanup our per-request based variables */
@@ -1635,7 +1636,7 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
point! */
if(!dead_connection && imapc->pp.conn && imapc->pp.conn->bits.protoconnstart)
if(!imap_perform_logout(conn))
- (void)imap_block_statemach(conn); /* ignore errors on LOGOUT */
+ (void)imap_block_statemach(conn, TRUE); /* ignore errors on LOGOUT */
/* Disconnect from the server */
Curl_pp_disconnect(&imapc->pp);
diff --git a/lib/multi.c b/lib/multi.c
index 311bde09c..5c09a04f5 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -114,7 +114,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 */
- data->easy_conn = NULL;
+ Curl_detach_connnection(data);
Curl_expire_clear(data); /* stop all timers */
}
@@ -163,8 +163,8 @@ static void mstate(struct Curl_easy *data, CURLMstate state
data->mstate < CURLM_STATE_COMPLETED) {
long connection_id = -5000;
- if(data->easy_conn)
- connection_id = data->easy_conn->connection_id;
+ if(data->conn)
+ connection_id = data->conn->connection_id;
infof(data,
"STATE: %s => %s handle %p; line %d (connection #%ld)\n",
@@ -189,14 +189,17 @@ static void mstate(struct Curl_easy *data, CURLMstate state
#endif
/*
- * We add one of these structs to the sockhash for a particular socket
+ * We add one of these structs to the sockhash for each socket
*/
struct Curl_sh_entry {
- struct Curl_easy *easy;
- int action; /* what action READ/WRITE this socket waits for */
- curl_socket_t socket; /* mainly to ease debugging */
+ struct curl_llist list; /* list of easy handles using this socket */
+ unsigned int action; /* what combined action READ/WRITE this socket waits
+ for */
void *socketp; /* settable by users with curl_multi_assign() */
+ unsigned int users; /* number of transfers using this */
+ unsigned int readers; /* this many transfers want to read */
+ unsigned int writers; /* this many transfers want to write */
};
/* bits for 'action' having no bits means this socket is not expecting any
action */
@@ -215,8 +218,7 @@ static struct Curl_sh_entry *sh_getentry(struct curl_hash *sh,
/* make sure this socket is present in the hash for this handle */
static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
- curl_socket_t s,
- struct Curl_easy *data)
+ curl_socket_t s)
{
struct Curl_sh_entry *there = sh_getentry(sh, s);
struct Curl_sh_entry *check;
@@ -230,8 +232,7 @@ static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
if(!check)
return NULL; /* major failure */
- check->easy = data;
- check->socket = s;
+ Curl_llist_init(&check->list, NULL);
/* make/add new hash entry */
if(!Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
@@ -516,31 +517,23 @@ static void debug_print_sock_hash(void *p)
}
#endif
-static CURLcode multi_done(struct connectdata **connp,
- CURLcode status, /* an error if this is called
- after an error was detected */
- bool premature)
+static CURLcode multi_done(struct Curl_easy *data,
+ CURLcode status, /* an error if this is called
+ after an error was detected */
+ bool premature)
{
CURLcode result;
- struct connectdata *conn;
- struct Curl_easy *data;
+ struct connectdata *conn = data->conn;
unsigned int i;
- DEBUGASSERT(*connp);
-
- conn = *connp;
- data = conn->data;
-
DEBUGF(infof(data, "multi_done\n"));
if(data->state.done)
/* Stop if multi_done() has already been called */
return CURLE_OK;
- if(data->mstate == CURLM_STATE_WAITRESOLVE) {
- /* still waiting for the resolve to complete */
- (void)Curl_resolver_wait_resolv(conn, NULL);
- }
+ /* Stop the resolver and free its own resources (but not dns_entry yet). */
+ Curl_resolver_kill(conn);
Curl_getoff_all_pipelines(data, conn);
@@ -579,7 +572,7 @@ static CURLcode multi_done(struct connectdata **connp,
if(conn->send_pipe.size || conn->recv_pipe.size) {
/* Stop if pipeline is not empty . */
- data->easy_conn = NULL;
+ Curl_detach_connnection(data);
DEBUGF(infof(data, "Connection still in use %zu/%zu, "
"no more multi_done now!\n",
conn->send_pipe.size, conn->recv_pipe.size));
@@ -587,7 +580,6 @@ static CURLcode multi_done(struct connectdata **connp,
}
data->state.done = TRUE; /* called just now! */
- Curl_resolver_cancel(conn);
if(conn->dns_entry) {
Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
@@ -653,10 +645,7 @@ static CURLcode multi_done(struct connectdata **connp,
data->state.lastconnect = NULL;
}
- *connp = NULL; /* to make the caller of this function better detect that
- this was either closed or handed over to the connection
- cache here, and therefore cannot be used from this point on
- */
+ Curl_detach_connnection(data);
Curl_free_request_state(data);
return result;
}
@@ -685,7 +674,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
return CURLM_RECURSIVE_API_CALL;
premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
- easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ?
+ easy_owns_conn = (data->conn && (data->conn->data == easy)) ?
TRUE : FALSE;
/* If the 'state' is not INIT or COMPLETED, we might need to do something
@@ -696,16 +685,16 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
multi->num_alive--;
}
- if(data->easy_conn &&
+ if(data->conn &&
data->mstate > CURLM_STATE_DO &&
data->mstate < CURLM_STATE_COMPLETED) {
/* Set connection owner so that the DONE function closes it. We can
safely do this here since connection is killed. */
- data->easy_conn->data = easy;
+ data->conn->data = easy;
/* If the handle is in a pipeline and has started sending off its
request but not received its response yet, we need to close
connection. */
- streamclose(data->easy_conn, "Removed with partial response");
+ streamclose(data->conn, "Removed with partial response");
easy_owns_conn = TRUE;
}
@@ -714,7 +703,7 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
curl_easy_cleanup is called. */
Curl_expire_clear(data);
- if(data->easy_conn) {
+ if(data->conn) {
/* we must call multi_done() here (if we still own the connection) so that
we don't leave a half-baked one around */
@@ -725,11 +714,11 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
Note that this ignores the return code simply because there's
nothing really useful to do with it anyway! */
- (void)multi_done(&data->easy_conn, data->result, premature);
+ (void)multi_done(data, data->result, premature);
}
else
/* Clear connection pipelines, if multi_done above was not called */
- Curl_getoff_all_pipelines(data, data->easy_conn);
+ Curl_getoff_all_pipelines(data, data->conn);
}
if(data->connect_queue.ptr)
@@ -761,9 +750,9 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
vanish with this handle */
/* Remove the association between the connection and the handle */
- if(data->easy_conn) {
- data->easy_conn->data = NULL;
- data->easy_conn = NULL;
+ if(data->conn) {
+ data->conn->data = NULL;
+ Curl_detach_connnection(data);
}
#ifdef USE_LIBPSL
@@ -813,9 +802,19 @@ bool Curl_pipeline_wanted(const struct Curl_multi *multi, int bits)
return (multi && (multi->pipelining & bits)) ? TRUE : FALSE;
}
-void Curl_multi_handlePipeBreak(struct Curl_easy *data)
+/* This is the only function that should clear data->conn. This will
+ occasionally be called with the pointer already cleared. */
+void Curl_detach_connnection(struct Curl_easy *data)
+{
+ data->conn = NULL;
+}
+
+/* This is the only function that should assign data->conn */
+void Curl_attach_connnection(struct Curl_easy *data,
+ struct connectdata *conn)
{
- data->easy_conn = NULL;
+ DEBUGASSERT(!data->conn);
+ data->conn = conn;
}
static int waitconnect_getsock(struct connectdata *conn,
@@ -879,13 +878,13 @@ static int multi_getsock(struct Curl_easy *data,
/* The no connection case can happen when this is called from
curl_multi_remove_handle() => singlesocket() => multi_getsock().
*/
- if(!data->easy_conn)
+ if(!data->conn)
return 0;
if(data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_COMPLETED) {
/* Set up ownership correctly */
- data->easy_conn->data = data;
+ data->conn->data = data;
}
switch(data->mstate) {
@@ -906,31 +905,31 @@ static int multi_getsock(struct Curl_easy *data,
return 0;
case CURLM_STATE_WAITRESOLVE:
- return Curl_resolv_getsock(data->easy_conn, socks, numsocks);
+ return Curl_resolv_getsock(data->conn, socks, numsocks);
case CURLM_STATE_PROTOCONNECT:
case CURLM_STATE_SENDPROTOCONNECT:
- return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
+ return Curl_protocol_getsock(data->conn, socks, numsocks);
case CURLM_STATE_DO:
case CURLM_STATE_DOING:
- return Curl_doing_getsock(data->easy_conn, socks, numsocks);
+ return Curl_doing_getsock(data->conn, socks, numsocks);
case CURLM_STATE_WAITPROXYCONNECT:
- return waitproxyconnect_getsock(data->easy_conn, socks, numsocks);
+ return waitproxyconnect_getsock(data->conn, socks, numsocks);
case CURLM_STATE_WAITCONNECT:
- return waitconnect_getsock(data->easy_conn, socks, numsocks);
+ return waitconnect_getsock(data->conn, socks, numsocks);
case CURLM_STATE_DO_MORE:
- return domore_getsock(data->easy_conn, socks, numsocks);
+ return domore_getsock(data->conn, socks, numsocks);
case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
to waiting for the same as the *PERFORM
states */
case CURLM_STATE_PERFORM:
case CURLM_STATE_WAITPERFORM:
- return Curl_single_getsock(data->easy_conn, socks, numsocks);
+ return Curl_single_getsock(data->conn, socks, numsocks);
}
}
@@ -1202,17 +1201,16 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
/* take this handle to the perform state right away */
multistate(data, CURLM_STATE_PERFORM);
- data->easy_conn = conn;
+ Curl_attach_connnection(data, conn);
k->keepon |= KEEP_RECV; /* setup to receive! */
}
return rc;
}
-static CURLcode multi_reconnect_request(struct connectdata **connp)
+static CURLcode multi_reconnect_request(struct Curl_easy *data)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = *connp;
- struct Curl_easy *data = conn->data;
+ struct connectdata *conn = data->conn;
/* This was a re-use of a connection and we got a write error in the
* DO-phase. Then we DISCONNECT this connection and have another attempt to
@@ -1223,11 +1221,9 @@ static CURLcode multi_reconnect_request(struct connectdata **connp)
infof(data, "Re-used connection seems dead, get a new one\n");
connclose(conn, "Reconnect dead connection"); /* enforce close */
- result = multi_done(&conn, result, FALSE); /* we are so done with this */
+ result = multi_done(data, result, FALSE); /* we are so done with this */
- /* conn may no longer be a good pointer, clear it to avoid mistakes by
- parent functions */
- *connp = NULL;
+ /* data->conn was detached in multi_done() */
/*
* We need to check for CURLE_SEND_ERROR here as well. This could happen
@@ -1239,11 +1235,11 @@ static CURLcode multi_reconnect_request(struct connectdata **connp)
bool protocol_done = TRUE;
/* Now, redo the connect and get a new connection */
- result = Curl_connect(data, connp, &async, &protocol_done);
+ result = Curl_connect(data, &async, &protocol_done);
if(!result) {
/* We have connected or sent away a name resolve query fine */
- conn = *connp; /* setup conn to again point to something nice */
+ conn = data->conn; /* in case it was updated */
if(async) {
/* Now, if async is TRUE here, we need to wait for the name
to resolve */
@@ -1276,11 +1272,10 @@ static void do_complete(struct connectdata *conn)
Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
}
-static CURLcode multi_do(struct connectdata **connp, bool *done)
+static CURLcode multi_do(struct Curl_easy *data, bool *done)
{
CURLcode result = CURLE_OK;
- struct connectdata *conn = *connp;
- struct Curl_easy *data = conn->data;
+ struct connectdata *conn = data->conn;
if(conn->handler->do_it) {
/* generic protocol-specific function pointer set in curl_connect() */
@@ -1294,12 +1289,12 @@ static CURLcode multi_do(struct connectdata **connp, bool *done)
* figure out how to re-establish the connection.
*/
if(!data->multi) {
- result = multi_reconnect_request(connp);
+ result = multi_reconnect_request(data);
if(!result) {
/* ... finally back to actually retry the DO phase */
- conn = *connp; /* re-assign conn since multi_reconnect_request
- creates a new connection */
+ conn = data->conn; /* re-assign conn since multi_reconnect_request
+ creates a new connection */
result = conn->handler->do_it(conn, done);
}
}
@@ -1368,13 +1363,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
bool stream_error = FALSE;
rc = CURLM_OK;
- if(!data->easy_conn &&
+ if(!data->conn &&
data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_DONE) {
- /* In all these states, the code will blindly access 'data->easy_conn'
+ /* 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 easy_conn, bail out!\n", data->mstate);
+ failf(data, "In state %d with no conn, bail out!\n", data->mstate);
return CURLM_INTERNAL_ERROR;
}
@@ -1383,13 +1378,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
process_pending_handles(multi); /* pipelined/multiplexed */
}
- if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
+ if(data->conn && data->mstate > CURLM_STATE_CONNECT &&
data->mstate < CURLM_STATE_COMPLETED) {
/* Make sure we set the connection's current owner */
- data->easy_conn->data = data;
+ data->conn->data = data;
}
- if(data->easy_conn &&
+ if(data->conn &&
(data->mstate >= CURLM_STATE_CONNECT) &&
(data->mstate < CURLM_STATE_COMPLETED)) {
/* we need to wait for the connect state as only then is the start time
@@ -1401,23 +1396,26 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(timeout_ms < 0) {
/* Handle timed out */
if(data->mstate == CURLM_STATE_WAITRESOLVE)
- failf(data, "Resolving timed out after %ld milliseconds",
+ failf(data, "Resolving timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
Curl_timediff(now, data->progress.t_startsingle));
else if(data->mstate == CURLM_STATE_WAITCONNECT)
- failf(data, "Connection timed out after %ld milliseconds",
+ failf(data, "Connection timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds",
Curl_timediff(now, data->progress.t_startsingle));
else {
k = &data->req;
if(k->size != -1) {
- failf(data, "Operation timed out after %ld milliseconds with %"
- CURL_FORMAT_CURL_OFF_T " out of %"
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
CURL_FORMAT_CURL_OFF_T " bytes received",
Curl_timediff(now, data->progress.t_startsingle),
k->bytecount, k->size);
}
else {
- failf(data, "Operation timed out after %ld milliseconds with %"
- CURL_FORMAT_CURL_OFF_T " bytes received",
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T
+ " bytes received",
Curl_timediff(now, data->progress.t_startsingle),
k->bytecount);
}
@@ -1425,11 +1423,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Force connection closed if the connection has indeed been used */
if(data->mstate > CURLM_STATE_DO) {
- streamclose(data->easy_conn, "Disconnected with pending data");
+ streamclose(data->conn, "Disconnected with pending data");
stream_error = TRUE;
}
result = CURLE_OPERATION_TIMEDOUT;
- (void)multi_done(&data->easy_conn, result, TRUE);
+ (void)multi_done(data, result, TRUE);
/* Skip the statemachine and go directly to error handling section. */
goto statemachine_end;
}
@@ -1456,8 +1454,13 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_CONNECT:
/* Connect. We want to get a connection identifier filled in. */
Curl_pgrsTime(data, TIMER_STARTSINGLE);
- result = Curl_connect(data, &data->easy_conn,
- &async, &protocol_connect);
+ if(data->set.timeout)
+ Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
+
+ if(data->set.connecttimeout)
+ Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
+
+ result = Curl_connect(data, &async, &protocol_connect);
if(CURLE_NO_CONNECTION_AVAILABLE == result) {
/* There was no connection available. We will go to the pending
state and wait for an available connection. */
@@ -1472,7 +1475,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(!result) {
/* Add this handle to the send or pend pipeline */
- result = Curl_add_handle_to_pipeline(data, data->easy_conn);
+ result = Curl_add_handle_to_pipeline(data, data->conn);
if(result)
stream_error = TRUE;
else {
@@ -1490,7 +1493,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
CURLM_STATE_WAITDO:CURLM_STATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
- if(Curl_connect_ongoing(data->easy_conn))
+ if(Curl_connect_ongoing(data->conn))
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
else
#endif
@@ -1505,7 +1508,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* awaiting an asynch name resolve to complete */
{
struct Curl_dns_entry *dns = NULL;
- struct connectdata *conn = data->easy_conn;
+ struct connectdata *conn = data->conn;
const char *hostname;
if(conn->bits.httpproxy)
@@ -1528,7 +1531,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!dns)
- result = Curl_resolv_check(data->easy_conn, &dns);
+ result = Curl_resolv_check(data->conn, &dns);
/* Update sockets here, because the socket(s) may have been
closed and the application thus needs to be told, even if it
@@ -1541,12 +1544,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
/* Perform the next step in the connection phase, and then move on
to the WAITCONNECT state */
- result = Curl_once_resolved(data->easy_conn, &protocol_connect);
+ result = Curl_once_resolved(data->conn, &protocol_connect);
if(result)
/* if Curl_once_resolved() returns failure, the connection struct
is already freed and gone */
- data->easy_conn = NULL; /* no more connection */
+ Curl_detach_connnection(data); /* no more connection */
else {
/* call again please so that we get the next socket setup */
rc = CURLM_CALL_MULTI_PERFORM;
@@ -1555,7 +1558,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
CURLM_STATE_WAITDO:CURLM_STATE_DO);
else {
#ifndef CURL_DISABLE_HTTP
- if(Curl_connect_ongoing(data->easy_conn))
+ if(Curl_connect_ongoing(data->conn))
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
else
#endif
@@ -1575,19 +1578,19 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
#ifndef CURL_DISABLE_HTTP
case CURLM_STATE_WAITPROXYCONNECT:
/* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
- result = Curl_http_connect(data->easy_conn, &protocol_connect);
+ result = Curl_http_connect(data->conn, &protocol_connect);
- if(data->easy_conn->bits.proxy_connect_closed) {
+ if(data->conn->bits.proxy_connect_closed) {
rc = CURLM_CALL_MULTI_PERFORM;
/* connect back to proxy again */
result = CURLE_OK;
- multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ multi_done(data, CURLE_OK, FALSE);
multistate(data, CURLM_STATE_CONNECT);
}
else if(!result) {
- if((data->easy_conn->http_proxy.proxytype != CURLPROXY_HTTPS ||
- data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) &&
- Curl_connect_complete(data->easy_conn)) {
+ 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);
@@ -1600,18 +1603,18 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_WAITCONNECT:
/* awaiting a completion of an asynch TCP connect */
- result = Curl_is_connected(data->easy_conn, FIRSTSOCKET, &connected);
+ result = Curl_is_connected(data->conn, FIRSTSOCKET, &connected);
if(connected && !result) {
#ifndef CURL_DISABLE_HTTP
- if((data->easy_conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
- !data->easy_conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
- Curl_connect_ongoing(data->easy_conn)) {
+ if((data->conn->http_proxy.proxytype == CURLPROXY_HTTPS &&
+ !data->conn->bits.proxy_ssl_connected[FIRSTSOCKET]) ||
+ Curl_connect_ongoing(data->conn)) {
multistate(data, CURLM_STATE_WAITPROXYCONNECT);
break;
}
#endif
rc = CURLM_CALL_MULTI_PERFORM;
- multistate(data, data->easy_conn->bits.tunnel_proxy?
+ multistate(data, data->conn->bits.tunnel_proxy?
CURLM_STATE_WAITPROXYCONNECT:
CURLM_STATE_SENDPROTOCONNECT);
}
@@ -1624,7 +1627,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
break;
case CURLM_STATE_SENDPROTOCONNECT:
- result = Curl_protocol_connect(data->easy_conn, &protocol_connect);
+ result = Curl_protocol_connect(data->conn, &protocol_connect);
if(!result && !protocol_connect)
/* switch to waiting state */
multistate(data, CURLM_STATE_PROTOCONNECT);
@@ -1637,14 +1640,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else if(result) {
/* failure detected */
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, TRUE);
+ multi_done(data, result, TRUE);
stream_error = TRUE;
}
break;
case CURLM_STATE_PROTOCONNECT:
/* protocol-specific connect phase */
- result = Curl_protocol_connecting(data->easy_conn, &protocol_connect);
+ result = Curl_protocol_connecting(data->conn, &protocol_connect);
if(!result && protocol_connect) {
/* after the connect has completed, go WAITDO or DO */
multistate(data, Curl_pipeline_wanted(multi, CURLPIPE_HTTP1)?
@@ -1654,14 +1657,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else if(result) {
/* failure detected */
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, TRUE);
+ multi_done(data, result, TRUE);
stream_error = TRUE;
}
break;
case CURLM_STATE_WAITDO:
/* Wait for our turn to DO when we're pipelining requests */
- if(Curl_pipeline_checkget_write(data, data->easy_conn)) {
+ if(Curl_pipeline_checkget_write(data, data->conn)) {
/* Grabbed the channel */
multistate(data, CURLM_STATE_DO);
rc = CURLM_CALL_MULTI_PERFORM;
@@ -1671,16 +1674,16 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_DO:
if(data->set.connect_only) {
/* keep connection open for application to use the socket */
- connkeep(data->easy_conn, "CONNECT_ONLY");
+ connkeep(data->conn, "CONNECT_ONLY");
multistate(data, CURLM_STATE_DONE);
result = CURLE_OK;
rc = CURLM_CALL_MULTI_PERFORM;
}
else {
/* Perform the protocol's DO action */
- result = multi_do(&data->easy_conn, &dophase_done);
+ result = multi_do(data, &dophase_done);
- /* When multi_do() returns failure, data->easy_conn might be NULL! */
+ /* When multi_do() returns failure, data->conn might be NULL! */
if(!result) {
if(!dophase_done) {
@@ -1689,7 +1692,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
struct WildcardData *wc = &data->wildcard;
if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
/* skip some states if it is important */
- multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ multi_done(data, CURLE_OK, FALSE);
multistate(data, CURLM_STATE_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
break;
@@ -1702,7 +1705,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* after DO, go DO_DONE... or DO_MORE */
- else if(data->easy_conn->bits.do_more) {
+ else if(data->conn->bits.do_more) {
/* we're supposed to do more, but we need to sit down, relax
and wait a little while first */
multistate(data, CURLM_STATE_DO_MORE);
@@ -1715,7 +1718,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
else if((CURLE_SEND_ERROR == result) &&
- data->easy_conn->bits.reuse) {
+ data->conn->bits.reuse) {
/*
* In this situation, a connection that we were trying to use
* may have unexpectedly died. If possible, send the connection
@@ -1725,7 +1728,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
followtype follow = FOLLOW_NONE;
CURLcode drc;
- drc = Curl_retry_request(data->easy_conn, &newurl);
+ drc = Curl_retry_request(data->conn, &newurl);
if(drc) {
/* a failure here pretty much implies an out of memory */
result = drc;
@@ -1733,7 +1736,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
Curl_posttransfer(data);
- drc = multi_done(&data->easy_conn, result, FALSE);
+ drc = multi_done(data, result, FALSE);
/* When set to retry the connection, we must to go back to
* the CONNECT state */
@@ -1765,8 +1768,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(data);
- if(data->easy_conn)
- multi_done(&data->easy_conn, result, FALSE);
+ if(data->conn)
+ multi_done(data, result, FALSE);
stream_error = TRUE;
}
}
@@ -1774,12 +1777,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_DOING:
/* we continue DOING until the DO phase is complete */
- result = Curl_protocol_doing(data->easy_conn,
+ result = Curl_protocol_doing(data->conn,
&dophase_done);
if(!result) {
if(dophase_done) {
/* after DO, go DO_DONE or DO_MORE */
- multistate(data, data->easy_conn->bits.do_more?
+ multistate(data, data->conn->bits.do_more?
CURLM_STATE_DO_MORE:
CURLM_STATE_DO_DONE);
rc = CURLM_CALL_MULTI_PERFORM;
@@ -1788,7 +1791,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, FALSE);
+ multi_done(data, result, FALSE);
stream_error = TRUE;
}
break;
@@ -1797,7 +1800,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/*
* When we are connected, DO MORE and then go DO_DONE
*/
- result = multi_do_more(data->easy_conn, &control);
+ result = multi_do_more(data->conn, &control);
/* No need to remove this handle from the send pipeline here since that
is done in multi_done() */
@@ -1817,27 +1820,27 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
else {
/* failure detected */
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, FALSE);
+ multi_done(data, result, FALSE);
stream_error = TRUE;
}
break;
case CURLM_STATE_DO_DONE:
/* Move ourselves from the send to recv pipeline */
- Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn);
+ Curl_move_handle_from_send_to_recv_pipe(data, data->conn);
- if(data->easy_conn->bits.multiplex || data->easy_conn->send_pipe.size)
+ if(data->conn->bits.multiplex || data->conn->send_pipe.size)
/* Check if we can move pending requests to send pipe */
process_pending_handles(multi); /* pipelined/multiplexed */
/* Only perform the transfer if there's a good socket to work with.
Having both BAD is a signal to skip immediately to DONE */
- if((data->easy_conn->sockfd != CURL_SOCKET_BAD) ||
- (data->easy_conn->writesockfd != CURL_SOCKET_BAD))
+ if((data->conn->sockfd != CURL_SOCKET_BAD) ||
+ (data->conn->writesockfd != CURL_SOCKET_BAD))
multistate(data, CURLM_STATE_WAITPERFORM);
else {
if(data->state.wildcardmatch &&
- ((data->easy_conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
+ ((data->conn->handler->flags & PROTOPT_WILDCARD) == 0)) {
data->wildcard.state = CURLWC_DONE;
}
multistate(data, CURLM_STATE_DONE);
@@ -1847,7 +1850,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_WAITPERFORM:
/* Wait for our turn to PERFORM */
- if(Curl_pipeline_checkget_read(data, data->easy_conn)) {
+ if(Curl_pipeline_checkget_read(data, data->conn)) {
/* Grabbed the channel */
multistate(data, CURLM_STATE_PERFORM);
rc = CURLM_CALL_MULTI_PERFORM;
@@ -1856,7 +1859,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
/* if both rates are within spec, resume transfer */
- if(Curl_pgrsUpdate(data->easy_conn))
+ if(Curl_pgrsUpdate(data->conn))
result = CURLE_ABORTED_BY_CALLBACK;
else
result = Curl_speedcheck(data, now);
@@ -1926,24 +1929,24 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* read/write data if it is ready to do so */
- result = Curl_readwrite(data->easy_conn, data, &done, &comeback);
+ result = Curl_readwrite(data->conn, data, &done, &comeback);
k = &data->req;
if(!(k->keepon & KEEP_RECV))
/* We're done receiving */
- Curl_pipeline_leave_read(data->easy_conn);
+ Curl_pipeline_leave_read(data->conn);
if(!(k->keepon & KEEP_SEND))
/* We're done sending */
- Curl_pipeline_leave_write(data->easy_conn);
+ Curl_pipeline_leave_write(data->conn);
if(done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
* condition and the server closed the re-used connection exactly when
* we wanted to use it, so figure out if that is indeed the case.
*/
- CURLcode ret = Curl_retry_request(data->easy_conn, &newurl);
+ CURLcode ret = Curl_retry_request(data->conn, &newurl);
if(!ret)
retry = (newurl)?TRUE:FALSE;
else if(!result)
@@ -1957,8 +1960,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
else if((CURLE_HTTP2_STREAM == result) &&
- Curl_h2_http_1_1_error(data->easy_conn)) {
- CURLcode ret = Curl_retry_request(data->easy_conn, &newurl);
+ Curl_h2_http_1_1_error(data->conn)) {
+ CURLcode ret = Curl_retry_request(data->conn, &newurl);
infof(data, "Forcing HTTP/1.1 for NTLM");
data->set.httpversion = CURL_HTTP_VERSION_1_1;
@@ -1985,12 +1988,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
* happened in the data connection.
*/
- if(!(data->easy_conn->handler->flags & PROTOPT_DUAL) &&
+ if(!(data->conn->handler->flags & PROTOPT_DUAL) &&
result != CURLE_HTTP2_STREAM)
- streamclose(data->easy_conn, "Transfer returned error");
+ streamclose(data->conn, "Transfer returned error");
Curl_posttransfer(data);
- multi_done(&data->easy_conn, result, TRUE);
+ multi_done(data, result, TRUE);
}
else if(done) {
followtype follow = FOLLOW_NONE;
@@ -1999,11 +2002,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
Curl_posttransfer(data);
/* we're no longer receiving */
- Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
+ Curl_removeHandleFromPipeline(data, &data->conn->recv_pipe);
/* expire the new receiving pipeline head */
- if(data->easy_conn->recv_pipe.head)
- Curl_expire(data->easy_conn->recv_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
+ if(data->conn->recv_pipe.head)
+ Curl_expire(data->conn->recv_pipe.head->ptr, 0, EXPIRE_RUN_NOW);
/* When we follow redirects or is set to retry the connection, we must
to go back to the CONNECT state */
@@ -2018,7 +2021,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
else
follow = FOLLOW_RETRY;
- result = multi_done(&data->easy_conn, CURLE_OK, FALSE);
+ result = multi_done(data, CURLE_OK, FALSE);
if(!result) {
result = Curl_follow(data, newurl, follow);
if(!result) {
@@ -2041,7 +2044,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
free(newurl);
if(result) {
stream_error = TRUE;
- result = multi_done(&data->easy_conn, result, TRUE);
+ result = multi_done(data, result, TRUE);
}
}
@@ -2060,18 +2063,18 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* this state is highly transient, so run another loop after this */
rc = CURLM_CALL_MULTI_PERFORM;
- if(data->easy_conn) {
+ if(data->conn) {
CURLcode res;
/* Remove ourselves from the receive pipeline, if we are there. */
- Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
+ Curl_removeHandleFromPipeline(data, &data->conn->recv_pipe);
- if(data->easy_conn->bits.multiplex || data->easy_conn->send_pipe.size)
+ if(data->conn->bits.multiplex || data->conn->send_pipe.size)
/* Check if we can move pending requests to connection */
process_pending_handles(multi); /* pipelined/multiplexing */
/* post-transfer command */
- res = multi_done(&data->easy_conn, result, FALSE);
+ res = multi_done(data, result, FALSE);
/* allow a previously set error code take precedence */
if(!result)
@@ -2079,12 +2082,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/*
* If there are other handles on the pipeline, multi_done won't set
- * easy_conn to NULL. In such a case, curl_multi_remove_handle() can
+ * conn to NULL. In such a case, curl_multi_remove_handle() can
* access free'd data, if the connection is free'd and the handle
* removed before we perform the processing in CURLM_STATE_COMPLETED
*/
- if(data->easy_conn)
- data->easy_conn = NULL;
+ if(data->conn)
+ Curl_detach_connnection(data);
}
if(data->state.wildcardmatch) {
@@ -2126,23 +2129,23 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
/* Check if we can move pending requests to send pipe */
process_pending_handles(multi); /* connection */
- if(data->easy_conn) {
+ if(data->conn) {
/* if this has a connection, unsubscribe from the pipelines */
- Curl_pipeline_leave_write(data->easy_conn);
- Curl_pipeline_leave_read(data->easy_conn);
- Curl_removeHandleFromPipeline(data, &data->easy_conn->send_pipe);
- Curl_removeHandleFromPipeline(data, &data->easy_conn->recv_pipe);
+ Curl_pipeline_leave_write(data->conn);
+ Curl_pipeline_leave_read(data->conn);
+ Curl_removeHandleFromPipeline(data, &data->conn->send_pipe);
+ Curl_removeHandleFromPipeline(data, &data->conn->recv_pipe);
if(stream_error) {
/* Don't attempt to send data over a connection that timed out */
bool dead_connection = result == CURLE_OPERATION_TIMEDOUT;
/* disconnect properly */
- Curl_disconnect(data, data->easy_conn, dead_connection);
+ Curl_disconnect(data, data->conn, dead_connection);
- /* This is where we make sure that the easy_conn pointer is reset.
+ /* 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 */
- data->easy_conn = NULL;
+ Curl_detach_connnection(data);
}
}
else if(data->mstate == CURLM_STATE_CONNECT) {
@@ -2154,11 +2157,11 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
rc = CURLM_CALL_MULTI_PERFORM;
}
/* if there's still a connection to use, call the progress function */
- else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) {
+ else if(data->conn && Curl_pgrsUpdate(data->conn)) {
/* aborted due to progress callback return code must close the
connection */
result = CURLE_ABORTED_BY_CALLBACK;
- streamclose(data->easy_conn, "Aborted by callback");
+ streamclose(data->conn, "Aborted by callback");
/* if not yet in DONE state, go there, otherwise COMPLETED */
multistate(data, (data->mstate < CURLM_STATE_DONE)?
@@ -2181,7 +2184,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
msg->extmsg.data.result = result;
rc = multi_addmsg(multi, msg);
- DEBUGASSERT(!data->easy_conn);
+ DEBUGASSERT(!data->conn);
}
multistate(data, CURLM_STATE_MSGSENT);
}
@@ -2261,9 +2264,9 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
data = multi->easyp;
while(data) {
nextdata = data->next;
- if(!data->state.done && data->easy_conn)
+ if(!data->state.done && data->conn)
/* if DONE was never called for this handle */
- (void)multi_done(&data->easy_conn, CURLE_OK, TRUE);
+ (void)multi_done(data, CURLE_OK, TRUE);
if(data->dns.hostcachetype == HCACHE_MULTI) {
/* clear out the usage of the shared DNS cache */
Curl_hostcache_clean(data, data->dns.hostcache);
@@ -2356,6 +2359,9 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
curl_socket_t s;
int num;
unsigned int curraction;
+ int actions[MAX_SOCKSPEREASYHANDLE];
+ unsigned int comboaction;
+ bool sincebefore = FALSE;
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++)
socks[i] = CURL_SOCKET_BAD;
@@ -2372,7 +2378,8 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
for(i = 0; (i< MAX_SOCKSPEREASYHANDLE) &&
(curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
i++) {
- int action = CURL_POLL_NONE;
+ unsigned int action = CURL_POLL_NONE;
+ unsigned int prevaction = 0;
s = socks[i];
@@ -2384,29 +2391,70 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
if(curraction & GETSOCK_WRITESOCK(i))
action |= CURL_POLL_OUT;
+ actions[i] = action;
if(entry) {
- /* yeps, already present so check if it has the same action set */
- if(entry->action == action)
- /* same, continue */
- continue;
+ /* check if new for this transfer */
+ for(i = 0; i< data->numsocks; i++) {
+ if(s == data->sockets[i]) {
+ prevaction = data->actions[i];
+ sincebefore = TRUE;
+ break;
+ }
+ }
+
}
else {
- /* this is a socket we didn't have before, add it! */
- entry = sh_addentry(&multi->sockhash, s, data);
+ /* this is a socket we didn't have before, add it to the hash! */
+ entry = sh_addentry(&multi->sockhash, s);
if(!entry)
/* fatal */
return CURLM_OUT_OF_MEMORY;
}
+ if(sincebefore && (prevaction != action)) {
+ /* Socket was used already, but different action now */
+ if(prevaction & CURL_POLL_IN)
+ entry->readers--;
+ if(prevaction & CURL_POLL_OUT)
+ entry->writers--;
+ if(action & CURL_POLL_IN)
+ entry->readers++;
+ if(action & CURL_POLL_OUT)
+ entry->writers++;
+ }
+ else if(!sincebefore) {
+ /* a new user */
+ entry->users++;
+ if(action & CURL_POLL_IN)
+ entry->readers++;
+ if(action & CURL_POLL_OUT)
+ entry->writers++;
+
+ /* add 'data' to the list of handles using this socket! */
+ Curl_llist_insert_next(&entry->list, entry->list.tail,
+ data, &data->sh_queue);
+ }
+
+ comboaction = (entry->writers? CURL_POLL_OUT : 0) |
+ (entry->readers ? CURL_POLL_IN : 0);
+
+#if 0
+ infof(data, "--- Comboaction: %u readers %u writers\n",
+ entry->readers, entry->writers);
+#endif
+ /* check if it has the same action set */
+ if(entry->action == comboaction)
+ /* same, continue */
+ continue;
/* we know (entry != NULL) at this point, see the logic above */
if(multi->socket_cb)
multi->socket_cb(data,
s,
- action,
+ comboaction,
multi->socket_userp,
entry->socketp);
- entry->action = action; /* store the current action state */
+ entry->action = comboaction; /* store the current action state */
}
num = i; /* number of sockets */
@@ -2415,73 +2463,45 @@ static CURLMcode singlesocket(struct Curl_multi *multi,
make sure to detect sockets that are removed */
for(i = 0; i< data->numsocks; i++) {
int j;
+ bool stillused = FALSE;
s = data->sockets[i];
- for(j = 0; j<num; j++) {
+ for(j = 0; j < num; j++) {
if(s == socks[j]) {
/* this is still supervised */
- s = CURL_SOCKET_BAD;
+ stillused = TRUE;
break;
}
}
+ if(stillused)
+ continue;
entry = sh_getentry(&multi->sockhash, s);
+ /* if this is NULL here, the socket has been closed and notified so
+ already by Curl_multi_closed() */
if(entry) {
- /* this socket has been removed. Tell the app to remove it */
- bool remove_sock_from_hash = TRUE;
-
- /* check if the socket to be removed serves a connection which has
- other easy-s in a pipeline. In this case the socket should not be
- removed. */
- struct connectdata *easy_conn = data->easy_conn;
- if(easy_conn) {
- if(easy_conn->recv_pipe.size > 1) {
- /* the handle should not be removed from the pipe yet */
- remove_sock_from_hash = FALSE;
-
- /* Update the sockhash entry to instead point to the next in line
- for the recv_pipe, or the first (in case this particular easy
- isn't already) */
- if(entry->easy == data) {
- if(Curl_recvpipe_head(data, easy_conn))
- entry->easy = easy_conn->recv_pipe.head->next->ptr;
- else
- entry->easy = easy_conn->recv_pipe.head->ptr;
- }
- }
- if(easy_conn->send_pipe.size > 1) {
- /* the handle should not be removed from the pipe yet */
- remove_sock_from_hash = FALSE;
-
- /* Update the sockhash entry to instead point to the next in line
- for the send_pipe, or the first (in case this particular easy
- isn't already) */
- if(entry->easy == data) {
- if(Curl_sendpipe_head(data, easy_conn))
- entry->easy = easy_conn->send_pipe.head->next->ptr;
- else
- entry->easy = easy_conn->send_pipe.head->ptr;
- }
- }
- /* Don't worry about overwriting recv_pipe head with send_pipe_head,
- when action will be asked on the socket (see multi_socket()), the
- head of the correct pipe will be taken according to the
- action. */
- }
-
- if(remove_sock_from_hash) {
- /* in this case 'entry' is always non-NULL */
+ int oldactions = data->actions[i];
+ /* this socket has been removed. Decrease user count */
+ entry->users--;
+ if(oldactions & CURL_POLL_OUT)
+ entry->writers--;
+ if(oldactions & CURL_POLL_IN)
+ entry->readers--;
+ if(!entry->users) {
if(multi->socket_cb)
- multi->socket_cb(data,
- s,
- CURL_POLL_REMOVE,
+ multi->socket_cb(data, s, CURL_POLL_REMOVE,
multi->socket_userp,
entry->socketp);
sh_delentry(&multi->sockhash, s);
}
- } /* if sockhash entry existed */
+ else {
+ /* remove this transfer as a user of this socket */
+ Curl_llist_remove(&entry->list, &data->sh_queue, NULL);
+ }
+ }
} /* for loop over numsocks */
memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
+ memcpy(data->actions, actions, num*sizeof(int));
data->numsocks = num;
return CURLM_OK;
}
@@ -2621,46 +2641,50 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
and just move on. */
;
else {
+ struct curl_llist *list = &entry->list;
+ struct curl_llist_element *e;
SIGPIPE_VARIABLE(pipe_st);
- data = entry->easy;
-
- if(data->magic != CURLEASY_MAGIC_NUMBER)
- /* bad bad bad bad bad bad bad */
- return CURLM_INTERNAL_ERROR;
-
- /* If the pipeline is enabled, take the handle which is in the head of
- the pipeline. If we should write into the socket, take the send_pipe
- head. If we should read from the socket, take the recv_pipe head. */
- if(data->easy_conn) {
- if((ev_bitmask & CURL_POLL_OUT) &&
- data->easy_conn->send_pipe.head)
- data = data->easy_conn->send_pipe.head->ptr;
- else if((ev_bitmask & CURL_POLL_IN) &&
- data->easy_conn->recv_pipe.head)
- data = data->easy_conn->recv_pipe.head->ptr;
- }
+ /* the socket can be shared by many transfers, iterate */
+ for(e = list->head; e; e = e->next) {
+ data = (struct Curl_easy *)e->ptr;
+
+ if(data->magic != CURLEASY_MAGIC_NUMBER)
+ /* bad bad bad bad bad bad bad */
+ return CURLM_INTERNAL_ERROR;
+
+ /* If the pipeline is enabled, take the handle which is in the head of
+ the pipeline. If we should write into the socket, take the
+ send_pipe head. If we should read from the socket, take the
+ recv_pipe head. */
+ if(data->conn) {
+ if((ev_bitmask & CURL_POLL_OUT) &&
+ data->conn->send_pipe.head)
+ data = data->conn->send_pipe.head->ptr;
+ else if((ev_bitmask & CURL_POLL_IN) &&
+ data->conn->recv_pipe.head)
+ data = data->conn->recv_pipe.head->ptr;
+ }
- if(data->easy_conn &&
- !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
- /* set socket event bitmask if they're not locked */
- data->easy_conn->cselect_bits = ev_bitmask;
+ if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
+ /* set socket event bitmask if they're not locked */
+ data->conn->cselect_bits = ev_bitmask;
- sigpipe_ignore(data, &pipe_st);
- result = multi_runsingle(multi, now, data);
- sigpipe_restore(&pipe_st);
+ sigpipe_ignore(data, &pipe_st);
+ result = multi_runsingle(multi, now, data);
+ sigpipe_restore(&pipe_st);
- if(data->easy_conn &&
- !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
- /* clear the bitmask only if not locked */
- data->easy_conn->cselect_bits = 0;
+ if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
+ /* clear the bitmask only if not locked */
+ data->conn->cselect_bits = 0;
- if(CURLM_OK >= result) {
- /* get the socket(s) and check if the state has been changed since
- last */
- result = singlesocket(multi, data);
- if(result)
- return result;
+ if(CURLM_OK >= result) {
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ result = singlesocket(multi, data);
+ if(result)
+ return result;
+ }
}
/* Now we fall-through and do the timer-based stuff, since we don't want
@@ -3004,6 +3028,9 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id id)
DEBUGASSERT(id < EXPIRE_LAST);
+ infof(data, "Expire in %ld ms for %x (transfer %p)\n",
+ (long)milli, id, data);
+
set = Curl_now();
set.tv_sec += milli/1000;
set.tv_usec += (unsigned int)(milli%1000)*1000;
@@ -3095,7 +3122,7 @@ void Curl_expire_clear(struct Curl_easy *data)
}
#ifdef DEBUGBUILD
- infof(data, "Expire cleared\n");
+ infof(data, "Expire cleared (transfer %p)\n", data);
#endif
nowp->tv_sec = 0;
nowp->tv_usec = 0;
diff --git a/lib/multiif.h b/lib/multiif.h
index e44646bf9..ed35ef427 100644
--- a/lib/multiif.h
+++ b/lib/multiif.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -31,7 +31,9 @@ void Curl_expire(struct Curl_easy *data, time_t milli, expire_id);
void Curl_expire_clear(struct Curl_easy *data);
void Curl_expire_done(struct Curl_easy *data, expire_id id);
bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits);
-void Curl_multi_handlePipeBreak(struct Curl_easy *data);
+void Curl_detach_connnection(struct Curl_easy *data);
+void Curl_attach_connnection(struct Curl_easy *data,
+ struct connectdata *conn);
void Curl_set_in_callback(struct Curl_easy *data, bool value);
bool Curl_is_in_callback(struct Curl_easy *easy);
diff --git a/lib/objnames-test08.sh b/lib/objnames-test08.sh
deleted file mode 100755
index 485975765..000000000
--- a/lib/objnames-test08.sh
+++ /dev/null
@@ -1,217 +0,0 @@
-#!/bin/sh
-# ***************************************************************************
-# * _ _ ____ _
-# * Project ___| | | | _ \| |
-# * / __| | | | |_) | |
-# * | (__| |_| | _ <| |___
-# * \___|\___/|_| \_\_____|
-# *
-# * Copyright (C) 2013, 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.
-# *
-# ***************************************************************************
-
-#
-# This Bourne shell script file is used by test case 1222 to do
-# unit testing of curl_8char_object_name() shell function which
-# is defined in file objnames.inc and sourced by this file and
-# any other shell script that may use it.
-#
-
-#
-# argument validation
-#
-
-if test $# -eq 1; then
- :
-else
- echo "Usage: ${0} srcdir"
- exit 1
-fi
-
-if test -f "${1}/runtests.pl"; then
- :
-else
- echo "${0}: Wrong srcdir"
- exit 1
-fi
-
-srcdir=${1}
-
-if test -f "$srcdir/../lib/objnames.inc"; then
- :
-else
- echo "$0: Missing objnames.inc"
- exit 1
-fi
-
-#
-# Some variables
-#
-
-logdir=log
-tstnum=1222
-
-list_c=$logdir/${tstnum}_list_c
-list_obj=$logdir/${tstnum}_list_obj
-list_obj_c=$logdir/${tstnum}_list_obj_c
-list_obj_uniq=$logdir/${tstnum}_list_obj_uniq
-
-
-#
-# Source curl_8char_object_name() function definition
-#
-
-. $srcdir/../lib/objnames.inc
-
-#
-# Some curl_8char_object_name() unit tests
-#
-
-echo 'Testing curl_8char_object_name...'
-echo ""
-
-argstr=123__678__ABC__FGH__KLM__PQRSTUV
-expect=16AFKPQR
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123__678__ABC__FGH__KLM__PQ.S.UV
-expect=16AFKPQ
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123__678__ABC..FGH..KLM..PQRSTUV
-expect=16ABC
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123__678_.ABC._FGH__KLM__PQRSTUV
-expect=16
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123.567.90ABCDEFGHIJKLMNOPQRSTUV
-expect=123
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=1234567.90A.CDEFGHIJKLMNOPQRSTUV
-expect=1234567
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=1234567890.BCD.FGHIJKLMNOPQRSTUV
-expect=12345678
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=12=45-78+0AB.DE.GHIJKLMNOPQRSTUV
-expect=1470AB
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=1234567890ABCDEFGHIJKLMNOPQRSTUV
-expect=12345678
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123_567_90A_CDE_GHIJKLMNOPQRSTUV
-expect=159CGHIJ
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123_567_90A_CDEFGHIJKLMNOPQRSTUV
-expect=159CDEFG
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123_567_90ABCDEFGHIJKLMNOPQRSTUV
-expect=1590ABCD
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123_567890ABCDEFGHIJKLMNOPQRSTUV
-expect=1567890A
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=1234567890ABCDEFGHIJKLMNOPQRSTUV
-expect=12345678
-outstr=`curl_8char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-#
-# Verify that generated object name is distinct for
-# all *.c source files in lib and src subdirectories.
-#
-
-ls $srcdir/../lib/*.c > $list_c
-ls $srcdir/../src/*.c >> $list_c
-
-rm -f $list_obj
-
-for c_fname in `cat $list_c`; do
- obj_name=`curl_8char_object_name $c_fname`
- echo "$obj_name" >> $list_obj
-done
-
-sort -u $list_obj > $list_obj_uniq
-
-cnt_c=`cat $list_c | wc -l`
-cnt_u=`cat $list_obj_uniq | wc -l`
-
-echo ""
-echo ""
-echo ""
-if test $cnt_c -eq $cnt_u; then
- echo "8-characters-or-less generated object names are unique."
- obj_name_clash="no"
-else
- echo "8-characters-or-less generated object names are clashing..."
- obj_name_clash="yes"
-fi
-
-if test $obj_name_clash = "yes"; then
- #
- # Show clashing object names and respective source file names
- #
- echo ""
- paste $list_obj $list_c | sort > $list_obj_c
- prev_match="no"
- prev_line="unknown"
- prev_obj_name="unknown"
- while read this_line; do
- obj_name=`echo "$this_line" | cut -f1`
- if test "x$obj_name" = "x$prev_obj_name"; then
- if test "x$prev_match" != "xyes"; then
- echo "$prev_line"
- echo "$this_line"
- prev_match="yes"
- else
- echo "$this_line"
- fi
- else
- prev_match="no"
- fi
- prev_line=$this_line
- prev_obj_name=$obj_name
- done < $list_obj_c
-fi
-
-rm -f $list_c
-rm -f $list_obj
-rm -f $list_obj_c
-rm -f $list_obj_uniq
-
-# end of objnames-test.sh
diff --git a/lib/objnames-test10.sh b/lib/objnames-test10.sh
deleted file mode 100755
index 62184b864..000000000
--- a/lib/objnames-test10.sh
+++ /dev/null
@@ -1,217 +0,0 @@
-#!/bin/sh
-# ***************************************************************************
-# * _ _ ____ _
-# * Project ___| | | | _ \| |
-# * / __| | | | |_) | |
-# * | (__| |_| | _ <| |___
-# * \___|\___/|_| \_\_____|
-# *
-# * Copyright (C) 2013, 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.
-# *
-# ***************************************************************************
-
-#
-# This Bourne shell script file is used by test case 1221 to do
-# unit testing of curl_10char_object_name() shell function which
-# is defined in file objnames.inc and sourced by this file and
-# any other shell script that may use it.
-#
-
-#
-# argument validation
-#
-
-if test $# -eq 1; then
- :
-else
- echo "Usage: ${0} srcdir"
- exit 1
-fi
-
-if test -f "${1}/runtests.pl"; then
- :
-else
- echo "${0}: Wrong srcdir"
- exit 1
-fi
-
-srcdir=${1}
-
-if test -f "$srcdir/../lib/objnames.inc"; then
- :
-else
- echo "$0: Missing objnames.inc"
- exit 1
-fi
-
-#
-# Some variables
-#
-
-logdir=log
-tstnum=1221
-
-list_c=$logdir/${tstnum}_list_c
-list_obj=$logdir/${tstnum}_list_obj
-list_obj_c=$logdir/${tstnum}_list_obj_c
-list_obj_uniq=$logdir/${tstnum}_list_obj_uniq
-
-
-#
-# Source curl_10char_object_name() function definition
-#
-
-. $srcdir/../lib/objnames.inc
-
-#
-# Some curl_10char_object_name() unit tests
-#
-
-echo 'Testing curl_10char_object_name...'
-echo ""
-
-argstr=123__678__ABC__FGH__KLM__PQRSTUV
-expect=16AFKPQRST
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123__678__ABC__FGH__KLM__PQ.S.UV
-expect=16AFKPQ
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123__678__ABC..FGH..KLM..PQRSTUV
-expect=16ABC
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123__678_.ABC._FGH__KLM__PQRSTUV
-expect=16
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123.567.90ABCDEFGHIJKLMNOPQRSTUV
-expect=123
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=1234567.90A.CDEFGHIJKLMNOPQRSTUV
-expect=1234567
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=1234567890.BCD.FGHIJKLMNOPQRSTUV
-expect=1234567890
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=12=45-78+0AB.DE.GHIJKLMNOPQRSTUV
-expect=1470AB
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=1234567890ABCDEFGHIJKLMNOPQRSTUV
-expect=1234567890
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123_567_90A_CDE_GHIJKLMNOPQRSTUV
-expect=159CGHIJKL
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123_567_90A_CDEFGHIJKLMNOPQRSTUV
-expect=159CDEFGHI
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123_567_90ABCDEFGHIJKLMNOPQRSTUV
-expect=1590ABCDEF
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=123_567890ABCDEFGHIJKLMNOPQRSTUV
-expect=1567890ABC
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-argstr=1234567890ABCDEFGHIJKLMNOPQRSTUV
-expect=1234567890
-outstr=`curl_10char_object_name $argstr`
-echo "result: $outstr expected: $expect input: $argstr"
-
-#
-# Verify that generated object name is distinct for
-# all *.c source files in lib and src subdirectories.
-#
-
-ls $srcdir/../lib/*.c > $list_c
-ls $srcdir/../src/*.c >> $list_c
-
-rm -f $list_obj
-
-for c_fname in `cat $list_c`; do
- obj_name=`curl_10char_object_name $c_fname`
- echo "$obj_name" >> $list_obj
-done
-
-sort -u $list_obj > $list_obj_uniq
-
-cnt_c=`cat $list_c | wc -l`
-cnt_u=`cat $list_obj_uniq | wc -l`
-
-echo ""
-echo ""
-echo ""
-if test $cnt_c -eq $cnt_u; then
- echo "10-characters-or-less generated object names are unique."
- obj_name_clash="no"
-else
- echo "10-characters-or-less generated object names are clashing..."
- obj_name_clash="yes"
-fi
-
-if test $obj_name_clash = "yes"; then
- #
- # Show clashing object names and respective source file names
- #
- echo ""
- paste $list_obj $list_c | sort > $list_obj_c
- prev_match="no"
- prev_line="unknown"
- prev_obj_name="unknown"
- while read this_line; do
- obj_name=`echo "$this_line" | cut -f1`
- if test "x$obj_name" = "x$prev_obj_name"; then
- if test "x$prev_match" != "xyes"; then
- echo "$prev_line"
- echo "$this_line"
- prev_match="yes"
- else
- echo "$this_line"
- fi
- else
- prev_match="no"
- fi
- prev_line=$this_line
- prev_obj_name=$obj_name
- done < $list_obj_c
-fi
-
-rm -f $list_c
-rm -f $list_obj
-rm -f $list_obj_c
-rm -f $list_obj_uniq
-
-# end of objnames-test10.sh
diff --git a/lib/objnames.inc b/lib/objnames.inc
deleted file mode 100644
index e362f6e8e..000000000
--- a/lib/objnames.inc
+++ /dev/null
@@ -1,107 +0,0 @@
-# ***************************************************************************
-# * _ _ ____ _
-# * Project ___| | | | _ \| |
-# * / __| | | | |_) | |
-# * | (__| |_| | _ <| |___
-# * \___|\___/|_| \_\_____|
-# *
-# * Copyright (C) 2012 - 2017, 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.
-# *
-# ***************************************************************************
-
-#
-# This file is sourced from curl/packages/OS400/initscript.sh and
-# other Bourne shell scripts. Keep it as portable as possible.
-#
-
-#
-# curl_10char_object_name
-#
-# This shell function accepts a single string argument with unspecified
-# length representing a (*.c) source file name and returns a string which
-# is a transformation of given argument.
-#
-# The intended purpose of this function is to transliterate a (*.c) source
-# file name that may be longer than 10 characters, or not, into a string
-# with at most 10 characters which may be used as an OS/400 object name.
-#
-# This function might not be universally useful, nor we care about it.
-#
-# It is intended to be used with libcurl's (*.c) source file names, so
-# dependency on libcurl's source file naming scheme is acceptable and
-# good enough for its intended use. Specifically it makes use of the fact
-# that libcurl's (*.c) source file names which may be longer than 10 chars
-# are conformed with underscore '_' separated substrings, or separated by
-# other character which does not belong to the [0-9], [a-z] or [A-Z] sets.
-#
-# This allows repeatable and automatic short object name generation with
-# no need for a hardcoded mapping table.
-#
-# Transformation is done in the following way:
-#
-# 1) Leading directory components are removed.
-# 2) Leftmost dot character and any other char following it are removed.
-# 3) Lowercase characters are transliterated to uppercase.
-# 4) Characters not in [A-Z] or [0-9] are transliterated to underscore '_'.
-# 5) Every sequence of one or more underscores is replaced with a single one.
-# 6) Five leftmost substrings which end in an underscore character are
-# replaced by the first character of each substring, while retaining
-# the rest of the string.
-# 7) Finally the result is truncated to 10 characters.
-#
-# Resulting object name may be shorter than 10 characters.
-#
-# Test case 1221 does unit testng of this function and also verifies
-# that it is possible to generate distinct short object names for all
-# curl and libcurl *.c source file names.
-#
-
-curl_10char_object_name() {
- echo "${1}" | \
- sed -e 's:.*/::' \
- -e 's:[.].*::' \
- -e 'y:abcdefghijklmnopqrstuvwxyz:ABCDEFGHIJKLMNOPQRSTUVWXYZ:' \
- -e 's:[^ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_]:_:g' \
- -e 's:__*:_:g' \
- -e 's:\([^_]\)[^_]*_\(.*\):\1\2:' \
- -e 's:\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3:' \
- -e 's:\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4:' \
- -e 's:\([^_]\)\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4\5:' \
- -e 's:\([^_]\)\([^_]\)\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4\5\6:' \
- -e 's:^\(..........\).*:\1:'
-}
-
-#
-# curl_8char_object_name
-#
-# Same as curl_10char_object_name() description and details above, except
-# that object name is limited to 8 characters maximum.
-#
-
-curl_8char_object_name() {
- echo "${1}" | \
- sed -e 's:.*/::' \
- -e 's:[.].*::' \
- -e 'y:abcdefghijklmnopqrstuvwxyz:ABCDEFGHIJKLMNOPQRSTUVWXYZ:' \
- -e 's:[^ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890_]:_:g' \
- -e 's:__*:_:g' \
- -e 's:\([^_]\)[^_]*_\(.*\):\1\2:' \
- -e 's:\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3:' \
- -e 's:\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4:' \
- -e 's:\([^_]\)\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4\5:' \
- -e 's:\([^_]\)\([^_]\)\([^_]\)\([^_]\)\([^_]\)[^_]*_\(.*\):\1\2\3\4\5\6:' \
- -e 's:^\(........\).*:\1:'
-}
-
-# end of objectname.inc
diff --git a/lib/pingpong.c b/lib/pingpong.c
index 2e93d201f..e9568ee3d 100644
--- a/lib/pingpong.c
+++ b/lib/pingpong.c
@@ -44,7 +44,7 @@
/* Returns timeout in ms. 0 or negative number means the timeout has already
triggered */
-time_t Curl_pp_state_timeout(struct pingpong *pp)
+time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting)
{
struct connectdata *conn = pp->conn;
struct Curl_easy *data = conn->data;
@@ -62,7 +62,7 @@ time_t Curl_pp_state_timeout(struct pingpong *pp)
timeout_ms = response_time -
Curl_timediff(Curl_now(), pp->response); /* spent time */
- if(data->set.timeout) {
+ 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 */
Curl_timediff(Curl_now(), conn->now); /* spent time */
@@ -77,13 +77,14 @@ time_t Curl_pp_state_timeout(struct pingpong *pp)
/*
* Curl_pp_statemach()
*/
-CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
+CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
+ bool disconnecting)
{
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);
+ time_t timeout_ms = Curl_pp_state_timeout(pp, disconnecting);
struct Curl_easy *data = conn->data;
CURLcode result = CURLE_OK;
diff --git a/lib/pingpong.h b/lib/pingpong.h
index 5ac8df876..dbe1f8d3d 100644
--- a/lib/pingpong.h
+++ b/lib/pingpong.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2018, 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,14 +81,15 @@ struct pingpong {
* called repeatedly until done. Set 'wait' to make it wait a while on the
* socket if there's no traffic.
*/
-CURLcode Curl_pp_statemach(struct pingpong *pp, bool block);
+CURLcode Curl_pp_statemach(struct pingpong *pp, bool block,
+ bool disconnecting);
/* initialize stuff to prepare for reading a fresh new response */
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);
+time_t Curl_pp_state_timeout(struct pingpong *pp, bool disconnecting);
/***********************************************************************
diff --git a/lib/pop3.c b/lib/pop3.c
index 6af4626d4..49474157e 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -208,7 +208,7 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
/* Are we processing CAPA command responses? */
if(pop3c->state == POP3_CAPA) {
/* Do we have the terminating line? */
- if(len >= 1 && !memcmp(line, ".", 1))
+ if(len >= 1 && line[0] == '.')
/* Treat the response as a success */
*resp = '+';
else
@@ -226,7 +226,7 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
}
/* Do we have a continuation response? */
- if(len >= 1 && !memcmp("+", line, 1)) {
+ if(len >= 1 && line[0] == '+') {
*resp = '*';
return TRUE;
@@ -1025,19 +1025,20 @@ static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
return result;
}
- result = Curl_pp_statemach(&pop3c->pp, FALSE);
+ result = Curl_pp_statemach(&pop3c->pp, FALSE, FALSE);
*done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
return result;
}
-static CURLcode pop3_block_statemach(struct connectdata *conn)
+static CURLcode pop3_block_statemach(struct connectdata *conn,
+ bool disconnecting)
{
CURLcode result = CURLE_OK;
struct pop3_conn *pop3c = &conn->proto.pop3c;
while(pop3c->state != POP3_STOP && !result)
- result = Curl_pp_statemach(&pop3c->pp, TRUE);
+ result = Curl_pp_statemach(&pop3c->pp, TRUE, disconnecting);
return result;
}
@@ -1235,7 +1236,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn, bool dead_connection)
point! */
if(!dead_connection && pop3c->pp.conn && pop3c->pp.conn->bits.protoconnstart)
if(!pop3_perform_quit(conn))
- (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
+ (void)pop3_block_statemach(conn, TRUE); /* ignore errors on QUIT */
/* Disconnect from the server */
Curl_pp_disconnect(&pop3c->pp);
diff --git a/lib/setopt.c b/lib/setopt.c
index 1627aba6d..d98ca66c9 100644
--- a/lib/setopt.c
+++ b/lib/setopt.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -803,12 +803,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
if(checkprefix("Set-Cookie:", argptr))
/* HTTP Header format line */
Curl_cookie_add(data, data->cookies, TRUE, FALSE, argptr + 11, NULL,
- NULL);
+ NULL, TRUE);
else
/* Netscape format line */
Curl_cookie_add(data, data->cookies, FALSE, FALSE, argptr, NULL,
- NULL);
+ NULL, TRUE);
Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
free(argptr);
@@ -860,6 +860,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.expect_100_timeout = arg;
break;
+ case CURLOPT_HTTP09_ALLOWED:
+ arg = va_arg(param, unsigned long);
+ if(arg > 1L)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ data->set.http09_allowed = arg ? TRUE : FALSE;
+ break;
#endif /* CURL_DISABLE_HTTP */
case CURLOPT_HTTPAUTH:
@@ -1693,8 +1699,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
TRUE : FALSE;
/* Update the current connection ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->ssl_config.verifypeer =
+ if(data->conn) {
+ data->conn->ssl_config.verifypeer =
data->set.ssl.primary.verifypeer;
}
break;
@@ -1706,8 +1712,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
(0 != va_arg(param, long))?TRUE:FALSE;
/* Update the current connection proxy_ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->proxy_ssl_config.verifypeer =
+ if(data->conn) {
+ data->conn->proxy_ssl_config.verifypeer =
data->set.proxy_ssl.primary.verifypeer;
}
break;
@@ -1730,8 +1736,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.ssl.primary.verifyhost = (0 != arg) ? TRUE : FALSE;
/* Update the current connection ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->ssl_config.verifyhost =
+ if(data->conn) {
+ data->conn->ssl_config.verifyhost =
data->set.ssl.primary.verifyhost;
}
break;
@@ -1754,8 +1760,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
data->set.proxy_ssl.primary.verifyhost = (0 != arg)?TRUE:FALSE;
/* Update the current connection proxy_ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->proxy_ssl_config.verifyhost =
+ if(data->conn) {
+ data->conn->proxy_ssl_config.verifyhost =
data->set.proxy_ssl.primary.verifyhost;
}
break;
@@ -1772,8 +1778,8 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
TRUE : FALSE;
/* Update the current connection ssl_config. */
- if(data->easy_conn) {
- data->easy_conn->ssl_config.verifystatus =
+ if(data->conn) {
+ data->conn->ssl_config.verifystatus =
data->set.ssl.primary.verifystatus;
}
break;
@@ -2231,7 +2237,7 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
result = Curl_setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
va_arg(param, char *));
break;
-#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+
case CURLOPT_SSH_KNOWNHOSTS:
/*
* Store the file name to read known hosts from.
@@ -2252,7 +2258,6 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
*/
data->set.ssh_keyfunc_userp = va_arg(param, void *);
break;
-#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
#endif /* USE_LIBSSH2 */
case CURLOPT_HTTP_TRANSFER_DECODING:
@@ -2636,6 +2641,16 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
return CURLE_BAD_FUNCTION_ARGUMENT;
data->set.upkeep_interval_ms = arg;
break;
+ case CURLOPT_TRAILERFUNCTION:
+#ifndef CURL_DISABLE_HTTP
+ data->set.trailer_callback = va_arg(param, curl_trailer_callback);
+#endif
+ break;
+ case CURLOPT_TRAILERDATA:
+#ifndef CURL_DISABLE_HTTP
+ data->set.trailer_data = va_arg(param, void *);
+#endif
+ break;
default:
/* unknown tag and its companion, just ignore: */
result = CURLE_UNKNOWN_OPTION;
diff --git a/lib/sigpipe.h b/lib/sigpipe.h
index 800f9d3b4..3960a139d 100644
--- a/lib/sigpipe.h
+++ b/lib/sigpipe.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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,7 +23,8 @@
***************************************************************************/
#include "curl_setup.h"
-#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && defined(USE_OPENSSL)
+#if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && \
+ (defined(USE_OPENSSL) || defined(USE_MBEDTLS))
#include <signal.h>
struct sigpipe_ignore {
diff --git a/lib/smb.c b/lib/smb.c
index e4f266e19..76c99a230 100644
--- a/lib/smb.c
+++ b/lib/smb.c
@@ -947,15 +947,10 @@ static int smb_getsock(struct connectdata *conn, curl_socket_t *socks,
static CURLcode smb_do(struct connectdata *conn, bool *done)
{
struct smb_conn *smbc = &conn->proto.smbc;
- struct smb_request *req = conn->data->req.protop;
*done = FALSE;
if(smbc->share) {
- req->path = strchr(smbc->share, '\0');
- if(req->path) {
- req->path++;
- return CURLE_OK;
- }
+ return CURLE_OK;
}
return CURLE_URL_MALFORMAT;
}
@@ -964,6 +959,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
{
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
+ struct smb_request *req = data->req.protop;
struct smb_conn *smbc = &conn->proto.smbc;
char *path;
char *slash;
@@ -992,6 +988,7 @@ static CURLcode smb_parse_url_path(struct connectdata *conn)
/* Parse the path for the file path converting any forward slashes into
backslashes */
*slash++ = 0;
+ req->path = slash;
for(; *slash; slash++) {
if(*slash == '/')
diff --git a/lib/smtp.c b/lib/smtp.c
index 4911ece7b..63f4d468f 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -207,8 +207,12 @@ static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
Section 4. Examples of RFC-4954 but some e-mail servers ignore this and
only send the response code instead as per Section 4.2. */
if(line[3] == ' ' || len == 5) {
+ char tmpline[6];
+
result = TRUE;
- *resp = curlx_sltosi(strtol(line, NULL, 10));
+ memset(tmpline, '\0', sizeof(tmpline));
+ memcpy(tmpline, line, (len == 5 ? 5 : 3));
+ *resp = curlx_sltosi(strtol(tmpline, NULL, 10));
/* Make sure real server never sends internal value */
if(*resp == 1)
@@ -1080,19 +1084,20 @@ static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
return result;
}
- result = Curl_pp_statemach(&smtpc->pp, FALSE);
+ result = Curl_pp_statemach(&smtpc->pp, FALSE, FALSE);
*done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
return result;
}
-static CURLcode smtp_block_statemach(struct connectdata *conn)
+static CURLcode smtp_block_statemach(struct connectdata *conn,
+ bool disconnecting)
{
CURLcode result = CURLE_OK;
struct smtp_conn *smtpc = &conn->proto.smtpc;
while(smtpc->state != SMTP_STOP && !result)
- result = Curl_pp_statemach(&smtpc->pp, TRUE);
+ result = Curl_pp_statemach(&smtpc->pp, TRUE, disconnecting);
return result;
}
@@ -1253,7 +1258,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
the smtp_multi_statemach function but we have no general support for
non-blocking DONE operations!
*/
- result = smtp_block_statemach(conn);
+ result = smtp_block_statemach(conn, FALSE);
}
/* Clear the transfer mode for the next request */
@@ -1360,7 +1365,7 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection)
point! */
if(!dead_connection && smtpc->pp.conn && smtpc->pp.conn->bits.protoconnstart)
if(!smtp_perform_quit(conn))
- (void)smtp_block_statemach(conn); /* ignore errors on QUIT */
+ (void)smtp_block_statemach(conn, TRUE); /* ignore errors on QUIT */
/* Disconnect from the server */
Curl_pp_disconnect(&smtpc->pp);
diff --git a/lib/ssh-libssh.c b/lib/ssh-libssh.c
index 2d7b1cfa2..718c0d343 100644
--- a/lib/ssh-libssh.c
+++ b/lib/ssh-libssh.c
@@ -95,6 +95,13 @@
#include "memdebug.h"
#include "curl_path.h"
+/* A recent macro provided by libssh. Or make our own. */
+#ifndef SSH_STRING_FREE_CHAR
+/* !checksrc! disable ASSIGNWITHINCONDITION 1 */
+#define SSH_STRING_FREE_CHAR(x) \
+ do { if((x) != NULL) { ssh_string_free_char(x); x = NULL; } } while(0)
+#endif
+
/* Local functions: */
static CURLcode myssh_connect(struct connectdata *conn, bool *done);
static CURLcode myssh_multi_statemach(struct connectdata *conn,
@@ -549,6 +556,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
struct Curl_easy *data = conn->data;
struct SSHPROTO *protop = data->req.protop;
struct ssh_conn *sshc = &conn->proto.sshc;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
int rc = SSH_NO_ERROR, err;
char *new_readdir_line;
int seekerr = CURL_SEEKFUNC_OK;
@@ -792,7 +800,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
- conn->sockfd = ssh_get_fd(sshc->ssh_session);
+ conn->sockfd = sock;
conn->writesockfd = CURL_SOCKET_BAD;
if(conn->handler->protocol == CURLPROTO_SFTP) {
@@ -1661,7 +1669,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
sshc->sftp_session = NULL;
}
- Curl_safefree(sshc->homedir);
+ SSH_STRING_FREE_CHAR(sshc->homedir);
conn->data->state.most_recent_ftp_entrypath = NULL;
state(conn, SSH_SESSION_DISCONNECT);
@@ -1829,7 +1837,7 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
ssh_disconnect(sshc->ssh_session);
- Curl_safefree(sshc->homedir);
+ SSH_STRING_FREE_CHAR(sshc->homedir);
conn->data->state.most_recent_ftp_entrypath = NULL;
state(conn, SSH_SESSION_FREE);
@@ -1866,14 +1874,11 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
Curl_safefree(sshc->rsa_pub);
Curl_safefree(sshc->rsa);
-
Curl_safefree(sshc->quote_path1);
Curl_safefree(sshc->quote_path2);
-
- Curl_safefree(sshc->homedir);
-
Curl_safefree(sshc->readdir_line);
Curl_safefree(sshc->readdir_linkPath);
+ SSH_STRING_FREE_CHAR(sshc->homedir);
/* the code we are about to return */
result = sshc->actualcode;
@@ -2048,6 +2053,7 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
{
struct ssh_conn *ssh;
CURLcode result;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
struct Curl_easy *data = conn->data;
int rc;
@@ -2076,6 +2082,8 @@ static CURLcode myssh_connect(struct connectdata *conn, bool *done)
return CURLE_FAILED_INIT;
}
+ ssh_options_set(ssh->ssh_session, SSH_OPTIONS_FD, &sock);
+
if(conn->user) {
infof(data, "User: %s\n", conn->user);
ssh_options_set(ssh->ssh_session, SSH_OPTIONS_USER, conn->user);
diff --git a/lib/ssh.c b/lib/ssh.c
index dc86e0a2f..910616bb6 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -667,7 +667,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
break;
}
if(rc) {
- failf(data, "Failure establishing ssh session");
+ char *err_msg = NULL;
+ (void)libssh2_session_last_error(sshc->ssh_session, &err_msg, NULL, 0);
+ failf(data, "Failure establishing ssh session: %d, %s", rc, err_msg);
+
state(conn, SSH_SESSION_FREE);
sshc->actualcode = CURLE_FAILED_INIT;
break;
diff --git a/lib/timeval.c b/lib/timeval.c
index dce1a761e..2569f175c 100644
--- a/lib/timeval.c
+++ b/lib/timeval.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -21,29 +21,45 @@
***************************************************************************/
#include "timeval.h"
+#include "system_win32.h"
#if defined(WIN32) && !defined(MSDOS)
struct curltime Curl_now(void)
{
- /*
- ** GetTickCount() is available on _all_ Windows versions from W95 up
- ** to nowadays. Returns milliseconds elapsed since last system boot,
- ** increases monotonically and wraps once 49.7 days have elapsed.
- */
struct curltime now;
-#if !defined(_WIN32_WINNT) || !defined(_WIN32_WINNT_VISTA) || \
- (_WIN32_WINNT < _WIN32_WINNT_VISTA) || \
- (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
- DWORD milliseconds = GetTickCount();
- now.tv_sec = milliseconds / 1000;
- now.tv_usec = (milliseconds % 1000) * 1000;
-#else
- ULONGLONG milliseconds = GetTickCount64();
- now.tv_sec = (time_t) (milliseconds / 1000);
- now.tv_usec = (unsigned int) (milliseconds % 1000) * 1000;
+ static LARGE_INTEGER freq;
+ static int isVistaOrGreater = -1;
+ if(isVistaOrGreater == -1) {
+ if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
+ VERSION_GREATER_THAN_EQUAL)) {
+ isVistaOrGreater = 1;
+ QueryPerformanceFrequency(&freq);
+ }
+ else
+ isVistaOrGreater = 0;
+ }
+ if(isVistaOrGreater == 1) { /* QPC timer might have issues pre-Vista */
+ LARGE_INTEGER count;
+ QueryPerformanceCounter(&count);
+ now.tv_sec = (time_t)(count.QuadPart / freq.QuadPart);
+ now.tv_usec =
+ (int)((count.QuadPart % freq.QuadPart) * 1000000 / freq.QuadPart);
+ }
+ else {
+ /* Disable /analyze warning that GetTickCount64 is preferred */
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable:28159)
+#endif
+ DWORD milliseconds = GetTickCount();
+#if defined(_MSC_VER)
+#pragma warning(pop)
#endif
+ now.tv_sec = milliseconds / 1000;
+ now.tv_usec = (milliseconds % 1000) * 1000;
+ }
return now;
}
@@ -180,7 +196,7 @@ struct curltime Curl_now(void)
*/
timediff_t Curl_timediff(struct curltime newer, struct curltime older)
{
- timediff_t diff = newer.tv_sec-older.tv_sec;
+ timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
if(diff >= (TIME_MAX/1000))
return TIME_MAX;
else if(diff <= (TIME_MIN/1000))
@@ -194,7 +210,7 @@ timediff_t Curl_timediff(struct curltime newer, struct curltime older)
*/
timediff_t Curl_timediff_us(struct curltime newer, struct curltime older)
{
- timediff_t diff = newer.tv_sec-older.tv_sec;
+ timediff_t diff = (timediff_t)newer.tv_sec-older.tv_sec;
if(diff >= (TIME_MAX/1000000))
return TIME_MAX;
else if(diff <= (TIME_MIN/1000000))
diff --git a/lib/timeval.h b/lib/timeval.h
index fb3f680c4..96867d713 100644
--- a/lib/timeval.h
+++ b/lib/timeval.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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,8 +26,10 @@
#if SIZEOF_TIME_T < 8
typedef int timediff_t;
+#define CURL_FORMAT_TIMEDIFF_T "d"
#else
typedef curl_off_t timediff_t;
+#define CURL_FORMAT_TIMEDIFF_T CURL_FORMAT_CURL_OFF_T
#endif
struct curltime {
diff --git a/lib/transfer.c b/lib/transfer.c
index c50809785..5d85f3d6b 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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,6 +117,35 @@ CURLcode Curl_get_upload_buffer(struct Curl_easy *data)
return CURLE_OK;
}
+#ifndef CURL_DISABLE_HTTP
+/*
+ * This function will be called to loop through the trailers buffer
+ * until no more data is available for sending.
+ */
+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;
+ 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],
+ to_copy);
+ data->state.trailers_bytes_sent += to_copy;
+ }
+ return to_copy;
+}
+
+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;
+}
+#endif
+
/*
* This function will call the read callback to fill our buffer with data
* to upload.
@@ -127,6 +156,17 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
struct Curl_easy *data = conn->data;
size_t buffersize = bytes;
size_t nread;
+
+#ifndef CURL_DISABLE_HTTP
+ struct curl_slist *trailers = NULL;
+ CURLcode c;
+ int trailers_ret_code;
+#endif
+
+ curl_read_callback readfunc = NULL;
+ void *extra_data = NULL;
+ bool added_crlf = FALSE;
+
#ifdef CURL_DOES_CONVERSIONS
bool sending_http_headers = FALSE;
@@ -140,15 +180,71 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
}
#endif
- if(data->req.upload_chunky) {
+#ifndef CURL_DISABLE_HTTP
+ if(data->state.trailers_state == TRAILERS_INITIALIZED) {
+ /* at this point we already verified that the callback exists
+ so we compile and store the trailers buffer, then proceed */
+ 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;
+ }
+ data->state.trailers_bytes_sent = 0;
+ Curl_set_in_callback(data, true);
+ trailers_ret_code = data->set.trailer_callback(&trailers,
+ data->set.trailer_data);
+ Curl_set_in_callback(data, false);
+ if(trailers_ret_code == CURL_TRAILERFUNC_OK) {
+ c = Curl_http_compile_trailers(trailers, data->state.trailers_buf, data);
+ }
+ else {
+ failf(data, "operation aborted by trailing headers callback");
+ *nreadp = 0;
+ c = CURLE_ABORTED_BY_CALLBACK;
+ }
+ if(c != CURLE_OK) {
+ Curl_add_buffer_free(&data->state.trailers_buf);
+ curl_slist_free_all(trailers);
+ return c;
+ }
+ infof(data, "Successfully compiled trailers.\r\n");
+ curl_slist_free_all(trailers);
+ }
+#endif
+
+ /* if we are transmitting trailing data, we don't need to write
+ a chunk size so we skip this */
+ if(data->req.upload_chunky &&
+ data->state.trailers_state == TRAILERS_NONE) {
/* if chunked Transfer-Encoding */
buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */
}
+#ifndef CURL_DISABLE_HTTP
+ if(data->state.trailers_state == TRAILERS_SENDING) {
+ /* if we're here then that means that we already sent the last empty chunk
+ but we didn't send a final CR LF, so we sent 0 CR LF. We then start
+ pulling trailing data until we ²have no more at which point we
+ simply return to the previous point in the state machine as if
+ nothing happened.
+ */
+ readfunc = Curl_trailers_read;
+ extra_data = (void *)data;
+ }
+ else
+#endif
+ {
+ readfunc = data->state.fread_func;
+ extra_data = data->state.in;
+ }
+
Curl_set_in_callback(data, true);
- nread = data->state.fread_func(data->req.upload_fromhere, 1,
- buffersize, data->state.in);
+ nread = readfunc(data->req.upload_fromhere, 1,
+ buffersize, extra_data);
Curl_set_in_callback(data, false);
if(nread == CURL_READFUNC_ABORT) {
@@ -203,7 +299,7 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
char hexbuffer[11];
const char *endofline_native;
const char *endofline_network;
- int hexlen;
+ int hexlen = 0;
if(
#ifdef CURL_DO_LINEEND_CONV
@@ -218,20 +314,36 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
endofline_native = "\r\n";
endofline_network = "\x0d\x0a";
}
- hexlen = msnprintf(hexbuffer, sizeof(hexbuffer),
- "%x%s", nread, endofline_native);
- /* move buffer pointer */
- data->req.upload_fromhere -= hexlen;
- nread += hexlen;
+ /* if we're not handling trailing data, proceed as usual */
+ if(data->state.trailers_state != TRAILERS_SENDING) {
+ hexlen = msnprintf(hexbuffer, sizeof(hexbuffer),
+ "%zx%s", nread, endofline_native);
- /* copy the prefix to the buffer, leaving out the NUL */
- memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+ /* move buffer pointer */
+ data->req.upload_fromhere -= hexlen;
+ nread += hexlen;
- /* always append ASCII CRLF to the data */
- memcpy(data->req.upload_fromhere + nread,
- endofline_network,
- strlen(endofline_network));
+ /* copy the prefix to the buffer, leaving out the NUL */
+ memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+
+ /* always append ASCII CRLF to the data unless
+ we have a valid trailer callback */
+#ifndef CURL_DISABLE_HTTP
+ if((nread-hexlen) == 0 &&
+ data->set.trailer_callback != NULL &&
+ data->state.trailers_state == TRAILERS_NONE) {
+ data->state.trailers_state = TRAILERS_INITIALIZED;
+ }
+ else
+#endif
+ {
+ memcpy(data->req.upload_fromhere + nread,
+ endofline_network,
+ strlen(endofline_network));
+ added_crlf = TRUE;
+ }
+ }
#ifdef CURL_DOES_CONVERSIONS
{
@@ -251,13 +363,29 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, size_t bytes,
}
#endif /* CURL_DOES_CONVERSIONS */
- if((nread - hexlen) == 0) {
- /* mark this as done once this chunk is transferred */
+#ifndef CURL_DISABLE_HTTP
+ if(data->state.trailers_state == TRAILERS_SENDING &&
+ !Curl_trailers_left(data)) {
+ Curl_add_buffer_free(&data->state.trailers_buf);
+ data->state.trailers_state = TRAILERS_DONE;
+ data->set.trailer_data = NULL;
+ data->set.trailer_callback = NULL;
+ /* mark the transfer as done */
data->req.upload_done = TRUE;
- infof(data, "Signaling end of chunked upload via terminating chunk.\n");
+ infof(data, "Signaling end of chunked upload after trailers.\n");
}
+ else
+#endif
+ if((nread - hexlen) == 0 &&
+ data->state.trailers_state != TRAILERS_INITIALIZED) {
+ /* mark this as done once this chunk is transferred */
+ data->req.upload_done = TRUE;
+ infof(data,
+ "Signaling end of chunked upload via terminating chunk.\n");
+ }
- nread += strlen(endofline_native); /* for the added end of line */
+ if(added_crlf)
+ nread += strlen(endofline_network); /* for the added end of line */
}
#ifdef CURL_DOES_CONVERSIONS
else if((data->set.prefer_ascii) && (!sending_http_headers)) {
@@ -925,7 +1053,6 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
*didwhat |= KEEP_SEND;
do {
-
/* only read more data if there's no upload data already
present in the upload buffer */
if(0 == k->upload_present) {
@@ -950,7 +1077,6 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
k->keepon &= ~KEEP_SEND; /* disable writing */
k->start100 = Curl_now(); /* timeout count starts now */
*didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
-
/* set a timeout for the multi interface */
Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT);
break;
@@ -1224,15 +1350,15 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if(k->keepon) {
if(0 > Curl_timeleft(data, &k->now, FALSE)) {
if(k->size != -1) {
- failf(data, "Operation timed out after %ld milliseconds with %"
- CURL_FORMAT_CURL_OFF_T " out of %"
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " out of %"
CURL_FORMAT_CURL_OFF_T " bytes received",
Curl_timediff(k->now, data->progress.t_startsingle),
k->bytecount, k->size);
}
else {
- failf(data, "Operation timed out after %ld milliseconds with %"
- CURL_FORMAT_CURL_OFF_T " bytes received",
+ failf(data, "Operation timed out after %" CURL_FORMAT_TIMEDIFF_T
+ " milliseconds with %" CURL_FORMAT_CURL_OFF_T " bytes received",
Curl_timediff(k->now, data->progress.t_startsingle),
k->bytecount);
}
@@ -1432,12 +1558,6 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
Curl_pgrsResetTransferSizes(data);
Curl_pgrsStartNow(data);
- if(data->set.timeout)
- Curl_expire(data, data->set.timeout, EXPIRE_TIMEOUT);
-
- if(data->set.connecttimeout)
- Curl_expire(data, data->set.connecttimeout, EXPIRE_CONNECTTIMEOUT);
-
/* In case the handle is re-used and an authentication method was picked
in the session we need to make sure we only use the one(s) we now
consider to be fine */
diff --git a/lib/url.c b/lib/url.c
index 7839dfa7c..d5a982008 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -492,9 +492,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
/* Set the default CA cert bundle/path detected/specified at build time.
*
- * If Schannel (WinSSL) is the selected SSL backend then these locations
- * are ignored. We allow setting CA location for schannel only when
- * explicitly specified by the user via CURLOPT_CAINFO / --cacert.
+ * If Schannel is the selected SSL backend then these locations are
+ * ignored. We allow setting CA location for schannel only when explicitly
+ * specified by the user via CURLOPT_CAINFO / --cacert.
*/
if(Curl_ssl_backend() != CURLSSLBACKEND_SCHANNEL) {
#if defined(CURL_CA_BUNDLE)
@@ -536,6 +536,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->fnmatch = ZERO_NULL;
set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+ set->http09_allowed = TRUE;
set->httpversion =
#ifdef USE_NGHTTP2
CURL_HTTP_VERSION_2TLS
@@ -768,7 +769,6 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
return CURLE_OK;
}
- conn->data = data;
if(conn->dns_entry != NULL) {
Curl_resolv_unlock(data, conn->dns_entry);
conn->dns_entry = NULL;
@@ -781,20 +781,22 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
Curl_http_ntlm_cleanup(conn);
#endif
+ /* the protocol specific disconnect handler needs a transfer for its
+ connection! */
+ conn->data = data;
if(conn->handler->disconnect)
/* This is set if protocol-specific cleanups should be made */
conn->handler->disconnect(conn, dead_connection);
/* unlink ourselves! */
infof(data, "Closing connection %ld\n", conn->connection_id);
- Curl_conncache_remove_conn(conn, TRUE);
+ Curl_conncache_remove_conn(data, conn, TRUE);
free_idnconverted_hostname(&conn->host);
free_idnconverted_hostname(&conn->conn_to_host);
free_idnconverted_hostname(&conn->http_proxy.host);
free_idnconverted_hostname(&conn->socks_proxy.host);
- DEBUGASSERT(conn->data == data);
/* this assumes that the pointer is still there after the connection was
detected from the cache */
Curl_ssl_close(conn, FIRSTSOCKET);
@@ -959,13 +961,10 @@ static bool extract_if_dead(struct connectdata *conn,
handles in pipeline and the connection isn't already marked in
use */
bool dead;
-
- conn->data = data;
if(conn->handler->connection_check) {
/* The protocol has a special method for checking the state of the
connection. Use it to check if the connection is dead. */
unsigned int state;
-
state = conn->handler->connection_check(conn, CONNCHECK_ISDEAD);
dead = (state & CONNRESULT_DEAD);
}
@@ -976,8 +975,7 @@ static bool extract_if_dead(struct connectdata *conn,
if(dead) {
infof(data, "Connection %ld seems to be dead!\n", conn->connection_id);
- Curl_conncache_remove_conn(conn, FALSE);
- conn->data = NULL; /* detach */
+ Curl_conncache_remove_conn(data, conn, FALSE);
return TRUE;
}
}
@@ -996,6 +994,7 @@ struct prunedead {
static int call_extract_if_dead(struct connectdata *conn, void *param)
{
struct prunedead *p = (struct prunedead *)param;
+ conn->data = p->data; /* transfer to use for this check */
if(extract_if_dead(conn, p->data)) {
/* stop the iteration here, pass back the connection that was extracted */
p->extracted = conn;
@@ -1101,7 +1100,7 @@ ConnectionExists(struct Curl_easy *data,
if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) {
infof(data, "Server doesn't support multi-use yet, wait\n");
*waitpipe = TRUE;
- Curl_conncache_unlock(needle);
+ Curl_conncache_unlock(data);
return FALSE; /* no re-use */
}
@@ -1461,11 +1460,11 @@ ConnectionExists(struct Curl_easy *data,
if(chosen) {
/* mark it as used before releasing the lock */
chosen->data = data; /* own it! */
- Curl_conncache_unlock(needle);
+ Curl_conncache_unlock(data);
*usethis = chosen;
return TRUE; /* yes, we found one to use! */
}
- Curl_conncache_unlock(needle);
+ Curl_conncache_unlock(data);
if(foundPendingCandidate && data->set.pipewait) {
infof(data,
@@ -2066,7 +2065,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
if(uc) {
DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url));
return Curl_uc_to_curlcode(uc);
- }
+ }
}
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
@@ -2997,7 +2996,7 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
char portbuf[16];
CURLUcode uc;
conn->remote_port = (unsigned short)data->set.use_port;
- msnprintf(portbuf, sizeof(portbuf), "%u", conn->remote_port);
+ msnprintf(portbuf, sizeof(portbuf), "%d", conn->remote_port);
uc = curl_url_set(data->state.uh, CURLUPART_PORT, portbuf, 0);
if(uc)
return CURLE_OUT_OF_MEMORY;
@@ -3608,6 +3607,7 @@ static CURLcode create_conn(struct Curl_easy *data,
size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
*async = FALSE;
+ *in_connect = NULL;
/*************************************************************
* Check input data
@@ -3773,7 +3773,6 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Setup a "faked" transfer that'll do nothing */
if(!result) {
- conn->data = data;
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
result = Curl_conncache_add_conn(data->state.conn_cache, conn);
@@ -3954,7 +3953,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(conn);
+ Curl_conncache_unlock(data);
if(conn_candidate)
(void)Curl_disconnect(data, conn_candidate,
@@ -3966,7 +3965,7 @@ static CURLcode create_conn(struct Curl_easy *data,
}
}
else
- Curl_conncache_unlock(conn);
+ Curl_conncache_unlock(data);
}
@@ -4135,11 +4134,11 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
}
CURLcode Curl_connect(struct Curl_easy *data,
- struct connectdata **in_connect,
bool *asyncp,
bool *protocol_done)
{
CURLcode result;
+ struct connectdata *conn;
*asyncp = FALSE; /* assume synchronous resolves by default */
@@ -4149,30 +4148,30 @@ CURLcode Curl_connect(struct Curl_easy *data,
data->req.maxdownload = -1;
/* call the stuff that needs to be called */
- result = create_conn(data, in_connect, asyncp);
+ result = create_conn(data, &conn, asyncp);
if(!result) {
- if(CONN_INUSE(*in_connect))
+ if(CONN_INUSE(conn))
/* pipelining */
*protocol_done = TRUE;
else if(!*asyncp) {
/* DNS resolution is done: that's either because this is a reused
connection, in which case DNS was unnecessary, or because DNS
really did finish already (synch resolver/fast async resolve) */
- result = Curl_setup_conn(*in_connect, protocol_done);
+ result = Curl_setup_conn(conn, protocol_done);
}
}
if(result == CURLE_NO_CONNECTION_AVAILABLE) {
- *in_connect = NULL;
return result;
}
- else if(result && *in_connect) {
+ else if(result && conn) {
/* We're not allowed to return failure with memory left allocated in the
connectdata struct, free those here */
- Curl_disconnect(data, *in_connect, TRUE);
- *in_connect = NULL; /* return a NULL */
+ Curl_disconnect(data, conn, TRUE);
}
+ else
+ Curl_attach_connnection(data, conn);
return result;
}
diff --git a/lib/url.h b/lib/url.h
index 095d63833..fbd8ef925 100644
--- a/lib/url.h
+++ b/lib/url.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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,8 +52,7 @@ void Curl_freeset(struct Curl_easy * data);
void Curl_up_free(struct Curl_easy *data);
CURLcode Curl_uc_to_curlcode(CURLUcode uc);
CURLcode Curl_close(struct Curl_easy *data); /* opposite of curl_open() */
-CURLcode Curl_connect(struct Curl_easy *, struct connectdata **,
- bool *async, bool *protocol_connect);
+CURLcode Curl_connect(struct Curl_easy *, bool *async, bool *protocol_connect);
CURLcode Curl_disconnect(struct Curl_easy *data,
struct connectdata *, bool dead_connection);
CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
diff --git a/lib/urlapi.c b/lib/urlapi.c
index 5cbda6a98..3af8e9399 100644
--- a/lib/urlapi.c
+++ b/lib/urlapi.c
@@ -510,8 +510,11 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
portptr = &hostname[len];
else if('%' == endbracket) {
int zonelen = len;
- if(1 == sscanf(hostname + zonelen, "25%*[^]]]%c%n", &endbracket, &len))
- portptr = &hostname[--zonelen + len];
+ if(1 == sscanf(hostname + zonelen, "25%*[^]]%c%n", &endbracket, &len)) {
+ if(']' != endbracket)
+ return CURLUE_MALFORMED_INPUT;
+ portptr = &hostname[--zonelen + len + 1];
+ }
else
return CURLUE_MALFORMED_INPUT;
}
@@ -534,6 +537,14 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
long port;
char portbuf[7];
+ /* Browser behavior adaptation. If there's a colon with no digits after,
+ just cut off the name there which makes us ignore the colon and just
+ use the default port. Firefox, Chrome and Safari all do that. */
+ if(!portptr[1]) {
+ *portptr = '\0';
+ return CURLUE_OK;
+ }
+
if(!ISDIGIT(portptr[1]))
return CURLUE_BAD_PORT_NUMBER;
@@ -547,22 +558,14 @@ UNITTEST CURLUcode Curl_parse_port(struct Curl_URL *u, char *hostname)
if(rest[0])
return CURLUE_BAD_PORT_NUMBER;
- if(rest != &portptr[1]) {
- *portptr++ = '\0'; /* cut off the name there */
- *rest = 0;
- /* generate a new to get rid of leading zeroes etc */
- msnprintf(portbuf, sizeof(portbuf), "%ld", port);
- u->portnum = port;
- u->port = strdup(portbuf);
- if(!u->port)
- return CURLUE_OUT_OF_MEMORY;
- }
- else {
- /* Browser behavior adaptation. If there's a colon with no digits after,
- just cut off the name there which makes us ignore the colon and just
- use the default port. Firefox and Chrome both do that. */
- *portptr = '\0';
- }
+ *portptr++ = '\0'; /* cut off the name there */
+ *rest = 0;
+ /* generate a new port number string to get rid of leading zeroes etc */
+ msnprintf(portbuf, sizeof(portbuf), "%ld", port);
+ u->portnum = port;
+ u->port = strdup(portbuf);
+ if(!u->port)
+ return CURLUE_OUT_OF_MEMORY;
}
return CURLUE_OK;
@@ -864,7 +867,7 @@ static CURLUcode seturl(const char *url, CURLU *u, unsigned int flags)
return CURLUE_OUT_OF_MEMORY;
}
- if(query && query[0]) {
+ if(query) {
u->query = strdup(query);
if(!u->query)
return CURLUE_OUT_OF_MEMORY;
@@ -1071,8 +1074,8 @@ CURLUcode curl_url_get(CURLU *u, CURLUPart what,
port ? port : "",
(u->path && (u->path[0] != '/')) ? "/": "",
u->path ? u->path : "/",
- u->query? "?": "",
- u->query? u->query : "",
+ (u->query && u->query[0]) ? "?": "",
+ (u->query && u->query[0]) ? u->query : "",
u->fragment? "#": "",
u->fragment? u->fragment : "");
}
diff --git a/lib/urldata.h b/lib/urldata.h
index b713e883b..73195c7d3 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -77,7 +77,7 @@
/* Default FTP/IMAP etc response timeout in milliseconds.
Symbian OS panics when given a timeout much greater than 1/2 hour.
*/
-#define RESP_TIMEOUT (1800*1000)
+#define RESP_TIMEOUT (120*1000)
#include "cookie.h"
#include "psl.h"
@@ -329,6 +329,12 @@ struct kerberos5data {
struct ntlmdata {
curlntlm state;
#ifdef USE_WINDOWS_SSPI
+/* The sslContext is used for the Schannel bindings. The
+ * api is available on the Windows 7 SDK and later.
+ */
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ CtxtHandle *sslContext;
+#endif
CredHandle *credentials;
CtxtHandle *context;
SEC_WINNT_AUTH_IDENTITY identity;
@@ -359,6 +365,9 @@ struct negotiatedata {
gss_buffer_desc output_token;
#else
#ifdef USE_WINDOWS_SSPI
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ CtxtHandle *sslContext;
+#endif
DWORD status;
CredHandle *credentials;
CtxtHandle *context;
@@ -975,6 +984,9 @@ struct connectdata {
void *seek_client; /* pointer to pass to the seek() above */
/*************** Request - specific items ************/
+#if defined(USE_WINDOWS_SSPI) && defined(SECPKG_ATTR_ENDPOINT_BINDINGS)
+ CtxtHandle *sslContext;
+#endif
#if defined(USE_NTLM)
struct ntlmdata ntlm; /* NTLM differs from other authentication schemes
@@ -1217,6 +1229,15 @@ typedef enum {
EXPIRE_LAST /* not an actual timer, used as a marker only */
} expire_id;
+
+typedef enum {
+ TRAILERS_NONE,
+ TRAILERS_INITIALIZED,
+ TRAILERS_SENDING,
+ TRAILERS_DONE
+} trailers_state;
+
+
/*
* One instance for each timeout an easy handle can set.
*/
@@ -1363,6 +1384,13 @@ struct UrlState {
#endif
CURLU *uh; /* URL handle for the current parsed URL */
struct urlpieces up;
+#ifndef CURL_DISABLE_HTTP
+ size_t trailers_bytes_sent;
+ Curl_send_buffer *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 */
};
@@ -1382,6 +1410,7 @@ struct DynamicStatic {
curl_easy_setopt(COOKIEFILE) calls */
struct curl_slist *resolve; /* set to point to the set.resolve list when
this should be dealt with in pretransfer */
+ bool wildcard_resolve; /* Set to true if any resolve change is a wildcard */
};
/*
@@ -1728,9 +1757,12 @@ struct UserDefined {
long upkeep_interval_ms; /* Time between calls for connection upkeep. */
bool doh; /* DNS-over-HTTPS enabled */
bool doh_get; /* use GET for DoH requests, instead of POST */
+ bool http09_allowed; /* allow HTTP/0.9 responses */
multidone_func fmultidone;
struct Curl_easy *dohfor; /* this is a DoH request for that transfer */
CURLU *uh; /* URL handle for the current parsed URL */
+ void *trailer_data; /* pointer to pass to trailer data callback */
+ curl_trailer_callback trailer_callback; /* trailing data callback */
};
struct Names {
@@ -1758,9 +1790,10 @@ struct Curl_easy {
struct Curl_easy *next;
struct Curl_easy *prev;
- struct connectdata *easy_conn; /* the "unit's" connection */
+ struct connectdata *conn;
struct curl_llist_element connect_queue;
struct curl_llist_element pipeline_queue;
+ struct curl_llist_element sh_queue; /* list per Curl_sh_entry */
CURLMstate mstate; /* the handle's state */
CURLcode result; /* previous result */
@@ -1772,6 +1805,8 @@ struct Curl_easy {
the state etc are also kept. This array is mostly used to detect when a
socket is to be removed from the hash. See singlesocket(). */
curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
+ int actions[MAX_SOCKSPEREASYHANDLE]; /* action for each socket in
+ sockets[] */
int numsocks;
struct Names dns;
diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c
index 2df1ac2db..d9db534c4 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 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2015 - 2019, 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
@@ -146,7 +146,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data,
}
/* Generate our SPN */
- spn = Curl_auth_build_spn(service, data->easy_conn->host.name, NULL);
+ spn = Curl_auth_build_spn(service, data->conn->host.name, NULL);
if(!spn) {
free(output_token);
free(input_token);
diff --git a/lib/vauth/ntlm.c b/lib/vauth/ntlm.c
index 458b27253..6a8fc5ab3 100644
--- a/lib/vauth/ntlm.c
+++ b/lib/vauth/ntlm.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -182,10 +182,11 @@ static CURLcode ntlm_decode_type2_target(struct Curl_easy *data,
target_info_len = Curl_read16_le(&buffer[40]);
target_info_offset = Curl_read32_le(&buffer[44]);
if(target_info_len > 0) {
- if(((target_info_offset + target_info_len) > size) ||
+ if((target_info_offset >= size) ||
+ ((target_info_offset + target_info_len) > size) ||
(target_info_offset < 48)) {
infof(data, "NTLM handshake failure (bad type-2 message). "
- "Target Info Offset Len is set incorrect by the peer\n");
+ "Target Info Offset Len is set incorrect by the peer\n");
return CURLE_BAD_CONTENT_ENCODING;
}
@@ -562,7 +563,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
}
#if defined(USE_NTRESPONSES) && defined(USE_NTLM_V2)
- if(ntlm->target_info_len) {
+ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
unsigned char ntbuffer[0x18];
unsigned char entropy[8];
unsigned char ntlmv2hash[0x18];
@@ -599,7 +600,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
#if defined(USE_NTRESPONSES) && defined(USE_NTLM2SESSION)
/* We don't support NTLM2 if we don't have USE_NTRESPONSES */
- if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
+ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM_KEY) {
unsigned char ntbuffer[0x18];
unsigned char tmp[0x18];
unsigned char md5sum[MD5_DIGEST_LENGTH];
@@ -631,7 +632,9 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
/* End of NTLM2 Session code */
-
+ /* NTLM v2 session security is a misnomer because it is not NTLM v2.
+ It is NTLM v1 using the extended session security that is also
+ in NTLM v2 */
}
else
#endif
@@ -776,11 +779,14 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
});
#ifdef USE_NTRESPONSES
- if(size < (NTLM_BUFSIZE - ntresplen)) {
- DEBUGASSERT(size == (size_t)ntrespoff);
- memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
- size += ntresplen;
+ /* ntresplen + size should not be risking an integer overflow here */
+ if(ntresplen + size > sizeof(ntlmbuf)) {
+ failf(data, "incoming NTLM message too big");
+ return CURLE_OUT_OF_MEMORY;
}
+ DEBUGASSERT(size == (size_t)ntrespoff);
+ memcpy(&ntlmbuf[size], ptr_ntresp, ntresplen);
+ size += ntresplen;
DEBUG_OUT({
fprintf(stderr, "\n ntresp=");
diff --git a/lib/vauth/ntlm_sspi.c b/lib/vauth/ntlm_sspi.c
index 80520a251..177327b7a 100644
--- a/lib/vauth/ntlm_sspi.c
+++ b/lib/vauth/ntlm_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -249,7 +249,7 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
char **outptr, size_t *outlen)
{
CURLcode result = CURLE_OK;
- SecBuffer type_2_buf;
+ SecBuffer type_2_bufs[2];
SecBuffer type_3_buf;
SecBufferDesc type_2_desc;
SecBufferDesc type_3_desc;
@@ -261,12 +261,39 @@ CURLcode Curl_auth_create_ntlm_type3_message(struct Curl_easy *data,
(void) userp;
/* Setup the type-2 "input" security buffer */
- type_2_desc.ulVersion = SECBUFFER_VERSION;
- type_2_desc.cBuffers = 1;
- type_2_desc.pBuffers = &type_2_buf;
- type_2_buf.BufferType = SECBUFFER_TOKEN;
- type_2_buf.pvBuffer = ntlm->input_token;
- type_2_buf.cbBuffer = curlx_uztoul(ntlm->input_token_len);
+ type_2_desc.ulVersion = SECBUFFER_VERSION;
+ type_2_desc.cBuffers = 1;
+ type_2_desc.pBuffers = &type_2_bufs[0];
+ type_2_bufs[0].BufferType = SECBUFFER_TOKEN;
+ type_2_bufs[0].pvBuffer = ntlm->input_token;
+ type_2_bufs[0].cbBuffer = curlx_uztoul(ntlm->input_token_len);
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ /* ssl context comes from schannel.
+ * When extended protection is used in IIS server,
+ * we have to pass a second SecBuffer to the SecBufferDesc
+ * otherwise IIS will not pass the authentication (401 response).
+ * Minimum supported version is Windows 7.
+ * https://docs.microsoft.com/en-us/security-updates
+ * /SecurityAdvisories/2009/973811
+ */
+ if(ntlm->sslContext) {
+ SEC_CHANNEL_BINDINGS channelBindings;
+ SecPkgContext_Bindings pkgBindings;
+ pkgBindings.Bindings = &channelBindings;
+ status = s_pSecFn->QueryContextAttributes(
+ ntlm->sslContext,
+ SECPKG_ATTR_ENDPOINT_BINDINGS,
+ &pkgBindings
+ );
+ if(status == SEC_E_OK) {
+ type_2_desc.cBuffers++;
+ type_2_bufs[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;
+ type_2_bufs[1].cbBuffer = pkgBindings.BindingsLength;
+ type_2_bufs[1].pvBuffer = pkgBindings.Bindings;
+ }
+ }
+#endif
/* Setup the type-3 "output" security buffer */
type_3_desc.ulVersion = SECBUFFER_VERSION;
diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c
index f807c49c4..aacc5d272 100644
--- a/lib/vauth/spnego_sspi.c
+++ b/lib/vauth/spnego_sspi.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -92,7 +92,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
size_t chlglen = 0;
unsigned char *chlg = NULL;
PSecPkgInfo SecurityPackage;
- SecBuffer chlg_buf;
+ SecBuffer chlg_buf[2];
SecBuffer resp_buf;
SecBufferDesc chlg_desc;
SecBufferDesc resp_desc;
@@ -189,12 +189,39 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
}
/* Setup the challenge "input" security buffer */
- chlg_desc.ulVersion = SECBUFFER_VERSION;
- chlg_desc.cBuffers = 1;
- chlg_desc.pBuffers = &chlg_buf;
- chlg_buf.BufferType = SECBUFFER_TOKEN;
- chlg_buf.pvBuffer = chlg;
- chlg_buf.cbBuffer = curlx_uztoul(chlglen);
+ chlg_desc.ulVersion = SECBUFFER_VERSION;
+ chlg_desc.cBuffers = 1;
+ chlg_desc.pBuffers = &chlg_buf[0];
+ chlg_buf[0].BufferType = SECBUFFER_TOKEN;
+ chlg_buf[0].pvBuffer = chlg;
+ chlg_buf[0].cbBuffer = curlx_uztoul(chlglen);
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ /* ssl context comes from Schannel.
+ * When extended protection is used in IIS server,
+ * we have to pass a second SecBuffer to the SecBufferDesc
+ * otherwise IIS will not pass the authentication (401 response).
+ * Minimum supported version is Windows 7.
+ * https://docs.microsoft.com/en-us/security-updates
+ * /SecurityAdvisories/2009/973811
+ */
+ if(nego->sslContext) {
+ SEC_CHANNEL_BINDINGS channelBindings;
+ SecPkgContext_Bindings pkgBindings;
+ pkgBindings.Bindings = &channelBindings;
+ nego->status = s_pSecFn->QueryContextAttributes(
+ nego->sslContext,
+ SECPKG_ATTR_ENDPOINT_BINDINGS,
+ &pkgBindings
+ );
+ if(nego->status == SEC_E_OK) {
+ chlg_desc.cBuffers++;
+ chlg_buf[1].BufferType = SECBUFFER_CHANNEL_BINDINGS;
+ chlg_buf[1].cbBuffer = pkgBindings.BindingsLength;
+ chlg_buf[1].pvBuffer = pkgBindings.Bindings;
+ }
+ }
+#endif
}
/* Setup the response "output" security buffer */
@@ -222,7 +249,7 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data,
if(GSS_ERROR(nego->status)) {
failf(data, "InitializeSecurityContext failed: %s",
- Curl_sspi_strerror(data->easy_conn, nego->status));
+ Curl_sspi_strerror(data->conn, nego->status));
return CURLE_OUT_OF_MEMORY;
}
diff --git a/lib/vtls/cyassl.c b/lib/vtls/cyassl.c
index 0d45afbf0..ea96cf65e 100644
--- a/lib/vtls/cyassl.c
+++ b/lib/vtls/cyassl.c
@@ -794,6 +794,12 @@ static int Curl_cyassl_init(void)
}
+static void Curl_cyassl_cleanup(void)
+{
+ CyaSSL_Cleanup();
+}
+
+
static bool Curl_cyassl_data_pending(const struct connectdata* conn,
int connindex)
{
@@ -1004,7 +1010,7 @@ const struct Curl_ssl Curl_ssl_cyassl = {
sizeof(struct ssl_backend_data),
Curl_cyassl_init, /* init */
- Curl_none_cleanup, /* cleanup */
+ Curl_cyassl_cleanup, /* cleanup */
Curl_cyassl_version, /* version */
Curl_none_check_cxn, /* check_cxn */
Curl_cyassl_shutdown, /* shutdown */
diff --git a/lib/vtls/darwinssl.c b/lib/vtls/darwinssl.c
index 25b101282..bb251cdb3 100644
--- a/lib/vtls/darwinssl.c
+++ b/lib/vtls/darwinssl.c
@@ -1298,7 +1298,6 @@ set_ssl_version_min_max(struct connectdata *conn, int sockindex)
case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
ssl_version = CURL_SSLVERSION_TLSv1_0;
- ssl_version_max = max_supported_version_by_os;
break;
}
@@ -1430,7 +1429,6 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
if(SSLSetProtocolVersionMax != NULL) {
switch(conn->ssl_config.version) {
- case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1:
(void)SSLSetProtocolVersionMin(BACKEND->ssl_ctx, kTLSProtocol1);
#if (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) && HAVE_BUILTIN_AVAILABLE == 1
@@ -1445,6 +1443,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn,
#endif /* (CURL_BUILD_MAC_10_13 || CURL_BUILD_IOS_11) &&
HAVE_BUILTIN_AVAILABLE == 1 */
break;
+ case CURL_SSLVERSION_DEFAULT:
case CURL_SSLVERSION_TLSv1_0:
case CURL_SSLVERSION_TLSv1_1:
case CURL_SSLVERSION_TLSv1_2:
diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
index 6a20e276e..bb6a757bf 100644
--- a/lib/vtls/mbedtls.c
+++ b/lib/vtls/mbedtls.c
@@ -6,7 +6,7 @@
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -373,7 +373,7 @@ mbed_connect_step1(struct connectdata *conn,
}
}
- infof(data, "mbedTLS: Connecting to %s:%d\n", hostname, port);
+ infof(data, "mbedTLS: Connecting to %s:%ld\n", hostname, port);
mbedtls_ssl_config_init(&BACKEND->config);
@@ -574,19 +574,21 @@ mbed_connect_step2(struct connectdata *conn,
ret = mbedtls_ssl_get_verify_result(&BACKEND->ssl);
+ if(!SSL_CONN_CONFIG(verifyhost))
+ /* Ignore hostname errors if verifyhost is disabled */
+ ret &= ~MBEDTLS_X509_BADCERT_CN_MISMATCH;
+
if(ret && SSL_CONN_CONFIG(verifypeer)) {
if(ret & MBEDTLS_X509_BADCERT_EXPIRED)
failf(data, "Cert verify failed: BADCERT_EXPIRED");
- if(ret & MBEDTLS_X509_BADCERT_REVOKED) {
+ else if(ret & MBEDTLS_X509_BADCERT_REVOKED)
failf(data, "Cert verify failed: BADCERT_REVOKED");
- return CURLE_PEER_FAILED_VERIFICATION;
- }
- if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
+ else if(ret & MBEDTLS_X509_BADCERT_CN_MISMATCH)
failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
- if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
+ else if(ret & MBEDTLS_X509_BADCERT_NOT_TRUSTED)
failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
return CURLE_PEER_FAILED_VERIFICATION;
diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
index 8bddb9a8c..9d11b89e5 100644
--- a/lib/vtls/openssl.c
+++ b/lib/vtls/openssl.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2019, 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
@@ -1692,6 +1692,7 @@ static CURLcode verifystatus(struct connectdata *conn,
struct ssl_connect_data *connssl)
{
int i, ocsp_status;
+ unsigned char *status;
const unsigned char *p;
CURLcode result = CURLE_OK;
struct Curl_easy *data = conn->data;
@@ -1701,14 +1702,14 @@ static CURLcode verifystatus(struct connectdata *conn,
X509_STORE *st = NULL;
STACK_OF(X509) *ch = NULL;
- long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &p);
+ long len = SSL_get_tlsext_status_ocsp_resp(BACKEND->handle, &status);
- if(!p) {
+ if(!status) {
failf(data, "No OCSP response received");
result = CURLE_SSL_INVALIDCERTSTATUS;
goto end;
}
-
+ p = status;
rsp = d2i_OCSP_RESPONSE(NULL, &p, len);
if(!rsp) {
failf(data, "Invalid OCSP response");
@@ -3774,7 +3775,12 @@ static size_t Curl_ossl_version(char *buffer, size_t size)
{
#ifdef OPENSSL_IS_BORINGSSL
return msnprintf(buffer, size, OSSL_PACKAGE);
-#else /* OPENSSL_IS_BORINGSSL */
+#elif defined(HAVE_OPENSSL_VERSION) && defined(OPENSSL_VERSION_STRING)
+ return msnprintf(buffer, size, "%s/%s",
+ OSSL_PACKAGE, OpenSSL_version(OPENSSL_VERSION_STRING));
+#else
+ /* not BoringSSL and not using OpenSSL_version */
+
char sub[3];
unsigned long ssleay_value;
sub[2]='\0';
diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
index 56fd93e1e..c8574f56c 100644
--- a/lib/vtls/schannel.c
+++ b/lib/vtls/schannel.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
* Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -356,6 +356,7 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
TCHAR **thumbprint)
{
TCHAR *sep;
+ TCHAR *store_path_start;
size_t store_name_len;
sep = _tcschr(path, TEXT('\\'));
@@ -386,13 +387,17 @@ get_cert_location(TCHAR *path, DWORD *store_name, TCHAR **store_path,
else
return CURLE_SSL_CERTPROBLEM;
- *store_path = sep + 1;
+ store_path_start = sep + 1;
- sep = _tcschr(*store_path, TEXT('\\'));
+ sep = _tcschr(store_path_start, TEXT('\\'));
if(sep == NULL)
return CURLE_SSL_CERTPROBLEM;
- *sep = 0;
+ *sep = TEXT('\0');
+ *store_path = _tcsdup(store_path_start);
+ *sep = TEXT('\\');
+ if(*store_path == NULL)
+ return CURLE_OUT_OF_MEMORY;
*thumbprint = sep + 1;
if(_tcslen(*thumbprint) != CERT_THUMBPRINT_STR_LEN)
@@ -435,7 +440,7 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
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: WinSSL version is old and may not be able to "
+ 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");
}
@@ -608,9 +613,11 @@ schannel_connect_step1(struct connectdata *conn, int sockindex)
failf(data, "schannel: Failed to open cert store %x %s, "
"last error is %x",
cert_store_name, cert_store_path, GetLastError());
+ free(cert_store_path);
Curl_unicodefree(cert_path);
return CURLE_SSL_CERTPROBLEM;
}
+ free(cert_store_path);
cert_thumbprint.pbData = cert_thumbprint_data;
cert_thumbprint.cbData = CERT_THUMBPRINT_DATA_LEN;
@@ -1414,6 +1421,16 @@ schannel_connect_common(struct connectdata *conn, int sockindex,
connssl->state = ssl_connection_complete;
conn->recv[sockindex] = schannel_recv;
conn->send[sockindex] = schannel_send;
+
+#ifdef SECPKG_ATTR_ENDPOINT_BINDINGS
+ /* When SSPI is used in combination with Schannel
+ * we need the Schannel context to create the Schannel
+ * binding to pass the IIS extended protection checks.
+ * Available on Windows 7 or later.
+ */
+ conn->sslContext = &BACKEND->ctxt->ctxt_handle;
+#endif
+
*done = TRUE;
}
else
@@ -2013,9 +2030,16 @@ static int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
/* free SSPI Schannel API credential handle */
if(BACKEND->cred) {
- Curl_ssl_sessionid_lock(conn);
+ /*
+ * When this function is called from Curl_schannel_close() the connection
+ * might not have an associated transfer so the check for conn->data is
+ * necessary.
+ */
+ if(conn->data)
+ Curl_ssl_sessionid_lock(conn);
Curl_schannel_session_free(BACKEND->cred);
- Curl_ssl_sessionid_unlock(conn);
+ if(conn->data)
+ Curl_ssl_sessionid_unlock(conn);
BACKEND->cred = NULL;
}
@@ -2049,7 +2073,7 @@ static void Curl_schannel_cleanup(void)
static size_t Curl_schannel_version(char *buffer, size_t size)
{
- size = msnprintf(buffer, size, "WinSSL");
+ size = msnprintf(buffer, size, "Schannel");
return size;
}
@@ -2137,11 +2161,11 @@ static CURLcode pkp_pin_peer_pubkey(struct connectdata *conn, int sockindex,
}
static void Curl_schannel_checksum(const unsigned char *input,
- size_t inputlen,
- unsigned char *checksum,
- size_t checksumlen,
- DWORD provType,
- const unsigned int algId)
+ size_t inputlen,
+ unsigned char *checksum,
+ size_t checksumlen,
+ DWORD provType,
+ const unsigned int algId)
{
HCRYPTPROV hProv = 0;
HCRYPTHASH hHash = 0;
@@ -2191,9 +2215,9 @@ static CURLcode Curl_schannel_md5sum(unsigned char *input,
unsigned char *md5sum,
size_t md5len)
{
- Curl_schannel_checksum(input, inputlen, md5sum, md5len,
- PROV_RSA_FULL, CALG_MD5);
- return CURLE_OK;
+ Curl_schannel_checksum(input, inputlen, md5sum, md5len,
+ PROV_RSA_FULL, CALG_MD5);
+ return CURLE_OK;
}
static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
@@ -2201,9 +2225,9 @@ static CURLcode Curl_schannel_sha256sum(const unsigned char *input,
unsigned char *sha256sum,
size_t sha256len)
{
- Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
- PROV_RSA_AES, CALG_SHA_256);
- return CURLE_OK;
+ Curl_schannel_checksum(input, inputlen, sha256sum, sha256len,
+ PROV_RSA_AES, CALG_SHA_256);
+ return CURLE_OK;
}
static void *Curl_schannel_get_internals(struct ssl_connect_data *connssl,
diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c
index 8b21624ba..680f6ec5d 100644
--- a/lib/vtls/schannel_verify.c
+++ b/lib/vtls/schannel_verify.c
@@ -7,7 +7,7 @@
*
* Copyright (C) 2012 - 2016, Marc Hoersken, <info@marc-hoersken.de>
* Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
- * Copyright (C) 2012 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2012 - 2019, 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
@@ -87,14 +87,14 @@ static CURLcode add_certs_to_store(HCERTSTORE trust_store,
LARGE_INTEGER file_size;
char *ca_file_buffer = NULL;
char *current_ca_file_ptr = NULL;
- const TCHAR *ca_file_tstr = NULL;
+ TCHAR *ca_file_tstr = NULL;
size_t ca_file_bufsize = 0;
DWORD total_bytes_read = 0;
bool more_certs = 0;
int num_certs = 0;
size_t END_CERT_LEN;
- ca_file_tstr = Curl_convert_UTF8_to_tchar(ca_file);
+ ca_file_tstr = Curl_convert_UTF8_to_tchar((char *)ca_file);
if(!ca_file_tstr) {
failf(data,
"schannel: invalid path name for CA file '%s': %s",