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_https_upstream.h"
31 #include "shrpx_client_handler.h"
32 #include "shrpx_downstream.h"
33 #include "shrpx_downstream_connection.h"
34 #include "shrpx_http.h"
35 #include "shrpx_config.h"
36 #include "shrpx_error.h"
37 #include "shrpx_log_config.h"
38 #include "shrpx_worker.h"
43 using namespace nghttp2;
47 HttpsUpstream::HttpsUpstream(ClientHandler *handler)
48 : handler_(handler), current_header_length_(0),
49 ioctrl_(handler->get_rlimit()) {
50 http_parser_init(&htp_, HTTP_REQUEST);
54 HttpsUpstream::~HttpsUpstream() {}
56 void HttpsUpstream::reset_current_header_length() {
57 current_header_length_ = 0;
61 int htp_msg_begin(http_parser *htp) {
62 auto upstream = static_cast<HttpsUpstream *>(htp->data);
63 if (LOG_ENABLED(INFO)) {
64 ULOG(INFO, upstream) << "HTTP request started";
66 upstream->reset_current_header_length();
68 auto handler = upstream->get_client_handler();
70 // TODO specify 0 as priority for now
71 upstream->attach_downstream(
72 make_unique<Downstream>(upstream, handler->get_mcpool(), 0, 0));
78 int htp_uricb(http_parser *htp, const char *data, size_t len) {
79 auto upstream = static_cast<HttpsUpstream *>(htp->data);
80 auto downstream = upstream->get_downstream();
81 if (downstream->get_request_headers_sum() + len >
82 get_config()->header_field_buffer) {
83 if (LOG_ENABLED(INFO)) {
84 ULOG(INFO, upstream) << "Too large URI size="
85 << downstream->get_request_headers_sum() + len;
87 assert(downstream->get_request_state() == Downstream::INITIAL);
88 downstream->set_request_state(Downstream::HTTP1_REQUEST_HEADER_TOO_LARGE);
91 downstream->add_request_headers_sum(len);
92 downstream->append_request_path(data, len);
98 int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
99 auto upstream = static_cast<HttpsUpstream *>(htp->data);
100 auto downstream = upstream->get_downstream();
101 if (downstream->get_request_headers_sum() + len >
102 get_config()->header_field_buffer) {
103 if (LOG_ENABLED(INFO)) {
104 ULOG(INFO, upstream) << "Too large header block size="
105 << downstream->get_request_headers_sum() + len;
107 if (downstream->get_request_state() == Downstream::INITIAL) {
108 downstream->set_request_state(Downstream::HTTP1_REQUEST_HEADER_TOO_LARGE);
112 if (downstream->get_request_state() == Downstream::INITIAL) {
113 if (downstream->get_request_header_key_prev()) {
114 downstream->append_last_request_header_key(data, len);
116 if (downstream->get_request_headers().size() >=
117 get_config()->max_header_fields) {
118 if (LOG_ENABLED(INFO)) {
119 ULOG(INFO, upstream) << "Too many header field num="
120 << downstream->get_request_headers().size() + 1;
122 downstream->set_request_state(
123 Downstream::HTTP1_REQUEST_HEADER_TOO_LARGE);
126 downstream->add_request_header(std::string(data, len), "");
130 if (downstream->get_request_trailer_key_prev()) {
131 downstream->append_last_request_trailer_key(data, len);
133 if (downstream->get_request_headers().size() >=
134 get_config()->max_header_fields) {
135 if (LOG_ENABLED(INFO)) {
136 ULOG(INFO, upstream) << "Too many header field num="
137 << downstream->get_request_headers().size() + 1;
141 downstream->add_request_trailer(std::string(data, len), "");
149 int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
150 auto upstream = static_cast<HttpsUpstream *>(htp->data);
151 auto downstream = upstream->get_downstream();
152 if (downstream->get_request_headers_sum() + len >
153 get_config()->header_field_buffer) {
154 if (LOG_ENABLED(INFO)) {
155 ULOG(INFO, upstream) << "Too large header block size="
156 << downstream->get_request_headers_sum() + len;
158 if (downstream->get_request_state() == Downstream::INITIAL) {
159 downstream->set_request_state(Downstream::HTTP1_REQUEST_HEADER_TOO_LARGE);
163 if (downstream->get_request_state() == Downstream::INITIAL) {
164 if (downstream->get_request_header_key_prev()) {
165 downstream->set_last_request_header_value(data, len);
167 downstream->append_last_request_header_value(data, len);
170 if (downstream->get_request_trailer_key_prev()) {
171 downstream->set_last_request_trailer_value(data, len);
173 downstream->append_last_request_trailer_value(data, len);
181 void rewrite_request_host_path_from_uri(Downstream *downstream, const char *uri,
182 http_parser_url &u) {
183 assert(u.field_set & (1 << UF_HOST));
185 // As per https://tools.ietf.org/html/rfc7230#section-5.4, we
186 // rewrite host header field with authority component.
187 std::string authority;
188 http2::copy_url_component(authority, &u, UF_HOST, uri);
189 // TODO properly check IPv6 numeric address
190 if (authority.find(':') != std::string::npos) {
191 authority = '[' + authority;
194 if (u.field_set & (1 << UF_PORT)) {
196 authority += util::utos(u.port);
198 downstream->set_request_http2_authority(authority);
201 if (u.field_set & (1 << UF_PATH)) {
202 http2::copy_url_component(path, &u, UF_PATH, uri);
203 } else if (downstream->get_request_method() == "OPTIONS") {
204 // Server-wide OPTIONS takes following form in proxy request:
206 // OPTIONS http://example.org HTTP/1.1
208 // Notice that no slash after authority. See
209 // http://tools.ietf.org/html/rfc7230#section-5.3.4
210 downstream->set_request_path("*");
211 // we ignore query component here
216 if (u.field_set & (1 << UF_QUERY)) {
217 auto &fdata = u.field_data[UF_QUERY];
219 path.append(uri + fdata.off, fdata.len);
221 downstream->set_request_path(std::move(path));
222 if (get_config()->http2_proxy || get_config()->client_proxy) {
224 http2::copy_url_component(scheme, &u, UF_SCHEMA, uri);
225 downstream->set_request_http2_scheme(std::move(scheme));
231 int htp_hdrs_completecb(http_parser *htp) {
233 auto upstream = static_cast<HttpsUpstream *>(htp->data);
234 if (LOG_ENABLED(INFO)) {
235 ULOG(INFO, upstream) << "HTTP request headers completed";
237 auto downstream = upstream->get_downstream();
239 downstream->set_request_method(
240 http_method_str((enum http_method)htp->method));
241 downstream->set_request_major(htp->http_major);
242 downstream->set_request_minor(htp->http_minor);
244 downstream->set_request_connection_close(!http_should_keep_alive(htp));
246 if (LOG_ENABLED(INFO)) {
247 std::stringstream ss;
248 ss << downstream->get_request_method() << " "
249 << downstream->get_request_path() << " "
250 << "HTTP/" << downstream->get_request_major() << "."
251 << downstream->get_request_minor() << "\n";
252 const auto &headers = downstream->get_request_headers();
253 for (size_t i = 0; i < headers.size(); ++i) {
254 ss << TTY_HTTP_HD << headers[i].name << TTY_RST << ": "
255 << headers[i].value << "\n";
257 ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
260 if (downstream->index_request_headers() != 0) {
264 if (downstream->get_request_major() == 1 &&
265 downstream->get_request_minor() == 1 &&
266 !downstream->get_request_header(http2::HD_HOST)) {
270 downstream->inspect_http1_request();
272 if (downstream->get_request_method() != "CONNECT") {
274 // make a copy of request path, since we may set request path
275 // while we are refering to original request path.
276 auto uri = downstream->get_request_path();
277 rv = http_parser_parse_url(uri.c_str(),
278 downstream->get_request_path().size(), 0, &u);
280 // Expect to respond with 400 bad request
283 // checking UF_HOST could be redundant, but just in case ...
284 if (!(u.field_set & (1 << UF_SCHEMA)) || !(u.field_set & (1 << UF_HOST))) {
285 if (get_config()->http2_proxy || get_config()->client_proxy) {
286 // Request URI should be absolute-form for client proxy mode
290 rewrite_request_host_path_from_uri(downstream, uri.c_str(), u);
294 rv = downstream->attach_downstream_connection(
295 upstream->get_client_handler()->get_downstream_connection());
298 downstream->set_request_state(Downstream::CONNECT_FAIL);
303 rv = downstream->push_request_headers();
309 downstream->set_request_state(Downstream::HEADER_COMPLETE);
316 int htp_bodycb(http_parser *htp, const char *data, size_t len) {
318 auto upstream = static_cast<HttpsUpstream *>(htp->data);
319 auto downstream = upstream->get_downstream();
320 rv = downstream->push_upload_data_chunk(
321 reinterpret_cast<const uint8_t *>(data), len);
330 int htp_msg_completecb(http_parser *htp) {
332 auto upstream = static_cast<HttpsUpstream *>(htp->data);
333 if (LOG_ENABLED(INFO)) {
334 ULOG(INFO, upstream) << "HTTP request completed";
336 auto handler = upstream->get_client_handler();
337 auto downstream = upstream->get_downstream();
338 downstream->set_request_state(Downstream::MSG_COMPLETE);
339 rv = downstream->end_upload_data();
344 if (handler->get_http2_upgrade_allowed() &&
345 downstream->get_http2_upgrade_request() &&
346 handler->perform_http2_upgrade(upstream) != 0) {
347 if (LOG_ENABLED(INFO)) {
348 ULOG(INFO, upstream) << "HTTP Upgrade to HTTP/2 failed";
352 // Stop further processing to complete this request
353 http_parser_pause(htp, 1);
359 http_parser_settings htp_hooks = {
360 htp_msg_begin, // http_cb on_message_begin;
361 htp_uricb, // http_data_cb on_url;
362 nullptr, // http_data_cb on_status;
363 htp_hdr_keycb, // http_data_cb on_header_field;
364 htp_hdr_valcb, // http_data_cb on_header_value;
365 htp_hdrs_completecb, // http_cb on_headers_complete;
366 htp_bodycb, // http_data_cb on_body;
367 htp_msg_completecb // http_cb on_message_complete;
371 // on_read() does not consume all available data in input buffer if
372 // one http request is fully received.
373 int HttpsUpstream::on_read() {
374 auto rb = handler_->get_rb();
375 auto rlimit = handler_->get_rlimit();
376 auto downstream = get_downstream();
378 if (rb->rleft() == 0) {
382 // downstream can be nullptr here, because it is initialized in the
383 // callback chain called by http_parser_execute()
384 if (downstream && downstream->get_upgraded()) {
386 auto rv = downstream->push_upload_data_chunk(rb->pos, rb->rleft());
395 if (downstream->request_buf_full()) {
396 if (LOG_ENABLED(INFO)) {
397 ULOG(INFO, this) << "Downstream request buf is full";
399 pause_read(SHRPX_NO_BUFFER);
408 // To avoid reading next pipelined request
409 switch (downstream->get_request_state()) {
410 case Downstream::INITIAL:
411 case Downstream::HEADER_COMPLETE:
418 // http_parser_execute() does nothing once it entered error state.
419 auto nread = http_parser_execute(
420 &htp_, &htp_hooks, reinterpret_cast<const char *>(rb->pos), rb->rleft());
425 // Well, actually header length + some body bytes
426 current_header_length_ += nread;
428 // Get downstream again because it may be initialized in http parser
430 downstream = get_downstream();
432 auto htperr = HTTP_PARSER_ERRNO(&htp_);
434 if (htperr == HPE_PAUSED) {
438 if (htperr != HPE_OK) {
439 if (LOG_ENABLED(INFO)) {
440 ULOG(INFO, this) << "HTTP parse failure: "
441 << "(" << http_errno_name(htperr) << ") "
442 << http_errno_description(htperr);
445 if (downstream && downstream->get_response_state() != Downstream::INITIAL) {
446 handler_->set_should_close_after_write(true);
447 handler_->signal_write();
451 unsigned int status_code;
454 if (downstream->get_request_state() == Downstream::CONNECT_FAIL) {
456 } else if (downstream->get_request_state() ==
457 Downstream::HTTP1_REQUEST_HEADER_TOO_LARGE) {
466 error_reply(status_code);
468 handler_->signal_write();
473 // downstream can be NULL here.
474 if (downstream && downstream->request_buf_full()) {
475 if (LOG_ENABLED(INFO)) {
476 ULOG(INFO, this) << "Downstream request buffer is full";
479 pause_read(SHRPX_NO_BUFFER);
487 int HttpsUpstream::on_write() {
488 auto downstream = get_downstream();
492 auto wb = handler_->get_wb();
493 if (wb->wleft() == 0) {
497 auto dconn = downstream->get_downstream_connection();
498 auto output = downstream->get_response_buf();
500 if (output->rleft() == 0 && dconn &&
501 downstream->get_response_state() != Downstream::MSG_COMPLETE) {
502 if (downstream->resume_read(SHRPX_NO_BUFFER,
503 downstream->get_response_datalen()) != 0) {
507 if (downstream_read(dconn) != 0) {
512 auto n = output->remove(wb->last, wb->wleft());
515 if (wb->rleft() > 0) {
519 // We need to postpone detachment until all data are sent so that
520 // we can notify nghttp2 library all data consumed.
521 if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
522 if (downstream->get_response_connection_close()) {
524 downstream->pop_downstream_connection();
528 downstream->detach_downstream_connection();
530 // We need this if response ends before request.
531 if (downstream->get_request_state() == Downstream::MSG_COMPLETE) {
533 return resume_read(SHRPX_NO_BUFFER, nullptr, 0);
537 return downstream->resume_read(SHRPX_NO_BUFFER,
538 downstream->get_response_datalen());
541 int HttpsUpstream::on_event() { return 0; }
543 ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; }
545 void HttpsUpstream::pause_read(IOCtrlReason reason) {
546 ioctrl_.pause_read(reason);
549 int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream,
551 // downstream could be nullptr
552 if (downstream && downstream->request_buf_full()) {
555 if (ioctrl_.resume_read(reason)) {
556 // Process remaining data in input buffer here because these bytes
557 // are not notified by readcb until new data arrive.
558 http_parser_pause(&htp_, 0);
565 int HttpsUpstream::downstream_read(DownstreamConnection *dconn) {
566 auto downstream = dconn->get_downstream();
569 rv = downstream->on_read();
571 if (rv == SHRPX_ERR_EOF) {
572 return downstream_eof(dconn);
576 return downstream_error(dconn, Downstream::EVENT_ERROR);
579 if (downstream->get_response_state() == Downstream::MSG_RESET) {
583 if (downstream->get_response_state() == Downstream::MSG_BAD_HEADER) {
585 downstream->pop_downstream_connection();
589 // Detach downstream connection early so that it could be reused
590 // without hitting server's request timeout.
591 if (downstream->get_response_state() == Downstream::MSG_COMPLETE &&
592 !downstream->get_response_connection_close()) {
594 downstream->detach_downstream_connection();
598 handler_->signal_write();
603 int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
605 rv = dconn->on_write();
606 if (rv == SHRPX_ERR_NETWORK) {
607 return downstream_error(dconn, Downstream::EVENT_ERROR);
617 int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
618 auto downstream = dconn->get_downstream();
620 if (LOG_ENABLED(INFO)) {
621 DCLOG(INFO, dconn) << "EOF";
624 if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
628 if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
629 // Server may indicate the end of the request by EOF
630 if (LOG_ENABLED(INFO)) {
631 DCLOG(INFO, dconn) << "The end of the response body was indicated by "
634 on_downstream_body_complete(downstream);
635 downstream->set_response_state(Downstream::MSG_COMPLETE);
636 downstream->pop_downstream_connection();
640 if (downstream->get_response_state() == Downstream::INITIAL) {
641 // we did not send any response headers, so we can reply error
643 if (LOG_ENABLED(INFO)) {
644 DCLOG(INFO, dconn) << "Return error reply";
647 downstream->pop_downstream_connection();
651 // Otherwise, we don't know how to recover from this situation. Just
655 handler_->signal_write();
660 int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
661 auto downstream = dconn->get_downstream();
662 if (LOG_ENABLED(INFO)) {
663 if (events & Downstream::EVENT_ERROR) {
664 DCLOG(INFO, dconn) << "Network error/general error";
666 DCLOG(INFO, dconn) << "Timeout";
669 if (downstream->get_response_state() != Downstream::INITIAL) {
674 if (events & Downstream::EVENT_TIMEOUT) {
681 downstream->pop_downstream_connection();
683 handler_->signal_write();
687 void HttpsUpstream::error_reply(unsigned int status_code) {
688 auto html = http::create_error_html(status_code);
689 auto downstream = get_downstream();
693 make_unique<Downstream>(this, handler_->get_mcpool(), 1, 1));
694 downstream = get_downstream();
697 downstream->set_response_http_status(status_code);
698 // we are going to close connection for both frontend and backend in
699 // error condition. This is safest option.
700 downstream->set_response_connection_close(true);
701 handler_->set_should_close_after_write(true);
703 auto output = downstream->get_response_buf();
705 output->append("HTTP/1.1 ");
706 auto status_str = http2::get_status_string(status_code);
707 output->append(status_str.c_str(), status_str.size());
708 output->append("\r\nServer: ");
709 output->append(get_config()->server_name, strlen(get_config()->server_name));
710 output->append("\r\nContent-Length: ");
711 auto cl = util::utos(html.size());
712 output->append(cl.c_str(), cl.size());
713 output->append("\r\nContent-Type: text/html; "
714 "charset=UTF-8\r\nConnection: close\r\n\r\n");
715 output->append(html.c_str(), html.size());
717 downstream->add_response_sent_bodylen(html.size());
718 downstream->set_response_state(Downstream::MSG_COMPLETE);
721 void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) {
722 assert(!downstream_);
723 downstream_ = std::move(downstream);
726 void HttpsUpstream::delete_downstream() {
727 if (downstream_ && downstream_->accesslog_ready()) {
728 handler_->write_accesslog(downstream_.get());
734 Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); }
736 std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
737 return std::unique_ptr<Downstream>(downstream_.release());
740 int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
741 if (LOG_ENABLED(INFO)) {
742 if (downstream->get_non_final_response()) {
743 DLOG(INFO, downstream) << "HTTP non-final response header";
745 DLOG(INFO, downstream) << "HTTP response header completed";
749 std::string hdrs = "HTTP/";
750 hdrs += util::utos(downstream->get_request_major());
752 hdrs += util::utos(downstream->get_request_minor());
754 hdrs += http2::get_status_string(downstream->get_response_http_status());
757 if (!get_config()->http2_proxy && !get_config()->client_proxy &&
758 !get_config()->no_location_rewrite) {
759 downstream->rewrite_location_response_header(
760 get_client_handler()->get_upstream_scheme());
763 http2::build_http1_headers_from_headers(hdrs,
764 downstream->get_response_headers());
766 auto output = downstream->get_response_buf();
768 if (downstream->get_non_final_response()) {
771 if (LOG_ENABLED(INFO)) {
772 log_response_headers(hdrs);
775 output->append(hdrs.c_str(), hdrs.size());
777 downstream->clear_response_headers();
782 auto worker = handler_->get_worker();
784 // after graceful shutdown commenced, add connection: close header
786 if (worker->get_graceful_shutdown()) {
787 downstream->set_response_connection_close(true);
790 // We check downstream->get_response_connection_close() in case when
791 // the Content-Length is not available.
792 if (!downstream->get_request_connection_close() &&
793 !downstream->get_response_connection_close()) {
794 if (downstream->get_request_major() <= 0 ||
795 downstream->get_request_minor() <= 0) {
796 // We add this header for HTTP/1.0 or HTTP/0.9 clients
797 hdrs += "Connection: Keep-Alive\r\n";
799 } else if (!downstream->get_upgraded() ||
800 downstream->get_request_method() != "CONNECT") {
801 hdrs += "Connection: close\r\n";
804 if (!downstream->get_response_header(http2::HD_ALT_SVC)) {
805 // We won't change or alter alt-svc from backend for now
806 if (!get_config()->altsvcs.empty()) {
809 for (auto &altsvc : get_config()->altsvcs) {
810 hdrs += util::percent_encode_token(altsvc.protocol_id);
812 hdrs += util::quote_string(std::string(altsvc.host, altsvc.host_len));
814 hdrs += util::utos(altsvc.port);
818 hdrs[hdrs.size() - 2] = '\r';
819 hdrs[hdrs.size() - 1] = '\n';
823 if (!get_config()->http2_proxy && !get_config()->client_proxy) {
825 hdrs += get_config()->server_name;
828 auto server = downstream->get_response_header(http2::HD_SERVER);
831 hdrs += (*server).value;
836 auto via = downstream->get_response_header(http2::HD_VIA);
837 if (get_config()->no_via) {
840 hdrs += (*via).value;
846 hdrs += (*via).value;
849 hdrs += http::create_via_header_value(downstream->get_response_major(),
850 downstream->get_response_minor());
854 for (auto &p : get_config()->add_response_headers) {
863 if (LOG_ENABLED(INFO)) {
864 log_response_headers(hdrs);
867 output->append(hdrs.c_str(), hdrs.size());
872 int HttpsUpstream::on_downstream_body(Downstream *downstream,
873 const uint8_t *data, size_t len,
878 auto output = downstream->get_response_buf();
879 if (downstream->get_chunked_response()) {
880 auto chunk_size_hex = util::utox(len);
881 chunk_size_hex += "\r\n";
883 output->append(chunk_size_hex.c_str(), chunk_size_hex.size());
885 output->append(data, len);
887 downstream->add_response_sent_bodylen(len);
889 if (downstream->get_chunked_response()) {
890 output->append("\r\n");
895 int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
896 if (downstream->get_chunked_response()) {
897 auto output = downstream->get_response_buf();
898 auto &trailers = downstream->get_response_trailers();
899 if (trailers.empty()) {
900 output->append("0\r\n\r\n");
902 output->append("0\r\n");
903 std::string trailer_part;
904 http2::build_http1_headers_from_headers(trailer_part, trailers);
905 output->append(trailer_part.c_str(), trailer_part.size());
906 output->append("\r\n");
909 if (LOG_ENABLED(INFO)) {
910 DLOG(INFO, downstream) << "HTTP response completed";
913 if (!downstream->validate_response_bodylen()) {
914 downstream->set_response_connection_close(true);
917 if (downstream->get_request_connection_close() ||
918 downstream->get_response_connection_close()) {
919 auto handler = get_client_handler();
920 handler->set_should_close_after_write(true);
925 int HttpsUpstream::on_downstream_abort_request(Downstream *downstream,
926 unsigned int status_code) {
927 error_reply(status_code);
928 handler_->signal_write();
932 void HttpsUpstream::log_response_headers(const std::string &hdrs) const {
935 if (log_config()->errorlog_tty) {
936 nhdrs = http::colorizeHeaders(hdrs.c_str());
937 hdrp = nhdrs.c_str();
941 ULOG(INFO, this) << "HTTP response headers\n" << hdrp;
944 void HttpsUpstream::on_handler_delete() {
945 if (downstream_ && downstream_->accesslog_ready()) {
946 handler_->write_accesslog(downstream_.get());
950 int HttpsUpstream::on_downstream_reset(bool no_retry) {
953 if (!downstream_->request_submission_ready()) {
954 // Return error so that caller can delete handler
958 downstream_->pop_downstream_connection();
960 downstream_->add_retry();
962 if (no_retry || downstream_->no_more_retry()) {
966 rv = downstream_->attach_downstream_connection(
967 handler_->get_downstream_connection());
975 if (on_downstream_abort_request(downstream_.get(), 503) != 0) {
978 downstream_->pop_downstream_connection();