diff --git a/src/shrpx_http.cc b/src/shrpx_http.cc index 32d508f0..87bb5b61 100644 --- a/src/shrpx_http.cc +++ b/src/shrpx_http.cc @@ -170,6 +170,24 @@ void copy_url_component(std::string& dest, http_parser_url *u, int field, } } +bool check_http2_allowed_header(const char *name) +{ + return check_http2_allowed_header(reinterpret_cast(name), + strlen(name)); +} + +bool check_http2_allowed_header(const uint8_t *name, size_t namelen) +{ + return + !util::strieq("connection", name, namelen) && + !util::strieq("host", name, namelen) && + !util::strieq("keep-alive", name, namelen) && + !util::strieq("proxy-connection", name, namelen) && + !util::strieq("te", name, namelen) && + !util::strieq("transfer-encoding", name, namelen) && + !util::strieq("upgrade", name, namelen); +} + } // namespace http } // namespace shrpx diff --git a/src/shrpx_http.h b/src/shrpx_http.h index e5732c70..b0e1fef1 100644 --- a/src/shrpx_http.h +++ b/src/shrpx_http.h @@ -52,6 +52,14 @@ std::string colorizeHeaders(const char *hdrs); void copy_url_component(std::string& dest, http_parser_url *u, int field, const char* url); +// Returns true if the header field |name| with length |namelen| bytes +// is valid for HTTP/2.0. +bool check_http2_allowed_header(const uint8_t *name, size_t namelen); + +// Calls check_http2_allowed_header with |name| and strlen(name), +// assuming |name| is null-terminated string. +bool check_http2_allowed_header(const char *name); + } // namespace http } // namespace shrpx diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 4c47ad8a..ee224bcb 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -217,6 +217,10 @@ void on_frame_recv_callback { size_t i, j; for(i = 0, j = 0; i < frame->headers.nvlen && j < req_hdlen;) { + if(!http::check_http2_allowed_header(nva[i].name, nva[i].namelen)) { + bad_req = true; + break; + } int rv = util::strcompare(req_headers[j], nva[i].name, nva[i].namelen); if(rv > 0) { if(nva[i].namelen > 0 && nva[i].name[0] != ':') { @@ -915,13 +919,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) nv[hdidx++] = response_status.c_str(); for(Headers::const_iterator i = downstream->get_response_headers().begin(); i != downstream->get_response_headers().end(); ++i) { - if(util::strieq((*i).first.c_str(), "connection") || - util::strieq((*i).first.c_str(), "host") || - util::strieq((*i).first.c_str(), "keep-alive") || - util::strieq((*i).first.c_str(), "proxy-connection") || - util::strieq((*i).first.c_str(), "te") || - util::strieq((*i).first.c_str(), "transfer-encoding") || - util::strieq((*i).first.c_str(), "upgrade")) { + if(!http::check_http2_allowed_header((*i).first.c_str())) { // These are ignored } else if(!get_config()->no_via && util::strieq((*i).first.c_str(), "via")) { diff --git a/src/shrpx_spdy_session.cc b/src/shrpx_spdy_session.cc index e57a623b..61ee89e1 100644 --- a/src/shrpx_spdy_session.cc +++ b/src/shrpx_spdy_session.cc @@ -39,6 +39,7 @@ #include "shrpx_spdy_downstream_connection.h" #include "shrpx_client_handler.h" #include "shrpx_ssl.h" +#include "shrpx_http.h" #include "util.h" #include "base64.h" @@ -747,6 +748,10 @@ void on_frame_recv_callback auto nva = frame->headers.nva; std::string status, content_length; for(size_t i = 0; i < frame->headers.nvlen; ++i) { + if(!http::check_http2_allowed_header(nva[i].name, nva[i].namelen)) { + status.clear(); + break; + } if(util::strieq(":status", nva[i].name, nva[i].namelen)) { status.assign(reinterpret_cast(nva[i].value), nva[i].valuelen);