aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2014-01-31 08:10:07 +0100
committerDaniel Stenberg <daniel@haxx.se>2014-04-04 17:03:43 +0200
commitac887eedbc17a0d78b11ff467858c76a5127d1f4 (patch)
tree33f12aad12cd5eb43e1a5d069e1ecb2747e7e864
parent42937f87e65554ec4b887a5bd0b34abdbf2e0977 (diff)
CURLOPT_PROXYHEADER: set headers for proxy-only
Includes docs and new test cases: 1525, 1526 and 1527 Co-written-by: Vijay Panghal
-rw-r--r--docs/libcurl/curl_easy_setopt.327
-rw-r--r--docs/libcurl/symbols-in-versions1
-rw-r--r--include/curl/curl.h9
-rw-r--r--lib/http.c84
-rw-r--r--lib/http.h9
-rw-r--r--lib/http_proxy.c8
-rw-r--r--lib/rtsp.c26
-rw-r--r--lib/url.c14
-rw-r--r--lib/urldata.h1
-rw-r--r--tests/data/Makefile.am2
-rw-r--r--tests/data/test152576
-rw-r--r--tests/data/test152676
-rw-r--r--tests/data/test152776
-rw-r--r--tests/libtest/Makefile.inc16
-rw-r--r--tests/libtest/lib1525.c96
-rw-r--r--tests/libtest/lib1526.c99
-rw-r--r--tests/libtest/lib1527.c95
17 files changed, 667 insertions, 48 deletions
diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3
index 5422bca8f..bda293576 100644
--- a/docs/libcurl/curl_easy_setopt.3
+++ b/docs/libcurl/curl_easy_setopt.3
@@ -1541,6 +1541,33 @@ Pass a NULL to this to reset back to no custom headers.
The most commonly replaced headers have "shortcuts" in the options
\fICURLOPT_COOKIE\fP, \fICURLOPT_USERAGENT\fP and \fICURLOPT_REFERER\fP.
+
+Starting in 7.36.0, libcurl offers an alternative option that sets or replaces
+headers only for requests that are sent to a proxy:
+\fICURLOPT_PROXYHEADER\fP. If \fICURLOPT_PROXYHEADER\fP is not used at all by
+an application, the \fICURLOPT_HTTPHEADER headers\fP will be used for proxy
+requests as well!
+.IP CURLOPT_PROXYHEADER
+Pass a pointer to a linked list of HTTP headers to pass in your HTTP request
+sent to a proxy. The rules for this list is identical to the
+\fICURLOPT_HTTPHEADER\fP option's.
+
+The headers set with this option is only ever used in requests sent to a
+proxy.
+
+As a special quirk to stay backwards compatible with the libcurl versions
+released before this option existed, all headers set with
+\fICURLOPT_HTTPHEADER\fP will also be used for proxies unless you set one or
+more headers (or even just NULL) with \fICURLOPT_PROXYHEADER\fP.
+
+The first line in a request (containing the method, usually a GET or POST) is
+not a header and cannot be replaced using this option. Only the lines
+following the request-line are headers. Adding this method line in this list
+of headers will only cause your request to send an invalid header.
+
+Pass a NULL to this to reset back to no custom headers.
+
+This option was added in libcurl 7.36.0.
.IP CURLOPT_HTTP200ALIASES
Pass a pointer to a linked list of aliases to be treated as valid HTTP 200
responses. Some servers respond with a custom header response line. For
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index 2e9fc4da0..925e47923 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -439,6 +439,7 @@ CURLOPT_PROGRESSFUNCTION 7.1 7.32.0
CURLOPT_PROTOCOLS 7.19.4
CURLOPT_PROXY 7.1
CURLOPT_PROXYAUTH 7.10.7
+CURLOPT_PROXYHEADER 7.36.0
CURLOPT_PROXYPASSWORD 7.19.1
CURLOPT_PROXYPORT 7.1
CURLOPT_PROXYTYPE 7.10
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 8038d8d25..efdd2e842 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2014, 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
@@ -903,7 +903,8 @@ typedef enum {
/* Set cookie in request: */
CINIT(COOKIE, OBJECTPOINT, 22),
- /* This points to a linked list of headers, struct curl_slist kind */
+ /* This points to a linked list of headers, struct curl_slist kind. This
+ list is also used for RTSP (in spite of its name) */
CINIT(HTTPHEADER, OBJECTPOINT, 23),
/* This points to a linked list of post entries, struct curl_httppost */
@@ -1581,6 +1582,10 @@ typedef enum {
* Expect: 100-continue header before sending the data anyway. */
CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227),
+ /* This points to a linked list of headers used for proxy requests only,
+ struct curl_slist kind */
+ CINIT(PROXYHEADER, OBJECTPOINT, 228),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
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)
diff --git a/lib/url.c b/lib/url.c
index ebd38ccee..25bb04115 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -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(?) */
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 5c520c4f6..82c7fa123 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -127,6 +127,8 @@ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
test1516 \
\
+test1525 test1526 test1527 \
+\
test1900 test1901 test1902 test1903 \
\
test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \
diff --git a/tests/data/test1525 b/tests/data/test1525
new file mode 100644
index 000000000..13e0d1489
--- /dev/null
+++ b/tests/data/test1525
@@ -0,0 +1,76 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP CONNECT
+HTTP proxy
+proxytunnel
+CURLOPT_PROXYHEADER
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 200 OK
+Content-Length: 17
+
+</connect>
+<data>
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</data>
+<datacheck>
+HTTP/1.1 200 OK
+Content-Length: 17
+
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</datacheck>
+
+</reply>
+# Client-side
+<client>
+<server>
+http
+http-proxy
+</server>
+<tool>
+lib1525
+</tool>
+ <name>
+CURLOPT_PROXYHEADER: same headers for host and proxy
+ </name>
+ <command>
+ http://the.old.moo.1525:%HTTPPORT/1525 %HOSTIP:%PROXYPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<proxy>
+CONNECT the.old.moo.1525:%HTTPPORT HTTP/1.1
+Host: the.old.moo.1525:%HTTPPORT
+Proxy-Connection: Keep-Alive
+User-Agent: Http Agent
+
+</proxy>
+<protocol>
+PUT /1525 HTTP/1.1
+Host: the.old.moo.1525:%HTTPPORT
+Accept: */*
+User-Agent: Http Agent
+Content-Length: 13
+Expect: 100-continue
+
+Hello Cloud!
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test1526 b/tests/data/test1526
new file mode 100644
index 000000000..aa111c890
--- /dev/null
+++ b/tests/data/test1526
@@ -0,0 +1,76 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP CONNECT
+HTTP proxy
+proxytunnel
+CURLOPT_PROXYHEADER
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 200 OK
+Server: present
+
+</connect>
+<data>
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</data>
+<datacheck>
+HTTP/1.1 200 OK
+Server: present
+
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+http-proxy
+</server>
+<tool>
+lib1526
+</tool>
+ <name>
+CURLOPT_PROXYHEADER: separate host/proxy headers
+ </name>
+ <command>
+ http://the.old.moo.1526:%HTTPPORT/1526 %HOSTIP:%PROXYPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<proxy>
+CONNECT the.old.moo.1526:%HTTPPORT HTTP/1.1
+Host: the.old.moo.1526:%HTTPPORT
+Proxy-Connection: Keep-Alive
+User-Agent: Proxy Agent
+
+</proxy>
+<protocol>
+PUT /1526 HTTP/1.1
+Host: the.old.moo.1526:%HTTPPORT
+Accept: */*
+User-Agent: Http Agent
+Content-Length: 13
+Expect: 100-continue
+
+Hello Cloud!
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test1527 b/tests/data/test1527
new file mode 100644
index 000000000..ee4887ac5
--- /dev/null
+++ b/tests/data/test1527
@@ -0,0 +1,76 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP CONNECT
+HTTP proxy
+proxytunnel
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<connect>
+HTTP/1.1 200 OK
+We-are: good
+
+</connect>
+<data>
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</data>
+<datacheck>
+HTTP/1.1 200 OK
+We-are: good
+
+HTTP/1.1 200 OK swsclose
+Date: Thu, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
+ETag: "21025-dc7-39462498"
+</datacheck>
+
+</reply>
+# Client-side
+<client>
+<server>
+http
+http-proxy
+</server>
+<tool>
+lib1527
+</tool>
+ <name>
+Check same headers are generated without CURLOPT_PROXYHEADER
+ </name>
+ <command>
+ http://the.old.moo.1527:%HTTPPORT/1527 %HOSTIP:%PROXYPORT
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<proxy>
+CONNECT the.old.moo.1527:%HTTPPORT HTTP/1.1
+Host: the.old.moo.1527:%HTTPPORT
+Proxy-Connection: Keep-Alive
+User-Agent: Http Agent
+Expect: 100-continue
+
+</proxy>
+<protocol>
+PUT /1527 HTTP/1.1
+Host: the.old.moo.1527:%HTTPPORT
+Accept: */*
+User-Agent: Http Agent
+Expect: 100-continue
+Content-Length: 13
+
+Hello Cloud!
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc
index 4aeb46cc1..bc243590f 100644
--- a/tests/libtest/Makefile.inc
+++ b/tests/libtest/Makefile.inc
@@ -22,6 +22,8 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
lib583 lib585 lib586 lib587 lib590 lib591 lib597 lib598 lib599 \
lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \
lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 \
+ lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 \
+ lib1525 lib1526 lib1527 \
lib1900 \
lib2033
@@ -353,7 +355,19 @@ lib1514_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1514
lib1515_SOURCES = lib1515.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1515_LDADD = $(TESTUTIL_LIBS)
-lib1515_CPPFLAGS = $(AM_CPPFLAGS)
+lib1515_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1515
+
+lib1525_SOURCES = lib1525.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
+lib1525_LDADD = $(TESTUTIL_LIBS)
+lib1525_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1525
+
+lib1526_SOURCES = lib1526.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
+lib1526_LDADD = $(TESTUTIL_LIBS)
+lib1526_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1526
+
+lib1527_SOURCES = lib1527.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
+lib1527_LDADD = $(TESTUTIL_LIBS)
+lib1527_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1527
lib1900_SOURCES = lib1900.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1900_LDADD = $(TESTUTIL_LIBS)
diff --git a/tests/libtest/lib1525.c b/tests/libtest/lib1525.c
new file mode 100644
index 000000000..45e914e69
--- /dev/null
+++ b/tests/libtest/lib1525.c
@@ -0,0 +1,96 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 2014, Vijay Panghal, <vpanghal@maginatics.com>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This unit test PUT http data over proxy. Proxy header will be different
+ * from server http header
+ */
+
+#include "test.h"
+
+#include "memdebug.h"
+
+static char data [] = "Hello Cloud!\n";
+
+static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ size_t amount = nmemb * size; /* Total bytes curl wants */
+ if (amount < strlen(data)) {
+ return strlen(data);
+ }
+ (void)stream;
+ memcpy(ptr, data, strlen(data));
+ return strlen(data);
+}
+
+
+int test(char *URL)
+{
+ CURL *curl = NULL;
+ CURLcode res = CURLE_FAILED_INIT;
+ /* http and proxy header list*/
+ struct curl_slist *hhl = NULL;
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ fprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ if((curl = curl_easy_init()) == NULL) {
+ fprintf(stderr, "curl_easy_init() failed\n");
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ hhl = curl_slist_append(hhl, "User-Agent: Http Agent");
+
+ if (!hhl) {
+ goto test_cleanup;
+ }
+
+ test_setopt(curl, CURLOPT_URL, URL);
+ test_setopt(curl, CURLOPT_PROXY, libtest_arg2);
+ test_setopt(curl, CURLOPT_HTTPHEADER, hhl);
+ test_setopt(curl, CURLOPT_PROXYHEADER, NULL);
+ test_setopt(curl, CURLOPT_POST, 0L);
+ test_setopt(curl, CURLOPT_UPLOAD, 1L);
+ test_setopt(curl, CURLOPT_VERBOSE, 1L);
+ test_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ test_setopt(curl, CURLOPT_HEADER, 1L);
+ test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
+ test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
+ test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
+ test_setopt(curl, CURLOPT_INFILESIZE, strlen(data));
+
+ res = curl_easy_perform(curl);
+
+test_cleanup:
+
+ curl_easy_cleanup(curl);
+
+ curl_slist_free_all(hhl);
+
+ curl_global_cleanup();
+
+ return (int)res;
+}
diff --git a/tests/libtest/lib1526.c b/tests/libtest/lib1526.c
new file mode 100644
index 000000000..e71512854
--- /dev/null
+++ b/tests/libtest/lib1526.c
@@ -0,0 +1,99 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Vijay Panghal, <vpanghal@maginatics.com>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This unit test PUT http data over proxy. Proxy header will be different
+ * from server http header
+ */
+
+#include "test.h"
+
+#include "memdebug.h"
+
+static char data [] = "Hello Cloud!\n";
+
+static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ size_t amount = nmemb * size; /* Total bytes curl wants */
+ if (amount < strlen(data)) {
+ return strlen(data);
+ }
+ (void)stream;
+ memcpy(ptr, data, strlen(data));
+ return strlen(data);
+}
+
+int test(char *URL)
+{
+ CURL *curl = NULL;
+ CURLcode res = CURLE_FAILED_INIT;
+ /* http and proxy header list*/
+ struct curl_slist *hhl = NULL, *phl = NULL;
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ fprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ if((curl = curl_easy_init()) == NULL) {
+ fprintf(stderr, "curl_easy_init() failed\n");
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ hhl = curl_slist_append(hhl, "User-Agent: Http Agent");
+ phl = curl_slist_append(phl, "User-Agent: Proxy Agent");
+ phl = curl_slist_append(phl, "Expect:");
+
+ if (!hhl || !phl) {
+ goto test_cleanup;
+ }
+
+ test_setopt(curl, CURLOPT_URL, URL);
+ test_setopt(curl, CURLOPT_PROXY, libtest_arg2);
+ test_setopt(curl, CURLOPT_HTTPHEADER, hhl);
+ test_setopt(curl, CURLOPT_PROXYHEADER, phl);
+ test_setopt(curl, CURLOPT_POST, 0L);
+ test_setopt(curl, CURLOPT_UPLOAD, 1L);
+ test_setopt(curl, CURLOPT_VERBOSE, 1L);
+ test_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ test_setopt(curl, CURLOPT_HEADER, 1L);
+ test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
+ test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
+ test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
+ test_setopt(curl, CURLOPT_INFILESIZE, strlen(data));
+
+ res = curl_easy_perform(curl);
+
+test_cleanup:
+
+ curl_easy_cleanup(curl);
+
+ curl_slist_free_all(hhl);
+
+ curl_slist_free_all(phl);
+
+ curl_global_cleanup();
+
+ return (int)res;
+}
+
diff --git a/tests/libtest/lib1527.c b/tests/libtest/lib1527.c
new file mode 100644
index 000000000..41792f14a
--- /dev/null
+++ b/tests/libtest/lib1527.c
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2014, Vijay Panghal, <vpanghal@maginatics.com>, et al.
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at http://curl.haxx.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+
+/*
+ * This unit test PUT http data over proxy. Same http header will be generated
+ * for server and proxy
+ */
+
+#include "test.h"
+
+#include "memdebug.h"
+
+static char data [] = "Hello Cloud!\n";
+
+static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ size_t amount = nmemb * size; /* Total bytes curl wants */
+ if (amount < strlen(data)) {
+ return strlen(data);
+ }
+ (void)stream;
+ memcpy(ptr, data, strlen(data));
+ return strlen(data);
+}
+
+
+int test(char *URL)
+{
+ CURL *curl = NULL;
+ CURLcode res = CURLE_FAILED_INIT;
+ /* http header list*/
+ struct curl_slist *hhl = NULL;
+
+ if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
+ fprintf(stderr, "curl_global_init() failed\n");
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ if((curl = curl_easy_init()) == NULL) {
+ fprintf(stderr, "curl_easy_init() failed\n");
+ curl_global_cleanup();
+ return TEST_ERR_MAJOR_BAD;
+ }
+
+ hhl = curl_slist_append(hhl, "User-Agent: Http Agent");
+ hhl = curl_slist_append(hhl, "Expect: 100-continue");
+
+ if (!hhl) {
+ goto test_cleanup;
+ }
+
+ test_setopt(curl, CURLOPT_URL, URL);
+ test_setopt(curl, CURLOPT_PROXY, libtest_arg2);
+ test_setopt(curl, CURLOPT_HTTPHEADER, hhl);
+ test_setopt(curl, CURLOPT_POST, 0L);
+ test_setopt(curl, CURLOPT_UPLOAD, 1L);
+ test_setopt(curl, CURLOPT_VERBOSE, 1L);
+ test_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
+ test_setopt(curl, CURLOPT_HEADER, 1L);
+ test_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
+ test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
+ test_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, 1L);
+ test_setopt(curl, CURLOPT_INFILESIZE, strlen(data));
+
+ res = curl_easy_perform(curl);
+
+test_cleanup:
+
+ curl_easy_cleanup(curl);
+
+ curl_slist_free_all(hhl);
+
+ curl_global_cleanup();
+
+ return (int)res;
+}