nghttpx: Extract response related fields to Response struct
This commit is contained in:
parent
a7fd37ffdf
commit
3b8889a2a1
|
@ -101,14 +101,10 @@ int main(int argc, char *argv[]) {
|
||||||
shrpx::test_http2_get_pure_path_component) ||
|
shrpx::test_http2_get_pure_path_component) ||
|
||||||
!CU_add_test(pSuite, "http2_construct_push_component",
|
!CU_add_test(pSuite, "http2_construct_push_component",
|
||||||
shrpx::test_http2_construct_push_component) ||
|
shrpx::test_http2_construct_push_component) ||
|
||||||
!CU_add_test(pSuite, "downstream_index_request_headers",
|
!CU_add_test(pSuite, "downstream_field_store_index_headers",
|
||||||
shrpx::test_downstream_index_request_headers) ||
|
shrpx::test_downstream_field_store_index_headers) ||
|
||||||
!CU_add_test(pSuite, "downstream_index_response_headers",
|
!CU_add_test(pSuite, "downstream_field_store_header",
|
||||||
shrpx::test_downstream_index_response_headers) ||
|
shrpx::test_downstream_field_store_header) ||
|
||||||
!CU_add_test(pSuite, "downstream_get_request_header",
|
|
||||||
shrpx::test_downstream_get_request_header) ||
|
|
||||||
!CU_add_test(pSuite, "downstream_get_response_header",
|
|
||||||
shrpx::test_downstream_get_response_header) ||
|
|
||||||
!CU_add_test(pSuite, "downstream_crumble_request_cookie",
|
!CU_add_test(pSuite, "downstream_crumble_request_cookie",
|
||||||
shrpx::test_downstream_crumble_request_cookie) ||
|
shrpx::test_downstream_crumble_request_cookie) ||
|
||||||
!CU_add_test(pSuite, "downstream_assemble_request_cookie",
|
!CU_add_test(pSuite, "downstream_assemble_request_cookie",
|
||||||
|
|
|
@ -812,6 +812,7 @@ std::string construct_absolute_request_uri(const Request &req) {
|
||||||
void ClientHandler::write_accesslog(Downstream *downstream) {
|
void ClientHandler::write_accesslog(Downstream *downstream) {
|
||||||
nghttp2::ssl::TLSSessionInfo tls_info;
|
nghttp2::ssl::TLSSessionInfo tls_info;
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
const auto &resp = downstream->response();
|
||||||
|
|
||||||
upstream_accesslog(
|
upstream_accesslog(
|
||||||
get_config()->accesslog_format,
|
get_config()->accesslog_format,
|
||||||
|
@ -832,8 +833,7 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
|
||||||
downstream->get_request_start_time(), // request_start_time
|
downstream->get_request_start_time(), // request_start_time
|
||||||
std::chrono::high_resolution_clock::now(), // request_end_time
|
std::chrono::high_resolution_clock::now(), // request_end_time
|
||||||
|
|
||||||
req.http_major, req.http_minor,
|
req.http_major, req.http_minor, resp.http_status,
|
||||||
downstream->get_response_http_status(),
|
|
||||||
downstream->get_response_sent_bodylen(), port_.c_str(),
|
downstream->get_response_sent_bodylen(), port_.c_str(),
|
||||||
get_config()->port, get_config()->pid,
|
get_config()->port, get_config()->pid,
|
||||||
});
|
});
|
||||||
|
|
|
@ -116,18 +116,15 @@ Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
|
||||||
: dlnext(nullptr), dlprev(nullptr),
|
: dlnext(nullptr), dlprev(nullptr),
|
||||||
request_start_time_(std::chrono::high_resolution_clock::now()),
|
request_start_time_(std::chrono::high_resolution_clock::now()),
|
||||||
request_buf_(mcpool), response_buf_(mcpool), request_bodylen_(0),
|
request_buf_(mcpool), response_buf_(mcpool), request_bodylen_(0),
|
||||||
response_bodylen_(0), response_sent_bodylen_(0),
|
response_bodylen_(0), response_sent_bodylen_(0), upstream_(upstream),
|
||||||
response_content_length_(-1), upstream_(upstream), blocked_link_(nullptr),
|
blocked_link_(nullptr), request_datalen_(0), response_datalen_(0),
|
||||||
response_headers_sum_(0), request_datalen_(0), response_datalen_(0),
|
|
||||||
num_retry_(0), stream_id_(stream_id), priority_(priority),
|
num_retry_(0), stream_id_(stream_id), priority_(priority),
|
||||||
downstream_stream_id_(-1),
|
downstream_stream_id_(-1),
|
||||||
response_rst_stream_error_code_(NGHTTP2_NO_ERROR),
|
response_rst_stream_error_code_(NGHTTP2_NO_ERROR),
|
||||||
request_state_(INITIAL), response_state_(INITIAL),
|
request_state_(INITIAL), response_state_(INITIAL),
|
||||||
response_http_status_(0), response_major_(1), response_minor_(1),
|
|
||||||
dispatch_state_(DISPATCH_NONE), upgraded_(false), chunked_request_(false),
|
dispatch_state_(DISPATCH_NONE), upgraded_(false), chunked_request_(false),
|
||||||
chunked_response_(false), response_connection_close_(false),
|
chunked_response_(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);
|
||||||
|
@ -142,10 +139,6 @@ Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
|
||||||
upstream_wtimer_.data = this;
|
upstream_wtimer_.data = this;
|
||||||
downstream_rtimer_.data = this;
|
downstream_rtimer_.data = this;
|
||||||
downstream_wtimer_.data = this;
|
downstream_wtimer_.data = this;
|
||||||
|
|
||||||
http2::init_hdidx(response_hdidx_);
|
|
||||||
|
|
||||||
response_headers_.reserve(32);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Downstream::~Downstream() {
|
Downstream::~Downstream() {
|
||||||
|
@ -367,50 +360,6 @@ void append_last_header_value(bool key_prev, size_t &sum, Headers &headers,
|
||||||
}
|
}
|
||||||
} // namespace
|
} // 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 {
|
|
||||||
int index_headers(http2::HeaderIndex &hdidx, Headers &headers,
|
|
||||||
int64_t &content_length) {
|
|
||||||
http2::init_hdidx(hdidx);
|
|
||||||
content_length = -1;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < headers.size(); ++i) {
|
|
||||||
auto &kv = headers[i];
|
|
||||||
util::inp_strlower(kv.name);
|
|
||||||
|
|
||||||
auto token = http2::lookup_token(
|
|
||||||
reinterpret_cast<const uint8_t *>(kv.name.c_str()), kv.name.size());
|
|
||||||
if (token < 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
kv.token = token;
|
|
||||||
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 (content_length != -1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
content_length = len;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
int FieldStore::index_headers() {
|
int FieldStore::index_headers() {
|
||||||
http2::init_hdidx(hdidx_);
|
http2::init_hdidx(hdidx_);
|
||||||
content_length = -1;
|
content_length = -1;
|
||||||
|
@ -446,6 +395,10 @@ const Headers::value_type *FieldStore::header(int16_t token) const {
|
||||||
return http2::get_header(hdidx_, token, headers_);
|
return http2::get_header(hdidx_, token, headers_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Headers::value_type *FieldStore::header(int16_t token) {
|
||||||
|
return http2::get_header(hdidx_, token, headers_);
|
||||||
|
}
|
||||||
|
|
||||||
const Headers::value_type *FieldStore::header(const std::string &name) const {
|
const Headers::value_type *FieldStore::header(const std::string &name) const {
|
||||||
return get_header_linear(headers_, name);
|
return get_header_linear(headers_, name);
|
||||||
}
|
}
|
||||||
|
@ -585,30 +538,9 @@ int Downstream::end_upload_data() {
|
||||||
return dconn_->end_upload_data();
|
return dconn_->end_upload_data();
|
||||||
}
|
}
|
||||||
|
|
||||||
const Headers &Downstream::get_response_headers() const {
|
|
||||||
return response_headers_;
|
|
||||||
}
|
|
||||||
|
|
||||||
Headers &Downstream::get_response_headers() { return 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(int16_t token) const {
|
|
||||||
return http2::get_header(response_hdidx_, token, response_headers_);
|
|
||||||
}
|
|
||||||
|
|
||||||
Headers::value_type *Downstream::get_response_header(int16_t token) {
|
|
||||||
return http2::get_header(response_hdidx_, token, response_headers_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::rewrite_location_response_header(
|
void Downstream::rewrite_location_response_header(
|
||||||
const std::string &upstream_scheme) {
|
const std::string &upstream_scheme) {
|
||||||
auto hd =
|
auto hd = resp_.fs.header(http2::HD_LOCATION);
|
||||||
http2::get_header(response_hdidx_, http2::HD_LOCATION, response_headers_);
|
|
||||||
if (!hd) {
|
if (!hd) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -656,131 +588,18 @@ void Downstream::rewrite_location_response_header(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!new_uri.empty()) {
|
|
||||||
auto idx = response_hdidx_[http2::HD_LOCATION];
|
if (new_uri.empty()) {
|
||||||
response_headers_[idx].value = std::move(new_uri);
|
return;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::add_response_header(std::string name, std::string value) {
|
(*hd).value = std::move(new_uri);
|
||||||
add_header(response_header_key_prev_, response_headers_sum_,
|
|
||||||
response_headers_, std::move(name), std::move(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::set_last_response_header_value(const char *data, size_t len) {
|
|
||||||
set_last_header_value(response_header_key_prev_, response_headers_sum_,
|
|
||||||
response_headers_, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::add_response_header(std::string name, std::string value,
|
|
||||||
int16_t token) {
|
|
||||||
http2::index_header(response_hdidx_, token, response_headers_.size());
|
|
||||||
response_headers_sum_ += name.size() + value.size();
|
|
||||||
response_headers_.emplace_back(std::move(name), std::move(value), false,
|
|
||||||
token);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::add_response_header(const uint8_t *name, size_t namelen,
|
|
||||||
const uint8_t *value, size_t valuelen,
|
|
||||||
bool no_index, int16_t token) {
|
|
||||||
http2::index_header(response_hdidx_, token, response_headers_.size());
|
|
||||||
add_header(response_headers_sum_, response_headers_, name, namelen, value,
|
|
||||||
valuelen, no_index, token);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Downstream::get_response_header_key_prev() const {
|
|
||||||
return response_header_key_prev_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::append_last_response_header_key(const char *data, size_t len) {
|
|
||||||
append_last_header_key(response_header_key_prev_, response_headers_sum_,
|
|
||||||
response_headers_, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::append_last_response_header_value(const char *data,
|
|
||||||
size_t len) {
|
|
||||||
append_last_header_value(response_header_key_prev_, response_headers_sum_,
|
|
||||||
response_headers_, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::clear_response_headers() {
|
|
||||||
Headers().swap(response_headers_);
|
|
||||||
http2::init_hdidx(response_hdidx_);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t Downstream::get_response_headers_sum() const {
|
|
||||||
return response_headers_sum_;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Headers &Downstream::get_response_trailers() const {
|
|
||||||
return response_trailers_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::add_response_trailer(const uint8_t *name, size_t namelen,
|
|
||||||
const uint8_t *value, size_t valuelen,
|
|
||||||
bool no_index, int16_t token) {
|
|
||||||
add_header(response_headers_sum_, response_trailers_, name, namelen, value,
|
|
||||||
valuelen, no_index, -1);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int Downstream::get_response_http_status() const {
|
|
||||||
return response_http_status_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::add_response_trailer(std::string name, std::string value) {
|
|
||||||
add_header(response_trailer_key_prev_, response_headers_sum_,
|
|
||||||
response_trailers_, 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 {
|
|
||||||
return response_trailer_key_prev_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::append_last_response_trailer_key(const char *data,
|
|
||||||
size_t len) {
|
|
||||||
append_last_header_key(response_trailer_key_prev_, response_headers_sum_,
|
|
||||||
response_trailers_, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::append_last_response_trailer_value(const char *data,
|
|
||||||
size_t len) {
|
|
||||||
append_last_header_value(response_trailer_key_prev_, response_headers_sum_,
|
|
||||||
response_trailers_, data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::set_response_http_status(unsigned int status) {
|
|
||||||
response_http_status_ = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::set_response_major(int major) { response_major_ = major; }
|
|
||||||
|
|
||||||
void Downstream::set_response_minor(int minor) { response_minor_ = minor; }
|
|
||||||
|
|
||||||
int Downstream::get_response_major() const { return response_major_; }
|
|
||||||
|
|
||||||
int Downstream::get_response_minor() const { return response_minor_; }
|
|
||||||
|
|
||||||
int Downstream::get_response_version() const {
|
|
||||||
return response_major_ * 100 + response_minor_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Downstream::get_chunked_response() const { return chunked_response_; }
|
bool Downstream::get_chunked_response() const { return chunked_response_; }
|
||||||
|
|
||||||
void Downstream::set_chunked_response(bool f) { chunked_response_ = f; }
|
void Downstream::set_chunked_response(bool f) { chunked_response_ = f; }
|
||||||
|
|
||||||
bool Downstream::get_response_connection_close() const {
|
|
||||||
return response_connection_close_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::set_response_connection_close(bool f) {
|
|
||||||
response_connection_close_ = f;
|
|
||||||
}
|
|
||||||
|
|
||||||
int Downstream::on_read() {
|
int Downstream::on_read() {
|
||||||
if (!dconn_) {
|
if (!dconn_) {
|
||||||
DLOG(INFO, this) << "dconn_ is NULL";
|
DLOG(INFO, this) << "dconn_ is NULL";
|
||||||
|
@ -826,14 +645,6 @@ int64_t Downstream::get_response_sent_bodylen() const {
|
||||||
return response_sent_bodylen_;
|
return response_sent_bodylen_;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Downstream::get_response_content_length() const {
|
|
||||||
return response_content_length_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Downstream::set_response_content_length(int64_t len) {
|
|
||||||
response_content_length_ = len;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Downstream::validate_request_bodylen() const {
|
bool Downstream::validate_request_bodylen() const {
|
||||||
if (req_.fs.content_length == -1) {
|
if (req_.fs.content_length == -1) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -852,14 +663,14 @@ bool Downstream::validate_request_bodylen() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Downstream::validate_response_bodylen() const {
|
bool Downstream::validate_response_bodylen() const {
|
||||||
if (!expect_response_body() || response_content_length_ == -1) {
|
if (!expect_response_body() || resp_.fs.content_length == -1) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response_content_length_ != response_bodylen_) {
|
if (resp_.fs.content_length != response_bodylen_) {
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
DLOG(INFO, this) << "response invalid bodylen: content-length="
|
DLOG(INFO, this) << "response invalid bodylen: content-length="
|
||||||
<< response_content_length_
|
<< resp_.fs.content_length
|
||||||
<< ", received=" << response_bodylen_;
|
<< ", received=" << response_bodylen_;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -874,12 +685,12 @@ int32_t Downstream::get_priority() const { return priority_; }
|
||||||
|
|
||||||
void Downstream::check_upgrade_fulfilled() {
|
void Downstream::check_upgrade_fulfilled() {
|
||||||
if (req_.method == HTTP_CONNECT) {
|
if (req_.method == HTTP_CONNECT) {
|
||||||
upgraded_ = 200 <= response_http_status_ && response_http_status_ < 300;
|
upgraded_ = 200 <= resp_.http_status && resp_.http_status < 300;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response_http_status_ == 101) {
|
if (resp_.http_status == 101) {
|
||||||
// TODO Do more strict checking for upgrade headers
|
// TODO Do more strict checking for upgrade headers
|
||||||
upgraded_ = req_.upgrade_request;
|
upgraded_ = req_.upgrade_request;
|
||||||
|
|
||||||
|
@ -921,23 +732,23 @@ void Downstream::inspect_http1_request() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Downstream::inspect_http1_response() {
|
void Downstream::inspect_http1_response() {
|
||||||
auto idx = response_hdidx_[http2::HD_TRANSFER_ENCODING];
|
auto transfer_encoding = resp_.fs.header(http2::HD_TRANSFER_ENCODING);
|
||||||
if (idx != -1) {
|
if (transfer_encoding) {
|
||||||
response_content_length_ = -1;
|
resp_.fs.content_length = -1;
|
||||||
if (util::strifind(response_headers_[idx].value.c_str(), "chunked")) {
|
if (util::strifind(transfer_encoding->value.c_str(), "chunked")) {
|
||||||
chunked_response_ = true;
|
chunked_response_ = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Downstream::reset_response() {
|
void Downstream::reset_response() {
|
||||||
response_http_status_ = 0;
|
resp_.http_status = 0;
|
||||||
response_major_ = 1;
|
resp_.http_major = 1;
|
||||||
response_minor_ = 1;
|
resp_.http_minor = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Downstream::get_non_final_response() const {
|
bool Downstream::get_non_final_response() const {
|
||||||
return !upgraded_ && response_http_status_ / 100 == 1;
|
return !upgraded_ && resp_.http_status / 100 == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Downstream::get_upgraded() const { return upgraded_; }
|
bool Downstream::get_upgraded() const { return upgraded_; }
|
||||||
|
@ -1004,24 +815,7 @@ size_t Downstream::get_response_datalen() const { return response_datalen_; }
|
||||||
void Downstream::reset_response_datalen() { response_datalen_ = 0; }
|
void Downstream::reset_response_datalen() { response_datalen_ = 0; }
|
||||||
|
|
||||||
bool Downstream::expect_response_body() const {
|
bool Downstream::expect_response_body() const {
|
||||||
return http2::expect_response_body(req_.method, response_http_status_);
|
return http2::expect_response_body(req_.method, resp_.http_status);
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
bool pseudo_header_allowed(const Headers &headers) {
|
|
||||||
if (headers.empty()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return headers.back().name.c_str()[0] == ':';
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
bool Downstream::response_pseudo_header_allowed(int16_t token) const {
|
|
||||||
if (!pseudo_header_allowed(response_headers_)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return http2::check_http2_response_pseudo_header(response_hdidx_, token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -1136,7 +930,7 @@ void Downstream::disable_downstream_wtimer() {
|
||||||
disable_timer(loop, &downstream_wtimer_);
|
disable_timer(loop, &downstream_wtimer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Downstream::accesslog_ready() const { return response_http_status_ > 0; }
|
bool Downstream::accesslog_ready() const { return resp_.http_status > 0; }
|
||||||
|
|
||||||
void Downstream::add_retry() { ++num_retry_; }
|
void Downstream::add_retry() { ++num_retry_; }
|
||||||
|
|
||||||
|
@ -1176,7 +970,7 @@ BlockedLink *Downstream::detach_blocked_link() {
|
||||||
bool Downstream::can_detach_downstream_connection() const {
|
bool Downstream::can_detach_downstream_connection() const {
|
||||||
return dconn_ && response_state_ == Downstream::MSG_COMPLETE &&
|
return dconn_ && response_state_ == Downstream::MSG_COMPLETE &&
|
||||||
request_state_ == Downstream::MSG_COMPLETE && !upgraded_ &&
|
request_state_ == Downstream::MSG_COMPLETE && !upgraded_ &&
|
||||||
!response_connection_close_;
|
!resp_.connection_close;
|
||||||
}
|
}
|
||||||
|
|
||||||
DefaultMemchunks Downstream::pop_response_buf() {
|
DefaultMemchunks Downstream::pop_response_buf() {
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
// the beginning. If no such header is found, returns nullptr.
|
// the beginning. If no such header is found, returns nullptr.
|
||||||
// This function must be called after headers are indexed
|
// This function must be called after headers are indexed
|
||||||
const Headers::value_type *header(int16_t token) const;
|
const Headers::value_type *header(int16_t token) const;
|
||||||
|
Headers::value_type *header(int16_t token);
|
||||||
// Returns pointer to the header field with the name |name|. If no
|
// Returns pointer to the header field with the name |name|. If no
|
||||||
// such header is found, returns nullptr.
|
// such header is found, returns nullptr.
|
||||||
const Headers::value_type *header(const std::string &name) const;
|
const Headers::value_type *header(const std::string &name) const;
|
||||||
|
@ -156,6 +157,18 @@ struct Request {
|
||||||
bool http2_expect_body;
|
bool http2_expect_body;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Response {
|
||||||
|
Response()
|
||||||
|
: fs(32), http_status(0), http_major(1), http_minor(1),
|
||||||
|
connection_close(false) {}
|
||||||
|
|
||||||
|
FieldStore fs;
|
||||||
|
// HTTP status code
|
||||||
|
unsigned int http_status;
|
||||||
|
int http_major, http_minor;
|
||||||
|
bool connection_close;
|
||||||
|
};
|
||||||
|
|
||||||
class Downstream {
|
class Downstream {
|
||||||
public:
|
public:
|
||||||
Downstream(Upstream *upstream, MemchunkPool *mcpool, int32_t stream_id,
|
Downstream(Upstream *upstream, MemchunkPool *mcpool, int32_t stream_id,
|
||||||
|
@ -251,58 +264,17 @@ public:
|
||||||
bool get_request_pending() const;
|
bool get_request_pending() const;
|
||||||
// Returns true if request is ready to be submitted to downstream.
|
// Returns true if request is ready to be submitted to downstream.
|
||||||
bool request_submission_ready() const;
|
bool request_submission_ready() const;
|
||||||
|
|
||||||
// downstream response API
|
// downstream response API
|
||||||
const Headers &get_response_headers() const;
|
const Response &response() const { return resp_; }
|
||||||
Headers &get_response_headers();
|
Response &response() { return resp_; }
|
||||||
// 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.
|
|
||||||
// This function must be called after response headers are indexed.
|
|
||||||
const Headers::value_type *get_response_header(int16_t token) const;
|
|
||||||
Headers::value_type *get_response_header(int16_t token);
|
|
||||||
// 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 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(const uint8_t *name, size_t namelen,
|
|
||||||
const uint8_t *value, size_t valuelen, bool no_index,
|
|
||||||
int16_t token);
|
|
||||||
|
|
||||||
bool get_response_header_key_prev() const;
|
|
||||||
void append_last_response_header_key(const char *data, size_t len);
|
|
||||||
void append_last_response_header_value(const char *data, size_t len);
|
|
||||||
// Empties response headers.
|
|
||||||
void clear_response_headers();
|
|
||||||
|
|
||||||
size_t get_response_headers_sum() const;
|
|
||||||
|
|
||||||
const Headers &get_response_trailers() const;
|
|
||||||
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);
|
|
||||||
void set_last_response_trailer_value(const char *data, size_t len);
|
|
||||||
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);
|
|
||||||
|
|
||||||
unsigned int get_response_http_status() const;
|
|
||||||
void set_response_http_status(unsigned int status);
|
|
||||||
void set_response_major(int major);
|
|
||||||
void set_response_minor(int minor);
|
|
||||||
int get_response_major() const;
|
|
||||||
int get_response_minor() const;
|
|
||||||
int get_response_version() const;
|
|
||||||
bool get_chunked_response() const;
|
bool get_chunked_response() const;
|
||||||
void set_chunked_response(bool f);
|
void set_chunked_response(bool f);
|
||||||
bool get_response_connection_close() const;
|
|
||||||
void set_response_connection_close(bool f);
|
|
||||||
void set_response_state(int state);
|
void set_response_state(int state);
|
||||||
int get_response_state() const;
|
int get_response_state() const;
|
||||||
DefaultMemchunks *get_response_buf();
|
DefaultMemchunks *get_response_buf();
|
||||||
|
@ -311,8 +283,6 @@ public:
|
||||||
int64_t get_response_bodylen() const;
|
int64_t get_response_bodylen() const;
|
||||||
void add_response_sent_bodylen(size_t amount);
|
void add_response_sent_bodylen(size_t amount);
|
||||||
int64_t get_response_sent_bodylen() const;
|
int64_t get_response_sent_bodylen() const;
|
||||||
int64_t get_response_content_length() const;
|
|
||||||
void set_response_content_length(int64_t len);
|
|
||||||
// Validates that received response body length and content-length
|
// Validates that received response body length and content-length
|
||||||
// matches.
|
// matches.
|
||||||
bool validate_response_bodylen() const;
|
bool validate_response_bodylen() const;
|
||||||
|
@ -331,7 +301,6 @@ public:
|
||||||
void dec_response_datalen(size_t len);
|
void dec_response_datalen(size_t len);
|
||||||
size_t get_response_datalen() const;
|
size_t get_response_datalen() const;
|
||||||
void reset_response_datalen();
|
void reset_response_datalen();
|
||||||
bool response_pseudo_header_allowed(int16_t token) const;
|
|
||||||
|
|
||||||
// Call this method when there is incoming data in downstream
|
// Call this method when there is incoming data in downstream
|
||||||
// connection.
|
// connection.
|
||||||
|
@ -402,12 +371,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Request req_;
|
Request req_;
|
||||||
|
Response resp_;
|
||||||
Headers response_headers_;
|
|
||||||
|
|
||||||
// trailer part. For HTTP/1.1, trailer part is only included with
|
|
||||||
// chunked encoding. For HTTP/2, there is no such limit.
|
|
||||||
Headers response_trailers_;
|
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point request_start_time_;
|
std::chrono::high_resolution_clock::time_point request_start_time_;
|
||||||
|
|
||||||
|
@ -434,17 +398,12 @@ private:
|
||||||
// the length of response body sent to upstream client
|
// the length of response body sent to upstream client
|
||||||
int64_t response_sent_bodylen_;
|
int64_t response_sent_bodylen_;
|
||||||
|
|
||||||
// content-length of response body, -1 if it is unknown.
|
|
||||||
int64_t response_content_length_;
|
|
||||||
|
|
||||||
Upstream *upstream_;
|
Upstream *upstream_;
|
||||||
std::unique_ptr<DownstreamConnection> dconn_;
|
std::unique_ptr<DownstreamConnection> dconn_;
|
||||||
|
|
||||||
// only used by HTTP/2 or SPDY upstream
|
// only used by HTTP/2 or SPDY upstream
|
||||||
BlockedLink *blocked_link_;
|
BlockedLink *blocked_link_;
|
||||||
|
|
||||||
size_t response_headers_sum_;
|
|
||||||
|
|
||||||
// The number of bytes not consumed by the application yet.
|
// The number of bytes not consumed by the application yet.
|
||||||
size_t request_datalen_;
|
size_t request_datalen_;
|
||||||
size_t response_datalen_;
|
size_t response_datalen_;
|
||||||
|
@ -460,26 +419,17 @@ private:
|
||||||
uint32_t response_rst_stream_error_code_;
|
uint32_t response_rst_stream_error_code_;
|
||||||
|
|
||||||
int request_state_;
|
int request_state_;
|
||||||
|
|
||||||
int response_state_;
|
int response_state_;
|
||||||
unsigned int response_http_status_;
|
|
||||||
int response_major_;
|
|
||||||
int response_minor_;
|
|
||||||
|
|
||||||
// only used by HTTP/2 or SPDY upstream
|
// only used by HTTP/2 or SPDY upstream
|
||||||
int dispatch_state_;
|
int dispatch_state_;
|
||||||
|
|
||||||
http2::HeaderIndex response_hdidx_;
|
|
||||||
|
|
||||||
// true if the connection is upgraded (HTTP Upgrade or CONNECT)
|
// true if the connection is upgraded (HTTP Upgrade or CONNECT)
|
||||||
bool upgraded_;
|
bool upgraded_;
|
||||||
|
|
||||||
bool chunked_request_;
|
bool chunked_request_;
|
||||||
|
|
||||||
bool chunked_response_;
|
bool chunked_response_;
|
||||||
bool response_connection_close_;
|
|
||||||
bool response_header_key_prev_;
|
|
||||||
bool response_trailer_key_prev_;
|
|
||||||
bool expect_final_response_;
|
bool expect_final_response_;
|
||||||
// true if downstream request is pending because backend connection
|
// true if downstream request is pending because backend connection
|
||||||
// has not been established or should be checked before use;
|
// has not been established or should be checked before use;
|
||||||
|
|
|
@ -32,17 +32,17 @@
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
void test_downstream_index_request_headers(void) {
|
void test_downstream_field_store_index_headers(void) {
|
||||||
Request req;
|
FieldStore fs(0);
|
||||||
req.fs.add_header("1", "0");
|
fs.add_header("1", "0");
|
||||||
req.fs.add_header("2", "1");
|
fs.add_header("2", "1");
|
||||||
req.fs.add_header("Charlie", "2");
|
fs.add_header("Charlie", "2");
|
||||||
req.fs.add_header("Alpha", "3");
|
fs.add_header("Alpha", "3");
|
||||||
req.fs.add_header("Delta", "4");
|
fs.add_header("Delta", "4");
|
||||||
req.fs.add_header("BravO", "5");
|
fs.add_header("BravO", "5");
|
||||||
req.fs.add_header(":method", "6");
|
fs.add_header(":method", "6");
|
||||||
req.fs.add_header(":authority", "7");
|
fs.add_header(":authority", "7");
|
||||||
req.fs.index_headers();
|
fs.index_headers();
|
||||||
|
|
||||||
auto ans = Headers{{"1", "0"},
|
auto ans = Headers{{"1", "0"},
|
||||||
{"2", "1"},
|
{"2", "1"},
|
||||||
|
@ -52,49 +52,23 @@ void test_downstream_index_request_headers(void) {
|
||||||
{"bravo", "5"},
|
{"bravo", "5"},
|
||||||
{":method", "6"},
|
{":method", "6"},
|
||||||
{":authority", "7"}};
|
{":authority", "7"}};
|
||||||
CU_ASSERT(ans == req.fs.headers());
|
CU_ASSERT(ans == fs.headers());
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_downstream_index_response_headers(void) {
|
void test_downstream_field_store_header(void) {
|
||||||
Downstream d(nullptr, nullptr, 0, 0);
|
FieldStore fs(0);
|
||||||
d.add_response_header("Charlie", "0");
|
fs.add_header("alpha", "0");
|
||||||
d.add_response_header("Alpha", "1");
|
fs.add_header(":authority", "1");
|
||||||
d.add_response_header("Delta", "2");
|
fs.add_header("content-length", "2");
|
||||||
d.add_response_header("BravO", "3");
|
fs.index_headers();
|
||||||
d.index_response_headers();
|
|
||||||
|
|
||||||
auto ans =
|
|
||||||
Headers{{"charlie", "0"}, {"alpha", "1"}, {"delta", "2"}, {"bravo", "3"}};
|
|
||||||
CU_ASSERT(ans == d.get_response_headers());
|
|
||||||
}
|
|
||||||
|
|
||||||
void test_downstream_get_request_header(void) {
|
|
||||||
Request req;
|
|
||||||
req.fs.add_header("alpha", "0");
|
|
||||||
req.fs.add_header(":authority", "1");
|
|
||||||
req.fs.add_header("content-length", "2");
|
|
||||||
req.fs.index_headers();
|
|
||||||
|
|
||||||
// By token
|
// By token
|
||||||
CU_ASSERT(Header(":authority", "1") == *req.fs.header(http2::HD__AUTHORITY));
|
CU_ASSERT(Header(":authority", "1") == *fs.header(http2::HD__AUTHORITY));
|
||||||
CU_ASSERT(nullptr == req.fs.header(http2::HD__METHOD));
|
CU_ASSERT(nullptr == fs.header(http2::HD__METHOD));
|
||||||
|
|
||||||
// By name
|
// By name
|
||||||
CU_ASSERT(Header("alpha", "0") == *req.fs.header("alpha"));
|
CU_ASSERT(Header("alpha", "0") == *fs.header("alpha"));
|
||||||
CU_ASSERT(nullptr == req.fs.header("bravo"));
|
CU_ASSERT(nullptr == fs.header("bravo"));
|
||||||
}
|
|
||||||
|
|
||||||
void test_downstream_get_response_header(void) {
|
|
||||||
Downstream d(nullptr, nullptr, 0, 0);
|
|
||||||
d.add_response_header("alpha", "0");
|
|
||||||
d.add_response_header(":status", "1");
|
|
||||||
d.add_response_header("content-length", "2");
|
|
||||||
d.index_response_headers();
|
|
||||||
|
|
||||||
// By token
|
|
||||||
CU_ASSERT(Header(":status", "1") ==
|
|
||||||
*d.get_response_header(http2::HD__STATUS));
|
|
||||||
CU_ASSERT(nullptr == d.get_response_header(http2::HD__METHOD));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_downstream_crumble_request_cookie(void) {
|
void test_downstream_crumble_request_cookie(void) {
|
||||||
|
@ -154,24 +128,26 @@ void test_downstream_rewrite_location_response_header(void) {
|
||||||
{
|
{
|
||||||
Downstream d(nullptr, nullptr, 0, 0);
|
Downstream d(nullptr, nullptr, 0, 0);
|
||||||
auto &req = d.request();
|
auto &req = d.request();
|
||||||
|
auto &resp = d.response();
|
||||||
d.set_request_downstream_host("localhost:3000");
|
d.set_request_downstream_host("localhost:3000");
|
||||||
req.fs.add_header("host", "localhost");
|
req.fs.add_header("host", "localhost");
|
||||||
d.add_response_header("location", "http://localhost:3000/");
|
resp.fs.add_header("location", "http://localhost:3000/");
|
||||||
req.fs.index_headers();
|
req.fs.index_headers();
|
||||||
d.index_response_headers();
|
resp.fs.index_headers();
|
||||||
d.rewrite_location_response_header("https");
|
d.rewrite_location_response_header("https");
|
||||||
auto location = d.get_response_header(http2::HD_LOCATION);
|
auto location = resp.fs.header(http2::HD_LOCATION);
|
||||||
CU_ASSERT("https://localhost/" == (*location).value);
|
CU_ASSERT("https://localhost/" == (*location).value);
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Downstream d(nullptr, nullptr, 0, 0);
|
Downstream d(nullptr, nullptr, 0, 0);
|
||||||
auto &req = d.request();
|
auto &req = d.request();
|
||||||
|
auto &resp = d.response();
|
||||||
d.set_request_downstream_host("localhost");
|
d.set_request_downstream_host("localhost");
|
||||||
req.authority = "localhost";
|
req.authority = "localhost";
|
||||||
d.add_response_header("location", "http://localhost:3000/");
|
resp.fs.add_header("location", "http://localhost:3000/");
|
||||||
d.index_response_headers();
|
resp.fs.index_headers();
|
||||||
d.rewrite_location_response_header("https");
|
d.rewrite_location_response_header("https");
|
||||||
auto location = d.get_response_header(http2::HD_LOCATION);
|
auto location = resp.fs.header(http2::HD_LOCATION);
|
||||||
CU_ASSERT("https://localhost/" == (*location).value);
|
CU_ASSERT("https://localhost/" == (*location).value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,10 +31,8 @@
|
||||||
|
|
||||||
namespace shrpx {
|
namespace shrpx {
|
||||||
|
|
||||||
void test_downstream_index_request_headers(void);
|
void test_downstream_field_store_index_headers(void);
|
||||||
void test_downstream_index_response_headers(void);
|
void test_downstream_field_store_header(void);
|
||||||
void test_downstream_get_request_header(void);
|
|
||||||
void test_downstream_get_response_header(void);
|
|
||||||
void test_downstream_crumble_request_cookie(void);
|
void test_downstream_crumble_request_cookie(void);
|
||||||
void test_downstream_assemble_request_cookie(void);
|
void test_downstream_assemble_request_cookie(void);
|
||||||
void test_downstream_rewrite_location_response_header(void);
|
void test_downstream_rewrite_location_response_header(void);
|
||||||
|
|
|
@ -752,6 +752,8 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
switch (frame->hd.type) {
|
switch (frame->hd.type) {
|
||||||
case NGHTTP2_HEADERS: {
|
case NGHTTP2_HEADERS: {
|
||||||
auto trailer = frame->headers.cat == NGHTTP2_HCAT_HEADERS &&
|
auto trailer = frame->headers.cat == NGHTTP2_HCAT_HEADERS &&
|
||||||
|
@ -759,14 +761,14 @@ int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||||
|
|
||||||
if (trailer) {
|
if (trailer) {
|
||||||
// just store header fields for trailer part
|
// just store header fields for trailer part
|
||||||
downstream->add_response_trailer(name, namelen, value, valuelen,
|
resp.fs.add_trailer(name, namelen, value, valuelen,
|
||||||
flags & NGHTTP2_NV_FLAG_NO_INDEX, -1);
|
flags & NGHTTP2_NV_FLAG_NO_INDEX, -1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto token = http2::lookup_token(name, namelen);
|
auto token = http2::lookup_token(name, namelen);
|
||||||
|
|
||||||
downstream->add_response_header(name, namelen, value, valuelen,
|
resp.fs.add_header(name, namelen, value, valuelen,
|
||||||
flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
|
flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -857,18 +859,19 @@ int on_response_headers(Http2Session *http2session, Downstream *downstream,
|
||||||
|
|
||||||
auto upstream = downstream->get_upstream();
|
auto upstream = downstream->get_upstream();
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
auto &nva = downstream->get_response_headers();
|
auto &nva = resp.fs.headers();
|
||||||
|
|
||||||
downstream->set_expect_final_response(false);
|
downstream->set_expect_final_response(false);
|
||||||
|
|
||||||
auto status = downstream->get_response_header(http2::HD__STATUS);
|
auto status = resp.fs.header(http2::HD__STATUS);
|
||||||
// libnghttp2 guarantees this exists and can be parsed
|
// libnghttp2 guarantees this exists and can be parsed
|
||||||
auto status_code = http2::parse_http_status_code(status->value);
|
auto status_code = http2::parse_http_status_code(status->value);
|
||||||
|
|
||||||
downstream->set_response_http_status(status_code);
|
resp.http_status = status_code;
|
||||||
downstream->set_response_major(2);
|
resp.http_major = 2;
|
||||||
downstream->set_response_minor(0);
|
resp.http_minor = 0;
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -904,7 +907,7 @@ int on_response_headers(Http2Session *http2session, Downstream *downstream,
|
||||||
downstream->check_upgrade_fulfilled();
|
downstream->check_upgrade_fulfilled();
|
||||||
|
|
||||||
if (downstream->get_upgraded()) {
|
if (downstream->get_upgraded()) {
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
// On upgrade sucess, both ends can send data
|
// On upgrade sucess, both ends can send data
|
||||||
if (upstream->resume_read(SHRPX_NO_BUFFER, downstream, 0) != 0) {
|
if (upstream->resume_read(SHRPX_NO_BUFFER, downstream, 0) != 0) {
|
||||||
// If resume_read fails, just drop connection. Not ideal.
|
// If resume_read fails, just drop connection. Not ideal.
|
||||||
|
@ -917,26 +920,23 @@ int on_response_headers(Http2Session *http2session, Downstream *downstream,
|
||||||
<< "HTTP upgrade success. stream_id=" << frame->hd.stream_id;
|
<< "HTTP upgrade success. stream_id=" << frame->hd.stream_id;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto content_length =
|
auto content_length = resp.fs.header(http2::HD_CONTENT_LENGTH);
|
||||||
downstream->get_response_header(http2::HD_CONTENT_LENGTH);
|
|
||||||
if (content_length) {
|
if (content_length) {
|
||||||
// libnghttp2 guarantees this can be parsed
|
// libnghttp2 guarantees this can be parsed
|
||||||
auto len = util::parse_uint(content_length->value);
|
resp.fs.content_length = util::parse_uint(content_length->value);
|
||||||
downstream->set_response_content_length(len);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downstream->get_response_content_length() == -1 &&
|
if (resp.fs.content_length == -1 && downstream->expect_response_body()) {
|
||||||
downstream->expect_response_body()) {
|
|
||||||
// Here we have response body but Content-Length is not known in
|
// Here we have response body but Content-Length is not known in
|
||||||
// advance.
|
// advance.
|
||||||
if (req.http_major <= 0 || (req.http_major == 1 && req.http_minor == 0)) {
|
if (req.http_major <= 0 || (req.http_major == 1 && req.http_minor == 0)) {
|
||||||
// We simply close connection for pre-HTTP/1.1 in this case.
|
// We simply close connection for pre-HTTP/1.1 in this case.
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, use chunked encoding to keep upstream connection
|
// Otherwise, use chunked encoding to keep upstream connection
|
||||||
// open. In HTTP2, we are supporsed not to receive
|
// open. In HTTP2, we are supporsed not to receive
|
||||||
// transfer-encoding.
|
// transfer-encoding.
|
||||||
downstream->add_response_header("transfer-encoding", "chunked",
|
resp.fs.add_header("transfer-encoding", "chunked",
|
||||||
http2::HD_TRANSFER_ENCODING);
|
http2::HD_TRANSFER_ENCODING);
|
||||||
downstream->set_chunked_response(true);
|
downstream->set_chunked_response(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1242,6 +1242,7 @@ ssize_t downstream_data_read_callback(nghttp2_session *session,
|
||||||
assert(body);
|
assert(body);
|
||||||
|
|
||||||
auto dconn = downstream->get_downstream_connection();
|
auto dconn = downstream->get_downstream_connection();
|
||||||
|
const auto &resp = downstream->response();
|
||||||
|
|
||||||
if (body->rleft() == 0 && dconn &&
|
if (body->rleft() == 0 && dconn &&
|
||||||
downstream->get_response_state() != Downstream::MSG_COMPLETE) {
|
downstream->get_response_state() != Downstream::MSG_COMPLETE) {
|
||||||
|
@ -1263,7 +1264,7 @@ ssize_t downstream_data_read_callback(nghttp2_session *session,
|
||||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||||
|
|
||||||
if (!downstream->get_upgraded()) {
|
if (!downstream->get_upgraded()) {
|
||||||
auto &trailers = downstream->get_response_trailers();
|
const auto &trailers = resp.fs.trailers();
|
||||||
if (!trailers.empty()) {
|
if (!trailers.empty()) {
|
||||||
std::vector<nghttp2_nv> nva;
|
std::vector<nghttp2_nv> nva;
|
||||||
nva.reserve(trailers.size());
|
nva.reserve(trailers.size());
|
||||||
|
@ -1303,18 +1304,19 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
data_prd_ptr = &data_prd;
|
data_prd_ptr = &data_prd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &headers = downstream->get_response_headers();
|
const auto &resp = downstream->response();
|
||||||
|
|
||||||
|
const auto &headers = resp.fs.headers();
|
||||||
auto nva = std::vector<nghttp2_nv>();
|
auto nva = std::vector<nghttp2_nv>();
|
||||||
// 2 for :status and server
|
// 2 for :status and server
|
||||||
nva.reserve(2 + headers.size());
|
nva.reserve(2 + headers.size());
|
||||||
|
|
||||||
std::string status_code_str;
|
std::string status_code_str;
|
||||||
auto response_status_const =
|
auto response_status_const = http2::stringify_status(resp.http_status);
|
||||||
http2::stringify_status(downstream->get_response_http_status());
|
|
||||||
if (response_status_const) {
|
if (response_status_const) {
|
||||||
nva.push_back(http2::make_nv_lc_nocopy(":status", response_status_const));
|
nva.push_back(http2::make_nv_lc_nocopy(":status", response_status_const));
|
||||||
} else {
|
} else {
|
||||||
status_code_str = util::utos(downstream->get_response_http_status());
|
status_code_str = util::utos(resp.http_status);
|
||||||
nva.push_back(http2::make_nv_ls(":status", status_code_str));
|
nva.push_back(http2::make_nv_ls(":status", status_code_str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1334,7 +1336,7 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
nva.push_back(http2::make_nv_nocopy(kv.name, kv.value, kv.no_index));
|
nva.push_back(http2::make_nv_nocopy(kv.name, kv.value, kv.no_index));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!downstream->get_response_header(http2::HD_SERVER)) {
|
if (!resp.fs.header(http2::HD_SERVER)) {
|
||||||
nva.push_back(
|
nva.push_back(
|
||||||
http2::make_nv_lc_nocopy("server", get_config()->server_name));
|
http2::make_nv_lc_nocopy("server", get_config()->server_name));
|
||||||
}
|
}
|
||||||
|
@ -1359,8 +1361,10 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
int Http2Upstream::error_reply(Downstream *downstream,
|
int Http2Upstream::error_reply(Downstream *downstream,
|
||||||
unsigned int status_code) {
|
unsigned int status_code) {
|
||||||
int rv;
|
int rv;
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
auto html = http::create_error_html(status_code);
|
auto html = http::create_error_html(status_code);
|
||||||
downstream->set_response_http_status(status_code);
|
resp.http_status = status_code;
|
||||||
auto body = downstream->get_response_buf();
|
auto body = downstream->get_response_buf();
|
||||||
body->append(html.c_str(), html.size());
|
body->append(html.c_str(), html.size());
|
||||||
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
||||||
|
@ -1429,6 +1433,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
if (downstream->get_non_final_response()) {
|
if (downstream->get_non_final_response()) {
|
||||||
|
@ -1462,25 +1467,24 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
}
|
}
|
||||||
#endif // HAVE_MRUBY
|
#endif // HAVE_MRUBY
|
||||||
|
|
||||||
size_t nheader = downstream->get_response_headers().size();
|
|
||||||
auto nva = std::vector<nghttp2_nv>();
|
auto nva = std::vector<nghttp2_nv>();
|
||||||
// 4 means :status and possible server, via and x-http2-push header
|
// 4 means :status and possible server, via and x-http2-push header
|
||||||
// field.
|
// field.
|
||||||
nva.reserve(nheader + 4 + get_config()->add_response_headers.size());
|
nva.reserve(resp.fs.headers().size() + 4 +
|
||||||
|
get_config()->add_response_headers.size());
|
||||||
std::string via_value;
|
std::string via_value;
|
||||||
std::string response_status;
|
std::string response_status;
|
||||||
|
|
||||||
auto response_status_const =
|
auto response_status_const = http2::stringify_status(resp.http_status);
|
||||||
http2::stringify_status(downstream->get_response_http_status());
|
|
||||||
if (response_status_const) {
|
if (response_status_const) {
|
||||||
nva.push_back(http2::make_nv_lc_nocopy(":status", response_status_const));
|
nva.push_back(http2::make_nv_lc_nocopy(":status", response_status_const));
|
||||||
} else {
|
} else {
|
||||||
response_status = util::utos(downstream->get_response_http_status());
|
response_status = util::utos(resp.http_status);
|
||||||
nva.push_back(http2::make_nv_ls(":status", response_status));
|
nva.push_back(http2::make_nv_ls(":status", response_status));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (downstream->get_non_final_response()) {
|
if (downstream->get_non_final_response()) {
|
||||||
http2::copy_headers_to_nva(nva, downstream->get_response_headers());
|
http2::copy_headers_to_nva(nva, resp.fs.headers());
|
||||||
|
|
||||||
if (LOG_ENABLED(INFO)) {
|
if (LOG_ENABLED(INFO)) {
|
||||||
log_response_headers(downstream, nva);
|
log_response_headers(downstream, nva);
|
||||||
|
@ -1490,7 +1494,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
downstream->get_stream_id(), nullptr,
|
downstream->get_stream_id(), nullptr,
|
||||||
nva.data(), nva.size(), nullptr);
|
nva.data(), nva.size(), nullptr);
|
||||||
|
|
||||||
downstream->clear_response_headers();
|
resp.fs.clear_headers();
|
||||||
|
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
ULOG(FATAL, this) << "nghttp2_submit_headers() failed";
|
ULOG(FATAL, this) << "nghttp2_submit_headers() failed";
|
||||||
|
@ -1500,19 +1504,19 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
http2::copy_headers_to_nva_nocopy(nva, downstream->get_response_headers());
|
http2::copy_headers_to_nva_nocopy(nva, resp.fs.headers());
|
||||||
|
|
||||||
if (!get_config()->http2_proxy && !get_config()->client_proxy) {
|
if (!get_config()->http2_proxy && !get_config()->client_proxy) {
|
||||||
nva.push_back(
|
nva.push_back(
|
||||||
http2::make_nv_lc_nocopy("server", get_config()->server_name));
|
http2::make_nv_lc_nocopy("server", get_config()->server_name));
|
||||||
} else {
|
} else {
|
||||||
auto server = downstream->get_response_header(http2::HD_SERVER);
|
auto server = resp.fs.header(http2::HD_SERVER);
|
||||||
if (server) {
|
if (server) {
|
||||||
nva.push_back(http2::make_nv_ls_nocopy("server", (*server).value));
|
nva.push_back(http2::make_nv_ls_nocopy("server", (*server).value));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto via = downstream->get_response_header(http2::HD_VIA);
|
auto via = resp.fs.header(http2::HD_VIA);
|
||||||
if (get_config()->no_via) {
|
if (get_config()->no_via) {
|
||||||
if (via) {
|
if (via) {
|
||||||
nva.push_back(http2::make_nv_ls_nocopy("via", (*via).value));
|
nva.push_back(http2::make_nv_ls_nocopy("via", (*via).value));
|
||||||
|
@ -1522,8 +1526,8 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
via_value = (*via).value;
|
via_value = (*via).value;
|
||||||
via_value += ", ";
|
via_value += ", ";
|
||||||
}
|
}
|
||||||
via_value += http::create_via_header_value(
|
via_value +=
|
||||||
downstream->get_response_major(), downstream->get_response_minor());
|
http::create_via_header_value(resp.http_major, resp.http_minor);
|
||||||
nva.push_back(http2::make_nv_ls("via", via_value));
|
nva.push_back(http2::make_nv_ls("via", via_value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1575,9 +1579,8 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
nghttp2_session_get_remote_settings(session_,
|
nghttp2_session_get_remote_settings(session_,
|
||||||
NGHTTP2_SETTINGS_ENABLE_PUSH) == 1 &&
|
NGHTTP2_SETTINGS_ENABLE_PUSH) == 1 &&
|
||||||
!get_config()->http2_proxy && !get_config()->client_proxy &&
|
!get_config()->http2_proxy && !get_config()->client_proxy &&
|
||||||
(downstream->get_stream_id() % 2) &&
|
(downstream->get_stream_id() % 2) && resp.fs.header(http2::HD_LINK) &&
|
||||||
downstream->get_response_header(http2::HD_LINK) &&
|
resp.http_status == 200 &&
|
||||||
downstream->get_response_http_status() == 200 &&
|
|
||||||
(req.method == HTTP_GET || req.method == HTTP_POST)) {
|
(req.method == HTTP_GET || req.method == HTTP_POST)) {
|
||||||
|
|
||||||
if (prepare_push_promise(downstream) != 0) {
|
if (prepare_push_promise(downstream) != 0) {
|
||||||
|
@ -1619,9 +1622,11 @@ int Http2Upstream::on_downstream_body_complete(Downstream *downstream) {
|
||||||
DLOG(INFO, downstream) << "HTTP response completed";
|
DLOG(INFO, downstream) << "HTTP response completed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
if (!downstream->validate_response_bodylen()) {
|
if (!downstream->validate_response_bodylen()) {
|
||||||
rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
|
rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1762,13 +1767,14 @@ int Http2Upstream::prepare_push_promise(Downstream *downstream) {
|
||||||
size_t baselen;
|
size_t baselen;
|
||||||
|
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
const auto &resp = downstream->response();
|
||||||
|
|
||||||
rv = http2::get_pure_path_component(&base, &baselen, req.path);
|
rv = http2::get_pure_path_component(&base, &baselen, req.path);
|
||||||
if (rv != 0) {
|
if (rv != 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &kv : downstream->get_response_headers()) {
|
for (auto &kv : resp.fs.headers()) {
|
||||||
if (kv.token != http2::HD_LINK) {
|
if (kv.token != http2::HD_LINK) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,9 +54,10 @@ void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
|
||||||
auto downstream = dconn->get_downstream();
|
auto downstream = dconn->get_downstream();
|
||||||
auto upstream = downstream->get_upstream();
|
auto upstream = downstream->get_upstream();
|
||||||
auto handler = upstream->get_client_handler();
|
auto handler = upstream->get_client_handler();
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
// Do this so that dconn is not pooled
|
// Do this so that dconn is not pooled
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
|
|
||||||
if (upstream->downstream_error(dconn, Downstream::EVENT_TIMEOUT) != 0) {
|
if (upstream->downstream_error(dconn, Downstream::EVENT_TIMEOUT) != 0) {
|
||||||
delete handler;
|
delete handler;
|
||||||
|
@ -482,13 +483,14 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
auto downstream = static_cast<Downstream *>(htp->data);
|
auto downstream = static_cast<Downstream *>(htp->data);
|
||||||
auto upstream = downstream->get_upstream();
|
auto upstream = downstream->get_upstream();
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
auto &resp = downstream->response();
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
downstream->set_response_http_status(htp->status_code);
|
resp.http_status = htp->status_code;
|
||||||
downstream->set_response_major(htp->http_major);
|
resp.http_major = htp->http_major;
|
||||||
downstream->set_response_minor(htp->http_minor);
|
resp.http_minor = htp->http_minor;
|
||||||
|
|
||||||
if (downstream->index_response_headers() != 0) {
|
if (resp.fs.index_headers() != 0) {
|
||||||
downstream->set_response_state(Downstream::MSG_BAD_HEADER);
|
downstream->set_response_state(Downstream::MSG_BAD_HEADER);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -500,7 +502,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
if (downstream->get_non_final_response()) {
|
if (downstream->get_non_final_response()) {
|
||||||
// Reset content-length because we reuse same Downstream for the
|
// Reset content-length because we reuse same Downstream for the
|
||||||
// next response.
|
// next response.
|
||||||
downstream->set_response_content_length(-1);
|
resp.fs.content_length = -1;
|
||||||
// For non-final response code, we just call
|
// For non-final response code, we just call
|
||||||
// on_downstream_header_complete() without changing response
|
// on_downstream_header_complete() without changing response
|
||||||
// state.
|
// state.
|
||||||
|
@ -514,13 +516,13 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
downstream->set_response_connection_close(!http_should_keep_alive(htp));
|
resp.connection_close = !http_should_keep_alive(htp);
|
||||||
downstream->set_response_state(Downstream::HEADER_COMPLETE);
|
downstream->set_response_state(Downstream::HEADER_COMPLETE);
|
||||||
downstream->inspect_http1_response();
|
downstream->inspect_http1_response();
|
||||||
if (downstream->get_upgraded()) {
|
if (downstream->get_upgraded()) {
|
||||||
// content-length must be ignored for upgraded connection.
|
// content-length must be ignored for upgraded connection.
|
||||||
downstream->set_response_content_length(-1);
|
resp.fs.content_length = -1;
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
// transfer-encoding not applied to upgraded connection
|
// transfer-encoding not applied to upgraded connection
|
||||||
downstream->set_chunked_response(false);
|
downstream->set_chunked_response(false);
|
||||||
}
|
}
|
||||||
|
@ -540,7 +542,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int status = downstream->get_response_http_status();
|
auto status = resp.http_status;
|
||||||
// Ignore the response body. HEAD response may contain
|
// Ignore the response body. HEAD response may contain
|
||||||
// Content-Length or Transfer-Encoding: chunked. Some server send
|
// Content-Length or Transfer-Encoding: chunked. Some server send
|
||||||
// 304 status code with nonzero Content-Length, but without response
|
// 304 status code with nonzero Content-Length, but without response
|
||||||
|
@ -559,18 +561,20 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
namespace {
|
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 downstream = static_cast<Downstream *>(htp->data);
|
auto downstream = static_cast<Downstream *>(htp->data);
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
if (downstream->get_response_state() == Downstream::INITIAL) {
|
if (downstream->get_response_state() == Downstream::INITIAL) {
|
||||||
if (downstream->get_response_header_key_prev()) {
|
if (resp.fs.header_key_prev()) {
|
||||||
downstream->append_last_response_header_key(data, len);
|
resp.fs.append_last_header_key(data, len);
|
||||||
} else {
|
} else {
|
||||||
downstream->add_response_header(std::string(data, len), "");
|
resp.fs.add_header(std::string(data, len), "");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// trailer part
|
// trailer part
|
||||||
if (downstream->get_response_trailer_key_prev()) {
|
if (resp.fs.trailer_key_prev()) {
|
||||||
downstream->append_last_response_trailer_key(data, len);
|
resp.fs.append_last_trailer_key(data, len);
|
||||||
} else {
|
} else {
|
||||||
downstream->add_response_trailer(std::string(data, len), "");
|
resp.fs.add_trailer(std::string(data, len), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -580,18 +584,12 @@ int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
|
||||||
namespace {
|
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 downstream = static_cast<Downstream *>(htp->data);
|
auto downstream = static_cast<Downstream *>(htp->data);
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
if (downstream->get_response_state() == Downstream::INITIAL) {
|
if (downstream->get_response_state() == Downstream::INITIAL) {
|
||||||
if (downstream->get_response_header_key_prev()) {
|
resp.fs.append_last_header_value(data, len);
|
||||||
downstream->set_last_response_header_value(data, len);
|
|
||||||
} else {
|
} else {
|
||||||
downstream->append_last_response_header_value(data, len);
|
resp.fs.append_last_trailer_value(data, len);
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (downstream->get_response_trailer_key_prev()) {
|
|
||||||
downstream->set_last_response_trailer_value(data, len);
|
|
||||||
} else {
|
|
||||||
downstream->append_last_response_trailer_value(data, len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,6 +247,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
}
|
}
|
||||||
auto downstream = upstream->get_downstream();
|
auto downstream = upstream->get_downstream();
|
||||||
auto &req = downstream->request();
|
auto &req = downstream->request();
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
req.http_major = htp->http_major;
|
req.http_major = htp->http_major;
|
||||||
req.http_minor = htp->http_minor;
|
req.http_minor = htp->http_minor;
|
||||||
|
@ -325,7 +326,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
||||||
auto mruby_ctx = worker->get_mruby_context();
|
auto mruby_ctx = worker->get_mruby_context();
|
||||||
|
|
||||||
if (mruby_ctx->run_on_request_proc(downstream) != 0) {
|
if (mruby_ctx->run_on_request_proc(downstream) != 0) {
|
||||||
downstream->set_response_http_status(500);
|
resp.http_status = 500;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif // HAVE_MRUBY
|
#endif // HAVE_MRUBY
|
||||||
|
@ -514,7 +515,7 @@ int HttpsUpstream::on_read() {
|
||||||
if (htperr == HPE_INVALID_METHOD) {
|
if (htperr == HPE_INVALID_METHOD) {
|
||||||
status_code = 501;
|
status_code = 501;
|
||||||
} else if (downstream) {
|
} else if (downstream) {
|
||||||
status_code = downstream->get_response_http_status();
|
status_code = downstream->response().http_status;
|
||||||
if (status_code == 0) {
|
if (status_code == 0) {
|
||||||
if (downstream->get_request_state() == Downstream::CONNECT_FAIL) {
|
if (downstream->get_request_state() == Downstream::CONNECT_FAIL) {
|
||||||
status_code = 503;
|
status_code = 503;
|
||||||
|
@ -558,6 +559,7 @@ int HttpsUpstream::on_write() {
|
||||||
|
|
||||||
auto dconn = downstream->get_downstream_connection();
|
auto dconn = downstream->get_downstream_connection();
|
||||||
auto output = downstream->get_response_buf();
|
auto output = downstream->get_response_buf();
|
||||||
|
const auto &resp = downstream->response();
|
||||||
|
|
||||||
if (output->rleft() == 0 && dconn &&
|
if (output->rleft() == 0 && dconn &&
|
||||||
downstream->get_response_state() != Downstream::MSG_COMPLETE) {
|
downstream->get_response_state() != Downstream::MSG_COMPLETE) {
|
||||||
|
@ -578,7 +580,7 @@ int HttpsUpstream::on_write() {
|
||||||
// We need to postpone detachment until all data are sent so that
|
// We need to postpone detachment until all data are sent so that
|
||||||
// we can notify nghttp2 library all data consumed.
|
// we can notify nghttp2 library all data consumed.
|
||||||
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
if (downstream->get_response_connection_close() ||
|
if (resp.connection_close ||
|
||||||
downstream->get_request_state() != Downstream::MSG_COMPLETE) {
|
downstream->get_request_state() != Downstream::MSG_COMPLETE) {
|
||||||
// Connection close
|
// Connection close
|
||||||
downstream->pop_downstream_connection();
|
downstream->pop_downstream_connection();
|
||||||
|
@ -754,30 +756,30 @@ int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
|
||||||
int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
size_t bodylen) {
|
size_t bodylen) {
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
auto connection_close = false;
|
auto connection_close = false;
|
||||||
if (req.http_major <= 0 || (req.http_major == 1 && req.http_minor == 0)) {
|
if (req.http_major <= 0 || (req.http_major == 1 && req.http_minor == 0)) {
|
||||||
connection_close = true;
|
connection_close = true;
|
||||||
} else {
|
} else {
|
||||||
auto c = downstream->get_response_header(http2::HD_CONNECTION);
|
auto c = resp.fs.header(http2::HD_CONNECTION);
|
||||||
if (c && util::strieq_l("close", c->value)) {
|
if (c && util::strieq_l("close", c->value)) {
|
||||||
connection_close = true;
|
connection_close = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connection_close) {
|
if (connection_close) {
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
handler_->set_should_close_after_write(true);
|
handler_->set_should_close_after_write(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output = downstream->get_response_buf();
|
auto output = downstream->get_response_buf();
|
||||||
|
|
||||||
output->append("HTTP/1.1 ");
|
output->append("HTTP/1.1 ");
|
||||||
output->append(
|
output->append(http2::get_status_string(resp.http_status));
|
||||||
http2::get_status_string(downstream->get_response_http_status()));
|
|
||||||
output->append("\r\n");
|
output->append("\r\n");
|
||||||
|
|
||||||
for (auto &kv : downstream->get_response_headers()) {
|
for (auto &kv : resp.fs.headers()) {
|
||||||
if (kv.name.empty() || kv.name[0] == ':') {
|
if (kv.name.empty() || kv.name[0] == ':') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -787,7 +789,7 @@ int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
output->append("\r\n");
|
output->append("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!downstream->get_response_header(http2::HD_SERVER)) {
|
if (!resp.fs.header(http2::HD_SERVER)) {
|
||||||
output->append("Server: ");
|
output->append("Server: ");
|
||||||
output->append(get_config()->server_name,
|
output->append(get_config()->server_name,
|
||||||
strlen(get_config()->server_name));
|
strlen(get_config()->server_name));
|
||||||
|
@ -814,10 +816,12 @@ void HttpsUpstream::error_reply(unsigned int status_code) {
|
||||||
downstream = get_downstream();
|
downstream = get_downstream();
|
||||||
}
|
}
|
||||||
|
|
||||||
downstream->set_response_http_status(status_code);
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
|
resp.http_status = status_code;
|
||||||
// we are going to close connection for both frontend and backend in
|
// we are going to close connection for both frontend and backend in
|
||||||
// error condition. This is safest option.
|
// error condition. This is safest option.
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
handler_->set_should_close_after_write(true);
|
handler_->set_should_close_after_write(true);
|
||||||
|
|
||||||
auto output = downstream->get_response_buf();
|
auto output = downstream->get_response_buf();
|
||||||
|
@ -883,6 +887,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
#ifdef HAVE_MRUBY
|
#ifdef HAVE_MRUBY
|
||||||
if (!downstream->get_non_final_response()) {
|
if (!downstream->get_non_final_response()) {
|
||||||
|
@ -909,7 +914,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
buf->append(".");
|
buf->append(".");
|
||||||
buf->append(util::utos(req.http_minor));
|
buf->append(util::utos(req.http_minor));
|
||||||
buf->append(" ");
|
buf->append(" ");
|
||||||
buf->append(http2::get_status_string(downstream->get_response_http_status()));
|
buf->append(http2::get_status_string(resp.http_status));
|
||||||
buf->append("\r\n");
|
buf->append("\r\n");
|
||||||
|
|
||||||
if (!get_config()->http2_proxy && !get_config()->client_proxy &&
|
if (!get_config()->http2_proxy && !get_config()->client_proxy &&
|
||||||
|
@ -918,8 +923,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
get_client_handler()->get_upstream_scheme());
|
get_client_handler()->get_upstream_scheme());
|
||||||
}
|
}
|
||||||
|
|
||||||
http2::build_http1_headers_from_headers(buf,
|
http2::build_http1_headers_from_headers(buf, resp.fs.headers());
|
||||||
downstream->get_response_headers());
|
|
||||||
|
|
||||||
if (downstream->get_non_final_response()) {
|
if (downstream->get_non_final_response()) {
|
||||||
buf->append("\r\n");
|
buf->append("\r\n");
|
||||||
|
@ -928,7 +932,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
log_response_headers(buf);
|
log_response_headers(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
downstream->clear_response_headers();
|
resp.fs.clear_headers();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -938,12 +942,12 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
// after graceful shutdown commenced, add connection: close header
|
// after graceful shutdown commenced, add connection: close header
|
||||||
// field.
|
// field.
|
||||||
if (worker->get_graceful_shutdown()) {
|
if (worker->get_graceful_shutdown()) {
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We check downstream->get_response_connection_close() in case when
|
// We check downstream->get_response_connection_close() in case when
|
||||||
// the Content-Length is not available.
|
// the Content-Length is not available.
|
||||||
if (!req.connection_close && !downstream->get_response_connection_close()) {
|
if (!req.connection_close && !resp.connection_close) {
|
||||||
if (req.http_major <= 0 || req.http_minor <= 0) {
|
if (req.http_major <= 0 || req.http_minor <= 0) {
|
||||||
// We add this header for HTTP/1.0 or HTTP/0.9 clients
|
// We add this header for HTTP/1.0 or HTTP/0.9 clients
|
||||||
buf->append("Connection: Keep-Alive\r\n");
|
buf->append("Connection: Keep-Alive\r\n");
|
||||||
|
@ -953,14 +957,14 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!connect_method && downstream->get_upgraded()) {
|
if (!connect_method && downstream->get_upgraded()) {
|
||||||
auto connection = downstream->get_response_header(http2::HD_CONNECTION);
|
auto connection = resp.fs.header(http2::HD_CONNECTION);
|
||||||
if (connection) {
|
if (connection) {
|
||||||
buf->append("Connection: ");
|
buf->append("Connection: ");
|
||||||
buf->append((*connection).value);
|
buf->append((*connection).value);
|
||||||
buf->append("\r\n");
|
buf->append("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto upgrade = downstream->get_response_header(http2::HD_UPGRADE);
|
auto upgrade = resp.fs.header(http2::HD_UPGRADE);
|
||||||
if (upgrade) {
|
if (upgrade) {
|
||||||
buf->append("Upgrade: ");
|
buf->append("Upgrade: ");
|
||||||
buf->append((*upgrade).value);
|
buf->append((*upgrade).value);
|
||||||
|
@ -968,7 +972,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!downstream->get_response_header(http2::HD_ALT_SVC)) {
|
if (!resp.fs.header(http2::HD_ALT_SVC)) {
|
||||||
// We won't change or alter alt-svc from backend for now
|
// We won't change or alter alt-svc from backend for now
|
||||||
if (!get_config()->altsvcs.empty()) {
|
if (!get_config()->altsvcs.empty()) {
|
||||||
buf->append("Alt-Svc: ");
|
buf->append("Alt-Svc: ");
|
||||||
|
@ -988,7 +992,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
buf->append(get_config()->server_name, strlen(get_config()->server_name));
|
buf->append(get_config()->server_name, strlen(get_config()->server_name));
|
||||||
buf->append("\r\n");
|
buf->append("\r\n");
|
||||||
} else {
|
} else {
|
||||||
auto server = downstream->get_response_header(http2::HD_SERVER);
|
auto server = resp.fs.header(http2::HD_SERVER);
|
||||||
if (server) {
|
if (server) {
|
||||||
buf->append("Server: ");
|
buf->append("Server: ");
|
||||||
buf->append((*server).value);
|
buf->append((*server).value);
|
||||||
|
@ -996,7 +1000,7 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto via = downstream->get_response_header(http2::HD_VIA);
|
auto via = resp.fs.header(http2::HD_VIA);
|
||||||
if (get_config()->no_via) {
|
if (get_config()->no_via) {
|
||||||
if (via) {
|
if (via) {
|
||||||
buf->append("Via: ");
|
buf->append("Via: ");
|
||||||
|
@ -1009,8 +1013,8 @@ int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
buf->append((*via).value);
|
buf->append((*via).value);
|
||||||
buf->append(", ");
|
buf->append(", ");
|
||||||
}
|
}
|
||||||
buf->append(http::create_via_header_value(
|
buf->append(
|
||||||
downstream->get_response_major(), downstream->get_response_minor()));
|
http::create_via_header_value(resp.http_major, resp.http_minor));
|
||||||
buf->append("\r\n");
|
buf->append("\r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1055,10 +1059,11 @@ int HttpsUpstream::on_downstream_body(Downstream *downstream,
|
||||||
|
|
||||||
int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
|
int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
|
||||||
const auto &req = downstream->request();
|
const auto &req = downstream->request();
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
if (downstream->get_chunked_response()) {
|
if (downstream->get_chunked_response()) {
|
||||||
auto output = downstream->get_response_buf();
|
auto output = downstream->get_response_buf();
|
||||||
auto &trailers = downstream->get_response_trailers();
|
const auto &trailers = resp.fs.trailers();
|
||||||
if (trailers.empty()) {
|
if (trailers.empty()) {
|
||||||
output->append("0\r\n\r\n");
|
output->append("0\r\n\r\n");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1072,10 +1077,10 @@ int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!downstream->validate_response_bodylen()) {
|
if (!downstream->validate_response_bodylen()) {
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.connection_close || downstream->get_response_connection_close()) {
|
if (req.connection_close || resp.connection_close) {
|
||||||
auto handler = get_client_handler();
|
auto handler = get_client_handler();
|
||||||
handler->set_should_close_after_write(true);
|
handler->set_should_close_after_write(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,7 +100,7 @@ int MRubyContext::run_app(Downstream *downstream, int phase) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.response_headers_dirty) {
|
if (data.response_headers_dirty) {
|
||||||
downstream->index_response_headers();
|
downstream->response().fs.index_headers();
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
|
|
|
@ -49,7 +49,8 @@ namespace {
|
||||||
mrb_value response_get_http_version_major(mrb_state *mrb, mrb_value self) {
|
mrb_value response_get_http_version_major(mrb_state *mrb, mrb_value self) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
return mrb_fixnum_value(downstream->get_response_major());
|
const auto &resp = downstream->response();
|
||||||
|
return mrb_fixnum_value(resp.http_major);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -57,7 +58,8 @@ namespace {
|
||||||
mrb_value response_get_http_version_minor(mrb_state *mrb, mrb_value self) {
|
mrb_value response_get_http_version_minor(mrb_state *mrb, mrb_value self) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
return mrb_fixnum_value(downstream->get_response_minor());
|
const auto &resp = downstream->response();
|
||||||
|
return mrb_fixnum_value(resp.http_minor);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -65,8 +67,8 @@ namespace {
|
||||||
mrb_value response_get_status(mrb_state *mrb, mrb_value self) {
|
mrb_value response_get_status(mrb_state *mrb, mrb_value self) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
|
const auto &resp = downstream->response();
|
||||||
return mrb_fixnum_value(downstream->get_response_http_status());
|
return mrb_fixnum_value(resp.http_status);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -74,6 +76,7 @@ namespace {
|
||||||
mrb_value response_set_status(mrb_state *mrb, mrb_value self) {
|
mrb_value response_set_status(mrb_state *mrb, mrb_value self) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
mrb_int status;
|
mrb_int status;
|
||||||
mrb_get_args(mrb, "i", &status);
|
mrb_get_args(mrb, "i", &status);
|
||||||
|
@ -83,7 +86,7 @@ mrb_value response_set_status(mrb_state *mrb, mrb_value self) {
|
||||||
"invalid status; it should be [200, 999], inclusive");
|
"invalid status; it should be [200, 999], inclusive");
|
||||||
}
|
}
|
||||||
|
|
||||||
downstream->set_response_http_status(status);
|
resp.http_status = status;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
@ -93,7 +96,9 @@ namespace {
|
||||||
mrb_value response_get_headers(mrb_state *mrb, mrb_value self) {
|
mrb_value response_get_headers(mrb_state *mrb, mrb_value self) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
return create_headers_hash(mrb, downstream->get_response_headers());
|
const auto &resp = downstream->response();
|
||||||
|
|
||||||
|
return create_headers_hash(mrb, resp.fs.headers());
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
@ -101,6 +106,7 @@ namespace {
|
||||||
mrb_value response_mod_header(mrb_state *mrb, mrb_value self, bool repl) {
|
mrb_value response_mod_header(mrb_state *mrb, mrb_value self, bool repl) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
mrb_value key, values;
|
mrb_value key, values;
|
||||||
mrb_get_args(mrb, "oo", &key, &values);
|
mrb_get_args(mrb, "oo", &key, &values);
|
||||||
|
@ -113,7 +119,7 @@ mrb_value response_mod_header(mrb_state *mrb, mrb_value self, bool repl) {
|
||||||
|
|
||||||
if (repl) {
|
if (repl) {
|
||||||
size_t p = 0;
|
size_t p = 0;
|
||||||
auto &headers = downstream->get_response_headers();
|
auto &headers = resp.fs.headers();
|
||||||
for (size_t i = 0; i < headers.size(); ++i) {
|
for (size_t i = 0; i < headers.size(); ++i) {
|
||||||
auto &hd = headers[i];
|
auto &hd = headers[i];
|
||||||
if (util::streq(std::begin(hd.name), hd.name.size(), RSTRING_PTR(key),
|
if (util::streq(std::begin(hd.name), hd.name.size(), RSTRING_PTR(key),
|
||||||
|
@ -131,13 +137,11 @@ mrb_value response_mod_header(mrb_state *mrb, mrb_value self, bool repl) {
|
||||||
auto n = mrb_ary_len(mrb, values);
|
auto n = mrb_ary_len(mrb, values);
|
||||||
for (int i = 0; i < n; ++i) {
|
for (int i = 0; i < n; ++i) {
|
||||||
auto value = mrb_ary_entry(values, i);
|
auto value = mrb_ary_entry(values, i);
|
||||||
downstream->add_response_header(
|
resp.fs.add_header(std::string(RSTRING_PTR(key), RSTRING_LEN(key)),
|
||||||
std::string(RSTRING_PTR(key), RSTRING_LEN(key)),
|
|
||||||
std::string(RSTRING_PTR(value), RSTRING_LEN(value)));
|
std::string(RSTRING_PTR(value), RSTRING_LEN(value)));
|
||||||
}
|
}
|
||||||
} else if (!mrb_nil_p(values)) {
|
} else if (!mrb_nil_p(values)) {
|
||||||
downstream->add_response_header(
|
resp.fs.add_header(std::string(RSTRING_PTR(key), RSTRING_LEN(key)),
|
||||||
std::string(RSTRING_PTR(key), RSTRING_LEN(key)),
|
|
||||||
std::string(RSTRING_PTR(values), RSTRING_LEN(values)));
|
std::string(RSTRING_PTR(values), RSTRING_LEN(values)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,8 +167,9 @@ namespace {
|
||||||
mrb_value response_clear_headers(mrb_state *mrb, mrb_value self) {
|
mrb_value response_clear_headers(mrb_state *mrb, mrb_value self) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
downstream->clear_response_headers();
|
resp.fs.clear_headers();
|
||||||
|
|
||||||
return mrb_nil_value();
|
return mrb_nil_value();
|
||||||
}
|
}
|
||||||
|
@ -174,6 +179,7 @@ namespace {
|
||||||
mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
||||||
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
auto data = static_cast<MRubyAssocData *>(mrb->ud);
|
||||||
auto downstream = data->downstream;
|
auto downstream = data->downstream;
|
||||||
|
auto &resp = downstream->response();
|
||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||||
|
@ -187,12 +193,12 @@ mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
||||||
const uint8_t *body = nullptr;
|
const uint8_t *body = nullptr;
|
||||||
size_t bodylen = 0;
|
size_t bodylen = 0;
|
||||||
|
|
||||||
if (downstream->get_response_http_status() == 0) {
|
if (resp.http_status == 0) {
|
||||||
downstream->set_response_http_status(200);
|
resp.http_status = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data->response_headers_dirty) {
|
if (data->response_headers_dirty) {
|
||||||
downstream->index_response_headers();
|
resp.fs.index_headers();
|
||||||
data->response_headers_dirty = false;
|
data->response_headers_dirty = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,21 +207,20 @@ mrb_value response_return(mrb_state *mrb, mrb_value self) {
|
||||||
bodylen = vallen;
|
bodylen = vallen;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto cl = downstream->get_response_header(http2::HD_CONTENT_LENGTH);
|
auto cl = resp.fs.header(http2::HD_CONTENT_LENGTH);
|
||||||
if (cl) {
|
if (cl) {
|
||||||
cl->value = util::utos(bodylen);
|
cl->value = util::utos(bodylen);
|
||||||
} else {
|
} else {
|
||||||
downstream->add_response_header("content-length", util::utos(bodylen),
|
resp.fs.add_header("content-length", util::utos(bodylen),
|
||||||
http2::HD_CONTENT_LENGTH);
|
http2::HD_CONTENT_LENGTH);
|
||||||
}
|
}
|
||||||
downstream->set_response_content_length(bodylen);
|
resp.fs.content_length = bodylen;
|
||||||
|
|
||||||
auto date = downstream->get_response_header(http2::HD_DATE);
|
auto date = resp.fs.header(http2::HD_DATE);
|
||||||
if (!date) {
|
if (!date) {
|
||||||
auto lgconf = log_config();
|
auto lgconf = log_config();
|
||||||
lgconf->update_tstamp(std::chrono::system_clock::now());
|
lgconf->update_tstamp(std::chrono::system_clock::now());
|
||||||
downstream->add_response_header("date", lgconf->time_http_str,
|
resp.fs.add_header("date", lgconf->time_http_str, http2::HD_DATE);
|
||||||
http2::HD_DATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto upstream = downstream->get_upstream();
|
auto upstream = downstream->get_upstream();
|
||||||
|
|
|
@ -820,10 +820,11 @@ int SpdyUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
data_prd_ptr = &data_prd;
|
data_prd_ptr = &data_prd;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto status_string =
|
const auto &resp = downstream->response();
|
||||||
http2::get_status_string(downstream->get_response_http_status());
|
|
||||||
|
|
||||||
auto &headers = downstream->get_response_headers();
|
auto status_string = http2::get_status_string(resp.http_status);
|
||||||
|
|
||||||
|
const auto &headers = resp.fs.headers();
|
||||||
|
|
||||||
auto nva = std::vector<const char *>();
|
auto nva = std::vector<const char *>();
|
||||||
// 3 for :status, :version and server
|
// 3 for :status, :version and server
|
||||||
|
@ -849,7 +850,7 @@ int SpdyUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
nva.push_back(kv.value.c_str());
|
nva.push_back(kv.value.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!downstream->get_response_header(http2::HD_SERVER)) {
|
if (!resp.fs.header(http2::HD_SERVER)) {
|
||||||
nva.push_back("server");
|
nva.push_back("server");
|
||||||
nva.push_back(get_config()->server_name);
|
nva.push_back(get_config()->server_name);
|
||||||
}
|
}
|
||||||
|
@ -876,8 +877,10 @@ int SpdyUpstream::send_reply(Downstream *downstream, const uint8_t *body,
|
||||||
int SpdyUpstream::error_reply(Downstream *downstream,
|
int SpdyUpstream::error_reply(Downstream *downstream,
|
||||||
unsigned int status_code) {
|
unsigned int status_code) {
|
||||||
int rv;
|
int rv;
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
auto html = http::create_error_html(status_code);
|
auto html = http::create_error_html(status_code);
|
||||||
downstream->set_response_http_status(status_code);
|
resp.http_status = status_code;
|
||||||
auto body = downstream->get_response_buf();
|
auto body = downstream->get_response_buf();
|
||||||
body->append(html.c_str(), html.size());
|
body->append(html.c_str(), html.size());
|
||||||
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
downstream->set_response_state(Downstream::MSG_COMPLETE);
|
||||||
|
@ -938,11 +941,13 @@ void SpdyUpstream::remove_downstream(Downstream *downstream) {
|
||||||
// WARNING: Never call directly or indirectly spdylay_session_send or
|
// WARNING: Never call directly or indirectly spdylay_session_send or
|
||||||
// spdylay_session_recv. These calls may delete downstream.
|
// spdylay_session_recv. These calls may delete downstream.
|
||||||
int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
|
int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
if (downstream->get_non_final_response()) {
|
if (downstream->get_non_final_response()) {
|
||||||
// SPDY does not support non-final response. We could send it
|
// SPDY does not support non-final response. We could send it
|
||||||
// with HEADERS and final response in SYN_REPLY, but it is not
|
// with HEADERS and final response in SYN_REPLY, but it is not
|
||||||
// official way.
|
// official way.
|
||||||
downstream->clear_response_headers();
|
resp.fs.clear_headers();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -974,20 +979,20 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
!get_config()->no_location_rewrite) {
|
!get_config()->no_location_rewrite) {
|
||||||
downstream->rewrite_location_response_header(req.scheme);
|
downstream->rewrite_location_response_header(req.scheme);
|
||||||
}
|
}
|
||||||
size_t nheader = downstream->get_response_headers().size();
|
|
||||||
// 8 means server, :status, :version and possible via header field.
|
// 8 means server, :status, :version and possible via header field.
|
||||||
auto nv = make_unique<const char *[]>(
|
auto nv = make_unique<const char *[]>(
|
||||||
nheader * 2 + 8 + get_config()->add_response_headers.size() * 2 + 1);
|
resp.fs.headers().size() * 2 + 8 +
|
||||||
|
get_config()->add_response_headers.size() * 2 + 1);
|
||||||
|
|
||||||
size_t hdidx = 0;
|
size_t hdidx = 0;
|
||||||
std::string via_value;
|
std::string via_value;
|
||||||
std::string status_string =
|
auto status_string = http2::get_status_string(resp.http_status);
|
||||||
http2::get_status_string(downstream->get_response_http_status());
|
|
||||||
nv[hdidx++] = ":status";
|
nv[hdidx++] = ":status";
|
||||||
nv[hdidx++] = status_string.c_str();
|
nv[hdidx++] = status_string.c_str();
|
||||||
nv[hdidx++] = ":version";
|
nv[hdidx++] = ":version";
|
||||||
nv[hdidx++] = "HTTP/1.1";
|
nv[hdidx++] = "HTTP/1.1";
|
||||||
for (auto &hd : downstream->get_response_headers()) {
|
for (auto &hd : resp.fs.headers()) {
|
||||||
if (hd.name.empty() || hd.name.c_str()[0] == ':') {
|
if (hd.name.empty() || hd.name.c_str()[0] == ':') {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1009,14 +1014,14 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
nv[hdidx++] = "server";
|
nv[hdidx++] = "server";
|
||||||
nv[hdidx++] = get_config()->server_name;
|
nv[hdidx++] = get_config()->server_name;
|
||||||
} else {
|
} else {
|
||||||
auto server = downstream->get_response_header(http2::HD_SERVER);
|
auto server = resp.fs.header(http2::HD_SERVER);
|
||||||
if (server) {
|
if (server) {
|
||||||
nv[hdidx++] = "server";
|
nv[hdidx++] = "server";
|
||||||
nv[hdidx++] = server->value.c_str();
|
nv[hdidx++] = server->value.c_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto via = downstream->get_response_header(http2::HD_VIA);
|
auto via = resp.fs.header(http2::HD_VIA);
|
||||||
if (get_config()->no_via) {
|
if (get_config()->no_via) {
|
||||||
if (via) {
|
if (via) {
|
||||||
nv[hdidx++] = "via";
|
nv[hdidx++] = "via";
|
||||||
|
@ -1027,8 +1032,8 @@ int SpdyUpstream::on_downstream_header_complete(Downstream *downstream) {
|
||||||
via_value = via->value;
|
via_value = via->value;
|
||||||
via_value += ", ";
|
via_value += ", ";
|
||||||
}
|
}
|
||||||
via_value += http::create_via_header_value(
|
via_value +=
|
||||||
downstream->get_response_major(), downstream->get_response_minor());
|
http::create_via_header_value(resp.http_major, resp.http_minor);
|
||||||
nv[hdidx++] = "via";
|
nv[hdidx++] = "via";
|
||||||
nv[hdidx++] = via_value.c_str();
|
nv[hdidx++] = via_value.c_str();
|
||||||
}
|
}
|
||||||
|
@ -1086,9 +1091,11 @@ int SpdyUpstream::on_downstream_body_complete(Downstream *downstream) {
|
||||||
DLOG(INFO, downstream) << "HTTP response completed";
|
DLOG(INFO, downstream) << "HTTP response completed";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto &resp = downstream->response();
|
||||||
|
|
||||||
if (!downstream->validate_response_bodylen()) {
|
if (!downstream->validate_response_bodylen()) {
|
||||||
rst_stream(downstream, SPDYLAY_PROTOCOL_ERROR);
|
rst_stream(downstream, SPDYLAY_PROTOCOL_ERROR);
|
||||||
downstream->set_response_connection_close(true);
|
resp.connection_close = true;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue