From 0023fce38d3bd6ee0e9b6ff8708fee1195057846 Mon Sep 17 00:00:00 2001 From: Barry Pollard Date: Sun, 22 Sep 2019 21:17:12 +0100 Subject: [PATCH] http: lowercase headernames for HTTP/2 and HTTP/3 Closes #4401 Fixes #4400 --- lib/http2.c | 4 ++- lib/strcase.c | 84 ++++++++++++++++++++++++++++++++++++++++++++++ lib/strcase.h | 2 ++ lib/vquic/ngtcp2.c | 4 ++- lib/vquic/quiche.c | 4 ++- 5 files changed, 95 insertions(+), 3 deletions(-) diff --git a/lib/http2.c b/lib/http2.c index 47583265d4..b33782cc38 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -2026,8 +2026,10 @@ static ssize_t http2_send(struct connectdata *conn, int sockindex, nva[i].namelen = strlen((char *)nva[i].name); } else { - nva[i].name = (unsigned char *)hdbuf; nva[i].namelen = (size_t)(end - hdbuf); + /* Lower case the header name for HTTP/2 */ + Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen); + nva[i].name = (unsigned char *)hdbuf; } hdbuf = end + 1; while(*hdbuf == ' ' || *hdbuf == '\t') diff --git a/lib/strcase.c b/lib/strcase.c index 24bcca9327..098cec7a8f 100644 --- a/lib/strcase.c +++ b/lib/strcase.c @@ -93,6 +93,75 @@ char Curl_raw_toupper(char in) return in; } + +/* Portable, consistent tolower (remember EBCDIC). Do not use tolower() because + its behavior is altered by the current locale. */ +char Curl_raw_tolower(char in) +{ +#if !defined(CURL_DOES_CONVERSIONS) + if(in >= 'A' && in <= 'Z') + return (char)('a' + in - 'A'); +#else + switch(in) { + case 'A': + return 'a'; + case 'B': + return 'b'; + case 'C': + return 'c'; + case 'D': + return 'd'; + case 'E': + return 'e'; + case 'F': + return 'f'; + case 'G': + return 'g'; + case 'H': + return 'h'; + case 'I': + return 'i'; + case 'J': + return 'j'; + case 'K': + return 'k'; + case 'L': + return 'l'; + case 'M': + return 'm'; + case 'N': + return 'n'; + case 'O': + return 'o'; + case 'P': + return 'p'; + case 'Q': + return 'q'; + case 'R': + return 'r'; + case 'S': + return 's'; + case 'T': + return 't'; + case 'U': + return 'u'; + case 'V': + return 'v'; + case 'W': + return 'w'; + case 'X': + return 'X'; + case 'Y': + return 'y'; + case 'Z': + return 'z'; + } +#endif + + return in; +} + + /* * Curl_strcasecompare() is for doing "raw" case insensitive strings. This is * meant to be locale independent and only compare strings we know are safe @@ -165,6 +234,21 @@ void Curl_strntoupper(char *dest, const char *src, size_t n) } while(*src++ && --n); } +/* Copy a lower case version of the string from src to dest. The + * strings may overlap. No more than n characters of the string are copied + * (including any NUL) and the destination string will NOT be + * NUL-terminated if that limit is reached. + */ +void Curl_strntolower(char *dest, const char *src, size_t n) +{ + if(n < 1) + return; + + do { + *dest++ = Curl_raw_tolower(*src); + } while(*src++ && --n); +} + /* --- public functions --- */ int curl_strequal(const char *first, const char *second) diff --git a/lib/strcase.h b/lib/strcase.h index 6fee3840e6..2f07a74c92 100644 --- a/lib/strcase.h +++ b/lib/strcase.h @@ -40,11 +40,13 @@ int Curl_safe_strcasecompare(const char *first, const char *second); int Curl_strncasecompare(const char *first, const char *second, size_t max); char Curl_raw_toupper(char in); +char Curl_raw_tolower(char in); /* checkprefix() is a shorter version of the above, used when the first argument is zero-byte terminated */ #define checkprefix(a,b) curl_strnequal(a,b,strlen(a)) void Curl_strntoupper(char *dest, const char *src, size_t n); +void Curl_strntolower(char *dest, const char *src, size_t n); #endif /* HEADER_CURL_STRCASE_H */ diff --git a/lib/vquic/ngtcp2.c b/lib/vquic/ngtcp2.c index 5fd07f7e80..cdba49b75e 100644 --- a/lib/vquic/ngtcp2.c +++ b/lib/vquic/ngtcp2.c @@ -1201,8 +1201,10 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, nva[i].namelen = strlen((char *)nva[i].name); } else { - nva[i].name = (unsigned char *)hdbuf; nva[i].namelen = (size_t)(end - hdbuf); + /* Lower case the header name for HTTP/3 */ + Curl_strntolower((char *)hdbuf, hdbuf, nva[i].namelen); + nva[i].name = (unsigned char *)hdbuf; } nva[i].flags = NGHTTP3_NV_FLAG_NONE; hdbuf = end + 1; diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c index 4d53d15359..b5548cc2f3 100644 --- a/lib/vquic/quiche.c +++ b/lib/vquic/quiche.c @@ -646,8 +646,10 @@ static CURLcode http_request(struct connectdata *conn, const void *mem, nva[i].name_len = strlen((char *)nva[i].name); } else { - nva[i].name = (unsigned char *)hdbuf; nva[i].name_len = (size_t)(end - hdbuf); + /* Lower case the header name for HTTP/3 */ + Curl_strntolower((char *)hdbuf, hdbuf, nva[i].name_len); + nva[i].name = (unsigned char *)hdbuf; } hdbuf = end + 1; while(*hdbuf == ' ' || *hdbuf == '\t')