diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index 1e6d5ed4..eb065406 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -286,9 +286,10 @@ const std::string &Downstream::get_assembled_request_cookie() const { return assembled_request_cookie_; } -int Downstream::index_request_headers() { - for (size_t i = 0; i < request_headers_.size(); ++i) { - auto &kv = request_headers_[i]; +namespace { +int index_headers(int *hdidx, Headers &headers, int64_t &content_length) { + for (size_t i = 0; i < headers.size(); ++i) { + auto &kv = headers[i]; util::inp_strlower(kv.name); auto token = http2::lookup_token( @@ -297,21 +298,27 @@ int Downstream::index_request_headers() { continue; } - http2::index_header(request_hdidx_, token, i); + http2::index_header(hdidx, token, i); if (token == http2::HD_CONTENT_LENGTH) { auto len = util::parse_uint(kv.value); if (len == -1) { return -1; } - if (request_content_length_ != -1 && request_content_length_ != len) { + if (content_length != -1 && content_length != len) { return -1; } - request_content_length_ = len; + content_length = len; } } return 0; } +} // namespace + +int Downstream::index_request_headers() { + return index_headers(request_hdidx_, request_headers_, + request_content_length_); +} const Headers::value_type *Downstream::get_request_header(int token) const { return http2::get_header(request_hdidx_, token, request_headers_); @@ -511,11 +518,9 @@ const Headers &Downstream::get_response_headers() const { return response_headers_; } -void Downstream::index_response_headers() { - for (auto &kv : response_headers_) { - util::inp_strlower(kv.name); - } - http2::index_headers(response_hdidx_, response_headers_); +int Downstream::index_response_headers() { + return index_headers(response_hdidx_, response_headers_, + response_content_length_); } const Headers::value_type *Downstream::get_response_header(int token) const { @@ -788,19 +793,10 @@ void Downstream::inspect_http1_request() { void Downstream::inspect_http1_response() { auto idx = response_hdidx_[http2::HD_TRANSFER_ENCODING]; - if (idx != -1 && - util::strifind(response_headers_[idx].value.c_str(), "chunked")) { - chunked_response_ = true; - } - - // examine Content-Length only when Transfer-Encoding is missing - if (idx == -1) { - idx = response_hdidx_[http2::HD_CONTENT_LENGTH]; - if (idx != -1) { - auto len = util::parse_uint(response_headers_[idx].value); - if (len != -1) { - response_content_length_ = len; - } + if (idx != -1) { + response_content_length_ = -1; + if (util::strifind(response_headers_[idx].value.c_str(), "chunked")) { + chunked_response_ = true; } } } diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index be8c856c..746597db 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -184,8 +184,10 @@ public: Memchunks4K *get_request_buf(); // downstream response API const Headers &get_response_headers() const; - // Lower the response header field names and indexes response headers - void index_response_headers(); + // Lower the response header field names and indexes response + // headers. If there are invalid headers (e.g., multiple + // Content-Length with different values), returns -1. + int index_response_headers(); // Returns pointer to the response header with the name |name|. If // multiple header have |name| as name, return last occurrence from // the beginning. If no such header is found, returns nullptr. diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index f8e667b6..dbdb8fad 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -469,7 +469,10 @@ int htp_hdrs_completecb(http_parser *htp) { downstream->set_response_major(htp->http_major); downstream->set_response_minor(htp->http_minor); - downstream->index_response_headers(); + if (downstream->index_response_headers() != 0) { + downstream->set_response_state(Downstream::MSG_BAD_HEADER); + return -1; + } if (downstream->get_non_final_response()) { // For non-final response code, we just call