2 * nghttp2 - HTTP/2 C Library
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 #include "shrpx_downstream.h"
29 #include "http-parser/http_parser.h"
31 #include "shrpx_upstream.h"
32 #include "shrpx_client_handler.h"
33 #include "shrpx_config.h"
34 #include "shrpx_error.h"
35 #include "shrpx_downstream_connection.h"
36 #include "shrpx_downstream_queue.h"
43 void upstream_timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
44 auto downstream = static_cast<Downstream *>(w->data);
45 auto upstream = downstream->get_upstream();
47 auto which = revents == EV_READ ? "read" : "write";
49 if (LOG_ENABLED(INFO)) {
50 DLOG(INFO, downstream) << "upstream timeout stream_id="
51 << downstream->get_stream_id() << " event=" << which;
54 downstream->disable_upstream_rtimer();
55 downstream->disable_upstream_wtimer();
57 upstream->on_timeout(downstream);
62 void upstream_rtimeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
63 upstream_timeoutcb(loop, w, EV_READ);
68 void upstream_wtimeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
69 upstream_timeoutcb(loop, w, EV_WRITE);
74 void downstream_timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
75 auto downstream = static_cast<Downstream *>(w->data);
77 auto which = revents == EV_READ ? "read" : "write";
79 if (LOG_ENABLED(INFO)) {
80 DLOG(INFO, downstream) << "downstream timeout stream_id="
81 << downstream->get_downstream_stream_id()
82 << " event=" << which;
85 downstream->disable_downstream_rtimer();
86 downstream->disable_downstream_wtimer();
88 auto dconn = downstream->get_downstream_connection();
97 void downstream_rtimeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
98 downstream_timeoutcb(loop, w, EV_READ);
103 void downstream_wtimeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
104 downstream_timeoutcb(loop, w, EV_WRITE);
108 // upstream could be nullptr for unittests
109 Downstream::Downstream(Upstream *upstream, MemchunkPool *mcpool,
110 int32_t stream_id, int32_t priority)
111 : dlnext(nullptr), dlprev(nullptr),
112 request_start_time_(std::chrono::high_resolution_clock::now()),
113 request_buf_(mcpool), response_buf_(mcpool), request_bodylen_(0),
114 response_bodylen_(0), response_sent_bodylen_(0),
115 request_content_length_(-1), response_content_length_(-1),
116 upstream_(upstream), blocked_link_(nullptr), request_headers_sum_(0),
117 response_headers_sum_(0), request_datalen_(0), response_datalen_(0),
118 num_retry_(0), stream_id_(stream_id), priority_(priority),
119 downstream_stream_id_(-1),
120 response_rst_stream_error_code_(NGHTTP2_NO_ERROR),
121 request_state_(INITIAL), request_major_(1), request_minor_(1),
122 response_state_(INITIAL), response_http_status_(0), response_major_(1),
123 response_minor_(1), dispatch_state_(DISPATCH_NONE),
124 upgrade_request_(false), upgraded_(false), http2_upgrade_seen_(false),
125 chunked_request_(false), request_connection_close_(false),
126 request_header_key_prev_(false), request_trailer_key_prev_(false),
127 request_http2_expect_body_(false), chunked_response_(false),
128 response_connection_close_(false), response_header_key_prev_(false),
129 response_trailer_key_prev_(false), expect_final_response_(false),
130 request_pending_(false) {
132 ev_timer_init(&upstream_rtimer_, &upstream_rtimeoutcb, 0.,
133 get_config()->stream_read_timeout);
134 ev_timer_init(&upstream_wtimer_, &upstream_wtimeoutcb, 0.,
135 get_config()->stream_write_timeout);
136 ev_timer_init(&downstream_rtimer_, &downstream_rtimeoutcb, 0.,
137 get_config()->stream_read_timeout);
138 ev_timer_init(&downstream_wtimer_, &downstream_wtimeoutcb, 0.,
139 get_config()->stream_write_timeout);
141 upstream_rtimer_.data = this;
142 upstream_wtimer_.data = this;
143 downstream_rtimer_.data = this;
144 downstream_wtimer_.data = this;
146 http2::init_hdidx(request_hdidx_);
147 http2::init_hdidx(response_hdidx_);
150 Downstream::~Downstream() {
151 if (LOG_ENABLED(INFO)) {
152 DLOG(INFO, this) << "Deleting";
156 detach_blocked_link(blocked_link_);
159 // check nullptr for unittest
161 auto loop = upstream_->get_client_handler()->get_loop();
163 ev_timer_stop(loop, &upstream_rtimer_);
164 ev_timer_stop(loop, &upstream_wtimer_);
165 ev_timer_stop(loop, &downstream_rtimer_);
166 ev_timer_stop(loop, &downstream_wtimer_);
169 if (LOG_ENABLED(INFO)) {
170 DLOG(INFO, this) << "Deleted";
174 int Downstream::attach_downstream_connection(
175 std::unique_ptr<DownstreamConnection> dconn) {
176 if (dconn->attach_downstream(this) != 0) {
180 dconn_ = std::move(dconn);
185 void Downstream::detach_downstream_connection() {
190 dconn_->detach_downstream(this);
192 auto handler = dconn_->get_client_handler();
194 handler->pool_downstream_connection(
195 std::unique_ptr<DownstreamConnection>(dconn_.release()));
198 void Downstream::release_downstream_connection() { dconn_.release(); }
200 DownstreamConnection *Downstream::get_downstream_connection() {
204 std::unique_ptr<DownstreamConnection> Downstream::pop_downstream_connection() {
205 return std::unique_ptr<DownstreamConnection>(dconn_.release());
208 void Downstream::pause_read(IOCtrlReason reason) {
210 dconn_->pause_read(reason);
214 int Downstream::resume_read(IOCtrlReason reason, size_t consumed) {
216 return dconn_->resume_read(reason, consumed);
222 void Downstream::force_resume_read() {
224 dconn_->force_resume_read();
229 const Headers::value_type *get_header_linear(const Headers &headers,
230 const std::string &name) {
231 const Headers::value_type *res = nullptr;
232 for (auto &kv : headers) {
233 if (kv.name == name) {
241 const Headers &Downstream::get_request_headers() const {
242 return request_headers_;
245 void Downstream::assemble_request_cookie() {
246 std::string &cookie = assembled_request_cookie_;
248 for (auto &kv : request_headers_) {
249 if (kv.name.size() != 6 || kv.name[5] != 'e' ||
250 !util::streq_l("cooki", kv.name.c_str(), 5)) {
254 auto end = kv.value.find_last_not_of(" ;");
255 if (end == std::string::npos) {
258 cookie.append(std::begin(kv.value), std::begin(kv.value) + end + 1);
262 if (cookie.size() >= 2) {
263 cookie.erase(cookie.size() - 2);
267 Headers Downstream::crumble_request_cookie() {
269 for (auto &kv : request_headers_) {
270 if (kv.name.size() != 6 || kv.name[5] != 'e' ||
271 !util::streq_l("cooki", kv.name.c_str(), 5)) {
274 size_t last = kv.value.size();
276 for (size_t j = 0; j < last;) {
277 j = kv.value.find_first_not_of("\t ;", j);
278 if (j == std::string::npos) {
283 j = kv.value.find(';', j);
284 if (j == std::string::npos) {
288 cookie_hdrs.push_back(
289 Header("cookie", kv.value.substr(first, j - first), kv.no_index));
295 const std::string &Downstream::get_assembled_request_cookie() const {
296 return assembled_request_cookie_;
300 void add_header(bool &key_prev, size_t &sum, Headers &headers, std::string name,
303 sum += name.size() + value.size();
304 headers.emplace_back(std::move(name), std::move(value));
309 void append_last_header_key(bool key_prev, size_t &sum, Headers &headers,
310 const char *data, size_t len) {
313 auto &item = headers.back();
314 item.name.append(data, len);
319 void append_last_header_value(bool key_prev, size_t &sum, Headers &headers,
320 const char *data, size_t len) {
323 auto &item = headers.back();
324 item.value.append(data, len);
329 void set_last_header_value(bool &key_prev, size_t &sum, Headers &headers,
330 const char *data, size_t len) {
333 auto &item = headers.back();
334 item.value.assign(data, len);
339 int index_headers(http2::HeaderIndex &hdidx, Headers &headers,
340 int64_t &content_length) {
341 for (size_t i = 0; i < headers.size(); ++i) {
342 auto &kv = headers[i];
343 util::inp_strlower(kv.name);
345 auto token = http2::lookup_token(
346 reinterpret_cast<const uint8_t *>(kv.name.c_str()), kv.name.size());
352 http2::index_header(hdidx, token, i);
354 if (token == http2::HD_CONTENT_LENGTH) {
355 auto len = util::parse_uint(kv.value);
359 if (content_length != -1) {
362 content_length = len;
369 int Downstream::index_request_headers() {
370 return index_headers(request_hdidx_, request_headers_,
371 request_content_length_);
374 const Headers::value_type *Downstream::get_request_header(int16_t token) const {
375 return http2::get_header(request_hdidx_, token, request_headers_);
378 const Headers::value_type *
379 Downstream::get_request_header(const std::string &name) const {
380 return get_header_linear(request_headers_, name);
383 void Downstream::add_request_header(std::string name, std::string value) {
384 add_header(request_header_key_prev_, request_headers_sum_, request_headers_,
385 std::move(name), std::move(value));
388 void Downstream::set_last_request_header_value(const char *data, size_t len) {
389 set_last_header_value(request_header_key_prev_, request_headers_sum_,
390 request_headers_, data, len);
393 void Downstream::add_request_header(std::string name, std::string value,
395 http2::index_header(request_hdidx_, token, request_headers_.size());
396 request_headers_sum_ += name.size() + value.size();
397 request_headers_.emplace_back(std::move(name), std::move(value), false,
401 void Downstream::add_request_header(const uint8_t *name, size_t namelen,
402 const uint8_t *value, size_t valuelen,
403 bool no_index, int16_t token) {
404 http2::index_header(request_hdidx_, token, request_headers_.size());
405 request_headers_sum_ += namelen + valuelen;
406 http2::add_header(request_headers_, name, namelen, value, valuelen, no_index,
410 bool Downstream::get_request_header_key_prev() const {
411 return request_header_key_prev_;
414 void Downstream::append_last_request_header_key(const char *data, size_t len) {
415 append_last_header_key(request_header_key_prev_, request_headers_sum_,
416 request_headers_, data, len);
419 void Downstream::append_last_request_header_value(const char *data,
421 append_last_header_value(request_header_key_prev_, request_headers_sum_,
422 request_headers_, data, len);
425 void Downstream::clear_request_headers() {
426 Headers().swap(request_headers_);
427 http2::init_hdidx(request_hdidx_);
430 size_t Downstream::get_request_headers_sum() const {
431 return request_headers_sum_;
434 void Downstream::add_request_trailer(const uint8_t *name, size_t namelen,
435 const uint8_t *value, size_t valuelen,
436 bool no_index, int16_t token) {
437 // we never index trailer part. Header size limit should be applied
438 // to all request header fields combined.
439 request_headers_sum_ += namelen + valuelen;
440 http2::add_header(request_trailers_, name, namelen, value, valuelen, no_index,
444 const Headers &Downstream::get_request_trailers() const {
445 return request_trailers_;
448 void Downstream::add_request_trailer(std::string name, std::string value) {
449 add_header(request_trailer_key_prev_, request_headers_sum_, request_trailers_,
450 std::move(name), std::move(value));
453 void Downstream::set_last_request_trailer_value(const char *data, size_t len) {
454 set_last_header_value(request_trailer_key_prev_, request_headers_sum_,
455 request_trailers_, data, len);
458 bool Downstream::get_request_trailer_key_prev() const {
459 return request_trailer_key_prev_;
462 void Downstream::append_last_request_trailer_key(const char *data, size_t len) {
463 append_last_header_key(request_trailer_key_prev_, request_headers_sum_,
464 request_trailers_, data, len);
467 void Downstream::append_last_request_trailer_value(const char *data,
469 append_last_header_value(request_trailer_key_prev_, request_headers_sum_,
470 request_trailers_, data, len);
473 void Downstream::set_request_method(std::string method) {
474 request_method_ = std::move(method);
477 const std::string &Downstream::get_request_method() const {
478 return request_method_;
481 void Downstream::set_request_path(std::string path) {
482 request_path_ = std::move(path);
485 void Downstream::append_request_path(const char *data, size_t len) {
486 request_path_.append(data, len);
489 const std::string &Downstream::get_request_path() const {
490 return request_path_;
493 void Downstream::set_request_start_time(
494 std::chrono::high_resolution_clock::time_point time) {
495 request_start_time_ = std::move(time);
498 const std::chrono::high_resolution_clock::time_point &
499 Downstream::get_request_start_time() const {
500 return request_start_time_;
503 const std::string &Downstream::get_request_http2_scheme() const {
504 return request_http2_scheme_;
507 void Downstream::set_request_http2_scheme(std::string scheme) {
508 request_http2_scheme_ = std::move(scheme);
511 const std::string &Downstream::get_request_http2_authority() const {
512 return request_http2_authority_;
515 void Downstream::set_request_http2_authority(std::string authority) {
516 request_http2_authority_ = std::move(authority);
519 void Downstream::set_request_major(int major) { request_major_ = major; }
521 void Downstream::set_request_minor(int minor) { request_minor_ = minor; }
523 int Downstream::get_request_major() const { return request_major_; }
525 int Downstream::get_request_minor() const { return request_minor_; }
527 void Downstream::reset_upstream(Upstream *upstream) {
528 upstream_ = upstream;
530 dconn_->on_upstream_change(upstream);
534 Upstream *Downstream::get_upstream() const { return upstream_; }
536 void Downstream::set_stream_id(int32_t stream_id) { stream_id_ = stream_id; }
538 int32_t Downstream::get_stream_id() const { return stream_id_; }
540 void Downstream::set_request_state(int state) { request_state_ = state; }
542 int Downstream::get_request_state() const { return request_state_; }
544 bool Downstream::get_chunked_request() const { return chunked_request_; }
546 void Downstream::set_chunked_request(bool f) { chunked_request_ = f; }
548 bool Downstream::get_request_connection_close() const {
549 return request_connection_close_;
552 void Downstream::set_request_connection_close(bool f) {
553 request_connection_close_ = f;
556 bool Downstream::get_request_http2_expect_body() const {
557 return request_http2_expect_body_;
560 void Downstream::set_request_http2_expect_body(bool f) {
561 request_http2_expect_body_ = f;
564 bool Downstream::request_buf_full() {
566 return request_buf_.rleft() >= get_config()->downstream_request_buffer_size;
572 DefaultMemchunks *Downstream::get_request_buf() { return &request_buf_; }
574 // Call this function after this object is attached to
575 // Downstream. Otherwise, the program will crash.
576 int Downstream::push_request_headers() {
578 DLOG(INFO, this) << "dconn_ is NULL";
581 return dconn_->push_request_headers();
584 int Downstream::push_upload_data_chunk(const uint8_t *data, size_t datalen) {
585 // Assumes that request headers have already been pushed to output
586 // buffer using push_request_headers().
588 DLOG(INFO, this) << "dconn_ is NULL";
591 request_bodylen_ += datalen;
592 if (dconn_->push_upload_data_chunk(data, datalen) != 0) {
596 request_datalen_ += datalen;
601 int Downstream::end_upload_data() {
603 DLOG(INFO, this) << "dconn_ is NULL";
606 return dconn_->end_upload_data();
609 const Headers &Downstream::get_response_headers() const {
610 return response_headers_;
613 int Downstream::index_response_headers() {
614 return index_headers(response_hdidx_, response_headers_,
615 response_content_length_);
618 const Headers::value_type *
619 Downstream::get_response_header(int16_t token) const {
620 return http2::get_header(response_hdidx_, token, response_headers_);
623 void Downstream::rewrite_location_response_header(
624 const std::string &upstream_scheme) {
626 http2::get_header(response_hdidx_, http2::HD_LOCATION, response_headers_);
631 memset(&u, 0, sizeof(u));
633 http_parser_parse_url((*hd).value.c_str(), (*hd).value.size(), 0, &u);
638 if (get_config()->no_host_rewrite || request_method_ == "CONNECT") {
639 if (!request_http2_authority_.empty()) {
640 new_uri = http2::rewrite_location_uri(
641 (*hd).value, u, request_http2_authority_, request_http2_authority_,
644 if (new_uri.empty()) {
645 auto host = get_request_header(http2::HD_HOST);
647 new_uri = http2::rewrite_location_uri((*hd).value, u, (*host).value,
648 (*host).value, upstream_scheme);
649 } else if (!request_downstream_host_.empty()) {
650 new_uri = http2::rewrite_location_uri(
651 (*hd).value, u, request_downstream_host_, "", upstream_scheme);
657 if (request_downstream_host_.empty()) {
660 if (!request_http2_authority_.empty()) {
661 new_uri = http2::rewrite_location_uri(
662 (*hd).value, u, request_downstream_host_, request_http2_authority_,
665 auto host = get_request_header(http2::HD_HOST);
667 new_uri = http2::rewrite_location_uri((*hd).value, u,
668 request_downstream_host_,
669 (*host).value, upstream_scheme);
671 new_uri = http2::rewrite_location_uri(
672 (*hd).value, u, request_downstream_host_, "", upstream_scheme);
676 if (!new_uri.empty()) {
677 auto idx = response_hdidx_[http2::HD_LOCATION];
678 response_headers_[idx].value = std::move(new_uri);
682 void Downstream::add_response_header(std::string name, std::string value) {
683 add_header(response_header_key_prev_, response_headers_sum_,
684 response_headers_, std::move(name), std::move(value));
687 void Downstream::set_last_response_header_value(const char *data, size_t len) {
688 set_last_header_value(response_header_key_prev_, response_headers_sum_,
689 response_headers_, data, len);
692 void Downstream::add_response_header(std::string name, std::string value,
694 http2::index_header(response_hdidx_, token, response_headers_.size());
695 response_headers_sum_ += name.size() + value.size();
696 response_headers_.emplace_back(std::move(name), std::move(value), false,
700 void Downstream::add_response_header(const uint8_t *name, size_t namelen,
701 const uint8_t *value, size_t valuelen,
702 bool no_index, int16_t token) {
703 http2::index_header(response_hdidx_, token, response_headers_.size());
704 response_headers_sum_ += namelen + valuelen;
705 http2::add_header(response_headers_, name, namelen, value, valuelen, no_index,
709 bool Downstream::get_response_header_key_prev() const {
710 return response_header_key_prev_;
713 void Downstream::append_last_response_header_key(const char *data, size_t len) {
714 append_last_header_key(response_header_key_prev_, response_headers_sum_,
715 response_headers_, data, len);
718 void Downstream::append_last_response_header_value(const char *data,
720 append_last_header_value(response_header_key_prev_, response_headers_sum_,
721 response_headers_, data, len);
724 void Downstream::clear_response_headers() {
725 Headers().swap(response_headers_);
726 http2::init_hdidx(response_hdidx_);
729 size_t Downstream::get_response_headers_sum() const {
730 return response_headers_sum_;
733 const Headers &Downstream::get_response_trailers() const {
734 return response_trailers_;
737 void Downstream::add_response_trailer(const uint8_t *name, size_t namelen,
738 const uint8_t *value, size_t valuelen,
739 bool no_index, int16_t token) {
740 response_headers_sum_ += namelen + valuelen;
741 http2::add_header(response_trailers_, name, namelen, value, valuelen,
745 unsigned int Downstream::get_response_http_status() const {
746 return response_http_status_;
749 void Downstream::add_response_trailer(std::string name, std::string value) {
750 add_header(response_trailer_key_prev_, response_headers_sum_,
751 response_trailers_, std::move(name), std::move(value));
754 void Downstream::set_last_response_trailer_value(const char *data, size_t len) {
755 set_last_header_value(response_trailer_key_prev_, response_headers_sum_,
756 response_trailers_, data, len);
759 bool Downstream::get_response_trailer_key_prev() const {
760 return response_trailer_key_prev_;
763 void Downstream::append_last_response_trailer_key(const char *data,
765 append_last_header_key(response_trailer_key_prev_, response_headers_sum_,
766 response_trailers_, data, len);
769 void Downstream::append_last_response_trailer_value(const char *data,
771 append_last_header_value(response_trailer_key_prev_, response_headers_sum_,
772 response_trailers_, data, len);
775 void Downstream::set_response_http_status(unsigned int status) {
776 response_http_status_ = status;
779 void Downstream::set_response_major(int major) { response_major_ = major; }
781 void Downstream::set_response_minor(int minor) { response_minor_ = minor; }
783 int Downstream::get_response_major() const { return response_major_; }
785 int Downstream::get_response_minor() const { return response_minor_; }
787 int Downstream::get_response_version() const {
788 return response_major_ * 100 + response_minor_;
791 bool Downstream::get_chunked_response() const { return chunked_response_; }
793 void Downstream::set_chunked_response(bool f) { chunked_response_ = f; }
795 bool Downstream::get_response_connection_close() const {
796 return response_connection_close_;
799 void Downstream::set_response_connection_close(bool f) {
800 response_connection_close_ = f;
803 int Downstream::on_read() {
805 DLOG(INFO, this) << "dconn_ is NULL";
808 return dconn_->on_read();
811 int Downstream::change_priority(int32_t pri) {
813 DLOG(INFO, this) << "dconn_ is NULL";
816 return dconn_->on_priority_change(pri);
819 void Downstream::set_response_state(int state) { response_state_ = state; }
821 int Downstream::get_response_state() const { return response_state_; }
823 DefaultMemchunks *Downstream::get_response_buf() { return &response_buf_; }
825 bool Downstream::response_buf_full() {
827 return response_buf_.rleft() >=
828 get_config()->downstream_response_buffer_size;
834 void Downstream::add_response_bodylen(size_t amount) {
835 response_bodylen_ += amount;
838 int64_t Downstream::get_response_bodylen() const { return response_bodylen_; }
840 void Downstream::add_response_sent_bodylen(size_t amount) {
841 response_sent_bodylen_ += amount;
844 int64_t Downstream::get_response_sent_bodylen() const {
845 return response_sent_bodylen_;
848 int64_t Downstream::get_response_content_length() const {
849 return response_content_length_;
852 void Downstream::set_response_content_length(int64_t len) {
853 response_content_length_ = len;
856 int64_t Downstream::get_request_content_length() const {
857 return request_content_length_;
860 void Downstream::set_request_content_length(int64_t len) {
861 request_content_length_ = len;
864 bool Downstream::validate_request_bodylen() const {
865 if (request_content_length_ == -1) {
869 if (request_content_length_ != request_bodylen_) {
870 if (LOG_ENABLED(INFO)) {
871 DLOG(INFO, this) << "request invalid bodylen: content-length="
872 << request_content_length_
873 << ", received=" << request_bodylen_;
881 bool Downstream::validate_response_bodylen() const {
882 if (!expect_response_body() || response_content_length_ == -1) {
886 if (response_content_length_ != response_bodylen_) {
887 if (LOG_ENABLED(INFO)) {
888 DLOG(INFO, this) << "response invalid bodylen: content-length="
889 << response_content_length_
890 << ", received=" << response_bodylen_;
898 void Downstream::set_priority(int32_t pri) { priority_ = pri; }
900 int32_t Downstream::get_priority() const { return priority_; }
902 void Downstream::check_upgrade_fulfilled() {
903 if (request_method_ == "CONNECT") {
904 upgraded_ = 200 <= response_http_status_ && response_http_status_ < 300;
909 if (response_http_status_ == 101) {
910 // TODO Do more strict checking for upgrade headers
911 upgraded_ = upgrade_request_;
917 void Downstream::inspect_http2_request() {
918 if (request_method_ == "CONNECT") {
919 upgrade_request_ = true;
923 void Downstream::inspect_http1_request() {
924 if (request_method_ == "CONNECT") {
925 upgrade_request_ = true;
928 if (!upgrade_request_) {
929 auto idx = request_hdidx_[http2::HD_UPGRADE];
931 upgrade_request_ = true;
933 auto &val = request_headers_[idx].value;
934 // TODO Perform more strict checking for upgrade headers
935 if (util::streq_l(NGHTTP2_CLEARTEXT_PROTO_VERSION_ID, val.c_str(),
937 http2_upgrade_seen_ = true;
941 auto idx = request_hdidx_[http2::HD_TRANSFER_ENCODING];
943 request_content_length_ = -1;
944 if (util::strifind(request_headers_[idx].value.c_str(), "chunked")) {
945 chunked_request_ = true;
950 void Downstream::inspect_http1_response() {
951 auto idx = response_hdidx_[http2::HD_TRANSFER_ENCODING];
953 response_content_length_ = -1;
954 if (util::strifind(response_headers_[idx].value.c_str(), "chunked")) {
955 chunked_response_ = true;
960 void Downstream::reset_response() {
961 response_http_status_ = 0;
966 bool Downstream::get_non_final_response() const {
967 return response_http_status_ / 100 == 1;
970 bool Downstream::get_upgraded() const { return upgraded_; }
972 bool Downstream::get_upgrade_request() const { return upgrade_request_; }
974 bool Downstream::get_http2_upgrade_request() const {
975 return request_bodylen_ == 0 && http2_upgrade_seen_ &&
976 request_hdidx_[http2::HD_HTTP2_SETTINGS] != -1;
980 const std::string EMPTY;
983 const std::string &Downstream::get_http2_settings() const {
984 auto idx = request_hdidx_[http2::HD_HTTP2_SETTINGS];
988 return request_headers_[idx].value;
991 void Downstream::set_downstream_stream_id(int32_t stream_id) {
992 downstream_stream_id_ = stream_id;
995 int32_t Downstream::get_downstream_stream_id() const {
996 return downstream_stream_id_;
999 uint32_t Downstream::get_response_rst_stream_error_code() const {
1000 return response_rst_stream_error_code_;
1003 void Downstream::set_response_rst_stream_error_code(uint32_t error_code) {
1004 response_rst_stream_error_code_ = error_code;
1007 void Downstream::set_expect_final_response(bool f) {
1008 expect_final_response_ = f;
1011 bool Downstream::get_expect_final_response() const {
1012 return expect_final_response_;
1015 size_t Downstream::get_request_datalen() const { return request_datalen_; }
1017 void Downstream::dec_request_datalen(size_t len) {
1018 assert(request_datalen_ >= len);
1019 request_datalen_ -= len;
1022 void Downstream::reset_request_datalen() { request_datalen_ = 0; }
1024 void Downstream::add_response_datalen(size_t len) { response_datalen_ += len; }
1026 void Downstream::dec_response_datalen(size_t len) {
1027 assert(response_datalen_ >= len);
1028 response_datalen_ -= len;
1031 size_t Downstream::get_response_datalen() const { return response_datalen_; }
1033 void Downstream::reset_response_datalen() { response_datalen_ = 0; }
1035 bool Downstream::expect_response_body() const {
1036 return http2::expect_response_body(request_method_, response_http_status_);
1040 bool pseudo_header_allowed(const Headers &headers) {
1041 if (headers.empty()) {
1045 return headers.back().name.c_str()[0] == ':';
1049 bool Downstream::request_pseudo_header_allowed(int16_t token) const {
1050 if (!pseudo_header_allowed(request_headers_)) {
1053 return http2::check_http2_request_pseudo_header(request_hdidx_, token);
1056 bool Downstream::response_pseudo_header_allowed(int16_t token) const {
1057 if (!pseudo_header_allowed(response_headers_)) {
1060 return http2::check_http2_response_pseudo_header(response_hdidx_, token);
1064 void reset_timer(struct ev_loop *loop, ev_timer *w) { ev_timer_again(loop, w); }
1068 void try_reset_timer(struct ev_loop *loop, ev_timer *w) {
1069 if (!ev_is_active(w)) {
1072 ev_timer_again(loop, w);
1077 void ensure_timer(struct ev_loop *loop, ev_timer *w) {
1078 if (ev_is_active(w)) {
1081 ev_timer_again(loop, w);
1086 void disable_timer(struct ev_loop *loop, ev_timer *w) {
1087 ev_timer_stop(loop, w);
1091 void Downstream::reset_upstream_rtimer() {
1092 if (get_config()->stream_read_timeout == 0.) {
1095 auto loop = upstream_->get_client_handler()->get_loop();
1096 reset_timer(loop, &upstream_rtimer_);
1099 void Downstream::reset_upstream_wtimer() {
1100 auto loop = upstream_->get_client_handler()->get_loop();
1101 if (get_config()->stream_write_timeout != 0.) {
1102 reset_timer(loop, &upstream_wtimer_);
1104 if (get_config()->stream_read_timeout != 0.) {
1105 try_reset_timer(loop, &upstream_rtimer_);
1109 void Downstream::ensure_upstream_wtimer() {
1110 if (get_config()->stream_write_timeout == 0.) {
1113 auto loop = upstream_->get_client_handler()->get_loop();
1114 ensure_timer(loop, &upstream_wtimer_);
1117 void Downstream::disable_upstream_rtimer() {
1118 if (get_config()->stream_read_timeout == 0.) {
1121 auto loop = upstream_->get_client_handler()->get_loop();
1122 disable_timer(loop, &upstream_rtimer_);
1125 void Downstream::disable_upstream_wtimer() {
1126 if (get_config()->stream_write_timeout == 0.) {
1129 auto loop = upstream_->get_client_handler()->get_loop();
1130 disable_timer(loop, &upstream_wtimer_);
1133 void Downstream::reset_downstream_rtimer() {
1134 if (get_config()->stream_read_timeout == 0.) {
1137 auto loop = upstream_->get_client_handler()->get_loop();
1138 reset_timer(loop, &downstream_rtimer_);
1141 void Downstream::reset_downstream_wtimer() {
1142 auto loop = upstream_->get_client_handler()->get_loop();
1143 if (get_config()->stream_write_timeout != 0.) {
1144 reset_timer(loop, &downstream_wtimer_);
1146 if (get_config()->stream_read_timeout != 0.) {
1147 try_reset_timer(loop, &downstream_rtimer_);
1151 void Downstream::ensure_downstream_wtimer() {
1152 if (get_config()->stream_write_timeout == 0.) {
1155 auto loop = upstream_->get_client_handler()->get_loop();
1156 ensure_timer(loop, &downstream_wtimer_);
1159 void Downstream::disable_downstream_rtimer() {
1160 if (get_config()->stream_read_timeout == 0.) {
1163 auto loop = upstream_->get_client_handler()->get_loop();
1164 disable_timer(loop, &downstream_rtimer_);
1167 void Downstream::disable_downstream_wtimer() {
1168 if (get_config()->stream_write_timeout == 0.) {
1171 auto loop = upstream_->get_client_handler()->get_loop();
1172 disable_timer(loop, &downstream_wtimer_);
1175 bool Downstream::accesslog_ready() const { return response_http_status_ > 0; }
1177 void Downstream::add_retry() { ++num_retry_; }
1179 bool Downstream::no_more_retry() const { return num_retry_ > 5; }
1181 void Downstream::set_request_downstream_host(std::string host) {
1182 request_downstream_host_ = std::move(host);
1185 void Downstream::set_request_pending(bool f) { request_pending_ = f; }
1187 bool Downstream::get_request_pending() const { return request_pending_; }
1189 bool Downstream::request_submission_ready() const {
1190 return (request_state_ == Downstream::HEADER_COMPLETE ||
1191 request_state_ == Downstream::MSG_COMPLETE) &&
1192 request_pending_ && response_state_ == Downstream::INITIAL;
1195 int Downstream::get_dispatch_state() const { return dispatch_state_; }
1197 void Downstream::set_dispatch_state(int s) { dispatch_state_ = s; }
1199 void Downstream::attach_blocked_link(BlockedLink *l) {
1200 assert(!blocked_link_);
1202 l->downstream = this;
1206 void Downstream::detach_blocked_link(BlockedLink *l) {
1207 assert(blocked_link_);
1208 assert(l->downstream == this);
1210 l->downstream = nullptr;
1211 blocked_link_ = nullptr;
1214 void Downstream::add_request_headers_sum(size_t amount) {
1215 request_headers_sum_ += amount;
1218 } // namespace shrpx