From 5d9fc28fa760e1b0b7f68fce7ae845f4e659e0fd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Wed, 11 May 2005 09:52:59 +0000 Subject: Modified the default HTTP headers used by libcurl: A) Normal non-proxy HTTP: - no more "Pragma: no-cache" (this only makes sense to proxies) B) Non-CONNECT HTTP request over proxy: - "Pragma: no-cache" is used (like before) - "Proxy-Connection: Keep-alive" (for older style 1.0-proxies) C) CONNECT HTTP request over proxy: - "Host: [name]:[port]" - "Proxy-Connection: Keep-alive" --- lib/http.c | 209 ++++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 143 insertions(+), 66 deletions(-) (limited to 'lib/http.c') diff --git a/lib/http.c b/lib/http.c index f61ce42c4..84f357a9c 100644 --- a/lib/http.c +++ b/lib/http.c @@ -811,6 +811,8 @@ struct send_buffer { }; typedef struct send_buffer send_buffer; +static CURLcode add_custom_headers(struct connectdata *conn, + send_buffer *req_buffer); static CURLcode add_buffer(send_buffer *in, const void *inptr, size_t size); @@ -885,34 +887,47 @@ CURLcode add_buffer_send(send_buffer *in, *bytes_written += amount; - if((size_t)amount != size) { - /* The whole request could not be sent in one system call. We must queue - it up and send it later when we get the chance. We must not loop here - and wait until it might work again. */ + if(http) { + if((size_t)amount != size) { + /* The whole request could not be sent in one system call. We must + queue it up and send it later when we get the chance. We must not + loop here and wait until it might work again. */ - size -= amount; + size -= amount; - ptr = in->buffer + amount; + ptr = in->buffer + amount; - /* backup the currently set pointers */ - http->backup.fread = conn->fread; - http->backup.fread_in = conn->fread_in; - http->backup.postdata = http->postdata; - http->backup.postsize = http->postsize; + /* backup the currently set pointers */ + http->backup.fread = conn->fread; + http->backup.fread_in = conn->fread_in; + http->backup.postdata = http->postdata; + http->backup.postsize = http->postsize; - /* set the new pointers for the request-sending */ - conn->fread = (curl_read_callback)readmoredata; - conn->fread_in = (void *)conn; - http->postdata = ptr; - http->postsize = (curl_off_t)size; + /* set the new pointers for the request-sending */ + conn->fread = (curl_read_callback)readmoredata; + conn->fread_in = (void *)conn; + http->postdata = ptr; + http->postsize = (curl_off_t)size; - http->send_buffer = in; - http->sending = HTTPSEND_REQUEST; + http->send_buffer = in; + http->sending = HTTPSEND_REQUEST; - return CURLE_OK; + return CURLE_OK; + } + http->sending = HTTPSEND_BODY; + /* the full buffer was sent, clean up and return */ + } + else { + if((size_t)amount != size) + /* We have no continue-send mechanism now, fail. This can only happen + when this function is used from the CONNECT sending function. We + currently (stupidly) assume that the whole request is always sent + away in the first single chunk. + + This needs FIXing. + */ + return CURLE_SEND_ERROR; } - http->sending = HTTPSEND_BODY; - /* the full buffer was sent, clean up and return */ } if(in->buffer) free(in->buffer); @@ -1038,9 +1053,15 @@ Curl_compareheader(char *headerline, /* line to check */ } /* - * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP proxy. This - * function will issue the necessary commands to get a seamless tunnel through - * this proxy. After that, the socket can be used just as a normal socket. + * ConnectHTTPProxyTunnel() requires that we're connected to a HTTP + * proxy. This function will issue the necessary commands to get a seamless + * tunnel through this proxy. After that, the socket can be used just as a + * normal socket. + * + * This badly needs to be rewritten. CONNECT should be sent and dealt with + * like any ordinary HTTP request, and not specially crafted like this. This + * function only remains here like this for now since the rewrite is a bit too + * much work to do at the moment. */ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, @@ -1063,6 +1084,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, char *line_start; char *host_port; curl_socket_t tunnelsocket = conn->sock[sockindex]; + send_buffer *req_buffer; #define SELECT_OK 0 #define SELECT_ERROR 1 @@ -1080,26 +1102,66 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn, conn->newurl = NULL; } + /* initialize a dynamic send-buffer */ + req_buffer = add_buffer_init(); + + if(!req_buffer) + return CURLE_OUT_OF_MEMORY; + host_port = aprintf("%s:%d", hostname, remote_port); if(!host_port) return CURLE_OUT_OF_MEMORY; /* Setup the proxy-authorization header, if any */ result = Curl_http_output_auth(conn, (char *)"CONNECT", host_port, TRUE); + if(CURLE_OK == result) { + char *host=(char *)""; + const char *proxyconn=""; + char *ptr; + + ptr = checkheaders(data, "Host:"); + if(!ptr) { + host = aprintf("Host: %s\r\n", host_port); + if(!host) + result = CURLE_OUT_OF_MEMORY; + } + ptr = checkheaders(data, "Proxy-Connection:"); + if(!ptr) + proxyconn = "Proxy-Connection: Keep-Alive\r\n"; - /* OK, now send the connect request to the proxy */ - result = - Curl_sendf(tunnelsocket, conn, - "CONNECT %s:%d HTTP/1.0\015\012" - "%s" - "%s" - "\r\n", - hostname, remote_port, - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - data->set.useragent?conn->allocptr.uagent:"" - ); + if(CURLE_OK == result) { + /* Send the connect request to the proxy */ + /* BLOCKING */ + result = + add_bufferf(req_buffer, + "CONNECT %s:%d HTTP/1.0\r\n" + "%s" /* Host: */ + "%s" /* Proxy-Authorization */ + "%s" /* User-Agent */ + "%s", /* Proxy-Connection */ + hostname, remote_port, + host, + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + data->set.useragent?conn->allocptr.uagent:"", + proxyconn); + + if(CURLE_OK == result) + result = add_custom_headers(conn, req_buffer); + + if(host && *host) + free(host); + + if(CURLE_OK == result) + /* CRLF terminate the request */ + result = add_bufferf(req_buffer, "\r\n"); + + if(CURLE_OK == result) + /* Now send off the request */ + result = add_buffer_send(req_buffer, conn, + &data->info.request_size); + } if(result) failf(data, "Failed sending CONNECT to proxy"); } @@ -1367,7 +1429,42 @@ static CURLcode expect100(struct SessionHandle *data, return result; } +static CURLcode add_custom_headers(struct connectdata *conn, + send_buffer *req_buffer) +{ + CURLcode result = CURLE_OK; + char *ptr; + struct curl_slist *headers=conn->data->set.headers; + + while(headers) { + ptr = strchr(headers->data, ':'); + if(ptr) { + /* we require a colon for this to be a true header */ + + ptr++; /* pass the colon */ + while(*ptr && isspace((int)*ptr)) + ptr++; + if(*ptr) { + /* only send this if the contents was non-blank */ + + if(conn->allocptr.host && + /* a Host: header was sent already, don't pass on any custom Host: + header as that will produce *two* in the same request! */ + curl_strnequal("Host:", headers->data, 5)) + ; + else { + + result = add_bufferf(req_buffer, "%s\r\n", headers->data); + if(result) + return result; + } + } + } + headers = headers->next; + } + return result; +} /* * Curl_http() gets called from the generic Curl_do() function when a HTTP @@ -1620,8 +1717,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } - if(!checkheaders(data, "Pragma:")) - http->p_pragma = "Pragma: no-cache\r\n"; + http->p_pragma = + (!checkheaders(data, "Pragma:") && + (conn->bits.httpproxy && !conn->bits.tunnel_proxy) )? + "Pragma: no-cache\r\n":NULL; if(!checkheaders(data, "Accept:")) http->p_accept = "Accept: */*\r\n"; @@ -1727,7 +1826,6 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1"; send_buffer *req_buffer; - struct curl_slist *headers=data->set.headers; curl_off_t postsize; /* off_t type to be able to hold a large file size */ /* initialize a dynamic send-buffer */ @@ -1750,6 +1848,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) "%s" /* accept */ "%s" /* accept-encoding */ "%s" /* referer */ + "%s" /* Proxy-Connection */ "%s",/* transfer-encoding */ request, @@ -1768,6 +1867,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) (data->set.encoding && *data->set.encoding && conn->allocptr.accept_encoding)? conn->allocptr.accept_encoding:"", (data->change.referer && conn->allocptr.ref)?conn->allocptr.ref:"" /* Referer: */, + (conn->bits.httpproxy && !conn->bits.tunnel_proxy)? + "Proxy-Connection: Keep-Alive\r\n":"", te ); @@ -1874,33 +1975,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } - while(headers) { - ptr = strchr(headers->data, ':'); - if(ptr) { - /* we require a colon for this to be a true header */ - - ptr++; /* pass the colon */ - while(*ptr && isspace((int)*ptr)) - ptr++; - - if(*ptr) { - /* only send this if the contents was non-blank */ - - if(conn->allocptr.host && - /* a Host: header was sent already, don't pass on any custom Host: - header as that will produce *two* in the same request! */ - curl_strnequal("Host:", headers->data, 5)) - ; - else { - - result = add_bufferf(req_buffer, "%s\r\n", headers->data); - if(result) - return result; - } - } - } - headers = headers->next; - } + result = add_custom_headers(conn, req_buffer); + if(result) + return result; http->postdata = NULL; /* nothing to post at this point */ Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */ -- cgit v1.2.3