nghttpx: Stream error if disallowed header field in HTTP2 is received

This commit is contained in:
Tatsuhiro Tsujikawa 2013-08-26 01:25:31 +09:00
parent 33743ab832
commit 89cd2ff479
4 changed files with 36 additions and 7 deletions

View File

@ -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<const uint8_t*>(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 http
} // namespace shrpx } // namespace shrpx

View File

@ -52,6 +52,14 @@ std::string colorizeHeaders(const char *hdrs);
void copy_url_component(std::string& dest, http_parser_url *u, int field, void copy_url_component(std::string& dest, http_parser_url *u, int field,
const char* url); 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 http
} // namespace shrpx } // namespace shrpx

View File

@ -217,6 +217,10 @@ void on_frame_recv_callback
{ {
size_t i, j; size_t i, j;
for(i = 0, j = 0; i < frame->headers.nvlen && j < req_hdlen;) { 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); int rv = util::strcompare(req_headers[j], nva[i].name, nva[i].namelen);
if(rv > 0) { if(rv > 0) {
if(nva[i].namelen > 0 && nva[i].name[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(); nv[hdidx++] = response_status.c_str();
for(Headers::const_iterator i = downstream->get_response_headers().begin(); for(Headers::const_iterator i = downstream->get_response_headers().begin();
i != downstream->get_response_headers().end(); ++i) { i != downstream->get_response_headers().end(); ++i) {
if(util::strieq((*i).first.c_str(), "connection") || if(!http::check_http2_allowed_header((*i).first.c_str())) {
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")) {
// These are ignored // These are ignored
} else if(!get_config()->no_via && } else if(!get_config()->no_via &&
util::strieq((*i).first.c_str(), "via")) { util::strieq((*i).first.c_str(), "via")) {

View File

@ -39,6 +39,7 @@
#include "shrpx_spdy_downstream_connection.h" #include "shrpx_spdy_downstream_connection.h"
#include "shrpx_client_handler.h" #include "shrpx_client_handler.h"
#include "shrpx_ssl.h" #include "shrpx_ssl.h"
#include "shrpx_http.h"
#include "util.h" #include "util.h"
#include "base64.h" #include "base64.h"
@ -747,6 +748,10 @@ void on_frame_recv_callback
auto nva = frame->headers.nva; auto nva = frame->headers.nva;
std::string status, content_length; std::string status, content_length;
for(size_t i = 0; i < frame->headers.nvlen; ++i) { 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)) { if(util::strieq(":status", nva[i].name, nva[i].namelen)) {
status.assign(reinterpret_cast<char*>(nva[i].value), status.assign(reinterpret_cast<char*>(nva[i].value),
nva[i].valuelen); nva[i].valuelen);