nghttpx: Allow accepting trailer part in h1 frontend

Downstream's headers mutation functions have been rewritten to share
code.
This commit is contained in:
Tatsuhiro Tsujikawa 2015-03-08 18:32:01 +09:00
parent 9ffbc45ba6
commit b9d6fff962
4 changed files with 131 additions and 73 deletions

View File

@ -120,10 +120,10 @@ Downstream::Downstream(Upstream *upstream, int32_t stream_id, int32_t priority)
response_minor_(1), upgrade_request_(false), upgraded_(false), response_minor_(1), upgrade_request_(false), upgraded_(false),
http2_upgrade_seen_(false), chunked_request_(false), http2_upgrade_seen_(false), chunked_request_(false),
request_connection_close_(false), request_header_key_prev_(false), request_connection_close_(false), request_header_key_prev_(false),
request_http2_expect_body_(false), chunked_response_(false), request_trailer_key_prev_(false), request_http2_expect_body_(false),
response_connection_close_(false), response_header_key_prev_(false), chunked_response_(false), response_connection_close_(false),
response_trailer_key_prev_(false), expect_final_response_(false), response_header_key_prev_(false), response_trailer_key_prev_(false),
request_pending_(false) { expect_final_response_(false), request_pending_(false) {
ev_timer_init(&upstream_rtimer_, &upstream_rtimeoutcb, 0., ev_timer_init(&upstream_rtimer_, &upstream_rtimeoutcb, 0.,
get_config()->stream_read_timeout); get_config()->stream_read_timeout);
@ -288,6 +288,45 @@ const std::string &Downstream::get_assembled_request_cookie() const {
return assembled_request_cookie_; return assembled_request_cookie_;
} }
namespace {
void add_header(bool &key_prev, size_t &sum, Headers &headers, std::string name,
std::string value) {
key_prev = true;
sum += name.size() + value.size();
headers.emplace_back(std::move(name), std::move(value));
}
} // namespace
namespace {
void append_last_header_key(bool key_prev, size_t &sum, Headers &headers,
const char *data, size_t len) {
assert(key_prev);
sum += len;
auto &item = headers.back();
item.name.append(data, len);
}
} // namespace
namespace {
void append_last_header_value(bool key_prev, size_t &sum, Headers &headers,
const char *data, size_t len) {
assert(!key_prev);
sum += len;
auto &item = headers.back();
item.value.append(data, len);
}
} // namespace
namespace {
void set_last_header_value(bool &key_prev, size_t &sum, Headers &headers,
const char *data, size_t len) {
key_prev = false;
sum += len;
auto &item = headers.back();
item.value.assign(data, len);
}
} // namespace
namespace { namespace {
int index_headers(http2::HeaderIndex &hdidx, Headers &headers, int index_headers(http2::HeaderIndex &hdidx, Headers &headers,
int64_t &content_length) { int64_t &content_length) {
@ -334,16 +373,13 @@ Downstream::get_request_header(const std::string &name) const {
} }
void Downstream::add_request_header(std::string name, std::string value) { void Downstream::add_request_header(std::string name, std::string value) {
request_header_key_prev_ = true; add_header(request_header_key_prev_, request_headers_sum_, request_headers_,
request_headers_sum_ += name.size() + value.size(); std::move(name), std::move(value));
request_headers_.emplace_back(std::move(name), std::move(value));
} }
void Downstream::set_last_request_header_value(std::string value) { void Downstream::set_last_request_header_value(const char *data, size_t len) {
request_header_key_prev_ = false; set_last_header_value(request_header_key_prev_, request_headers_sum_,
request_headers_sum_ += value.size(); request_headers_, data, len);
Headers::value_type &item = request_headers_.back();
item.value = std::move(value);
} }
void Downstream::add_request_header(const uint8_t *name, size_t namelen, void Downstream::add_request_header(const uint8_t *name, size_t namelen,
@ -360,18 +396,14 @@ bool Downstream::get_request_header_key_prev() const {
} }
void Downstream::append_last_request_header_key(const char *data, size_t len) { void Downstream::append_last_request_header_key(const char *data, size_t len) {
assert(request_header_key_prev_); append_last_header_key(request_header_key_prev_, request_headers_sum_,
request_headers_sum_ += len; request_headers_, data, len);
auto &item = request_headers_.back();
item.name.append(data, len);
} }
void Downstream::append_last_request_header_value(const char *data, void Downstream::append_last_request_header_value(const char *data,
size_t len) { size_t len) {
assert(!request_header_key_prev_); append_last_header_value(request_header_key_prev_, request_headers_sum_,
request_headers_sum_ += len; request_headers_, data, len);
auto &item = request_headers_.back();
item.value.append(data, len);
} }
void Downstream::clear_request_headers() { void Downstream::clear_request_headers() {
@ -397,6 +429,31 @@ const Headers &Downstream::get_request_trailers() const {
return request_trailers_; return request_trailers_;
} }
void Downstream::add_request_trailer(std::string name, std::string value) {
add_header(request_trailer_key_prev_, request_headers_sum_, request_trailers_,
std::move(name), std::move(value));
}
void Downstream::set_last_request_trailer_value(const char *data, size_t len) {
set_last_header_value(request_trailer_key_prev_, request_headers_sum_,
request_trailers_, data, len);
}
bool Downstream::get_request_trailer_key_prev() const {
return request_trailer_key_prev_;
}
void Downstream::append_last_request_trailer_key(const char *data, size_t len) {
append_last_header_key(request_trailer_key_prev_, request_headers_sum_,
request_trailers_, data, len);
}
void Downstream::append_last_request_trailer_value(const char *data,
size_t len) {
append_last_header_value(request_trailer_key_prev_, request_headers_sum_,
request_trailers_, data, len);
}
void Downstream::set_request_method(std::string method) { void Downstream::set_request_method(std::string method) {
request_method_ = std::move(method); request_method_ = std::move(method);
} }
@ -607,16 +664,13 @@ void Downstream::rewrite_location_response_header(
} }
void Downstream::add_response_header(std::string name, std::string value) { void Downstream::add_response_header(std::string name, std::string value) {
response_header_key_prev_ = true; add_header(response_header_key_prev_, response_headers_sum_,
response_headers_sum_ += name.size() + value.size(); response_headers_, std::move(name), std::move(value));
response_headers_.emplace_back(std::move(name), std::move(value));
} }
void Downstream::set_last_response_header_value(std::string value) { void Downstream::set_last_response_header_value(const char *data, size_t len) {
response_header_key_prev_ = false; set_last_header_value(response_header_key_prev_, response_headers_sum_,
response_headers_sum_ += value.size(); response_headers_, data, len);
auto &item = response_headers_.back();
item.value = std::move(value);
} }
void Downstream::add_response_header(std::string name, std::string value, void Downstream::add_response_header(std::string name, std::string value,
@ -641,18 +695,14 @@ bool Downstream::get_response_header_key_prev() const {
} }
void Downstream::append_last_response_header_key(const char *data, size_t len) { void Downstream::append_last_response_header_key(const char *data, size_t len) {
assert(response_header_key_prev_); append_last_header_key(response_header_key_prev_, response_headers_sum_,
response_headers_sum_ += len; response_headers_, data, len);
auto &item = response_headers_.back();
item.name.append(data, len);
} }
void Downstream::append_last_response_header_value(const char *data, void Downstream::append_last_response_header_value(const char *data,
size_t len) { size_t len) {
assert(!response_header_key_prev_); append_last_header_value(response_header_key_prev_, response_headers_sum_,
response_headers_sum_ += len; response_headers_, data, len);
auto &item = response_headers_.back();
item.value.append(data, len);
} }
void Downstream::clear_response_headers() { void Downstream::clear_response_headers() {
@ -681,9 +731,13 @@ unsigned int Downstream::get_response_http_status() const {
} }
void Downstream::add_response_trailer(std::string name, std::string value) { void Downstream::add_response_trailer(std::string name, std::string value) {
response_trailer_key_prev_ = true; add_header(response_trailer_key_prev_, response_headers_sum_,
response_headers_sum_ += name.size() + value.size(); response_trailers_, std::move(name), std::move(value));
response_trailers_.emplace_back(std::move(name), std::move(value)); }
void Downstream::set_last_response_trailer_value(const char *data, size_t len) {
set_last_header_value(response_trailer_key_prev_, response_headers_sum_,
response_trailers_, data, len);
} }
bool Downstream::get_response_trailer_key_prev() const { bool Downstream::get_response_trailer_key_prev() const {
@ -692,25 +746,14 @@ bool Downstream::get_response_trailer_key_prev() const {
void Downstream::append_last_response_trailer_key(const char *data, void Downstream::append_last_response_trailer_key(const char *data,
size_t len) { size_t len) {
assert(response_trailer_key_prev_); append_last_header_key(response_trailer_key_prev_, response_headers_sum_,
response_headers_sum_ += len; response_trailers_, data, len);
auto &item = response_trailers_.back();
item.name.append(data, len);
} }
void Downstream::append_last_response_trailer_value(const char *data, void Downstream::append_last_response_trailer_value(const char *data,
size_t len) { size_t len) {
assert(!response_trailer_key_prev_); append_last_header_value(response_trailer_key_prev_, response_headers_sum_,
response_headers_sum_ += len; response_trailers_, data, 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) { void Downstream::set_response_http_status(unsigned int status) {

View File

@ -113,7 +113,7 @@ public:
// no such header is found, returns nullptr. // no such header is found, returns nullptr.
const Headers::value_type *get_request_header(const std::string &name) const; const Headers::value_type *get_request_header(const std::string &name) const;
void add_request_header(std::string name, std::string value); void add_request_header(std::string name, std::string value);
void set_last_request_header_value(std::string value); void set_last_request_header_value(const char *data, size_t len);
void add_request_header(const uint8_t *name, size_t namelen, void add_request_header(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen, bool no_index, const uint8_t *value, size_t valuelen, bool no_index,
@ -131,6 +131,11 @@ public:
void add_request_trailer(const uint8_t *name, size_t namelen, void add_request_trailer(const uint8_t *name, size_t namelen,
const uint8_t *value, size_t valuelen, bool no_index, const uint8_t *value, size_t valuelen, bool no_index,
int16_t token); int16_t token);
void add_request_trailer(std::string name, std::string value);
void set_last_request_trailer_value(const char *data, size_t len);
bool get_request_trailer_key_prev() const;
void append_last_request_trailer_key(const char *data, size_t len);
void append_last_request_trailer_value(const char *data, size_t len);
void set_request_method(std::string method); void set_request_method(std::string method);
const std::string &get_request_method() const; const std::string &get_request_method() const;
@ -206,7 +211,7 @@ public:
// Rewrites the location response header field. // Rewrites the location response header field.
void rewrite_location_response_header(const std::string &upstream_scheme); void rewrite_location_response_header(const std::string &upstream_scheme);
void add_response_header(std::string name, std::string value); void add_response_header(std::string name, std::string value);
void set_last_response_header_value(std::string value); void set_last_response_header_value(const char *data, size_t len);
void add_response_header(std::string name, std::string value, int16_t token); void add_response_header(std::string name, std::string value, int16_t token);
void add_response_header(const uint8_t *name, size_t namelen, void add_response_header(const uint8_t *name, size_t namelen,
@ -226,10 +231,10 @@ public:
const uint8_t *value, size_t valuelen, const uint8_t *value, size_t valuelen,
bool no_index, int16_t token); bool no_index, int16_t token);
void add_response_trailer(std::string name, std::string value); void add_response_trailer(std::string name, std::string value);
void set_last_response_trailer_value(const char *data, size_t len);
bool get_response_trailer_key_prev() const; bool get_response_trailer_key_prev() const;
void append_last_response_trailer_key(const char *data, size_t len); 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 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; unsigned int get_response_http_status() const;
void set_response_http_status(unsigned int status); void set_response_http_status(unsigned int status);
@ -405,6 +410,7 @@ private:
bool chunked_request_; bool chunked_request_;
bool request_connection_close_; bool request_connection_close_;
bool request_header_key_prev_; bool request_header_key_prev_;
bool request_trailer_key_prev_;
bool request_http2_expect_body_; bool request_http2_expect_body_;
bool chunked_response_; bool chunked_response_;

View File

@ -594,13 +594,13 @@ int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
auto downstream = static_cast<Downstream *>(htp->data); auto downstream = static_cast<Downstream *>(htp->data);
if (downstream->get_response_state() == Downstream::INITIAL) { if (downstream->get_response_state() == Downstream::INITIAL) {
if (downstream->get_response_header_key_prev()) { if (downstream->get_response_header_key_prev()) {
downstream->set_last_response_header_value(std::string(data, len)); downstream->set_last_response_header_value(data, len);
} else { } else {
downstream->append_last_response_header_value(data, len); downstream->append_last_response_header_value(data, len);
} }
} else { } else {
if (downstream->get_response_trailer_key_prev()) { if (downstream->get_response_trailer_key_prev()) {
downstream->set_last_response_trailer_value(std::string(data, len)); downstream->set_last_response_trailer_value(data, len);
} else { } else {
downstream->append_last_response_trailer_value(data, len); downstream->append_last_response_trailer_value(data, len);
} }

View File

@ -83,15 +83,20 @@ namespace {
int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) { int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
auto upstream = static_cast<HttpsUpstream *>(htp->data); auto upstream = static_cast<HttpsUpstream *>(htp->data);
auto downstream = upstream->get_downstream(); auto downstream = upstream->get_downstream();
if (downstream->get_request_state() != Downstream::INITIAL) { if (downstream->get_request_state() == Downstream::INITIAL) {
// ignore trailers
return 0;
}
if (downstream->get_request_header_key_prev()) { if (downstream->get_request_header_key_prev()) {
downstream->append_last_request_header_key(data, len); downstream->append_last_request_header_key(data, len);
} else { } else {
downstream->add_request_header(std::string(data, len), ""); downstream->add_request_header(std::string(data, len), "");
} }
} else {
// trailer part
if (downstream->get_request_trailer_key_prev()) {
downstream->append_last_request_trailer_key(data, len);
} else {
downstream->add_request_trailer(std::string(data, len), "");
}
}
if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) { if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
ULOG(INFO, upstream) << "Too large header block size=" ULOG(INFO, upstream) << "Too large header block size="
@ -107,15 +112,19 @@ namespace {
int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) { int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
auto upstream = static_cast<HttpsUpstream *>(htp->data); auto upstream = static_cast<HttpsUpstream *>(htp->data);
auto downstream = upstream->get_downstream(); auto downstream = upstream->get_downstream();
if (downstream->get_request_state() != Downstream::INITIAL) { if (downstream->get_request_state() == Downstream::INITIAL) {
// ignore trailers
return 0;
}
if (downstream->get_request_header_key_prev()) { if (downstream->get_request_header_key_prev()) {
downstream->set_last_request_header_value(std::string(data, len)); downstream->set_last_request_header_value(data, len);
} else { } else {
downstream->append_last_request_header_value(data, len); downstream->append_last_request_header_value(data, len);
} }
} else {
if (downstream->get_request_trailer_key_prev()) {
downstream->set_last_request_trailer_value(data, len);
} else {
downstream->append_last_request_trailer_value(data, len);
}
}
if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) { if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
if (LOG_ENABLED(INFO)) { if (LOG_ENABLED(INFO)) {
ULOG(INFO, upstream) << "Too large header block size=" ULOG(INFO, upstream) << "Too large header block size="