diff options
author | Brad King <brad.king@kitware.com> | 2017-10-04 11:28:34 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2017-10-10 15:15:16 (GMT) |
commit | 9e3ef40edb6eae36e822c129bec5d4ee9de0dd57 (patch) | |
tree | c739e929f90b5e6c4e26d4f5fea7f17d3772aefb /Utilities/cmcurl/lib/http.c | |
parent | 2fad0e20b6b2b4c3cfc177267cf9689658f50c23 (diff) | |
parent | de7c21d677db1ddaeece03c19e13e448f4031511 (diff) | |
download | CMake-9e3ef40edb6eae36e822c129bec5d4ee9de0dd57.zip CMake-9e3ef40edb6eae36e822c129bec5d4ee9de0dd57.tar.gz CMake-9e3ef40edb6eae36e822c129bec5d4ee9de0dd57.tar.bz2 |
Merge branch 'upstream-curl' into update-curl
* upstream-curl:
curl 2017-10-04 (3ea76790)
Diffstat (limited to 'Utilities/cmcurl/lib/http.c')
-rw-r--r-- | Utilities/cmcurl/lib/http.c | 444 |
1 files changed, 240 insertions, 204 deletions
diff --git a/Utilities/cmcurl/lib/http.c b/Utilities/cmcurl/lib/http.c index 21574e2..38227eb 100644 --- a/Utilities/cmcurl/lib/http.c +++ b/Utilities/cmcurl/lib/http.c @@ -50,6 +50,7 @@ #include "transfer.h" #include "sendf.h" #include "formdata.h" +#include "mime.h" #include "progress.h" #include "curl_base64.h" #include "cookie.h" @@ -119,6 +120,7 @@ const struct Curl_handler Curl_handler_http = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_HTTP, /* defport */ CURLPROTO_HTTP, /* protocol */ PROTOPT_CREDSPERREQUEST /* flags */ @@ -143,6 +145,7 @@ const struct Curl_handler Curl_handler_https = { ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ + ZERO_NULL, /* connection_check */ PORT_HTTPS, /* defport */ CURLPROTO_HTTPS, /* protocol */ PROTOPT_SSL | PROTOPT_CREDSPERREQUEST | PROTOPT_ALPN_NPN /* flags */ @@ -160,6 +163,7 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn) if(!http) return CURLE_OUT_OF_MEMORY; + Curl_mime_initpart(&http->form, conn->data); conn->data->req.protop = http; Curl_http2_setup_conn(conn); @@ -168,26 +172,6 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn) return CURLE_OK; } -/* - * checkheaders() checks the linked list of custom HTTP headers for a - * particular header (prefix). - * - * Returns a pointer to the first matching header or NULL if none matched. - */ -char *Curl_checkheaders(const struct connectdata *conn, - const char *thisheader) -{ - struct curl_slist *head; - size_t thislen = strlen(thisheader); - struct Curl_easy *data = conn->data; - - for(head = data->set.headers;head; head=head->next) { - if(strncasecompare(head->data, thisheader, thislen)) - return head->data; - } - - return NULL; -} /* * checkProxyHeaders() checks the linked list of custom proxy headers @@ -207,7 +191,7 @@ char *Curl_checkProxyheaders(const struct connectdata *conn, for(head = (conn->bits.proxy && data->set.sep_headers) ? data->set.proxyheaders : data->set.headers; - head; head=head->next) { + head; head = head->next) { if(strncasecompare(head->data, thisheader, thislen)) return head->data; } @@ -425,6 +409,7 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) expectsend = data->state.infilesize; break; case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: expectsend = http->postsize; break; default: @@ -608,7 +593,7 @@ output_auth_headers(struct connectdata *conn, #endif #if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) if(authstatus->picked == CURLAUTH_NTLM_WB) { - auth="NTLM_WB"; + auth = "NTLM_WB"; result = Curl_output_ntlm_wb(conn, proxy); if(result) return result; @@ -1020,7 +1005,7 @@ static size_t readmoredata(char *buffer, http->sending++; /* move one step up */ - http->backup.postsize=0; + http->backup.postsize = 0; } else http->postsize = 0; @@ -1148,7 +1133,7 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, /* 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); + ptr + headlen, bodylen, conn); } } @@ -1260,7 +1245,7 @@ CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size) (~(size * 2) < (in->size_used * 2))) new_size = (size_t)-1; else - new_size = (in->size_used+size) * 2; + new_size = (in->size_used + size) * 2; if(in->buffer) /* we have a buffer, enlarge the existing one */ @@ -1337,7 +1322,7 @@ Curl_compareheader(const char *headerline, /* line to check */ clen = strlen(content); /* length of the word to find */ /* find the content string in the rest of the line */ - for(;len>=clen;len--, start++) { + for(; len >= clen; len--, start++) { if(strncasecompare(start, content, clen)) return TRUE; /* match! */ } @@ -1369,7 +1354,7 @@ CURLcode Curl_http_connect(struct connectdata *conn, bool *done) if(CONNECT_FIRSTSOCKET_PROXY_SSL()) return CURLE_OK; /* wait for HTTPS proxy SSL initialization to complete */ - if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT) + if(Curl_connect_ongoing(conn)) /* nothing else to do except wait right now - we're not done here. */ return CURLE_OK; @@ -1468,18 +1453,17 @@ CURLcode Curl_http_done(struct connectdata *conn, Curl_http2_done(conn, premature); - if(HTTPREQ_POST_FORM == data->set.httpreq) { - data->req.bytecount = http->readbytecount + http->writebytecount; + Curl_mime_cleanpart(&http->form); - Curl_formclean(&http->sendit); /* Now free that whole lot */ - if(http->form.fp) { - /* a file being uploaded was left opened, close it! */ - fclose(http->form.fp); - http->form.fp = NULL; - } - } - else if(HTTPREQ_PUT == data->set.httpreq) + switch(data->set.httpreq) { + case HTTPREQ_PUT: + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: data->req.bytecount = http->readbytecount + http->writebytecount; + break; + default: + break; + } if(status) return status; @@ -1579,7 +1563,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, char *ptr; struct curl_slist *h[2]; struct curl_slist *headers; - int numlists=1; /* by default */ + int numlists = 1; /* by default */ struct Curl_easy *data = conn->data; int i; @@ -1611,7 +1595,7 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, } /* loop through one or two lists */ - for(i=0; i < numlists; i++) { + for(i = 0; i < numlists; i++) { headers = h[i]; while(headers) { @@ -1635,15 +1619,19 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, /* this header (extended by formdata.c) is sent later */ checkprefix("Content-Type:", headers->data)) ; + else if(data->set.httpreq == HTTPREQ_POST_MIME && + /* this header is sent later */ + checkprefix("Content-Type:", headers->data)) + ; else if(conn->bits.authneg && /* while doing auth neg, don't allow the custom length since we will force length zero then */ - checkprefix("Content-Length", headers->data)) + checkprefix("Content-Length:", headers->data)) ; else if(conn->allocptr.te && /* when asking for Transfer-Encoding, don't pass on a custom Connection: */ - checkprefix("Connection", headers->data)) + checkprefix("Connection:", headers->data)) ; else if((conn->httpversion == 20) && checkprefix("Transfer-Encoding:", headers->data)) @@ -1676,6 +1664,10 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, *ptr = ':'; result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data); + + /* restore the previous value */ + *ptr = ';'; + if(result) return result; } @@ -1773,7 +1765,7 @@ 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_OK; + 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 @@ -1846,11 +1838,15 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) switch(httpreq) { case HTTPREQ_POST: case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: request = "POST"; break; case HTTPREQ_PUT: request = "PUT"; break; + case HTTPREQ_OPTIONS: + request = "OPTIONS"; + break; default: /* this should never happen */ case HTTPREQ_GET: request = "GET"; @@ -1868,7 +1864,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) here. */ if(Curl_checkheaders(conn, "User-Agent:")) { free(conn->allocptr.uagent); - conn->allocptr.uagent=NULL; + conn->allocptr.uagent = NULL; } /* setup the authentication headers */ @@ -1937,6 +1933,48 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif + switch(httpreq) { + case HTTPREQ_POST_MIME: + http->sendit = &data->set.mimepost; + break; + case HTTPREQ_POST_FORM: + /* Convert the form structure into a mime structure. */ + Curl_mime_cleanpart(&http->form); + result = Curl_getformdata(data, &http->form, data->set.httppost, + data->state.fread_func); + if(result) + return result; + http->sendit = &http->form; + break; + default: + http->sendit = NULL; + } + + if(http->sendit) { + const char *cthdr = Curl_checkheaders(conn, "Content-Type:"); + + /* Read and seek body only. */ + http->sendit->flags |= MIME_BODY_ONLY; + + /* Prepare the mime structure headers & set content type. */ + + if(cthdr) + for(cthdr += 13; *cthdr == ' '; cthdr++) + ; + else if(http->sendit->kind == MIMEKIND_MULTIPART) + cthdr = "multipart/form-data"; + + curl_mime_headers(http->sendit, data->set.headers, 0); + result = Curl_mime_prepare_headers(http->sendit, cthdr, + NULL, MIMESTRATEGY_FORM); + curl_mime_headers(http->sendit, NULL, 0); + if(!result) + result = Curl_mime_rewind(http->sendit); + if(result) + return result; + http->postsize = Curl_mime_size(http->sendit); + } + ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); if(ptr) { /* Some kind of TE is requested, check if 'chunked' is chosen */ @@ -1944,9 +1982,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_compareheader(ptr, "Transfer-Encoding:", "chunked"); } else { - if((conn->handler->protocol&PROTO_FAMILY_HTTP) && - data->set.upload && - (data->state.infilesize == -1)) { + if((conn->handler->protocol & PROTO_FAMILY_HTTP) && + (((httpreq == HTTPREQ_POST_MIME || httpreq == HTTPREQ_POST_FORM) && + http->postsize < 0) || + (data->set.upload && data->state.infilesize == -1))) { if(conn->bits.authneg) /* don't enable chunked during auth neg */ ; @@ -2044,7 +2083,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #ifndef CURL_DISABLE_PROXY - if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { + if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) { /* Using a proxy but does not tunnel through it */ /* The path sent to the proxy is in fact the entire URL. But if the remote @@ -2118,21 +2157,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif /* CURL_DISABLE_PROXY */ - if(HTTPREQ_POST_FORM == httpreq) { - /* we must build the whole post sequence first, so that we have a size of - the whole transfer before we start to send it */ - result = Curl_getformdata(data, &http->sendit, data->set.httppost, - Curl_checkheaders(conn, "Content-Type:"), - &http->postsize); - if(result) - return result; - } - http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n"; - if(( (HTTPREQ_POST == httpreq) || - (HTTPREQ_POST_FORM == httpreq) || - (HTTPREQ_PUT == httpreq) ) && + if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) && data->state.resume_from) { /********************************************************************** * Resuming upload in HTTP means that we PUT or POST and that we have @@ -2140,6 +2167,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * a Range: header that will be passed along. We need to "fast forward" * the file the given number of bytes and decrease the assume upload * file size before we continue this venture in the dark lands of HTTP. + * Resuming mime/form posting at an offset > 0 has no sense and is ignored. *********************************************************************/ if(data->state.resume_from < 0) { @@ -2161,7 +2189,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(seekerr != CURL_SEEKFUNC_OK) { - curl_off_t passed=0; + curl_off_t passed = 0; if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); @@ -2214,7 +2242,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->state.range); } - else if((httpreq != HTTPREQ_GET) && + else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && !Curl_checkheaders(conn, "Content-Range:")) { /* if a line like this was already allocated, free the previous one */ @@ -2232,7 +2260,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } else if(data->state.resume_from) { /* This is because "resume" was selected */ - curl_off_t total_expected_size= + curl_off_t total_expected_size = data->state.resume_from + data->state.infilesize; conn->allocptr.rangeline = aprintf("Content-Range: bytes %s%" CURL_FORMAT_CURL_OFF_T @@ -2266,6 +2294,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(result) return result; + if(data->set.str[STRING_TARGET]) + ppath = data->set.str[STRING_TARGET]; + /* url */ if(paste_ftp_userpwd) result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s", @@ -2339,8 +2370,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) #if !defined(CURL_DISABLE_COOKIES) if(data->cookies || addcookies) { - struct Cookie *co=NULL; /* no cookies from start */ - int count=0; + struct Cookie *co = NULL; /* no cookies from start */ + int count = 0; if(data->cookies) { Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); @@ -2353,7 +2384,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } if(co) { - struct Cookie *store=co; + struct Cookie *store = co; /* now loop through all cookies that matched */ while(co) { if(co->value) { @@ -2407,117 +2438,79 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) switch(httpreq) { - case HTTPREQ_POST_FORM: - if(!http->sendit || conn->bits.authneg) { - /* nothing to post! */ - result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n"); - if(result) - return result; - - result = Curl_add_buffer_send(req_buffer, conn, - &data->info.request_size, 0, FIRSTSOCKET); - if(result) - failf(data, "Failed sending POST request"); - else - /* setup variables for the upcoming transfer */ - Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, - -1, NULL); - break; - } - - if(Curl_FormInit(&http->form, http->sendit)) { - failf(data, "Internal HTTP POST error!"); - return CURLE_HTTP_POST_ERROR; - } - - /* 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 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 = data->state.fread_func; - - /* Set the read function to read from the generated form data */ - data->state.fread_func = (curl_read_callback)Curl_FormReader; - data->state.in = &http->form; + case HTTPREQ_PUT: /* Let's PUT the data to the server! */ - http->sending = HTTPSEND_BODY; + if(conn->bits.authneg) + postsize = 0; + else + postsize = data->state.infilesize; - if(!data->req.upload_chunky && - !Curl_checkheaders(conn, "Content-Length:")) { + if((postsize != -1) && !data->req.upload_chunky && + (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T - "\r\n", http->postsize); + "\r\n", postsize); if(result) return result; } - result = expect100(data, conn, req_buffer); - if(result) - return result; - - { - - /* Get Content-Type: line from Curl_formpostheader. - */ - char *contentType; - size_t linelength=0; - contentType = Curl_formpostheader((void *)&http->form, - &linelength); - if(!contentType) { - failf(data, "Could not get Content-Type header line!"); - return CURLE_HTTP_POST_ERROR; - } - - result = Curl_add_buffer(req_buffer, contentType, linelength); + if(postsize != 0) { + result = expect100(data, conn, req_buffer); if(result) return result; } - /* make the request end in a true CRLF */ - result = Curl_add_buffer(req_buffer, "\r\n", 2); + result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */ if(result) return result; - /* set upload size to the progress meter */ - Curl_pgrsSetUploadSize(data, http->postsize); + /* set the upload size to the progress meter */ + Curl_pgrsSetUploadSize(data, postsize); - /* fire away the whole request to the server */ + /* this sends the buffer and frees all the buffer resources */ result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size, 0, FIRSTSOCKET); if(result) - failf(data, "Failed sending POST request"); + failf(data, "Failed sending PUT request"); else - /* setup variables for the upcoming transfer */ + /* prepare for transfer */ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, - &http->readbytecount, FIRSTSOCKET, - &http->writebytecount); - - if(result) { - Curl_formclean(&http->sendit); /* free that whole lot */ - return result; - } - - /* convert the form data */ - result = Curl_convert_form(data, http->sendit); - if(result) { - Curl_formclean(&http->sendit); /* free that whole lot */ + &http->readbytecount, postsize?FIRSTSOCKET:-1, + postsize?&http->writebytecount:NULL); + if(result) return result; - } - break; - case HTTPREQ_PUT: /* Let's PUT the data to the server! */ + case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: + /* This is form posting using mime data. */ + if(conn->bits.authneg) { + /* nothing to post! */ + result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n"); + if(result) + return result; - if(conn->bits.authneg) - postsize = 0; - else - postsize = data->state.infilesize; + result = Curl_add_buffer_send(req_buffer, conn, + &data->info.request_size, 0, FIRSTSOCKET); + if(result) + failf(data, "Failed sending POST request"); + else + /* setup variables for the upcoming transfer */ + Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount, + -1, NULL); + break; + } - if((postsize != -1) && !data->req.upload_chunky && + postsize = http->postsize; + + /* We only set Content-Length and allow a custom Content-Length if + we don't upload data chunked, as RFC2616 forbids us to set both + kinds of headers (Transfer-Encoding: chunked and Content-Length) */ + if(postsize != -1 && !data->req.upload_chunky && (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { - /* only add Content-Length if not uploading chunked */ + /* we allow replacing this header if not during auth negotiation, + although it isn't very wise to actually set your own */ result = Curl_add_bufferf(req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T "\r\n", postsize); @@ -2525,24 +2518,52 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - if(postsize != 0) { + /* Output mime-generated headers. */ + { + struct curl_slist *hdr; + + for(hdr = http->sendit->curlheaders; hdr; hdr = hdr->next) { + result = Curl_add_bufferf(req_buffer, "%s\r\n", hdr->data); + if(result) + return result; + } + } + + /* For really small posts we don't use Expect: headers at all, and for + the somewhat bigger ones we allow the app to disable it. Just make + sure that the expect100header is always set to the preferred value + here. */ + ptr = Curl_checkheaders(conn, "Expect:"); + if(ptr) { + data->state.expect100header = + Curl_compareheader(ptr, "Expect:", "100-continue"); + } + else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { result = expect100(data, conn, req_buffer); if(result) return result; } + else + data->state.expect100header = FALSE; - result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */ + /* make the request end in a true CRLF */ + result = Curl_add_buffer(req_buffer, "\r\n", 2); if(result) return result; /* set the upload size to the progress meter */ Curl_pgrsSetUploadSize(data, postsize); + /* Read from mime structure. */ + data->state.fread_func = (curl_read_callback) Curl_mime_read; + data->state.in = (void *) http->sendit; + http->sending = HTTPSEND_BODY; + /* this sends the buffer and frees all the buffer resources */ result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size, 0, FIRSTSOCKET); if(result) - failf(data, "Failed sending PUT request"); + failf(data, "Failed sending POST request"); else /* prepare for transfer */ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, @@ -2550,6 +2571,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize?&http->writebytecount:NULL); if(result) return result; + break; case HTTPREQ_POST: @@ -2592,7 +2614,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); } - else if(postsize > TINY_INITIAL_POST_SIZE || postsize < 0) { + else if(postsize > EXPECT_100_THRESHOLD || postsize < 0) { result = expect100(data, conn, req_buffer); if(result) return result; @@ -2606,7 +2628,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) its size. */ if(conn->httpversion != 20 && !data->state.expect100header && - (postsize < MAX_INITIAL_POST_SIZE)) { + (postsize < MAX_INITIAL_POST_SIZE)) { /* if we don't use expect: 100 AND postsize is less than MAX_INITIAL_POST_SIZE @@ -2771,7 +2793,7 @@ checkhttpprefix(struct Curl_easy *data, failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } - if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { + if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { /* Curl_convert_from_network calls failf if unsuccessful */ free(scratch); return FALSE; /* can't return CURLE_foobar so return FALSE */ @@ -2801,6 +2823,7 @@ static bool checkrtspprefix(struct Curl_easy *data, const char *s) { + bool result = FALSE; #ifdef CURL_DOES_CONVERSIONS /* convert from the network encoding using a scratch area */ @@ -2809,18 +2832,19 @@ checkrtspprefix(struct Curl_easy *data, failf(data, "Failed to allocate memory for conversion!"); return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */ } - if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) { + if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s) + 1)) { /* Curl_convert_from_network calls failf if unsuccessful */ - free(scratch); - return FALSE; /* can't return CURLE_foobar so return FALSE */ + result = FALSE; /* can't return CURLE_foobar so return FALSE */ } - s = scratch; + else + result = checkprefix("RTSP/", scratch)? TRUE: FALSE; + free(scratch); #else (void)data; /* unused */ + result = checkprefix("RTSP/", s)? TRUE: FALSE; #endif /* CURL_DOES_CONVERSIONS */ - if(checkprefix("RTSP/", s)) - return TRUE; - return FALSE; + + return result; } #endif /* CURL_DISABLE_RTSP */ @@ -2862,14 +2886,14 @@ static CURLcode header_append(struct Curl_easy *data, return CURLE_OUT_OF_MEMORY; } - newsize=CURLMAX((k->hbuflen+ length)*3/2, data->state.headersize*2); + newsize = CURLMAX((k->hbuflen + length) * 3 / 2, data->state.headersize*2); hbufp_index = k->hbufp - data->state.headerbuff; newbuff = realloc(data->state.headerbuff, newsize); if(!newbuff) { failf(data, "Failed to alloc memory for big header!"); return CURLE_OUT_OF_MEMORY; } - data->state.headersize=newsize; + data->state.headersize = newsize; data->state.headerbuff = newbuff; k->hbufp = data->state.headerbuff + hbufp_index; } @@ -2962,7 +2986,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } /* decrease the size of the remaining (supposed) header line */ - rest_length = (k->end_ptr - k->str)+1; + rest_length = (k->end_ptr - k->str) + 1; *nread -= (ssize_t)rest_length; k->str = k->end_ptr + 1; /* move past new line */ @@ -3161,6 +3185,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, case HTTPREQ_PUT: case HTTPREQ_POST: case HTTPREQ_POST_FORM: + case HTTPREQ_POST_MIME: /* We got an error response. If this happened before the whole * request body has been sent we stop sending and mark the * connection for closure after we've read the entire response. @@ -3288,7 +3313,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #define HEADER1 scratch #define SCRATCHSIZE 21 CURLcode res; - char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */ + char scratch[SCRATCHSIZE + 1]; /* "HTTP/major.minor 123" */ /* We can't really convert this yet because we don't know if it's the 1st header line or the body. So we do a partial conversion into a scratch area, @@ -3314,19 +3339,22 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * says. We try to allow any number here, but we cannot make * guarantees on future behaviors since it isn't within the protocol. */ + char separator; nc = sscanf(HEADER1, - " HTTP/%d.%d %d", + " HTTP/%1d.%1d%c%3d", &httpversion_major, &conn->httpversion, + &separator, &k->httpcode); if(nc == 1 && httpversion_major == 2 && 1 == sscanf(HEADER1, " HTTP/2 %d", &k->httpcode)) { conn->httpversion = 0; - nc = 3; + nc = 4; + separator = ' '; } - if(nc==3) { + if((nc == 4) && (' ' == separator)) { conn->httpversion += 10 * httpversion_major; if(k->upgr101 == UPGR101_RECEIVED) { @@ -3335,11 +3363,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, infof(data, "Lying server, not serving HTTP/2\n"); } } - else { + else if(!nc) { /* this is the real world, not a Nirvana NCSA 1.5.x returns this crap when asked for HTTP/1.1 */ - nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); + nc = sscanf(HEADER1, " HTTP %3d", &k->httpcode); conn->httpversion = 10; /* If user has set option HTTP200ALIASES, @@ -3353,6 +3381,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, } } } + else { + failf(data, "Unsupported HTTP version in response\n"); + return CURLE_UNSUPPORTED_PROTOCOL; + } } else if(conn->handler->protocol & CURLPROTO_RTSP) { nc = sscanf(HEADER1, @@ -3360,7 +3392,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, &rtspversion_major, &conn->rtspversion, &k->httpcode); - if(nc==3) { + if(nc == 3) { conn->rtspversion += 10 * rtspversion_major; conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */ } @@ -3392,7 +3424,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) { if(data->state.resume_from && - (data->set.httpreq==HTTPREQ_GET) && + (data->set.httpreq == HTTPREQ_GET) && (k->httpcode == 416)) { /* "Requested Range Not Satisfiable", just proceed and pretend this is no error */ @@ -3448,8 +3480,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, * fields. */ if(data->set.timecondition) data->info.timecond = TRUE; - k->size=0; - k->maxdownload=0; + k->size = 0; + k->maxdownload = 0; k->ignorecl = TRUE; /* ignore Content-Length headers */ break; default: @@ -3471,28 +3503,32 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* Check for Content-Length: header lines to get size */ if(!k->ignorecl && !data->set.ignorecl && checkprefix("Content-Length:", k->p)) { - curl_off_t contentlength = curlx_strtoofft(k->p+15, NULL, 10); - if(data->set.max_filesize && - contentlength > data->set.max_filesize) { - failf(data, "Maximum file size exceeded"); - return CURLE_FILESIZE_EXCEEDED; - } - if(contentlength >= 0) { - k->size = contentlength; - k->maxdownload = k->size; - /* we set the progress download size already at this point - just to make it easier for apps/callbacks to extract this - info as soon as possible */ - Curl_pgrsSetDownloadSize(data, k->size); - } - else { - /* Negative Content-Length is really odd, and we know it - happens for example when older Apache servers send large - files */ - streamclose(conn, "negative content-length"); - infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T - ", closing after transfer\n", contentlength); + curl_off_t contentlength; + if(!curlx_strtoofft(k->p + 15, NULL, 10, &contentlength)) { + if(data->set.max_filesize && + contentlength > data->set.max_filesize) { + failf(data, "Maximum file size exceeded"); + return CURLE_FILESIZE_EXCEEDED; + } + if(contentlength >= 0) { + k->size = contentlength; + k->maxdownload = k->size; + /* we set the progress download size already at this point + just to make it easier for apps/callbacks to extract this + info as soon as possible */ + Curl_pgrsSetDownloadSize(data, k->size); + } + else { + /* Negative Content-Length is really odd, and we know it + happens for example when older Apache servers send large + files */ + streamclose(conn, "negative content-length"); + infof(data, "Negative content-length: %" CURL_FORMAT_CURL_OFF_T + ", closing after transfer\n", contentlength); + } } + else + infof(data, "Illegal Content-Length: header\n"); } /* check for Content-Type: header lines to get the MIME-type */ else if(checkprefix("Content-Type:", k->p)) { @@ -3667,11 +3703,11 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, /* if it truly stopped on a digit */ if(ISDIGIT(*ptr)) { - k->offset = curlx_strtoofft(ptr, NULL, 10); - - if(data->state.resume_from == k->offset) - /* we asked for a resume and we got it */ - k->content_range = TRUE; + if(!curlx_strtoofft(ptr, NULL, 10, &k->offset)) { + if(data->state.resume_from == k->offset) + /* we asked for a resume and we got it */ + k->content_range = TRUE; + } } else data->state.resume_from = 0; /* get everything */ @@ -3682,7 +3718,7 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); Curl_cookie_add(data, - data->cookies, TRUE, k->p+11, + data->cookies, TRUE, k->p + 11, /* If there is a custom-set Host: name, use it here, or else use real peer host name. */ conn->allocptr.cookiehost? @@ -3693,8 +3729,8 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data, #endif else if(checkprefix("Last-Modified:", k->p) && (data->set.timecondition || data->set.get_filetime) ) { - time_t secs=time(NULL); - k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"), + time_t secs = time(NULL); + k->timeofdoc = curl_getdate(k->p + strlen("Last-Modified:"), &secs); if(data->set.get_filetime) data->info.filetime = (long)k->timeofdoc; |