diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index 8480d856..e71893a8 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -122,7 +122,8 @@ Downstream::Downstream(Upstream *upstream, int32_t stream_id, int32_t priority) request_connection_close_(false), request_header_key_prev_(false), request_http2_expect_body_(false), chunked_response_(false), response_connection_close_(false), response_header_key_prev_(false), - expect_final_response_(false), request_pending_(false) { + response_trailer_key_prev_(false), expect_final_response_(false), + request_pending_(false) { ev_timer_init(&upstream_rtimer_, &upstream_rtimeoutcb, 0., get_config()->stream_read_timeout); @@ -679,6 +680,39 @@ unsigned int Downstream::get_response_http_status() const { return response_http_status_; } +void Downstream::add_response_trailer(std::string name, std::string value) { + response_trailer_key_prev_ = true; + response_headers_sum_ += name.size() + value.size(); + response_trailers_.emplace_back(std::move(name), std::move(value)); +} + +bool Downstream::get_response_trailer_key_prev() const { + return response_trailer_key_prev_; +} + +void Downstream::append_last_response_trailer_key(const char *data, + size_t len) { + assert(response_trailer_key_prev_); + response_headers_sum_ += len; + auto &item = response_trailers_.back(); + item.name.append(data, len); +} + +void Downstream::append_last_response_trailer_value(const char *data, + size_t len) { + assert(!response_trailer_key_prev_); + response_headers_sum_ += len; + auto &item = response_trailers_.back(); + item.value.append(data, len); +} + +void Downstream::set_last_response_trailer_value(std::string value) { + response_trailer_key_prev_ = false; + response_headers_sum_ += value.size(); + auto &item = response_trailers_.back(); + item.value = std::move(value); +} + void Downstream::set_response_http_status(unsigned int status) { response_http_status_ = status; } diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index f138811a..8ffff731 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -225,6 +225,11 @@ public: void add_response_trailer(const uint8_t *name, size_t namelen, const uint8_t *value, size_t valuelen, bool no_index, int16_t token); + void add_response_trailer(std::string name, std::string value); + bool get_response_trailer_key_prev() const; + void append_last_response_trailer_key(const char *data, size_t len); + void append_last_response_trailer_value(const char *data, size_t len); + void set_last_response_trailer_value(std::string value); unsigned int get_response_http_status() const; void set_response_http_status(unsigned int status); @@ -405,6 +410,7 @@ private: bool chunked_response_; bool response_connection_close_; bool response_header_key_prev_; + bool response_trailer_key_prev_; bool expect_final_response_; // true if downstream request is pending because backend connection // has not been established or should be checked before use; diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index f27e3029..323d2b0e 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -555,14 +555,19 @@ int htp_hdrs_completecb(http_parser *htp) { namespace { int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) { auto downstream = static_cast(htp->data); - if (downstream->get_response_state() != Downstream::INITIAL) { - // ignore trailers - return 0; - } - if (downstream->get_response_header_key_prev()) { - downstream->append_last_response_header_key(data, len); + if (downstream->get_response_state() == Downstream::INITIAL) { + if (downstream->get_response_header_key_prev()) { + downstream->append_last_response_header_key(data, len); + } else { + downstream->add_response_header(std::string(data, len), ""); + } } else { - downstream->add_response_header(std::string(data, len), ""); + // trailer part + if (downstream->get_response_trailer_key_prev()) { + downstream->append_last_response_trailer_key(data, len); + } else { + downstream->add_response_trailer(std::string(data, len), ""); + } } if (downstream->get_response_headers_sum() > Downstream::MAX_HEADERS_SUM) { if (LOG_ENABLED(INFO)) { @@ -578,14 +583,18 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) { namespace { int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) { auto downstream = static_cast(htp->data); - if (downstream->get_response_state() != Downstream::INITIAL) { - // ignore trailers - return 0; - } - if (downstream->get_response_header_key_prev()) { - downstream->set_last_response_header_value(std::string(data, len)); + if (downstream->get_response_state() == Downstream::INITIAL) { + if (downstream->get_response_header_key_prev()) { + downstream->set_last_response_header_value(std::string(data, len)); + } else { + downstream->append_last_response_header_value(data, len); + } } else { - downstream->append_last_response_header_value(data, len); + if (downstream->get_response_trailer_key_prev()) { + downstream->set_last_response_trailer_value(std::string(data, len)); + } else { + downstream->append_last_response_trailer_value(data, len); + } } if (downstream->get_response_headers_sum() > Downstream::MAX_HEADERS_SUM) { if (LOG_ENABLED(INFO)) {