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
This commit is contained in:
Stefan Eissing 2026-03-24 10:03:18 +01:00 committed by Daniel Stenberg
parent 39036c9021
commit a186ecf4bf
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2
15 changed files with 84 additions and 29 deletions

View File

@ -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);

View File

@ -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,

View File

@ -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 \
\

View File

@ -42,7 +42,7 @@ ftp://test-number:%TESTNUMBER/wanted/page -p -x %HOSTIP:%HTTPPORT
<verify>
# The server does not implement CONNECT for ftp, so this must be a failure test
<errorcode>
56
7
</errorcode>
<protocol crlf="headers">
CONNECT test-number:%TESTNUMBER HTTP/1.1

54
tests/data/test1715 Normal file
View File

@ -0,0 +1,54 @@
<?xml version="1.0" encoding="US-ASCII"?>
<testcase>
<info>
<keywords>
HTTP
HTTP GET
HTTP CONNECT
HTTP proxy
proxytunnel
</keywords>
</info>
<reply>
<connect crlf="headers">
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
</connect>
</reply>
<client>
<server>
http
</server>
<features>
proxy
</features>
<name>
HTTP CONNECT with proxy returning Content-Length and chunked
</name>
<command>
http://test.example --proxy http://%HOSTIP:%HTTPPORT --proxytunnel -sS
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<protocol crlf="headers">
CONNECT test.example:80 HTTP/1.1
Host: test.example:80
User-Agent: curl/%VERSION
Proxy-Connection: Keep-Alive
</protocol>
<errorcode>
56
</errorcode>
</verify>
</testcase>

View File

@ -49,9 +49,9 @@ User-Agent: curl/%VERSION
Proxy-Connection: Keep-Alive
</protocol>
# CURLE_RECV_ERROR
# CURLE_COULDNT_CONNECT
<errorcode>
56
7
</errorcode>
<stdout crlf="headers">
HTTP/1.1 405 Method Not Allowed swsclose

View File

@ -45,9 +45,9 @@ Proxy-Connection: Keep-Alive
User-Agent: looser/2007
</protocol>
# CURLE_RECV_ERROR
# CURLE_COULDNT_CONNECT
<errorcode>
56
7
</errorcode>
<stdout crlf="headers">
HTTP/1.1 405 Method Not Allowed swsclose

View File

@ -41,7 +41,7 @@ HTTPS GET over HTTP proxy fails
# Verify data after the test has been "shot"
<verify>
<errorcode>
56
7
</errorcode>
<data>
</data>

View File

@ -72,7 +72,7 @@ https://this.hsts.example./%TESTNUMBER
</stdout>
# Proxy CONNECT aborted
<errorcode>
56
7
</errorcode>
<limits>
Allocations: 160

View File

@ -71,7 +71,7 @@ https://this.hsts.example/%TESTNUMBER
</stdout>
# Proxy CONNECT aborted
<errorcode>
56
7
</errorcode>
</verify>
</testcase>

View File

@ -70,7 +70,7 @@ https://this.hsts.example/%TESTNUMBER
</stdout>
# Proxy CONNECT aborted
<errorcode>
56
7
</errorcode>
</verify>
</testcase>

View File

@ -56,7 +56,7 @@ Proxy-Connection: Keep-Alive
</protocol>
<errorcode>
56
7
</errorcode>
</verify>
</testcase>

View File

@ -53,10 +53,10 @@ Proxy-Connection: Keep-Alive
</protocol>
<errorcode>
56
7
</errorcode>
<stderr mode="text">
curl: (56) CONNECT tunnel failed, response 400
curl: (7) CONNECT tunnel failed, response 400
</stderr>
</verify>
</testcase>

View File

@ -41,7 +41,7 @@ https://test.anything.really.com:%TESTNUMBER --proxy1.0 %HOSTIP:%HTTPPORT
# Verify data after the test has been "shot"
<verify>
<errorcode>
56
7
</errorcode>
<protocol crlf="headers">
CONNECT test.anything.really.com:%TESTNUMBER HTTP/1.0

View File

@ -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")