proxy: CONNECT trailers handling
No binary (build failed)
—
(log yok)
| @@ -220,3 +220,7 @@ answer to arrive before starting any connect attempt. | |
| When passing `--ssl-reqd`, clear it for the first URL in a curl command. | |
| This allows testing of connection reuse in mixed `STARTTLS` needs. | |
| + | |
| + | ## `CURL_DBG_SUPPRESS_CONNECT_HDS` |
| + | |
| + | Existence of this variable suppresses the collection of CONNECT headers. |
| @@ -135,7 +135,7 @@ static CURLcode tunnel_init(struct Curl_cfilter *cf, | |
| curlx_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS); | |
| curlx_dyn_init(&ts->request_data, DYN_HTTP_REQUEST); | |
| - | Curl_httpchunk_init(data, &ts->ch, TRUE); |
| + | Curl_httpchunk_init(data, &ts->ch, TRUE, TRUE); |
| *pts = ts; | |
| return tunnel_reinit(cf, data, ts); | |
| @@ -980,7 +980,7 @@ CURLcode Curl_cf_h1_proxy_insert_after(struct Curl_cfilter *cf_at, | |
| ts->httpversion = httpversion; | |
| curlx_dyn_init(&ts->rcvbuf, DYN_PROXY_CONNECT_HEADERS); | |
| curlx_dyn_init(&ts->request_data, DYN_HTTP_REQUEST); | |
| - | Curl_httpchunk_init(data, &ts->ch, TRUE); |
| + | Curl_httpchunk_init(data, &ts->ch, TRUE, TRUE); |
| pctx = curlx_calloc(1, sizeof(*pctx)); | |
| if(!pctx) { | |
| @@ -71,7 +71,7 @@ | |
| */ | |
| void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, | |
| - | bool ignore_body) |
| + | bool ignore_body, bool in_connect) |
| { | |
| (void)data; | |
| ch->hexindex = 0; /* start at 0 */ | |
| @@ -79,6 +79,7 @@ void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, | |
| ch->last_code = CHUNKE_OK; | |
| curlx_dyn_init(&ch->trailer, DYN_H1_TRAILER); | |
| ch->ignore_body = ignore_body; | |
| + | ch->in_connect = in_connect; |
| } | |
| void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch, | |
| @@ -268,16 +269,14 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data, | |
| } | |
| if(!data->set.http_te_skip) { | |
| + | int hd_type = CLIENTWRITE_HEADER | CLIENTWRITE_TRAILER; |
| + | if(ch->in_connect) |
| + | hd_type |= CLIENTWRITE_CONNECT; |
| if(cw_next) | |
| - | result = Curl_cwriter_write(data, cw_next, |
| - | CLIENTWRITE_HEADER | |
| - | CLIENTWRITE_TRAILER, |
| - | tr, trlen); |
| + | result = Curl_cwriter_write(data, cw_next, hd_type, tr, trlen); |
| else | |
| - | result = Curl_client_write(data, |
| - | CLIENTWRITE_HEADER | |
| - | CLIENTWRITE_TRAILER, |
| - | tr, trlen); |
| + | result = Curl_client_write(data, hd_type, tr, trlen); |
| + | CURL_TRC_WRITE(data, "wrote trailer '%s'", tr); |
| if(result) { | |
| ch->state = CHUNK_FAILED; | |
| ch->last_code = CHUNKE_PASSTHRU_ERROR; | |
| @@ -408,7 +407,7 @@ static CURLcode cw_chunked_init(struct Curl_easy *data, | |
| struct chunked_writer *ctx = writer->ctx; | |
| data->req.chunk = TRUE; /* chunks coming our way. */ | |
| - | Curl_httpchunk_init(data, &ctx->ch, FALSE); |
| + | Curl_httpchunk_init(data, &ctx->ch, FALSE, FALSE); |
| return CURLE_OK; | |
| } | |
| @@ -99,11 +99,12 @@ struct Curl_chunker { | |
| unsigned char hexindex; | |
| char hexbuffer[CHUNK_MAXNUM_LEN + 1]; /* +1 for null-terminator */ | |
| BIT(ignore_body); /* never write response body data */ | |
| + | BIT(in_connect); /* this is a CONNECT response body */ |
| }; | |
| /* The following functions are defined in http_chunks.c */ | |
| void Curl_httpchunk_init(struct Curl_easy *data, struct Curl_chunker *ch, | |
| - | bool ignore_body); |
| + | bool ignore_body, bool in_connect); |
| void Curl_httpchunk_free(struct Curl_easy *data, struct Curl_chunker *ch); | |
| void Curl_httpchunk_reset(struct Curl_easy *data, struct Curl_chunker *ch, | |
| bool ignore_body); | |
| @@ -189,6 +189,10 @@ static CURLcode cw_download_write(struct Curl_easy *data, | |
| if(!(type & CLIENTWRITE_BODY)) { | |
| if(is_connect && data->set.suppress_connect_headers) | |
| return CURLE_OK; | |
| + | #ifdef DEBUGBUILD |
| + | if(is_connect && getenv("CURL_DBG_SUPPRESS_CONNECT_HDS")) |
| + | return CURLE_OK; |
| + | #endif |
| result = Curl_cwriter_write(data, writer->next, type, buf, nbytes); | |
| CURL_TRC_WRITE(data, "download_write header(type=%x, blen=%zu) -> %d", | |
| (unsigned int)type, nbytes, (int)result); | |
| @@ -1940,7 +1940,10 @@ TESTCASES = \ | |
| test2309 \ | |
| test2310 \ | |
| test2311 \ | |
| + | test2349 \ |
| + | \ |
| test2397 \ | |
| + | \ |
| test2400 \ | |
| test2401 \ | |
| test2402 \ | |
| @@ -0,0 +1,63 @@ | |
| + | <?xml version="1.0" encoding="US-ASCII"?> |
| + | <testcase> |
| + | <info> |
| + | <keywords> |
| + | HTTP |
| + | HTTP GET |
| + | </keywords> |
| + | </info> |
| + | |
| + | <reply> |
| + | <connect> |
| + | HTTP/1.1 407 NoNoNo |
| + | Transfer-Encoding: chunked |
| + | Trailer: proxy-trailer |
| + | |
| + | 4 |
| + | aaaa |
| + | 0 |
| + | proxy-trailer: 12345 |
| + | |
| + | </connect> |
| + | </reply> |
| + | |
| + | # Client-side |
| + | <client> |
| + | <server> |
| + | http |
| + | http-proxy |
| + | </server> |
| + | <features> |
| + | proxy |
| + | Debug |
| + | </features> |
| + | <name> |
| + | HTTP CONNECT -D file |
| + | </name> |
| + | <setenv> |
| + | CURL_DBG_SUPPRESS_CONNECT_HDS=1 |
| + | </setenv> |
| + | <command option="no-output,no-include"> |
| + | http://%HOSTIP:%HTTPPORT/ --proxy %HOSTIP:%PROXYPORT --proxytunnel -sS -D %LOGDIR/heads%TESTNUMBER |
| + | </command> |
| + | </client> |
| + | |
| + | # Verify data after the test has been "shot" |
| + | <verify> |
| + | <errorcode> |
| + | 7 |
| + | </errorcode> |
| + | <proxy crlf="headers"> |
| + | CONNECT %HOSTIP:%HTTPPORT HTTP/1.1 |
| + | Host: %HOSTIP:%HTTPPORT |
| + | User-Agent: curl/%VERSION |
| + | Proxy-Connection: Keep-Alive |
| + | |
| + | </proxy> |
| + | |
| + | # Header file is empty, as CONNECT headers were suppress by DEBUG env var |
| + | <file name="%LOGDIR/heads%TESTNUMBER"> |
| + | </file> |
| + | |
| + | </verify> |
| + | </testcase> |