From fbffd2c923b6f8bdc7704a9dc3e4f1ba75fbdcd0 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Mon, 27 Jan 2014 00:44:08 +0900 Subject: [PATCH] nghttpx: Limit the number of receiving headers --- src/http2.cc | 15 +++++++++++++++ src/http2.h | 4 ++++ src/shrpx_downstream.h | 4 ++++ src/shrpx_http2_session.cc | 8 ++++++++ src/shrpx_http2_upstream.cc | 8 ++++++++ 5 files changed, 39 insertions(+) diff --git a/src/http2.cc b/src/http2.cc index f94f17b8..6ea829a9 100644 --- a/src/http2.cc +++ b/src/http2.cc @@ -730,6 +730,21 @@ int check_nv(const uint8_t *name, size_t namelen, return 1; } +int handle_too_many_headers(nghttp2_session *session, int32_t stream_id) +{ + int rv; + rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE, stream_id, + NGHTTP2_INTERNAL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + rv = nghttp2_session_terminate_session(session, NGHTTP2_INTERNAL_ERROR); + if(nghttp2_is_fatal(rv)) { + return rv; + } + return 0; +} + } // namespace http2 } // namespace nghttp2 diff --git a/src/http2.h b/src/http2.h index 3a177522..f2cb4c53 100644 --- a/src/http2.h +++ b/src/http2.h @@ -221,6 +221,10 @@ int check_header_value(const uint8_t* value, size_t len); int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value, size_t valuelen); +// Handles the situation that incoming headers are too many. It is +// dealt with by issuing RST_STREAM and GOAWAY. +int handle_too_many_headers(nghttp2_session *session, int32_t stream_id); + } // namespace http2 } // namespace nghttp2 diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index 57f012f1..fa6ca494 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -199,6 +199,10 @@ public: // Change the priority of downstream int change_priority(int32_t pri); + + // Maximum number of headers per HEADERS frame, including its + // following CONTINUATIONs. + static const size_t MAX_HEADERS = 128; private: Headers request_headers_; Headers response_headers_; diff --git a/src/shrpx_http2_session.cc b/src/shrpx_http2_session.cc index f8f3a7ca..a97548fe 100644 --- a/src/shrpx_http2_session.cc +++ b/src/shrpx_http2_session.cc @@ -804,6 +804,7 @@ int on_header_callback(nghttp2_session *session, const uint8_t *value, size_t valuelen, void *user_data) { + int rv; if(frame->hd.type != NGHTTP2_HEADERS || frame->headers.cat != NGHTTP2_HCAT_RESPONSE) { return 0; @@ -817,6 +818,13 @@ int on_header_callback(nghttp2_session *session, if(!downstream) { return 0; } + if(downstream->get_request_headers().size() >= Downstream::MAX_HEADERS) { + rv = http2::handle_too_many_headers(session, frame->hd.stream_id); + if(nghttp2_is_fatal(rv)) { + return rv; + } + return 0; + } if(!http2::check_nv(name, namelen, value, valuelen)) { return 0; } diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 717ec62c..13ec1903 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -205,6 +205,7 @@ int on_header_callback(nghttp2_session *session, const uint8_t *value, size_t valuelen, void *user_data) { + int rv; if(frame->hd.type != NGHTTP2_HEADERS || frame->headers.cat != NGHTTP2_HCAT_REQUEST) { return 0; @@ -214,6 +215,13 @@ int on_header_callback(nghttp2_session *session, if(!downstream) { return 0; } + if(downstream->get_request_headers().size() >= Downstream::MAX_HEADERS) { + rv = http2::handle_too_many_headers(session, frame->hd.stream_id); + if(nghttp2_is_fatal(rv)) { + return rv; + } + return 0; + } if(!http2::check_nv(name, namelen, value, valuelen)) { return 0; }