diff --git a/lib/http.c b/lib/http.c index f8ca40b0a4..cf9177922d 100644 --- a/lib/http.c +++ b/lib/http.c @@ -3808,8 +3808,8 @@ static CURLcode http_size(struct Curl_easy *data) return CURLE_OK; } -static CURLcode verify_header(struct Curl_easy *data, - const char *hd, size_t hdlen) +CURLcode Curl_verify_header(struct Curl_easy *data, + const char *hd, size_t hdlen) { struct SingleRequest *k = &data->req; const char *ptr = memchr(hd, 0x00, hdlen); @@ -4359,7 +4359,7 @@ static CURLcode http_rw_hd(struct Curl_easy *data, } } - result = verify_header(data, hd, hdlen); + result = Curl_verify_header(data, hd, hdlen); if(result) return result; diff --git a/lib/http.h b/lib/http.h index ed93d265e3..5050215743 100644 --- a/lib/http.h +++ b/lib/http.h @@ -106,6 +106,11 @@ CURLcode Curl_http_write_resp_hd(struct Curl_easy *data, const char *hd, size_t hdlen, bool is_eos); +/* check a received header line for forbidden bytes/format, the same checks + applied to regular response headers */ +CURLcode Curl_verify_header(struct Curl_easy *data, + const char *hd, size_t hdlen); + /* These functions are in http.c */ CURLcode Curl_http_input_auth(struct Curl_easy *data, bool proxy, const char *auth); diff --git a/lib/http_chunks.c b/lib/http_chunks.c index aa45c79e38..9e3e3bd1fe 100644 --- a/lib/http_chunks.c +++ b/lib/http_chunks.c @@ -27,6 +27,7 @@ #include "urldata.h" /* it includes http_chunks.h */ #include "curl_trc.h" +#include "http.h" /* for Curl_verify_header */ #include "sendf.h" /* for the client write stuff */ #include "curlx/dynbuf.h" #include "multiif.h" @@ -247,6 +248,7 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data, there was no trailer and we move on */ if(tr) { + size_t trlen; result = curlx_dyn_addn(&ch->trailer, STRCONST("\x0d\x0a")); if(result) { ch->state = CHUNK_FAILED; @@ -254,8 +256,18 @@ static CURLcode httpchunk_readwrite(struct Curl_easy *data, return result; } tr = curlx_dyn_ptr(&ch->trailer); + trlen = curlx_dyn_len(&ch->trailer); + + /* a trailer is delivered to the client as a header, so it must pass + the same checks as a regular response header */ + result = Curl_verify_header(data, tr, trlen); + if(result) { + ch->state = CHUNK_FAILED; + ch->last_code = CHUNKE_BAD_CHUNK; + return result; + } + if(!data->set.http_te_skip) { - size_t trlen = curlx_dyn_len(&ch->trailer); if(cw_next) result = Curl_cwriter_write(data, cw_next, CLIENTWRITE_HEADER | diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 211c96f846..1fb219832e 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -253,7 +253,7 @@ test2064 test2065 test2066 test2067 test2068 test2069 test2070 test2071 \ test2072 test2073 test2074 test2075 test2076 test2077 test2078 test2079 \ test2080 test2081 test2082 test2083 test2084 test2085 test2086 test2087 \ test2088 test2089 test2090 test2091 test2092 \ -test2100 test2101 test2102 test2103 test2104 test2105 \ +test2100 test2101 test2102 test2103 test2104 test2105 test2106 \ \ test2200 test2201 test2202 test2203 test2204 test2205 test2206 test2207 \ \ diff --git a/tests/data/test2106 b/tests/data/test2106 new file mode 100644 index 0000000000..40d2dc8b62 --- /dev/null +++ b/tests/data/test2106 @@ -0,0 +1,53 @@ + + + + +HTTP +HTTP GET +chunked Transfer-Encoding + + + +# Server-side + + +HTTP/1.1 200 OK%CR +Server: test%CR +Transfer-Encoding: chunked%CR +Trailer: chunky-trailer%CR +%CR +6%CR +-foo-%CR +0%CR +chunky-trailer: he%hex[%00]hex%llo%CR +%CR + + + +# Client-side + + +http + + +HTTP chunked response with a nul byte in the trailer + + +http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# Verify data after the test has been "shot" + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +User-Agent: curl/%VERSION +Accept: */* + + + +8 + + +