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_worker_config.h"
42 using namespace nghttp2;
46 HttpsUpstream::HttpsUpstream(ClientHandler *handler)
47 : handler_(handler), current_header_length_(0),
48 ioctrl_(handler->get_rlimit()) {
49 http_parser_init(&htp_, HTTP_REQUEST);
53 HttpsUpstream::~HttpsUpstream() {}
55 void HttpsUpstream::reset_current_header_length() {
56 current_header_length_ = 0;
60 int htp_msg_begin(http_parser *htp) {
61 auto upstream = static_cast<HttpsUpstream *>(htp->data);
62 if (LOG_ENABLED(INFO)) {
63 ULOG(INFO, upstream) << "HTTP request started";
65 upstream->reset_current_header_length();
66 // TODO specify 0 as priority for now
67 upstream->attach_downstream(make_unique<Downstream>(upstream, 0, 0));
73 int htp_uricb(http_parser *htp, const char *data, size_t len) {
74 auto upstream = static_cast<HttpsUpstream *>(htp->data);
75 auto downstream = upstream->get_downstream();
76 downstream->append_request_path(data, len);
82 int htp_hdr_keycb(http_parser *htp, const char *data, size_t len) {
83 auto upstream = static_cast<HttpsUpstream *>(htp->data);
84 auto downstream = upstream->get_downstream();
85 if (downstream->get_request_state() != Downstream::INITIAL) {
89 if (downstream->get_request_header_key_prev()) {
90 downstream->append_last_request_header_key(data, len);
92 downstream->add_request_header(std::string(data, len), "");
94 if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
95 if (LOG_ENABLED(INFO)) {
96 ULOG(INFO, upstream) << "Too large header block size="
97 << downstream->get_request_headers_sum();
106 int htp_hdr_valcb(http_parser *htp, const char *data, size_t len) {
107 auto upstream = static_cast<HttpsUpstream *>(htp->data);
108 auto downstream = upstream->get_downstream();
109 if (downstream->get_request_state() != Downstream::INITIAL) {
113 if (downstream->get_request_header_key_prev()) {
114 downstream->set_last_request_header_value(std::string(data, len));
116 downstream->append_last_request_header_value(data, len);
118 if (downstream->get_request_headers_sum() > Downstream::MAX_HEADERS_SUM) {
119 if (LOG_ENABLED(INFO)) {
120 ULOG(INFO, upstream) << "Too large header block size="
121 << downstream->get_request_headers_sum();
130 int htp_hdrs_completecb(http_parser *htp) {
132 auto upstream = static_cast<HttpsUpstream *>(htp->data);
133 if (LOG_ENABLED(INFO)) {
134 ULOG(INFO, upstream) << "HTTP request headers completed";
136 auto downstream = upstream->get_downstream();
138 downstream->set_request_method(
139 http_method_str((enum http_method)htp->method));
140 downstream->set_request_major(htp->http_major);
141 downstream->set_request_minor(htp->http_minor);
143 downstream->set_request_connection_close(!http_should_keep_alive(htp));
145 if (LOG_ENABLED(INFO)) {
146 std::stringstream ss;
147 ss << downstream->get_request_method() << " "
148 << downstream->get_request_path() << " "
149 << "HTTP/" << downstream->get_request_major() << "."
150 << downstream->get_request_minor() << "\n";
151 const auto &headers = downstream->get_request_headers();
152 for (size_t i = 0; i < headers.size(); ++i) {
153 ss << TTY_HTTP_HD << headers[i].name << TTY_RST << ": "
154 << headers[i].value << "\n";
156 ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
159 if (downstream->index_request_headers() != 0) {
163 if (downstream->get_request_major() == 1 &&
164 downstream->get_request_minor() == 1 &&
165 !downstream->get_request_header(http2::HD_HOST)) {
169 downstream->inspect_http1_request();
171 if (get_config()->client_proxy &&
172 downstream->get_request_method() != "CONNECT") {
173 // Make sure that request path is an absolute URI.
175 auto url = downstream->get_request_path().c_str();
176 memset(&u, 0, sizeof(u));
177 rv = http_parser_parse_url(url, downstream->get_request_path().size(), 0,
179 if (rv != 0 || !(u.field_set & (1 << UF_SCHEMA))) {
180 // Expect to respond with 400 bad request
185 rv = downstream->attach_downstream_connection(
186 upstream->get_client_handler()->get_downstream_connection());
189 downstream->set_request_state(Downstream::CONNECT_FAIL);
194 rv = downstream->push_request_headers();
200 downstream->set_request_state(Downstream::HEADER_COMPLETE);
207 int htp_bodycb(http_parser *htp, const char *data, size_t len) {
209 auto upstream = static_cast<HttpsUpstream *>(htp->data);
210 auto downstream = upstream->get_downstream();
211 rv = downstream->push_upload_data_chunk(
212 reinterpret_cast<const uint8_t *>(data), len);
221 int htp_msg_completecb(http_parser *htp) {
223 auto upstream = static_cast<HttpsUpstream *>(htp->data);
224 if (LOG_ENABLED(INFO)) {
225 ULOG(INFO, upstream) << "HTTP request completed";
227 auto downstream = upstream->get_downstream();
228 downstream->set_request_state(Downstream::MSG_COMPLETE);
229 rv = downstream->end_upload_data();
233 // Stop further processing to complete this request
234 http_parser_pause(htp, 1);
240 http_parser_settings htp_hooks = {
241 htp_msg_begin, // http_cb on_message_begin;
242 htp_uricb, // http_data_cb on_url;
243 nullptr, // http_data_cb on_status;
244 htp_hdr_keycb, // http_data_cb on_header_field;
245 htp_hdr_valcb, // http_data_cb on_header_value;
246 htp_hdrs_completecb, // http_cb on_headers_complete;
247 htp_bodycb, // http_data_cb on_body;
248 htp_msg_completecb // http_cb on_message_complete;
252 // on_read() does not consume all available data in input buffer if
253 // one http request is fully received.
254 int HttpsUpstream::on_read() {
255 auto rb = handler_->get_rb();
256 auto downstream = get_downstream();
258 if (rb->rleft() == 0) {
262 // downstream can be nullptr here, because it is initialized in the
263 // callback chain called by http_parser_execute()
264 if (downstream && downstream->get_upgraded()) {
266 auto rv = downstream->push_upload_data_chunk(rb->pos, rb->rleft());
274 if (downstream->request_buf_full()) {
275 if (LOG_ENABLED(INFO)) {
276 ULOG(INFO, this) << "Downstream request buf is full";
278 pause_read(SHRPX_NO_BUFFER);
286 auto nread = http_parser_execute(
287 &htp_, &htp_hooks, reinterpret_cast<const char *>(rb->pos), rb->rleft());
291 // Well, actually header length + some body bytes
292 current_header_length_ += nread;
294 // Get downstream again because it may be initialized in http parser
296 downstream = get_downstream();
298 auto handler = get_client_handler();
299 auto htperr = HTTP_PARSER_ERRNO(&htp_);
301 if (htperr == HPE_PAUSED) {
305 if (downstream->get_request_state() == Downstream::CONNECT_FAIL) {
306 // Following paues_read is needed to avoid reading next data.
307 pause_read(SHRPX_MSG_BLOCK);
309 handler_->signal_write();
310 // Downstream gets deleted after response body is read.
314 assert(downstream->get_request_state() == Downstream::MSG_COMPLETE);
316 if (downstream->get_downstream_connection() == nullptr) {
317 // Error response has already be sent
318 assert(downstream->get_response_state() == Downstream::MSG_COMPLETE);
324 if (handler->get_http2_upgrade_allowed() &&
325 downstream->get_http2_upgrade_request()) {
327 if (handler->perform_http2_upgrade(this) != 0) {
331 handler_->signal_write();
336 pause_read(SHRPX_MSG_BLOCK);
341 if (htperr != HPE_OK) {
342 if (LOG_ENABLED(INFO)) {
343 ULOG(INFO, this) << "HTTP parse failure: "
344 << "(" << http_errno_name(htperr) << ") "
345 << http_errno_description(htperr);
348 pause_read(SHRPX_MSG_BLOCK);
350 unsigned int status_code;
353 downstream->get_request_state() == Downstream::CONNECT_FAIL) {
359 error_reply(status_code);
361 handler_->signal_write();
366 // downstream can be NULL here.
367 if (downstream && downstream->request_buf_full()) {
368 if (LOG_ENABLED(INFO)) {
369 ULOG(INFO, this) << "Downstream request buffer is full";
372 pause_read(SHRPX_NO_BUFFER);
380 int HttpsUpstream::on_write() {
381 auto downstream = get_downstream();
385 auto wb = handler_->get_wb();
386 if (wb->wleft() == 0) {
390 auto dconn = downstream->get_downstream_connection();
391 auto output = downstream->get_response_buf();
393 if (output->rleft() == 0 && dconn &&
394 downstream->get_response_state() != Downstream::MSG_COMPLETE) {
395 if (downstream->resume_read(SHRPX_NO_BUFFER,
396 downstream->get_response_datalen()) != 0) {
400 if (downstream_read(dconn) != 0) {
405 auto n = output->remove(wb->last, wb->wleft());
408 if (wb->rleft() > 0) {
412 // We need to postpone detachment until all data are sent so that
413 // we can notify nghttp2 library all data consumed.
414 if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
415 if (downstream->get_response_connection_close()) {
417 downstream->pop_downstream_connection();
421 downstream->detach_downstream_connection();
423 // We need this if response ends before request.
424 if (downstream->get_request_state() == Downstream::MSG_COMPLETE) {
426 return resume_read(SHRPX_MSG_BLOCK, nullptr, 0);
430 return downstream->resume_read(SHRPX_NO_BUFFER,
431 downstream->get_response_datalen());
434 int HttpsUpstream::on_event() { return 0; }
436 ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; }
438 void HttpsUpstream::pause_read(IOCtrlReason reason) {
439 ioctrl_.pause_read(reason);
442 int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream,
444 // downstream could be nullptr if reason is SHRPX_MSG_BLOCK.
445 if (downstream && downstream->request_buf_full()) {
448 if (ioctrl_.resume_read(reason)) {
449 // Process remaining data in input buffer here because these bytes
450 // are not notified by readcb until new data arrive.
451 http_parser_pause(&htp_, 0);
458 int HttpsUpstream::downstream_read(DownstreamConnection *dconn) {
459 auto downstream = dconn->get_downstream();
462 rv = downstream->on_read();
464 if (downstream->get_response_state() == Downstream::MSG_RESET) {
468 if (downstream->get_response_state() == Downstream::MSG_BAD_HEADER) {
470 downstream->pop_downstream_connection();
474 // Detach downstream connection early so that it could be reused
475 // without hitting server's request timeout.
476 if (downstream->get_response_state() == Downstream::MSG_COMPLETE &&
477 !downstream->get_response_connection_close()) {
479 downstream->detach_downstream_connection();
482 if (rv == SHRPX_ERR_EOF) {
483 return downstream_eof(dconn);
487 return downstream_error(dconn, Downstream::EVENT_ERROR);
491 handler_->signal_write();
496 int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
498 rv = dconn->on_write();
499 if (rv == SHRPX_ERR_NETWORK) {
500 return downstream_error(dconn, Downstream::EVENT_ERROR);
510 int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
511 auto downstream = dconn->get_downstream();
513 if (LOG_ENABLED(INFO)) {
514 DCLOG(INFO, dconn) << "EOF";
517 if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
521 if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
522 // Server may indicate the end of the request by EOF
523 if (LOG_ENABLED(INFO)) {
524 DCLOG(INFO, dconn) << "The end of the response body was indicated by "
527 on_downstream_body_complete(downstream);
528 downstream->set_response_state(Downstream::MSG_COMPLETE);
529 downstream->pop_downstream_connection();
533 if (downstream->get_response_state() == Downstream::INITIAL) {
534 // we did not send any response headers, so we can reply error
536 if (LOG_ENABLED(INFO)) {
537 DCLOG(INFO, dconn) << "Return error reply";
540 downstream->pop_downstream_connection();
544 // Otherwise, we don't know how to recover from this situation. Just
548 handler_->signal_write();
553 int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
554 auto downstream = dconn->get_downstream();
555 if (LOG_ENABLED(INFO)) {
556 if (events & Downstream::EVENT_ERROR) {
557 DCLOG(INFO, dconn) << "Network error/general error";
559 DCLOG(INFO, dconn) << "Timeout";
562 if (downstream->get_response_state() != Downstream::INITIAL) {
567 if (events & Downstream::EVENT_TIMEOUT) {
574 downstream->pop_downstream_connection();
576 handler_->signal_write();
580 void HttpsUpstream::error_reply(unsigned int status_code) {
581 auto html = http::create_error_html(status_code);
582 auto downstream = get_downstream();
585 attach_downstream(make_unique<Downstream>(this, 1, 1));
586 downstream = get_downstream();
589 downstream->set_response_http_status(status_code);
590 // we are going to close connection for both frontend and backend in
591 // error condition. This is safest option.
592 downstream->set_response_connection_close(true);
593 handler_->set_should_close_after_write(true);
595 auto output = downstream->get_response_buf();
597 output->append("HTTP/1.1 ");
598 auto status_str = http2::get_status_string(status_code);
599 output->append(status_str.c_str(), status_str.size());
600 output->append("\r\nServer: ");
601 output->append(get_config()->server_name, strlen(get_config()->server_name));
602 output->append("\r\nContent-Length: ");
603 auto cl = util::utos(html.size());
604 output->append(cl.c_str(), cl.size());
605 output->append("\r\nContent-Type: text/html; "
606 "charset=UTF-8\r\nConnection: close\r\n\r\n");
607 output->append(html.c_str(), html.size());
609 downstream->add_response_sent_bodylen(html.size());
610 downstream->set_response_state(Downstream::MSG_COMPLETE);
613 void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) {
614 assert(!downstream_);
615 downstream_ = std::move(downstream);
618 void HttpsUpstream::delete_downstream() {
619 if (downstream_ && downstream_->accesslog_ready()) {
620 handler_->write_accesslog(downstream_.get());
626 Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); }
628 std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
629 return std::unique_ptr<Downstream>(downstream_.release());
632 int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
633 if (LOG_ENABLED(INFO)) {
634 if (downstream->get_non_final_response()) {
635 DLOG(INFO, downstream) << "HTTP non-final response header";
637 DLOG(INFO, downstream) << "HTTP response header completed";
641 std::string hdrs = "HTTP/";
642 hdrs += util::utos(downstream->get_request_major());
644 hdrs += util::utos(downstream->get_request_minor());
646 hdrs += http2::get_status_string(downstream->get_response_http_status());
649 if (!get_config()->http2_proxy && !get_config()->client_proxy &&
650 !get_config()->no_location_rewrite) {
651 downstream->rewrite_location_response_header(
652 get_client_handler()->get_upstream_scheme());
655 http2::build_http1_headers_from_headers(hdrs,
656 downstream->get_response_headers());
658 auto output = downstream->get_response_buf();
660 if (downstream->get_non_final_response()) {
663 if (LOG_ENABLED(INFO)) {
664 log_response_headers(hdrs);
667 output->append(hdrs.c_str(), hdrs.size());
669 downstream->clear_response_headers();
674 // after graceful shutdown commenced, add connection: close header
676 if (worker_config->graceful_shutdown) {
677 downstream->set_response_connection_close(true);
680 // We check downstream->get_response_connection_close() in case when
681 // the Content-Length is not available.
682 if (!downstream->get_request_connection_close() &&
683 !downstream->get_response_connection_close()) {
684 if (downstream->get_request_major() <= 0 ||
685 downstream->get_request_minor() <= 0) {
686 // We add this header for HTTP/1.0 or HTTP/0.9 clients
687 hdrs += "Connection: Keep-Alive\r\n";
689 } else if (!downstream->get_upgraded() ||
690 downstream->get_request_method() != "CONNECT") {
691 hdrs += "Connection: close\r\n";
694 if (!downstream->get_response_header(http2::HD_ALT_SVC)) {
695 // We won't change or alter alt-svc from backend for now
696 if (!get_config()->altsvcs.empty()) {
699 for (auto &altsvc : get_config()->altsvcs) {
700 hdrs += util::percent_encode_token(altsvc.protocol_id);
702 hdrs += util::quote_string(std::string(altsvc.host, altsvc.host_len));
704 hdrs += util::utos(altsvc.port);
708 hdrs[hdrs.size() - 2] = '\r';
709 hdrs[hdrs.size() - 1] = '\n';
713 if (!get_config()->http2_proxy && !get_config()->client_proxy) {
715 hdrs += get_config()->server_name;
718 auto server = downstream->get_response_header(http2::HD_SERVER);
721 hdrs += (*server).value;
726 auto via = downstream->get_response_header(http2::HD_VIA);
727 if (get_config()->no_via) {
730 hdrs += (*via).value;
736 hdrs += (*via).value;
739 hdrs += http::create_via_header_value(downstream->get_response_major(),
740 downstream->get_response_minor());
744 for (auto &p : get_config()->add_response_headers) {
753 if (LOG_ENABLED(INFO)) {
754 log_response_headers(hdrs);
757 output->append(hdrs.c_str(), hdrs.size());
762 int HttpsUpstream::on_downstream_body(Downstream *downstream,
763 const uint8_t *data, size_t len,
768 auto output = downstream->get_response_buf();
769 if (downstream->get_chunked_response()) {
770 auto chunk_size_hex = util::utox(len);
771 chunk_size_hex += "\r\n";
773 output->append(chunk_size_hex.c_str(), chunk_size_hex.size());
775 output->append(data, len);
777 downstream->add_response_sent_bodylen(len);
779 if (downstream->get_chunked_response()) {
780 output->append("\r\n");
785 int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
786 if (downstream->get_chunked_response()) {
787 auto output = downstream->get_response_buf();
788 output->append("0\r\n\r\n");
790 if (LOG_ENABLED(INFO)) {
791 DLOG(INFO, downstream) << "HTTP response completed";
794 if (!downstream->validate_response_bodylen()) {
795 downstream->set_response_connection_close(true);
798 if (downstream->get_request_connection_close() ||
799 downstream->get_response_connection_close()) {
800 auto handler = get_client_handler();
801 handler->set_should_close_after_write(true);
806 int HttpsUpstream::on_downstream_abort_request(Downstream *downstream,
807 unsigned int status_code) {
808 error_reply(status_code);
809 handler_->signal_write();
813 void HttpsUpstream::log_response_headers(const std::string &hdrs) const {
816 if (worker_config->errorlog_tty) {
817 nhdrs = http::colorizeHeaders(hdrs.c_str());
818 hdrp = nhdrs.c_str();
822 ULOG(INFO, this) << "HTTP response headers\n" << hdrp;
825 void HttpsUpstream::on_handler_delete() {
826 if (downstream_ && downstream_->accesslog_ready()) {
827 handler_->write_accesslog(downstream_.get());
831 int HttpsUpstream::on_downstream_reset(bool no_retry) {
834 if ((downstream_->get_request_state() != Downstream::HEADER_COMPLETE &&
835 downstream_->get_request_state() != Downstream::MSG_COMPLETE) ||
836 downstream_->get_response_state() != Downstream::INITIAL) {
837 // Return error so that caller can delete handler
841 downstream_->pop_downstream_connection();
843 downstream_->add_retry();
845 if (no_retry || downstream_->no_more_retry()) {
846 if (on_downstream_abort_request(downstream_.get(), 503) != 0) {
852 rv = downstream_->attach_downstream_connection(
853 handler_->get_downstream_connection());
860 MemchunkPool *HttpsUpstream::get_mcpool() { return &mcpool_; }