CURLOPT_PROXYHEADER: set headers for proxy-only

Includes docs and new test cases: 1525, 1526 and 1527

Co-written-by: Vijay Panghal
This commit is contained in:
Daniel Stenberg 2014-01-31 08:10:07 +01:00
parent 42937f87e6
commit ac887eedbc
17 changed files with 667 additions and 48 deletions

View File

@ -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 The most commonly replaced headers have "shortcuts" in the options
\fICURLOPT_COOKIE\fP, \fICURLOPT_USERAGENT\fP and \fICURLOPT_REFERER\fP. \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 .IP CURLOPT_HTTP200ALIASES
Pass a pointer to a linked list of aliases to be treated as valid HTTP 200 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 responses. Some servers respond with a custom header response line. For

View File

@ -439,6 +439,7 @@ CURLOPT_PROGRESSFUNCTION 7.1 7.32.0
CURLOPT_PROTOCOLS 7.19.4 CURLOPT_PROTOCOLS 7.19.4
CURLOPT_PROXY 7.1 CURLOPT_PROXY 7.1
CURLOPT_PROXYAUTH 7.10.7 CURLOPT_PROXYAUTH 7.10.7
CURLOPT_PROXYHEADER 7.36.0
CURLOPT_PROXYPASSWORD 7.19.1 CURLOPT_PROXYPASSWORD 7.19.1
CURLOPT_PROXYPORT 7.1 CURLOPT_PROXYPORT 7.1
CURLOPT_PROXYTYPE 7.10 CURLOPT_PROXYTYPE 7.10

View File

@ -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 * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -903,7 +903,8 @@ typedef enum {
/* Set cookie in request: */ /* Set cookie in request: */
CINIT(COOKIE, OBJECTPOINT, 22), 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), CINIT(HTTPHEADER, OBJECTPOINT, 23),
/* This points to a linked list of post entries, struct curl_httppost */ /* 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. */ * Expect: 100-continue header before sending the data anyway. */
CINIT(EXPECT_100_TIMEOUT_MS, LONG, 227), 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 */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

View File

@ -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. * 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; struct curl_slist *head;
size_t thislen = strlen(thisheader); size_t thislen = strlen(thisheader);
struct SessionHandle *data = conn->data;
for(head = data->set.headers; head; head=head->next) { 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 = (conn->bits.proxy && data->set.proxyheaders)?
data->set.proxyheaders:data->set.headers;
head; head=head->next) {
if(Curl_raw_nequal(head->data, thisheader, thislen)) if(Curl_raw_nequal(head->data, thisheader, thislen))
return head->data; return head->data;
} }
@ -584,9 +612,9 @@ output_auth_headers(struct connectdata *conn,
if(authstatus->picked == CURLAUTH_BASIC) { if(authstatus->picked == CURLAUTH_BASIC) {
/* Basic */ /* Basic */
if((proxy && conn->bits.proxy_user_passwd && if((proxy && conn->bits.proxy_user_passwd &&
!Curl_checkheaders(data, "Proxy-authorization:")) || !Curl_checkProxyheaders(conn, "Proxy-authorization:")) ||
(!proxy && conn->bits.user_passwd && (!proxy && conn->bits.user_passwd &&
!Curl_checkheaders(data, "Authorization:"))) { !Curl_checkheaders(conn, "Authorization:"))) {
auth="Basic"; auth="Basic";
result = http_output_basic(conn, proxy); result = http_output_basic(conn, proxy);
if(result) 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: /* if not doing HTTP 1.0 or disabled explicitly, we add a Expect:
100-continue to the headers which actually speeds up post operations 100-continue to the headers which actually speeds up post operations
(as there is one packet coming back from the web server) */ (as there is one packet coming back from the web server) */
ptr = Curl_checkheaders(data, "Expect:"); ptr = Curl_checkheaders(conn, "Expect:");
if(ptr) { if(ptr) {
data->state.expect100header = data->state.expect100header =
Curl_compareheader(ptr, "Expect:", "100-continue"); Curl_compareheader(ptr, "Expect:", "100-continue");
@ -1517,10 +1545,13 @@ static CURLcode expect100(struct SessionHandle *data,
} }
CURLcode Curl_add_custom_headers(struct connectdata *conn, CURLcode Curl_add_custom_headers(struct connectdata *conn,
Curl_send_buffer *req_buffer) bool is_proxy,
Curl_send_buffer *req_buffer)
{ {
char *ptr; 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) { while(headers) {
ptr = strchr(headers->data, ':'); 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 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 with the user-agent string specified, we erase the previously made string
here. */ here. */
if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) { if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) {
free(conn->allocptr.uagent); free(conn->allocptr.uagent);
conn->allocptr.uagent=NULL; conn->allocptr.uagent=NULL;
} }
@ -1757,7 +1788,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
conn->bits.authneg = FALSE; conn->bits.authneg = FALSE;
Curl_safefree(conn->allocptr.ref); 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); conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
if(!conn->allocptr.ref) if(!conn->allocptr.ref)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
@ -1765,10 +1796,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
else else
conn->allocptr.ref = NULL; 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]; addcookies = data->set.str[STRING_COOKIE];
if(!Curl_checkheaders(data, "Accept-Encoding:") && if(!Curl_checkheaders(conn, "Accept-Encoding:") &&
data->set.str[STRING_ENCODING]) { data->set.str[STRING_ENCODING]) {
Curl_safefree(conn->allocptr.accept_encoding); Curl_safefree(conn->allocptr.accept_encoding);
conn->allocptr.accept_encoding = conn->allocptr.accept_encoding =
@ -1780,13 +1811,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
/* we only consider transfer-encoding magic if libz support is built-in */ /* 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 /* 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 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 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 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! */ 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" #define TE_HEADER "TE: gzip\r\n"
Curl_safefree(conn->allocptr.te); Curl_safefree(conn->allocptr.te);
@ -1804,7 +1836,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
/* In HTTP2 forbids Transfer-Encoding: chunked */ /* In HTTP2 forbids Transfer-Encoding: chunked */
ptr = NULL; ptr = NULL;
else { else {
ptr = Curl_checkheaders(data, "Transfer-Encoding:"); ptr = Curl_checkheaders(conn, "Transfer-Encoding:");
if(ptr) { if(ptr) {
/* Some kind of TE is requested, check if 'chunked' is chosen */ /* Some kind of TE is requested, check if 'chunked' is chosen */
data->req.upload_chunky = data->req.upload_chunky =
@ -1838,7 +1870,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
Curl_safefree(conn->allocptr.host); Curl_safefree(conn->allocptr.host);
ptr = Curl_checkheaders(data, "Host:"); ptr = Curl_checkheaders(conn, "Host:");
if(ptr && (!data->state.this_is_a_follow || if(ptr && (!data->state.this_is_a_follow ||
Curl_raw_equal(data->state.first_host, conn->host.name))) { Curl_raw_equal(data->state.first_host, conn->host.name))) {
#if !defined(CURL_DISABLE_COOKIES) #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 /* we must build the whole post sequence first, so that we have a size of
the whole transfer before we start to send it */ the whole transfer before we start to send it */
result = Curl_getformdata(data, &http->sendit, data->set.httppost, result = Curl_getformdata(data, &http->sendit, data->set.httppost,
Curl_checkheaders(data, "Content-Type:"), Curl_checkheaders(conn, "Content-Type:"),
&http->postsize); &http->postsize);
if(result) if(result)
return 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) || if(( (HTTPREQ_POST == httpreq) ||
(HTTPREQ_POST_FORM == httpreq) || (HTTPREQ_POST_FORM == httpreq) ||
@ -2069,7 +2101,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
* ones if any such are specified. * ones if any such are specified.
*/ */
if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) && 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 a line like this was already allocated, free the previous one */
if(conn->allocptr.rangeline) if(conn->allocptr.rangeline)
free(conn->allocptr.rangeline); free(conn->allocptr.rangeline);
@ -2077,7 +2109,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
data->state.range); data->state.range);
} }
else if((httpreq != HTTPREQ_GET) && 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 a line like this was already allocated, free the previous one */
if(conn->allocptr.rangeline) if(conn->allocptr.rangeline)
@ -2179,7 +2211,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
conn->allocptr.ref:"" /* Referer: <data> */, conn->allocptr.ref:"" /* Referer: <data> */,
(conn->bits.httpproxy && (conn->bits.httpproxy &&
!conn->bits.tunnel_proxy && !conn->bits.tunnel_proxy &&
!Curl_checkheaders(data, "Proxy-Connection:"))? !Curl_checkProxyheaders(conn, "Proxy-Connection:"))?
"Proxy-Connection: Keep-Alive\r\n":"", "Proxy-Connection: Keep-Alive\r\n":"",
te te
); );
@ -2264,7 +2296,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result; return result;
} }
result = Curl_add_custom_headers(conn, req_buffer); result = Curl_add_custom_headers(conn, FALSE, req_buffer);
if(result) if(result)
return result; return result;
@ -2314,7 +2346,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
http->sending = HTTPSEND_BODY; http->sending = HTTPSEND_BODY;
if(!data->req.upload_chunky && if(!data->req.upload_chunky &&
!Curl_checkheaders(data, "Content-Length:")) { !Curl_checkheaders(conn, "Content-Length:")) {
/* only add Content-Length if not uploading chunked */ /* only add Content-Length if not uploading chunked */
result = Curl_add_bufferf(req_buffer, result = Curl_add_bufferf(req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T "Content-Length: %" CURL_FORMAT_CURL_OFF_T
@ -2386,7 +2418,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
postsize = data->set.infilesize; postsize = data->set.infilesize;
if((postsize != -1) && !data->req.upload_chunky && 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 */ /* only add Content-Length if not uploading chunked */
result = Curl_add_bufferf(req_buffer, result = Curl_add_bufferf(req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T "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 we don't upload data chunked, as RFC2616 forbids us to set both
kinds of headers (Transfer-Encoding: chunked and Content-Length) */ kinds of headers (Transfer-Encoding: chunked and Content-Length) */
if((postsize != -1) && !data->req.upload_chunky && 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, /* we allow replacing this header if not during auth negotiation,
although it isn't very wise to actually set your own */ although it isn't very wise to actually set your own */
result = Curl_add_bufferf(req_buffer, result = Curl_add_bufferf(req_buffer,
@ -2448,7 +2480,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
return result; return result;
} }
if(!Curl_checkheaders(data, "Content-Type:")) { if(!Curl_checkheaders(conn, "Content-Type:")) {
result = Curl_add_bufferf(req_buffer, result = Curl_add_bufferf(req_buffer,
"Content-Type: application/" "Content-Type: application/"
"x-www-form-urlencoded\r\n"); "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 the somewhat bigger ones we allow the app to disable it. Just make
sure that the expect100header is always set to the preferred value sure that the expect100header is always set to the preferred value
here. */ here. */
ptr = Curl_checkheaders(data, "Expect:"); ptr = Curl_checkheaders(conn, "Expect:");
if(ptr) { if(ptr) {
data->state.expect100header = data->state.expect100header =
Curl_compareheader(ptr, "Expect:", "100-continue"); Curl_compareheader(ptr, "Expect:", "100-continue");

View File

@ -39,9 +39,13 @@ extern const struct Curl_handler Curl_handler_https;
bool Curl_compareheader(const char *headerline, /* line to check */ bool Curl_compareheader(const char *headerline, /* line to check */
const char *header, /* header keyword _with_ colon */ const char *header, /* header keyword _with_ colon */
const char *content); /* content string to find */ 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_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 * 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, CURLcode Curl_add_timecondition(struct SessionHandle *data,
Curl_send_buffer *buf); Curl_send_buffer *buf);
CURLcode Curl_add_custom_headers(struct connectdata *conn, 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 */ /* protocol-specific functions set up to be called by the main engine */
CURLcode Curl_http(struct connectdata *conn, bool *done); CURLcode Curl_http(struct connectdata *conn, bool *done);

View File

@ -165,7 +165,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
if(!Curl_checkheaders(data, "Host:")) { if(!Curl_checkProxyheaders(conn, "Host:")) {
host = aprintf("Host: %s\r\n", hostheader); host = aprintf("Host: %s\r\n", hostheader);
if(!host) { if(!host) {
free(hostheader); free(hostheader);
@ -173,10 +173,10 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
} }
if(!Curl_checkheaders(data, "Proxy-Connection:")) if(!Curl_checkProxyheaders(conn, "Proxy-Connection:"))
proxyconn = "Proxy-Connection: Keep-Alive\r\n"; proxyconn = "Proxy-Connection: Keep-Alive\r\n";
if(!Curl_checkheaders(data, "User-Agent:") && if(!Curl_checkProxyheaders(conn, "User-Agent:") &&
data->set.str[STRING_USERAGENT]) data->set.str[STRING_USERAGENT])
useragent = conn->allocptr.uagent; useragent = conn->allocptr.uagent;
@ -200,7 +200,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn,
free(hostheader); free(hostheader);
if(CURLE_OK == result) 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) if(CURLE_OK == result)
/* CRLF terminate the request */ /* CRLF terminate the request */

View File

@ -341,7 +341,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
} }
/* Transport Header for SETUP requests */ /* Transport Header for SETUP requests */
p_transport = Curl_checkheaders(data, "Transport:"); p_transport = Curl_checkheaders(conn, "Transport:");
if(rtspreq == RTSPREQ_SETUP && !p_transport) { if(rtspreq == RTSPREQ_SETUP && !p_transport) {
/* New Transport: setting? */ /* New Transport: setting? */
if(data->set.str[STRING_RTSP_TRANSPORT]) { 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 */ /* Accept Headers for DESCRIBE requests */
if(rtspreq == RTSPREQ_DESCRIBE) { if(rtspreq == RTSPREQ_DESCRIBE) {
/* Accept Header */ /* Accept Header */
p_accept = Curl_checkheaders(data, "Accept:")? p_accept = Curl_checkheaders(conn, "Accept:")?
NULL:"Accept: application/sdp\r\n"; NULL:"Accept: application/sdp\r\n";
/* Accept-Encoding header */ /* Accept-Encoding header */
if(!Curl_checkheaders(data, "Accept-Encoding:") && if(!Curl_checkheaders(conn, "Accept-Encoding:") &&
data->set.str[STRING_ENCODING]) { data->set.str[STRING_ENCODING]) {
Curl_safefree(conn->allocptr.accept_encoding); Curl_safefree(conn->allocptr.accept_encoding);
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 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 with the user-agent string specified, we erase the previously made string
here. */ here. */
if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) { if(Curl_checkheaders(conn, "User-Agent:") && conn->allocptr.uagent) {
Curl_safefree(conn->allocptr.uagent); Curl_safefree(conn->allocptr.uagent);
conn->allocptr.uagent = NULL; conn->allocptr.uagent = NULL;
} }
else if(!Curl_checkheaders(data, "User-Agent:") && else if(!Curl_checkheaders(conn, "User-Agent:") &&
data->set.str[STRING_USERAGENT]) { data->set.str[STRING_USERAGENT]) {
p_uagent = conn->allocptr.uagent; p_uagent = conn->allocptr.uagent;
} }
/* Referrer */ /* Referrer */
Curl_safefree(conn->allocptr.ref); 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); conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
else else
conn->allocptr.ref = NULL; conn->allocptr.ref = NULL;
@ -414,7 +414,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
(rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) { (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
/* Check to see if there is a range set in the custom headers */ /* 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); Curl_safefree(conn->allocptr.rangeline);
conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range); conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
p_range = conn->allocptr.rangeline; p_range = conn->allocptr.rangeline;
@ -424,11 +424,11 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
/* /*
* Sanity check the custom headers * 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."); failf(data, "CSeq cannot be set as a custom header.");
return CURLE_RTSP_CSEQ_ERROR; 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."); failf(data, "Session ID cannot be set as a custom header.");
return CURLE_BAD_FUNCTION_ARGUMENT; return CURLE_BAD_FUNCTION_ARGUMENT;
} }
@ -484,7 +484,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
return result; return result;
} }
result = Curl_add_custom_headers(conn, req_buffer); result = Curl_add_custom_headers(conn, FALSE, req_buffer);
if(result) if(result)
return result; return result;
@ -507,7 +507,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(putsize > 0 || postsize > 0) { if(putsize > 0 || postsize > 0) {
/* As stated in the http comments, it is probably not wise to /* As stated in the http comments, it is probably not wise to
* actually set a custom Content-Length in the headers */ * 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, result = Curl_add_bufferf(req_buffer,
"Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n", "Content-Length: %" CURL_FORMAT_CURL_OFF_T"\r\n",
(data->set.upload ? putsize : postsize)); (data->set.upload ? putsize : postsize));
@ -517,7 +517,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
if(rtspreq == RTSPREQ_SET_PARAMETER || if(rtspreq == RTSPREQ_SET_PARAMETER ||
rtspreq == RTSPREQ_GET_PARAMETER) { rtspreq == RTSPREQ_GET_PARAMETER) {
if(!Curl_checkheaders(data, "Content-Type:")) { if(!Curl_checkheaders(conn, "Content-Type:")) {
result = Curl_add_bufferf(req_buffer, result = Curl_add_bufferf(req_buffer,
"Content-Type: text/parameters\r\n"); "Content-Type: text/parameters\r\n");
if(result) if(result)
@ -526,7 +526,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done)
} }
if(rtspreq == RTSPREQ_ANNOUNCE) { if(rtspreq == RTSPREQ_ANNOUNCE) {
if(!Curl_checkheaders(data, "Content-Type:")) { if(!Curl_checkheaders(conn, "Content-Type:")) {
result = Curl_add_bufferf(req_buffer, result = Curl_add_bufferf(req_buffer,
"Content-Type: application/sdp\r\n"); "Content-Type: application/sdp\r\n");
if(result) if(result)

View File

@ -1067,6 +1067,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
data->set.headers = va_arg(param, struct curl_slist *); data->set.headers = va_arg(param, struct curl_slist *);
break; 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: case CURLOPT_HTTP200ALIASES:
/* /*
* Set a list of aliases for HTTP 200 in response header * Set a list of aliases for HTTP 200 in response header

View File

@ -1465,6 +1465,7 @@ struct UserDefined {
download */ download */
curl_off_t set_resume_from; /* continue [ftp] transfer from here */ curl_off_t set_resume_from; /* continue [ftp] transfer from here */
struct curl_slist *headers; /* linked list of extra headers */ 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 */ struct curl_httppost *httppost; /* linked list of POST data */
bool cookiesession; /* new cookie session? */ bool cookiesession; /* new cookie session? */
bool crlf; /* convert crlf on ftp upload(?) */ bool crlf; /* convert crlf on ftp upload(?) */

View File

@ -127,6 +127,8 @@ test1500 test1501 test1502 test1503 test1504 test1505 test1506 test1507 \
test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \ test1508 test1509 test1510 test1511 test1512 test1513 test1514 test1515 \
test1516 \ test1516 \
\ \
test1525 test1526 test1527 \
\
test1900 test1901 test1902 test1903 \ test1900 test1901 test1902 test1903 \
\ \
test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \ test2000 test2001 test2002 test2003 test2004 test2005 test2006 test2007 \

76
tests/data/test1525 Normal file
View File

@ -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>

76
tests/data/test1526 Normal file
View File

@ -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>

76
tests/data/test1527 Normal file
View File

@ -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>

View File

@ -22,6 +22,8 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
lib583 lib585 lib586 lib587 lib590 lib591 lib597 lib598 lib599 \ lib583 lib585 lib586 lib587 lib590 lib591 lib597 lib598 lib599 \
lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \ lib1500 lib1501 lib1502 lib1503 lib1504 lib1505 lib1506 lib1507 lib1508 \
lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 \ lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 \
lib1509 lib1510 lib1511 lib1512 lib1513 lib1514 lib1515 \
lib1525 lib1526 lib1527 \
lib1900 \ lib1900 \
lib2033 lib2033
@ -353,7 +355,19 @@ lib1514_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1514
lib1515_SOURCES = lib1515.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib1515_SOURCES = lib1515.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1515_LDADD = $(TESTUTIL_LIBS) 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_SOURCES = lib1900.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
lib1900_LDADD = $(TESTUTIL_LIBS) lib1900_LDADD = $(TESTUTIL_LIBS)

96
tests/libtest/lib1525.c Normal file
View File

@ -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;
}

99
tests/libtest/lib1526.c Normal file
View File

@ -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;
}

95
tests/libtest/lib1527.c Normal file
View File

@ -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;
}