diff options
author | Daniel Stenberg <daniel@haxx.se> | 2018-03-05 23:38:16 +0100 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2018-03-11 11:46:10 +0100 |
commit | 8123560d4496992baecc0c7a05e56ce48e6b6273 (patch) | |
tree | 5597389e87043f3fd82d84334a61d690784d8c53 /lib | |
parent | 019aa722aa82e8642254f3e835992bc425ed3e19 (diff) |
HTTP: allow "header;" to replace an internal header with a blank one
Reported-by: Michael Kaufmann
Fixes #2357
Closes #2362
Diffstat (limited to 'lib')
-rw-r--r-- | lib/http.c | 134 | ||||
-rw-r--r-- | lib/http_proxy.c | 8 | ||||
-rw-r--r-- | lib/rtsp.c | 26 | ||||
-rw-r--r-- | lib/transfer.c | 7 | ||||
-rw-r--r-- | lib/transfer.h | 3 |
5 files changed, 93 insertions, 85 deletions
diff --git a/lib/http.c b/lib/http.c index c1c7b3908..841f6cc0b 100644 --- a/lib/http.c +++ b/lib/http.c @@ -177,9 +177,9 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn) * if proxy headers are not available, then it will lookup into http header * link list * - * It takes a connectdata struct as input instead of the Curl_easy simply - * to know if this is a proxy request or not, as it then might check a - * different header list. + * It takes a connectdata struct as input instead of the Curl_easy simply to + * know if this is a proxy request or not, as it then might check a different + * header list. Provide the header prefix without colon!. */ char *Curl_checkProxyheaders(const struct connectdata *conn, const char *thisheader) @@ -191,7 +191,8 @@ 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) { - if(strncasecompare(head->data, thisheader, thislen)) + if(strncasecompare(head->data, thisheader, thislen) && + Curl_headersep(head->data[thislen])) return head->data; } @@ -614,9 +615,9 @@ output_auth_headers(struct connectdata *conn, if(authstatus->picked == CURLAUTH_BASIC) { /* Basic */ if((proxy && conn->bits.proxy_user_passwd && - !Curl_checkProxyheaders(conn, "Proxy-authorization:")) || + !Curl_checkProxyheaders(conn, "Proxy-authorization")) || (!proxy && conn->bits.user_passwd && - !Curl_checkheaders(conn, "Authorization:"))) { + !Curl_checkheaders(conn, "Authorization"))) { auth = "Basic"; result = http_output_basic(conn, proxy); if(result) @@ -1533,7 +1534,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:"); + ptr = Curl_checkheaders(conn, "Expect"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); @@ -1598,7 +1599,32 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, headers = h[i]; while(headers) { + char *semicolonp = NULL; ptr = strchr(headers->data, ':'); + if(!ptr) { + char *optr; + /* no colon, semicolon? */ + ptr = strchr(headers->data, ';'); + if(ptr) { + optr = ptr; + ptr++; /* pass the semicolon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* this may be used for something else in the future */ + optr = NULL; + } + else { + if(*(--ptr) == ';') { + /* send no-value custom header if terminated by semicolon */ + *ptr = ':'; + semicolonp = ptr; + } + } + ptr = optr; + } + } if(ptr) { /* we require a colon for this to be a true header */ @@ -1606,8 +1632,9 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, while(*ptr && ISSPACE(*ptr)) ptr++; - if(*ptr) { - /* only send this if the contents was non-blank */ + if(*ptr || semicolonp) { + /* only send this if the contents was non-blank or done special */ + CURLcode result = CURLE_OK; if(conn->allocptr.host && /* a Host: header was sent already, don't pass on any custom Host: @@ -1645,40 +1672,12 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, !strcasecompare(data->state.first_host, conn->host.name))) ; else { - CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n", - headers->data); - if(result) - return result; - } - } - } - else { - ptr = strchr(headers->data, ';'); - if(ptr) { - - ptr++; /* pass the semicolon */ - while(*ptr && ISSPACE(*ptr)) - ptr++; - - if(*ptr) { - /* this may be used for something else in the future */ - } - else { - if(*(--ptr) == ';') { - CURLcode result; - - /* send no-value custom header if terminated by semicolon */ - *ptr = ':'; - result = Curl_add_bufferf(req_buffer, "%s\r\n", - headers->data); - - /* restore the previous value */ - *ptr = ';'; - - if(result) - return result; - } + result = Curl_add_bufferf(req_buffer, "%s\r\n", headers->data); } + if(semicolonp) + *semicolonp = ';'; /* put back the semicolon */ + if(result) + return result; } } headers = headers->next; @@ -1869,7 +1868,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:")) { + if(Curl_checkheaders(conn, "User-Agent")) { free(conn->allocptr.uagent); conn->allocptr.uagent = NULL; } @@ -1890,7 +1889,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->bits.authneg = FALSE; Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) { + if(data->change.referer && !Curl_checkheaders(conn, "Referer")) { conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); if(!conn->allocptr.ref) return CURLE_OUT_OF_MEMORY; @@ -1899,11 +1898,11 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.ref = NULL; #if !defined(CURL_DISABLE_COOKIES) - if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie:")) + if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie")) addcookies = data->set.str[STRING_COOKIE]; #endif - if(!Curl_checkheaders(conn, "Accept-Encoding:") && + if(!Curl_checkheaders(conn, "Accept-Encoding") && data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = @@ -1919,22 +1918,29 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) #ifdef HAVE_LIBZ /* we only consider transfer-encoding magic if libz support is built-in */ - if(!Curl_checkheaders(conn, "TE:") && + if(!Curl_checkheaders(conn, "TE") && data->set.http_transfer_encoding) { /* When we are to insert a TE: header in the request, we must also insert TE in a Connection: header, so we need to merge the custom provided Connection: header and prevent the original to get sent. Note that if the user has inserted his/hers own TE: header we don't do this magic but then assume that the user will handle it all! */ - char *cptr = Curl_checkheaders(conn, "Connection:"); + char *cptr = Curl_checkheaders(conn, "Connection"); #define TE_HEADER "TE: gzip\r\n" Curl_safefree(conn->allocptr.te); + if(cptr) { + cptr = Curl_copy_header_value(cptr); + if(!cptr) + return CURLE_OUT_OF_MEMORY; + } + /* Create the (updated) Connection: header */ - conn->allocptr.te = cptr? aprintf("%s, TE\r\n" TE_HEADER, cptr): - strdup("Connection: TE\r\n" TE_HEADER); + conn->allocptr.te = aprintf("Connection: %s%sTE\r\n" TE_HEADER, + cptr ? cptr : "", (cptr && *cptr) ? ", ":""); + free(cptr); if(!conn->allocptr.te) return CURLE_OUT_OF_MEMORY; } @@ -1958,7 +1964,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } if(http->sendit) { - const char *cthdr = Curl_checkheaders(conn, "Content-Type:"); + const char *cthdr = Curl_checkheaders(conn, "Content-Type"); /* Read and seek body only. */ http->sendit->flags |= MIME_BODY_ONLY; @@ -1982,7 +1988,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->postsize = Curl_mime_size(http->sendit); } - ptr = Curl_checkheaders(conn, "Transfer-Encoding:"); + ptr = Curl_checkheaders(conn, "Transfer-Encoding"); if(ptr) { /* Some kind of TE is requested, check if 'chunked' is chosen */ data->req.upload_chunky = @@ -2016,7 +2022,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_safefree(conn->allocptr.host); - ptr = Curl_checkheaders(conn, "Host:"); + ptr = Curl_checkheaders(conn, "Host"); if(ptr && (!data->state.this_is_a_follow || strcasecompare(data->state.first_host, conn->host.name))) { #if !defined(CURL_DISABLE_COOKIES) @@ -2055,7 +2061,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) #endif if(strcmp("Host:", ptr)) { - conn->allocptr.host = aprintf("%s\r\n", ptr); + conn->allocptr.host = aprintf("Host:%s\r\n", &ptr[5]); if(!conn->allocptr.host) return CURLE_OUT_OF_MEMORY; } @@ -2164,7 +2170,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } #endif /* CURL_DISABLE_PROXY */ - http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n"; + http->p_accept = Curl_checkheaders(conn, "Accept")?NULL:"Accept: */*\r\n"; if((HTTPREQ_POST == httpreq || HTTPREQ_PUT == httpreq) && data->state.resume_from) { @@ -2245,14 +2251,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * ones if any such are specified. */ if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && - !Curl_checkheaders(conn, "Range:")) { + !Curl_checkheaders(conn, "Range")) { /* if a line like this was already allocated, free the previous one */ free(conn->allocptr.rangeline); conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n", data->state.range); } else if((httpreq == HTTPREQ_POST || httpreq == HTTPREQ_PUT) && - !Curl_checkheaders(conn, "Content-Range:")) { + !Curl_checkheaders(conn, "Content-Range")) { /* if a line like this was already allocated, free the previous one */ free(conn->allocptr.rangeline); @@ -2354,7 +2360,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.ref:"" /* Referer: <data> */, (conn->bits.httpproxy && !conn->bits.tunnel_proxy && - !Curl_checkProxyheaders(conn, "Proxy-Connection:"))? + !Curl_checkProxyheaders(conn, "Proxy-Connection"))? "Proxy-Connection: Keep-Alive\r\n":"", te ); @@ -2455,7 +2461,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize = data->state.infilesize; if((postsize != -1) && !data->req.upload_chunky && - (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length:"))) { + (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 @@ -2517,7 +2523,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) 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:"))) { + (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* 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, @@ -2542,7 +2548,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) 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:"); + ptr = Curl_checkheaders(conn, "Expect"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); @@ -2596,7 +2602,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) 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:"))) { + (conn->bits.authneg || !Curl_checkheaders(conn, "Content-Length"))) { /* 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, @@ -2606,7 +2612,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - if(!Curl_checkheaders(conn, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type")) { result = Curl_add_bufferf(req_buffer, "Content-Type: application/" "x-www-form-urlencoded\r\n"); @@ -2618,7 +2624,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) 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:"); + ptr = Curl_checkheaders(conn, "Expect"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 7f5040543..c1eb177dd 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, 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 @@ -252,7 +252,7 @@ static CURLcode CONNECT(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - if(!Curl_checkProxyheaders(conn, "Host:")) { + if(!Curl_checkProxyheaders(conn, "Host")) { host = aprintf("Host: %s\r\n", hostheader); if(!host) { free(hostheader); @@ -260,10 +260,10 @@ static CURLcode CONNECT(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } } - if(!Curl_checkProxyheaders(conn, "Proxy-Connection:")) + if(!Curl_checkProxyheaders(conn, "Proxy-Connection")) proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - if(!Curl_checkProxyheaders(conn, "User-Agent:") && + if(!Curl_checkProxyheaders(conn, "User-Agent") && data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; diff --git a/lib/rtsp.c b/lib/rtsp.c index c60697290..194bc949e 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, 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 @@ -357,7 +357,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } /* Transport Header for SETUP requests */ - p_transport = Curl_checkheaders(conn, "Transport:"); + p_transport = Curl_checkheaders(conn, "Transport"); if(rtspreq == RTSPREQ_SETUP && !p_transport) { /* New Transport: setting? */ if(data->set.str[STRING_RTSP_TRANSPORT]) { @@ -381,11 +381,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* Accept Headers for DESCRIBE requests */ if(rtspreq == RTSPREQ_DESCRIBE) { /* Accept Header */ - p_accept = Curl_checkheaders(conn, "Accept:")? + p_accept = Curl_checkheaders(conn, "Accept")? NULL:"Accept: application/sdp\r\n"; /* Accept-Encoding header */ - if(!Curl_checkheaders(conn, "Accept-Encoding:") && + if(!Curl_checkheaders(conn, "Accept-Encoding") && data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = @@ -402,11 +402,11 @@ static CURLcode rtsp_do(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") && conn->allocptr.uagent) { Curl_safefree(conn->allocptr.uagent); conn->allocptr.uagent = NULL; } - else if(!Curl_checkheaders(conn, "User-Agent:") && + else if(!Curl_checkheaders(conn, "User-Agent") && data->set.str[STRING_USERAGENT]) { p_uagent = conn->allocptr.uagent; } @@ -421,7 +421,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* Referrer */ Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !Curl_checkheaders(conn, "Referer:")) + if(data->change.referer && !Curl_checkheaders(conn, "Referer")) conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer); else conn->allocptr.ref = NULL; @@ -438,7 +438,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) { /* Check to see if there is a range set in the custom headers */ - if(!Curl_checkheaders(conn, "Range:") && data->state.range) { + if(!Curl_checkheaders(conn, "Range") && data->state.range) { Curl_safefree(conn->allocptr.rangeline); conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range); p_range = conn->allocptr.rangeline; @@ -448,11 +448,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* * Sanity check the custom headers */ - if(Curl_checkheaders(conn, "CSeq:")) { + if(Curl_checkheaders(conn, "CSeq")) { failf(data, "CSeq cannot be set as a custom header."); return CURLE_RTSP_CSEQ_ERROR; } - if(Curl_checkheaders(conn, "Session:")) { + if(Curl_checkheaders(conn, "Session")) { failf(data, "Session ID cannot be set as a custom header."); return CURLE_BAD_FUNCTION_ARGUMENT; } @@ -542,7 +542,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(putsize > 0 || postsize > 0) { /* As stated in the http comments, it is probably not wise to * actually set a custom Content-Length in the headers */ - if(!Curl_checkheaders(conn, "Content-Length:")) { + if(!Curl_checkheaders(conn, "Content-Length")) { result = Curl_add_bufferf(req_buffer, "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", (data->set.upload ? putsize : postsize)); @@ -552,7 +552,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { - if(!Curl_checkheaders(conn, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type")) { result = Curl_add_bufferf(req_buffer, "Content-Type: text/parameters\r\n"); if(result) @@ -561,7 +561,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } if(rtspreq == RTSPREQ_ANNOUNCE) { - if(!Curl_checkheaders(conn, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type")) { result = Curl_add_bufferf(req_buffer, "Content-Type: application/sdp\r\n"); if(result) diff --git a/lib/transfer.c b/lib/transfer.c index e27792c10..c46ac25f4 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, 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 @@ -85,7 +85,7 @@ !defined(CURL_DISABLE_IMAP) /* * checkheaders() checks the linked list of custom headers for a - * particular header (prefix). + * particular header (prefix). Provide the prefix without colon! * * Returns a pointer to the first matching header or NULL if none matched. */ @@ -97,7 +97,8 @@ char *Curl_checkheaders(const struct connectdata *conn, struct Curl_easy *data = conn->data; for(head = data->set.headers; head; head = head->next) { - if(strncasecompare(head->data, thisheader, thislen)) + if(strncasecompare(head->data, thisheader, thislen) && + Curl_headersep(head->data[thislen]) ) return head->data; } diff --git a/lib/transfer.h b/lib/transfer.h index 72526a834..9ba398d27 100644 --- a/lib/transfer.h +++ b/lib/transfer.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2017, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2018, 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 @@ -22,6 +22,7 @@ * ***************************************************************************/ +#define Curl_headersep(x) ((((x)==':') || ((x)==';'))) char *Curl_checkheaders(const struct connectdata *conn, const char *thisheader); |