← Commit list

dc6adf3cb7

Stefan Eissing
Stefan Eissing
2026-08-27
SUCCESS Duration: 417s

Subject

proxy: CONNECT trailers handling

Binary

No binary (build failed)

Architecture & Compiler Flags

Architecture: x86_64-linux-gnu Compiler: gcc (Ubuntu 11.4.0-1ubuntu1~22.04.3) 11.4.0

—

Build Log

(log yok)

Commit Diff GitHub →

docs/libcurl/libcurl-env-dbg.md+4 -0
@@ -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.
lib/cf-h1-proxy.c+2 -2
@@ -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) {
lib/http_chunks.c+9 -10
@@ -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;
}
lib/http_chunks.h+2 -1
@@ -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);
lib/sendf.c+4 -0
@@ -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);
tests/data/Makefile.am+3 -0
@@ -1940,7 +1940,10 @@ TESTCASES = \
test2309 \
test2310 \
test2311 \
+ test2349 \
+ \
test2397 \
+ \
test2400 \
test2401 \
test2402 \
tests/data/test2349+63 -0
@@ -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>