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"
39 #include "shrpx_http2_session.h"
40 #include "shrpx_log.h"
42 # include "shrpx_mruby.h"
48 #include "url-parser/url_parser.h"
50 using namespace nghttp2;
55 int htp_msg_begin(llhttp_t *htp);
56 int htp_uricb(llhttp_t *htp, const char *data, size_t len);
57 int htp_hdr_keycb(llhttp_t *htp, const char *data, size_t len);
58 int htp_hdr_valcb(llhttp_t *htp, const char *data, size_t len);
59 int htp_hdrs_completecb(llhttp_t *htp);
60 int htp_bodycb(llhttp_t *htp, const char *data, size_t len);
61 int htp_msg_completecb(llhttp_t *htp);
65 constexpr llhttp_settings_t htp_hooks = {
66 htp_msg_begin, // llhttp_cb on_message_begin;
67 htp_uricb, // llhttp_data_cb on_url;
68 nullptr, // llhttp_data_cb on_status;
69 htp_hdr_keycb, // llhttp_data_cb on_header_field;
70 htp_hdr_valcb, // llhttp_data_cb on_header_value;
71 htp_hdrs_completecb, // llhttp_cb on_headers_complete;
72 htp_bodycb, // llhttp_data_cb on_body;
73 htp_msg_completecb, // llhttp_cb on_message_complete;
74 nullptr, // llhttp_cb on_chunk_header;
75 nullptr, // llhttp_cb on_chunk_complete;
79 HttpsUpstream::HttpsUpstream(ClientHandler *handler)
81 current_header_length_(0),
82 ioctrl_(handler->get_rlimit()),
84 llhttp_init(&htp_, HTTP_REQUEST, &htp_hooks);
88 HttpsUpstream::~HttpsUpstream() {}
90 void HttpsUpstream::reset_current_header_length() {
91 current_header_length_ = 0;
94 void HttpsUpstream::on_start_request() {
95 if (LOG_ENABLED(INFO)) {
96 ULOG(INFO, this) << "HTTP request started";
98 reset_current_header_length();
101 std::make_unique<Downstream>(this, handler_->get_mcpool(), 0);
103 attach_downstream(std::move(downstream));
105 auto conn = handler_->get_connection();
106 auto &upstreamconf = get_config()->conn.upstream;
108 conn->rt.repeat = upstreamconf.timeout.read;
110 handler_->repeat_read_timer();
116 int htp_msg_begin(llhttp_t *htp) {
117 auto upstream = static_cast<HttpsUpstream *>(htp->data);
118 upstream->on_start_request();
124 int htp_uricb(llhttp_t *htp, const char *data, size_t len) {
125 auto upstream = static_cast<HttpsUpstream *>(htp->data);
126 auto downstream = upstream->get_downstream();
127 auto &req = downstream->request();
129 auto &balloc = downstream->get_block_allocator();
131 // We happen to have the same value for method token.
132 req.method = htp->method;
134 if (req.fs.buffer_size() + len >
135 get_config()->http.request_header_field_buffer) {
136 if (LOG_ENABLED(INFO)) {
137 ULOG(INFO, upstream) << "Too large URI size="
138 << req.fs.buffer_size() + len;
140 assert(downstream->get_request_state() == DownstreamState::INITIAL);
141 downstream->set_request_state(
142 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE);
143 llhttp_set_error_reason(htp, "too long request URI");
147 req.fs.add_extra_buffer_size(len);
149 if (req.method == HTTP_CONNECT) {
151 concat_string_ref(balloc, req.authority, StringRef{data, len});
153 req.path = concat_string_ref(balloc, req.path, StringRef{data, len});
161 int htp_hdr_keycb(llhttp_t *htp, const char *data, size_t len) {
162 auto upstream = static_cast<HttpsUpstream *>(htp->data);
163 auto downstream = upstream->get_downstream();
164 auto &req = downstream->request();
165 auto &httpconf = get_config()->http;
167 if (req.fs.buffer_size() + len > httpconf.request_header_field_buffer) {
168 if (LOG_ENABLED(INFO)) {
169 ULOG(INFO, upstream) << "Too large header block size="
170 << req.fs.buffer_size() + len;
172 if (downstream->get_request_state() == DownstreamState::INITIAL) {
173 downstream->set_request_state(
174 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE);
176 llhttp_set_error_reason(htp, "too large header");
179 if (downstream->get_request_state() == DownstreamState::INITIAL) {
180 if (req.fs.header_key_prev()) {
181 req.fs.append_last_header_key(data, len);
183 if (req.fs.num_fields() >= httpconf.max_request_header_fields) {
184 if (LOG_ENABLED(INFO)) {
186 << "Too many header field num=" << req.fs.num_fields() + 1;
188 downstream->set_request_state(
189 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE);
190 llhttp_set_error_reason(htp, "too many headers");
193 req.fs.alloc_add_header_name(StringRef{data, len});
197 if (req.fs.trailer_key_prev()) {
198 req.fs.append_last_trailer_key(data, len);
200 if (req.fs.num_fields() >= httpconf.max_request_header_fields) {
201 if (LOG_ENABLED(INFO)) {
203 << "Too many header field num=" << req.fs.num_fields() + 1;
205 llhttp_set_error_reason(htp, "too many headers");
208 req.fs.alloc_add_trailer_name(StringRef{data, len});
216 int htp_hdr_valcb(llhttp_t *htp, const char *data, size_t len) {
217 auto upstream = static_cast<HttpsUpstream *>(htp->data);
218 auto downstream = upstream->get_downstream();
219 auto &req = downstream->request();
221 if (req.fs.buffer_size() + len >
222 get_config()->http.request_header_field_buffer) {
223 if (LOG_ENABLED(INFO)) {
224 ULOG(INFO, upstream) << "Too large header block size="
225 << req.fs.buffer_size() + len;
227 if (downstream->get_request_state() == DownstreamState::INITIAL) {
228 downstream->set_request_state(
229 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE);
231 llhttp_set_error_reason(htp, "too large header");
234 if (downstream->get_request_state() == DownstreamState::INITIAL) {
235 req.fs.append_last_header_value(data, len);
237 req.fs.append_last_trailer_value(data, len);
244 void rewrite_request_host_path_from_uri(BlockAllocator &balloc, Request &req,
245 const StringRef &uri,
246 http_parser_url &u) {
247 assert(u.field_set & (1 << UF_HOST));
249 // As per https://tools.ietf.org/html/rfc7230#section-5.4, we
250 // rewrite host header field with authority component.
251 auto authority = util::get_uri_field(uri.c_str(), u, UF_HOST);
252 // TODO properly check IPv6 numeric address
253 auto ipv6 = std::find(std::begin(authority), std::end(authority), ':') !=
255 auto authoritylen = authority.size();
259 if (u.field_set & (1 << UF_PORT)) {
260 authoritylen += 1 + str_size("65535");
262 if (authoritylen > authority.size()) {
263 auto iovec = make_byte_ref(balloc, authoritylen + 1);
268 p = std::copy(std::begin(authority), std::end(authority), p);
273 if (u.field_set & (1 << UF_PORT)) {
275 p = util::utos(p, u.port);
279 req.authority = StringRef{iovec.base, p};
281 req.authority = authority;
284 req.scheme = util::get_uri_field(uri.c_str(), u, UF_SCHEMA);
287 if (u.field_set & (1 << UF_PATH)) {
288 path = util::get_uri_field(uri.c_str(), u, UF_PATH);
289 } else if (req.method == HTTP_OPTIONS) {
290 // Server-wide OPTIONS takes following form in proxy request:
292 // OPTIONS http://example.org HTTP/1.1
294 // Notice that no slash after authority. See
295 // http://tools.ietf.org/html/rfc7230#section-5.3.4
296 req.path = StringRef::from_lit("");
297 // we ignore query component here
300 path = StringRef::from_lit("/");
303 if (u.field_set & (1 << UF_QUERY)) {
304 auto &fdata = u.field_data[UF_QUERY];
306 if (u.field_set & (1 << UF_PATH)) {
307 auto q = util::get_uri_field(uri.c_str(), u, UF_QUERY);
308 path = StringRef{std::begin(path), std::end(q)};
310 path = concat_string_ref(balloc, path, StringRef::from_lit("?"),
311 StringRef{&uri[fdata.off], fdata.len});
315 req.path = http2::rewrite_clean_path(balloc, path);
320 int htp_hdrs_completecb(llhttp_t *htp) {
322 auto upstream = static_cast<HttpsUpstream *>(htp->data);
323 if (LOG_ENABLED(INFO)) {
324 ULOG(INFO, upstream) << "HTTP request headers completed";
327 auto handler = upstream->get_client_handler();
329 auto downstream = upstream->get_downstream();
330 auto &req = downstream->request();
332 auto lgconf = log_config();
333 lgconf->update_tstamp(std::chrono::system_clock::now());
334 req.tstamp = lgconf->tstamp;
336 req.http_major = htp->http_major;
337 req.http_minor = htp->http_minor;
339 req.connection_close = !llhttp_should_keep_alive(htp);
341 handler->stop_read_timer();
343 auto method = req.method;
345 if (LOG_ENABLED(INFO)) {
346 std::stringstream ss;
347 ss << http2::to_method_string(method) << " "
348 << (method == HTTP_CONNECT ? req.authority : req.path) << " "
349 << "HTTP/" << req.http_major << "." << req.http_minor << "\n";
351 for (const auto &kv : req.fs.headers()) {
352 if (kv.name == "authorization") {
353 ss << TTY_HTTP_HD << kv.name << TTY_RST << ": <redacted>\n";
356 ss << TTY_HTTP_HD << kv.name << TTY_RST << ": " << kv.value << "\n";
359 ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
362 // set content-length if method is not CONNECT, and no
363 // transfer-encoding is given. If transfer-encoding is given, leave
364 // req.fs.content_length to -1.
365 if (method != HTTP_CONNECT && !req.fs.header(http2::HD_TRANSFER_ENCODING)) {
366 // llhttp sets 0 to htp->content_length if there is no
367 // content-length header field. If we don't have both
368 // transfer-encoding and content-length header field, we assume
369 // that there is no request body.
370 req.fs.content_length = htp->content_length;
373 auto host = req.fs.header(http2::HD_HOST);
375 if (req.http_major > 1 || req.http_minor > 1) {
381 if (req.http_major == 1 && req.http_minor == 1 && !host) {
386 const auto &value = host->value;
387 // Not allow at least '"' or '\' in host. They are illegal in
388 // authority component, also they cause headaches when we put them
390 if (std::find_if(std::begin(value), std::end(value), [](char c) {
391 return c == '"' || c == '\\';
392 }) != std::end(value)) {
397 downstream->inspect_http1_request();
399 auto faddr = handler->get_upstream_addr();
400 auto &balloc = downstream->get_block_allocator();
401 auto config = get_config();
403 if (method != HTTP_CONNECT) {
405 rv = http_parser_parse_url(req.path.c_str(), req.path.size(), 0, &u);
407 // Expect to respond with 400 bad request
410 // checking UF_HOST could be redundant, but just in case ...
411 if (!(u.field_set & (1 << UF_SCHEMA)) || !(u.field_set & (1 << UF_HOST))) {
412 req.no_authority = true;
414 if (method == HTTP_OPTIONS && req.path == StringRef::from_lit("*")) {
415 req.path = StringRef{};
417 req.path = http2::rewrite_clean_path(balloc, req.path);
421 req.authority = host->value;
424 if (handler->get_ssl()) {
425 req.scheme = StringRef::from_lit("https");
427 req.scheme = StringRef::from_lit("http");
430 rewrite_request_host_path_from_uri(balloc, req, req.path, u);
434 downstream->set_request_state(DownstreamState::HEADER_COMPLETE);
437 auto worker = handler->get_worker();
438 auto mruby_ctx = worker->get_mruby_context();
440 auto &resp = downstream->response();
442 if (mruby_ctx->run_on_request_proc(downstream) != 0) {
443 resp.http_status = 500;
448 // mruby hook may change method value
450 if (req.no_authority && config->http2_proxy &&
451 faddr->alt_mode == UpstreamAltMode::NONE) {
452 // Request URI should be absolute-form for client proxy mode
456 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
460 DownstreamConnection *dconn_ptr;
463 auto dconn = handler->get_downstream_connection(rv, downstream);
466 if (rv == SHRPX_ERR_TLS_REQUIRED) {
467 upstream->redirect_to_https(downstream);
469 downstream->set_request_state(DownstreamState::CONNECT_FAIL);
474 dconn_ptr = dconn.get();
476 if (downstream->attach_downstream_connection(std::move(dconn)) == 0) {
482 const auto &group = dconn_ptr->get_downstream_addr_group();
484 const auto &dmruby_ctx = group->shared_addr->mruby_ctx;
486 if (dmruby_ctx->run_on_request_proc(downstream) != 0) {
487 resp.http_status = 500;
491 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
497 rv = downstream->push_request_headers();
503 if (faddr->alt_mode != UpstreamAltMode::NONE) {
504 // Normally, we forward expect: 100-continue to backend server,
505 // and let them decide whether responds with 100 Continue or not.
506 // For alternative mode, we have no backend, so just send 100
507 // Continue here to make the client happy.
508 if (downstream->get_expect_100_continue()) {
509 auto output = downstream->get_response_buf();
510 constexpr auto res = StringRef::from_lit("HTTP/1.1 100 Continue\r\n\r\n");
512 handler->signal_write();
521 int htp_bodycb(llhttp_t *htp, const char *data, size_t len) {
523 auto upstream = static_cast<HttpsUpstream *>(htp->data);
524 auto downstream = upstream->get_downstream();
525 rv = downstream->push_upload_data_chunk(
526 reinterpret_cast<const uint8_t *>(data), len);
528 // Ignore error if response has been completed. We will end up in
529 // htp_msg_completecb, and request will end gracefully.
530 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
534 llhttp_set_error_reason(htp, "could not process request body");
542 int htp_msg_completecb(llhttp_t *htp) {
544 auto upstream = static_cast<HttpsUpstream *>(htp->data);
545 if (LOG_ENABLED(INFO)) {
546 ULOG(INFO, upstream) << "HTTP request completed";
548 auto handler = upstream->get_client_handler();
549 auto downstream = upstream->get_downstream();
550 downstream->set_request_state(DownstreamState::MSG_COMPLETE);
551 rv = downstream->end_upload_data();
553 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
554 // Here both response and request were completed. One of the
555 // reason why end_upload_data() failed is when we sent response
556 // in request phase hook. We only delete and proceed to the
557 // next request handling (if we don't close the connection). We
558 // first pause parser here just as we normally do, and call
559 // signal_write() to run on_write().
565 if (handler->get_http2_upgrade_allowed() &&
566 downstream->get_http2_upgrade_request() &&
567 handler->perform_http2_upgrade(upstream) != 0) {
568 if (LOG_ENABLED(INFO)) {
569 ULOG(INFO, upstream) << "HTTP Upgrade to HTTP/2 failed";
573 // Stop further processing to complete this request
578 // on_read() does not consume all available data in input buffer if
579 // one http request is fully received.
580 int HttpsUpstream::on_read() {
581 auto rb = handler_->get_rb();
582 auto rlimit = handler_->get_rlimit();
583 auto downstream = get_downstream();
585 if (rb->rleft() == 0 || handler_->get_should_close_after_write()) {
589 // downstream can be nullptr here, because it is initialized in the
590 // callback chain called by llhttp_execute()
591 if (downstream && downstream->get_upgraded()) {
593 auto rv = downstream->push_upload_data_chunk(rb->pos(), rb->rleft());
602 if (downstream->request_buf_full()) {
603 if (LOG_ENABLED(INFO)) {
604 ULOG(INFO, this) << "Downstream request buf is full";
606 pause_read(SHRPX_NO_BUFFER);
615 // To avoid reading next pipelined request
616 switch (downstream->get_request_state()) {
617 case DownstreamState::INITIAL:
618 case DownstreamState::HEADER_COMPLETE:
625 // llhttp_execute() does nothing once it entered error state.
626 auto htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()),
632 : reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_)) -
637 // Well, actually header length + some body bytes
638 current_header_length_ += nread;
640 // Get downstream again because it may be initialized in http parser
642 downstream = get_downstream();
644 if (htperr == HPE_PAUSED) {
645 // We may pause parser in htp_msg_completecb when both side are
646 // completed. Signal write, so that we can run on_write().
648 downstream->get_request_state() == DownstreamState::MSG_COMPLETE &&
649 downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
650 handler_->signal_write();
655 if (htperr != HPE_OK) {
656 if (LOG_ENABLED(INFO)) {
657 ULOG(INFO, this) << "HTTP parse failure: "
658 << "(" << llhttp_errno_name(htperr) << ") "
659 << llhttp_get_error_reason(&htp_);
663 downstream->get_response_state() != DownstreamState::INITIAL) {
664 handler_->set_should_close_after_write(true);
665 handler_->signal_write();
669 unsigned int status_code;
671 if (htperr == HPE_INVALID_METHOD) {
673 } else if (downstream) {
674 status_code = downstream->response().http_status;
675 if (status_code == 0) {
676 if (downstream->get_request_state() == DownstreamState::CONNECT_FAIL) {
678 } else if (downstream->get_request_state() ==
679 DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE) {
689 error_reply(status_code);
691 handler_->signal_write();
696 // downstream can be NULL here.
697 if (downstream && downstream->request_buf_full()) {
698 if (LOG_ENABLED(INFO)) {
699 ULOG(INFO, this) << "Downstream request buffer is full";
702 pause_read(SHRPX_NO_BUFFER);
710 int HttpsUpstream::on_write() {
711 auto downstream = get_downstream();
716 auto output = downstream->get_response_buf();
717 const auto &resp = downstream->response();
719 if (output->rleft() > 0) {
723 // We need to postpone detachment until all data are sent so that
724 // we can notify nghttp2 library all data consumed.
725 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
726 if (downstream->can_detach_downstream_connection()) {
728 downstream->detach_downstream_connection();
731 downstream->pop_downstream_connection();
734 // We need this if response ends before request.
735 if (downstream->get_request_state() == DownstreamState::MSG_COMPLETE) {
738 if (handler_->get_should_close_after_write()) {
742 auto conn = handler_->get_connection();
743 auto &upstreamconf = get_config()->conn.upstream;
745 conn->rt.repeat = upstreamconf.timeout.idle_read;
747 handler_->repeat_read_timer();
749 return resume_read(SHRPX_NO_BUFFER, nullptr, 0);
751 // If the request is not complete, close the connection.
754 handler_->set_should_close_after_write(true);
760 return downstream->resume_read(SHRPX_NO_BUFFER, resp.unconsumed_body_length);
763 int HttpsUpstream::on_event() { return 0; }
765 ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; }
767 void HttpsUpstream::pause_read(IOCtrlReason reason) {
768 ioctrl_.pause_read(reason);
771 int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream,
773 // downstream could be nullptr
774 if (downstream && downstream->request_buf_full()) {
777 if (ioctrl_.resume_read(reason)) {
778 // Process remaining data in input buffer here because these bytes
779 // are not notified by readcb until new data arrive.
780 llhttp_resume(&htp_);
782 auto conn = handler_->get_connection();
783 ev_feed_event(conn->loop, &conn->rev, EV_READ);
790 int HttpsUpstream::downstream_read(DownstreamConnection *dconn) {
791 auto downstream = dconn->get_downstream();
794 rv = downstream->on_read();
796 if (rv == SHRPX_ERR_EOF) {
797 if (downstream->get_request_header_sent()) {
798 return downstream_eof(dconn);
800 return SHRPX_ERR_RETRY;
803 if (rv == SHRPX_ERR_DCONN_CANCELED) {
804 downstream->pop_downstream_connection();
809 return downstream_error(dconn, Downstream::EVENT_ERROR);
812 if (downstream->get_response_state() == DownstreamState::MSG_RESET) {
816 if (downstream->get_response_state() == DownstreamState::MSG_BAD_HEADER) {
818 downstream->pop_downstream_connection();
822 if (downstream->can_detach_downstream_connection()) {
824 downstream->detach_downstream_connection();
828 handler_->signal_write();
833 int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
835 rv = dconn->on_write();
836 if (rv == SHRPX_ERR_NETWORK) {
837 return downstream_error(dconn, Downstream::EVENT_ERROR);
847 int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
848 auto downstream = dconn->get_downstream();
850 if (LOG_ENABLED(INFO)) {
851 DCLOG(INFO, dconn) << "EOF";
854 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
858 if (downstream->get_response_state() == DownstreamState::HEADER_COMPLETE) {
859 // Server may indicate the end of the request by EOF
860 if (LOG_ENABLED(INFO)) {
861 DCLOG(INFO, dconn) << "The end of the response body was indicated by "
864 on_downstream_body_complete(downstream);
865 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
866 downstream->pop_downstream_connection();
870 if (downstream->get_response_state() == DownstreamState::INITIAL) {
871 // we did not send any response headers, so we can reply error
873 if (LOG_ENABLED(INFO)) {
874 DCLOG(INFO, dconn) << "Return error reply";
877 downstream->pop_downstream_connection();
881 // Otherwise, we don't know how to recover from this situation. Just
885 handler_->signal_write();
890 int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
891 auto downstream = dconn->get_downstream();
892 if (LOG_ENABLED(INFO)) {
893 if (events & Downstream::EVENT_ERROR) {
894 DCLOG(INFO, dconn) << "Network error/general error";
896 DCLOG(INFO, dconn) << "Timeout";
899 if (downstream->get_response_state() != DownstreamState::INITIAL) {
904 if (events & Downstream::EVENT_TIMEOUT) {
905 if (downstream->get_request_header_sent()) {
915 downstream->pop_downstream_connection();
917 handler_->signal_write();
921 int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
923 const auto &req = downstream->request();
924 auto &resp = downstream->response();
925 auto &balloc = downstream->get_block_allocator();
926 auto config = get_config();
927 auto &httpconf = config->http;
929 auto connection_close = false;
931 auto worker = handler_->get_worker();
933 if (httpconf.max_requests <= num_requests_ ||
934 worker->get_graceful_shutdown()) {
935 resp.fs.add_header_token(StringRef::from_lit("connection"),
936 StringRef::from_lit("close"), false,
937 http2::HD_CONNECTION);
938 connection_close = true;
939 } else if (req.http_major <= 0 ||
940 (req.http_major == 1 && req.http_minor == 0)) {
941 connection_close = true;
943 auto c = resp.fs.header(http2::HD_CONNECTION);
944 if (c && util::strieq_l("close", c->value)) {
945 connection_close = true;
949 if (connection_close) {
950 resp.connection_close = true;
951 handler_->set_should_close_after_write(true);
954 auto output = downstream->get_response_buf();
956 output->append("HTTP/1.1 ");
957 output->append(http2::stringify_status(balloc, resp.http_status));
959 output->append(http2::get_reason_phrase(resp.http_status));
960 output->append("\r\n");
962 for (auto &kv : resp.fs.headers()) {
963 if (kv.name.empty() || kv.name[0] == ':') {
966 http2::capitalize(output, kv.name);
967 output->append(": ");
968 output->append(kv.value);
969 output->append("\r\n");
972 if (!resp.fs.header(http2::HD_SERVER)) {
973 output->append("Server: ");
974 output->append(config->http.server_name);
975 output->append("\r\n");
978 for (auto &p : httpconf.add_response_headers) {
979 output->append(p.name);
980 output->append(": ");
981 output->append(p.value);
982 output->append("\r\n");
985 output->append("\r\n");
987 output->append(body, bodylen);
989 downstream->response_sent_body_length += bodylen;
990 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
995 void HttpsUpstream::error_reply(unsigned int status_code) {
996 auto downstream = get_downstream();
1000 std::make_unique<Downstream>(this, handler_->get_mcpool(), 1));
1001 downstream = get_downstream();
1004 auto &resp = downstream->response();
1005 auto &balloc = downstream->get_block_allocator();
1007 auto html = http::create_error_html(balloc, status_code);
1009 resp.http_status = status_code;
1010 // we are going to close connection for both frontend and backend in
1011 // error condition. This is safest option.
1012 resp.connection_close = true;
1013 handler_->set_should_close_after_write(true);
1015 auto output = downstream->get_response_buf();
1017 output->append("HTTP/1.1 ");
1018 output->append(http2::stringify_status(balloc, status_code));
1019 output->append(' ');
1020 output->append(http2::get_reason_phrase(status_code));
1021 output->append("\r\nServer: ");
1022 output->append(get_config()->http.server_name);
1023 output->append("\r\nContent-Length: ");
1024 std::array<uint8_t, NGHTTP2_MAX_UINT64_DIGITS> intbuf;
1025 output->append(StringRef{std::begin(intbuf),
1026 util::utos(std::begin(intbuf), html.size())});
1027 output->append("\r\nDate: ");
1028 auto lgconf = log_config();
1029 lgconf->update_tstamp(std::chrono::system_clock::now());
1030 output->append(lgconf->tstamp->time_http);
1031 output->append("\r\nContent-Type: text/html; "
1032 "charset=UTF-8\r\nConnection: close\r\n\r\n");
1033 output->append(html);
1035 downstream->response_sent_body_length += html.size();
1036 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1039 void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) {
1040 assert(!downstream_);
1041 downstream_ = std::move(downstream);
1044 void HttpsUpstream::delete_downstream() {
1045 if (downstream_ && downstream_->accesslog_ready()) {
1046 handler_->write_accesslog(downstream_.get());
1049 downstream_.reset();
1052 Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); }
1054 std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
1055 return std::unique_ptr<Downstream>(downstream_.release());
1058 int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
1059 if (LOG_ENABLED(INFO)) {
1060 if (downstream->get_non_final_response()) {
1061 DLOG(INFO, downstream) << "HTTP non-final response header";
1063 DLOG(INFO, downstream) << "HTTP response header completed";
1067 const auto &req = downstream->request();
1068 auto &resp = downstream->response();
1069 auto &balloc = downstream->get_block_allocator();
1070 auto dconn = downstream->get_downstream_connection();
1071 // dconn might be nullptr if this is non-final response from mruby.
1073 if (downstream->get_non_final_response() &&
1074 !downstream->supports_non_final_response()) {
1075 resp.fs.clear_headers();
1080 if (!downstream->get_non_final_response()) {
1082 const auto &group = dconn->get_downstream_addr_group();
1084 const auto &dmruby_ctx = group->shared_addr->mruby_ctx;
1086 if (dmruby_ctx->run_on_response_proc(downstream) != 0) {
1091 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1096 auto worker = handler_->get_worker();
1097 auto mruby_ctx = worker->get_mruby_context();
1099 if (mruby_ctx->run_on_response_proc(downstream) != 0) {
1104 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1108 #endif // HAVE_MRUBY
1110 auto connect_method = req.method == HTTP_CONNECT;
1112 auto buf = downstream->get_response_buf();
1113 buf->append("HTTP/");
1114 buf->append('0' + req.http_major);
1116 buf->append('0' + req.http_minor);
1118 if (req.connect_proto != ConnectProto::NONE && downstream->get_upgraded()) {
1119 buf->append(http2::stringify_status(balloc, 101));
1121 buf->append(http2::get_reason_phrase(101));
1123 buf->append(http2::stringify_status(balloc, resp.http_status));
1125 buf->append(http2::get_reason_phrase(resp.http_status));
1127 buf->append("\r\n");
1129 auto config = get_config();
1130 auto &httpconf = config->http;
1132 if (!config->http2_proxy && !httpconf.no_location_rewrite) {
1133 downstream->rewrite_location_response_header(
1134 get_client_handler()->get_upstream_scheme());
1137 if (downstream->get_non_final_response()) {
1138 http2::build_http1_headers_from_headers(buf, resp.fs.headers(),
1139 http2::HDOP_STRIP_ALL);
1141 buf->append("\r\n");
1143 if (LOG_ENABLED(INFO)) {
1144 log_response_headers(buf);
1147 resp.fs.clear_headers();
1152 auto build_flags = (http2::HDOP_STRIP_ALL & ~http2::HDOP_STRIP_VIA) |
1153 (!http2::legacy_http1(req.http_major, req.http_minor)
1155 : http2::HDOP_STRIP_TRANSFER_ENCODING);
1157 http2::build_http1_headers_from_headers(buf, resp.fs.headers(), build_flags);
1159 auto worker = handler_->get_worker();
1161 // after graceful shutdown commenced, add connection: close header
1163 if (httpconf.max_requests <= num_requests_ ||
1164 worker->get_graceful_shutdown()) {
1165 resp.connection_close = true;
1168 // We check downstream->get_response_connection_close() in case when
1169 // the Content-Length is not available.
1170 if (!req.connection_close && !resp.connection_close) {
1171 if (req.http_major <= 0 || req.http_minor <= 0) {
1172 // We add this header for HTTP/1.0 or HTTP/0.9 clients
1173 buf->append("Connection: Keep-Alive\r\n");
1175 } else if (!downstream->get_upgraded()) {
1176 buf->append("Connection: close\r\n");
1179 if (!connect_method && downstream->get_upgraded()) {
1180 if (req.connect_proto == ConnectProto::WEBSOCKET &&
1181 resp.http_status / 100 == 2) {
1182 buf->append("Upgrade: websocket\r\nConnection: Upgrade\r\n");
1183 auto key = req.fs.header(http2::HD_SEC_WEBSOCKET_KEY);
1184 if (!key || key->value.size() != base64::encode_length(16)) {
1187 std::array<uint8_t, base64::encode_length(20)> out;
1188 auto accept = http2::make_websocket_accept_token(out.data(), key->value);
1189 if (accept.empty()) {
1192 buf->append("Sec-WebSocket-Accept: ");
1193 buf->append(accept);
1194 buf->append("\r\n");
1196 auto connection = resp.fs.header(http2::HD_CONNECTION);
1198 buf->append("Connection: ");
1199 buf->append((*connection).value);
1200 buf->append("\r\n");
1203 auto upgrade = resp.fs.header(http2::HD_UPGRADE);
1205 buf->append("Upgrade: ");
1206 buf->append((*upgrade).value);
1207 buf->append("\r\n");
1212 if (!resp.fs.header(http2::HD_ALT_SVC)) {
1213 // We won't change or alter alt-svc from backend for now
1214 if (!httpconf.altsvcs.empty()) {
1215 buf->append("Alt-Svc: ");
1216 buf->append(httpconf.altsvc_header_value);
1217 buf->append("\r\n");
1221 if (!config->http2_proxy && !httpconf.no_server_rewrite) {
1222 buf->append("Server: ");
1223 buf->append(httpconf.server_name);
1224 buf->append("\r\n");
1226 auto server = resp.fs.header(http2::HD_SERVER);
1228 buf->append("Server: ");
1229 buf->append((*server).value);
1230 buf->append("\r\n");
1234 if (req.method != HTTP_CONNECT || !downstream->get_upgraded()) {
1235 auto affinity_cookie = downstream->get_affinity_cookie_to_send();
1236 if (affinity_cookie) {
1237 auto &group = dconn->get_downstream_addr_group();
1238 auto &shared_addr = group->shared_addr;
1239 auto &cookieconf = shared_addr->affinity.cookie;
1241 http::require_cookie_secure_attribute(cookieconf.secure, req.scheme);
1242 auto cookie_str = http::create_affinity_cookie(
1243 balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure);
1244 buf->append("Set-Cookie: ");
1245 buf->append(cookie_str);
1246 buf->append("\r\n");
1250 auto via = resp.fs.header(http2::HD_VIA);
1251 if (httpconf.no_via) {
1253 buf->append("Via: ");
1254 buf->append((*via).value);
1255 buf->append("\r\n");
1258 buf->append("Via: ");
1260 buf->append((*via).value);
1263 std::array<char, 16> viabuf;
1264 auto end = http::create_via_header_value(viabuf.data(), resp.http_major,
1266 buf->append(viabuf.data(), end - std::begin(viabuf));
1267 buf->append("\r\n");
1270 for (auto &p : httpconf.add_response_headers) {
1271 buf->append(p.name);
1273 buf->append(p.value);
1274 buf->append("\r\n");
1277 buf->append("\r\n");
1279 if (LOG_ENABLED(INFO)) {
1280 log_response_headers(buf);
1286 int HttpsUpstream::on_downstream_body(Downstream *downstream,
1287 const uint8_t *data, size_t len,
1292 auto output = downstream->get_response_buf();
1293 if (downstream->get_chunked_response()) {
1294 output->append(util::utox(len));
1295 output->append("\r\n");
1297 output->append(data, len);
1299 downstream->response_sent_body_length += len;
1301 if (downstream->get_chunked_response()) {
1302 output->append("\r\n");
1307 int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
1308 const auto &req = downstream->request();
1309 auto &resp = downstream->response();
1311 if (downstream->get_chunked_response()) {
1312 auto output = downstream->get_response_buf();
1313 const auto &trailers = resp.fs.trailers();
1314 if (trailers.empty()) {
1315 output->append("0\r\n\r\n");
1317 output->append("0\r\n");
1318 http2::build_http1_headers_from_headers(output, trailers,
1319 http2::HDOP_STRIP_ALL);
1320 output->append("\r\n");
1323 if (LOG_ENABLED(INFO)) {
1324 DLOG(INFO, downstream) << "HTTP response completed";
1327 if (!downstream->validate_response_recv_body_length()) {
1328 resp.connection_close = true;
1331 if (req.connection_close || resp.connection_close ||
1332 // To avoid to stall upload body
1333 downstream->get_request_state() != DownstreamState::MSG_COMPLETE) {
1334 auto handler = get_client_handler();
1335 handler->set_should_close_after_write(true);
1340 int HttpsUpstream::on_downstream_abort_request(Downstream *downstream,
1341 unsigned int status_code) {
1342 error_reply(status_code);
1343 handler_->signal_write();
1347 int HttpsUpstream::on_downstream_abort_request_with_https_redirect(
1348 Downstream *downstream) {
1349 redirect_to_https(downstream);
1350 handler_->signal_write();
1354 int HttpsUpstream::redirect_to_https(Downstream *downstream) {
1355 auto &req = downstream->request();
1356 if (req.method == HTTP_CONNECT || req.scheme != "http" ||
1357 req.authority.empty()) {
1362 auto authority = util::extract_host(req.authority);
1363 if (authority.empty()) {
1368 auto &balloc = downstream->get_block_allocator();
1369 auto config = get_config();
1370 auto &httpconf = config->http;
1373 if (httpconf.redirect_https_port == StringRef::from_lit("443")) {
1374 loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
1377 loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
1378 StringRef::from_lit(":"),
1379 httpconf.redirect_https_port, req.path);
1382 auto &resp = downstream->response();
1383 resp.http_status = 308;
1384 resp.fs.add_header_token(StringRef::from_lit("location"), loc, false,
1385 http2::HD_LOCATION);
1386 resp.fs.add_header_token(StringRef::from_lit("connection"),
1387 StringRef::from_lit("close"), false,
1388 http2::HD_CONNECTION);
1390 return send_reply(downstream, nullptr, 0);
1393 void HttpsUpstream::log_response_headers(DefaultMemchunks *buf) const {
1395 for (auto chunk = buf->head; chunk; chunk = chunk->next) {
1396 nhdrs.append(chunk->pos, chunk->last);
1398 if (log_config()->errorlog_tty) {
1399 nhdrs = http::colorizeHeaders(nhdrs.c_str());
1401 ULOG(INFO, this) << "HTTP response headers\n" << nhdrs;
1404 void HttpsUpstream::on_handler_delete() {
1405 if (downstream_ && downstream_->accesslog_ready()) {
1406 handler_->write_accesslog(downstream_.get());
1410 int HttpsUpstream::on_downstream_reset(Downstream *downstream, bool no_retry) {
1412 std::unique_ptr<DownstreamConnection> dconn;
1414 assert(downstream == downstream_.get());
1416 downstream_->pop_downstream_connection();
1418 if (!downstream_->request_submission_ready()) {
1419 switch (downstream_->get_response_state()) {
1420 case DownstreamState::MSG_COMPLETE:
1421 // We have got all response body already. Send it off.
1423 case DownstreamState::INITIAL:
1424 if (on_downstream_abort_request(downstream_.get(), 502) != 0) {
1431 // Return error so that caller can delete handler
1435 downstream_->add_retry();
1439 if (no_retry || downstream_->no_more_retry()) {
1444 auto dconn = handler_->get_downstream_connection(rv, downstream_.get());
1449 rv = downstream_->attach_downstream_connection(std::move(dconn));
1455 rv = downstream_->push_request_headers();
1463 if (rv == SHRPX_ERR_TLS_REQUIRED) {
1464 rv = on_downstream_abort_request_with_https_redirect(downstream);
1466 rv = on_downstream_abort_request(downstream_.get(), 502);
1471 downstream_->pop_downstream_connection();
1476 int HttpsUpstream::initiate_push(Downstream *downstream, const StringRef &uri) {
1480 int HttpsUpstream::response_riovec(struct iovec *iov, int iovcnt) const {
1485 auto buf = downstream_->get_response_buf();
1487 return buf->riovec(iov, iovcnt);
1490 void HttpsUpstream::response_drain(size_t n) {
1495 auto buf = downstream_->get_response_buf();
1500 bool HttpsUpstream::response_empty() const {
1505 auto buf = downstream_->get_response_buf();
1507 return buf->rleft() == 0;
1511 HttpsUpstream::on_downstream_push_promise(Downstream *downstream,
1512 int32_t promised_stream_id) {
1516 int HttpsUpstream::on_downstream_push_promise_complete(
1517 Downstream *downstream, Downstream *promised_downstream) {
1521 bool HttpsUpstream::push_enabled() const { return false; }
1523 void HttpsUpstream::cancel_premature_downstream(
1524 Downstream *promised_downstream) {}
1526 } // namespace shrpx