http: stop dropping large custom headers

Closes #22336
This commit is contained in:
Graham Campbell 2026-07-16 13:29:44 +01:00 committed by Daniel Stenberg
parent f0f84d1251
commit 5bb7d7a4f2
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
5 changed files with 126 additions and 10 deletions

View file

@ -175,7 +175,7 @@ static bool header_has_value(const char **headerp, struct Curl_str *outp)
(!curlx_str_single(headerp, ':') || !curlx_str_single(headerp, ';'));
if(value) {
curlx_str_untilnl(headerp, outp, MAX_HTTP_RESP_HEADER_SIZE);
curlx_str_cspn(headerp, outp, "\r\n");
curlx_str_trimblanks(outp);
}
return value;
@ -1415,7 +1415,7 @@ bool Curl_compareheader(const char *headerline, /* line to check */
/* pass the header */
p = &headerline[hlen];
if(curlx_str_untilnl(&p, &val, MAX_HTTP_RESP_HEADER_SIZE))
if(curlx_str_cspn(&p, &val, "\r\n"))
return FALSE;
curlx_str_trimblanks(&val);
@ -1432,7 +1432,7 @@ bool Curl_compareheader(const char *headerline, /* line to check */
!p[clen]))
return TRUE; /* match! */
/* advance to the next comma */
if(curlx_str_until(&p, &next, MAX_HTTP_RESP_HEADER_SIZE, ',') ||
if(curlx_str_until(&p, &next, len, ',') ||
curlx_str_single(&p, ','))
break; /* no comma, get out */
@ -1784,21 +1784,22 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
struct Curl_str name;
const char *p = headers->data;
const char *origp = p;
size_t hlen = strlen(origp);
/* explicitly asked to send header without content is done by a header
that ends with a semicolon, but there must be no colon present in the
name */
if(!curlx_str_until(&p, &name, MAX_HTTP_RESP_HEADER_SIZE, ';') &&
if(!curlx_str_until(&p, &name, hlen, ';') &&
!curlx_str_single(&p, ';') &&
!curlx_str_single(&p, '\0') &&
!memchr(curlx_str(&name), ':', curlx_strlen(&name)))
blankheader = TRUE;
else {
p = origp;
if(!curlx_str_until(&p, &name, MAX_HTTP_RESP_HEADER_SIZE, ':') &&
if(!curlx_str_until(&p, &name, hlen, ':') &&
!curlx_str_single(&p, ':')) {
struct Curl_str val;
curlx_str_untilnl(&p, &val, MAX_HTTP_RESP_HEADER_SIZE);
curlx_str_untilnl(&p, &val, hlen);
curlx_str_trimblanks(&val);
if(!curlx_strlen(&val))
/* no content, do not send this */
@ -1849,9 +1850,11 @@ CURLcode Curl_add_custom_headers(struct Curl_easy *data,
other hosts */
!Curl_auth_allowed_to_host(data))
;
else if(blankheader)
result = curlx_dyn_addf(req, "%.*s:\r\n", (int)curlx_strlen(&name),
curlx_str(&name));
else if(blankheader) {
result = curlx_dyn_addn(req, curlx_str(&name), curlx_strlen(&name));
if(!result)
result = curlx_dyn_addn(req, STRCONST(":\r\n"));
}
else
result = curlx_dyn_addf(req, "%s\r\n", origp);

View file

@ -284,7 +284,7 @@ test3100 test3101 test3102 test3103 test3104 test3105 test3106 \
test3200 test3201 test3202 test3203 test3204 test3205 test3206 test3207 \
test3208 test3209 test3210 test3211 test3212 test3213 test3214 test3215 \
test3216 test3217 test3218 test3219 test3220 test3221 test3222 \
test3223 test3224 test3225 test3226 test3227 \
test3223 test3224 test3225 test3226 test3227 test3228 test3229 \
\
test3300 test3301 test3302 test3303 test3304 test3305 \
\

58
tests/data/test3228 Normal file
View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="US-ASCII"?>
<testcase>
<info>
<keywords>
HTTP
HTTP GET
HTTP added headers
</keywords>
</info>
# Server-side
<reply>
<data>
HTTP/1.1 200 OK
Date: Tue, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
Content-Length: 6
Connection: close
-foo-
</data>
</reply>
# Client-side
<client>
<server>
http
</server>
<name>
Send custom request headers larger than the response header limit
</name>
<stdin>
header "X-Large: %repeat[307200 x x]%"
header "Connection: %repeat[307200 x x]%"
header "%repeat[307201 x X]%;"
</stdin>
<command>
-K - http://%HOSTIP:%HTTPPORT/%TESTNUMBER
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<protocol crlf="yes">
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
User-Agent: curl/%VERSION
Accept: */*
X-Large: %repeat[307200 x x]%
%repeat[307201 x X]%:
Connection: %repeat[307200 x x]%
</protocol>
<limits>
Maximum allocated: 4000000
</limits>
</verify>
</testcase>

37
tests/data/test3229 Normal file
View file

@ -0,0 +1,37 @@
<?xml version="1.0" encoding="US-ASCII"?>
<testcase>
<info>
<keywords>
HTTP
HTTP GET
HTTP added headers
</keywords>
</info>
# Client-side
<client>
<server>
http
</server>
<name>
Reject a custom request header larger than the request buffer
</name>
<stdin>
header "X-Large: %repeat[1048576 x x]%"
</stdin>
<command>
-K - http://%HOSTIP:%HTTPPORT/%TESTNUMBER
</command>
</client>
# Verify data after the test has been "shot"
<verify>
# 100 == CURLE_TOO_LARGE
<errorcode>
100
</errorcode>
<limits>
Maximum allocated: 6000000
</limits>
</verify>
</testcase>

View file

@ -38,7 +38,11 @@ static CURLcode test_unit1625(const char *arg)
{
UNITTEST_BEGIN_SIMPLE
char *large;
size_t i;
const size_t large_value_len = MAX_HTTP_RESP_HEADER_SIZE;
const size_t large_prefix_len = strlen("Encoding: ");
const size_t large_suffix_len = strlen(", chunked");
static const struct check1625 list[] = {
/* basic case */
{ "Encoding: gzip, chunked", "Encoding:", "chunked", TRUE },
@ -129,6 +133,20 @@ static CURLcode test_unit1625(const char *arg)
if(i != CURL_ARRAYSIZE(list))
return CURLE_FAILED_INIT;
large = curlx_malloc(large_prefix_len + large_value_len +
large_suffix_len + 1);
if(!large)
return CURLE_OUT_OF_MEMORY;
memcpy(large, "Encoding: ", large_prefix_len + 1);
memset(&large[large_prefix_len], 'a', large_value_len);
memcpy(&large[large_prefix_len + large_value_len], ", chunked",
large_suffix_len + 1);
fail_unless(Curl_compareheader(large, STRCONST("Encoding:"),
STRCONST("chunked")),
"token after 300 KiB was not found");
curlx_free(large);
UNITTEST_END_SIMPLE
}
#else /* CURL_DISABLE_HTTP */