From 119364741ef2ca0931c0ceaa6f92cb476457863c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 2 Oct 2007 10:21:36 +0000 Subject: known bug #46: chunked-encoded CONNECT responses from a http proxy now works. Added test case 1008 to verify. Note that #47 is still there. --- lib/http.c | 169 +++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 120 insertions(+), 49 deletions(-) (limited to 'lib/http.c') diff --git a/lib/http.c b/lib/http.c index 67b2d3f55..90f56f1ba 100644 --- a/lib/http.c +++ b/lib/http.c @@ -1143,6 +1143,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, curl_socket_t tunnelsocket = conn->sock[sockindex]; curl_off_t cl=0; bool closeConnection = FALSE; + bool chunked_encoding = FALSE; long check; #define SELECT_OK 0 @@ -1203,37 +1204,37 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, data->set.str[STRING_USERAGENT]) useragent = conn->allocptr.uagent; - /* 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:"", - useragent, - proxyconn); - - if(host && *host) - free(host); - - if(CURLE_OK == result) - result = add_custom_headers(conn, req_buffer); - - 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, 0, sockindex); - } + /* 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:"", + useragent, + proxyconn); + + if(host && *host) + free(host); + + if(CURLE_OK == result) + result = add_custom_headers(conn, req_buffer); + + 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, 0, sockindex); + } req_buffer = NULL; if(result) failf(data, "Failed sending CONNECT to proxy"); @@ -1340,13 +1341,33 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, nread += gotbytes; if(keepon > TRUE) { - /* This means we are currently ignoring a response-body, so we - simply count down our counter and make sure to break out of - the loop when we're done! */ - cl -= gotbytes; - if(cl<=0) { - keepon = FALSE; - break; + /* This means we are currently ignoring a response-body */ + if(cl) { + /* A Content-Length based body: simply count down the counter + and make sure to break out of the loop when we're done! */ + cl -= gotbytes; + if(cl<=0) { + keepon = FALSE; + break; + } + } + else { + /* chunked-encoded body, so we need to do the chunked dance + properly to know when the end of the body is reached */ + CHUNKcode r; + ssize_t tookcareof=0; + + /* now parse the chunked piece of data so that we can + properly tell when the stream ends */ + r = Curl_httpchunk_read(conn, ptr, gotbytes, &tookcareof); + if(r == CHUNKE_STOP) { + /* we're done reading chunks! */ + infof(data, "chunk reading DONE\n"); + keepon = FALSE; + } + else + infof(data, "Read %d bytes of chunk, continue\n", + tookcareof); } } else @@ -1366,7 +1387,8 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(data->set.include_header) writetype |= CLIENTWRITE_BODY; - result = Curl_client_write(conn, writetype, line_start, perline); + result = Curl_client_write(conn, writetype, line_start, + perline); if(result) return result; @@ -1377,19 +1399,60 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, if(('\r' == line_start[0]) || ('\n' == line_start[0])) { /* end of response-headers from the proxy */ - if(cl && (407 == k->httpcode) && - !data->state.authproblem) { + if((407 == k->httpcode) && !data->state.authproblem) { /* If we get a 407 response code with content length - * when we have no auth problem, we must ignore the - * whole response-body */ + when we have no auth problem, we must ignore the + whole response-body */ keepon = 2; - infof(data, "Ignore %" FORMAT_OFF_T - " bytes of response-body\n", cl); - cl -= (gotbytes - i);/* remove the remaining chunk of - what we already read */ - if(cl<=0) - /* if the whole thing was already read, we are done! */ + + if(cl) { + + infof(data, "Ignore %" FORMAT_OFF_T + " bytes of response-body\n", cl); + /* remove the remaining chunk of what we already + read */ + cl -= (gotbytes - i); + + if(cl<=0) + /* if the whole thing was already read, we are done! + */ + keepon=FALSE; + } + else if(chunked_encoding) { + CHUNKcode r; + /* We set ignorebody true here since the chunked + decoder function will acknowledge that. Pay + attention so that this is cleared again when this + function returns! */ + k->ignorebody = TRUE; + infof(data, "%d bytes of chunk left\n", gotbytes-i); + + if(line_start[1] == '\n') { + /* this can only be a LF if the letter at index 0 + was a CR */ + line_start++; + i++; + } + + /* now parse the chunked piece of data so that we can + properly tell when the stream ends */ + r = Curl_httpchunk_read(conn, line_start+1, + gotbytes -i, &gotbytes); + if(r == CHUNKE_STOP) { + /* we're done reading chunks! */ + infof(data, "chunk reading DONE\n"); + keepon = FALSE; + } + else + infof(data, "Read %d bytes of chunk, continue\n", + gotbytes); + } + else { + /* without content-length or chunked encoding, we + can't keep the connection alive since the close is + the end signal so we bail out at once instead */ keepon=FALSE; + } } else keepon = FALSE; @@ -1415,6 +1478,13 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, else if(Curl_compareheader(line_start, "Connection:", "close")) closeConnection = TRUE; + else if(Curl_compareheader(line_start, + "Transfer-Encoding:", "chunked")) { + infof(data, "CONNECT responded chunked\n"); + chunked_encoding = TRUE; + /* init our chunky engine */ + Curl_httpchunk_init(conn); + } else if(Curl_compareheader(line_start, "Proxy-Connection:", "close")) closeConnection = TRUE; @@ -1472,6 +1542,7 @@ CURLcode Curl_proxyCONNECT(struct connectdata *conn, data->state.authproxy.done = TRUE; infof (data, "Proxy replied OK to CONNECT request\n"); + k->ignorebody = FALSE; /* put it (back) to non-ignore state */ return CURLE_OK; } -- cgit v1.2.3