From 400615ca3587e1d6c3f4ee4bb2248eb1e26960af Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Wed, 28 Aug 2013 03:14:19 +0900 Subject: [PATCH] nghttpd: Check disallowed headers --- src/HttpServer.cc | 69 ++++++++++++++++++++++++++--------------------- src/Makefile.am | 4 +-- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/HttpServer.cc b/src/HttpServer.cc index 01e8e424..3418d968 100644 --- a/src/HttpServer.cc +++ b/src/HttpServer.cc @@ -45,6 +45,7 @@ #include #include "app_helper.h" +#include "http2.h" #include "util.h" #ifndef O_BINARY @@ -608,39 +609,26 @@ void prepare_status_response(Request *req, Http2Handler *hd, namespace { void prepare_response(Request *req, Http2Handler *hd) { - std::string url; - bool url_found = false; - bool method_found = false; - bool scheme_found = false; - bool host_found = false; + auto url = (*std::lower_bound(std::begin(req->headers), + std::end(req->headers), + std::make_pair(std::string(":path"), + std::string()))).second; + auto ims = std::lower_bound(std::begin(req->headers), + std::end(req->headers), + std::make_pair(std::string("if-modified-since"), + std::string())); time_t last_mod = 0; bool last_mod_found = false; - for(int i = 0; i < (int)req->headers.size(); ++i) { - const std::string &field = req->headers[i].first; - const std::string &value = req->headers[i].second; - if(!url_found && field == ":path") { - url_found = true; - url = value; - } else if(field == ":method") { - method_found = true; - } else if(field == ":scheme") { - scheme_found = true; - } else if(field == ":host") { - host_found = true; - } else if(!last_mod_found && field == "if-modified-since") { + if(ims != std::end(req->headers) && + (*ims).first == "if-modified-since") { last_mod_found = true; - last_mod = util::parse_http_date(value); - } - } - if(!url_found || !method_found || !scheme_found || !host_found) { - prepare_status_response(req, hd, STATUS_400); - return; + last_mod = util::parse_http_date((*ims).second); } auto query_pos = url.find("?"); if(query_pos != std::string::npos) { // Do not response to this request to allow clients to test timeouts. - if (url.find("nghttpd_do_not_respond_to_req=yes", - query_pos) != std::string::npos) { + if(url.find("nghttpd_do_not_respond_to_req=yes", + query_pos) != std::string::npos) { return; } url = url.substr(0, query_pos); @@ -690,6 +678,12 @@ void append_nv(Request *req, nghttp2_nv *nva, size_t nvlen) } } // namespace +namespace { +const char *REQUIRED_HEADERS[] = { + ":host", ":method", ":path", ":scheme", nullptr +}; +} // namespace + namespace { void hd_on_frame_recv_callback (nghttp2_session *session, nghttp2_frame *frame, void *user_data) @@ -704,15 +698,25 @@ void hd_on_frame_recv_callback switch(frame->headers.cat) { case NGHTTP2_HCAT_REQUEST: { int32_t stream_id = frame->hd.stream_id; + if(!http2::check_http2_headers(frame->headers.nva, + frame->headers.nvlen)) { + nghttp2_submit_rst_stream(session, stream_id, NGHTTP2_PROTOCOL_ERROR); + return; + } + for(size_t i = 0; REQUIRED_HEADERS[i]; ++i) { + if(!http2::get_unique_header(frame->headers.nva, + frame->headers.nvlen, + REQUIRED_HEADERS[i])) { + nghttp2_submit_rst_stream(session, stream_id, + NGHTTP2_PROTOCOL_ERROR); + return; + } + } auto req = util::make_unique(stream_id); append_nv(req.get(), frame->headers.nva, frame->headers.nvlen); hd->add_stream(stream_id, std::move(req)); break; } - case NGHTTP2_HCAT_HEADERS: - append_nv(hd->get_stream(frame->hd.stream_id), - frame->headers.nva, frame->headers.nvlen); - break; default: break; } @@ -727,7 +731,10 @@ void htdocs_on_request_recv_callback (nghttp2_session *session, int32_t stream_id, void *user_data) { auto hd = reinterpret_cast(user_data); - prepare_response(hd->get_stream(stream_id), hd); + auto stream = hd->get_stream(stream_id); + if(stream) { + prepare_response(hd->get_stream(stream_id), hd); + } } namespace { diff --git a/src/Makefile.am b/src/Makefile.am index f1d7ddb0..e30904d3 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -44,8 +44,8 @@ LDADD = $(top_builddir)/lib/libnghttp2.la bin_PROGRAMS += nghttp nghttpd nghttpx -HELPER_OBJECTS = util.cc timegm.c app_helper.cc -HELPER_HFILES = util.h timegm.h app_helper.h nghttp2_config.h +HELPER_OBJECTS = util.cc http2.cc timegm.c app_helper.cc +HELPER_HFILES = util.h http2.h timegm.h app_helper.h nghttp2_config.h HTML_PARSER_OBJECTS = HTML_PARSER_HFILES = HtmlParser.h