diff options
author | Daniel Stenberg <daniel@haxx.se> | 2014-01-31 08:10:07 +0100 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2014-04-04 17:03:43 +0200 |
commit | ac887eedbc17a0d78b11ff467858c76a5127d1f4 (patch) | |
tree | 33f12aad12cd5eb43e1a5d069e1ecb2747e7e864 /lib | |
parent | 42937f87e65554ec4b887a5bd0b34abdbf2e0977 (diff) |
CURLOPT_PROXYHEADER: set headers for proxy-only
Includes docs and new test cases: 1525, 1526 and 1527
Co-written-by: Vijay Panghal
Diffstat (limited to 'lib')
-rw-r--r-- | lib/http.c | 84 | ||||
-rw-r--r-- | lib/http.h | 9 | ||||
-rw-r--r-- | lib/http_proxy.c | 8 | ||||
-rw-r--r-- | lib/rtsp.c | 26 | ||||
-rw-r--r-- | lib/url.c | 14 | ||||
-rw-r--r-- | lib/urldata.h | 1 |
6 files changed, 97 insertions, 45 deletions
diff --git a/lib/http.c b/lib/http.c index f803e58f8..c0cb4c069 100644 --- a/lib/http.c +++ b/lib/http.c @@ -169,12 +169,40 @@ CURLcode Curl_http_setup_conn(struct connectdata *conn) * * Returns a pointer to the first matching header or NULL if none matched. */ -char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader) +char *Curl_checkheaders(const struct connectdata *conn, + const char *thisheader) { struct curl_slist *head; size_t thislen = strlen(thisheader); + struct SessionHandle *data = conn->data; + + for(head = data->set.headers;head; head=head->next) { + if(Curl_raw_nequal(head->data, thisheader, thislen)) + return head->data; + } + return NULL; +} + +/* + * checkProxyHeaders() checks the linked list of custom proxy headers + * 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 SessionHandle simply + * to know if this is a proxy request or not, as it then might check a + * different header list. + * + */ +char *Curl_checkProxyheaders(const struct connectdata *conn, + const char *thisheader) +{ + struct curl_slist *head; + size_t thislen = strlen(thisheader); + struct SessionHandle *data = conn->data; - for(head = data->set.headers; head; head=head->next) { + for(head = (conn->bits.proxy && data->set.proxyheaders)? + data->set.proxyheaders:data->set.headers; + head; head=head->next) { if(Curl_raw_nequal(head->data, thisheader, thislen)) return head->data; } @@ -584,9 +612,9 @@ output_auth_headers(struct connectdata *conn, if(authstatus->picked == CURLAUTH_BASIC) { /* Basic */ if((proxy && conn->bits.proxy_user_passwd && - !Curl_checkheaders(data, "Proxy-authorization:")) || + !Curl_checkProxyheaders(conn, "Proxy-authorization:")) || (!proxy && conn->bits.user_passwd && - !Curl_checkheaders(data, "Authorization:"))) { + !Curl_checkheaders(conn, "Authorization:"))) { auth="Basic"; result = http_output_basic(conn, proxy); if(result) @@ -1501,7 +1529,7 @@ static CURLcode expect100(struct SessionHandle *data, /* 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) */ - ptr = Curl_checkheaders(data, "Expect:"); + ptr = Curl_checkheaders(conn, "Expect:"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); @@ -1517,10 +1545,13 @@ static CURLcode expect100(struct SessionHandle *data, } CURLcode Curl_add_custom_headers(struct connectdata *conn, - Curl_send_buffer *req_buffer) + bool is_proxy, + Curl_send_buffer *req_buffer) { char *ptr; - struct curl_slist *headers=conn->data->set.headers; + struct curl_slist *headers= + (is_proxy && conn->data->set.proxyheaders)? + conn->data->set.proxyheaders:conn->data->set.headers; while(headers) { ptr = strchr(headers->data, ':'); @@ -1736,7 +1767,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(data, "User-Agent:") && conn->allocptr.uagent) { + if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) { free(conn->allocptr.uagent); conn->allocptr.uagent=NULL; } @@ -1757,7 +1788,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->bits.authneg = FALSE; Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !Curl_checkheaders(data, "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; @@ -1765,10 +1796,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else conn->allocptr.ref = NULL; - if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, "Cookie:")) + if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(conn, "Cookie:")) addcookies = data->set.str[STRING_COOKIE]; - if(!Curl_checkheaders(data, "Accept-Encoding:") && + if(!Curl_checkheaders(conn, "Accept-Encoding:") && data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = @@ -1780,13 +1811,14 @@ 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(data, "TE:") && data->set.http_transfer_encoding) { + 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(data, "Connection:"); + char *cptr = Curl_checkheaders(conn, "Connection:"); #define TE_HEADER "TE: gzip\r\n" Curl_safefree(conn->allocptr.te); @@ -1804,7 +1836,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* In HTTP2 forbids Transfer-Encoding: chunked */ ptr = NULL; else { - ptr = Curl_checkheaders(data, "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 = @@ -1838,7 +1870,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_safefree(conn->allocptr.host); - ptr = Curl_checkheaders(data, "Host:"); + ptr = Curl_checkheaders(conn, "Host:"); if(ptr && (!data->state.this_is_a_follow || Curl_raw_equal(data->state.first_host, conn->host.name))) { #if !defined(CURL_DISABLE_COOKIES) @@ -1983,13 +2015,13 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* 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(data, "Content-Type:"), + Curl_checkheaders(conn, "Content-Type:"), &http->postsize); if(result) return result; } - http->p_accept = Curl_checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n"; + http->p_accept = Curl_checkheaders(conn, "Accept:")?NULL:"Accept: */*\r\n"; if(( (HTTPREQ_POST == httpreq) || (HTTPREQ_POST_FORM == httpreq) || @@ -2069,7 +2101,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * ones if any such are specified. */ if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && - !Curl_checkheaders(data, "Range:")) { + !Curl_checkheaders(conn, "Range:")) { /* if a line like this was already allocated, free the previous one */ if(conn->allocptr.rangeline) free(conn->allocptr.rangeline); @@ -2077,7 +2109,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->state.range); } else if((httpreq != HTTPREQ_GET) && - !Curl_checkheaders(data, "Content-Range:")) { + !Curl_checkheaders(conn, "Content-Range:")) { /* if a line like this was already allocated, free the previous one */ if(conn->allocptr.rangeline) @@ -2179,7 +2211,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.ref:"" /* Referer: <data> */, (conn->bits.httpproxy && !conn->bits.tunnel_proxy && - !Curl_checkheaders(data, "Proxy-Connection:"))? + !Curl_checkProxyheaders(conn, "Proxy-Connection:"))? "Proxy-Connection: Keep-Alive\r\n":"", te ); @@ -2264,7 +2296,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - result = Curl_add_custom_headers(conn, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, req_buffer); if(result) return result; @@ -2314,7 +2346,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; if(!data->req.upload_chunky && - !Curl_checkheaders(data, "Content-Length:")) { + !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 @@ -2386,7 +2418,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) postsize = data->set.infilesize; if((postsize != -1) && !data->req.upload_chunky && - !Curl_checkheaders(data, "Content-Length:")) { + !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 @@ -2438,7 +2470,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 && - !Curl_checkheaders(data, "Content-Length:")) { + !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, @@ -2448,7 +2480,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - if(!Curl_checkheaders(data, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type:")) { result = Curl_add_bufferf(req_buffer, "Content-Type: application/" "x-www-form-urlencoded\r\n"); @@ -2460,7 +2492,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(data, "Expect:"); + ptr = Curl_checkheaders(conn, "Expect:"); if(ptr) { data->state.expect100header = Curl_compareheader(ptr, "Expect:", "100-continue"); diff --git a/lib/http.h b/lib/http.h index 407f7b621..7cf183101 100644 --- a/lib/http.h +++ b/lib/http.h @@ -39,9 +39,13 @@ extern const struct Curl_handler Curl_handler_https; bool Curl_compareheader(const char *headerline, /* line to check */ const char *header, /* header keyword _with_ colon */ const char *content); /* content string to find */ -char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader); + +char *Curl_checkheaders(const struct connectdata *conn, + const char *thisheader); char *Curl_copy_header_value(const char *header); +char *Curl_checkProxyheaders(const struct connectdata *conn, + const char *thisheader); /* ------------------------------------------------------------------------- */ /* * The add_buffer series of functions are used to build one large memory chunk @@ -67,7 +71,8 @@ CURLcode Curl_add_buffer_send(Curl_send_buffer *in, CURLcode Curl_add_timecondition(struct SessionHandle *data, Curl_send_buffer *buf); CURLcode Curl_add_custom_headers(struct connectdata *conn, - Curl_send_buffer *req_buffer); + bool is_connect, + Curl_send_buffer *req_buffer); /* protocol-specific functions set up to be called by the main engine */ CURLcode Curl_http(struct connectdata *conn, bool *done); diff --git a/lib/http_proxy.c b/lib/http_proxy.c index adcfe42dd..0ee1a73d5 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -165,7 +165,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - if(!Curl_checkheaders(data, "Host:")) { + if(!Curl_checkProxyheaders(conn, "Host:")) { host = aprintf("Host: %s\r\n", hostheader); if(!host) { free(hostheader); @@ -173,10 +173,10 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } } - if(!Curl_checkheaders(data, "Proxy-Connection:")) + if(!Curl_checkProxyheaders(conn, "Proxy-Connection:")) proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - if(!Curl_checkheaders(data, "User-Agent:") && + if(!Curl_checkProxyheaders(conn, "User-Agent:") && data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; @@ -200,7 +200,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, free(hostheader); if(CURLE_OK == result) - result = Curl_add_custom_headers(conn, req_buffer); + result = Curl_add_custom_headers(conn, TRUE, req_buffer); if(CURLE_OK == result) /* CRLF terminate the request */ diff --git a/lib/rtsp.c b/lib/rtsp.c index 5cd6cb467..e746fb1b1 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -341,7 +341,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } /* Transport Header for SETUP requests */ - p_transport = Curl_checkheaders(data, "Transport:"); + p_transport = Curl_checkheaders(conn, "Transport:"); if(rtspreq == RTSPREQ_SETUP && !p_transport) { /* New Transport: setting? */ if(data->set.str[STRING_RTSP_TRANSPORT]) { @@ -365,11 +365,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(data, "Accept:")? + p_accept = Curl_checkheaders(conn, "Accept:")? NULL:"Accept: application/sdp\r\n"; /* Accept-Encoding header */ - if(!Curl_checkheaders(data, "Accept-Encoding:") && + if(!Curl_checkheaders(conn, "Accept-Encoding:") && data->set.str[STRING_ENCODING]) { Curl_safefree(conn->allocptr.accept_encoding); conn->allocptr.accept_encoding = @@ -386,18 +386,18 @@ 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(data, "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(data, "User-Agent:") && + else if(!Curl_checkheaders(conn, "User-Agent:") && data->set.str[STRING_USERAGENT]) { p_uagent = conn->allocptr.uagent; } /* Referrer */ Curl_safefree(conn->allocptr.ref); - if(data->change.referer && !Curl_checkheaders(data, "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; @@ -414,7 +414,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(data, "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; @@ -424,11 +424,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) /* * Sanity check the custom headers */ - if(Curl_checkheaders(data, "CSeq:")) { + if(Curl_checkheaders(conn, "CSeq:")) { failf(data, "CSeq cannot be set as a custom header."); return CURLE_RTSP_CSEQ_ERROR; } - if(Curl_checkheaders(data, "Session:")) { + if(Curl_checkheaders(conn, "Session:")) { failf(data, "Session ID cannot be set as a custom header."); return CURLE_BAD_FUNCTION_ARGUMENT; } @@ -484,7 +484,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) return result; } - result = Curl_add_custom_headers(conn, req_buffer); + result = Curl_add_custom_headers(conn, FALSE, req_buffer); if(result) return result; @@ -507,7 +507,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(data, "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)); @@ -517,7 +517,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) if(rtspreq == RTSPREQ_SET_PARAMETER || rtspreq == RTSPREQ_GET_PARAMETER) { - if(!Curl_checkheaders(data, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type:")) { result = Curl_add_bufferf(req_buffer, "Content-Type: text/parameters\r\n"); if(result) @@ -526,7 +526,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) } if(rtspreq == RTSPREQ_ANNOUNCE) { - if(!Curl_checkheaders(data, "Content-Type:")) { + if(!Curl_checkheaders(conn, "Content-Type:")) { result = Curl_add_bufferf(req_buffer, "Content-Type: application/sdp\r\n"); if(result) @@ -1067,6 +1067,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.headers = va_arg(param, struct curl_slist *); break; + case CURLOPT_PROXYHEADER: + /* + * Set a list with proxy headers to use (or replace internals with) + * + * Since CURLOPT_HTTPHEADER was the only way to set HTTP headers for a + * long time we remain doing it this way until CURLOPT_PROXYHEADER is + * used. As soon as this option has been used, if set to anything but + * NULL, custom headers for proxies are only picked from this list. + * + * Set this option to NULL to restore the previous behavior. + */ + data->set.proxyheaders = va_arg(param, struct curl_slist *); + break; + case CURLOPT_HTTP200ALIASES: /* * Set a list of aliases for HTTP 200 in response header diff --git a/lib/urldata.h b/lib/urldata.h index b24562a4d..fd13eb981 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -1465,6 +1465,7 @@ struct UserDefined { download */ curl_off_t set_resume_from; /* continue [ftp] transfer from here */ struct curl_slist *headers; /* linked list of extra headers */ + struct curl_slist *proxyheaders; /* linked list of extra CONNECT headers */ struct curl_httppost *httppost; /* linked list of POST data */ bool cookiesession; /* new cookie session? */ bool crlf; /* convert crlf on ftp upload(?) */ |