Loading CHANGES +13 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,19 @@ Changelog Daniel Fandrich (5 Sep 2008) - Improved the logic the decides whether to use HTTP 1.1 features or not in a request. Setting a specific version with CURLOPT_HTTP_VERSION overrides all other checks, but otherwise, a 1.0 request will be made if the server is known to support only 1.0 because it previously responded so and the connection was kept alive, or a response to a previous request on this handle came back as 1.0. The latter could take place in cases like redirection or authentication where several requests have to be made before the operation is complete. - Detect cases where an upload must be sent chunked and the server supports only HTTP 1.0 and return CURLE_UPLOAD_FAILED. Daniel Stenberg (5 Sep 2008) - Martin Drasar provided the CURLOPT_POSTREDIR patch. It renames CURLOPT_POST301 (but adds a define for backwards compatibility for you who Loading RELEASE-NOTES +1 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ This release includes the following changes: o pkg-config can now show supported_protocols and supported_features o Added CURLOPT_CERTINFO and CURLINFO_CERTINFO o Added CURLOPT_POSTREDIR o Better detect HTTP 1.0 servers and don't do HTTP 1.1 requests on them This release includes the following bugfixes: Loading TODO-RELEASE +0 −6 Original line number Diff line number Diff line Loading @@ -4,12 +4,6 @@ To be addressed before 7.19.1 (planned release: October/November 2008) 162 - Craig Perras' note "http upload: how to stop on error" http://curl.haxx.se/mail/archive-2008-08/0138.html 163 - Detecting illegal attempts at chunked transfers on HTTP 1.0 (tests 1069, 1072, 1073) http://curl.haxx.se/mail/archive-2008-08/0435.html 164 - Automatic downgrading to HTTP 1.0 (tests 1071 through 1074) 165 - "Problem with CURLOPT_RESUME_FROM and CURLOPT_APPEND" by Daniele Pinau, recipe: http://curl.haxx.se/mail/lib-2008-08/0439.html Loading lib/http.c +31 −11 Original line number Diff line number Diff line Loading @@ -1950,15 +1950,30 @@ CURLcode Curl_http_done(struct connectdata *conn, return CURLE_OK; } /* Determine if we should use HTTP 1.1 for this request. Reasons to avoid it are if the user specifically requested HTTP 1.0, if the server we are connected to only supports 1.0, or if any server previously contacted to handle this request only supports 1.0. */ static bool use_http_1_1(const struct SessionHandle *data, const struct connectdata *conn) { return (data->set.httpversion == CURL_HTTP_VERSION_1_1) || ((data->set.httpversion != CURL_HTTP_VERSION_1_0) && ((conn->httpversion == 11) || ((conn->httpversion != 10) && (data->state.httpversion != 10)))); } /* check and possibly add an Expect: header */ static CURLcode expect100(struct SessionHandle *data, struct connectdata *conn, send_buffer *req_buffer) { CURLcode result = CURLE_OK; data->state.expect100header = FALSE; /* default to false unless it is set to TRUE below */ if((data->set.httpversion != CURL_HTTP_VERSION_1_0) && !checkheaders(data, "Expect:")) { if(use_http_1_1(data, conn) && !checkheaders(data, "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 (as there is one packet coming back from the web Loading Loading @@ -2139,10 +2154,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else { if((conn->protocol&PROT_HTTP) && data->set.upload && (data->set.infilesize == -1) && (data->set.httpversion != CURL_HTTP_VERSION_1_0)) { (data->set.infilesize == -1)) { if (use_http_1_1(data, conn)) { /* HTTP, upload, unknown file size and not HTTP 1.0 */ data->req.upload_chunky = TRUE; } else { failf(data, "Chunky upload is not supported by HTTP 1.0"); return CURLE_UPLOAD_FAILED; } } else { /* else, no chunky upload */ Loading Loading @@ -2410,8 +2429,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } /* Use 1.1 unless the use specificly asked for 1.0 */ httpstring= data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1"; /* Use 1.1 unless the user specifically asked for 1.0 or the server only supports 1.0 */ httpstring= use_http_1_1(data, conn)?"1.1":"1.0"; /* initialize a dynamic send-buffer */ req_buffer = add_buffer_init(); Loading Loading @@ -2635,7 +2655,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } result = expect100(data, req_buffer); result = expect100(data, conn, req_buffer); if(result) return result; Loading Loading @@ -2707,7 +2727,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } result = expect100(data, req_buffer); result = expect100(data, conn, req_buffer); if(result) return result; Loading Loading @@ -2772,7 +2792,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) sure that the expect100header is always set to the preferred value here. */ if(postsize > TINY_INITIAL_POST_SIZE) { result = expect100(data, req_buffer); result = expect100(data, conn, req_buffer); if(result) return result; } Loading lib/transfer.c +16 −11 Original line number Diff line number Diff line Loading @@ -832,7 +832,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data, k->header = FALSE; /* no more header to parse! */ if((k->size == -1) && !k->chunk && !conn->bits.close && (k->httpversion >= 11) ) { (conn->httpversion >= 11) ) { /* On HTTP 1.1, when connection is not to get closed, but no Content-Length nor Content-Encoding chunked have been received, according to RFC2616 section 4.4 point 5, we Loading Loading @@ -1006,17 +1006,17 @@ static CURLcode readwrite_headers(struct SessionHandle *data, nc = sscanf(HEADER1, " HTTP/%d.%d %3d", &httpversion_major, &k->httpversion, &conn->httpversion, &k->httpcode); if(nc==3) { k->httpversion += 10 * httpversion_major; conn->httpversion += 10 * httpversion_major; } else { /* this is the real world, not a Nirvana NCSA 1.5.x returns this crap when asked for HTTP/1.1 */ nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); k->httpversion = 10; conn->httpversion = 10; /* If user has set option HTTP200ALIASES, compare header line against list of aliases Loading @@ -1025,14 +1025,18 @@ static CURLcode readwrite_headers(struct SessionHandle *data, if(checkhttpprefix(data, k->p)) { nc = 1; k->httpcode = 200; k->httpversion = 10; conn->httpversion = 10; } } } if(nc) { data->info.httpcode = k->httpcode; data->info.httpversion = k->httpversion; data->info.httpversion = conn->httpversion; if (!data->state.httpversion || data->state.httpversion > conn->httpversion) /* store the lowest server version we encounter */ data->state.httpversion = conn->httpversion; /* * This code executes as part of processing the header. As a Loading Loading @@ -1060,14 +1064,14 @@ static CURLcode readwrite_headers(struct SessionHandle *data, } } if(k->httpversion == 10) { if(conn->httpversion == 10) { /* Default action for HTTP/1.0 must be to close, unless we get one of those fancy headers that tell us the server keeps it open for us! */ infof(data, "HTTP 1.0, assume close after body\n"); conn->bits.close = TRUE; } else if(k->httpversion >= 11 && else if(conn->httpversion >= 11 && !conn->bits.close) { /* If HTTP version is >= 1.1 and connection is persistent server supports pipelining. */ Loading Loading @@ -1161,7 +1165,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data, data->info.contenttype = contenttype; } } else if((k->httpversion == 10) && else if((conn->httpversion == 10) && conn->bits.httpproxy && Curl_compareheader(k->p, "Proxy-Connection:", "keep-alive")) { Loading @@ -1174,7 +1178,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data, conn->bits.close = FALSE; /* don't close when done */ infof(data, "HTTP/1.0 proxy connection set to keep alive!\n"); } else if((k->httpversion == 11) && else if((conn->httpversion == 11) && conn->bits.httpproxy && Curl_compareheader(k->p, "Proxy-Connection:", "close")) { Loading @@ -1185,7 +1189,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data, conn->bits.close = TRUE; /* close when done */ infof(data, "HTTP/1.1 proxy connection set close!\n"); } else if((k->httpversion == 10) && else if((conn->httpversion == 10) && Curl_compareheader(k->p, "Connection:", "keep-alive")) { /* * A HTTP/1.0 reply with the 'Connection: keep-alive' line Loading Loading @@ -1886,6 +1890,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) data->set.followlocation=0; /* reset the location-follow counter */ data->state.this_is_a_follow = FALSE; /* reset this */ data->state.errorbuf = FALSE; /* no error has occurred */ data->state.httpversion = 0; /* don't assume any particular server version */ data->state.authproblem = FALSE; data->state.authhost.want = data->set.httpauth; Loading Loading
CHANGES +13 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,19 @@ Changelog Daniel Fandrich (5 Sep 2008) - Improved the logic the decides whether to use HTTP 1.1 features or not in a request. Setting a specific version with CURLOPT_HTTP_VERSION overrides all other checks, but otherwise, a 1.0 request will be made if the server is known to support only 1.0 because it previously responded so and the connection was kept alive, or a response to a previous request on this handle came back as 1.0. The latter could take place in cases like redirection or authentication where several requests have to be made before the operation is complete. - Detect cases where an upload must be sent chunked and the server supports only HTTP 1.0 and return CURLE_UPLOAD_FAILED. Daniel Stenberg (5 Sep 2008) - Martin Drasar provided the CURLOPT_POSTREDIR patch. It renames CURLOPT_POST301 (but adds a define for backwards compatibility for you who Loading
RELEASE-NOTES +1 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ This release includes the following changes: o pkg-config can now show supported_protocols and supported_features o Added CURLOPT_CERTINFO and CURLINFO_CERTINFO o Added CURLOPT_POSTREDIR o Better detect HTTP 1.0 servers and don't do HTTP 1.1 requests on them This release includes the following bugfixes: Loading
TODO-RELEASE +0 −6 Original line number Diff line number Diff line Loading @@ -4,12 +4,6 @@ To be addressed before 7.19.1 (planned release: October/November 2008) 162 - Craig Perras' note "http upload: how to stop on error" http://curl.haxx.se/mail/archive-2008-08/0138.html 163 - Detecting illegal attempts at chunked transfers on HTTP 1.0 (tests 1069, 1072, 1073) http://curl.haxx.se/mail/archive-2008-08/0435.html 164 - Automatic downgrading to HTTP 1.0 (tests 1071 through 1074) 165 - "Problem with CURLOPT_RESUME_FROM and CURLOPT_APPEND" by Daniele Pinau, recipe: http://curl.haxx.se/mail/lib-2008-08/0439.html Loading
lib/http.c +31 −11 Original line number Diff line number Diff line Loading @@ -1950,15 +1950,30 @@ CURLcode Curl_http_done(struct connectdata *conn, return CURLE_OK; } /* Determine if we should use HTTP 1.1 for this request. Reasons to avoid it are if the user specifically requested HTTP 1.0, if the server we are connected to only supports 1.0, or if any server previously contacted to handle this request only supports 1.0. */ static bool use_http_1_1(const struct SessionHandle *data, const struct connectdata *conn) { return (data->set.httpversion == CURL_HTTP_VERSION_1_1) || ((data->set.httpversion != CURL_HTTP_VERSION_1_0) && ((conn->httpversion == 11) || ((conn->httpversion != 10) && (data->state.httpversion != 10)))); } /* check and possibly add an Expect: header */ static CURLcode expect100(struct SessionHandle *data, struct connectdata *conn, send_buffer *req_buffer) { CURLcode result = CURLE_OK; data->state.expect100header = FALSE; /* default to false unless it is set to TRUE below */ if((data->set.httpversion != CURL_HTTP_VERSION_1_0) && !checkheaders(data, "Expect:")) { if(use_http_1_1(data, conn) && !checkheaders(data, "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 (as there is one packet coming back from the web Loading Loading @@ -2139,10 +2154,14 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else { if((conn->protocol&PROT_HTTP) && data->set.upload && (data->set.infilesize == -1) && (data->set.httpversion != CURL_HTTP_VERSION_1_0)) { (data->set.infilesize == -1)) { if (use_http_1_1(data, conn)) { /* HTTP, upload, unknown file size and not HTTP 1.0 */ data->req.upload_chunky = TRUE; } else { failf(data, "Chunky upload is not supported by HTTP 1.0"); return CURLE_UPLOAD_FAILED; } } else { /* else, no chunky upload */ Loading Loading @@ -2410,8 +2429,9 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } } /* Use 1.1 unless the use specificly asked for 1.0 */ httpstring= data->set.httpversion==CURL_HTTP_VERSION_1_0?"1.0":"1.1"; /* Use 1.1 unless the user specifically asked for 1.0 or the server only supports 1.0 */ httpstring= use_http_1_1(data, conn)?"1.1":"1.0"; /* initialize a dynamic send-buffer */ req_buffer = add_buffer_init(); Loading Loading @@ -2635,7 +2655,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } result = expect100(data, req_buffer); result = expect100(data, conn, req_buffer); if(result) return result; Loading Loading @@ -2707,7 +2727,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) return result; } result = expect100(data, req_buffer); result = expect100(data, conn, req_buffer); if(result) return result; Loading Loading @@ -2772,7 +2792,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) sure that the expect100header is always set to the preferred value here. */ if(postsize > TINY_INITIAL_POST_SIZE) { result = expect100(data, req_buffer); result = expect100(data, conn, req_buffer); if(result) return result; } Loading
lib/transfer.c +16 −11 Original line number Diff line number Diff line Loading @@ -832,7 +832,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data, k->header = FALSE; /* no more header to parse! */ if((k->size == -1) && !k->chunk && !conn->bits.close && (k->httpversion >= 11) ) { (conn->httpversion >= 11) ) { /* On HTTP 1.1, when connection is not to get closed, but no Content-Length nor Content-Encoding chunked have been received, according to RFC2616 section 4.4 point 5, we Loading Loading @@ -1006,17 +1006,17 @@ static CURLcode readwrite_headers(struct SessionHandle *data, nc = sscanf(HEADER1, " HTTP/%d.%d %3d", &httpversion_major, &k->httpversion, &conn->httpversion, &k->httpcode); if(nc==3) { k->httpversion += 10 * httpversion_major; conn->httpversion += 10 * httpversion_major; } else { /* this is the real world, not a Nirvana NCSA 1.5.x returns this crap when asked for HTTP/1.1 */ nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); k->httpversion = 10; conn->httpversion = 10; /* If user has set option HTTP200ALIASES, compare header line against list of aliases Loading @@ -1025,14 +1025,18 @@ static CURLcode readwrite_headers(struct SessionHandle *data, if(checkhttpprefix(data, k->p)) { nc = 1; k->httpcode = 200; k->httpversion = 10; conn->httpversion = 10; } } } if(nc) { data->info.httpcode = k->httpcode; data->info.httpversion = k->httpversion; data->info.httpversion = conn->httpversion; if (!data->state.httpversion || data->state.httpversion > conn->httpversion) /* store the lowest server version we encounter */ data->state.httpversion = conn->httpversion; /* * This code executes as part of processing the header. As a Loading Loading @@ -1060,14 +1064,14 @@ static CURLcode readwrite_headers(struct SessionHandle *data, } } if(k->httpversion == 10) { if(conn->httpversion == 10) { /* Default action for HTTP/1.0 must be to close, unless we get one of those fancy headers that tell us the server keeps it open for us! */ infof(data, "HTTP 1.0, assume close after body\n"); conn->bits.close = TRUE; } else if(k->httpversion >= 11 && else if(conn->httpversion >= 11 && !conn->bits.close) { /* If HTTP version is >= 1.1 and connection is persistent server supports pipelining. */ Loading Loading @@ -1161,7 +1165,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data, data->info.contenttype = contenttype; } } else if((k->httpversion == 10) && else if((conn->httpversion == 10) && conn->bits.httpproxy && Curl_compareheader(k->p, "Proxy-Connection:", "keep-alive")) { Loading @@ -1174,7 +1178,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data, conn->bits.close = FALSE; /* don't close when done */ infof(data, "HTTP/1.0 proxy connection set to keep alive!\n"); } else if((k->httpversion == 11) && else if((conn->httpversion == 11) && conn->bits.httpproxy && Curl_compareheader(k->p, "Proxy-Connection:", "close")) { Loading @@ -1185,7 +1189,7 @@ static CURLcode readwrite_headers(struct SessionHandle *data, conn->bits.close = TRUE; /* close when done */ infof(data, "HTTP/1.1 proxy connection set close!\n"); } else if((k->httpversion == 10) && else if((conn->httpversion == 10) && Curl_compareheader(k->p, "Connection:", "keep-alive")) { /* * A HTTP/1.0 reply with the 'Connection: keep-alive' line Loading Loading @@ -1886,6 +1890,7 @@ CURLcode Curl_pretransfer(struct SessionHandle *data) data->set.followlocation=0; /* reset the location-follow counter */ data->state.this_is_a_follow = FALSE; /* reset this */ data->state.errorbuf = FALSE; /* no error has occurred */ data->state.httpversion = 0; /* don't assume any particular server version */ data->state.authproblem = FALSE; data->state.authhost.want = data->set.httpauth; Loading