From a186ecf4bf0c8ebb3a9a826155b3392164ec257a Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Tue, 24 Mar 2026 10:03:18 +0100 Subject: [PATCH] proxy: chunked response, error code Add test1715 to check proper handling of chunked transfer encoding in CONNECT responses. Change proxy error code from 56 (RECV_ERROR) for everything to 7 (COULDNT_CONNECT) when the server response could be read successfully, but establishing the connection is not possible (http status code wrong). Adapt several test expectations from 56 to 7. Closes #21084 --- lib/cf-h1-proxy.c | 25 ++++++++------- lib/cf-h2-proxy.c | 2 +- tests/data/Makefile.am | 2 +- tests/data/test1059 | 2 +- tests/data/test1715 | 54 ++++++++++++++++++++++++++++++++ tests/data/test217 | 4 +-- tests/data/test287 | 4 +-- tests/data/test302 | 2 +- tests/data/test440 | 2 +- tests/data/test441 | 2 +- tests/data/test493 | 2 +- tests/data/test718 | 2 +- tests/data/test749 | 4 +-- tests/data/test94 | 2 +- tests/http/test_13_proxy_auth.py | 4 +-- 15 files changed, 84 insertions(+), 29 deletions(-) create mode 100644 tests/data/test1715 diff --git a/lib/cf-h1-proxy.c b/lib/cf-h1-proxy.c index 36cb4eadb8..9e94e97e63 100644 --- a/lib/cf-h1-proxy.c +++ b/lib/cf-h1-proxy.c @@ -465,17 +465,7 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, if(ts->keepon == KEEPON_IGNORE) { /* This means we are currently ignoring a response-body */ - - if(ts->cl) { - /* A Content-Length based body: count down the counter - and make sure to break out of the loop when we are done! */ - ts->cl--; - if(ts->cl <= 0) { - ts->keepon = KEEPON_DONE; - break; - } - } - else if(ts->chunked_encoding) { + if(ts->chunked_encoding) { /* chunked-encoded body, so we need to do the chunked dance properly to know when the end of the body is reached */ size_t consumed = 0; @@ -491,6 +481,15 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf, ts->keepon = KEEPON_DONE; } } + else if(ts->cl) { + /* A Content-Length based body: count down the counter + and make sure to break out of the loop when we are done! */ + ts->cl--; + if(ts->cl <= 0) { + ts->keepon = KEEPON_DONE; + break; + } + } continue; } @@ -597,6 +596,8 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf, /* read what is there */ CURL_TRC_CF(data, cf, "CONNECT receive"); result = recv_CONNECT_resp(cf, data, ts, &done); + if(result) + CURL_TRC_CF(data, cf, "error receiving CONNECT response: %d", result); if(!result) result = Curl_pgrsUpdate(data); /* error or not complete yet. return for more multi-multi */ @@ -645,7 +646,7 @@ static CURLcode H1_CONNECT(struct Curl_cfilter *cf, Curl_safefree(data->req.newurl); h1_tunnel_go_state(cf, ts, H1_TUNNEL_FAILED, data); failf(data, "CONNECT tunnel failed, response %d", data->req.httpcode); - return CURLE_RECV_ERROR; + return CURLE_COULDNT_CONNECT; } /* 2xx response, SUCCESS! */ h1_tunnel_go_state(cf, ts, H1_TUNNEL_ESTABLISHED, data); diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index a9472b96c8..f836b05693 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -811,7 +811,7 @@ static CURLcode inspect_response(struct Curl_cfilter *cf, } /* Seems to have failed */ - return CURLE_RECV_ERROR; + return CURLE_COULDNT_CONNECT; } static CURLcode H2_CONNECT(struct Curl_cfilter *cf, diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 3f410fe763..f85d0b0723 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -229,7 +229,7 @@ test1670 test1671 test1672 test1673 \ test1680 test1681 test1682 test1683 test1684 \ \ test1700 test1701 test1702 test1703 test1704 test1705 test1706 test1707 \ -test1708 test1709 test1710 test1711 test1712 test1713 test1714 \ +test1708 test1709 test1710 test1711 test1712 test1713 test1714 test1715 \ \ test1800 test1801 test1802 test1847 test1848 test1849 test1850 test1851 \ \ diff --git a/tests/data/test1059 b/tests/data/test1059 index 63dbdf878f..c982ec3ac1 100644 --- a/tests/data/test1059 +++ b/tests/data/test1059 @@ -42,7 +42,7 @@ ftp://test-number:%TESTNUMBER/wanted/page -p -x %HOSTIP:%HTTPPORT # The server does not implement CONNECT for ftp, so this must be a failure test -56 +7 CONNECT test-number:%TESTNUMBER HTTP/1.1 diff --git a/tests/data/test1715 b/tests/data/test1715 new file mode 100644 index 0000000000..df50322a58 --- /dev/null +++ b/tests/data/test1715 @@ -0,0 +1,54 @@ + + + + +HTTP +HTTP GET +HTTP CONNECT +HTTP proxy +proxytunnel + + + + + + +HTTP/1.1 407 Proxy Authentication Required +Proxy-Authenticate: Special realm="none", nonce="abc123" +Content-Length: 13 +Transfer-Encoding: chunked +Magic-special: true + +some content + + + + + +http + + +proxy + + +HTTP CONNECT with proxy returning Content-Length and chunked + + +http://test.example --proxy http://%HOSTIP:%HTTPPORT --proxytunnel -sS + + + +# Verify data after the test has been "shot" + + +CONNECT test.example:80 HTTP/1.1 +Host: test.example:80 +User-Agent: curl/%VERSION +Proxy-Connection: Keep-Alive + + + +56 + + + diff --git a/tests/data/test217 b/tests/data/test217 index eae1303d67..a393700a05 100644 --- a/tests/data/test217 +++ b/tests/data/test217 @@ -49,9 +49,9 @@ User-Agent: curl/%VERSION Proxy-Connection: Keep-Alive -# CURLE_RECV_ERROR +# CURLE_COULDNT_CONNECT -56 +7 HTTP/1.1 405 Method Not Allowed swsclose diff --git a/tests/data/test287 b/tests/data/test287 index 00ae50bcb3..564b8ce99a 100644 --- a/tests/data/test287 +++ b/tests/data/test287 @@ -45,9 +45,9 @@ Proxy-Connection: Keep-Alive User-Agent: looser/2007 -# CURLE_RECV_ERROR +# CURLE_COULDNT_CONNECT -56 +7 HTTP/1.1 405 Method Not Allowed swsclose diff --git a/tests/data/test302 b/tests/data/test302 index 5a68c1dd4b..1bae0c7641 100644 --- a/tests/data/test302 +++ b/tests/data/test302 @@ -41,7 +41,7 @@ HTTPS GET over HTTP proxy fails # Verify data after the test has been "shot" -56 +7 diff --git a/tests/data/test440 b/tests/data/test440 index ea4a0e224b..3ed08f4730 100644 --- a/tests/data/test440 +++ b/tests/data/test440 @@ -72,7 +72,7 @@ https://this.hsts.example./%TESTNUMBER # Proxy CONNECT aborted -56 +7 Allocations: 160 diff --git a/tests/data/test441 b/tests/data/test441 index 497ec7d7a1..9574233302 100644 --- a/tests/data/test441 +++ b/tests/data/test441 @@ -71,7 +71,7 @@ https://this.hsts.example/%TESTNUMBER # Proxy CONNECT aborted -56 +7 diff --git a/tests/data/test493 b/tests/data/test493 index 1193dbd971..7c882c5600 100644 --- a/tests/data/test493 +++ b/tests/data/test493 @@ -70,7 +70,7 @@ https://this.hsts.example/%TESTNUMBER # Proxy CONNECT aborted -56 +7 diff --git a/tests/data/test718 b/tests/data/test718 index f9a1a6d8de..0555c20d19 100644 --- a/tests/data/test718 +++ b/tests/data/test718 @@ -56,7 +56,7 @@ Proxy-Connection: Keep-Alive -56 +7 diff --git a/tests/data/test749 b/tests/data/test749 index 86e15f8b50..1a86e09fb3 100644 --- a/tests/data/test749 +++ b/tests/data/test749 @@ -53,10 +53,10 @@ Proxy-Connection: Keep-Alive -56 +7 -curl: (56) CONNECT tunnel failed, response 400 +curl: (7) CONNECT tunnel failed, response 400 diff --git a/tests/data/test94 b/tests/data/test94 index 9824c745c1..bca0a8e1cc 100644 --- a/tests/data/test94 +++ b/tests/data/test94 @@ -41,7 +41,7 @@ https://test.anything.really.com:%TESTNUMBER --proxy1.0 %HOSTIP:%HTTPPORT # Verify data after the test has been "shot" -56 +7 CONNECT test.anything.really.com:%TESTNUMBER HTTP/1.0 diff --git a/tests/http/test_13_proxy_auth.py b/tests/http/test_13_proxy_auth.py index 33fb211e99..0d7e744dca 100644 --- a/tests/http/test_13_proxy_auth.py +++ b/tests/http/test_13_proxy_auth.py @@ -104,7 +104,7 @@ class TestProxyAuth: r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, extra_args=xargs) # expect "COULD_NOT_CONNECT" - r.check_response(exitcode=56, http_status=None) + r.check_response(exitcode=7, http_status=None) def test_13_06_tunnel_http_auth(self, env: Env, httpd, configures_httpd): self.httpd_configure(env, httpd) @@ -133,7 +133,7 @@ class TestProxyAuth: r = curl.http_download(urls=[url], alpn_proto=proto, with_stats=True, extra_args=xargs) # expect "COULD_NOT_CONNECT" - r.check_response(exitcode=56, http_status=None) + r.check_response(exitcode=7, http_status=None) assert self.get_tunnel_proto_used(r) == tunnel @pytest.mark.skipif(condition=not Env.have_nghttpx(), reason="no nghttpx available")