|
@@ -158,18 +158,20 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn)
|
|
|
/* allocate the HTTP-specific struct for the Curl_easy, only to survive
|
|
|
during this request */
|
|
|
struct HTTP *http;
|
|
|
- DEBUGASSERT(conn->data->req.protop == NULL);
|
|
|
+ struct Curl_easy *data = conn->data;
|
|
|
+ DEBUGASSERT(data->req.protop == NULL);
|
|
|
|
|
|
http = calloc(1, sizeof(struct HTTP));
|
|
|
if(!http)
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
|
|
|
Curl_mime_initpart(&http->form, conn->data);
|
|
|
- conn->data->req.protop = http;
|
|
|
-
|
|
|
- Curl_http2_setup_conn(conn);
|
|
|
- Curl_http2_setup_req(conn->data);
|
|
|
+ data->req.protop = http;
|
|
|
|
|
|
+ if(!CONN_INUSE(conn))
|
|
|
+ /* if not alredy multi-using, setup connection details */
|
|
|
+ Curl_http2_setup_conn(conn);
|
|
|
+ Curl_http2_setup_req(data);
|
|
|
return CURLE_OK;
|
|
|
}
|
|
|
|
|
@@ -310,22 +312,49 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * http_output_bearer() sets up an Authorization: header
|
|
|
+ * for HTTP Bearer authentication.
|
|
|
+ *
|
|
|
+ * Returns CURLcode.
|
|
|
+ */
|
|
|
+static CURLcode http_output_bearer(struct connectdata *conn)
|
|
|
+{
|
|
|
+ char **userp;
|
|
|
+ CURLcode result = CURLE_OK;
|
|
|
+
|
|
|
+ userp = &conn->allocptr.userpwd;
|
|
|
+ free(*userp);
|
|
|
+ *userp = aprintf("Authorization: Bearer %s\r\n",
|
|
|
+ conn->oauth_bearer);
|
|
|
+
|
|
|
+ if(!*userp) {
|
|
|
+ result = CURLE_OUT_OF_MEMORY;
|
|
|
+ goto fail;
|
|
|
+ }
|
|
|
+
|
|
|
+ fail:
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
/* pickoneauth() selects the most favourable authentication method from the
|
|
|
* ones available and the ones we want.
|
|
|
*
|
|
|
* return TRUE if one was picked
|
|
|
*/
|
|
|
-static bool pickoneauth(struct auth *pick)
|
|
|
+static bool pickoneauth(struct auth *pick, unsigned long mask)
|
|
|
{
|
|
|
bool picked;
|
|
|
/* only deal with authentication we want */
|
|
|
- unsigned long avail = pick->avail & pick->want;
|
|
|
+ unsigned long avail = pick->avail & pick->want & mask;
|
|
|
picked = TRUE;
|
|
|
|
|
|
/* The order of these checks is highly relevant, as this will be the order
|
|
|
of preference in case of the existence of multiple accepted types. */
|
|
|
if(avail & CURLAUTH_NEGOTIATE)
|
|
|
pick->picked = CURLAUTH_NEGOTIATE;
|
|
|
+ else if(avail & CURLAUTH_BEARER)
|
|
|
+ pick->picked = CURLAUTH_BEARER;
|
|
|
else if(avail & CURLAUTH_DIGEST)
|
|
|
pick->picked = CURLAUTH_DIGEST;
|
|
|
else if(avail & CURLAUTH_NTLM)
|
|
@@ -479,6 +508,10 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
|
|
|
bool pickhost = FALSE;
|
|
|
bool pickproxy = FALSE;
|
|
|
CURLcode result = CURLE_OK;
|
|
|
+ unsigned long authmask = ~0ul;
|
|
|
+
|
|
|
+ if(!conn->oauth_bearer)
|
|
|
+ authmask &= (unsigned long)~CURLAUTH_BEARER;
|
|
|
|
|
|
if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
|
|
|
/* this is a transient response code, ignore */
|
|
@@ -487,17 +520,18 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
|
|
|
if(data->state.authproblem)
|
|
|
return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
|
|
|
|
|
|
- if(conn->bits.user_passwd &&
|
|
|
+ if((conn->bits.user_passwd || conn->oauth_bearer) &&
|
|
|
((data->req.httpcode == 401) ||
|
|
|
(conn->bits.authneg && data->req.httpcode < 300))) {
|
|
|
- pickhost = pickoneauth(&data->state.authhost);
|
|
|
+ pickhost = pickoneauth(&data->state.authhost, authmask);
|
|
|
if(!pickhost)
|
|
|
data->state.authproblem = TRUE;
|
|
|
}
|
|
|
if(conn->bits.proxy_user_passwd &&
|
|
|
((data->req.httpcode == 407) ||
|
|
|
(conn->bits.authneg && data->req.httpcode < 300))) {
|
|
|
- pickproxy = pickoneauth(&data->state.authproxy);
|
|
|
+ pickproxy = pickoneauth(&data->state.authproxy,
|
|
|
+ authmask & ~CURLAUTH_BEARER);
|
|
|
if(!pickproxy)
|
|
|
data->state.authproblem = TRUE;
|
|
|
}
|
|
@@ -628,6 +662,20 @@ output_auth_headers(struct connectdata *conn,
|
|
|
functions work that way */
|
|
|
authstatus->done = TRUE;
|
|
|
}
|
|
|
+ if(authstatus->picked == CURLAUTH_BEARER) {
|
|
|
+ /* Bearer */
|
|
|
+ if((!proxy && conn->oauth_bearer &&
|
|
|
+ !Curl_checkheaders(conn, "Authorization:"))) {
|
|
|
+ auth = "Bearer";
|
|
|
+ result = http_output_bearer(conn);
|
|
|
+ if(result)
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* NOTE: this function should set 'done' TRUE, as the other auth
|
|
|
+ functions work that way */
|
|
|
+ authstatus->done = TRUE;
|
|
|
+ }
|
|
|
|
|
|
if(auth) {
|
|
|
infof(data, "%s auth using %s with user '%s'\n",
|
|
@@ -674,7 +722,7 @@ Curl_http_output_auth(struct connectdata *conn,
|
|
|
authproxy = &data->state.authproxy;
|
|
|
|
|
|
if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
|
|
|
- conn->bits.user_passwd)
|
|
|
+ conn->bits.user_passwd || conn->oauth_bearer)
|
|
|
/* continue please */;
|
|
|
else {
|
|
|
authhost->done = TRUE;
|
|
@@ -883,6 +931,18 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, bool proxy,
|
|
|
data->state.authproblem = TRUE;
|
|
|
}
|
|
|
}
|
|
|
+ else
|
|
|
+ if(checkprefix("Bearer", auth)) {
|
|
|
+ *availp |= CURLAUTH_BEARER;
|
|
|
+ authp->avail |= CURLAUTH_BEARER;
|
|
|
+ if(authp->picked == CURLAUTH_BEARER) {
|
|
|
+ /* We asked for Bearer authentication but got a 40X back
|
|
|
+ anyway, which basically means our token isn't valid. */
|
|
|
+ authp->avail = CURLAUTH_NONE;
|
|
|
+ infof(data, "Authentication problem. Ignoring this.\n");
|
|
|
+ data->state.authproblem = TRUE;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
/* there may be multiple methods on one line, so keep reading */
|
|
|
while(*auth && *auth != ',') /* read up to the next comma */
|
|
@@ -1063,7 +1123,8 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
|
|
|
CURLcode result;
|
|
|
char *ptr;
|
|
|
size_t size;
|
|
|
- struct HTTP *http = conn->data->req.protop;
|
|
|
+ struct Curl_easy *data = conn->data;
|
|
|
+ struct HTTP *http = data->req.protop;
|
|
|
size_t sendsize;
|
|
|
curl_socket_t sockfd;
|
|
|
size_t headersize;
|
|
@@ -1083,7 +1144,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
|
|
|
|
|
|
DEBUGASSERT(size > included_body_bytes);
|
|
|
|
|
|
- result = Curl_convert_to_network(conn->data, ptr, headersize);
|
|
|
+ result = Curl_convert_to_network(data, ptr, headersize);
|
|
|
/* Curl_convert_to_network calls failf if unsuccessful */
|
|
|
if(result) {
|
|
|
/* conversion failed, free memory and return to the caller */
|
|
@@ -1108,8 +1169,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
|
|
|
must copy the data to the uploadbuffer first, since that is the buffer
|
|
|
we will be using if this send is retried later.
|
|
|
*/
|
|
|
- memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
|
|
|
- ptr = conn->data->state.uploadbuffer;
|
|
|
+ result = Curl_get_upload_buffer(data);
|
|
|
+ if(result) {
|
|
|
+ /* malloc failed, free memory and return to the caller */
|
|
|
+ Curl_add_buffer_free(in);
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+ memcpy(data->state.ulbuf, ptr, sendsize);
|
|
|
+ ptr = data->state.ulbuf;
|
|
|
}
|
|
|
else
|
|
|
sendsize = size;
|
|
@@ -1126,14 +1193,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
|
|
|
size_t headlen = (size_t)amount>headersize ? headersize : (size_t)amount;
|
|
|
size_t bodylen = amount - headlen;
|
|
|
|
|
|
- if(conn->data->set.verbose) {
|
|
|
+ if(data->set.verbose) {
|
|
|
/* this data _may_ contain binary stuff */
|
|
|
- Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, headlen, conn);
|
|
|
+ Curl_debug(data, CURLINFO_HEADER_OUT, ptr, headlen);
|
|
|
if(bodylen) {
|
|
|
/* there was body data sent beyond the initial header part, pass that
|
|
|
on to the debug callback too */
|
|
|
- Curl_debug(conn->data, CURLINFO_DATA_OUT,
|
|
|
- ptr + headlen, bodylen, conn);
|
|
|
+ Curl_debug(data, CURLINFO_DATA_OUT,
|
|
|
+ ptr + headlen, bodylen);
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1157,14 +1224,14 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
|
|
|
ptr = in->buffer + amount;
|
|
|
|
|
|
/* backup the currently set pointers */
|
|
|
- http->backup.fread_func = conn->data->state.fread_func;
|
|
|
- http->backup.fread_in = conn->data->state.in;
|
|
|
+ http->backup.fread_func = data->state.fread_func;
|
|
|
+ http->backup.fread_in = data->state.in;
|
|
|
http->backup.postdata = http->postdata;
|
|
|
http->backup.postsize = http->postsize;
|
|
|
|
|
|
/* set the new pointers for the request-sending */
|
|
|
- conn->data->state.fread_func = (curl_read_callback)readmoredata;
|
|
|
- conn->data->state.in = (void *)conn;
|
|
|
+ data->state.fread_func = (curl_read_callback)readmoredata;
|
|
|
+ data->state.in = (void *)conn;
|
|
|
http->postdata = ptr;
|
|
|
http->postsize = (curl_off_t)size;
|
|
|
|
|
@@ -1223,7 +1290,6 @@ CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
|
|
|
CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
|
|
|
{
|
|
|
char *new_rb;
|
|
|
- size_t new_size;
|
|
|
|
|
|
if(~size < in->size_used) {
|
|
|
/* If resulting used size of send buffer would wrap size_t, cleanup
|
|
@@ -1236,10 +1302,10 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
|
|
|
|
|
|
if(!in->buffer ||
|
|
|
((in->size_used + size) > (in->size_max - 1))) {
|
|
|
-
|
|
|
/* If current buffer size isn't enough to hold the result, use a
|
|
|
buffer size that doubles the required size. If this new size
|
|
|
would wrap size_t, then just use the largest possible one */
|
|
|
+ size_t new_size;
|
|
|
|
|
|
if((size > (size_t)-1 / 2) || (in->size_used > (size_t)-1 / 2) ||
|
|
|
(~(size * 2) < (in->size_used * 2)))
|
|
@@ -1406,7 +1472,7 @@ static CURLcode add_haproxy_protocol_header(struct connectdata *conn)
|
|
|
}
|
|
|
|
|
|
snprintf(proxy_header,
|
|
|
- sizeof proxy_header,
|
|
|
+ sizeof(proxy_header),
|
|
|
"PROXY %s %s %s %li %li\r\n",
|
|
|
tcp_version,
|
|
|
conn->data->info.conn_local_ip,
|
|
@@ -1574,7 +1640,6 @@ static CURLcode expect100(struct Curl_easy *data,
|
|
|
Curl_send_buffer *req_buffer)
|
|
|
{
|
|
|
CURLcode result = CURLE_OK;
|
|
|
- const char *ptr;
|
|
|
data->state.expect100header = FALSE; /* default to false unless it is set
|
|
|
to TRUE below */
|
|
|
if(use_http_1_1plus(data, conn) &&
|
|
@@ -1582,7 +1647,7 @@ static CURLcode expect100(struct Curl_easy *data,
|
|
|
/* 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");
|
|
|
+ const char *ptr = Curl_checkheaders(conn, "Expect");
|
|
|
if(ptr) {
|
|
|
data->state.expect100header =
|
|
|
Curl_compareheader(ptr, "Expect:", "100-continue");
|
|
@@ -1819,7 +1884,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
|
|
const char *httpstring;
|
|
|
Curl_send_buffer *req_buffer;
|
|
|
curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
|
|
|
- int seekerr = CURL_SEEKFUNC_CANTSEEK;
|
|
|
|
|
|
/* Always consider the DO phase done after this function call, even if there
|
|
|
may be parts of the request that is not yet sent, since we can deal with
|
|
@@ -1863,6 +1927,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
|
|
}
|
|
|
|
|
|
http = data->req.protop;
|
|
|
+ DEBUGASSERT(http);
|
|
|
|
|
|
if(!data->state.this_is_a_follow) {
|
|
|
/* Free to avoid leaking memory on multiple requests*/
|
|
@@ -2088,7 +2153,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
|
|
else {
|
|
|
/* If the host begins with '[', we start searching for the port after
|
|
|
the bracket has been closed */
|
|
|
- int startsearch = 0;
|
|
|
if(*cookiehost == '[') {
|
|
|
char *closingbracket;
|
|
|
/* since the 'cookiehost' is an allocated memory area that will be
|
|
@@ -2099,6 +2163,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
|
|
*closingbracket = 0;
|
|
|
}
|
|
|
else {
|
|
|
+ int startsearch = 0;
|
|
|
char *colon = strchr(cookiehost + startsearch, ':');
|
|
|
if(colon)
|
|
|
*colon = 0; /* The host must not include an embedded port number */
|
|
@@ -2244,6 +2309,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
|
|
|
|
|
/* Now, let's read off the proper amount of bytes from the
|
|
|
input. */
|
|
|
+ int seekerr = CURL_SEEKFUNC_CANTSEEK;
|
|
|
if(conn->seek_func) {
|
|
|
Curl_set_in_callback(data, true);
|
|
|
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
|
@@ -2828,6 +2894,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
|
|
data->req.exp100 = EXP100_SEND_DATA; /* already sent */
|
|
|
Curl_expire_done(data, EXPIRE_100_TIMEOUT);
|
|
|
}
|
|
|
+ else
|
|
|
+ data->req.writebytecount = http->writebytecount;
|
|
|
}
|
|
|
|
|
|
if((conn->httpversion == 20) && data->req.upload_chunky)
|
|
@@ -2838,17 +2906,32 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
+typedef enum {
|
|
|
+ STATUS_UNKNOWN, /* not enough data to tell yet */
|
|
|
+ STATUS_DONE, /* a status line was read */
|
|
|
+ STATUS_BAD /* not a status line */
|
|
|
+} statusline;
|
|
|
+
|
|
|
+
|
|
|
+/* Check a string for a prefix. Check no more than 'len' bytes */
|
|
|
+static bool checkprefixmax(const char *prefix, const char *buffer, size_t len)
|
|
|
+{
|
|
|
+ size_t ch = CURLMIN(strlen(prefix), len);
|
|
|
+ return curl_strnequal(prefix, buffer, ch);
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* checkhttpprefix()
|
|
|
*
|
|
|
* Returns TRUE if member of the list matches prefix of string
|
|
|
*/
|
|
|
-static bool
|
|
|
+static statusline
|
|
|
checkhttpprefix(struct Curl_easy *data,
|
|
|
- const char *s)
|
|
|
+ const char *s, size_t len)
|
|
|
{
|
|
|
struct curl_slist *head = data->set.http200aliases;
|
|
|
- bool rc = FALSE;
|
|
|
+ statusline rc = STATUS_BAD;
|
|
|
+ statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
|
|
|
#ifdef CURL_DOES_CONVERSIONS
|
|
|
/* convert from the network encoding using a scratch area */
|
|
|
char *scratch = strdup(s);
|
|
@@ -2865,15 +2948,15 @@ checkhttpprefix(struct Curl_easy *data,
|
|
|
#endif /* CURL_DOES_CONVERSIONS */
|
|
|
|
|
|
while(head) {
|
|
|
- if(checkprefix(head->data, s)) {
|
|
|
- rc = TRUE;
|
|
|
+ if(checkprefixmax(head->data, s, len)) {
|
|
|
+ rc = onmatch;
|
|
|
break;
|
|
|
}
|
|
|
head = head->next;
|
|
|
}
|
|
|
|
|
|
- if(!rc && (checkprefix("HTTP/", s)))
|
|
|
- rc = TRUE;
|
|
|
+ if((rc != STATUS_DONE) && (checkprefixmax("HTTP/", s, len)))
|
|
|
+ rc = onmatch;
|
|
|
|
|
|
#ifdef CURL_DOES_CONVERSIONS
|
|
|
free(scratch);
|
|
@@ -2882,11 +2965,12 @@ checkhttpprefix(struct Curl_easy *data,
|
|
|
}
|
|
|
|
|
|
#ifndef CURL_DISABLE_RTSP
|
|
|
-static bool
|
|
|
+static statusline
|
|
|
checkrtspprefix(struct Curl_easy *data,
|
|
|
- const char *s)
|
|
|
+ const char *s, size_t len)
|
|
|
{
|
|
|
- bool result = FALSE;
|
|
|
+ statusline result = STATUS_BAD;
|
|
|
+ statusline onmatch = len >= 5? STATUS_DONE : STATUS_UNKNOWN;
|
|
|
|
|
|
#ifdef CURL_DOES_CONVERSIONS
|
|
|
/* convert from the network encoding using a scratch area */
|
|
@@ -2899,30 +2983,31 @@ checkrtspprefix(struct Curl_easy *data,
|
|
|
/* Curl_convert_from_network calls failf if unsuccessful */
|
|
|
result = FALSE; /* can't return CURLE_foobar so return FALSE */
|
|
|
}
|
|
|
- else
|
|
|
- result = checkprefix("RTSP/", scratch)? TRUE: FALSE;
|
|
|
+ else if(checkprefixmax("RTSP/", scratch, len))
|
|
|
+ result = onmatch;
|
|
|
free(scratch);
|
|
|
#else
|
|
|
(void)data; /* unused */
|
|
|
- result = checkprefix("RTSP/", s)? TRUE: FALSE;
|
|
|
+ if(checkprefixmax("RTSP/", s, len))
|
|
|
+ result = onmatch;
|
|
|
#endif /* CURL_DOES_CONVERSIONS */
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
#endif /* CURL_DISABLE_RTSP */
|
|
|
|
|
|
-static bool
|
|
|
+static statusline
|
|
|
checkprotoprefix(struct Curl_easy *data, struct connectdata *conn,
|
|
|
- const char *s)
|
|
|
+ const char *s, size_t len)
|
|
|
{
|
|
|
#ifndef CURL_DISABLE_RTSP
|
|
|
if(conn->handler->protocol & CURLPROTO_RTSP)
|
|
|
- return checkrtspprefix(data, s);
|
|
|
+ return checkrtspprefix(data, s, len);
|
|
|
#else
|
|
|
(void)conn;
|
|
|
#endif /* CURL_DISABLE_RTSP */
|
|
|
|
|
|
- return checkhttpprefix(data, s);
|
|
|
+ return checkhttpprefix(data, s, len);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2939,7 +3024,7 @@ static CURLcode header_append(struct Curl_easy *data,
|
|
|
/* The reason to have a max limit for this is to avoid the risk of a bad
|
|
|
server feeding libcurl with a never-ending header that will cause
|
|
|
reallocs infinitely */
|
|
|
- failf(data, "Rejected %zd bytes header (max is %d)!", newsize,
|
|
|
+ failf(data, "Rejected %zu bytes header (max is %d)!", newsize,
|
|
|
CURL_MAX_HTTP_HEADER);
|
|
|
return CURLE_OUT_OF_MEMORY;
|
|
|
}
|
|
@@ -3036,12 +3121,15 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|
|
if(result)
|
|
|
return result;
|
|
|
|
|
|
- if(!k->headerline && (k->hbuflen>5)) {
|
|
|
- /* make a first check that this looks like a protocol header */
|
|
|
- if(!checkprotoprefix(data, conn, data->state.headerbuff)) {
|
|
|
+ if(!k->headerline) {
|
|
|
+ /* check if this looks like a protocol header */
|
|
|
+ statusline st = checkprotoprefix(data, conn, data->state.headerbuff,
|
|
|
+ k->hbuflen);
|
|
|
+ if(st == STATUS_BAD) {
|
|
|
/* this is not the beginning of a protocol first header line */
|
|
|
k->header = FALSE;
|
|
|
k->badheader = HEADER_ALLBAD;
|
|
|
+ streamclose(conn, "bad HTTP: No end-of-message indicator");
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -3070,8 +3158,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|
|
|
|
|
if(!k->headerline) {
|
|
|
/* the first read header */
|
|
|
- if((k->hbuflen>5) &&
|
|
|
- !checkprotoprefix(data, conn, data->state.headerbuff)) {
|
|
|
+ statusline st = checkprotoprefix(data, conn, data->state.headerbuff,
|
|
|
+ k->hbuflen);
|
|
|
+ if(st == STATUS_BAD) {
|
|
|
+ streamclose(conn, "bad HTTP: No end-of-message indicator");
|
|
|
/* this is not the beginning of a protocol first header line */
|
|
|
k->header = FALSE;
|
|
|
if(*nread)
|
|
@@ -3354,7 +3444,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|
|
|
|
|
if(data->set.verbose)
|
|
|
Curl_debug(data, CURLINFO_HEADER_IN,
|
|
|
- k->str_start, headerlen, conn);
|
|
|
+ k->str_start, headerlen);
|
|
|
break; /* exit header line loop */
|
|
|
}
|
|
|
|
|
@@ -3440,7 +3530,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|
|
compare header line against list of aliases
|
|
|
*/
|
|
|
if(!nc) {
|
|
|
- if(checkhttpprefix(data, k->p)) {
|
|
|
+ if(checkhttpprefix(data, k->p, k->hbuflen) == STATUS_DONE) {
|
|
|
nc = 1;
|
|
|
k->httpcode = 200;
|
|
|
conn->httpversion = 10;
|
|
@@ -3487,21 +3577,18 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|
|
* depending on how authentication is working. Other codes
|
|
|
* are definitely errors, so give up here.
|
|
|
*/
|
|
|
- if(data->set.http_fail_on_error && (k->httpcode >= 400) &&
|
|
|
+ if(data->state.resume_from && data->set.httpreq == HTTPREQ_GET &&
|
|
|
+ k->httpcode == 416) {
|
|
|
+ /* "Requested Range Not Satisfiable", just proceed and
|
|
|
+ pretend this is no error */
|
|
|
+ k->ignorebody = TRUE; /* Avoid appending error msg to good data. */
|
|
|
+ }
|
|
|
+ else if(data->set.http_fail_on_error && (k->httpcode >= 400) &&
|
|
|
((k->httpcode != 401) || !conn->bits.user_passwd) &&
|
|
|
((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
|
|
|
-
|
|
|
- if(data->state.resume_from &&
|
|
|
- (data->set.httpreq == HTTPREQ_GET) &&
|
|
|
- (k->httpcode == 416)) {
|
|
|
- /* "Requested Range Not Satisfiable", just proceed and
|
|
|
- pretend this is no error */
|
|
|
- }
|
|
|
- else {
|
|
|
- /* serious error, go home! */
|
|
|
- print_http_error(data);
|
|
|
- return CURLE_HTTP_RETURNED_ERROR;
|
|
|
- }
|
|
|
+ /* serious error, go home! */
|
|
|
+ print_http_error(data);
|
|
|
+ return CURLE_HTTP_RETURNED_ERROR;
|
|
|
}
|
|
|
|
|
|
if(conn->httpversion == 10) {
|
|
@@ -3812,8 +3899,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
|
|
|
writetype |= CLIENTWRITE_BODY;
|
|
|
|
|
|
if(data->set.verbose)
|
|
|
- Curl_debug(data, CURLINFO_HEADER_IN,
|
|
|
- k->p, (size_t)k->hbuflen, conn);
|
|
|
+ Curl_debug(data, CURLINFO_HEADER_IN, k->p, (size_t)k->hbuflen);
|
|
|
|
|
|
result = Curl_client_write(conn, writetype, k->p, k->hbuflen);
|
|
|
if(result)
|