mirror of
https://github.com/curl/curl.git
synced 2026-08-24 22:43:38 +03:00
http: fix HTTP/2 handling of TE request header using "trailers"
A "TE" request header is allowed in HTTP/2 when it only carries the "trailers" value. RFC 9113 ch. 8.2.2. Check client supplied TE values for the "trailers" token and only pass that one in a HTTP/2 request. Add test_01_17 to verify. Fixes #17122 Reported-by: epicmkirzinger on github Closes #17128
This commit is contained in:
parent
ebe6612505
commit
1d66a769d7
3 changed files with 67 additions and 7 deletions
49
lib/http.c
49
lib/http.c
|
|
@ -4445,7 +4445,6 @@ struct name_const {
|
|||
|
||||
/* keep them sorted by length! */
|
||||
static struct name_const H2_NON_FIELD[] = {
|
||||
{ STRCONST("TE") },
|
||||
{ STRCONST("Host") },
|
||||
{ STRCONST("Upgrade") },
|
||||
{ STRCONST("Connection") },
|
||||
|
|
@ -4454,15 +4453,44 @@ static struct name_const H2_NON_FIELD[] = {
|
|||
{ STRCONST("Transfer-Encoding") },
|
||||
};
|
||||
|
||||
static bool h2_non_field(const char *name, size_t namelen)
|
||||
static bool h2_permissible_field(struct dynhds_entry *e)
|
||||
{
|
||||
size_t i;
|
||||
for(i = 0; i < CURL_ARRAYSIZE(H2_NON_FIELD); ++i) {
|
||||
if(namelen < H2_NON_FIELD[i].namelen)
|
||||
return FALSE;
|
||||
if(namelen == H2_NON_FIELD[i].namelen &&
|
||||
strcasecompare(H2_NON_FIELD[i].name, name))
|
||||
if(e->namelen < H2_NON_FIELD[i].namelen)
|
||||
return TRUE;
|
||||
if(e->namelen == H2_NON_FIELD[i].namelen &&
|
||||
strcasecompare(H2_NON_FIELD[i].name, e->name))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static bool http_TE_has_token(const char *fvalue, const char *token)
|
||||
{
|
||||
while(*fvalue) {
|
||||
struct Curl_str name;
|
||||
|
||||
/* skip to first token */
|
||||
while(ISBLANK(*fvalue) || *fvalue == ',')
|
||||
fvalue++;
|
||||
if(Curl_str_cspn(&fvalue, &name, " \t\r;,"))
|
||||
return FALSE;
|
||||
if(Curl_str_casecompare(&name, token))
|
||||
return TRUE;
|
||||
|
||||
/* skip any remainder after token, e.g. parameters with quoted strings */
|
||||
while(*fvalue && *fvalue != ',') {
|
||||
if(*fvalue == '"') {
|
||||
struct Curl_str qw;
|
||||
/* if we do not cleanly find a quoted word here, the header value
|
||||
* does not follow HTTP syntax and we reject */
|
||||
if(Curl_str_quotedword(&fvalue, &qw, CURL_MAX_HTTP_HEADER))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
fvalue++;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -4521,7 +4549,14 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers,
|
|||
}
|
||||
for(i = 0; !result && i < Curl_dynhds_count(&req->headers); ++i) {
|
||||
e = Curl_dynhds_getn(&req->headers, i);
|
||||
if(!h2_non_field(e->name, e->namelen)) {
|
||||
/* "TE" is special in that it is only permissible when it
|
||||
* has only value "trailers". RFC 9113 ch. 8.2.2 */
|
||||
if(e->namelen == 2 && strcasecompare("TE", e->name)) {
|
||||
if(http_TE_has_token(e->value, "trailers"))
|
||||
result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
|
||||
"trailers", sizeof("trailers") - 1);
|
||||
}
|
||||
else if(h2_permissible_field(e)) {
|
||||
result = Curl_dynhds_add(h2_headers, e->name, e->namelen,
|
||||
e->value, e->valuelen);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue