summaryrefslogtreecommitdiffstats
path: root/Utilities/cmcurl/lib/http.c
diff options
context:
space:
mode:
Diffstat (limited to 'Utilities/cmcurl/lib/http.c')
-rw-r--r--Utilities/cmcurl/lib/http.c226
1 files changed, 156 insertions, 70 deletions
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c
index ff1d681..e727ed8 100644
--- a/Utilities/cmcurl/lib/http.c
+++ b/Utilities/cmcurl/lib/http.c
@@ -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)