summaryrefslogtreecommitdiffstats
path: root/lib/http.c
diff options
context:
space:
mode:
authorCurl Upstream <curl-library@cool.haxx.se>2015-08-11 18:13:01 (GMT)
committerBrad King <brad.king@kitware.com>2015-08-12 18:18:06 (GMT)
commit706542615828488a5ad197d0ef3dd5e42eb739c4 (patch)
tree66bac7b097b4502a0e41eaba51c6b82312bc7f16 /lib/http.c
parent3fe5d9bff98b4716e219516c30d71462495324f4 (diff)
downloadCMake-706542615828488a5ad197d0ef3dd5e42eb739c4.zip
CMake-706542615828488a5ad197d0ef3dd5e42eb739c4.tar.gz
CMake-706542615828488a5ad197d0ef3dd5e42eb739c4.tar.bz2
curl 7.44.0 (reduced)
Extract upstream curl using the following shell code. url=git://github.com/bagder/curl.git && v=7.44.0 && r=1a7f66a3 && paths=" CMake/* CMakeLists.txt COPYING include/curl/*.h include/curl/curlbuild.h.cmake lib/*.c lib/*.h lib/CMakeLists.txt lib/Makefile.inc lib/curl_config.h.cmake lib/libcurl.rc lib/vtls/*.c lib/vtls/*.h " && mkdir curl-$v-g$r-reduced && git clone $url curl-git && date=$(cd curl-git && git log -n 1 --format='%cd' $r) && (cd curl-git && git checkout $r && git archive --format=tar $r -- $paths) | (cd curl-$v-g$r-reduced && tar xv && rm lib/config-*.h) && echo "g$r date: $date"
Diffstat (limited to 'lib/http.c')
-rw-r--r--lib/http.c378
1 files changed, 226 insertions, 152 deletions
diff --git a/lib/http.c b/lib/http.c
index 35baa34..9817d72 100644
--- a/lib/http.c
+++ b/lib/http.c
@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2015, 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
@@ -63,7 +63,6 @@
#include "share.h"
#include "hostip.h"
#include "http.h"
-#include "curl_memory.h"
#include "select.h"
#include "parsedate.h" /* for the week day and month names */
#include "strtoofft.h"
@@ -73,15 +72,14 @@
#include "http_proxy.h"
#include "warnless.h"
#include "non-ascii.h"
-#include "bundles.h"
+#include "conncache.h"
#include "pipeline.h"
#include "http2.h"
#include "connect.h"
+#include "curl_printf.h"
-#define _MPRINTF_REPLACE /* use our functions only */
-#include <curl/mprintf.h>
-
-/* The last #include file should be: */
+/* The last #include files should be: */
+#include "curl_memory.h"
#include "memdebug.h"
/*
@@ -155,12 +153,18 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
{
/* allocate the HTTP-specific struct for the SessionHandle, only to survive
during this request */
+ struct HTTP *http;
DEBUGASSERT(conn->data->req.protop == NULL);
- conn->data->req.protop = calloc(1, sizeof(struct HTTP));
- if(!conn->data->req.protop)
+ http = calloc(1, sizeof(struct HTTP));
+ if(!http)
return CURLE_OUT_OF_MEMORY;
+ conn->data->req.protop = http;
+
+ Curl_http2_setup_conn(conn);
+ Curl_http2_setup_req(conn->data);
+
return CURLE_OK;
}
@@ -279,7 +283,7 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
char **userp;
const char *user;
const char *pwd;
- CURLcode error;
+ CURLcode result;
if(proxy) {
userp = &conn->allocptr.proxyuserpwd;
@@ -294,16 +298,16 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
- error = Curl_base64_encode(data,
- data->state.buffer, strlen(data->state.buffer),
- &authorization, &size);
- if(error)
- return error;
+ result = Curl_base64_encode(data,
+ data->state.buffer, strlen(data->state.buffer),
+ &authorization, &size);
+ if(result)
+ return result;
if(!authorization)
return CURLE_REMOTE_ACCESS_DENIED;
- Curl_safefree(*userp);
+ free(*userp);
*userp = aprintf("%sAuthorization: Basic %s\r\n",
proxy?"Proxy-":"",
authorization);
@@ -392,16 +396,21 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
bytessent = http->writebytecount;
- if(conn->bits.authneg)
+ if(conn->bits.authneg) {
/* This is a state where we are known to be negotiating and we don't send
any data then. */
expectsend = 0;
+ }
+ else if(!conn->bits.protoconnstart) {
+ /* HTTP CONNECT in progress: there is no body */
+ expectsend = 0;
+ }
else {
/* figure out how much data we are expected to send */
switch(data->set.httpreq) {
case HTTPREQ_POST:
- if(data->set.postfieldsize != -1)
- expectsend = data->set.postfieldsize;
+ if(data->state.infilesize != -1)
+ expectsend = data->state.infilesize;
else if(data->set.postfields)
expectsend = (curl_off_t)strlen(data->set.postfields);
break;
@@ -420,6 +429,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
conn->bits.rewindaftersend = FALSE; /* default */
if((expectsend == -1) || (expectsend > bytessent)) {
+#if defined(USE_NTLM)
/* There is still data left to send */
if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
(data->state.authhost.picked == CURLAUTH_NTLM) ||
@@ -439,6 +449,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
return CURLE_OK;
}
+
if(conn->bits.close)
/* this is already marked to get closed */
return CURLE_OK;
@@ -447,9 +458,9 @@ static CURLcode http_perhapsrewind(struct connectdata *conn)
CURL_FORMAT_CURL_OFF_T " bytes\n",
(curl_off_t)(expectsend - bytessent));
}
+#endif
- /* This is not NTLM or many bytes left to send: close
- */
+ /* This is not NTLM or many bytes left to send: close */
connclose(conn, "Mid-auth HTTP and much data left to send");
data->req.size = 0; /* don't download any more than 0 bytes */
@@ -476,7 +487,7 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
struct SessionHandle *data = conn->data;
bool pickhost = FALSE;
bool pickproxy = FALSE;
- CURLcode code = CURLE_OK;
+ CURLcode result = CURLE_OK;
if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
/* this is a transient response code, ignore */
@@ -512,9 +523,9 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
if((data->set.httpreq != HTTPREQ_GET) &&
(data->set.httpreq != HTTPREQ_HEAD) &&
!conn->bits.rewindaftersend) {
- code = http_perhapsrewind(conn);
- if(code)
- return code;
+ result = http_perhapsrewind(conn);
+ if(result)
+ return result;
}
}
@@ -536,10 +547,10 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
if(http_should_fail(conn)) {
failf (data, "The requested URL returned error: %d",
data->req.httpcode);
- code = CURLE_HTTP_RETURNED_ERROR;
+ result = CURLE_HTTP_RETURNED_ERROR;
}
- return code;
+ return result;
}
@@ -554,9 +565,11 @@ output_auth_headers(struct connectdata *conn,
const char *path,
bool proxy)
{
- struct SessionHandle *data = conn->data;
- const char *auth=NULL;
+ const char *auth = NULL;
CURLcode result = CURLE_OK;
+#if defined(USE_SPNEGO) || !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ struct SessionHandle *data = conn->data;
+#endif
#ifdef USE_SPNEGO
struct negotiatedata *negdata = proxy?
&data->state.proxyneg:&data->state.negotiate;
@@ -672,7 +685,7 @@ Curl_http_output_auth(struct connectdata *conn,
if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
conn->bits.user_passwd)
- /* continue please */ ;
+ /* continue please */;
else {
authhost->done = TRUE;
authproxy->done = TRUE;
@@ -773,14 +786,13 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
while(*auth) {
#ifdef USE_SPNEGO
if(checkprefix("Negotiate", auth)) {
- int neg;
*availp |= CURLAUTH_NEGOTIATE;
authp->avail |= CURLAUTH_NEGOTIATE;
if(authp->picked == CURLAUTH_NEGOTIATE) {
if(negdata->state == GSS_AUTHSENT || negdata->state == GSS_AUTHNONE) {
- neg = Curl_input_negotiate(conn, proxy, auth);
- if(neg == 0) {
+ CURLcode result = Curl_input_negotiate(conn, proxy, auth);
+ if(!result) {
DEBUGASSERT(!data->req.newurl);
data->req.newurl = strdup(data->change.url);
if(!data->req.newurl)
@@ -804,9 +816,8 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
if(authp->picked == CURLAUTH_NTLM ||
authp->picked == CURLAUTH_NTLM_WB) {
/* NTLM authentication is picked and activated */
- CURLcode ntlm =
- Curl_input_ntlm(conn, proxy, auth);
- if(CURLE_OK == ntlm) {
+ CURLcode result = Curl_input_ntlm(conn, proxy, auth);
+ if(!result) {
data->state.authproblem = FALSE;
#ifdef NTLM_WB_ENABLED
if(authp->picked == CURLAUTH_NTLM_WB) {
@@ -844,7 +855,7 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
infof(data, "Ignoring duplicate digest auth header.\n");
}
else {
- CURLdigest dig;
+ CURLcode result;
*availp |= CURLAUTH_DIGEST;
authp->avail |= CURLAUTH_DIGEST;
@@ -852,9 +863,8 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
* authentication isn't activated yet, as we need to store the
* incoming data from this header in case we are gonna use
* Digest. */
- dig = Curl_input_digest(conn, proxy, auth);
-
- if(CURLDIGEST_FINE != dig) {
+ result = Curl_input_digest(conn, proxy, auth);
+ if(result) {
infof(data, "Authentication problem. Ignoring this.\n");
data->state.authproblem = TRUE;
}
@@ -991,8 +1001,8 @@ static size_t readmoredata(char *buffer,
/* move backup data into focus and continue on that */
http->postdata = http->backup.postdata;
http->postsize = http->backup.postsize;
- conn->fread_func = http->backup.fread_func;
- conn->fread_in = http->backup.fread_in;
+ conn->data->set.fread_func = http->backup.fread_func;
+ conn->data->set.in = http->backup.fread_in;
http->sending++; /* move one step up */
@@ -1023,6 +1033,16 @@ Curl_send_buffer *Curl_add_buffer_init(void)
}
/*
+ * Curl_add_buffer_free() frees all associated resources.
+ */
+void Curl_add_buffer_free(Curl_send_buffer *buff)
+{
+ if(buff) /* deal with NULL input */
+ free(buff->buffer);
+ free(buff);
+}
+
+/*
* Curl_add_buffer_send() sends a header buffer and frees all associated
* memory. Body data may be appended to the header data if desired.
*
@@ -1041,7 +1061,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
{
ssize_t amount;
- CURLcode res;
+ CURLcode result;
char *ptr;
size_t size;
struct HTTP *http = conn->data->req.protop;
@@ -1064,14 +1084,12 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
DEBUGASSERT(size > included_body_bytes);
- res = Curl_convert_to_network(conn->data, ptr, headersize);
+ result = Curl_convert_to_network(conn->data, ptr, headersize);
/* Curl_convert_to_network calls failf if unsuccessful */
- if(res) {
+ if(result) {
/* conversion failed, free memory and return to the caller */
- if(in->buffer)
- free(in->buffer);
- free(in);
- return res;
+ Curl_add_buffer_free(in);
+ return result;
}
@@ -1096,9 +1114,9 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
else
sendsize = size;
- res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
+ result = Curl_write(conn, sockfd, ptr, sendsize, &amount);
- if(CURLE_OK == res) {
+ if(!result) {
/*
* Note that we may not send the entire chunk at once, and we have a set
* number of data bytes at the end of the big buffer (out of which we may
@@ -1139,14 +1157,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
ptr = in->buffer + amount;
/* backup the currently set pointers */
- http->backup.fread_func = conn->fread_func;
- http->backup.fread_in = conn->fread_in;
+ http->backup.fread_func = conn->data->set.fread_func;
+ http->backup.fread_in = conn->data->set.in;
http->backup.postdata = http->postdata;
http->backup.postsize = http->postsize;
/* set the new pointers for the request-sending */
- conn->fread_func = (curl_read_callback)readmoredata;
- conn->fread_in = (void *)conn;
+ conn->data->set.fread_func = (curl_read_callback)readmoredata;
+ conn->data->set.in = (void *)conn;
http->postdata = ptr;
http->postsize = (curl_off_t)size;
@@ -1169,14 +1187,12 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
*/
return CURLE_SEND_ERROR;
else
- conn->writechannel_inuse = FALSE;
+ Curl_pipeline_leave_write(conn);
}
}
- if(in->buffer)
- free(in->buffer);
- free(in);
+ Curl_add_buffer_free(in);
- return res;
+ return result;
}
@@ -1197,8 +1213,7 @@ CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
return result;
}
/* If we failed, we cleanup the whole buffer and return error */
- if(in->buffer)
- free(in->buffer);
+ free(in->buffer);
free(in);
return CURLE_OUT_OF_MEMORY;
}
@@ -1378,7 +1393,7 @@ static CURLcode https_connecting(struct connectdata *conn, bool *done)
}
#endif
-#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
+#if defined(USE_OPENSSL) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
defined(USE_DARWINSSL) || defined(USE_POLARSSL) || defined(USE_NSS)
/* This function is for OpenSSL, GnuTLS, darwinssl, schannel and polarssl only.
It should be made to query the generic SSL layer instead. */
@@ -1417,7 +1432,7 @@ static int https_getsock(struct connectdata *conn,
return GETSOCK_BLANK;
}
#endif /* USE_SSL */
-#endif /* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL */
+#endif /* USE_OPENSSL || USE_GNUTLS || USE_SCHANNEL */
/*
* Curl_http_done() gets called from Curl_done() after a single HTTP request
@@ -1428,19 +1443,26 @@ CURLcode Curl_http_done(struct connectdata *conn,
CURLcode status, bool premature)
{
struct SessionHandle *data = conn->data;
- struct HTTP *http =data->req.protop;
+ struct HTTP *http = data->req.protop;
+#ifdef USE_NGHTTP2
+ struct http_conn *httpc = &conn->proto.httpc;
+#endif
Curl_unencode_cleanup(conn);
#ifdef USE_SPNEGO
if(data->state.proxyneg.state == GSS_AUTHSENT ||
- data->state.negotiate.state == GSS_AUTHSENT)
+ data->state.negotiate.state == GSS_AUTHSENT) {
+ /* add forbid re-use if http-code != 401/407 as a WA only needed for
+ * 401/407 that signal auth failure (empty) otherwise state will be RECV
+ * with current code */
+ if((data->req.httpcode != 401) && (data->req.httpcode != 407))
+ connclose(conn, "Negotiate transfer completed");
Curl_cleanup_negotiate(data);
+ }
#endif
/* set the proper values (possibly modified on POST) */
- conn->fread_func = data->set.fread_func; /* restore */
- conn->fread_in = data->set.in; /* restore */
conn->seek_func = data->set.seek_func; /* restore */
conn->seek_client = data->set.seek_client; /* restore */
@@ -1448,13 +1470,27 @@ CURLcode Curl_http_done(struct connectdata *conn,
return CURLE_OK;
if(http->send_buffer) {
- Curl_send_buffer *buff = http->send_buffer;
-
- free(buff->buffer);
- free(buff);
+ Curl_add_buffer_free(http->send_buffer);
http->send_buffer = NULL; /* clear the pointer */
}
+#ifdef USE_NGHTTP2
+ if(http->header_recvbuf) {
+ DEBUGF(infof(data, "free header_recvbuf!!\n"));
+ Curl_add_buffer_free(http->header_recvbuf);
+ http->header_recvbuf = NULL; /* clear the pointer */
+ for(; http->push_headers_used > 0; --http->push_headers_used) {
+ free(http->push_headers[http->push_headers_used - 1]);
+ }
+ free(http->push_headers);
+ http->push_headers = NULL;
+ }
+ if(http->stream_id) {
+ nghttp2_session_set_stream_user_data(httpc->h2, http->stream_id, 0);
+ http->stream_id = 0;
+ }
+#endif
+
if(HTTPREQ_POST_FORM == data->set.httpreq) {
data->req.bytecount = http->readbytecount + http->writebytecount;
@@ -1468,8 +1504,8 @@ CURLcode Curl_http_done(struct connectdata *conn,
else if(HTTPREQ_PUT == data->set.httpreq)
data->req.bytecount = http->readbytecount + http->writebytecount;
- if(status != CURLE_OK)
- return (status);
+ if(status)
+ return status;
if(!premature && /* this check is pointless when DONE is called before the
entire operation is complete */
@@ -1517,10 +1553,11 @@ static CURLcode expect100(struct SessionHandle *data,
const char *ptr;
data->state.expect100header = FALSE; /* default to false unless it is set
to TRUE below */
- if(use_http_1_1plus(data, conn)) {
- /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
- 100-continue to the headers which actually speeds up post operations
- (as there is one packet coming back from the web server) */
+ if(use_http_1_1plus(data, conn) &&
+ (conn->httpversion != 20)) {
+ /* if not doing HTTP 1.0 or version 2, or disabled explicitly, we add an
+ Expect: 100-continue to the headers which actually speeds up post
+ operations (as there is one packet coming back from the web server) */
ptr = Curl_checkheaders(conn, "Expect:");
if(ptr) {
data->state.expect100header =
@@ -1529,7 +1566,7 @@ static CURLcode expect100(struct SessionHandle *data,
else {
result = Curl_add_bufferf(req_buffer,
"Expect: 100-continue\r\n");
- if(result == CURLE_OK)
+ if(!result)
data->state.expect100header = TRUE;
}
}
@@ -1659,10 +1696,8 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data,
{
const struct tm *tm;
char *buf = data->state.buffer;
- CURLcode result = CURLE_OK;
struct tm keeptime;
-
- result = Curl_gmtime(data->set.timevalue, &keeptime);
+ CURLcode result = Curl_gmtime(data->set.timevalue, &keeptime);
if(result) {
failf(data, "Invalid TIMEVALUE");
return result;
@@ -1713,8 +1748,8 @@ CURLcode Curl_add_timecondition(struct SessionHandle *data,
*/
CURLcode Curl_http(struct connectdata *conn, bool *done)
{
- struct SessionHandle *data=conn->data;
- CURLcode result=CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ CURLcode result = CURLE_OK;
struct HTTP *http;
const char *ppath = data->state.path;
bool paste_ftp_userpwd = FALSE;
@@ -1724,7 +1759,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
const char *ptr;
const char *request;
Curl_HttpReq httpreq = data->set.httpreq;
+#if !defined(CURL_DISABLE_COOKIES)
char *addcookies = NULL;
+#endif
curl_off_t included_body = 0;
const char *httpstring;
Curl_send_buffer *req_buffer;
@@ -1738,8 +1775,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(conn->httpversion < 20) { /* unless the connection is re-used and already
http2 */
- switch (conn->negnpn) {
- case NPN_HTTP2:
+ switch(conn->negnpn) {
+ case CURL_HTTP_VERSION_2_0:
+ conn->httpversion = 20; /* we know we're on HTTP/2 now */
result = Curl_http2_init(conn);
if(result)
return result;
@@ -1748,11 +1786,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(result)
return result;
- result = Curl_http2_switched(conn);
+ result = Curl_http2_switched(conn, NULL, 0);
if(result)
return result;
break;
- case NPN_HTTP1_1:
+ case CURL_HTTP_VERSION_1_1:
/* continue with HTTP/1.1 when explicitly requested */
break;
default:
@@ -1770,10 +1808,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
http = data->req.protop;
if(!data->state.this_is_a_follow) {
- /* this is not a followed location, get the original host name */
- if(data->state.first_host)
- /* Free to avoid leaking memory on multiple requests*/
- free(data->state.first_host);
+ /* Free to avoid leaking memory on multiple requests*/
+ free(data->state.first_host);
data->state.first_host = strdup(conn->host.name);
if(!data->state.first_host)
@@ -1817,7 +1853,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
it might have been used in the proxy connect, but if we have got a header
with the user-agent string specified, we erase the previously made string
here. */
- if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) {
+ if(Curl_checkheaders(conn, "User-Agent:")) {
free(conn->allocptr.uagent);
conn->allocptr.uagent=NULL;
}
@@ -1846,8 +1882,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
else
conn->allocptr.ref = NULL;
+#if !defined(CURL_DISABLE_COOKIES)
if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie:"))
addcookies = data->set.str[STRING_COOKIE];
+#endif
if(!Curl_checkheaders(conn, "Accept-Encoding:") &&
data->set.str[STRING_ENCODING]) {
@@ -1958,7 +1996,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
#endif
- conn->allocptr.host = NULL;
+ if(strcmp("Host:", ptr)) {
+ conn->allocptr.host = aprintf("%s\r\n", ptr);
+ if(!conn->allocptr.host)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else
+ /* when clearing the header */
+ conn->allocptr.host = NULL;
}
else {
/* When building Host: headers, we must put the host name within
@@ -2153,8 +2198,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
!Curl_checkheaders(conn, "Range:")) {
/* if a line like this was already allocated, free the previous one */
- if(conn->allocptr.rangeline)
- free(conn->allocptr.rangeline);
+ free(conn->allocptr.rangeline);
conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
data->state.range);
}
@@ -2162,8 +2206,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
!Curl_checkheaders(conn, "Content-Range:")) {
/* if a line like this was already allocated, free the previous one */
- if(conn->allocptr.rangeline)
- free(conn->allocptr.rangeline);
+ free(conn->allocptr.rangeline);
if(data->set.set_resume_from < 0) {
/* Upload resume was asked for, but we don't know the size of the
@@ -2227,11 +2270,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_add_bufferf(req_buffer,
"%s" /* ftp typecode (;type=x) */
" HTTP/%s\r\n" /* HTTP version */
+ "%s" /* host */
"%s" /* proxyuserpwd */
"%s" /* userpwd */
"%s" /* range */
"%s" /* user agent */
- "%s" /* host */
"%s" /* accept */
"%s" /* TE: */
"%s" /* accept-encoding */
@@ -2241,6 +2284,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
ftp_typecode,
httpstring,
+ (conn->allocptr.host?conn->allocptr.host:""),
conn->allocptr.proxyuserpwd?
conn->allocptr.proxyuserpwd:"",
conn->allocptr.userpwd?conn->allocptr.userpwd:"",
@@ -2250,7 +2294,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
*data->set.str[STRING_USERAGENT] &&
conn->allocptr.uagent)?
conn->allocptr.uagent:"",
- (conn->allocptr.host?conn->allocptr.host:""),
http->p_accept?http->p_accept:"",
conn->allocptr.te?conn->allocptr.te:"",
(data->set.str[STRING_ENCODING] &&
@@ -2266,18 +2309,26 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
te
);
+ /* clear userpwd to avoid re-using credentials from re-used connections */
+ Curl_safefree(conn->allocptr.userpwd);
+
/*
- * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
- * with basic and digest, it will be freed anyway by the next request
+ * Free proxyuserpwd for Negotiate/NTLM. Cannot reuse as it is associated
+ * with the connection and shouldn't be repeated over it either.
*/
-
- Curl_safefree (conn->allocptr.userpwd);
- conn->allocptr.userpwd = NULL;
+ switch (data->state.authproxy.picked) {
+ case CURLAUTH_NEGOTIATE:
+ case CURLAUTH_NTLM:
+ case CURLAUTH_NTLM_WB:
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ break;
+ }
if(result)
return result;
if(!(conn->handler->flags&PROTOPT_SSL) &&
+ conn->httpversion != 20 &&
(data->set.httpversion == CURL_HTTP_VERSION_2_0)) {
/* append HTTP2 upgrade magic stuff to the HTTP request if it isn't done
over SSL */
@@ -2322,17 +2373,16 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
}
Curl_cookie_freelist(store, FALSE); /* free the cookie list */
}
- if(addcookies && (CURLE_OK == result)) {
+ if(addcookies && !result) {
if(!count)
result = Curl_add_bufferf(req_buffer, "Cookie: ");
- if(CURLE_OK == result) {
- result = Curl_add_bufferf(req_buffer, "%s%s",
- count?"; ":"",
+ if(!result) {
+ result = Curl_add_bufferf(req_buffer, "%s%s", count?"; ":"",
addcookies);
count++;
}
}
- if(count && (CURLE_OK == result))
+ if(count && !result)
result = Curl_add_buffer(req_buffer, "\r\n", 2);
if(result)
@@ -2384,14 +2434,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* Get the currently set callback function pointer and store that in the
form struct since we might want the actual user-provided callback later
- on. The conn->fread_func pointer itself will be changed for the
+ on. The data->set.fread_func pointer itself will be changed for the
multipart case to the function that returns a multipart formatted
stream. */
- http->form.fread_func = conn->fread_func;
+ http->form.fread_func = data->set.fread_func;
/* Set the read function to read from the generated form data */
- conn->fread_func = (curl_read_callback)Curl_FormReader;
- conn->fread_in = &http->form;
+ data->set.fread_func = (curl_read_callback)Curl_FormReader;
+ data->set.in = &http->form;
http->sending = HTTPSEND_BODY;
@@ -2511,8 +2561,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
postsize = 0;
else {
/* figure out the size of the postfields */
- postsize = (data->set.postfieldsize != -1)?
- data->set.postfieldsize:
+ postsize = (data->state.infilesize != -1)?
+ data->state.infilesize:
(data->set.postfields? (curl_off_t)strlen(data->set.postfields):-1);
}
@@ -2584,17 +2634,16 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
if(postsize) {
/* Append the POST data chunky-style */
result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize);
- if(CURLE_OK == result) {
+ if(!result) {
result = Curl_add_buffer(req_buffer, data->set.postfields,
(size_t)postsize);
- if(CURLE_OK == result)
- result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ if(!result)
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
included_body = postsize + 2;
}
}
- if(CURLE_OK == result)
- result = Curl_add_buffer(req_buffer,
- "\x30\x0d\x0a\x0d\x0a", 5);
+ if(!result)
+ result = Curl_add_buffer(req_buffer, "\x30\x0d\x0a\x0d\x0a", 5);
/* 0 CR LF CR LF */
included_body += 5;
}
@@ -2610,8 +2659,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
http->sending = HTTPSEND_BODY;
- conn->fread_func = (curl_read_callback)readmoredata;
- conn->fread_in = (void *)conn;
+ data->set.fread_func = (curl_read_callback)readmoredata;
+ data->set.in = (void *)conn;
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
@@ -2636,7 +2685,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result;
}
- else if(data->set.postfieldsize) {
+ else if(data->state.infilesize) {
/* set the upload size to the progress meter */
Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
@@ -2997,10 +3046,12 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
infof(data, "Received 101\n");
k->upgr101 = UPGR101_RECEIVED;
- /* switch to http2 now */
- result = Curl_http2_switched(conn);
+ /* switch to http2 now. The bytes after response headers
+ are also processed here, otherwise they are lost. */
+ result = Curl_http2_switched(conn, k->str, *nread);
if(result)
return result;
+ *nread = 0;
}
break;
default:
@@ -3025,6 +3076,19 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
}
}
+ /* At this point we have some idea about the fate of the connection.
+ If we are closing the connection it may result auth failure. */
+#if defined(USE_NTLM)
+ if(conn->bits.close &&
+ (((data->req.httpcode == 401) &&
+ (conn->ntlm.state == NTLMSTATE_TYPE2)) ||
+ ((data->req.httpcode == 407) &&
+ (conn->proxyntlm.state == NTLMSTATE_TYPE2)))) {
+ infof(data, "Connection closure while negotiating auth (HTTP 1.0?)\n");
+ data->state.authproblem = TRUE;
+ }
+#endif
+
/*
* When all the headers have been parsed, see if we should give
* up and return an error.
@@ -3203,13 +3267,26 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
#endif /* CURL_DOES_CONVERSIONS */
if(conn->handler->protocol & PROTO_FAMILY_HTTP) {
+ /*
+ * https://tools.ietf.org/html/rfc7230#section-3.1.2
+ *
+ * The reponse code is always a three-digit number in HTTP as the spec
+ * says. We try to allow any number here, but we cannot make
+ * guarantees on future behaviors since it isn't within the protocol.
+ */
nc = sscanf(HEADER1,
- " HTTP/%d.%d %3d",
+ " HTTP/%d.%d %d",
&httpversion_major,
&conn->httpversion,
&k->httpcode);
if(nc==3) {
conn->httpversion += 10 * httpversion_major;
+
+ if(k->upgr101 == UPGR101_RECEIVED) {
+ /* supposedly upgraded to http2 now */
+ if(conn->httpversion != 20)
+ infof(data, "Lying server, not serving HTTP/2\n");
+ }
}
else {
/* this is the real world, not a Nirvana
@@ -3287,20 +3364,25 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
infof(data, "HTTP 1.0, assume close after body\n");
connclose(conn, "HTTP/1.0 close after body");
}
+ else if(conn->httpversion == 20 ||
+ (k->upgr101 == UPGR101_REQUESTED && k->httpcode == 101)) {
+ DEBUGF(infof(data, "HTTP/2 found, allow multiplexing\n"));
+
+ /* HTTP/2 cannot blacklist multiplexing since it is a core
+ functionality of the protocol */
+ conn->bundle->multiuse = BUNDLE_MULTIPLEX;
+ }
else if(conn->httpversion >= 11 &&
!conn->bits.close) {
- struct connectbundle *cb_ptr;
-
/* If HTTP version is >= 1.1 and connection is persistent
server supports pipelining. */
DEBUGF(infof(data,
"HTTP 1.1 or later with persistent connection, "
"pipelining supported\n"));
/* Activate pipelining if needed */
- cb_ptr = conn->bundle;
- if(cb_ptr) {
+ if(conn->bundle) {
if(!Curl_pipeline_site_blacklisted(data, conn))
- cb_ptr->server_supports_pipelining = TRUE;
+ conn->bundle->multiuse = BUNDLE_PIPELINING;
}
}
@@ -3379,14 +3461,17 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
}
}
else if(checkprefix("Server:", k->p)) {
- char *server_name = Curl_copy_header_value(k->p);
-
- /* Turn off pipelining if the server version is blacklisted */
- if(conn->bundle && conn->bundle->server_supports_pipelining) {
- if(Curl_pipeline_server_blacklisted(data, server_name))
- conn->bundle->server_supports_pipelining = FALSE;
+ if(conn->httpversion < 20) {
+ /* only do this for non-h2 servers */
+ char *server_name = Curl_copy_header_value(k->p);
+
+ /* Turn off pipelining if the server version is blacklisted */
+ if(conn->bundle && (conn->bundle->multiuse == BUNDLE_PIPELINING)) {
+ if(Curl_pipeline_server_blacklisted(data, server_name))
+ conn->bundle->multiuse = BUNDLE_NO_MULTIUSE;
+ }
+ free(server_name);
}
- Curl_safefree(server_name);
}
else if((conn->httpversion == 10) &&
conn->bits.httpproxy &&
@@ -3483,14 +3568,6 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
k->auto_decoding = GZIP;
start += 6;
}
- else if(checkprefix("compress", start)) {
- k->auto_decoding = COMPRESS;
- start += 8;
- }
- else if(checkprefix("x-compress", start)) {
- k->auto_decoding = COMPRESS;
- start += 10;
- }
else
/* unknown! */
break;
@@ -3523,9 +3600,6 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
else if(checkprefix("gzip", start)
|| checkprefix("x-gzip", start))
k->auto_decoding = GZIP;
- else if(checkprefix("compress", start)
- || checkprefix("x-compress", start))
- k->auto_decoding = COMPRESS;
}
else if(checkprefix("Content-Range:", k->p)) {
/* Content-Range: bytes [num]-
@@ -3591,7 +3665,7 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
result = Curl_http_input_auth(conn, proxy, auth);
- Curl_safefree(auth);
+ free(auth);
if(result)
return result;