diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index ce3196eb..e517bdf7 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -744,6 +744,13 @@ bool Downstream::expect_response_body() const { http2::expect_response_body(req_.method, resp_.http_status); } +bool Downstream::expect_response_trailer() const { + // In HTTP/2, if final response HEADERS does not bear END_STREAM it + // is possible trailer fields might come, regardless of request + // method or status code. + return !resp_.headers_only && resp_.http_major == 2; +} + namespace { void reset_timer(struct ev_loop *loop, ev_timer *w) { ev_timer_again(loop, w); } } // namespace diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index 2e59ea98..9f5c7f67 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -278,6 +278,7 @@ public: bool validate_request_recv_body_length() const; void set_request_downstream_host(const StringRef &host); bool expect_response_body() const; + bool expect_response_trailer() const; enum { INITIAL, HEADER_COMPLETE, diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 29eca0b6..1fa49a3a 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -1520,7 +1520,8 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) { nghttp2_data_provider *data_prdptr; - if (downstream->expect_response_body()) { + if (downstream->expect_response_body() || + downstream->expect_response_trailer()) { data_prdptr = &data_prd; } else { data_prdptr = nullptr; diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index 9677a6c8..2b1fd267 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -604,6 +604,13 @@ int htp_hdrs_completecb(http_parser *htp) { resp.http_major = htp->http_major; resp.http_minor = htp->http_minor; + if (resp.http_major > 1) { + // Normalize HTTP version, since we use http_major == 2 specially + // in Downstream::expect_response_trailer(). + resp.http_major = 1; + resp.http_minor = 1; + } + if (resp.fs.parse_content_length() != 0) { downstream->set_response_state(Downstream::MSG_BAD_HEADER); return -1;