mirror of
https://github.com/moparisthebest/curl
synced 2024-12-22 08:08:50 -05:00
http2: Don't send header fields prohibited by HTTP/2 spec
Previously, we just ignored "Connection" header field. But HTTP/2 specification actually prohibits few more header fields. This commit ignores all of them so that we don't send these bad header fields. Bug: https://curl.haxx.se/mail/archive-2016-10/0033.html Reported-by: Ricki Hirner Closes https://github.com/curl/curl/pull/1092
This commit is contained in:
parent
677d8b3fec
commit
0269f6446d
89
lib/http2.c
89
lib/http2.c
@ -1572,6 +1572,71 @@ static ssize_t http2_recv(struct connectdata *conn, int sockindex,
|
|||||||
#define HEADER_OVERFLOW(x) \
|
#define HEADER_OVERFLOW(x) \
|
||||||
(x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen)
|
(x.namelen > (uint16_t)-1 || x.valuelen > (uint16_t)-1 - x.namelen)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check header memory for the token "trailers".
|
||||||
|
* Parse the tokens as separated by comma and surrounded by whitespace.
|
||||||
|
* Returns TRUE if found or FALSE if not.
|
||||||
|
*/
|
||||||
|
static bool contains_trailers(const char *p, size_t len) {
|
||||||
|
const char *end = p + len;
|
||||||
|
for(;;) {
|
||||||
|
for(; p != end && (*p == ' ' || *p == '\t'); ++p)
|
||||||
|
;
|
||||||
|
if(p == end || (size_t)(end - p) < sizeof("trailers") - 1)
|
||||||
|
return FALSE;
|
||||||
|
if(strncasecompare("trailers", p, sizeof("trailers") - 1)) {
|
||||||
|
p += sizeof("trailers") - 1;
|
||||||
|
for(; p != end && (*p == ' ' || *p == '\t'); ++p)
|
||||||
|
;
|
||||||
|
if(p == end || *p == ',')
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
/* skip to next token */
|
||||||
|
for(; p != end && *p != ','; ++p)
|
||||||
|
;
|
||||||
|
if(p == end)
|
||||||
|
return FALSE;
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
/* Send header to server */
|
||||||
|
HEADERINST_FORWARD,
|
||||||
|
/* Don't send header to server */
|
||||||
|
HEADERINST_IGNORE,
|
||||||
|
/* Discard header, and replace it with "te: trailers" */
|
||||||
|
HEADERINST_TE_TRAILERS
|
||||||
|
} header_instruction;
|
||||||
|
|
||||||
|
/* Decides how to treat given header field. */
|
||||||
|
static header_instruction inspect_header(const char *name, size_t namelen,
|
||||||
|
const char *value, size_t valuelen) {
|
||||||
|
switch(namelen) {
|
||||||
|
case 2:
|
||||||
|
if(!strncasecompare("te", name, namelen))
|
||||||
|
return HEADERINST_FORWARD;
|
||||||
|
|
||||||
|
return contains_trailers(value, valuelen) ?
|
||||||
|
HEADERINST_TE_TRAILERS : HEADERINST_IGNORE;
|
||||||
|
case 7:
|
||||||
|
return strncasecompare("upgrade", name, namelen) ?
|
||||||
|
HEADERINST_IGNORE : HEADERINST_FORWARD;
|
||||||
|
case 10:
|
||||||
|
return (strncasecompare("connection", name, namelen) ||
|
||||||
|
strncasecompare("keep-alive", name, namelen)) ?
|
||||||
|
HEADERINST_IGNORE : HEADERINST_FORWARD;
|
||||||
|
case 16:
|
||||||
|
return strncasecompare("proxy-connection", name, namelen) ?
|
||||||
|
HEADERINST_IGNORE : HEADERINST_FORWARD;
|
||||||
|
case 17:
|
||||||
|
return strncasecompare("transfer-encoding", name, namelen) ?
|
||||||
|
HEADERINST_IGNORE : HEADERINST_FORWARD;
|
||||||
|
default:
|
||||||
|
return HEADERINST_FORWARD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
||||||
const void *mem, size_t len, CURLcode *err)
|
const void *mem, size_t len, CURLcode *err)
|
||||||
{
|
{
|
||||||
@ -1725,7 +1790,6 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
|||||||
i = 3;
|
i = 3;
|
||||||
while(i < nheader) {
|
while(i < nheader) {
|
||||||
size_t hlen;
|
size_t hlen;
|
||||||
int skip = 0;
|
|
||||||
|
|
||||||
hdbuf = line_end + 2;
|
hdbuf = line_end + 2;
|
||||||
|
|
||||||
@ -1743,12 +1807,7 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
|||||||
goto fail;
|
goto fail;
|
||||||
hlen = end - hdbuf;
|
hlen = end - hdbuf;
|
||||||
|
|
||||||
if(hlen == 10 && strncasecompare("connection", hdbuf, 10)) {
|
if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
|
||||||
/* skip Connection: headers! */
|
|
||||||
skip = 1;
|
|
||||||
--nheader;
|
|
||||||
}
|
|
||||||
else if(hlen == 4 && strncasecompare("host", hdbuf, 4)) {
|
|
||||||
authority_idx = i;
|
authority_idx = i;
|
||||||
nva[i].name = (unsigned char *)":authority";
|
nva[i].name = (unsigned char *)":authority";
|
||||||
nva[i].namelen = strlen((char *)nva[i].name);
|
nva[i].namelen = strlen((char *)nva[i].name);
|
||||||
@ -1761,9 +1820,22 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
|||||||
while(*hdbuf == ' ' || *hdbuf == '\t')
|
while(*hdbuf == ' ' || *hdbuf == '\t')
|
||||||
++hdbuf;
|
++hdbuf;
|
||||||
end = line_end;
|
end = line_end;
|
||||||
if(!skip) {
|
|
||||||
|
switch(inspect_header((const char *)nva[i].name, nva[i].namelen, hdbuf,
|
||||||
|
end - hdbuf)) {
|
||||||
|
case HEADERINST_IGNORE:
|
||||||
|
/* skip header fields prohibited by HTTP/2 specification. */
|
||||||
|
--nheader;
|
||||||
|
continue;
|
||||||
|
case HEADERINST_TE_TRAILERS:
|
||||||
|
nva[i].value = (uint8_t*)"trailers";
|
||||||
|
nva[i].valuelen = sizeof("trailers") - 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
nva[i].value = (unsigned char *)hdbuf;
|
nva[i].value = (unsigned char *)hdbuf;
|
||||||
nva[i].valuelen = (size_t)(end - hdbuf);
|
nva[i].valuelen = (size_t)(end - hdbuf);
|
||||||
|
}
|
||||||
|
|
||||||
nva[i].flags = NGHTTP2_NV_FLAG_NONE;
|
nva[i].flags = NGHTTP2_NV_FLAG_NONE;
|
||||||
if(HEADER_OVERFLOW(nva[i])) {
|
if(HEADER_OVERFLOW(nva[i])) {
|
||||||
failf(conn->data, "Failed sending HTTP request: Header overflow");
|
failf(conn->data, "Failed sending HTTP request: Header overflow");
|
||||||
@ -1771,7 +1843,6 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex,
|
|||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* :authority must come before non-pseudo header fields */
|
/* :authority must come before non-pseudo header fields */
|
||||||
if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
|
if(authority_idx != 0 && authority_idx != AUTHORITY_DST_IDX) {
|
||||||
|
Loading…
Reference in New Issue
Block a user