summaryrefslogtreecommitdiff
path: root/Utilities/cmcurl/lib/url.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/url.c')
-rw-r--r--Utilities/cmcurl/lib/url.c1115
1 files changed, 536 insertions, 579 deletions
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index c441ae716..a1a6b6910 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
@@ -34,10 +34,12 @@
#ifdef HAVE_NET_IF_H
#include <net/if.h>
#endif
+#ifdef HAVE_IPHLPAPI_H
+#include <Iphlpapi.h>
+#endif
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
-
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
@@ -93,6 +95,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "inet_pton.h"
#include "getinfo.h"
#include "urlapi-int.h"
+#include "system_win32.h"
/* And now for the protocols */
#include "ftp.h"
@@ -103,15 +106,15 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "http2.h"
#include "file.h"
#include "curl_ldap.h"
-#include "ssh.h"
+#include "vssh/ssh.h"
#include "imap.h"
#include "url.h"
#include "connect.h"
#include "inet_ntop.h"
#include "http_ntlm.h"
-#include "socks.h"
#include "curl_rtmp.h"
#include "gopher.h"
+#include "mqtt.h"
#include "http_proxy.h"
#include "conncache.h"
#include "multihandle.h"
@@ -119,6 +122,7 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "strdup.h"
#include "setopt.h"
#include "altsvc.h"
+#include "dynbuf.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -126,7 +130,6 @@ bool curl_win32_idn_to_ascii(const char *in, char **out);
#include "memdebug.h"
static void conn_free(struct connectdata *conn);
-static void free_idnconverted_hostname(struct hostname *host);
static unsigned int get_protocol_family(unsigned int protocol);
/* Some parts of the code (e.g. chunked encoding) assume this buffer has at
@@ -139,19 +142,21 @@ static unsigned int get_protocol_family(unsigned int protocol);
/*
- * Protocol table.
+ * Protocol table. Schemes (roughly) in 2019 popularity order:
+ *
+ * HTTPS, HTTP, FTP, FTPS, SFTP, FILE, SCP, SMTP, LDAP, IMAPS, TELNET, IMAP,
+ * LDAPS, SMTPS, TFTP, SMB, POP3, GOPHER POP3S, RTSP, RTMP, SMBS, DICT
*/
-
static const struct Curl_handler * const protocols[] = {
-#ifndef CURL_DISABLE_HTTP
- &Curl_handler_http,
-#endif
-
#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
&Curl_handler_https,
#endif
+#ifndef CURL_DISABLE_HTTP
+ &Curl_handler_http,
+#endif
+
#ifndef CURL_DISABLE_FTP
&Curl_handler_ftp,
#endif
@@ -160,12 +165,23 @@ static const struct Curl_handler * const protocols[] = {
&Curl_handler_ftps,
#endif
-#ifndef CURL_DISABLE_TELNET
- &Curl_handler_telnet,
+#if defined(USE_SSH)
+ &Curl_handler_sftp,
#endif
-#ifndef CURL_DISABLE_DICT
- &Curl_handler_dict,
+#ifndef CURL_DISABLE_FILE
+ &Curl_handler_file,
+#endif
+
+#if defined(USE_SSH) && !defined(USE_WOLFSSH)
+ &Curl_handler_scp,
+#endif
+
+#ifndef CURL_DISABLE_SMTP
+ &Curl_handler_smtp,
+#ifdef USE_SSL
+ &Curl_handler_smtps,
+#endif
#endif
#ifndef CURL_DISABLE_LDAP
@@ -177,22 +193,6 @@ static const struct Curl_handler * const protocols[] = {
#endif
#endif
-#ifndef CURL_DISABLE_FILE
- &Curl_handler_file,
-#endif
-
-#ifndef CURL_DISABLE_TFTP
- &Curl_handler_tftp,
-#endif
-
-#if defined(USE_SSH)
- &Curl_handler_scp,
-#endif
-
-#if defined(USE_SSH)
- &Curl_handler_sftp,
-#endif
-
#ifndef CURL_DISABLE_IMAP
&Curl_handler_imap,
#ifdef USE_SSL
@@ -200,6 +200,14 @@ static const struct Curl_handler * const protocols[] = {
#endif
#endif
+#ifndef CURL_DISABLE_TELNET
+ &Curl_handler_telnet,
+#endif
+
+#ifndef CURL_DISABLE_TFTP
+ &Curl_handler_tftp,
+#endif
+
#ifndef CURL_DISABLE_POP3
&Curl_handler_pop3,
#ifdef USE_SSL
@@ -216,17 +224,14 @@ static const struct Curl_handler * const protocols[] = {
#endif
#endif
-#ifndef CURL_DISABLE_SMTP
- &Curl_handler_smtp,
-#ifdef USE_SSL
- &Curl_handler_smtps,
-#endif
-#endif
-
#ifndef CURL_DISABLE_RTSP
&Curl_handler_rtsp,
#endif
+#ifdef CURL_ENABLE_MQTT
+ &Curl_handler_mqtt,
+#endif
+
#ifndef CURL_DISABLE_GOPHER
&Curl_handler_gopher,
#endif
@@ -240,6 +245,10 @@ static const struct Curl_handler * const protocols[] = {
&Curl_handler_rtmpts,
#endif
+#ifndef CURL_DISABLE_DICT
+ &Curl_handler_dict,
+#endif
+
(struct Curl_handler *) NULL
};
@@ -272,10 +281,16 @@ void Curl_freeset(struct Curl_easy *data)
{
/* Free all dynamic strings stored in the data->set substructure. */
enum dupstring i;
+ enum dupblob j;
+
for(i = (enum dupstring)0; i < STRING_LAST; i++) {
Curl_safefree(data->set.str[i]);
}
+ for(j = (enum dupblob)0; j < BLOB_LAST; j++) {
+ Curl_safefree(data->set.blobs[j]);
+ }
+
if(data->change.referer_alloc) {
Curl_safefree(data->change.referer);
data->change.referer_alloc = FALSE;
@@ -315,13 +330,17 @@ static void up_free(struct Curl_easy *data)
* when curl_easy_perform() is invoked.
*/
-CURLcode Curl_close(struct Curl_easy *data)
+CURLcode Curl_close(struct Curl_easy **datap)
{
struct Curl_multi *m;
+ struct Curl_easy *data;
- if(!data)
+ if(!datap || !*datap)
return CURLE_OK;
+ data = *datap;
+ *datap = NULL;
+
Curl_expire_clear(data); /* shut off timers */
m = data->multi;
@@ -370,11 +389,11 @@ CURLcode Curl_close(struct Curl_easy *data)
up_free(data);
Curl_safefree(data->state.buffer);
- Curl_safefree(data->state.headerbuff);
+ Curl_dyn_free(&data->state.headerb);
Curl_safefree(data->state.ulbuf);
- Curl_flush_cookies(data, 1);
+ Curl_flush_cookies(data, TRUE);
#ifdef USE_ALTSVC
- Curl_altsvc_save(data->asi, data->set.str[STRING_ALTSVC]);
+ Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
Curl_altsvc_cleanup(data->asi);
data->asi = NULL;
#endif
@@ -397,6 +416,23 @@ CURLcode Curl_close(struct Curl_easy *data)
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
+ Curl_safefree(data->state.aptr.proxyuserpwd);
+ Curl_safefree(data->state.aptr.uagent);
+ Curl_safefree(data->state.aptr.userpwd);
+ Curl_safefree(data->state.aptr.accept_encoding);
+ Curl_safefree(data->state.aptr.te);
+ Curl_safefree(data->state.aptr.rangeline);
+ Curl_safefree(data->state.aptr.ref);
+ Curl_safefree(data->state.aptr.host);
+ Curl_safefree(data->state.aptr.cookiehost);
+ Curl_safefree(data->state.aptr.rtsp_transport);
+
+#ifndef CURL_DISABLE_DOH
+ Curl_dyn_free(&data->req.doh.probe[0].serverdoh);
+ Curl_dyn_free(&data->req.doh.probe[1].serverdoh);
+ curl_slist_free_all(data->req.doh.headers);
+#endif
+
/* destruct wildcard structures if it is needed */
Curl_wildcard_dtor(&data->wildcard);
Curl_freeset(data);
@@ -437,9 +473,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->postfieldsize = -1; /* unknown size */
set->maxredirs = -1; /* allow any amount by default */
- set->httpreq = HTTPREQ_GET; /* Default HTTP request */
+ set->method = HTTPREQ_GET; /* Default HTTP request */
set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
-#ifndef CURL_DISABLE_FILE
+#ifndef CURL_DISABLE_FTP
set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
@@ -476,7 +512,9 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
type */
set->ssl.primary.sessionid = TRUE; /* session ID caching enabled by
default */
+#ifndef CURL_DISABLE_PROXY
set->proxy_ssl = set->ssl;
+#endif
set->new_file_perms = 0644; /* Default permissions */
set->new_directory_perms = 0755; /* Default permissions */
@@ -485,9 +523,8 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
define since we internally only use the lower 16 bits for the passed
in bitmask to not conflict with the private bits */
set->allowed_protocols = CURLPROTO_ALL;
- set->redir_protocols = CURLPROTO_ALL & /* All except FILE, SCP and SMB */
- ~(CURLPROTO_FILE | CURLPROTO_SCP | CURLPROTO_SMB |
- CURLPROTO_SMBS);
+ set->redir_protocols = CURLPROTO_HTTP | CURLPROTO_HTTPS | CURLPROTO_FTP |
+ CURLPROTO_FTPS;
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
/*
@@ -544,7 +581,7 @@ CURLcode Curl_init_userdefined(struct Curl_easy *data)
set->upkeep_interval_ms = CURL_UPKEEP_INTERVAL_DEFAULT;
set->maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
set->maxage_conn = 118;
- set->http09_allowed = TRUE;
+ set->http09_allowed = FALSE;
set->httpversion =
#ifdef USE_NGHTTP2
CURL_HTTP_VERSION_2TLS
@@ -586,40 +623,22 @@ CURLcode Curl_open(struct Curl_easy **curl)
return result;
}
- /* We do some initial setup here, all those fields that can't be just 0 */
-
- data->state.buffer = malloc(READBUFFER_SIZE + 1);
- if(!data->state.buffer) {
- DEBUGF(fprintf(stderr, "Error: malloc of buffer failed\n"));
- result = CURLE_OUT_OF_MEMORY;
- }
- else {
- data->state.headerbuff = malloc(HEADERSIZE);
- if(!data->state.headerbuff) {
- DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
- result = CURLE_OUT_OF_MEMORY;
- }
- else {
- result = Curl_init_userdefined(data);
-
- data->state.headersize = HEADERSIZE;
- Curl_convert_init(data);
- Curl_initinfo(data);
-
- /* most recent connection is not yet defined */
- data->state.lastconnect = NULL;
+ result = Curl_init_userdefined(data);
+ if(!result) {
+ Curl_dyn_init(&data->state.headerb, CURL_MAX_HTTP_HEADER);
+ Curl_convert_init(data);
+ Curl_initinfo(data);
- data->progress.flags |= PGRS_HIDE;
- data->state.current_speed = -1; /* init to negative == impossible */
+ /* most recent connection is not yet defined */
+ data->state.lastconnect = NULL;
- Curl_http2_init_state(&data->state);
- }
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
}
if(result) {
Curl_resolver_cleanup(data->state.resolver);
- free(data->state.buffer);
- free(data->state.headerbuff);
+ Curl_dyn_free(&data->state.headerb);
Curl_freeset(data);
free(data);
data = NULL;
@@ -665,15 +684,13 @@ static void conn_reset_all_postponed_data(struct connectdata *conn)
}
#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
/* Use "do-nothing" macro instead of function when workaround not used */
-#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE
+#define conn_reset_all_postponed_data(c) do {} while(0)
#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
static void conn_shutdown(struct connectdata *conn)
{
- if(!conn)
- return;
-
+ DEBUGASSERT(conn);
infof(conn->data, "Closing connection %ld\n", conn->connection_id);
DEBUGASSERT(conn->data);
@@ -694,54 +711,40 @@ static void conn_shutdown(struct connectdata *conn)
Curl_closesocket(conn, conn->tempsock[0]);
if(CURL_SOCKET_BAD != conn->tempsock[1])
Curl_closesocket(conn, conn->tempsock[1]);
-
- /* unlink ourselves. this should be called last since other shutdown
- procedures need a valid conn->data and this may clear it. */
- Curl_conncache_remove_conn(conn->data, conn, TRUE);
}
static void conn_free(struct connectdata *conn)
{
- if(!conn)
- return;
-
- 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);
- Curl_safefree(conn->user);
- Curl_safefree(conn->passwd);
- Curl_safefree(conn->oauth_bearer);
- Curl_safefree(conn->options);
+ Curl_free_idnconverted_hostname(&conn->host);
+ Curl_free_idnconverted_hostname(&conn->conn_to_host);
+#ifndef CURL_DISABLE_PROXY
+ Curl_free_idnconverted_hostname(&conn->http_proxy.host);
+ Curl_free_idnconverted_hostname(&conn->socks_proxy.host);
Curl_safefree(conn->http_proxy.user);
Curl_safefree(conn->socks_proxy.user);
Curl_safefree(conn->http_proxy.passwd);
Curl_safefree(conn->socks_proxy.passwd);
- Curl_safefree(conn->allocptr.proxyuserpwd);
- Curl_safefree(conn->allocptr.uagent);
- Curl_safefree(conn->allocptr.userpwd);
- Curl_safefree(conn->allocptr.accept_encoding);
- Curl_safefree(conn->allocptr.te);
- Curl_safefree(conn->allocptr.rangeline);
- Curl_safefree(conn->allocptr.ref);
- Curl_safefree(conn->allocptr.host);
- Curl_safefree(conn->allocptr.cookiehost);
- Curl_safefree(conn->allocptr.rtsp_transport);
- Curl_safefree(conn->trailer);
+ Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
+ Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
+ Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
+#endif
+ Curl_safefree(conn->user);
+ Curl_safefree(conn->passwd);
+ Curl_safefree(conn->sasl_authzid);
+ Curl_safefree(conn->options);
+ Curl_dyn_free(&conn->trailer);
Curl_safefree(conn->host.rawalloc); /* host name buffer */
Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
Curl_safefree(conn->hostname_resolve);
Curl_safefree(conn->secondaryhostname);
- Curl_safefree(conn->http_proxy.host.rawalloc); /* http proxy name buffer */
- Curl_safefree(conn->socks_proxy.host.rawalloc); /* socks proxy name buffer */
Curl_safefree(conn->connect_state);
conn_reset_all_postponed_data(conn);
Curl_llist_destroy(&conn->easyq, NULL);
Curl_safefree(conn->localdev);
Curl_free_primary_ssl_config(&conn->ssl_config);
- Curl_free_primary_ssl_config(&conn->proxy_ssl_config);
#ifdef USE_UNIX_SOCKETS
Curl_safefree(conn->unix_domain_socket);
@@ -770,13 +773,17 @@ static void conn_free(struct connectdata *conn)
CURLcode Curl_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead_connection)
{
- if(!conn)
- return CURLE_OK; /* this is closed and fine already */
+ /* there must be a connection to close */
+ DEBUGASSERT(conn);
- if(!data) {
- DEBUGF(infof(data, "DISCONNECT without easy handle, ignoring\n"));
- return CURLE_OK;
- }
+ /* it must be removed from the connection cache */
+ DEBUGASSERT(!conn->bundle);
+
+ /* there must be an associated transfer */
+ DEBUGASSERT(data);
+
+ /* the transfer must be detached from the connection */
+ DEBUGASSERT(!data->conn);
/*
* If this connection isn't marked to force-close, leave it open if there
@@ -792,16 +799,11 @@ CURLcode Curl_disconnect(struct Curl_easy *data,
conn->dns_entry = NULL;
}
- Curl_hostcache_prune(data); /* kill old DNS cache entries */
-
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM)
/* Cleanup NTLM connection-related data */
Curl_http_auth_cleanup_ntlm(conn);
-#endif
-#if !defined(CURL_DISABLE_HTTP) && defined(USE_SPNEGO)
+
/* Cleanup NEGOTIATE connection-related data */
Curl_http_auth_cleanup_negotiate(conn);
-#endif
/* the protocol specific disconnect handler and conn_shutdown need a transfer
for the connection! */
@@ -863,8 +865,8 @@ static int IsMultiplexingPossible(const struct Curl_easy *handle,
#ifndef CURL_DISABLE_PROXY
static bool
-proxy_info_matches(const struct proxy_info* data,
- const struct proxy_info* needle)
+proxy_info_matches(const struct proxy_info *data,
+ const struct proxy_info *needle)
{
if((data->proxytype == needle->proxytype) &&
(data->port == needle->port) &&
@@ -873,11 +875,59 @@ proxy_info_matches(const struct proxy_info* data,
return FALSE;
}
+
+static bool
+socks_proxy_info_matches(const struct proxy_info *data,
+ const struct proxy_info *needle)
+{
+ if(!proxy_info_matches(data, needle))
+ return FALSE;
+
+ /* the user information is case-sensitive
+ or at least it is not defined as case-insensitive
+ see https://tools.ietf.org/html/rfc3986#section-3.2.1 */
+ if((data->user == NULL) != (needle->user == NULL))
+ return FALSE;
+ /* curl_strequal does a case insentive comparison, so do not use it here! */
+ if(data->user &&
+ needle->user &&
+ strcmp(data->user, needle->user) != 0)
+ return FALSE;
+ if((data->passwd == NULL) != (needle->passwd == NULL))
+ return FALSE;
+ /* curl_strequal does a case insentive comparison, so do not use it here! */
+ if(data->passwd &&
+ needle->passwd &&
+ strcmp(data->passwd, needle->passwd) != 0)
+ return FALSE;
+ return TRUE;
+}
#else
/* disabled, won't get called */
#define proxy_info_matches(x,y) FALSE
+#define socks_proxy_info_matches(x,y) FALSE
#endif
+/* A connection has to have been idle for a shorter time than 'maxage_conn' to
+ be subject for reuse. The success rate is just too low after this. */
+
+static bool conn_maxage(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct curltime now)
+{
+ if(!conn->data) {
+ timediff_t idletime = Curl_timediff(now, conn->lastused);
+ idletime /= 1000; /* integer seconds is fine */
+
+ if(idletime > data->set.maxage_conn) {
+ infof(data, "Too old connection (%ld seconds), disconnect it\n",
+ idletime);
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
/*
* This function checks if the given connection is dead and extracts it from
* the connection cache if so.
@@ -894,7 +944,11 @@ static bool extract_if_dead(struct connectdata *conn,
/* The check for a dead socket makes sense only if the connection isn't in
use */
bool dead;
- if(conn->handler->connection_check) {
+ struct curltime now = Curl_now();
+ if(conn_maxage(data, conn, now)) {
+ dead = TRUE;
+ }
+ else 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;
@@ -946,7 +1000,12 @@ static int call_extract_if_dead(struct connectdata *conn, void *param)
static void prune_dead_connections(struct Curl_easy *data)
{
struct curltime now = Curl_now();
- time_t elapsed = Curl_timediff(now, data->state.conn_cache->last_cleanup);
+ timediff_t elapsed;
+
+ CONNCACHE_LOCK(data);
+ elapsed =
+ Curl_timediff(now, data->state.conn_cache->last_cleanup);
+ CONNCACHE_UNLOCK(data);
if(elapsed >= 1000L) {
struct prunedead prune;
@@ -954,32 +1013,20 @@ static void prune_dead_connections(struct Curl_easy *data)
prune.extracted = NULL;
while(Curl_conncache_foreach(data, data->state.conn_cache, &prune,
call_extract_if_dead)) {
+ /* unlocked */
+
+ /* remove connection from cache */
+ Curl_conncache_remove_conn(data, prune.extracted, TRUE);
+
/* disconnect it */
(void)Curl_disconnect(data, prune.extracted, /* dead_connection */TRUE);
}
+ CONNCACHE_LOCK(data);
data->state.conn_cache->last_cleanup = now;
+ CONNCACHE_UNLOCK(data);
}
}
-/* A connection has to have been idle for a shorter time than 'maxage_conn' to
- be subject for reuse. The success rate is just too low after this. */
-
-static bool conn_maxage(struct Curl_easy *data,
- struct connectdata *conn,
- struct curltime now)
-{
- if(!conn->data) {
- timediff_t idletime = Curl_timediff(now, conn->lastused);
- idletime /= 1000; /* integer seconds is fine */
-
- if(idletime/1000 > data->set.maxage_conn) {
- infof(data, "Too old connection (%ld seconds), disconnect it\n",
- idletime);
- return TRUE;
- }
- }
- return FALSE;
-}
/*
* Given one filled in connection struct (named needle), this function should
* detect if there already is one that has all the significant details
@@ -1003,16 +1050,20 @@ ConnectionExists(struct Curl_easy *data,
bool foundPendingCandidate = FALSE;
bool canmultiplex = IsMultiplexingPossible(data, needle);
struct connectbundle *bundle;
- struct curltime now = Curl_now();
+ const char *hostbundle;
#ifdef USE_NTLM
bool wantNTLMhttp = ((data->state.authhost.want &
(CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
(needle->handler->protocol & PROTO_FAMILY_HTTP));
+#ifndef CURL_DISABLE_PROXY
bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
((data->state.authproxy.want &
(CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
(needle->handler->protocol & PROTO_FAMILY_HTTP)));
+#else
+ bool wantProxyNTLMhttp = FALSE;
+#endif
#endif
*force_reuse = FALSE;
@@ -1020,24 +1071,23 @@ ConnectionExists(struct Curl_easy *data,
/* Look up the bundle with all the connections to this particular host.
Locks the connection cache, beware of early returns! */
- bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache);
+ bundle = Curl_conncache_find_bundle(needle, data->state.conn_cache,
+ &hostbundle);
if(bundle) {
/* Max pipe length is zero (unlimited) for multiplexed connections */
struct curl_llist_element *curr;
infof(data, "Found bundle for host %s: %p [%s]\n",
- (needle->bits.conn_to_host ? needle->conn_to_host.name :
- needle->host.name), (void *)bundle,
- (bundle->multiuse == BUNDLE_MULTIPLEX ?
- "can multiplex" : "serially"));
+ hostbundle, (void *)bundle, (bundle->multiuse == BUNDLE_MULTIPLEX ?
+ "can multiplex" : "serially"));
/* We can't multiplex if we don't know anything about the server */
if(canmultiplex) {
if(bundle->multiuse == BUNDLE_UNKNOWN) {
- if((bundle->multiuse == BUNDLE_UNKNOWN) && data->set.pipewait) {
+ if(data->set.pipewait) {
infof(data, "Server doesn't support multiplex yet, wait\n");
*waitpipe = TRUE;
- Curl_conncache_unlock(data);
+ CONNCACHE_UNLOCK(data);
return FALSE; /* no re-use */
}
@@ -1058,7 +1108,7 @@ ConnectionExists(struct Curl_easy *data,
curr = bundle->conn_list.head;
while(curr) {
bool match = FALSE;
- size_t multiplexed;
+ size_t multiplexed = 0;
/*
* Note that if we use a HTTP proxy in normal mode (no tunneling), we
@@ -1067,22 +1117,15 @@ ConnectionExists(struct Curl_easy *data,
check = curr->ptr;
curr = curr->next;
- if(check->bits.connect_only)
- /* connect-only connections will not be reused */
+ if(check->bits.connect_only || check->bits.close)
+ /* connect-only or to-be-closed connections will not be reused */
continue;
- if(conn_maxage(data, check, now) || extract_if_dead(check, data)) {
- /* disconnect it */
- (void)Curl_disconnect(data, check, /* dead_connection */TRUE);
- continue;
- }
-
- multiplexed = CONN_INUSE(check) &&
- (bundle->multiuse == BUNDLE_MULTIPLEX);
+ if(bundle->multiuse == BUNDLE_MULTIPLEX)
+ multiplexed = CONN_INUSE(check);
if(canmultiplex) {
- if(check->bits.protoconnstart && check->bits.close)
- continue;
+ ;
}
else {
if(multiplexed) {
@@ -1102,12 +1145,9 @@ ConnectionExists(struct Curl_easy *data,
}
}
- if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) ||
- check->bits.close) {
- if(!check->bits.close)
- foundPendingCandidate = TRUE;
- /* Don't pick a connection that hasn't connected yet or that is going
- to get closed. */
+ if(check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) {
+ foundPendingCandidate = TRUE;
+ /* Don't pick a connection that hasn't connected yet */
infof(data, "Connection #%ld isn't open enough, can't reuse\n",
check->connection_id);
continue;
@@ -1120,7 +1160,8 @@ ConnectionExists(struct Curl_easy *data,
continue;
if(strcmp(needle->unix_domain_socket, check->unix_domain_socket))
continue;
- if(needle->abstract_unix_socket != check->abstract_unix_socket)
+ if(needle->bits.abstract_unix_socket !=
+ check->bits.abstract_unix_socket)
continue;
}
else if(check->unix_domain_socket)
@@ -1131,18 +1172,20 @@ ConnectionExists(struct Curl_easy *data,
(check->handler->flags&PROTOPT_SSL))
/* don't do mixed SSL and non-SSL connections */
if(get_protocol_family(check->handler->protocol) !=
- needle->handler->protocol || !check->tls_upgraded)
+ needle->handler->protocol || !check->bits.tls_upgraded)
/* except protocols that have been upgraded via TLS */
continue;
+#ifndef CURL_DISABLE_PROXY
if(needle->bits.httpproxy != check->bits.httpproxy ||
needle->bits.socksproxy != check->bits.socksproxy)
continue;
- if(needle->bits.socksproxy && !proxy_info_matches(&needle->socks_proxy,
- &check->socks_proxy))
+ if(needle->bits.socksproxy &&
+ !socks_proxy_info_matches(&needle->socks_proxy,
+ &check->socks_proxy))
continue;
-
+#endif
if(needle->bits.conn_to_host != check->bits.conn_to_host)
/* don't mix connections that use the "connect to host" feature and
* connections that don't use this feature */
@@ -1153,6 +1196,7 @@ ConnectionExists(struct Curl_easy *data,
* connections that don't use this feature */
continue;
+#ifndef CURL_DISABLE_PROXY
if(needle->bits.httpproxy) {
if(!proxy_info_matches(&needle->http_proxy, &check->http_proxy))
continue;
@@ -1179,14 +1223,16 @@ ConnectionExists(struct Curl_easy *data,
}
}
}
+#endif
+
+ DEBUGASSERT(!check->data || GOOD_EASY_HANDLE(check->data));
if(!canmultiplex && check->data)
/* this request can't be multiplexed but the checked connection is
already in use so we skip it */
continue;
- if(CONN_INUSE(check) && check->data &&
- (check->data->multi != needle->data->multi))
+ if(check->data && (check->data->multi != needle->data->multi))
/* this could be subject for multiplex use, but only if they belong to
* the same multi handle */
continue;
@@ -1220,22 +1266,25 @@ ConnectionExists(struct Curl_easy *data,
}
}
- if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) ||
- needle->bits.tunnel_proxy) {
+ if((needle->handler->flags&PROTOPT_SSL)
+#ifndef CURL_DISABLE_PROXY
+ || !needle->bits.httpproxy || needle->bits.tunnel_proxy
+#endif
+ ) {
/* The requested connection does not use a HTTP proxy or it uses SSL or
it is a non-SSL protocol tunneled or it is a non-SSL protocol which
is allowed to be upgraded via TLS */
if((strcasecompare(needle->handler->scheme, check->handler->scheme) ||
(get_protocol_family(check->handler->protocol) ==
- needle->handler->protocol && check->tls_upgraded)) &&
+ needle->handler->protocol && check->bits.tls_upgraded)) &&
(!needle->bits.conn_to_host || strcasecompare(
needle->conn_to_host.name, check->conn_to_host.name)) &&
(!needle->bits.conn_to_port ||
needle->conn_to_port == check->conn_to_port) &&
strcasecompare(needle->host.name, check->host.name) &&
needle->remote_port == check->remote_port) {
- /* The schemes match or the the protocol family is the same and the
+ /* The schemes match or the protocol family is the same and the
previous connection was TLS upgraded, and the hostname and host
port match */
if(needle->handler->flags & PROTOPT_SSL) {
@@ -1276,14 +1325,21 @@ ConnectionExists(struct Curl_easy *data,
partway through a handshake!) */
if(wantNTLMhttp) {
if(strcmp(needle->user, check->user) ||
- strcmp(needle->passwd, check->passwd))
+ strcmp(needle->passwd, check->passwd)) {
+
+ /* we prefer a credential match, but this is at least a connection
+ that can be reused and "upgraded" to NTLM */
+ if(check->http_ntlm_state == NTLMSTATE_NONE)
+ chosen = check;
continue;
+ }
}
else if(check->http_ntlm_state != NTLMSTATE_NONE) {
/* Connection is using NTLM auth but we don't want NTLM */
continue;
}
+#ifndef CURL_DISABLE_PROXY
/* Same for Proxy NTLM authentication */
if(wantProxyNTLMhttp) {
/* Both check->http_proxy.user and check->http_proxy.passwd can be
@@ -1299,7 +1355,7 @@ ConnectionExists(struct Curl_easy *data,
/* Proxy connection is using NTLM auth but we don't want NTLM */
continue;
}
-
+#endif
if(wantNTLMhttp || wantProxyNTLMhttp) {
/* Credentials are already checked, we can use this connection */
chosen = check;
@@ -1337,6 +1393,13 @@ ConnectionExists(struct Curl_easy *data,
multiplexed);
continue;
}
+ else if(multiplexed >=
+ Curl_multi_max_concurrent_streams(needle->data->multi)) {
+ infof(data, "client side MAX_CONCURRENT_STREAMS reached"
+ ", skip (%zu)\n",
+ multiplexed);
+ continue;
+ }
}
#endif
/* When not multiplexed, we have a match here! */
@@ -1356,11 +1419,12 @@ ConnectionExists(struct Curl_easy *data,
if(chosen) {
/* mark it as used before releasing the lock */
chosen->data = data; /* own it! */
- Curl_conncache_unlock(data);
+ Curl_attach_connnection(data, chosen);
+ CONNCACHE_UNLOCK(data);
*usethis = chosen;
return TRUE; /* yes, we found one to use! */
}
- Curl_conncache_unlock(data);
+ CONNCACHE_UNLOCK(data);
if(foundPendingCandidate && data->set.pipewait) {
infof(data,
@@ -1371,58 +1435,6 @@ ConnectionExists(struct Curl_easy *data,
return FALSE; /* no matching connecting exists */
}
-/* after a TCP connection to the proxy has been verified, this function does
- the next magic step.
-
- Note: this function's sub-functions call failf()
-
-*/
-CURLcode Curl_connected_proxy(struct connectdata *conn, int sockindex)
-{
- CURLcode result = CURLE_OK;
-
- if(conn->bits.socksproxy) {
-#ifndef CURL_DISABLE_PROXY
- /* for the secondary socket (FTP), use the "connect to host"
- * but ignore the "connect to port" (use the secondary port)
- */
- const char * const host = conn->bits.httpproxy ?
- conn->http_proxy.host.name :
- conn->bits.conn_to_host ?
- conn->conn_to_host.name :
- sockindex == SECONDARYSOCKET ?
- conn->secondaryhostname : conn->host.name;
- const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port :
- sockindex == SECONDARYSOCKET ? conn->secondary_port :
- conn->bits.conn_to_port ? conn->conn_to_port :
- conn->remote_port;
- conn->bits.socksproxy_connecting = TRUE;
- switch(conn->socks_proxy.proxytype) {
- case CURLPROXY_SOCKS5:
- case CURLPROXY_SOCKS5_HOSTNAME:
- result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
- host, port, sockindex, conn);
- break;
-
- case CURLPROXY_SOCKS4:
- case CURLPROXY_SOCKS4A:
- result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
- conn);
- break;
-
- default:
- failf(conn->data, "unknown proxytype option given");
- result = CURLE_COULDNT_CONNECT;
- } /* switch proxytype */
- conn->bits.socksproxy_connecting = FALSE;
-#else
- (void)sockindex;
-#endif /* CURL_DISABLE_PROXY */
- }
-
- return result;
-}
-
/*
* verboseconnect() displays verbose information after a connect
*/
@@ -1431,142 +1443,27 @@ void Curl_verboseconnect(struct connectdata *conn)
{
if(conn->data->set.verbose)
infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n",
+#ifndef CURL_DISABLE_PROXY
conn->bits.socksproxy ? conn->socks_proxy.host.dispname :
conn->bits.httpproxy ? conn->http_proxy.host.dispname :
+#endif
conn->bits.conn_to_host ? conn->conn_to_host.dispname :
conn->host.dispname,
conn->ip_addr_str, conn->port, conn->connection_id);
}
#endif
-int Curl_protocol_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- if(conn->handler->proto_getsock)
- return conn->handler->proto_getsock(conn, socks, numsocks);
- /* Backup getsock logic. Since there is a live socket in use, we must wait
- for it or it will be removed from watching when the multi_socket API is
- used. */
- socks[0] = conn->sock[FIRSTSOCKET];
- return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0);
-}
-
-int Curl_doing_getsock(struct connectdata *conn,
- curl_socket_t *socks,
- int numsocks)
-{
- if(conn && conn->handler->doing_getsock)
- return conn->handler->doing_getsock(conn, socks, numsocks);
- return GETSOCK_BLANK;
-}
-
-/*
- * We are doing protocol-specific connecting and this is being called over and
- * over from the multi interface until the connection phase is done on
- * protocol layer.
- */
-
-CURLcode Curl_protocol_connecting(struct connectdata *conn,
- bool *done)
-{
- CURLcode result = CURLE_OK;
-
- if(conn && conn->handler->connecting) {
- *done = FALSE;
- result = conn->handler->connecting(conn, done);
- }
- else
- *done = TRUE;
-
- return result;
-}
-
-/*
- * We are DOING this is being called over and over from the multi interface
- * until the DOING phase is done on protocol layer.
- */
-
-CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
-{
- CURLcode result = CURLE_OK;
-
- if(conn && conn->handler->doing) {
- *done = FALSE;
- result = conn->handler->doing(conn, done);
- }
- else
- *done = TRUE;
-
- return result;
-}
-
-/*
- * We have discovered that the TCP connection has been successful, we can now
- * proceed with some action.
- *
- */
-CURLcode Curl_protocol_connect(struct connectdata *conn,
- bool *protocol_done)
-{
- CURLcode result = CURLE_OK;
-
- *protocol_done = FALSE;
-
- if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) {
- /* We already are connected, get back. This may happen when the connect
- worked fine in the first call, like when we connect to a local server
- or proxy. Note that we don't know if the protocol is actually done.
-
- Unless this protocol doesn't have any protocol-connect callback, as
- then we know we're done. */
- if(!conn->handler->connecting)
- *protocol_done = TRUE;
-
- return CURLE_OK;
- }
-
- if(!conn->bits.protoconnstart) {
-
- result = Curl_proxy_connect(conn, FIRSTSOCKET);
- if(result)
- return result;
-
- if(CONNECT_FIRSTSOCKET_PROXY_SSL())
- /* wait for HTTPS proxy SSL initialization to complete */
- return CURLE_OK;
-
- if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
- Curl_connect_ongoing(conn))
- /* when using an HTTP tunnel proxy, await complete tunnel establishment
- before proceeding further. Return CURLE_OK so we'll be called again */
- return CURLE_OK;
-
- if(conn->handler->connect_it) {
- /* is there a protocol-specific connect() procedure? */
-
- /* Call the protocol-specific connect function */
- result = conn->handler->connect_it(conn, protocol_done);
- }
- else
- *protocol_done = TRUE;
-
- /* it has started, possibly even completed but that knowledge isn't stored
- in this bit! */
- if(!result)
- conn->bits.protoconnstart = TRUE;
- }
-
- return result; /* pass back status */
-}
-
/*
* Helpers for IDNA conversions.
*/
-static bool is_ASCII_name(const char *hostname)
+bool Curl_is_ASCII_name(const char *hostname)
{
+ /* get an UNSIGNED local version of the pointer */
const unsigned char *ch = (const unsigned char *)hostname;
+ if(!hostname) /* bad input, consider it ASCII! */
+ return TRUE;
+
while(*ch) {
if(*ch++ & 0x80)
return FALSE;
@@ -1591,8 +1488,8 @@ static void strip_trailing_dot(struct hostname *host)
/*
* Perform any necessary IDN conversion of hostname
*/
-static CURLcode idnconvert_hostname(struct connectdata *conn,
- struct hostname *host)
+CURLcode Curl_idnconvert_hostname(struct connectdata *conn,
+ struct hostname *host)
{
struct Curl_easy *data = conn->data;
@@ -1607,7 +1504,7 @@ static CURLcode idnconvert_hostname(struct connectdata *conn,
host->dispname = host->name;
/* Check name for non-ASCII and convert hostname to ACE form if we can */
- if(!is_ASCII_name(host->name)) {
+ if(!Curl_is_ASCII_name(host->name)) {
#ifdef USE_LIBIDN2
if(idn2_check_version(IDN2_VERSION)) {
char *ace_hostname = NULL;
@@ -1640,7 +1537,9 @@ static CURLcode idnconvert_hostname(struct connectdata *conn,
host->name = host->encalloc;
}
else {
- failf(data, "Failed to convert %s to ACE;\n", host->name);
+ char buffer[STRERROR_LEN];
+ failf(data, "Failed to convert %s to ACE; %s\n", host->name,
+ Curl_winapi_strerror(GetLastError(), buffer, sizeof(buffer)));
return CURLE_URL_MALFORMAT;
}
#else
@@ -1653,7 +1552,7 @@ static CURLcode idnconvert_hostname(struct connectdata *conn,
/*
* Frees data allocated by idnconvert_hostname()
*/
-static void free_idnconverted_hostname(struct hostname *host)
+void Curl_free_idnconverted_hostname(struct hostname *host)
{
#if defined(USE_LIBIDN2)
if(host->encalloc) {
@@ -1670,13 +1569,6 @@ static void free_idnconverted_hostname(struct hostname *host)
#endif
}
-static void llist_dtor(void *user, void *element)
-{
- (void)user;
- (void)element;
- /* Do nothing */
-}
-
/*
* Allocate and initialize a new connectdata object.
*/
@@ -1701,8 +1593,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->ssl_extra = ssl;
conn->ssl[0].backend = (void *)ssl;
conn->ssl[1].backend = (void *)(ssl + sslsize);
+#ifndef CURL_DISABLE_PROXY
conn->proxy_ssl[0].backend = (void *)(ssl + 2 * sslsize);
conn->proxy_ssl[1].backend = (void *)(ssl + 3 * sslsize);
+#endif
}
#endif
@@ -1741,10 +1635,10 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->data = data; /* Setup the association between this connection
and the Curl_easy */
+#ifndef CURL_DISABLE_PROXY
conn->http_proxy.proxytype = data->set.proxytype;
conn->socks_proxy.proxytype = CURLPROXY_SOCKS4;
-#if !defined(CURL_DISABLE_PROXY)
/* note that these two proxy bits are now just on what looks to be
requested, they may be altered down the road */
conn->bits.proxy = (data->set.str[STRING_PROXY] &&
@@ -1775,20 +1669,24 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
conn->ssl_config.verifystatus = data->set.ssl.primary.verifystatus;
conn->ssl_config.verifypeer = data->set.ssl.primary.verifypeer;
conn->ssl_config.verifyhost = data->set.ssl.primary.verifyhost;
+#ifndef CURL_DISABLE_PROXY
conn->proxy_ssl_config.verifystatus =
data->set.proxy_ssl.primary.verifystatus;
conn->proxy_ssl_config.verifypeer = data->set.proxy_ssl.primary.verifypeer;
conn->proxy_ssl_config.verifyhost = data->set.proxy_ssl.primary.verifyhost;
+#endif
conn->ip_version = data->set.ipver;
conn->bits.connect_only = data->set.connect_only;
+ conn->transport = TRNSPRT_TCP; /* most of them are TCP streams */
#if !defined(CURL_DISABLE_HTTP) && defined(USE_NTLM) && \
defined(NTLM_WB_ENABLED)
- conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ conn->ntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ conn->proxyntlm.ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
#endif
/* Initialize the easy handle list */
- Curl_llist_init(&conn->easyq, (curl_llist_dtor) llist_dtor);
+ Curl_llist_init(&conn->easyq, NULL);
#ifdef HAVE_GSSAPI
conn->data_prot = PROT_CLEAR;
@@ -1807,6 +1705,7 @@ static struct connectdata *allocate_conn(struct Curl_easy *data)
it may live on without (this specific) Curl_easy */
conn->fclosesocket = data->set.fclosesocket;
conn->closesocket_client = data->set.closesocket_client;
+ conn->lastused = Curl_now(); /* used now */
return conn;
error:
@@ -1884,6 +1783,50 @@ CURLcode Curl_uc_to_curlcode(CURLUcode uc)
}
/*
+ * If the URL was set with an IPv6 numerical address with a zone id part, set
+ * the scope_id based on that!
+ */
+
+static void zonefrom_url(CURLU *uh, struct connectdata *conn)
+{
+ char *zoneid;
+ CURLUcode uc;
+
+ uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
+
+ if(!uc && zoneid) {
+ char *endp;
+ unsigned long scope = strtoul(zoneid, &endp, 10);
+ if(!*endp && (scope < UINT_MAX))
+ /* A plain number, use it directly as a scope id. */
+ conn->scope_id = (unsigned int)scope;
+#if defined(HAVE_IF_NAMETOINDEX)
+ else {
+#elif defined(WIN32)
+ else if(Curl_if_nametoindex) {
+#endif
+
+#if defined(HAVE_IF_NAMETOINDEX) || defined(WIN32)
+ /* Zone identifier is not numeric */
+ unsigned int scopeidx = 0;
+#if defined(WIN32)
+ scopeidx = Curl_if_nametoindex(zoneid);
+#else
+ scopeidx = if_nametoindex(zoneid);
+#endif
+ if(!scopeidx)
+ infof(conn->data, "Invalid zoneid: %s; %s\n", zoneid,
+ strerror(errno));
+ else
+ conn->scope_id = scopeidx;
+ }
+#endif /* HAVE_IF_NAMETOINDEX || WIN32 */
+
+ free(zoneid);
+ }
+}
+
+/*
* Parse URL and fill in the relevant members of the connection struct.
*/
static CURLcode parseurlandfillconn(struct Curl_easy *data,
@@ -1921,6 +1864,7 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
}
if(!data->set.uh) {
+ char *newurl;
uc = curl_url_set(uh, CURLUPART_URL, data->change.url,
CURLU_GUESS_SCHEME |
CURLU_NON_SUPPORT_SCHEME |
@@ -1931,6 +1875,15 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
DEBUGF(infof(data, "curl_url_set rejected %s\n", data->change.url));
return Curl_uc_to_curlcode(uc);
}
+
+ /* after it was parsed, get the generated normalized version */
+ uc = curl_url_get(uh, CURLUPART_URL, &newurl, 0);
+ if(uc)
+ return Curl_uc_to_curlcode(uc);
+ if(data->change.url_alloc)
+ free(data->change.url);
+ data->change.url = newurl;
+ data->change.url_alloc = TRUE;
}
uc = curl_url_get(uh, CURLUPART_SCHEME, &data->state.up.scheme, 0);
@@ -1941,23 +1894,32 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
if(result)
return result;
- uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user,
- CURLU_URLDECODE);
+ /* we don't use the URL API's URL decoder option here since it rejects
+ control codes and we want to allow them for some schemes in the user and
+ password fields */
+ uc = curl_url_get(uh, CURLUPART_USER, &data->state.up.user, 0);
if(!uc) {
- conn->user = strdup(data->state.up.user);
- if(!conn->user)
- return CURLE_OUT_OF_MEMORY;
+ char *decoded;
+ result = Curl_urldecode(NULL, data->state.up.user, 0, &decoded, NULL,
+ conn->handler->flags&PROTOPT_USERPWDCTRL ?
+ REJECT_ZERO : REJECT_CTRL);
+ if(result)
+ return result;
+ conn->user = decoded;
conn->bits.user_passwd = TRUE;
}
else if(uc != CURLUE_NO_USER)
return Curl_uc_to_curlcode(uc);
- uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password,
- CURLU_URLDECODE);
+ uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
if(!uc) {
- conn->passwd = strdup(data->state.up.password);
- if(!conn->passwd)
- return CURLE_OUT_OF_MEMORY;
+ char *decoded;
+ result = Curl_urldecode(NULL, data->state.up.password, 0, &decoded, NULL,
+ conn->handler->flags&PROTOPT_USERPWDCTRL ?
+ REJECT_ZERO : REJECT_CTRL);
+ if(result)
+ return result;
+ conn->passwd = decoded;
conn->bits.user_passwd = TRUE;
}
else if(uc != CURLUE_NO_PASSWORD)
@@ -1991,55 +1953,27 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
}
else {
unsigned long port = strtoul(data->state.up.port, NULL, 10);
- conn->remote_port = curlx_ultous(port);
+ conn->port = conn->remote_port = curlx_ultous(port);
}
(void)curl_url_get(uh, CURLUPART_QUERY, &data->state.up.query, 0);
hostname = data->state.up.hostname;
- if(!hostname)
- /* this is for file:// transfers, get a dummy made */
- hostname = (char *)"";
-
- if(hostname[0] == '[') {
+ if(hostname && hostname[0] == '[') {
/* This looks like an IPv6 address literal. See if there is an address
scope. */
- char *zoneid;
size_t hlen;
- uc = curl_url_get(uh, CURLUPART_ZONEID, &zoneid, 0);
conn->bits.ipv6_ip = TRUE;
-
/* cut off the brackets! */
hostname++;
hlen = strlen(hostname);
hostname[hlen - 1] = 0;
- if(!uc && zoneid) {
- char *endp;
- unsigned long scope;
- scope = strtoul(zoneid, &endp, 10);
- if(!*endp && (scope < UINT_MAX)) {
- /* A plain number, use it direcly as a scope id. */
- conn->scope_id = (unsigned int)scope;
- }
-#ifdef HAVE_IF_NAMETOINDEX
- else {
- /* Zone identifier is not numeric */
- unsigned int scopeidx = 0;
- scopeidx = if_nametoindex(zoneid);
- if(!scopeidx)
- infof(data, "Invalid zoneid id: %s; %s\n", zoneid,
- strerror(errno));
- else
- conn->scope_id = scopeidx;
- }
-#endif /* HAVE_IF_NAMETOINDEX */
- free(zoneid);
- }
+ zonefrom_url(uh, conn);
}
/* make sure the connect struct gets its own copy of the host name */
- conn->host.rawalloc = strdup(hostname);
+ conn->host.rawalloc = strdup(hostname ? hostname : "");
if(!conn->host.rawalloc)
return CURLE_OUT_OF_MEMORY;
conn->host.name = conn->host.rawalloc;
@@ -2095,9 +2029,8 @@ static CURLcode setup_range(struct Curl_easy *data)
*/
static CURLcode setup_connection_internals(struct connectdata *conn)
{
- const struct Curl_handler * p;
+ const struct Curl_handler *p;
CURLcode result;
- conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
/* Perform setup complement if some. */
p = conn->handler;
@@ -2128,6 +2061,11 @@ void Curl_free_request_state(struct Curl_easy *data)
{
Curl_safefree(data->req.protop);
Curl_safefree(data->req.newurl);
+
+#ifndef CURL_DISABLE_DOH
+ Curl_close(&data->req.doh.probe[0].easy);
+ Curl_close(&data->req.doh.probe[1].easy);
+#endif
}
@@ -2298,7 +2236,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
struct connectdata *conn, char *proxy,
curl_proxytype proxytype)
{
- char *portptr;
+ char *portptr = NULL;
long port = -1;
char *proxyuser = NULL;
char *proxypasswd = NULL;
@@ -2422,6 +2360,7 @@ static CURLcode parse_proxy(struct Curl_easy *data,
size_t len = strlen(host);
host[len-1] = 0; /* clear the trailing bracket */
host++;
+ zonefrom_url(uhp, conn);
}
proxyinfo->host.name = host;
@@ -2437,26 +2376,16 @@ static CURLcode parse_proxy(struct Curl_easy *data,
static CURLcode parse_proxy_auth(struct Curl_easy *data,
struct connectdata *conn)
{
- char proxyuser[MAX_CURL_USER_LENGTH]="";
- char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
- CURLcode result;
-
- if(data->set.str[STRING_PROXYUSERNAME] != NULL) {
- strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME],
- MAX_CURL_USER_LENGTH);
- proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/
- }
- if(data->set.str[STRING_PROXYPASSWORD] != NULL) {
- strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD],
- MAX_CURL_PASSWORD_LENGTH);
- proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
- }
+ char *proxyuser = data->set.str[STRING_PROXYUSERNAME];
+ char *proxypasswd = data->set.str[STRING_PROXYPASSWORD];
+ CURLcode result = CURLE_OK;
- result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL,
- FALSE);
- if(!result)
+ if(proxyuser)
+ result = Curl_urldecode(data, proxyuser, 0, &conn->http_proxy.user, NULL,
+ REJECT_ZERO);
+ if(!result && proxypasswd)
result = Curl_urldecode(data, proxypasswd, 0, &conn->http_proxy.passwd,
- NULL, FALSE);
+ NULL, REJECT_ZERO);
return result;
}
@@ -2674,6 +2603,12 @@ CURLcode Curl_parse_login_details(const char *login, const size_t len,
size_t plen;
size_t olen;
+ /* the input length check is because this is called directcly from setopt
+ and isn't going through the regular string length check */
+ size_t llen = strlen(login);
+ if(llen > CURL_MAX_INPUT_LENGTH)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
/* Attempt to find the password separator */
if(passwdp) {
psep = strchr(login, ':');
@@ -2846,8 +2781,7 @@ static CURLcode override_login(struct Curl_easy *data,
&netrc_user_changed, &netrc_passwd_changed,
data->set.str[STRING_NETRC_FILE]);
if(ret > 0) {
- infof(data, "Couldn't find host %s in the "
- DOT_CHAR "netrc file; using defaults\n",
+ infof(data, "Couldn't find host %s in the .netrc file; using defaults\n",
conn->host.name);
}
else if(ret < 0) {
@@ -2871,12 +2805,14 @@ static CURLcode override_login(struct Curl_easy *data,
/* for updated strings, we update them in the URL */
if(user_changed) {
- uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp, 0);
+ uc = curl_url_set(data->state.uh, CURLUPART_USER, *userp,
+ CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
}
if(passwd_changed) {
- uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp, 0);
+ uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD, *passwdp,
+ CURLU_URLENCODE);
if(uc)
return Curl_uc_to_curlcode(uc);
}
@@ -2913,13 +2849,6 @@ static CURLcode set_login(struct connectdata *conn)
result = CURLE_OUT_OF_MEMORY;
}
- /* if there's a user without password, consider password blank */
- if(conn->user && !conn->passwd) {
- conn->passwd = strdup("");
- if(!conn->passwd)
- result = CURLE_OUT_OF_MEMORY;
- }
-
return result;
}
@@ -3142,28 +3071,74 @@ static CURLcode parse_connect_to_slist(struct Curl_easy *data,
#ifdef USE_ALTSVC
if(data->asi && !host && (port == -1) &&
- (conn->handler->protocol == CURLPROTO_HTTPS)) {
+ ((conn->handler->protocol == CURLPROTO_HTTPS) ||
+#ifdef CURLDEBUG
+ /* allow debug builds to circumvent the HTTPS restriction */
+ getenv("CURL_ALTSVC_HTTP")
+#else
+ 0
+#endif
+ )) {
/* no connect_to match, try alt-svc! */
- const char *nhost;
- int nport;
- enum alpnid nalpnid;
+ enum alpnid srcalpnid;
bool hit;
+ struct altsvc *as;
+ const int allowed_versions = ( ALPN_h1
+#ifdef USE_NGHTTP2
+ | ALPN_h2
+#endif
+#ifdef ENABLE_QUIC
+ | ALPN_h3
+#endif
+ ) & data->asi->flags;
+
host = conn->host.rawalloc;
+#ifdef USE_NGHTTP2
+ /* with h2 support, check that first */
+ srcalpnid = ALPN_h2;
hit = Curl_altsvc_lookup(data->asi,
- ALPN_h1, host, conn->remote_port, /* from */
- &nalpnid, &nhost, &nport /* to */);
+ srcalpnid, host, conn->remote_port, /* from */
+ &as /* to */,
+ allowed_versions);
+ if(!hit)
+#endif
+ {
+ srcalpnid = ALPN_h1;
+ hit = Curl_altsvc_lookup(data->asi,
+ srcalpnid, host, conn->remote_port, /* from */
+ &as /* to */,
+ allowed_versions);
+ }
if(hit) {
- char *hostd = strdup((char *)nhost);
+ char *hostd = strdup((char *)as->dst.host);
if(!hostd)
return CURLE_OUT_OF_MEMORY;
conn->conn_to_host.rawalloc = hostd;
conn->conn_to_host.name = hostd;
conn->bits.conn_to_host = TRUE;
- conn->conn_to_port = nport;
+ conn->conn_to_port = as->dst.port;
conn->bits.conn_to_port = TRUE;
+ conn->bits.altused = TRUE;
infof(data, "Alt-svc connecting from [%s]%s:%d to [%s]%s:%d\n",
- Curl_alpnid2str(ALPN_h1), host, conn->remote_port,
- Curl_alpnid2str(nalpnid), hostd, nport);
+ Curl_alpnid2str(srcalpnid), host, conn->remote_port,
+ Curl_alpnid2str(as->dst.alpnid), hostd, as->dst.port);
+ if(srcalpnid != as->dst.alpnid) {
+ /* protocol version switch */
+ switch(as->dst.alpnid) {
+ case ALPN_h1:
+ conn->httpversion = 11;
+ break;
+ case ALPN_h2:
+ conn->httpversion = 20;
+ break;
+ case ALPN_h3:
+ conn->transport = TRNSPRT_QUIC;
+ conn->httpversion = 30;
+ break;
+ default: /* shouldn't be possible */
+ break;
+ }
+ }
}
}
#endif
@@ -3210,7 +3185,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
else {
bool longpath = FALSE;
hostaddr->addr = Curl_unix2addr(path, &longpath,
- conn->abstract_unix_socket);
+ conn->bits.abstract_unix_socket);
if(hostaddr->addr)
hostaddr->inuse++;
else {
@@ -3228,6 +3203,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
}
else
#endif
+
if(!conn->bits.proxy) {
struct hostname *connhost;
if(conn->bits.conn_to_host)
@@ -3256,10 +3232,11 @@ static CURLcode resolve_server(struct Curl_easy *data,
else if(!hostaddr) {
failf(data, "Couldn't resolve host '%s'", connhost->dispname);
- result = CURLE_COULDNT_RESOLVE_HOST;
+ result = CURLE_COULDNT_RESOLVE_HOST;
/* don't return yet, we need to clean up the timeout first */
}
}
+#ifndef CURL_DISABLE_PROXY
else {
/* This is a proxy that hasn't been resolved yet. */
@@ -3285,6 +3262,7 @@ static CURLcode resolve_server(struct Curl_easy *data,
/* don't return yet, we need to clean up the timeout first */
}
}
+#endif
DEBUGASSERT(conn->dns_entry == NULL);
conn->dns_entry = hostaddr;
}
@@ -3300,16 +3278,17 @@ static CURLcode resolve_server(struct Curl_easy *data,
static void reuse_conn(struct connectdata *old_conn,
struct connectdata *conn)
{
- free_idnconverted_hostname(&old_conn->http_proxy.host);
- free_idnconverted_hostname(&old_conn->socks_proxy.host);
+#ifndef CURL_DISABLE_PROXY
+ Curl_free_idnconverted_hostname(&old_conn->http_proxy.host);
+ Curl_free_idnconverted_hostname(&old_conn->socks_proxy.host);
free(old_conn->http_proxy.host.rawalloc);
free(old_conn->socks_proxy.host.rawalloc);
-
+ Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config);
+#endif
/* free the SSL config struct from this connection struct as this was
allocated in vain and is targeted for destruction */
Curl_free_primary_ssl_config(&old_conn->ssl_config);
- Curl_free_primary_ssl_config(&old_conn->proxy_ssl_config);
conn->data = old_conn->data;
@@ -3326,6 +3305,7 @@ static void reuse_conn(struct connectdata *old_conn,
old_conn->passwd = NULL;
}
+#ifndef CURL_DISABLE_PROXY
conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
if(conn->bits.proxy_user_passwd) {
/* use the new proxy user name and proxy password though */
@@ -3342,11 +3322,16 @@ static void reuse_conn(struct connectdata *old_conn,
old_conn->http_proxy.passwd = NULL;
old_conn->socks_proxy.passwd = NULL;
}
+ Curl_safefree(old_conn->http_proxy.user);
+ Curl_safefree(old_conn->socks_proxy.user);
+ Curl_safefree(old_conn->http_proxy.passwd);
+ Curl_safefree(old_conn->socks_proxy.passwd);
+#endif
/* host can change, when doing keepalive with a proxy or if the case is
different this time etc */
- free_idnconverted_hostname(&conn->host);
- free_idnconverted_hostname(&conn->conn_to_host);
+ Curl_free_idnconverted_hostname(&conn->host);
+ Curl_free_idnconverted_hostname(&conn->conn_to_host);
Curl_safefree(conn->host.rawalloc);
Curl_safefree(conn->conn_to_host.rawalloc);
conn->host = old_conn->host;
@@ -3369,10 +3354,6 @@ static void reuse_conn(struct connectdata *old_conn,
Curl_safefree(old_conn->user);
Curl_safefree(old_conn->passwd);
Curl_safefree(old_conn->options);
- Curl_safefree(old_conn->http_proxy.user);
- Curl_safefree(old_conn->socks_proxy.user);
- Curl_safefree(old_conn->http_proxy.passwd);
- Curl_safefree(old_conn->socks_proxy.passwd);
Curl_safefree(old_conn->localdev);
Curl_llist_destroy(&old_conn->easyq, NULL);
@@ -3442,9 +3423,9 @@ static CURLcode create_conn(struct Curl_easy *data,
if(result)
goto out;
- if(data->set.str[STRING_BEARER]) {
- conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
- if(!conn->oauth_bearer) {
+ if(data->set.str[STRING_SASL_AUTHZID]) {
+ conn->sasl_authzid = strdup(data->set.str[STRING_SASL_AUTHZID]);
+ if(!conn->sasl_authzid) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
@@ -3457,7 +3438,7 @@ static CURLcode create_conn(struct Curl_easy *data,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
- conn->abstract_unix_socket = data->set.abstract_unix_socket;
+ conn->bits.abstract_unix_socket = data->set.abstract_unix_socket;
}
#endif
@@ -3467,7 +3448,6 @@ static CURLcode create_conn(struct Curl_easy *data,
result = create_conn_helper_init_proxy(conn);
if(result)
goto out;
-#endif
/*************************************************************
* If the protocol is using SSL and HTTP proxy is used, we set
@@ -3475,6 +3455,7 @@ static CURLcode create_conn(struct Curl_easy *data,
*************************************************************/
if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
conn->bits.tunnel_proxy = TRUE;
+#endif
/*************************************************************
* Figure out the remote port number and fix it in the URL
@@ -3505,24 +3486,26 @@ static CURLcode create_conn(struct Curl_easy *data,
/*************************************************************
* IDN-convert the hostnames
*************************************************************/
- result = idnconvert_hostname(conn, &conn->host);
+ result = Curl_idnconvert_hostname(conn, &conn->host);
if(result)
goto out;
if(conn->bits.conn_to_host) {
- result = idnconvert_hostname(conn, &conn->conn_to_host);
+ result = Curl_idnconvert_hostname(conn, &conn->conn_to_host);
if(result)
goto out;
}
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy) {
- result = idnconvert_hostname(conn, &conn->http_proxy.host);
+ result = Curl_idnconvert_hostname(conn, &conn->http_proxy.host);
if(result)
goto out;
}
if(conn->bits.socksproxy) {
- result = idnconvert_hostname(conn, &conn->socks_proxy.host);
+ result = Curl_idnconvert_hostname(conn, &conn->socks_proxy.host);
if(result)
goto out;
}
+#endif
/*************************************************************
* Check whether the host and the "connect to host" are equal.
@@ -3541,6 +3524,7 @@ static CURLcode create_conn(struct Curl_easy *data,
conn->bits.conn_to_port = FALSE;
}
+#ifndef CURL_DISABLE_PROXY
/*************************************************************
* If the "connect to" feature is used with an HTTP proxy,
* we set the tunnel_proxy bit.
@@ -3548,6 +3532,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
conn->bits.httpproxy)
conn->bits.tunnel_proxy = TRUE;
+#endif
/*************************************************************
* Setup internals depending on protocol. Needs to be done after
@@ -3580,6 +3565,7 @@ static CURLcode create_conn(struct Curl_easy *data,
if(!result) {
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
+ Curl_attach_connnection(data, conn);
result = Curl_conncache_add_conn(data->state.conn_cache, conn);
if(result)
goto out;
@@ -3594,7 +3580,6 @@ static CURLcode create_conn(struct Curl_easy *data,
(void)conn->handler->done(conn, result, FALSE);
goto out;
}
- Curl_attach_connnection(data, conn);
Curl_setup_transfer(data, -1, -1, FALSE, -1);
}
@@ -3615,57 +3600,75 @@ static CURLcode create_conn(struct Curl_easy *data,
copies will be separately allocated.
*/
data->set.ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_ORIG];
- data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
data->set.ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_ORIG];
- data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
data->set.ssl.primary.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
- data->set.proxy_ssl.primary.random_file =
- data->set.str[STRING_SSL_RANDOM_FILE];
data->set.ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
- data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
data->set.ssl.primary.cipher_list =
data->set.str[STRING_SSL_CIPHER_LIST_ORIG];
- data->set.proxy_ssl.primary.cipher_list =
- data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
data->set.ssl.primary.cipher_list13 =
data->set.str[STRING_SSL_CIPHER13_LIST_ORIG];
+ data->set.ssl.primary.pinned_key =
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_ORIG];
+ data->set.ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
+
+#ifndef CURL_DISABLE_PROXY
+ data->set.proxy_ssl.primary.CApath = data->set.str[STRING_SSL_CAPATH_PROXY];
+ data->set.proxy_ssl.primary.CAfile = data->set.str[STRING_SSL_CAFILE_PROXY];
+ data->set.proxy_ssl.primary.random_file =
+ data->set.str[STRING_SSL_RANDOM_FILE];
+ data->set.proxy_ssl.primary.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
+ data->set.proxy_ssl.primary.cipher_list =
+ data->set.str[STRING_SSL_CIPHER_LIST_PROXY];
data->set.proxy_ssl.primary.cipher_list13 =
data->set.str[STRING_SSL_CIPHER13_LIST_PROXY];
-
- data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
+ data->set.proxy_ssl.primary.pinned_key =
+ data->set.str[STRING_SSL_PINNEDPUBLICKEY_PROXY];
+ data->set.proxy_ssl.primary.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
data->set.proxy_ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_PROXY];
- data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG];
data->set.proxy_ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_PROXY];
- data->set.ssl.cert = data->set.str[STRING_CERT_ORIG];
data->set.proxy_ssl.cert = data->set.str[STRING_CERT_PROXY];
- data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG];
data->set.proxy_ssl.cert_type = data->set.str[STRING_CERT_TYPE_PROXY];
- data->set.ssl.key = data->set.str[STRING_KEY_ORIG];
data->set.proxy_ssl.key = data->set.str[STRING_KEY_PROXY];
- data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG];
data->set.proxy_ssl.key_type = data->set.str[STRING_KEY_TYPE_PROXY];
- data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG];
data->set.proxy_ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_PROXY];
- data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG];
data->set.proxy_ssl.primary.clientcert = data->set.str[STRING_CERT_PROXY];
+ data->set.proxy_ssl.cert_blob = data->set.blobs[BLOB_CERT_PROXY];
+ data->set.proxy_ssl.key_blob = data->set.blobs[BLOB_KEY_PROXY];
+#endif
+ data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE_ORIG];
+ data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT_ORIG];
+ data->set.ssl.cert = data->set.str[STRING_CERT_ORIG];
+ data->set.ssl.cert_type = data->set.str[STRING_CERT_TYPE_ORIG];
+ data->set.ssl.key = data->set.str[STRING_KEY_ORIG];
+ data->set.ssl.key_type = data->set.str[STRING_KEY_TYPE_ORIG];
+ data->set.ssl.key_passwd = data->set.str[STRING_KEY_PASSWD_ORIG];
+ data->set.ssl.primary.clientcert = data->set.str[STRING_CERT_ORIG];
#ifdef USE_TLS_SRP
data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_ORIG];
- data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_ORIG];
+#ifndef CURL_DISABLE_PROXY
+ data->set.proxy_ssl.username = data->set.str[STRING_TLSAUTH_USERNAME_PROXY];
data->set.proxy_ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD_PROXY];
#endif
+#endif
+
+ data->set.ssl.cert_blob = data->set.blobs[BLOB_CERT_ORIG];
+ data->set.ssl.key_blob = data->set.blobs[BLOB_KEY_ORIG];
+ data->set.ssl.issuercert_blob = data->set.blobs[BLOB_SSL_ISSUERCERT_ORIG];
if(!Curl_clone_primary_ssl_config(&data->set.ssl.primary,
- &conn->ssl_config)) {
+ &conn->ssl_config)) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+#ifndef CURL_DISABLE_PROXY
if(!Curl_clone_primary_ssl_config(&data->set.proxy_ssl.primary,
&conn->proxy_ssl_config)) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
+#endif
prune_dead_connections(data);
@@ -3688,25 +3691,6 @@ static CURLcode create_conn(struct Curl_easy *data,
else
reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse, &waitpipe);
- /* If we found a reusable connection that is now marked as in use, we may
- still want to open a new connection if we are multiplexing. */
- if(reuse && !force_reuse && IsMultiplexingPossible(data, conn_temp)) {
- size_t multiplexed = CONN_INUSE(conn_temp);
- if(multiplexed > 0) {
- infof(data, "Found connection %ld, with %zu requests on it\n",
- conn_temp->connection_id, multiplexed);
-
- if(Curl_conncache_bundle_size(conn_temp) < max_host_connections &&
- Curl_conncache_size(data) < max_total_connections) {
- /* We want a new connection anyway */
- reuse = FALSE;
-
- infof(data, "We can reuse, but we want a new connection anyway\n");
- Curl_conncache_return_conn(conn_temp);
- }
- }
- }
-
if(reuse) {
/*
* We already have a connection for this, we got the former connection
@@ -3722,12 +3706,17 @@ static CURLcode create_conn(struct Curl_easy *data,
conn = conn_temp;
*in_connect = conn;
+#ifndef CURL_DISABLE_PROXY
infof(data, "Re-using existing connection! (#%ld) with %s %s\n",
conn->connection_id,
conn->bits.proxy?"proxy":"host",
conn->socks_proxy.host.name ? conn->socks_proxy.host.dispname :
conn->http_proxy.host.name ? conn->http_proxy.host.dispname :
- conn->host.dispname);
+ conn->host.dispname);
+#else
+ infof(data, "Re-using existing connection! (#%ld) with host %s\n",
+ conn->connection_id, conn->host.dispname);
+#endif
}
else {
/* We have decided that we want a new connection. However, we may not
@@ -3749,8 +3738,9 @@ static CURLcode create_conn(struct Curl_easy *data,
connections_available = FALSE;
else {
/* this gets a lock on the conncache */
+ const char *bundlehost;
struct connectbundle *bundle =
- Curl_conncache_find_bundle(conn, data->state.conn_cache);
+ Curl_conncache_find_bundle(conn, data->state.conn_cache, &bundlehost);
if(max_host_connections > 0 && bundle &&
(bundle->num_connections >= max_host_connections)) {
@@ -3758,19 +3748,19 @@ static CURLcode create_conn(struct Curl_easy *data,
/* The bundle is full. Extract the oldest connection. */
conn_candidate = Curl_conncache_extract_bundle(data, bundle);
- Curl_conncache_unlock(data);
+ CONNCACHE_UNLOCK(data);
if(conn_candidate)
(void)Curl_disconnect(data, conn_candidate,
/* dead_connection */ FALSE);
else {
- infof(data, "No more connections allowed to host: %zu\n",
- max_host_connections);
+ infof(data, "No more connections allowed to host %s: %zu\n",
+ bundlehost, max_host_connections);
connections_available = FALSE;
}
}
else
- Curl_conncache_unlock(data);
+ CONNCACHE_UNLOCK(data);
}
@@ -3804,6 +3794,8 @@ static CURLcode create_conn(struct Curl_easy *data,
* This is a brand new connection, so let's store it in the connection
* cache of ours!
*/
+ Curl_attach_connnection(data, conn);
+
result = Curl_conncache_add_conn(data->state.conn_cache, conn);
if(result)
goto out;
@@ -3855,10 +3847,12 @@ static CURLcode create_conn(struct Curl_easy *data,
/* Strip trailing dots. resolve_server copied the name. */
strip_trailing_dot(&conn->host);
+#ifndef CURL_DISABLE_PROXY
if(conn->bits.httpproxy)
strip_trailing_dot(&conn->http_proxy.host);
if(conn->bits.socksproxy)
strip_trailing_dot(&conn->socks_proxy.host);
+#endif
if(conn->bits.conn_to_host)
strip_trailing_dot(&conn->conn_to_host);
@@ -3889,22 +3883,23 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
}
*protocol_done = FALSE; /* default to not done */
+#ifndef CURL_DISABLE_PROXY
/* set proxy_connect_closed to false unconditionally already here since it
is used strictly to provide extra information to a parent function in the
case of proxy CONNECT failures and we must make sure we don't have it
lingering set from a previous invoke */
conn->bits.proxy_connect_closed = FALSE;
-
+#endif
/*
* Set user-agent. Used for HTTP, but since we can attempt to tunnel
* basically anything through a http proxy we can't limit this based on
* protocol.
*/
if(data->set.str[STRING_USERAGENT]) {
- Curl_safefree(conn->allocptr.uagent);
- conn->allocptr.uagent =
+ Curl_safefree(data->state.aptr.uagent);
+ data->state.aptr.uagent =
aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
- if(!conn->allocptr.uagent)
+ if(!data->state.aptr.uagent)
return CURLE_OUT_OF_MEMORY;
}
@@ -3926,7 +3921,9 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
}
else {
Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
- Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+ if(conn->ssl[FIRSTSOCKET].use ||
+ (conn->handler->protocol & PROTO_FAMILY_SSH))
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
*protocol_done = TRUE;
Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]);
@@ -3956,7 +3953,7 @@ CURLcode Curl_connect(struct Curl_easy *data,
result = create_conn(data, &conn, asyncp);
if(!result) {
- if(CONN_INUSE(conn))
+ if(CONN_INUSE(conn) > 1)
/* multiplexed */
*protocol_done = TRUE;
else if(!*asyncp) {
@@ -3973,11 +3970,10 @@ CURLcode Curl_connect(struct Curl_easy *data,
else if(result && conn) {
/* We're not allowed to return failure with memory left allocated in the
connectdata struct, free those here */
+ Curl_detach_connnection(data);
+ Curl_conncache_remove_conn(data, conn, TRUE);
Curl_disconnect(data, conn, TRUE);
}
- else if(!result && !data->conn)
- /* FILE: transfers already have the connection attached */
- Curl_attach_connnection(data, conn);
return result;
}
@@ -3996,6 +3992,11 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
struct SingleRequest *k = &data->req;
+ /* if this is a pushed stream, we need this: */
+ CURLcode result = Curl_preconnect(data);
+ if(result)
+ return result;
+
if(conn) {
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
use */
@@ -4008,30 +4009,17 @@ CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
data->state.done = FALSE; /* *_done() is not called yet */
data->state.expect100header = FALSE;
-
if(data->set.opt_no_body)
/* in HTTP lingo, no body means using the HEAD request... */
- data->set.httpreq = HTTPREQ_HEAD;
- else if(HTTPREQ_HEAD == data->set.httpreq)
- /* ... but if unset there really is no perfect method that is the
- "opposite" of HEAD but in reality most people probably think GET
- then. The important thing is that we can't let it remain HEAD if the
- opt_no_body is set FALSE since then we'll behave wrong when getting
- HTTP. */
- data->set.httpreq = HTTPREQ_GET;
+ data->state.httpreq = HTTPREQ_HEAD;
k->start = Curl_now(); /* start time */
k->now = k->start; /* current time is now */
k->header = TRUE; /* assume header */
-
k->bytecount = 0;
-
- k->buf = data->state.buffer;
- k->hbufp = data->state.headerbuff;
k->ignorebody = FALSE;
Curl_speedinit(data);
-
Curl_pgrsSetUploadCounter(data, 0);
Curl_pgrsSetDownloadCounter(data, 0);
@@ -4147,34 +4135,3 @@ static unsigned int get_protocol_family(unsigned int protocol)
return family;
}
-
-
-/*
- * Wrapper to call functions in Curl_conncache_foreach()
- *
- * Returns always 0.
- */
-static int conn_upkeep(struct connectdata *conn,
- void *param)
-{
- /* Param is unused. */
- (void)param;
-
- if(conn->handler->connection_check) {
- /* Do a protocol-specific keepalive check on the connection. */
- conn->handler->connection_check(conn, CONNCHECK_KEEPALIVE);
- }
-
- return 0; /* continue iteration */
-}
-
-CURLcode Curl_upkeep(struct conncache *conn_cache,
- void *data)
-{
- /* Loop over every connection and make connection alive. */
- Curl_conncache_foreach(data,
- conn_cache,
- data,
- conn_upkeep);
- return CURLE_OK;
-}