summaryrefslogtreecommitdiffstats
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.c1449
1 files changed, 908 insertions, 541 deletions
diff --git a/Utilities/cmcurl/lib/url.c b/Utilities/cmcurl/lib/url.c
index 406c1f0..e547e5c 100644
--- a/Utilities/cmcurl/lib/url.c
+++ b/Utilities/cmcurl/lib/url.c
@@ -5,11 +5,11 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2016, 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 http://curl.haxx.se/docs/copyright.html.
+ * 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
@@ -75,7 +75,7 @@ void idn_free (void *ptr);
#endif
#elif defined(USE_WIN32_IDN)
/* prototype for curl_win32_idn_to_ascii() */
-int curl_win32_idn_to_ascii(const char *in, char **out);
+bool curl_win32_idn_to_ascii(const char *in, char **out);
#endif /* USE_LIBIDN */
#include "urldata.h"
@@ -111,6 +111,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
#include "telnet.h"
#include "tftp.h"
#include "http.h"
+#include "http2.h"
#include "file.h"
#include "curl_ldap.h"
#include "ssh.h"
@@ -118,7 +119,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
#include "url.h"
#include "connect.h"
#include "inet_ntop.h"
-#include "curl_ntlm.h"
+#include "http_ntlm.h"
#include "curl_ntlm_wb.h"
#include "socks.h"
#include "curl_rtmp.h"
@@ -129,26 +130,27 @@ int curl_win32_idn_to_ascii(const char *in, char **out);
#include "pipeline.h"
#include "dotdot.h"
#include "strdup.h"
+/* The last 3 #include files should be in this order */
#include "curl_printf.h"
#include "curl_memory.h"
-/* The last #include file should be: */
#include "memdebug.h"
/* Local static prototypes */
static struct connectdata *
-find_oldest_idle_connection(struct SessionHandle *data);
-static struct connectdata *
-find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
+find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
struct connectbundle *bundle);
static void conn_free(struct connectdata *conn);
+static void free_fixed_hostname(struct hostname *host);
static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
-static CURLcode parse_url_login(struct SessionHandle *data,
+static CURLcode parse_url_login(struct Curl_easy *data,
struct connectdata *conn,
char **userptr, char **passwdptr,
char **optionsptr);
static CURLcode parse_login_details(const char *login, const size_t len,
char **userptr, char **passwdptr,
char **optionsptr);
+static unsigned int get_protocol_family(unsigned int protocol);
+
/*
* Protocol table.
*/
@@ -275,7 +277,7 @@ static const struct Curl_handler Curl_handler_dummy = {
PROTOPT_NONE /* flags */
};
-void Curl_freeset(struct SessionHandle *data)
+void Curl_freeset(struct Curl_easy *data)
{
/* Free all dynamic strings stored in the data->set substructure. */
enum dupstring i;
@@ -295,7 +297,7 @@ void Curl_freeset(struct SessionHandle *data)
data->change.url = NULL;
}
-static CURLcode setstropt(char **charp, char *s)
+static CURLcode setstropt(char **charp, const char *s)
{
/* Release the previous storage at `charp' and replace by a dynamic storage
copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
@@ -303,12 +305,12 @@ static CURLcode setstropt(char **charp, char *s)
Curl_safefree(*charp);
if(s) {
- s = strdup(s);
+ char *str = strdup(s);
- if(!s)
+ if(!str)
return CURLE_OUT_OF_MEMORY;
- *charp = s;
+ *charp = str;
}
return CURLE_OK;
@@ -353,7 +355,7 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
return result;
}
-CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src)
+CURLcode Curl_dupset(struct Curl_easy *dst, struct Curl_easy *src)
{
CURLcode result = CURLE_OK;
enum dupstring i;
@@ -396,7 +398,7 @@ CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src)
* when curl_easy_perform() is invoked.
*/
-CURLcode Curl_close(struct SessionHandle *data)
+CURLcode Curl_close(struct Curl_easy *data)
{
struct Curl_multi *m;
@@ -482,28 +484,34 @@ CURLcode Curl_close(struct SessionHandle *data)
Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
}
+ if(data->set.wildcardmatch) {
+ /* destruct wildcard structures if it is needed */
+ struct WildcardData *wc = &data->wildcard;
+ Curl_wildcard_dtor(wc);
+ }
+
Curl_freeset(data);
free(data);
return CURLE_OK;
}
/*
- * Initialize the UserDefined fields within a SessionHandle.
- * This may be safely called on a new or existing SessionHandle.
+ * Initialize the UserDefined fields within a Curl_easy.
+ * This may be safely called on a new or existing Curl_easy.
*/
CURLcode Curl_init_userdefined(struct UserDefined *set)
{
CURLcode result = CURLE_OK;
set->out = stdout; /* default output to stdout */
- set->in = stdin; /* default input from stdin */
+ set->in_set = stdin; /* default input from stdin */
set->err = stderr; /* default stderr to stderr */
/* use fwrite as default function to store output */
set->fwrite_func = (curl_write_callback)fwrite;
/* use fread as default function to read input */
- set->fread_func = (curl_read_callback)fread;
+ set->fread_func_set = (curl_read_callback)fread;
set->is_fread_set = 0;
set->is_fwrite_set = 0;
@@ -569,33 +577,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
* seem not to follow rfc1961 section 4.3/4.4
*/
set->socks5_gssapi_nec = FALSE;
- /* set default GSS-API service name */
- result = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE],
- (char *) CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE);
- if(result)
- return result;
-
- /* set default negotiate proxy service name */
- result = setstropt(&set->str[STRING_PROXY_SERVICE_NAME],
- (char *) CURL_DEFAULT_PROXY_SERVICE_NAME);
- if(result)
- return result;
-
- /* set default negotiate service name */
- result = setstropt(&set->str[STRING_SERVICE_NAME],
- (char *) CURL_DEFAULT_SERVICE_NAME);
- if(result)
- return result;
#endif
/* This is our preferred CA cert bundle/path since install time */
#if defined(CURL_CA_BUNDLE)
- result = setstropt(&set->str[STRING_SSL_CAFILE], (char *) CURL_CA_BUNDLE);
+ result = setstropt(&set->str[STRING_SSL_CAFILE], CURL_CA_BUNDLE);
if(result)
return result;
#endif
#if defined(CURL_CA_PATH)
- result = setstropt(&set->str[STRING_SSL_CAPATH], (char *) CURL_CA_PATH);
+ result = setstropt(&set->str[STRING_SSL_CAPATH], CURL_CA_PATH);
if(result)
return result;
#endif
@@ -610,12 +601,15 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
set->tcp_keepalive = FALSE;
set->tcp_keepintvl = 60;
set->tcp_keepidle = 60;
+ set->tcp_fastopen = FALSE;
set->ssl_enable_npn = TRUE;
set->ssl_enable_alpn = TRUE;
set->expect_100_timeout = 1000L; /* Wait for a second by default. */
set->sep_headers = TRUE; /* separated header lists by default */
+
+ Curl_http2_init_userset(set);
return result;
}
@@ -627,16 +621,16 @@ CURLcode Curl_init_userdefined(struct UserDefined *set)
* @return CURLcode
*/
-CURLcode Curl_open(struct SessionHandle **curl)
+CURLcode Curl_open(struct Curl_easy **curl)
{
CURLcode result;
- struct SessionHandle *data;
+ struct Curl_easy *data;
/* Very simple start-up: alloc the struct, init it with zeroes and return */
- data = calloc(1, sizeof(struct SessionHandle));
+ data = calloc(1, sizeof(struct Curl_easy));
if(!data) {
/* this is a very serious error */
- DEBUGF(fprintf(stderr, "Error: calloc of SessionHandle failed\n"));
+ DEBUGF(fprintf(stderr, "Error: calloc of Curl_easy failed\n"));
return CURLE_OUT_OF_MEMORY;
}
@@ -673,6 +667,8 @@ CURLcode Curl_open(struct SessionHandle **curl)
data->wildcard.filelist = NULL;
data->set.fnmatch = ZERO_NULL;
data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+
+ Curl_http2_init_state(&data->state);
}
if(result) {
@@ -688,7 +684,7 @@ CURLcode Curl_open(struct SessionHandle **curl)
return result;
}
-CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
+CURLcode Curl_setopt(struct Curl_easy *data, CURLoption option,
va_list param)
{
char *argptr;
@@ -705,7 +701,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
case CURLOPT_DNS_USE_GLOBAL_CACHE:
/* remember we want this enabled */
arg = va_arg(param, long);
- data->set.global_dns_cache = (0 != arg)?TRUE:FALSE;
+ data->set.global_dns_cache = (0 != arg) ? TRUE : FALSE;
break;
case CURLOPT_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection */
@@ -740,33 +736,33 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* When this transfer is done, it must not be left to be reused by a
* subsequent transfer but shall be closed immediately.
*/
- data->set.reuse_forbid = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.reuse_forbid = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FRESH_CONNECT:
/*
* This transfer shall not use a previously cached connection but
* should be made with a fresh new connect!
*/
- data->set.reuse_fresh = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.reuse_fresh = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_VERBOSE:
/*
* Verbose means infof() calls that give a lot of information about
* the connection and transfer procedures as well as internal choices.
*/
- data->set.verbose = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.verbose = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_HEADER:
/*
* Set to include the header in the general data output stream.
*/
- data->set.include_header = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.include_header = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_NOPROGRESS:
/*
* Shut off the internal supported progress meter
*/
- data->set.hide_progress = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.hide_progress = (0 != va_arg(param, long)) ? TRUE : FALSE;
if(data->set.hide_progress)
data->progress.flags |= PGRS_HIDE;
else
@@ -776,14 +772,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Do not include the body part in the output data stream.
*/
- data->set.opt_no_body = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.opt_no_body = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FAILONERROR:
/*
* Don't output the >=400 error code HTML-page, but instead only
* return error.
*/
- data->set.http_fail_on_error = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.http_fail_on_error = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_UPLOAD:
case CURLOPT_PUT:
@@ -791,7 +787,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* We want to sent data to the remote host. If this is HTTP, that equals
* using the PUT request.
*/
- data->set.upload = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.upload = (0 != va_arg(param, long)) ? TRUE : FALSE;
if(data->set.upload) {
/* If this is HTTP, PUT is what's needed to "upload" */
data->set.httpreq = HTTPREQ_PUT;
@@ -807,7 +803,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* Try to get the file time of the remote document. The time will
* later (possibly) become available using curl_easy_getinfo().
*/
- data->set.get_filetime = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.get_filetime = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FTP_CREATE_MISSING_DIRS:
/*
@@ -835,11 +831,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* Option that specifies how quickly an server response must be obtained
* before it is considered failure. For pingpong protocols.
*/
- data->set.server_response_timeout = va_arg( param , long ) * 1000;
+ data->set.server_response_timeout = va_arg(param, long) * 1000;
+ break;
+ case CURLOPT_TFTP_NO_OPTIONS:
+ /*
+ * Option that prevents libcurl from sending TFTP option requests to the
+ * server.
+ */
+ data->set.tftp_no_options = va_arg(param, long) != 0;
break;
case CURLOPT_TFTP_BLKSIZE:
/*
- * TFTP option that specifies the block size to use for data transmission
+ * TFTP option that specifies the block size to use for data transmission.
*/
data->set.tftp_blksize = va_arg(param, long);
break;
@@ -848,13 +851,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* An option that changes the command to one that asks for a list
* only, no file info details.
*/
- data->set.ftp_list_only = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ftp_list_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_APPEND:
/*
* We want to upload and append to an existing file.
*/
- data->set.ftp_append = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ftp_append = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FTP_FILEMETHOD:
/*
@@ -882,7 +885,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*
* Transfer using ASCII (instead of BINARY).
*/
- data->set.prefer_ascii = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.prefer_ascii = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_TIMECONDITION:
/*
@@ -915,7 +918,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Switch on automatic referer that gets set if curl follows locations.
*/
- data->set.http_auto_referer = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.http_auto_referer = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_ACCEPT_ENCODING:
@@ -931,18 +934,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
argptr = va_arg(param, char *);
result = setstropt(&data->set.str[STRING_ENCODING],
(argptr && !*argptr)?
- (char *) ALL_CONTENT_ENCODINGS: argptr);
+ ALL_CONTENT_ENCODINGS: argptr);
break;
case CURLOPT_TRANSFER_ENCODING:
- data->set.http_transfer_encoding = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.http_transfer_encoding = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
break;
case CURLOPT_FOLLOWLOCATION:
/*
* Follow Location: header hints on a HTTP-server.
*/
- data->set.http_follow_location = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.http_follow_location = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_UNRESTRICTED_AUTH:
@@ -951,7 +955,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* hostname changed.
*/
data->set.http_disable_hostname_check_before_authentication =
- (0 != va_arg(param, long))?TRUE:FALSE;
+ (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_MAXREDIRS:
@@ -1212,7 +1216,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* We run mostly with the original cookie spec, as hardly anyone implements
* anything else.
*/
- data->set.cookiesession = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.cookiesession = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_COOKIELIST:
@@ -1289,7 +1293,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*/
arg = va_arg(param, long);
#ifndef USE_NGHTTP2
- if(arg == CURL_HTTP_VERSION_2_0)
+ if(arg >= CURL_HTTP_VERSION_2)
return CURLE_UNSUPPORTED_PROTOCOL;
#endif
data->set.httpversion = arg;
@@ -1311,7 +1315,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/* the DIGEST_IE bit is only used to set a special marker, for all the
rest we need to handle it as normal DIGEST */
- data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE;
+ data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
if(auth & CURLAUTH_DIGEST_IE) {
auth |= CURLAUTH_DIGEST; /* set standard digest bit */
@@ -1374,7 +1378,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Tunnel operations through the proxy instead of normal proxy use
*/
- data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long)) ?
+ TRUE : FALSE;
break;
case CURLOPT_PROXYPORT:
@@ -1400,7 +1405,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/* the DIGEST_IE bit is only used to set a special marker, for all the
rest we need to handle it as normal DIGEST */
- data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE;
+ data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE) ? TRUE : FALSE;
if(auth & CURLAUTH_DIGEST_IE) {
auth |= CURLAUTH_DIGEST; /* set standard digest bit */
@@ -1475,32 +1480,28 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
#endif /* CURL_DISABLE_PROXY */
#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
- case CURLOPT_SOCKS5_GSSAPI_SERVICE:
+ case CURLOPT_SOCKS5_GSSAPI_NEC:
/*
- * Set GSS-API service name
+ * Set flag for NEC SOCK5 support
*/
- result = setstropt(&data->set.str[STRING_SOCKS5_GSSAPI_SERVICE],
- va_arg(param, char *));
+ data->set.socks5_gssapi_nec = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
+ case CURLOPT_SOCKS5_GSSAPI_SERVICE:
case CURLOPT_PROXY_SERVICE_NAME:
/*
- * Set negotiate proxy service name
+ * Set proxy authentication service name for Kerberos 5 and SPNEGO
*/
result = setstropt(&data->set.str[STRING_PROXY_SERVICE_NAME],
va_arg(param, char *));
break;
+#endif
- case CURLOPT_SOCKS5_GSSAPI_NEC:
- /*
- * set flag for nec socks5 support
- */
- data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE;
- break;
-
+#if !defined(CURL_DISABLE_CRYPTO_AUTH) || defined(USE_KERBEROS5) || \
+ defined(USE_SPNEGO)
case CURLOPT_SERVICE_NAME:
/*
- * Set negotiate service identity
+ * Set authentication service name for DIGEST-MD5, Kerberos 5 and SPNEGO
*/
result = setstropt(&data->set.str[STRING_SERVICE_NAME],
va_arg(param, char *));
@@ -1534,20 +1535,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*/
result = setstropt(&data->set.str[STRING_FTPPORT],
va_arg(param, char *));
- data->set.ftp_use_port = (NULL != data->set.str[STRING_FTPPORT]) ?
- TRUE:FALSE;
+ data->set.ftp_use_port = (data->set.str[STRING_FTPPORT]) ? TRUE : FALSE;
break;
case CURLOPT_FTP_USE_EPRT:
- data->set.ftp_use_eprt = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ftp_use_eprt = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FTP_USE_EPSV:
- data->set.ftp_use_epsv = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ftp_use_epsv = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FTP_USE_PRET:
- data->set.ftp_use_pret = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ftp_use_pret = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FTP_SSL_CCC:
@@ -1559,7 +1559,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
* bypass of the IP address in PASV responses.
*/
- data->set.ftp_skip_ip = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ftp_skip_ip = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_READDATA:
@@ -1567,7 +1567,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* FILE pointer to read the file to be uploaded from. Or possibly
* used as argument to the read callback.
*/
- data->set.in = va_arg(param, void *);
+ data->set.in_set = va_arg(param, void *);
break;
case CURLOPT_INFILESIZE:
/*
@@ -1695,7 +1695,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
case CURLOPT_XOAUTH2_BEARER:
/*
- * XOAUTH2 bearer token to use in the operation
+ * OAuth 2.0 bearer token to use in the operation
*/
result = setstropt(&data->set.str[STRING_BEARER],
va_arg(param, char *));
@@ -1862,11 +1862,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Read data callback
*/
- data->set.fread_func = va_arg(param, curl_read_callback);
- if(!data->set.fread_func) {
+ data->set.fread_func_set = va_arg(param, curl_read_callback);
+ if(!data->set.fread_func_set) {
data->set.is_fread_set = 0;
/* When set to NULL, reset to our internal default function */
- data->set.fread_func = (curl_read_callback)fread;
+ data->set.fread_func_set = (curl_read_callback)fread;
}
else
data->set.is_fread_set = 1;
@@ -1967,7 +1967,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Kludgy option to enable CRLF conversions. Subject for removal.
*/
- data->set.crlf = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.crlf = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_INTERFACE:
@@ -1996,7 +1996,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*/
result = setstropt(&data->set.str[STRING_KRB_LEVEL],
va_arg(param, char *));
- data->set.krb = (NULL != data->set.str[STRING_KRB_LEVEL])?TRUE:FALSE;
+ data->set.krb = (data->set.str[STRING_KRB_LEVEL]) ? TRUE : FALSE;
break;
case CURLOPT_GSSAPI_DELEGATION:
/*
@@ -2008,7 +2008,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* Enable peer SSL verifying.
*/
- data->set.ssl.verifypeer = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ssl.verifypeer = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_SSL_VERIFYHOST:
/*
@@ -2026,7 +2026,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
return CURLE_BAD_FUNCTION_ARGUMENT;
}
- data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE;
+ data->set.ssl.verifyhost = (0 != arg) ? TRUE : FALSE;
break;
case CURLOPT_SSL_VERIFYSTATUS:
/*
@@ -2037,7 +2037,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
}
- data->set.ssl.verifystatus = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ssl.verifystatus = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_SSL_CTX_FUNCTION:
#ifdef have_curlssl_ssl_ctx
@@ -2068,22 +2068,26 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
}
- data->set.ssl.falsestart = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ssl.falsestart = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_CERTINFO:
#ifdef have_curlssl_certinfo
- data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ssl.certinfo = (0 != va_arg(param, long)) ? TRUE : FALSE;
#else
result = CURLE_NOT_BUILT_IN;
#endif
break;
case CURLOPT_PINNEDPUBLICKEY:
+#ifdef have_curlssl_pinnedpubkey /* only by supported backends */
/*
* Set pinned public key for SSL connection.
* Specify file name of the public key in DER format.
*/
result = setstropt(&data->set.str[STRING_SSL_PINNEDPUBLICKEY],
va_arg(param, char *));
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
break;
case CURLOPT_CAINFO:
/*
@@ -2135,7 +2139,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*/
data->set.buffer_size = va_arg(param, long);
- if((data->set.buffer_size> (BUFSIZE -1 )) ||
+ if((data->set.buffer_size> (BUFSIZE -1)) ||
(data->set.buffer_size < 1))
data->set.buffer_size = 0; /* huge internal default */
@@ -2146,7 +2150,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* The application asks not to set any signal() or alarm() handlers,
* even when using a timeout.
*/
- data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.no_signal = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_SHARE:
@@ -2262,7 +2266,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
* Enable or disable TCP_NODELAY, which will disable/enable the Nagle
* algorithm
*/
- data->set.tcp_nodelay = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.tcp_nodelay = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FTP_ACCOUNT:
@@ -2271,14 +2275,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
case CURLOPT_IGNORE_CONTENT_LENGTH:
- data->set.ignorecl = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ignorecl = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_CONNECT_ONLY:
/*
* No data transfer, set up connection and let application use the socket
*/
- data->set.connect_only = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.connect_only = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_FTP_ALTERNATIVE_TO_USER:
@@ -2331,7 +2335,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
case CURLOPT_SSL_SESSIONID_CACHE:
- data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ssl.sessionid = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
#ifdef USE_LIBSSH2
@@ -2392,14 +2396,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
/*
* disable libcurl transfer encoding is used
*/
- data->set.http_te_skip = (0 == va_arg(param, long))?TRUE:FALSE;
+ data->set.http_te_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_HTTP_CONTENT_DECODING:
/*
* raw data passed to the application when content encoding is used
*/
- data->set.http_ce_skip = (0 == va_arg(param, long))?TRUE:FALSE;
+ data->set.http_ce_skip = (0 == va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_NEW_FILE_PERMS:
@@ -2441,6 +2445,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
data->set.redir_protocols = va_arg(param, long);
break;
+ case CURLOPT_DEFAULT_PROTOCOL:
+ /* Set the protocol to use when the URL doesn't include any protocol */
+ result = setstropt(&data->set.str[STRING_DEFAULT_PROTOCOL],
+ va_arg(param, char *));
+ break;
+
case CURLOPT_MAIL_FROM:
/* Set the SMTP mail originator */
result = setstropt(&data->set.str[STRING_MAIL_FROM],
@@ -2573,7 +2583,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
case CURLOPT_WILDCARDMATCH:
- data->set.wildcardmatch = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.wildcardmatch = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_CHUNK_BGN_FUNCTION:
data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
@@ -2624,7 +2634,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
break;
case CURLOPT_TCP_KEEPALIVE:
- data->set.tcp_keepalive = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.tcp_keepalive = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_TCP_KEEPIDLE:
data->set.tcp_keepidle = va_arg(param, long);
@@ -2632,11 +2642,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
case CURLOPT_TCP_KEEPINTVL:
data->set.tcp_keepintvl = va_arg(param, long);
break;
+ case CURLOPT_TCP_FASTOPEN:
+#if defined(CONNECT_DATA_IDEMPOTENT) || defined(MSG_FASTOPEN)
+ data->set.tcp_fastopen = (0 != va_arg(param, long))?TRUE:FALSE;
+#else
+ result = CURLE_NOT_BUILT_IN;
+#endif
+ break;
case CURLOPT_SSL_ENABLE_NPN:
- data->set.ssl_enable_npn = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ssl_enable_npn = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_SSL_ENABLE_ALPN:
- data->set.ssl_enable_alpn = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.ssl_enable_alpn = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
#ifdef USE_UNIX_SOCKETS
@@ -2647,10 +2664,36 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
#endif
case CURLOPT_PATH_AS_IS:
- data->set.path_as_is = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.path_as_is = (0 != va_arg(param, long)) ? TRUE : FALSE;
break;
case CURLOPT_PIPEWAIT:
- data->set.pipewait = (0 != va_arg(param, long))?TRUE:FALSE;
+ data->set.pipewait = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLOPT_STREAM_WEIGHT:
+#ifndef USE_NGHTTP2
+ return CURLE_NOT_BUILT_IN;
+#else
+ arg = va_arg(param, long);
+ if((arg>=1) && (arg <= 256))
+ data->set.stream_weight = (int)arg;
+ break;
+#endif
+ case CURLOPT_STREAM_DEPENDS:
+ case CURLOPT_STREAM_DEPENDS_E:
+ {
+#ifndef USE_NGHTTP2
+ return CURLE_NOT_BUILT_IN;
+#else
+ struct Curl_easy *dep = va_arg(param, struct Curl_easy *);
+ if(dep && GOOD_EASY_HANDLE(dep)) {
+ data->set.stream_depends_on = dep;
+ data->set.stream_depends_e = (option == CURLOPT_STREAM_DEPENDS_E);
+ }
+ break;
+#endif
+ }
+ case CURLOPT_CONNECT_TO:
+ data->set.connect_to = va_arg(param, struct curl_slist *);
break;
default:
/* unknown tag and its companion, just ignore: */
@@ -2661,6 +2704,45 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
return result;
}
+#ifdef USE_RECV_BEFORE_SEND_WORKAROUND
+static void conn_reset_postponed_data(struct connectdata *conn, int num)
+{
+ struct postponed_data * const psnd = &(conn->postponed[num]);
+ if(psnd->buffer) {
+ DEBUGASSERT(psnd->allocated_size > 0);
+ DEBUGASSERT(psnd->recv_size <= psnd->allocated_size);
+ DEBUGASSERT(psnd->recv_size ?
+ (psnd->recv_processed < psnd->recv_size) :
+ (psnd->recv_processed == 0));
+ DEBUGASSERT(psnd->bindsock != CURL_SOCKET_BAD);
+ free(psnd->buffer);
+ psnd->buffer = NULL;
+ psnd->allocated_size = 0;
+ psnd->recv_size = 0;
+ psnd->recv_processed = 0;
+#ifdef DEBUGBUILD
+ psnd->bindsock = CURL_SOCKET_BAD; /* used only for DEBUGASSERT */
+#endif /* DEBUGBUILD */
+ }
+ else {
+ DEBUGASSERT (psnd->allocated_size == 0);
+ DEBUGASSERT (psnd->recv_size == 0);
+ DEBUGASSERT (psnd->recv_processed == 0);
+ DEBUGASSERT (psnd->bindsock == CURL_SOCKET_BAD);
+ }
+}
+
+static void conn_reset_all_postponed_data(struct connectdata *conn)
+{
+ conn_reset_postponed_data(conn, 0);
+ conn_reset_postponed_data(conn, 1);
+}
+#else /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+/* Use "do-nothing" macros instead of functions when workaround not used */
+#define conn_reset_postponed_data(c,n) do {} WHILE_FALSE
+#define conn_reset_all_postponed_data(c) do {} WHILE_FALSE
+#endif /* ! USE_RECV_BEFORE_SEND_WORKAROUND */
+
static void conn_free(struct connectdata *conn)
{
if(!conn)
@@ -2691,7 +2773,7 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->user);
Curl_safefree(conn->passwd);
- Curl_safefree(conn->xoauth2_bearer);
+ Curl_safefree(conn->oauth_bearer);
Curl_safefree(conn->options);
Curl_safefree(conn->proxyuser);
Curl_safefree(conn->proxypasswd);
@@ -2707,9 +2789,12 @@ static void conn_free(struct connectdata *conn)
Curl_safefree(conn->allocptr.rtsp_transport);
Curl_safefree(conn->trailer);
Curl_safefree(conn->host.rawalloc); /* host name buffer */
+ Curl_safefree(conn->conn_to_host.rawalloc); /* host name buffer */
Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
Curl_safefree(conn->master_buffer);
+ conn_reset_all_postponed_data(conn);
+
Curl_llist_destroy(conn->send_pipe, NULL);
Curl_llist_destroy(conn->recv_pipe, NULL);
@@ -2727,14 +2812,14 @@ static void conn_free(struct connectdata *conn)
* primary connection, like when freeing room in the connection cache or
* killing of a dead old connection.
*
- * This function MUST NOT reset state in the SessionHandle struct if that
+ * This function MUST NOT reset state in the Curl_easy struct if that
* isn't strictly bound to the life-time of *this* particular connection.
*
*/
CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
{
- struct SessionHandle *data;
+ struct Curl_easy *data;
if(!conn)
return CURLE_OK; /* this is closed and fine already */
data = conn->data;
@@ -2764,23 +2849,9 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
infof(data, "Closing connection %ld\n", conn->connection_id);
Curl_conncache_remove_conn(data->state.conn_cache, conn);
-#if defined(USE_LIBIDN)
- if(conn->host.encalloc)
- idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed
- with idn_free() since this was allocated
- by libidn */
- if(conn->proxy.encalloc)
- idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be
- freed with idn_free() since this was
- allocated by libidn */
-#elif defined(USE_WIN32_IDN)
- free(conn->host.encalloc); /* encoded host name buffer, must be freed with
- idn_free() since this was allocated by
- curl_win32_idn_to_ascii */
- free(conn->proxy.encalloc); /* encoded proxy name buffer, must be freed
- with idn_free() since this was allocated by
- curl_win32_idn_to_ascii */
-#endif
+ free_fixed_hostname(&conn->host);
+ free_fixed_hostname(&conn->conn_to_host);
+ free_fixed_hostname(&conn->proxy);
Curl_ssl_close(conn, FIRSTSOCKET);
@@ -2817,7 +2888,7 @@ static bool SocketIsDead(curl_socket_t sock)
* IsPipeliningPossible() returns TRUE if the options set would allow
* pipelining/multiplexing and the connection is using a HTTP protocol.
*/
-static bool IsPipeliningPossible(const struct SessionHandle *handle,
+static bool IsPipeliningPossible(const struct Curl_easy *handle,
const struct connectdata *conn)
{
/* If a HTTP protocol and pipelining is enabled */
@@ -2831,25 +2902,27 @@ static bool IsPipeliningPossible(const struct SessionHandle *handle,
return TRUE;
if(Curl_pipeline_wanted(handle->multi, CURLPIPE_MULTIPLEX) &&
- (handle->set.httpversion == CURL_HTTP_VERSION_2_0))
+ (handle->set.httpversion >= CURL_HTTP_VERSION_2))
/* allows HTTP/2 */
return TRUE;
}
return FALSE;
}
-int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
+int Curl_removeHandleFromPipeline(struct Curl_easy *handle,
struct curl_llist *pipeline)
{
- struct curl_llist_element *curr;
+ if(pipeline) {
+ struct curl_llist_element *curr;
- curr = pipeline->head;
- while(curr) {
- if(curr->ptr == handle) {
- Curl_llist_remove(pipeline, curr, NULL);
- return 1; /* we removed a handle */
+ curr = pipeline->head;
+ while(curr) {
+ if(curr->ptr == handle) {
+ Curl_llist_remove(pipeline, curr, NULL);
+ return 1; /* we removed a handle */
+ }
+ curr = curr->next;
}
- curr = curr->next;
}
return 0;
@@ -2862,18 +2935,18 @@ static void Curl_printPipeline(struct curl_llist *pipeline)
curr = pipeline->head;
while(curr) {
- struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
+ struct Curl_easy *data = (struct Curl_easy *) curr->ptr;
infof(data, "Handle in pipeline: %s\n", data->state.path);
curr = curr->next;
}
}
#endif
-static struct SessionHandle* gethandleathead(struct curl_llist *pipeline)
+static struct Curl_easy* gethandleathead(struct curl_llist *pipeline)
{
struct curl_llist_element *curr = pipeline->head;
if(curr) {
- return (struct SessionHandle *) curr->ptr;
+ return (struct Curl_easy *) curr->ptr;
}
return NULL;
@@ -2881,7 +2954,7 @@ static struct SessionHandle* gethandleathead(struct curl_llist *pipeline)
/* remove the specified connection from all (possible) pipelines and related
queues */
-void Curl_getoff_all_pipelines(struct SessionHandle *data,
+void Curl_getoff_all_pipelines(struct Curl_easy *data,
struct connectdata *conn)
{
bool recv_head = (conn->readchannel_inuse &&
@@ -2905,7 +2978,7 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
curr = pipeline->head;
while(curr) {
struct curl_llist_element *next = curr->next;
- struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
+ struct Curl_easy *data = (struct Curl_easy *) curr->ptr;
#ifdef DEBUGBUILD /* debug-only code */
if(data->magic != CURLEASY_MAGIC_NUMBER) {
@@ -2929,8 +3002,8 @@ static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
* Returns the pointer to the oldest idle connection, or NULL if none was
* found.
*/
-static struct connectdata *
-find_oldest_idle_connection(struct SessionHandle *data)
+struct connectdata *
+Curl_oldest_idle_connection(struct Curl_easy *data)
{
struct conncache *bc = data->state.conn_cache;
struct curl_hash_iterator iter;
@@ -2982,7 +3055,7 @@ find_oldest_idle_connection(struct SessionHandle *data)
* found.
*/
static struct connectdata *
-find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
+find_oldest_idle_connection_in_bundle(struct Curl_easy *data,
struct connectbundle *bundle)
{
struct curl_llist_element *curr;
@@ -3022,7 +3095,7 @@ find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
* Returns TRUE if the connection actually was dead and disconnected.
*/
static bool disconnect_if_dead(struct connectdata *conn,
- struct SessionHandle *data)
+ struct Curl_easy *data)
{
size_t pipeLen = conn->send_pipe->size + conn->recv_pipe->size;
if(!pipeLen && !conn->inuse) {
@@ -3056,7 +3129,7 @@ static bool disconnect_if_dead(struct connectdata *conn,
static int call_disconnect_if_dead(struct connectdata *conn,
void *param)
{
- struct SessionHandle* data = (struct SessionHandle*)param;
+ struct Curl_easy* data = (struct Curl_easy*)param;
disconnect_if_dead(conn, data);
return 0; /* continue iteration */
}
@@ -3066,7 +3139,7 @@ static int call_disconnect_if_dead(struct connectdata *conn,
* closes and removes them.
* The cleanup is done at most once per second.
*/
-static void prune_dead_connections(struct SessionHandle *data)
+static void prune_dead_connections(struct Curl_easy *data)
{
struct timeval now = Curl_tvnow();
long elapsed = Curl_tvdiff(now, data->state.conn_cache->last_cleanup);
@@ -3098,7 +3171,7 @@ static size_t max_pipeline_length(struct Curl_multi *multi)
* the pipelining strategy wants to open a new connection instead of reusing.
*/
static bool
-ConnectionExists(struct SessionHandle *data,
+ConnectionExists(struct Curl_easy *data,
struct connectdata *needle,
struct connectdata **usethis,
bool *force_reuse,
@@ -3106,13 +3179,19 @@ ConnectionExists(struct SessionHandle *data,
{
struct connectdata *check;
struct connectdata *chosen = 0;
+ bool foundPendingCandidate = FALSE;
bool canPipeline = IsPipeliningPossible(data, needle);
+ struct connectbundle *bundle;
+
#ifdef USE_NTLM
- bool wantNTLMhttp = ((data->state.authhost.want & CURLAUTH_NTLM) ||
- (data->state.authhost.want & CURLAUTH_NTLM_WB)) &&
- (needle->handler->protocol & PROTO_FAMILY_HTTP) ? TRUE : FALSE;
+ bool wantNTLMhttp = ((data->state.authhost.want &
+ (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP));
+ bool wantProxyNTLMhttp = (needle->bits.proxy_user_passwd &&
+ ((data->state.authproxy.want &
+ (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
+ (needle->handler->protocol & PROTO_FAMILY_HTTP)));
#endif
- struct connectbundle *bundle;
*force_reuse = FALSE;
*waitpipe = FALSE;
@@ -3131,9 +3210,19 @@ ConnectionExists(struct SessionHandle *data,
max_pipeline_length(data->multi):0;
size_t best_pipe_len = max_pipe_len;
struct curl_llist_element *curr;
+ const char *hostname;
- infof(data, "Found bundle for host %s: %p\n",
- needle->host.name, (void *)bundle);
+ if(needle->bits.conn_to_host)
+ hostname = needle->conn_to_host.name;
+ else
+ hostname = needle->host.name;
+
+ infof(data, "Found bundle for host %s: %p [%s]\n",
+ hostname, (void *)bundle,
+ (bundle->multiuse== BUNDLE_PIPELINING?
+ "can pipeline":
+ (bundle->multiuse== BUNDLE_MULTIPLEX?
+ "can multiplex":"serially")));
/* We can't pipe if we don't know anything about the server */
if(canPipeline) {
@@ -3147,19 +3236,27 @@ ConnectionExists(struct SessionHandle *data,
infof(data, "Server doesn't support multi-use (yet)\n");
canPipeline = FALSE;
}
+ if((bundle->multiuse == BUNDLE_PIPELINING) &&
+ !Curl_pipeline_wanted(data->multi, CURLPIPE_HTTP1)) {
+ /* not asked for, switch off */
+ infof(data, "Could pipeline, but not asked to!\n");
+ canPipeline = FALSE;
+ }
+ else if((bundle->multiuse == BUNDLE_MULTIPLEX) &&
+ !Curl_pipeline_wanted(data->multi, CURLPIPE_MULTIPLEX)) {
+ infof(data, "Could multiplex, but not asked to!\n");
+ canPipeline = FALSE;
+ }
}
curr = bundle->conn_list->head;
while(curr) {
bool match = FALSE;
-#if defined(USE_NTLM)
- bool credentialsMatch = FALSE;
-#endif
size_t pipeLen;
/*
- * Note that if we use a HTTP proxy, we check connections to that
- * proxy and not to the actual remote server.
+ * Note that if we use a HTTP proxy in normal mode (no tunneling), we
+ * check connections to that proxy and not to the actual remote server.
*/
check = curr->ptr;
curr = curr->next;
@@ -3173,8 +3270,8 @@ ConnectionExists(struct SessionHandle *data,
if(!check->bits.multiplex) {
/* If not multiplexing, make sure the pipe has only GET requests */
- struct SessionHandle* sh = gethandleathead(check->send_pipe);
- struct SessionHandle* rh = gethandleathead(check->recv_pipe);
+ struct Curl_easy* sh = gethandleathead(check->send_pipe);
+ struct Curl_easy* rh = gethandleathead(check->recv_pipe);
if(sh) {
if(!IsPipeliningPossible(sh, check))
continue;
@@ -3205,6 +3302,8 @@ ConnectionExists(struct SessionHandle *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. */
infof(data, "Connection #%ld isn't open enough, can't reuse\n",
@@ -3223,7 +3322,8 @@ ConnectionExists(struct SessionHandle *data,
if((needle->handler->flags&PROTOPT_SSL) !=
(check->handler->flags&PROTOPT_SSL))
/* don't do mixed SSL and non-SSL connections */
- if(!(needle->handler->protocol & check->handler->protocol))
+ if(get_protocol_family(check->handler->protocol) !=
+ needle->handler->protocol || !check->tls_upgraded)
/* except protocols that have been upgraded via TLS */
continue;
@@ -3237,6 +3337,25 @@ ConnectionExists(struct SessionHandle *data,
/* don't do mixed proxy and non-proxy connections */
continue;
+ if(needle->bits.proxy &&
+ (needle->proxytype != check->proxytype ||
+ needle->bits.httpproxy != check->bits.httpproxy ||
+ needle->bits.tunnel_proxy != check->bits.tunnel_proxy ||
+ !Curl_raw_equal(needle->proxy.name, check->proxy.name) ||
+ needle->port != check->port))
+ /* don't mix connections that use different proxies */
+ continue;
+
+ 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 */
+ continue;
+
+ if(needle->bits.conn_to_port != check->bits.conn_to_port)
+ /* don't mix connections that use the "connect to port" feature and
+ * connections that don't use this feature */
+ continue;
+
if(!canPipeline && check->inuse)
/* this request can't be pipelined but the checked connection is
already in use so we skip it */
@@ -3262,37 +3381,33 @@ ConnectionExists(struct SessionHandle *data,
continue;
}
- if((!(needle->handler->flags & PROTOPT_CREDSPERREQUEST))
-#ifdef USE_NTLM
- || (wantNTLMhttp || check->ntlm.state != NTLMSTATE_NONE)
-#endif
- ) {
- /* This protocol requires credentials per connection or is HTTP+NTLM,
+ if(!(needle->handler->flags & PROTOPT_CREDSPERREQUEST)) {
+ /* This protocol requires credentials per connection,
so verify that we're using the same name and password as well */
if(!strequal(needle->user, check->user) ||
!strequal(needle->passwd, check->passwd)) {
/* one of them was different */
continue;
}
-#if defined(USE_NTLM)
- credentialsMatch = TRUE;
-#endif
}
- if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL ||
- (needle->bits.httpproxy && check->bits.httpproxy &&
- needle->bits.tunnel_proxy && check->bits.tunnel_proxy &&
- Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
- (needle->port == check->port))) {
+ if(!needle->bits.httpproxy || (needle->handler->flags&PROTOPT_SSL) ||
+ (needle->bits.httpproxy && needle->bits.tunnel_proxy)) {
/* The requested connection does not use a HTTP proxy or it uses SSL or
- it is a non-SSL protocol tunneled over the same http proxy name and
- port number or it is a non-SSL protocol which is allowed to be
- upgraded via TLS */
-
+ it is a non-SSL protocol tunneled over the same HTTP proxy name and
+ port number */
if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) ||
- needle->handler->protocol & check->handler->protocol) &&
+ (get_protocol_family(check->handler->protocol) ==
+ needle->handler->protocol && check->tls_upgraded)) &&
+ (!needle->bits.conn_to_host || Curl_raw_equal(
+ needle->conn_to_host.name, check->conn_to_host.name)) &&
+ (!needle->bits.conn_to_port ||
+ needle->conn_to_port == check->conn_to_port) &&
Curl_raw_equal(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
+ previous connection was TLS upgraded, and the hostname and host
+ port match */
if(needle->handler->flags & PROTOPT_SSL) {
/* This is a SSL connection so verify that we're using the same
SSL options as well */
@@ -3305,6 +3420,7 @@ ConnectionExists(struct SessionHandle *data,
continue;
}
else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) {
+ foundPendingCandidate = TRUE;
DEBUGF(infof(data,
"Connection #%ld has not started SSL connect, "
"can't reuse\n",
@@ -3315,16 +3431,10 @@ ConnectionExists(struct SessionHandle *data,
match = TRUE;
}
}
- else { /* The requested needle connection is using a proxy,
- is the checked one using the same host, port and type? */
- if(check->bits.proxy &&
- (needle->proxytype == check->proxytype) &&
- (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) &&
- Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
- needle->port == check->port) {
- /* This is the same proxy connection, use it! */
- match = TRUE;
- }
+ else {
+ /* The requested connection is using the same HTTP proxy in normal
+ mode (no tunneling) */
+ match = TRUE;
}
if(match) {
@@ -3335,20 +3445,47 @@ ConnectionExists(struct SessionHandle *data,
possible. (Especially we must not reuse the same connection if
partway through a handshake!) */
if(wantNTLMhttp) {
- if(credentialsMatch && check->ntlm.state != NTLMSTATE_NONE) {
- chosen = check;
+ if(!strequal(needle->user, check->user) ||
+ !strequal(needle->passwd, check->passwd))
+ continue;
+ }
+ else if(check->ntlm.state != NTLMSTATE_NONE) {
+ /* Connection is using NTLM auth but we don't want NTLM */
+ continue;
+ }
+
+ /* Same for Proxy NTLM authentication */
+ if(wantProxyNTLMhttp) {
+ /* Both check->proxyuser and check->proxypasswd can be NULL */
+ if(!check->proxyuser || !check->proxypasswd)
+ continue;
+ if(!strequal(needle->proxyuser, check->proxyuser) ||
+ !strequal(needle->proxypasswd, check->proxypasswd))
+ continue;
+ }
+ else if(check->proxyntlm.state != NTLMSTATE_NONE) {
+ /* Proxy connection is using NTLM auth but we don't want NTLM */
+ continue;
+ }
+
+ if(wantNTLMhttp || wantProxyNTLMhttp) {
+ /* Credentials are already checked, we can use this connection */
+ chosen = check;
+
+ if((wantNTLMhttp &&
+ (check->ntlm.state != NTLMSTATE_NONE)) ||
+ (wantProxyNTLMhttp &&
+ (check->proxyntlm.state != NTLMSTATE_NONE))) {
/* We must use this connection, no other */
*force_reuse = TRUE;
break;
}
- else if(credentialsMatch)
- /* this is a backup choice */
- chosen = check;
+
+ /* Continue look up for a better connection */
continue;
}
#endif
-
if(canPipeline) {
/* We can pipeline if we want to. Let's continue looking for
the optimal connection to use, i.e the shortest pipe that is not
@@ -3413,39 +3550,13 @@ ConnectionExists(struct SessionHandle *data,
return TRUE; /* yes, we found one to use! */
}
- return FALSE; /* no matching connecting exists */
-}
-
-/* Mark the connection as 'idle', or close it if the cache is full.
- Returns TRUE if the connection is kept, or FALSE if it was closed. */
-static bool
-ConnectionDone(struct SessionHandle *data, struct connectdata *conn)
-{
- /* data->multi->maxconnects can be negative, deal with it. */
- size_t maxconnects =
- (data->multi->maxconnects < 0) ? data->multi->num_easy * 4:
- data->multi->maxconnects;
- struct connectdata *conn_candidate = NULL;
-
- /* Mark the current connection as 'unused' */
- conn->inuse = FALSE;
-
- if(maxconnects > 0 &&
- data->state.conn_cache->num_connections > maxconnects) {
- infof(data, "Connection cache is full, closing the oldest one.\n");
-
- conn_candidate = find_oldest_idle_connection(data);
-
- if(conn_candidate) {
- /* Set the connection's owner correctly */
- conn_candidate->data = data;
-
- /* the winner gets the honour of being disconnected */
- (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
- }
+ if(foundPendingCandidate && data->set.pipewait) {
+ infof(data,
+ "Found pending candidate for reuse and CURLOPT_PIPEWAIT is set\n");
+ *waitpipe = TRUE;
}
- return (conn_candidate == conn) ? FALSE : TRUE;
+ return FALSE; /* no matching connecting exists */
}
/* after a TCP connection to the proxy has been verified, this function does
@@ -3467,16 +3578,27 @@ CURLcode Curl_connected_proxy(struct connectdata *conn,
case CURLPROXY_SOCKS5:
case CURLPROXY_SOCKS5_HOSTNAME:
return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd,
- conn->host.name, conn->remote_port,
+ conn->bits.conn_to_host ? conn->conn_to_host.name :
+ conn->host.name,
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port,
FIRSTSOCKET, conn);
case CURLPROXY_SOCKS4:
- return Curl_SOCKS4(conn->proxyuser, conn->host.name,
- conn->remote_port, FIRSTSOCKET, conn, FALSE);
+ return Curl_SOCKS4(conn->proxyuser,
+ conn->bits.conn_to_host ? conn->conn_to_host.name :
+ conn->host.name,
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port,
+ FIRSTSOCKET, conn, FALSE);
case CURLPROXY_SOCKS4A:
- return Curl_SOCKS4(conn->proxyuser, conn->host.name,
- conn->remote_port, FIRSTSOCKET, conn, TRUE);
+ return Curl_SOCKS4(conn->proxyuser,
+ conn->bits.conn_to_host ? conn->conn_to_host.name :
+ conn->host.name,
+ conn->bits.conn_to_port ? conn->conn_to_port :
+ conn->remote_port,
+ FIRSTSOCKET, conn, TRUE);
#endif /* CURL_DISABLE_PROXY */
case CURLPROXY_HTTP:
@@ -3634,7 +3756,7 @@ static bool is_ASCII_name(const char *hostname)
/*
* Check if characters in hostname is allowed in Top Level Domain.
*/
-static bool tld_check_name(struct SessionHandle *data,
+static bool tld_check_name(struct Curl_easy *data,
const char *ace_hostname)
{
size_t err_pos;
@@ -3651,17 +3773,16 @@ static bool tld_check_name(struct SessionHandle *data,
if(rc != IDNA_SUCCESS)
return FALSE;
+ /* Warning: err_pos receives "the decoded character offset rather than the
+ byte position in the string." And as of libidn 1.32 that character offset
+ is for UTF-8, even if the passed in string is another locale. */
rc = tld_check_lz(uc_name, &err_pos, NULL);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
#ifdef HAVE_TLD_STRERROR
if(rc != TLD_SUCCESS)
tld_errmsg = tld_strerror((Tld_rc)rc);
#endif
- if(rc == TLD_INVALID)
- infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
- tld_errmsg, err_pos, uc_name[err_pos],
- uc_name[err_pos] & 255);
- else if(rc != TLD_SUCCESS)
+ if(rc != TLD_SUCCESS)
infof(data, "WARNING: TLD check for %s failed; %s\n",
uc_name, tld_errmsg);
#endif /* CURL_DISABLE_VERBOSE_STRINGS */
@@ -3677,7 +3798,7 @@ static bool tld_check_name(struct SessionHandle *data,
/*
* Perform any necessary IDN conversion of hostname
*/
-static void fix_hostname(struct SessionHandle *data,
+static void fix_hostname(struct Curl_easy *data,
struct connectdata *conn, struct hostname *host)
{
size_t len;
@@ -3698,49 +3819,64 @@ static void fix_hostname(struct SessionHandle *data,
there's no use for it */
host->name[len-1]=0;
+ /* Check name for non-ASCII and convert hostname to ACE form if we can */
if(!is_ASCII_name(host->name)) {
#ifdef USE_LIBIDN
- /*************************************************************
- * Check name for non-ASCII and convert hostname to ACE form.
- *************************************************************/
- if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
- char *ace_hostname = NULL;
- int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
- infof (data, "Input domain encoded as `%s'\n",
- stringprep_locale_charset ());
- if(rc != IDNA_SUCCESS)
- infof(data, "Failed to convert %s to ACE; %s\n",
- host->name, Curl_idn_strerror(conn, rc));
- else {
- /* tld_check_name() displays a warning if the host name contains
- "illegal" characters for this TLD */
- (void)tld_check_name(data, ace_hostname);
-
- host->encalloc = ace_hostname;
- /* change the name pointer to point to the encoded hostname */
- host->name = host->encalloc;
+ if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
+ char *ace_hostname = NULL;
+
+ int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
+ infof(data, "Input domain encoded as `%s'\n",
+ stringprep_locale_charset());
+ if(rc == IDNA_SUCCESS) {
+ /* tld_check_name() displays a warning if the host name contains
+ "illegal" characters for this TLD */
+ (void)tld_check_name(data, ace_hostname);
+
+ host->encalloc = ace_hostname;
+ /* change the name pointer to point to the encoded hostname */
+ host->name = host->encalloc;
+ }
+ else
+ infof(data, "Failed to convert %s to ACE; %s\n", host->name,
+ Curl_idn_strerror(conn, rc));
}
- }
#elif defined(USE_WIN32_IDN)
- /*************************************************************
- * Check name for non-ASCII and convert hostname to ACE form.
- *************************************************************/
char *ace_hostname = NULL;
- int rc = curl_win32_idn_to_ascii(host->name, &ace_hostname);
- if(rc == 0)
- infof(data, "Failed to convert %s to ACE;\n",
- host->name);
- else {
+
+ if(curl_win32_idn_to_ascii(host->name, &ace_hostname)) {
host->encalloc = ace_hostname;
/* change the name pointer to point to the encoded hostname */
host->name = host->encalloc;
}
+ else
+ infof(data, "Failed to convert %s to ACE;\n", host->name);
#else
infof(data, "IDN support not present, can't parse Unicode domains\n");
#endif
}
}
+/*
+ * Frees data allocated by fix_hostname()
+ */
+static void free_fixed_hostname(struct hostname *host)
+{
+#if defined(USE_LIBIDN)
+ if(host->encalloc) {
+ idn_free(host->encalloc); /* must be freed with idn_free() since this was
+ allocated by libidn */
+ host->encalloc = NULL;
+ }
+#elif defined(USE_WIN32_IDN)
+ free(host->encalloc); /* must be freed withidn_free() since this was
+ allocated by curl_win32_idn_to_ascii */
+ host->encalloc = NULL;
+#else
+ (void)host;
+#endif
+}
+
static void llist_dtor(void *user, void *element)
{
(void)user;
@@ -3751,7 +3887,7 @@ static void llist_dtor(void *user, void *element)
/*
* Allocate and initialize a new connectdata object.
*/
-static struct connectdata *allocate_conn(struct SessionHandle *data)
+static struct connectdata *allocate_conn(struct Curl_easy *data)
{
struct connectdata *conn = calloc(1, sizeof(struct connectdata));
if(!conn)
@@ -3770,6 +3906,10 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
conn->connection_id = -1; /* no ID */
conn->port = -1; /* unknown at this point */
conn->remote_port = -1; /* unknown */
+#if defined(USE_RECV_BEFORE_SEND_WORKAROUND) && defined(DEBUGBUILD)
+ conn->postponed[0].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->postponed[1].bindsock = CURL_SOCKET_BAD; /* no file descriptor */
+#endif /* USE_RECV_BEFORE_SEND_WORKAROUND && DEBUGBUILD */
/* Default protocol-independent behavior doesn't support persistent
connections, so we set this to force-close. Protocols that support
@@ -3780,7 +3920,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
conn->created = Curl_tvnow();
conn->data = data; /* Setup the association between this connection
- and the SessionHandle */
+ and the Curl_easy */
conn->proxytype = data->set.proxytype; /* type */
@@ -3796,17 +3936,18 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
/* 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] &&
- *data->set.str[STRING_PROXY])?TRUE:FALSE;
+ *data->set.str[STRING_PROXY]) ? TRUE : FALSE;
conn->bits.httpproxy = (conn->bits.proxy &&
(conn->proxytype == CURLPROXY_HTTP ||
- conn->proxytype == CURLPROXY_HTTP_1_0))?TRUE:FALSE;
- conn->bits.proxy_user_passwd =
- (NULL != data->set.str[STRING_PROXYUSERNAME])?TRUE:FALSE;
+ conn->proxytype == CURLPROXY_HTTP_1_0)) ?
+ TRUE : FALSE;
+ conn->bits.proxy_user_passwd = (data->set.str[STRING_PROXYUSERNAME]) ?
+ TRUE : FALSE;
conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
#endif /* CURL_DISABLE_PROXY */
- conn->bits.user_passwd = (NULL != data->set.str[STRING_USERNAME])?TRUE:FALSE;
+ conn->bits.user_passwd = (data->set.str[STRING_USERNAME]) ? TRUE : FALSE;
conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
@@ -3851,7 +3992,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
conn->localport = data->set.localport;
/* the close socket stuff needs to be copied to the connection struct as
- it may live on without (this specific) SessionHandle */
+ it may live on without (this specific) Curl_easy */
conn->fclosesocket = data->set.fclosesocket;
conn->closesocket_client = data->set.closesocket_client;
@@ -3870,7 +4011,7 @@ static struct connectdata *allocate_conn(struct SessionHandle *data)
return NULL;
}
-static CURLcode findprotocol(struct SessionHandle *data,
+static CURLcode findprotocol(struct Curl_easy *data,
struct connectdata *conn,
const char *protostr)
{
@@ -3915,7 +4056,7 @@ static CURLcode findprotocol(struct SessionHandle *data,
/*
* Parse URL and fill in the relevant members of the connection struct.
*/
-static CURLcode parseurlandfillconn(struct SessionHandle *data,
+static CURLcode parseurlandfillconn(struct Curl_easy *data,
struct connectdata *conn,
bool *prot_missing,
char **userp, char **passwdp,
@@ -4000,12 +4141,17 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
}
else {
/* clear path */
+ char slashbuf[4];
path[0]=0;
- if(2 > sscanf(data->change.url,
- "%15[^\n:]://%[^\n/?]%[^\n]",
- protobuf,
- conn->host.name, path)) {
+ rc = sscanf(data->change.url,
+ "%15[^\n:]:%3[/]%[^\n/?]%[^\n]",
+ protobuf, slashbuf, conn->host.name, path);
+ if(2 == rc) {
+ failf(data, "Bad URL");
+ return CURLE_URL_MALFORMAT;
+ }
+ if(3 > rc) {
/*
* The URL was badly formatted, let's try the browser-style _without_
@@ -4028,33 +4174,51 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
}
/*
- * Since there was no protocol part specified, we guess what protocol it
- * is based on the first letters of the server name.
+ * Since there was no protocol part specified in the URL use the
+ * user-specified default protocol. If we weren't given a default make a
+ * guess by matching some protocols against the host's outermost
+ * sub-domain name. Finally if there was no match use HTTP.
*/
- /* Note: if you add a new protocol, please update the list in
- * lib/version.c too! */
-
- if(checkprefix("FTP.", conn->host.name))
- protop = "ftp";
- else if(checkprefix("DICT.", conn->host.name))
- protop = "DICT";
- else if(checkprefix("LDAP.", conn->host.name))
- protop = "LDAP";
- else if(checkprefix("IMAP.", conn->host.name))
- protop = "IMAP";
- else if(checkprefix("SMTP.", conn->host.name))
- protop = "smtp";
- else if(checkprefix("POP3.", conn->host.name))
- protop = "pop3";
- else {
- protop = "http";
+ protop = data->set.str[STRING_DEFAULT_PROTOCOL];
+ if(!protop) {
+ /* Note: if you add a new protocol, please update the list in
+ * lib/version.c too! */
+ if(checkprefix("FTP.", conn->host.name))
+ protop = "ftp";
+ else if(checkprefix("DICT.", conn->host.name))
+ protop = "DICT";
+ else if(checkprefix("LDAP.", conn->host.name))
+ protop = "LDAP";
+ else if(checkprefix("IMAP.", conn->host.name))
+ protop = "IMAP";
+ else if(checkprefix("SMTP.", conn->host.name))
+ protop = "smtp";
+ else if(checkprefix("POP3.", conn->host.name))
+ protop = "pop3";
+ else
+ protop = "http";
}
*prot_missing = TRUE; /* not given in URL */
}
- else
+ else {
+ size_t s = strlen(slashbuf);
protop = protobuf;
+ if(s != 2) {
+ infof(data, "Unwillingly accepted illegal URL using %d slash%s!\n",
+ s, s>1?"es":"");
+
+ if(data->change.url_alloc)
+ free(data->change.url);
+ /* repair the URL to use two slashes */
+ data->change.url = aprintf("%s://%s%s",
+ protobuf, conn->host.name, path);
+ if(!data->change.url)
+ return CURLE_OUT_OF_MEMORY;
+ data->change.url_alloc = TRUE;
+ }
+ }
}
/* We search for '?' in the host name (but only on the right side of a
@@ -4260,7 +4424,7 @@ static CURLcode parseurlandfillconn(struct SessionHandle *data,
* If we're doing a resumed transfer, we need to setup our stuff
* properly.
*/
-static CURLcode setup_range(struct SessionHandle *data)
+static CURLcode setup_range(struct Curl_easy *data)
{
struct UrlState *s = &data->state;
s->resume_from = data->set.set_resume_from;
@@ -4273,7 +4437,7 @@ static CURLcode setup_range(struct SessionHandle *data)
else
s->range = strdup(data->set.str[STRING_SET_RANGE]);
- s->rangestringalloc = (s->range)?TRUE:FALSE;
+ s->rangestringalloc = (s->range) ? TRUE : FALSE;
if(!s->range)
return CURLE_OUT_OF_MEMORY;
@@ -4292,7 +4456,7 @@ static CURLcode setup_range(struct SessionHandle *data)
* setup_connection_internals() -
*
* Setup connection internals specific to the requested protocol in the
- * SessionHandle. This is inited and setup before the connection is made but
+ * Curl_easy. This is inited and setup before the connection is made but
* is about the particular protocol that is to be used.
*
* This MUST get called after proxy magic has been figured out.
@@ -4301,7 +4465,7 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
{
const struct Curl_handler * p;
CURLcode result;
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
/* in some case in the multi state-machine, we go back to the CONNECT state
and then a second (or third or...) call to this function will be made
@@ -4332,20 +4496,15 @@ static CURLcode setup_connection_internals(struct connectdata *conn)
was very likely already set to the proxy port */
conn->port = p->defport;
- /* only if remote_port was not already parsed off the URL we use the
- default port number */
- if(conn->remote_port < 0)
- conn->remote_port = (unsigned short)conn->given->defport;
-
return CURLE_OK;
}
/*
* Curl_free_request_state() should free temp data that was allocated in the
- * SessionHandle for this single request.
+ * Curl_easy for this single request.
*/
-void Curl_free_request_state(struct SessionHandle *data)
+void Curl_free_request_state(struct Curl_easy *data)
{
Curl_safefree(data->req.protop);
Curl_safefree(data->req.newurl);
@@ -4519,7 +4678,7 @@ static char *detect_proxy(struct connectdata *conn)
* host name, so that we can re-use an existing connection
* that may exist registered to the same proxy host.
*/
-static CURLcode parse_proxy(struct SessionHandle *data,
+static CURLcode parse_proxy(struct Curl_easy *data,
struct connectdata *conn, char *proxy)
{
char *prox_portno;
@@ -4611,7 +4770,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
if(strncmp("%25", ptr, 3))
infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
ptr++;
- /* Allow unresered characters as defined in RFC 3986 */
+ /* Allow unreserved characters as defined in RFC 3986 */
while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
(*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
ptr++;
@@ -4631,10 +4790,24 @@ static CURLcode parse_proxy(struct SessionHandle *data,
/* Get port number off proxy.server.com:1080 */
prox_portno = strchr(portptr, ':');
if(prox_portno) {
+ char *endp = NULL;
+ long port = 0;
*prox_portno = 0x0; /* cut off number from host name */
prox_portno ++;
/* now set the local port number */
- conn->port = strtol(prox_portno, NULL, 10);
+ port = strtol(prox_portno, &endp, 10);
+ if((endp && *endp && (*endp != '/') && (*endp != ' ')) ||
+ (port < 0) || (port > 65535)) {
+ /* meant to detect for example invalid IPv6 numerical addresses without
+ brackets: "2a00:fac0:a000::7:13". Accept a trailing slash only
+ because we then allow "URL style" with the number followed by a
+ slash, used in curl test cases already. Space is also an acceptable
+ terminating symbol. */
+ infof(data, "No valid port number in proxy string (%s)\n",
+ prox_portno);
+ }
+ else
+ conn->port = port;
}
else {
if(proxyptr[0]=='/')
@@ -4647,7 +4820,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
a slash so we strip everything from the first slash */
atsign = strchr(proxyptr, '/');
if(atsign)
- *atsign = 0x0; /* cut off path part from host name */
+ *atsign = '\0'; /* cut off path part from host name */
if(data->set.proxyport)
/* None given in the proxy string, then get the default one if it is
@@ -4668,7 +4841,7 @@ static CURLcode parse_proxy(struct SessionHandle *data,
/*
* Extract the user and password from the authentication string
*/
-static CURLcode parse_proxy_auth(struct SessionHandle *data,
+static CURLcode parse_proxy_auth(struct Curl_easy *data,
struct connectdata *conn)
{
char proxyuser[MAX_CURL_USER_LENGTH]="";
@@ -4713,7 +4886,7 @@ static CURLcode parse_proxy_auth(struct SessionHandle *data,
* options - non-zero length if defined
* conn->host.name - remove user name and password
*/
-static CURLcode parse_url_login(struct SessionHandle *data,
+static CURLcode parse_url_login(struct Curl_easy *data,
struct connectdata *conn,
char **user, char **passwd, char **options)
{
@@ -4952,7 +5125,7 @@ static CURLcode parse_login_details(const char *login, const size_t len,
*
* The port number embedded in the URL is replaced, if necessary.
*************************************************************/
-static CURLcode parse_remote_port(struct SessionHandle *data,
+static CURLcode parse_remote_port(struct Curl_easy *data,
struct connectdata *conn)
{
char *portptr;
@@ -5051,6 +5224,12 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
use the default port. Firefox and Chrome both do that. */
*portptr = '\0';
}
+
+ /* only if remote_port was not already parsed off the URL we use the
+ default port number */
+ if(conn->remote_port < 0)
+ conn->remote_port = (unsigned short)conn->given->defport;
+
return CURLE_OK;
}
@@ -5058,7 +5237,7 @@ static CURLcode parse_remote_port(struct SessionHandle *data,
* Override the login details from the URL with that in the CURLOPT_USERPWD
* option or a .netrc file, if applicable.
*/
-static CURLcode override_login(struct SessionHandle *data,
+static CURLcode override_login(struct Curl_easy *data,
struct connectdata *conn,
char **userp, char **passwdp, char **optionsp)
{
@@ -5093,7 +5272,7 @@ static CURLcode override_login(struct SessionHandle *data,
DOT_CHAR "netrc file; using defaults\n",
conn->host.name);
}
- else if(ret < 0 ) {
+ else if(ret < 0) {
return CURLE_OUT_OF_MEMORY;
}
else {
@@ -5156,10 +5335,218 @@ static CURLcode set_login(struct connectdata *conn,
return result;
}
+/*
+ * Parses a "host:port" string to connect to.
+ * The hostname and the port may be empty; in this case, NULL is returned for
+ * the hostname and -1 for the port.
+ */
+static CURLcode parse_connect_to_host_port(struct Curl_easy *data,
+ const char *host,
+ char **hostname_result,
+ int *port_result)
+{
+ char *host_dup;
+ char *hostptr;
+ char *host_portno;
+ char *portptr;
+ int port = -1;
+
+ *hostname_result = NULL;
+ *port_result = -1;
+
+ if(!host || !*host)
+ return CURLE_OK;
+
+ host_dup = strdup(host);
+ if(!host_dup)
+ return CURLE_OUT_OF_MEMORY;
+
+ hostptr = host_dup;
+
+ /* start scanning for port number at this point */
+ portptr = hostptr;
+
+ /* detect and extract RFC6874-style IPv6-addresses */
+ if(*hostptr == '[') {
+ char *ptr = ++hostptr; /* advance beyond the initial bracket */
+ while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '.')))
+ ptr++;
+ if(*ptr == '%') {
+ /* There might be a zone identifier */
+ if(strncmp("%25", ptr, 3))
+ infof(data, "Please URL encode %% as %%25, see RFC 6874.\n");
+ ptr++;
+ /* Allow unreserved characters as defined in RFC 3986 */
+ while(*ptr && (ISALPHA(*ptr) || ISXDIGIT(*ptr) || (*ptr == '-') ||
+ (*ptr == '.') || (*ptr == '_') || (*ptr == '~')))
+ ptr++;
+ }
+ if(*ptr == ']')
+ /* yeps, it ended nicely with a bracket as well */
+ *ptr++ = '\0';
+ else
+ infof(data, "Invalid IPv6 address format\n");
+ portptr = ptr;
+ /* Note that if this didn't end with a bracket, we still advanced the
+ * hostptr first, but I can't see anything wrong with that as no host
+ * name nor a numeric can legally start with a bracket.
+ */
+ }
+
+ /* Get port number off server.com:1080 */
+ host_portno = strchr(portptr, ':');
+ if(host_portno) {
+ char *endp = NULL;
+ *host_portno = '\0'; /* cut off number from host name */
+ host_portno++;
+ if(*host_portno) {
+ long portparse = strtol(host_portno, &endp, 10);
+ if((endp && *endp) || (portparse < 0) || (portparse > 65535)) {
+ infof(data, "No valid port number in connect to host string (%s)\n",
+ host_portno);
+ hostptr = NULL;
+ port = -1;
+ }
+ else
+ port = (int)portparse; /* we know it will fit */
+ }
+ }
+
+ /* now, clone the cleaned host name */
+ if(hostptr) {
+ *hostname_result = strdup(hostptr);
+ if(!*hostname_result) {
+ free(host_dup);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ *port_result = port;
+
+ free(host_dup);
+ return CURLE_OK;
+}
+
+/*
+ * Parses one "connect to" string in the form:
+ * "HOST:PORT:CONNECT-TO-HOST:CONNECT-TO-PORT".
+ */
+static CURLcode parse_connect_to_string(struct Curl_easy *data,
+ struct connectdata *conn,
+ const char *conn_to_host,
+ char **host_result,
+ int *port_result)
+{
+ CURLcode result = CURLE_OK;
+ const char *ptr = conn_to_host;
+ int host_match = FALSE;
+ int port_match = FALSE;
+
+ if(*ptr == ':') {
+ /* an empty hostname always matches */
+ host_match = TRUE;
+ ptr++;
+ }
+ else {
+ /* check whether the URL's hostname matches */
+ size_t hostname_to_match_len;
+ char *hostname_to_match = aprintf("%s%s%s",
+ conn->bits.ipv6_ip ? "[" : "",
+ conn->host.name,
+ conn->bits.ipv6_ip ? "]" : "");
+ if(!hostname_to_match)
+ return CURLE_OUT_OF_MEMORY;
+ hostname_to_match_len = strlen(hostname_to_match);
+ host_match = curl_strnequal(ptr, hostname_to_match, hostname_to_match_len);
+ free(hostname_to_match);
+ ptr += hostname_to_match_len;
+
+ host_match = host_match && *ptr == ':';
+ ptr++;
+ }
+
+ if(host_match) {
+ if(*ptr == ':') {
+ /* an empty port always matches */
+ port_match = TRUE;
+ ptr++;
+ }
+ else {
+ /* check whether the URL's port matches */
+ char *ptr_next = strchr(ptr, ':');
+ if(ptr_next) {
+ char *endp = NULL;
+ long port_to_match = strtol(ptr, &endp, 10);
+ if((endp == ptr_next) && (port_to_match == conn->remote_port)) {
+ port_match = TRUE;
+ ptr = ptr_next + 1;
+ }
+ }
+ }
+ }
+
+ if(host_match && port_match) {
+ /* parse the hostname and port to connect to */
+ result = parse_connect_to_host_port(data, ptr, host_result, port_result);
+ }
+
+ return result;
+}
+
+/*
+ * Processes all strings in the "connect to" slist, and uses the "connect
+ * to host" and "connect to port" of the first string that matches.
+ */
+static CURLcode parse_connect_to_slist(struct Curl_easy *data,
+ struct connectdata *conn,
+ struct curl_slist *conn_to_host)
+{
+ CURLcode result = CURLE_OK;
+ char *host = NULL;
+ int port = 0;
+
+ while(conn_to_host && !host) {
+ result = parse_connect_to_string(data, conn, conn_to_host->data,
+ &host, &port);
+ if(result)
+ return result;
+
+ if(host && *host) {
+ bool ipv6host;
+ conn->conn_to_host.rawalloc = host;
+ conn->conn_to_host.name = host;
+ conn->bits.conn_to_host = TRUE;
+
+ ipv6host = strchr(host, ':') != NULL;
+ infof(data, "Connecting to hostname: %s%s%s\n",
+ ipv6host ? "[" : "", host, ipv6host ? "]" : "");
+ }
+ else {
+ /* no "connect to host" */
+ conn->bits.conn_to_host = FALSE;
+ free(host);
+ }
+
+ if(port >= 0) {
+ conn->conn_to_port = port;
+ conn->bits.conn_to_port = TRUE;
+ infof(data, "Connecting to port: %d\n", port);
+ }
+ else {
+ /* no "connect to port" */
+ conn->bits.conn_to_port = FALSE;
+ }
+
+ conn_to_host = conn_to_host->next;
+ }
+
+ return result;
+}
+
/*************************************************************
* Resolve the address of the server or proxy
*************************************************************/
-static CURLcode resolve_server(struct SessionHandle *data,
+static CURLcode resolve_server(struct Curl_easy *data,
struct connectdata *conn,
bool *async)
{
@@ -5180,9 +5567,6 @@ static CURLcode resolve_server(struct SessionHandle *data,
int rc;
struct Curl_dns_entry *hostaddr;
- /* set a pointer to the hostname we display */
- fix_hostname(data, conn, &conn->host);
-
#ifdef USE_UNIX_SOCKETS
if(data->set.str[STRING_UNIX_SOCKET_PATH]) {
/* Unix domain sockets are local. The host gets ignored, just use the
@@ -5210,12 +5594,21 @@ static CURLcode resolve_server(struct SessionHandle *data,
else
#endif
if(!conn->proxy.name || !*conn->proxy.name) {
+ struct hostname *connhost;
+ if(conn->bits.conn_to_host)
+ connhost = &conn->conn_to_host;
+ else
+ connhost = &conn->host;
+
/* If not connecting via a proxy, extract the port from the URL, if it is
* there, thus overriding any defaults that might have been set above. */
- conn->port = conn->remote_port; /* it is the same port */
+ if(conn->bits.conn_to_port)
+ conn->port = conn->conn_to_port;
+ else
+ conn->port = conn->remote_port; /* it is the same port */
/* Resolve target host right on */
- rc = Curl_resolv_timeout(conn, conn->host.name, (int)conn->port,
+ rc = Curl_resolv_timeout(conn, connhost->name, (int)conn->port,
&hostaddr, timeout_ms);
if(rc == CURLRESOLV_PENDING)
*async = TRUE;
@@ -5224,7 +5617,7 @@ static CURLcode resolve_server(struct SessionHandle *data,
result = CURLE_OPERATION_TIMEDOUT;
else if(!hostaddr) {
- failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
+ failf(data, "Couldn't resolve host '%s'", connhost->dispname);
result = CURLE_COULDNT_RESOLVE_HOST;
/* don't return yet, we need to clean up the timeout first */
}
@@ -5232,9 +5625,6 @@ static CURLcode resolve_server(struct SessionHandle *data,
else {
/* This is a proxy that hasn't been resolved yet. */
- /* IDN-fix the proxy name */
- fix_hostname(data, conn, &conn->proxy);
-
/* resolve proxy */
rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port,
&hostaddr, timeout_ms);
@@ -5266,6 +5656,7 @@ static CURLcode resolve_server(struct SessionHandle *data,
static void reuse_conn(struct connectdata *old_conn,
struct connectdata *conn)
{
+ free_fixed_hostname(&old_conn->proxy);
free(old_conn->proxy.rawalloc);
/* free the SSL config struct from this connection struct as this was
@@ -5300,12 +5691,22 @@ static void reuse_conn(struct connectdata *old_conn,
/* host can change, when doing keepalive with a proxy or if the case is
different this time etc */
+ free_fixed_hostname(&conn->host);
+ free_fixed_hostname(&conn->conn_to_host);
Curl_safefree(conn->host.rawalloc);
+ Curl_safefree(conn->conn_to_host.rawalloc);
conn->host=old_conn->host;
+ conn->bits.conn_to_host = old_conn->bits.conn_to_host;
+ conn->conn_to_host = old_conn->conn_to_host;
+ conn->bits.conn_to_port = old_conn->bits.conn_to_port;
+ conn->conn_to_port = old_conn->conn_to_port;
/* persist connection info in session handle */
Curl_persistconninfo(conn);
+ conn_reset_all_postponed_data(old_conn); /* free buffers */
+ conn_reset_all_postponed_data(conn); /* reset unprocessed data */
+
/* re-use init */
conn->bits.reuse = TRUE; /* yes, we're re-using here */
@@ -5340,7 +5741,7 @@ static void reuse_conn(struct connectdata *old_conn,
* *NOTE* this function assigns the conn->data pointer!
*/
-static CURLcode create_conn(struct SessionHandle *data,
+static CURLcode create_conn(struct Curl_easy *data,
struct connectdata **in_connect,
bool *async)
{
@@ -5448,6 +5849,7 @@ static CURLcode create_conn(struct SessionHandle *data,
we're gonna follow a Location: later or... then we need the protocol
part added so that we have a valid URL. */
char *reurl;
+ char *ch_lower;
reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url);
@@ -5456,6 +5858,10 @@ static CURLcode create_conn(struct SessionHandle *data,
goto out;
}
+ /* Change protocol prefix to lower-case */
+ for(ch_lower = reurl; *ch_lower != ':'; ch_lower++)
+ *ch_lower = (char)TOLOWER(*ch_lower);
+
if(data->change.url_alloc) {
Curl_safefree(data->change.url);
data->change.url_alloc = FALSE;
@@ -5484,8 +5890,8 @@ static CURLcode create_conn(struct SessionHandle *data,
}
if(data->set.str[STRING_BEARER]) {
- conn->xoauth2_bearer = strdup(data->set.str[STRING_BEARER]);
- if(!conn->xoauth2_bearer) {
+ conn->oauth_bearer = strdup(data->set.str[STRING_BEARER]);
+ if(!conn->oauth_bearer) {
result = CURLE_OUT_OF_MEMORY;
goto out;
}
@@ -5605,6 +6011,48 @@ static CURLcode create_conn(struct SessionHandle *data,
goto out;
/*************************************************************
+ * Process the "connect to" linked list of hostname/port mappings.
+ * Do this after the remote port number has been fixed in the URL.
+ *************************************************************/
+ result = parse_connect_to_slist(data, conn, data->set.connect_to);
+ if(result)
+ goto out;
+
+ /*************************************************************
+ * IDN-fix the hostnames
+ *************************************************************/
+ fix_hostname(data, conn, &conn->host);
+ if(conn->bits.conn_to_host)
+ fix_hostname(data, conn, &conn->conn_to_host);
+ if(conn->proxy.name && *conn->proxy.name)
+ fix_hostname(data, conn, &conn->proxy);
+
+ /*************************************************************
+ * Check whether the host and the "connect to host" are equal.
+ * Do this after the hostnames have been IDN-fixed .
+ *************************************************************/
+ if(conn->bits.conn_to_host &&
+ Curl_raw_equal(conn->conn_to_host.name, conn->host.name)) {
+ conn->bits.conn_to_host = FALSE;
+ }
+
+ /*************************************************************
+ * Check whether the port and the "connect to port" are equal.
+ * Do this after the remote port number has been fixed in the URL.
+ *************************************************************/
+ if(conn->bits.conn_to_port && conn->conn_to_port == conn->remote_port) {
+ conn->bits.conn_to_port = FALSE;
+ }
+
+ /*************************************************************
+ * If the "connect to" feature is used with an HTTP proxy,
+ * we set the tunnel_proxy bit.
+ *************************************************************/
+ if((conn->bits.conn_to_host || conn->bits.conn_to_port) &&
+ conn->bits.httpproxy)
+ conn->bits.tunnel_proxy = TRUE;
+
+ /*************************************************************
* Setup internals depending on protocol. Needs to be done after
* we figured out what/if proxy to use.
*************************************************************/
@@ -5617,6 +6065,8 @@ static CURLcode create_conn(struct SessionHandle *data,
conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
conn->send[SECONDARYSOCKET] = Curl_send_plain;
+ conn->bits.tcp_fastopen = data->set.tcp_fastopen;
+
/***********************************************************************
* file: is a special case in that it doesn't need a network connection
***********************************************************************/
@@ -5663,7 +6113,7 @@ static CURLcode create_conn(struct SessionHandle *data,
strings in the session handle strings array!
Keep in mind that the pointers in the master copy are pointing to strings
- that will be freed as part of the SessionHandle struct, but all cloned
+ that will be freed as part of the Curl_easy struct, but all cloned
copies will be separately allocated.
*/
data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
@@ -5673,6 +6123,7 @@ static CURLcode create_conn(struct SessionHandle *data,
data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
+ data->set.ssl.clientcert = data->set.str[STRING_CERT];
#ifdef USE_TLS_SRP
data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME];
data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD];
@@ -5732,9 +6183,6 @@ static CURLcode create_conn(struct SessionHandle *data,
conn = conn_temp;
*in_connect = conn;
- /* set a pointer to the hostname we display */
- fix_hostname(data, conn, &conn->host);
-
infof(data, "Re-using existing connection! (#%ld) with %s %s\n",
conn->connection_id,
conn->bits.proxy?"proxy":"host",
@@ -5746,6 +6194,15 @@ static CURLcode create_conn(struct SessionHandle *data,
connections we are allowed to open. */
struct connectbundle *bundle = NULL;
+ if(conn->handler->flags & PROTOPT_ALPN_NPN) {
+ /* The protocol wants it, so set the bits if enabled in the easy handle
+ (default) */
+ if(data->set.ssl_enable_alpn)
+ conn->bits.tls_enable_alpn = TRUE;
+ if(data->set.ssl_enable_npn)
+ conn->bits.tls_enable_npn = TRUE;
+ }
+
if(waitpipe)
/* There is a connection that *might* become usable for pipelining
"soon", and we wait for that */
@@ -5778,7 +6235,7 @@ static CURLcode create_conn(struct SessionHandle *data,
struct connectdata *conn_candidate;
/* The cache is full. Let's see if we can kill a connection. */
- conn_candidate = find_oldest_idle_connection(data);
+ conn_candidate = Curl_oldest_idle_connection(data);
if(conn_candidate) {
/* Set the connection's owner correctly, then kill it */
@@ -5816,12 +6273,14 @@ static CURLcode create_conn(struct SessionHandle *data,
data->state.authhost.done) {
infof(data, "NTLM picked AND auth done set, clear picked!\n");
data->state.authhost.picked = CURLAUTH_NONE;
+ data->state.authhost.done = FALSE;
}
if((data->state.authproxy.picked & (CURLAUTH_NTLM | CURLAUTH_NTLM_WB)) &&
data->state.authproxy.done) {
infof(data, "NTLM-proxy picked AND auth done set, clear picked!\n");
data->state.authproxy.picked = CURLAUTH_NONE;
+ data->state.authproxy.done = FALSE;
}
#endif
}
@@ -5874,7 +6333,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
bool *protocol_done)
{
CURLcode result = CURLE_OK;
- struct SessionHandle *data = conn->data;
+ struct Curl_easy *data = conn->data;
Curl_pgrsTime(data, TIMER_NAMELOOKUP);
@@ -5948,7 +6407,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn,
return result;
}
-CURLcode Curl_connect(struct SessionHandle *data,
+CURLcode Curl_connect(struct Curl_easy *data,
struct connectdata **in_connect,
bool *asyncp,
bool *protocol_done)
@@ -5988,140 +6447,17 @@ CURLcode Curl_connect(struct SessionHandle *data,
return result;
}
-CURLcode Curl_done(struct connectdata **connp,
- CURLcode status, /* an error if this is called after an
- error was detected */
- bool premature)
-{
- CURLcode result;
- struct connectdata *conn;
- struct SessionHandle *data;
-
- DEBUGASSERT(*connp);
-
- conn = *connp;
- data = conn->data;
-
- DEBUGF(infof(data, "Curl_done\n"));
-
- if(data->state.done)
- /* Stop if Curl_done() has already been called */
- return CURLE_OK;
-
- Curl_getoff_all_pipelines(data, conn);
-
- /* Cleanup possible redirect junk */
- free(data->req.newurl);
- data->req.newurl = NULL;
- free(data->req.location);
- data->req.location = NULL;
-
- switch(status) {
- case CURLE_ABORTED_BY_CALLBACK:
- case CURLE_READ_ERROR:
- case CURLE_WRITE_ERROR:
- /* When we're aborted due to a callback return code it basically have to
- be counted as premature as there is trouble ahead if we don't. We have
- many callbacks and protocols work differently, we could potentially do
- this more fine-grained in the future. */
- premature = TRUE;
- default:
- break;
- }
-
- /* this calls the protocol-specific function pointer previously set */
- if(conn->handler->done)
- result = conn->handler->done(conn, status, premature);
- else
- result = status;
-
- if(!result && Curl_pgrsDone(conn))
- result = CURLE_ABORTED_BY_CALLBACK;
-
- if((conn->send_pipe->size + conn->recv_pipe->size != 0 &&
- !data->set.reuse_forbid &&
- !conn->bits.close)) {
- /* Stop if pipeline is not empty and we do not have to close
- connection. */
- DEBUGF(infof(data, "Connection still in use, no more Curl_done now!\n"));
- return CURLE_OK;
- }
-
- 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 */
- conn->dns_entry = NULL;
- }
-
- /* if the transfer was completed in a paused state there can be buffered
- data left to write and then kill */
- free(data->state.tempwrite);
- data->state.tempwrite = NULL;
-
- /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
- forced us to close this connection. This is ignored for requests taking
- place in a NTLM authentication handshake
-
- if conn->bits.close is TRUE, it means that the connection should be
- closed in spite of all our efforts to be nice, due to protocol
- restrictions in our or the server's end
-
- if premature is TRUE, it means this connection was said to be DONE before
- the entire request operation is complete and thus we can't know in what
- state it is for re-using, so we're forced to close it. In a perfect world
- we can add code that keep track of if we really must close it here or not,
- but currently we have no such detail knowledge.
- */
-
- if((data->set.reuse_forbid
-#if defined(USE_NTLM)
- && !(conn->ntlm.state == NTLMSTATE_TYPE2 ||
- conn->proxyntlm.state == NTLMSTATE_TYPE2)
-#endif
- ) || conn->bits.close || premature) {
- CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
-
- /* If we had an error already, make sure we return that one. But
- if we got a new error, return that. */
- if(!result && res2)
- result = res2;
- }
- else {
- /* the connection is no longer in use */
- if(ConnectionDone(data, conn)) {
- /* remember the most recently used connection */
- data->state.lastconnect = conn;
-
- infof(data, "Connection #%ld to host %s left intact\n",
- conn->connection_id,
- conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
- }
- else
- 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_free_request_state(data);
-
- return result;
-}
-
/*
* Curl_init_do() inits the readwrite session. This is inited each time (in
* the DO function before the protocol-specific DO functions are invoked) for
- * a transfer, sometimes multiple times on the same SessionHandle. Make sure
+ * a transfer, sometimes multiple times on the same Curl_easy. Make sure
* nothing in here depends on stuff that are setup dynamically for the
* transfer.
*
* Allow this function to get called with 'conn' set to NULL.
*/
-CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn)
+CURLcode Curl_init_do(struct Curl_easy *data, struct connectdata *conn)
{
struct SingleRequest *k = &data->req;
@@ -6129,7 +6465,7 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn)
conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to
* use */
- data->state.done = FALSE; /* Curl_done() is not called yet */
+ data->state.done = FALSE; /* *_done() is not called yet */
data->state.expect100header = FALSE;
if(data->set.opt_no_body)
@@ -6163,80 +6499,111 @@ CURLcode Curl_init_do(struct SessionHandle *data, struct connectdata *conn)
}
/*
- * do_complete is called when the DO actions are complete.
- *
- * We init chunking and trailer bits to their default values here immediately
- * before receiving any header data for the current request in the pipeline.
- */
-static void do_complete(struct connectdata *conn)
-{
- conn->data->req.chunk=FALSE;
- conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
- conn->sockfd:conn->writesockfd)+1;
- Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
-}
+* get_protocol_family()
+*
+* This is used to return the protocol family for a given protocol.
+*
+* Parameters:
+*
+* protocol [in] - A single bit protocol identifier such as HTTP or HTTPS.
+*
+* Returns the family as a single bit protocol identifier.
+*/
-CURLcode Curl_do(struct connectdata **connp, bool *done)
+unsigned int get_protocol_family(unsigned int protocol)
{
- CURLcode result=CURLE_OK;
- struct connectdata *conn = *connp;
- struct SessionHandle *data = conn->data;
+ unsigned int family;
- if(conn->handler->do_it) {
- /* generic protocol-specific function pointer set in curl_connect() */
- result = conn->handler->do_it(conn, done);
+ switch(protocol) {
+ case CURLPROTO_HTTP:
+ case CURLPROTO_HTTPS:
+ family = CURLPROTO_HTTP;
+ break;
- /* This was formerly done in transfer.c, but we better do it here */
- if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
- /*
- * If the connection is using an easy handle, call reconnect
- * to re-establish the connection. Otherwise, let the multi logic
- * figure out how to re-establish the connection.
- */
- if(!data->multi) {
- result = Curl_reconnect_request(connp);
-
- if(!result) {
- /* ... finally back to actually retry the DO phase */
- conn = *connp; /* re-assign conn since Curl_reconnect_request
- creates a new connection */
- result = conn->handler->do_it(conn, done);
- }
- }
- else
- return result;
- }
+ case CURLPROTO_FTP:
+ case CURLPROTO_FTPS:
+ family = CURLPROTO_FTP;
+ break;
- if(!result && *done)
- /* do_complete must be called after the protocol-specific DO function */
- do_complete(conn);
- }
- return result;
-}
+ case CURLPROTO_SCP:
+ family = CURLPROTO_SCP;
+ break;
-/*
- * Curl_do_more() is called during the DO_MORE multi state. It is basically a
- * second stage DO state which (wrongly) was introduced to support FTP's
- * second connection.
- *
- * TODO: A future libcurl should be able to work away this state.
- *
- * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
- * DOING state there's more work to do!
- */
+ case CURLPROTO_SFTP:
+ family = CURLPROTO_SFTP;
+ break;
-CURLcode Curl_do_more(struct connectdata *conn, int *complete)
-{
- CURLcode result=CURLE_OK;
+ case CURLPROTO_TELNET:
+ family = CURLPROTO_TELNET;
+ break;
- *complete = 0;
+ case CURLPROTO_LDAP:
+ case CURLPROTO_LDAPS:
+ family = CURLPROTO_LDAP;
+ break;
- if(conn->handler->do_more)
- result = conn->handler->do_more(conn, complete);
+ case CURLPROTO_DICT:
+ family = CURLPROTO_DICT;
+ break;
- if(!result && (*complete == 1))
- /* do_complete must be called after the protocol-specific DO function */
- do_complete(conn);
+ case CURLPROTO_FILE:
+ family = CURLPROTO_FILE;
+ break;
- return result;
+ case CURLPROTO_TFTP:
+ family = CURLPROTO_TFTP;
+ break;
+
+ case CURLPROTO_IMAP:
+ case CURLPROTO_IMAPS:
+ family = CURLPROTO_IMAP;
+ break;
+
+ case CURLPROTO_POP3:
+ case CURLPROTO_POP3S:
+ family = CURLPROTO_POP3;
+ break;
+
+ case CURLPROTO_SMTP:
+ case CURLPROTO_SMTPS:
+ family = CURLPROTO_SMTP;
+ break;
+
+ case CURLPROTO_RTSP:
+ family = CURLPROTO_RTSP;
+ break;
+
+ case CURLPROTO_RTMP:
+ case CURLPROTO_RTMPS:
+ family = CURLPROTO_RTMP;
+ break;
+
+ case CURLPROTO_RTMPT:
+ case CURLPROTO_RTMPTS:
+ family = CURLPROTO_RTMPT;
+ break;
+
+ case CURLPROTO_RTMPE:
+ family = CURLPROTO_RTMPE;
+ break;
+
+ case CURLPROTO_RTMPTE:
+ family = CURLPROTO_RTMPTE;
+ break;
+
+ case CURLPROTO_GOPHER:
+ family = CURLPROTO_GOPHER;
+ break;
+
+ case CURLPROTO_SMB:
+ case CURLPROTO_SMBS:
+ family = CURLPROTO_SMB;
+ break;
+
+ default:
+ family = 0;
+ break;
+ }
+
+ return family;
}