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_http2_upstream.h"
27 #include <netinet/tcp.h>
32 #include "shrpx_client_handler.h"
33 #include "shrpx_https_upstream.h"
34 #include "shrpx_downstream.h"
35 #include "shrpx_downstream_connection.h"
36 #include "shrpx_config.h"
37 #include "shrpx_http.h"
38 #include "shrpx_worker.h"
42 #include "app_helper.h"
45 using namespace nghttp2;
50 int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
51 uint32_t error_code, void *user_data) {
52 auto upstream = static_cast<Http2Upstream *>(user_data);
53 if (LOG_ENABLED(INFO)) {
54 ULOG(INFO, upstream) << "Stream stream_id=" << stream_id
55 << " is being closed";
58 auto downstream = static_cast<Downstream *>(
59 nghttp2_session_get_stream_user_data(session, stream_id));
65 upstream->consume(stream_id, downstream->get_request_datalen());
67 downstream->reset_request_datalen();
69 if (downstream->get_request_state() == Downstream::CONNECT_FAIL) {
70 upstream->remove_downstream(downstream);
71 // downstream was deleted
76 downstream->set_request_state(Downstream::STREAM_CLOSED);
78 if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
79 // At this point, downstream response was read
80 if (!downstream->get_upgraded() &&
81 !downstream->get_response_connection_close()) {
83 downstream->detach_downstream_connection();
86 upstream->remove_downstream(downstream);
87 // downstream was deleted
92 // At this point, downstream read may be paused.
94 // If shrpx_downstream::push_request_headers() failed, the
95 // error is handled here.
96 upstream->remove_downstream(downstream);
97 // downstream was deleted
99 // How to test this case? Request sufficient large download
100 // and make client send RST_STREAM after it gets first DATA
107 int Http2Upstream::upgrade_upstream(HttpsUpstream *http) {
110 // to deduce :scheme and :authority, first we have to parse request
112 http_parser_url u = {};
113 auto &url = http->get_downstream()->get_request_path();
115 std::string scheme, authority;
116 rv = http_parser_parse_url(url.c_str(), url.size(), 0, &u);
118 http2::copy_url_component(scheme, &u, UF_SCHEMA, url.c_str());
119 http2::copy_url_component(authority, &u, UF_HOST, url.c_str());
121 if (scheme.empty()) {
122 if (handler_->get_ssl()) {
128 if (!authority.empty()) {
129 if (authority.find(":") != std::string::npos) {
130 authority = "[" + authority;
133 if (u.field_set & (1 << UF_PORT)) {
135 authority += util::utos(u.port);
139 auto http2_settings = http->get_downstream()->get_http2_settings();
140 util::to_base64(http2_settings);
142 auto settings_payload =
143 base64::decode(std::begin(http2_settings), std::end(http2_settings));
145 rv = nghttp2_session_upgrade(
146 session_, reinterpret_cast<const uint8_t *>(settings_payload.c_str()),
147 settings_payload.size(), nullptr);
149 if (LOG_ENABLED(INFO)) {
150 ULOG(INFO, this) << "nghttp2_session_upgrade() returned error: "
151 << nghttp2_strerror(rv);
155 pre_upstream_.reset(http);
156 auto downstream = http->pop_downstream();
157 downstream->reset_upstream(this);
158 downstream->set_stream_id(1);
159 downstream->reset_upstream_rtimer();
160 downstream->set_stream_id(1);
161 downstream->set_priority(0);
162 downstream->set_request_http2_authority(authority);
163 downstream->set_request_http2_scheme(scheme);
165 auto ptr = downstream.get();
167 nghttp2_session_set_stream_user_data(session_, 1, ptr);
168 downstream_queue_.add_pending(std::move(downstream));
169 downstream_queue_.mark_active(ptr);
171 if (LOG_ENABLED(INFO)) {
172 ULOG(INFO, this) << "Connection upgraded to HTTP/2";
178 void Http2Upstream::start_settings_timer() {
179 ev_timer_start(handler_->get_loop(), &settings_timer_);
182 void Http2Upstream::stop_settings_timer() {
183 ev_timer_stop(handler_->get_loop(), &settings_timer_);
187 int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
188 const uint8_t *name, size_t namelen,
189 const uint8_t *value, size_t valuelen, uint8_t flags,
191 if (get_config()->upstream_frame_debug) {
192 verbose_on_header_callback(session, frame, name, namelen, value, valuelen,
195 if (frame->hd.type != NGHTTP2_HEADERS) {
198 auto upstream = static_cast<Http2Upstream *>(user_data);
199 auto downstream = static_cast<Downstream *>(
200 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
205 if (downstream->get_request_headers_sum() + namelen + valuelen >
206 get_config()->header_field_buffer ||
207 downstream->get_request_headers().size() >=
208 get_config()->max_header_fields) {
209 if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
213 if (LOG_ENABLED(INFO)) {
214 ULOG(INFO, upstream) << "Too large or many header field size="
215 << downstream->get_request_headers_sum() + namelen +
217 << downstream->get_request_headers().size() + 1;
220 // just ignore header fields if this is trailer part.
221 if (frame->headers.cat == NGHTTP2_HCAT_HEADERS) {
225 if (upstream->error_reply(downstream, 431) != 0) {
226 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
232 if (frame->headers.cat == NGHTTP2_HCAT_HEADERS) {
233 // just store header fields for trailer part
234 downstream->add_request_trailer(name, namelen, value, valuelen,
235 flags & NGHTTP2_NV_FLAG_NO_INDEX, -1);
239 auto token = http2::lookup_token(name, namelen);
241 downstream->add_request_header(name, namelen, value, valuelen,
242 flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
248 int on_begin_headers_callback(nghttp2_session *session,
249 const nghttp2_frame *frame, void *user_data) {
250 auto upstream = static_cast<Http2Upstream *>(user_data);
252 if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
255 if (LOG_ENABLED(INFO)) {
256 ULOG(INFO, upstream) << "Received upstream request HEADERS stream_id="
257 << frame->hd.stream_id;
260 auto handler = upstream->get_client_handler();
262 // TODO Use priority 0 for now
263 auto downstream = make_unique<Downstream>(upstream, handler->get_mcpool(),
264 frame->hd.stream_id, 0);
265 nghttp2_session_set_stream_user_data(session, frame->hd.stream_id,
268 downstream->reset_upstream_rtimer();
270 // Although, we deprecated minor version from HTTP/2, we supply
271 // minor version 0 to use via header field in a conventional way.
272 downstream->set_request_major(2);
273 downstream->set_request_minor(0);
275 upstream->add_pending_downstream(std::move(downstream));
281 int Http2Upstream::on_request_headers(Downstream *downstream,
282 const nghttp2_frame *frame) {
283 if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
287 auto &nva = downstream->get_request_headers();
289 if (LOG_ENABLED(INFO)) {
290 std::stringstream ss;
291 for (auto &nv : nva) {
292 ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
294 ULOG(INFO, this) << "HTTP request headers. stream_id="
295 << downstream->get_stream_id() << "\n" << ss.str();
298 if (get_config()->http2_upstream_dump_request_header) {
299 http2::dump_nv(get_config()->http2_upstream_dump_request_header, nva);
302 auto content_length =
303 downstream->get_request_header(http2::HD_CONTENT_LENGTH);
304 if (content_length) {
305 // libnghttp2 guarantees this can be parsed
306 auto len = util::parse_uint(content_length->value);
307 downstream->set_request_content_length(len);
310 auto authority = downstream->get_request_header(http2::HD__AUTHORITY);
311 auto path = downstream->get_request_header(http2::HD__PATH);
312 auto method = downstream->get_request_header(http2::HD__METHOD);
313 auto scheme = downstream->get_request_header(http2::HD__SCHEME);
315 // presence of mandatory header fields are guaranteed by libnghttp2.
317 // For HTTP/2 proxy, we request :authority.
318 if (method->value != "CONNECT" && get_config()->http2_proxy && !authority) {
319 rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
323 downstream->set_request_method(http2::value_to_str(method));
324 downstream->set_request_http2_scheme(http2::value_to_str(scheme));
325 downstream->set_request_http2_authority(http2::value_to_str(authority));
326 downstream->set_request_path(http2::value_to_str(path));
328 if (!(frame->hd.flags & NGHTTP2_FLAG_END_STREAM)) {
329 downstream->set_request_http2_expect_body(true);
332 downstream->inspect_http2_request();
334 downstream->set_request_state(Downstream::HEADER_COMPLETE);
335 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
336 downstream->disable_upstream_rtimer();
338 downstream->set_request_state(Downstream::MSG_COMPLETE);
341 start_downstream(downstream);
346 void Http2Upstream::start_downstream(Downstream *downstream) {
347 if (downstream_queue_.can_activate(
348 downstream->get_request_http2_authority())) {
349 initiate_downstream(downstream);
353 downstream_queue_.mark_blocked(downstream);
356 void Http2Upstream::initiate_downstream(Downstream *downstream) {
359 rv = downstream->attach_downstream_connection(
360 handler_->get_downstream_connection());
362 // downstream connection fails, send error page
363 if (error_reply(downstream, 503) != 0) {
364 rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
367 downstream->set_request_state(Downstream::CONNECT_FAIL);
369 downstream_queue_.mark_failure(downstream);
373 rv = downstream->push_request_headers();
376 if (error_reply(downstream, 503) != 0) {
377 rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
380 downstream_queue_.mark_failure(downstream);
385 downstream_queue_.mark_active(downstream);
391 int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
393 if (get_config()->upstream_frame_debug) {
394 verbose_on_frame_recv_callback(session, frame, user_data);
396 auto upstream = static_cast<Http2Upstream *>(user_data);
398 switch (frame->hd.type) {
400 auto downstream = static_cast<Downstream *>(
401 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
406 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
407 downstream->disable_upstream_rtimer();
409 downstream->end_upload_data();
410 downstream->set_request_state(Downstream::MSG_COMPLETE);
415 case NGHTTP2_HEADERS: {
416 auto downstream = static_cast<Downstream *>(
417 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
422 if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
423 downstream->reset_upstream_rtimer();
425 return upstream->on_request_headers(downstream, frame);
428 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
429 downstream->disable_upstream_rtimer();
431 downstream->end_upload_data();
432 downstream->set_request_state(Downstream::MSG_COMPLETE);
437 case NGHTTP2_SETTINGS:
438 if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
441 upstream->stop_settings_timer();
444 if (LOG_ENABLED(INFO)) {
445 auto debug_data = util::ascii_dump(frame->goaway.opaque_data,
446 frame->goaway.opaque_data_len);
448 ULOG(INFO, upstream) << "GOAWAY received: last-stream-id="
449 << frame->goaway.last_stream_id
450 << ", error_code=" << frame->goaway.error_code
451 << ", debug_data=" << debug_data;
461 int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
462 int32_t stream_id, const uint8_t *data,
463 size_t len, void *user_data) {
464 auto upstream = static_cast<Http2Upstream *>(user_data);
465 auto downstream = static_cast<Downstream *>(
466 nghttp2_session_get_stream_user_data(session, stream_id));
468 if (!downstream || !downstream->get_downstream_connection()) {
469 if (upstream->consume(stream_id, len) != 0) {
470 return NGHTTP2_ERR_CALLBACK_FAILURE;
476 downstream->reset_upstream_rtimer();
478 if (downstream->push_upload_data_chunk(data, len) != 0) {
479 upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
481 if (upstream->consume(stream_id, len) != 0) {
482 return NGHTTP2_ERR_CALLBACK_FAILURE;
493 int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
495 if (get_config()->upstream_frame_debug) {
496 verbose_on_frame_send_callback(session, frame, user_data);
498 auto upstream = static_cast<Http2Upstream *>(user_data);
499 auto handler = upstream->get_client_handler();
501 switch (frame->hd.type) {
503 case NGHTTP2_HEADERS: {
504 if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
507 // RST_STREAM if request is still incomplete.
508 auto stream_id = frame->hd.stream_id;
509 auto downstream = static_cast<Downstream *>(
510 nghttp2_session_get_stream_user_data(session, stream_id));
516 // For tunneling, issue RST_STREAM to finish the stream.
517 if (downstream->get_upgraded() ||
518 nghttp2_session_get_stream_remote_close(session, stream_id) == 0) {
519 if (LOG_ENABLED(INFO)) {
521 << "Send RST_STREAM to "
522 << (downstream->get_upgraded() ? "tunneled " : "")
523 << "stream stream_id=" << downstream->get_stream_id()
524 << " to finish off incomplete request";
527 upstream->rst_stream(downstream, NGHTTP2_NO_ERROR);
532 case NGHTTP2_SETTINGS:
533 if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
534 upstream->start_settings_timer();
537 case NGHTTP2_PUSH_PROMISE: {
538 auto promised_stream_id = frame->push_promise.promised_stream_id;
539 auto downstream = make_unique<Downstream>(upstream, handler->get_mcpool(),
540 promised_stream_id, 0);
542 nghttp2_session_set_stream_user_data(session, promised_stream_id,
545 downstream->disable_upstream_rtimer();
547 downstream->set_request_major(2);
548 downstream->set_request_minor(0);
550 for (size_t i = 0; i < frame->push_promise.nvlen; ++i) {
551 auto &nv = frame->push_promise.nva[i];
552 auto token = http2::lookup_token(nv.name, nv.namelen);
554 case http2::HD__METHOD:
555 downstream->set_request_method({nv.value, nv.value + nv.valuelen});
557 case http2::HD__SCHEME:
558 downstream->set_request_http2_scheme(
559 {nv.value, nv.value + nv.valuelen});
561 case http2::HD__AUTHORITY:
562 downstream->set_request_http2_authority(
563 {nv.value, nv.value + nv.valuelen});
565 case http2::HD__PATH:
566 downstream->set_request_path({nv.value, nv.value + nv.valuelen});
569 downstream->add_request_header(nv.name, nv.namelen, nv.value, nv.valuelen,
570 nv.flags & NGHTTP2_NV_FLAG_NO_INDEX,
574 downstream->inspect_http2_request();
576 downstream->set_request_state(Downstream::MSG_COMPLETE);
578 // a bit weird but start_downstream() expects that given
579 // downstream is in pending queue.
580 auto ptr = downstream.get();
581 upstream->add_pending_downstream(std::move(downstream));
582 upstream->start_downstream(ptr);
587 if (LOG_ENABLED(INFO)) {
588 auto debug_data = util::ascii_dump(frame->goaway.opaque_data,
589 frame->goaway.opaque_data_len);
591 ULOG(INFO, upstream) << "Sending GOAWAY: last-stream-id="
592 << frame->goaway.last_stream_id
593 << ", error_code=" << frame->goaway.error_code
594 << ", debug_data=" << debug_data;
604 int on_frame_not_send_callback(nghttp2_session *session,
605 const nghttp2_frame *frame, int lib_error_code,
607 auto upstream = static_cast<Http2Upstream *>(user_data);
608 if (LOG_ENABLED(INFO)) {
609 ULOG(INFO, upstream) << "Failed to send control frame type="
610 << static_cast<uint32_t>(frame->hd.type)
611 << ", lib_error_code=" << lib_error_code << ":"
612 << nghttp2_strerror(lib_error_code);
614 if (frame->hd.type == NGHTTP2_HEADERS &&
615 lib_error_code != NGHTTP2_ERR_STREAM_CLOSED &&
616 lib_error_code != NGHTTP2_ERR_STREAM_CLOSING) {
617 // To avoid stream hanging around, issue RST_STREAM.
618 auto downstream = static_cast<Downstream *>(
619 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
621 upstream->rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
629 uint32_t infer_upstream_rst_stream_error_code(uint32_t downstream_error_code) {
630 // NGHTTP2_REFUSED_STREAM is important because it tells upstream
632 switch (downstream_error_code) {
633 case NGHTTP2_NO_ERROR:
634 case NGHTTP2_REFUSED_STREAM:
635 return downstream_error_code;
637 return NGHTTP2_INTERNAL_ERROR;
643 void settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
644 auto upstream = static_cast<Http2Upstream *>(w->data);
645 auto handler = upstream->get_client_handler();
646 ULOG(INFO, upstream) << "SETTINGS timeout";
647 if (upstream->terminate_session(NGHTTP2_SETTINGS_TIMEOUT) != 0) {
651 handler->signal_write();
656 void shutdown_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
657 auto upstream = static_cast<Http2Upstream *>(w->data);
658 auto handler = upstream->get_client_handler();
659 upstream->submit_goaway();
660 handler->signal_write();
665 void prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) {
666 auto upstream = static_cast<Http2Upstream *>(w->data);
667 upstream->check_shutdown();
671 void Http2Upstream::submit_goaway() {
672 auto last_stream_id = nghttp2_session_get_last_proc_stream_id(session_);
673 nghttp2_submit_goaway(session_, NGHTTP2_FLAG_NONE, last_stream_id,
674 NGHTTP2_NO_ERROR, nullptr, 0);
677 void Http2Upstream::check_shutdown() {
679 if (shutdown_handled_) {
683 auto worker = handler_->get_worker();
685 if (worker->get_graceful_shutdown()) {
686 shutdown_handled_ = true;
687 rv = nghttp2_submit_shutdown_notice(session_);
689 ULOG(FATAL, this) << "nghttp2_submit_shutdown_notice() failed: "
690 << nghttp2_strerror(rv);
693 handler_->signal_write();
694 ev_timer_start(handler_->get_loop(), &shutdown_timer_);
698 nghttp2_session_callbacks *create_http2_upstream_callbacks() {
700 nghttp2_session_callbacks *callbacks;
702 rv = nghttp2_session_callbacks_new(&callbacks);
708 nghttp2_session_callbacks_set_on_stream_close_callback(
709 callbacks, on_stream_close_callback);
711 nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
712 on_frame_recv_callback);
714 nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
715 callbacks, on_data_chunk_recv_callback);
717 nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
718 on_frame_send_callback);
720 nghttp2_session_callbacks_set_on_frame_not_send_callback(
721 callbacks, on_frame_not_send_callback);
723 nghttp2_session_callbacks_set_on_header_callback(callbacks,
726 nghttp2_session_callbacks_set_on_begin_headers_callback(
727 callbacks, on_begin_headers_callback);
729 if (get_config()->padding) {
730 nghttp2_session_callbacks_set_select_padding_callback(
731 callbacks, http::select_padding_callback);
737 Http2Upstream::Http2Upstream(ClientHandler *handler)
739 get_config()->http2_proxy
740 ? get_config()->downstream_connections_per_host
741 : get_config()->downstream_proto == PROTO_HTTP
742 ? get_config()->downstream_connections_per_frontend
744 !get_config()->http2_proxy),
745 handler_(handler), session_(nullptr), data_pending_(nullptr),
746 data_pendinglen_(0), shutdown_handled_(false) {
750 rv = nghttp2_session_server_new2(&session_,
751 get_config()->http2_upstream_callbacks, this,
752 get_config()->http2_option);
756 flow_control_ = true;
758 // TODO Maybe call from outside?
759 std::array<nghttp2_settings_entry, 2> entry;
760 entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
761 entry[0].value = get_config()->http2_max_concurrent_streams;
763 entry[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
764 entry[1].value = (1 << get_config()->http2_upstream_window_bits) - 1;
766 rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(),
769 ULOG(ERROR, this) << "nghttp2_submit_settings() returned error: "
770 << nghttp2_strerror(rv);
773 if (get_config()->http2_upstream_connection_window_bits > 16) {
774 int32_t delta = (1 << get_config()->http2_upstream_connection_window_bits) -
775 1 - NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
776 rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, 0, delta);
779 ULOG(ERROR, this) << "nghttp2_submit_window_update() returned error: "
780 << nghttp2_strerror(rv);
784 // We wait for SETTINGS ACK at least 10 seconds.
785 ev_timer_init(&settings_timer_, settings_timeout_cb, 10., 0.);
787 settings_timer_.data = this;
789 // timer for 2nd GOAWAY. HTTP/2 spec recommend 1 RTT. We wait for
791 ev_timer_init(&shutdown_timer_, shutdown_timeout_cb, 2., 0);
792 shutdown_timer_.data = this;
794 ev_prepare_init(&prep_, prepare_cb);
796 ev_prepare_start(handler_->get_loop(), &prep_);
798 handler_->reset_upstream_read_timeout(
799 get_config()->http2_upstream_read_timeout);
801 handler_->signal_write();
804 Http2Upstream::~Http2Upstream() {
805 nghttp2_session_del(session_);
806 ev_prepare_stop(handler_->get_loop(), &prep_);
807 ev_timer_stop(handler_->get_loop(), &shutdown_timer_);
808 ev_timer_stop(handler_->get_loop(), &settings_timer_);
811 int Http2Upstream::on_read() {
813 auto rb = handler_->get_rb();
814 auto rlimit = handler_->get_rlimit();
817 rv = nghttp2_session_mem_recv(session_, rb->pos, rb->rleft());
819 if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
820 ULOG(ERROR, this) << "nghttp2_session_recv() returned error: "
821 << nghttp2_strerror(rv);
826 // nghttp2_session_mem_recv should consume all input bytes on
828 assert(static_cast<size_t>(rv) == rb->rleft());
833 auto wb = handler_->get_wb();
834 if (nghttp2_session_want_read(session_) == 0 &&
835 nghttp2_session_want_write(session_) == 0 && wb->rleft() == 0) {
836 if (LOG_ENABLED(INFO)) {
837 ULOG(INFO, this) << "No more read/write for this HTTP2 session";
842 handler_->signal_write();
846 // After this function call, downstream may be deleted.
847 int Http2Upstream::on_write() {
848 auto wb = handler_->get_wb();
851 auto n = std::min(wb->wleft(), data_pendinglen_);
852 wb->write(data_pending_, n);
853 if (n < data_pendinglen_) {
855 data_pendinglen_ -= n;
859 data_pending_ = nullptr;
860 data_pendinglen_ = 0;
865 auto datalen = nghttp2_session_mem_send(session_, &data);
868 ULOG(ERROR, this) << "nghttp2_session_mem_send() returned error: "
869 << nghttp2_strerror(datalen);
875 auto n = wb->write(data, datalen);
876 if (n < static_cast<decltype(n)>(datalen)) {
877 data_pending_ = data + n;
878 data_pendinglen_ = datalen - n;
883 if (nghttp2_session_want_read(session_) == 0 &&
884 nghttp2_session_want_write(session_) == 0 && wb->rleft() == 0) {
885 if (LOG_ENABLED(INFO)) {
886 ULOG(INFO, this) << "No more read/write for this HTTP2 session";
894 ClientHandler *Http2Upstream::get_client_handler() const { return handler_; }
896 int Http2Upstream::downstream_read(DownstreamConnection *dconn) {
897 auto downstream = dconn->get_downstream();
899 if (downstream->get_request_state() == Downstream::STREAM_CLOSED) {
900 // If upstream HTTP2 stream was closed, we just close downstream,
901 // because there is no consumer now. Downstream connection is also
902 // closed in this case.
903 remove_downstream(downstream);
904 // downstream was deleted
909 if (downstream->get_response_state() == Downstream::MSG_RESET) {
910 // The downstream stream was reset (canceled). In this case,
911 // RST_STREAM to the upstream and delete downstream connection
912 // here. Deleting downstream will be taken place at
913 // on_stream_close_callback.
914 rst_stream(downstream,
915 infer_upstream_rst_stream_error_code(
916 downstream->get_response_rst_stream_error_code()));
917 downstream->pop_downstream_connection();
920 } else if (downstream->get_response_state() == Downstream::MSG_BAD_HEADER) {
921 if (error_reply(downstream, 502) != 0) {
924 downstream->pop_downstream_connection();
928 auto rv = downstream->on_read();
929 if (rv == SHRPX_ERR_EOF) {
930 return downstream_eof(dconn);
933 if (rv != SHRPX_ERR_NETWORK) {
934 if (LOG_ENABLED(INFO)) {
935 DCLOG(INFO, dconn) << "HTTP parser failure";
938 return downstream_error(dconn, Downstream::EVENT_ERROR);
940 // Detach downstream connection early so that it could be reused
941 // without hitting server's request timeout.
942 if (downstream->get_response_state() == Downstream::MSG_COMPLETE &&
943 !downstream->get_response_connection_close()) {
945 downstream->detach_downstream_connection();
949 handler_->signal_write();
951 // At this point, downstream may be deleted.
956 int Http2Upstream::downstream_write(DownstreamConnection *dconn) {
958 rv = dconn->on_write();
959 if (rv == SHRPX_ERR_NETWORK) {
960 return downstream_error(dconn, Downstream::EVENT_ERROR);
968 int Http2Upstream::downstream_eof(DownstreamConnection *dconn) {
969 auto downstream = dconn->get_downstream();
971 if (LOG_ENABLED(INFO)) {
972 DCLOG(INFO, dconn) << "EOF. stream_id=" << downstream->get_stream_id();
974 if (downstream->get_request_state() == Downstream::STREAM_CLOSED) {
975 // If stream was closed already, we don't need to send reply at
976 // the first place. We can delete downstream.
977 remove_downstream(downstream);
978 // downstream was deleted
983 // Delete downstream connection. If we don't delete it here, it will
984 // be pooled in on_stream_close_callback.
985 downstream->pop_downstream_connection();
988 // downstream wil be deleted in on_stream_close_callback.
989 if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
990 // Server may indicate the end of the request by EOF
991 if (LOG_ENABLED(INFO)) {
992 ULOG(INFO, this) << "Downstream body was ended by EOF";
994 downstream->set_response_state(Downstream::MSG_COMPLETE);
996 // For tunneled connection, MSG_COMPLETE signals
997 // downstream_data_read_callback to send RST_STREAM after pending
998 // response body is sent. This is needed to ensure that RST_STREAM
999 // is sent after all pending data are sent.
1000 on_downstream_body_complete(downstream);
1001 } else if (downstream->get_response_state() != Downstream::MSG_COMPLETE) {
1002 // If stream was not closed, then we set MSG_COMPLETE and let
1003 // on_stream_close_callback delete downstream.
1004 if (error_reply(downstream, 502) != 0) {
1008 handler_->signal_write();
1009 // At this point, downstream may be deleted.
1013 int Http2Upstream::downstream_error(DownstreamConnection *dconn, int events) {
1014 auto downstream = dconn->get_downstream();
1016 if (LOG_ENABLED(INFO)) {
1017 if (events & Downstream::EVENT_ERROR) {
1018 DCLOG(INFO, dconn) << "Downstream network/general error";
1020 DCLOG(INFO, dconn) << "Timeout";
1022 if (downstream->get_upgraded()) {
1023 DCLOG(INFO, dconn) << "Note: this is tunnel connection";
1027 if (downstream->get_request_state() == Downstream::STREAM_CLOSED) {
1028 remove_downstream(downstream);
1029 // downstream was deleted
1034 // Delete downstream connection. If we don't delete it here, it will
1035 // be pooled in on_stream_close_callback.
1036 downstream->pop_downstream_connection();
1037 // dconn was deleted
1040 if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
1041 // For SSL tunneling, we issue RST_STREAM. For other types of
1042 // stream, we don't have to do anything since response was
1044 if (downstream->get_upgraded()) {
1045 rst_stream(downstream, NGHTTP2_NO_ERROR);
1048 if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
1049 if (downstream->get_upgraded()) {
1050 on_downstream_body_complete(downstream);
1052 rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
1055 unsigned int status;
1056 if (events & Downstream::EVENT_TIMEOUT) {
1061 if (error_reply(downstream, status) != 0) {
1065 downstream->set_response_state(Downstream::MSG_COMPLETE);
1067 handler_->signal_write();
1068 // At this point, downstream may be deleted.
1072 int Http2Upstream::rst_stream(Downstream *downstream, uint32_t error_code) {
1073 if (LOG_ENABLED(INFO)) {
1074 ULOG(INFO, this) << "RST_STREAM stream_id=" << downstream->get_stream_id()
1075 << " with error_code=" << error_code;
1078 rv = nghttp2_submit_rst_stream(session_, NGHTTP2_FLAG_NONE,
1079 downstream->get_stream_id(), error_code);
1080 if (rv < NGHTTP2_ERR_FATAL) {
1081 ULOG(FATAL, this) << "nghttp2_submit_rst_stream() failed: "
1082 << nghttp2_strerror(rv);
1088 int Http2Upstream::terminate_session(uint32_t error_code) {
1090 rv = nghttp2_session_terminate_session(session_, error_code);
1098 ssize_t downstream_data_read_callback(nghttp2_session *session,
1099 int32_t stream_id, uint8_t *buf,
1100 size_t length, uint32_t *data_flags,
1101 nghttp2_data_source *source,
1104 auto downstream = static_cast<Downstream *>(source->ptr);
1105 auto upstream = static_cast<Http2Upstream *>(downstream->get_upstream());
1106 auto body = downstream->get_response_buf();
1109 auto dconn = downstream->get_downstream_connection();
1111 if (body->rleft() == 0 && dconn &&
1112 downstream->get_response_state() != Downstream::MSG_COMPLETE) {
1113 // Try to read more if buffer is empty. This will help small
1114 // buffer and make priority handling a bit better.
1115 if (upstream->downstream_read(dconn) != 0) {
1116 return NGHTTP2_ERR_CALLBACK_FAILURE;
1120 auto nread = body->remove(buf, length);
1121 auto body_empty = body->rleft() == 0;
1124 downstream->get_response_state() == Downstream::MSG_COMPLETE) {
1126 *data_flags |= NGHTTP2_DATA_FLAG_EOF;
1128 if (!downstream->get_upgraded()) {
1129 auto &trailers = downstream->get_response_trailers();
1130 if (!trailers.empty()) {
1131 std::vector<nghttp2_nv> nva;
1132 nva.reserve(trailers.size());
1133 http2::copy_headers_to_nva(nva, trailers);
1135 rv = nghttp2_submit_trailer(session, stream_id, nva.data(),
1138 if (nghttp2_is_fatal(rv)) {
1139 return NGHTTP2_ERR_CALLBACK_FAILURE;
1142 *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
1150 downstream->disable_upstream_wtimer();
1152 downstream->reset_upstream_wtimer();
1155 if (nread > 0 && downstream->resume_read(SHRPX_NO_BUFFER, nread) != 0) {
1156 return NGHTTP2_ERR_CALLBACK_FAILURE;
1159 if (nread == 0 && ((*data_flags) & NGHTTP2_DATA_FLAG_EOF) == 0) {
1160 return NGHTTP2_ERR_DEFERRED;
1164 downstream->add_response_sent_bodylen(nread);
1171 int Http2Upstream::error_reply(Downstream *downstream,
1172 unsigned int status_code) {
1174 auto html = http::create_error_html(status_code);
1175 downstream->set_response_http_status(status_code);
1176 auto body = downstream->get_response_buf();
1177 body->append(html.c_str(), html.size());
1178 downstream->set_response_state(Downstream::MSG_COMPLETE);
1180 nghttp2_data_provider data_prd;
1181 data_prd.source.ptr = downstream;
1182 data_prd.read_callback = downstream_data_read_callback;
1184 auto content_length = util::utos(html.size());
1185 auto status_code_str = util::utos(status_code);
1187 make_array(http2::make_nv_ls(":status", status_code_str),
1188 http2::make_nv_ll("content-type", "text/html; charset=UTF-8"),
1189 http2::make_nv_lc("server", get_config()->server_name),
1190 http2::make_nv_ls("content-length", content_length));
1192 rv = nghttp2_submit_response(session_, downstream->get_stream_id(),
1193 nva.data(), nva.size(), &data_prd);
1194 if (rv < NGHTTP2_ERR_FATAL) {
1195 ULOG(FATAL, this) << "nghttp2_submit_response() failed: "
1196 << nghttp2_strerror(rv);
1204 Http2Upstream::add_pending_downstream(std::unique_ptr<Downstream> downstream) {
1205 downstream_queue_.add_pending(std::move(downstream));
1208 void Http2Upstream::remove_downstream(Downstream *downstream) {
1209 if (downstream->accesslog_ready()) {
1210 handler_->write_accesslog(downstream);
1213 nghttp2_session_set_stream_user_data(session_, downstream->get_stream_id(),
1216 auto next_downstream = downstream_queue_.remove_and_get_blocked(downstream);
1218 if (next_downstream) {
1219 initiate_downstream(next_downstream);
1223 // WARNING: Never call directly or indirectly nghttp2_session_send or
1224 // nghttp2_session_recv. These calls may delete downstream.
1225 int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
1228 if (LOG_ENABLED(INFO)) {
1229 if (downstream->get_non_final_response()) {
1230 DLOG(INFO, downstream) << "HTTP non-final response header";
1232 DLOG(INFO, downstream) << "HTTP response header completed";
1236 if (!get_config()->http2_proxy && !get_config()->client_proxy &&
1237 !get_config()->no_location_rewrite) {
1238 downstream->rewrite_location_response_header(
1239 downstream->get_request_http2_scheme());
1242 size_t nheader = downstream->get_response_headers().size();
1243 auto nva = std::vector<nghttp2_nv>();
1244 // 3 means :status and possible server and via header field.
1245 nva.reserve(nheader + 3 + get_config()->add_response_headers.size());
1246 std::string via_value;
1247 auto response_status = util::utos(downstream->get_response_http_status());
1248 nva.push_back(http2::make_nv_ls(":status", response_status));
1250 http2::copy_headers_to_nva(nva, downstream->get_response_headers());
1252 if (downstream->get_non_final_response()) {
1253 if (LOG_ENABLED(INFO)) {
1254 log_response_headers(downstream, nva);
1257 rv = nghttp2_submit_headers(session_, NGHTTP2_FLAG_NONE,
1258 downstream->get_stream_id(), nullptr,
1259 nva.data(), nva.size(), nullptr);
1261 downstream->clear_response_headers();
1264 ULOG(FATAL, this) << "nghttp2_submit_headers() failed";
1271 if (!get_config()->http2_proxy && !get_config()->client_proxy) {
1272 nva.push_back(http2::make_nv_lc("server", get_config()->server_name));
1274 auto server = downstream->get_response_header(http2::HD_SERVER);
1276 nva.push_back(http2::make_nv_ls("server", (*server).value));
1280 auto via = downstream->get_response_header(http2::HD_VIA);
1281 if (get_config()->no_via) {
1283 nva.push_back(http2::make_nv_ls("via", (*via).value));
1287 via_value = (*via).value;
1290 via_value += http::create_via_header_value(
1291 downstream->get_response_major(), downstream->get_response_minor());
1292 nva.push_back(http2::make_nv_ls("via", via_value));
1295 for (auto &p : get_config()->add_response_headers) {
1296 nva.push_back(http2::make_nv(p.first, p.second));
1299 if (LOG_ENABLED(INFO)) {
1300 log_response_headers(downstream, nva);
1303 if (get_config()->http2_upstream_dump_response_header) {
1304 http2::dump_nv(get_config()->http2_upstream_dump_response_header,
1305 nva.data(), nva.size());
1308 nghttp2_data_provider data_prd;
1309 data_prd.source.ptr = downstream;
1310 data_prd.read_callback = downstream_data_read_callback;
1312 nghttp2_data_provider *data_prdptr;
1314 if (downstream->expect_response_body()) {
1315 data_prdptr = &data_prd;
1317 data_prdptr = nullptr;
1320 rv = nghttp2_submit_response(session_, downstream->get_stream_id(),
1321 nva.data(), nva.size(), data_prdptr);
1323 ULOG(FATAL, this) << "nghttp2_submit_response() failed";
1327 // We need some conditions that must be fulfilled to initiate server
1330 // * Server push is disabled for http2 proxy, since incoming headers
1331 // are mixed origins. We don't know how to reliably determine the
1334 // * If downstream is http/2, it is likely that PUSH_PROMISE is
1335 // coming from there, so we don't initiate PUSH_RPOMISE here.
1337 // * We need 200 response code for associated resource. This is too
1338 // restrictive, we will review this later.
1340 // * We requires GET or POST for associated resource. Probably we
1341 // don't want to push for HEAD request. Not sure other methods
1342 // are also eligible for push.
1343 if (!get_config()->no_server_push &&
1344 get_config()->downstream_proto == PROTO_HTTP &&
1345 !get_config()->http2_proxy && (downstream->get_stream_id() % 2) &&
1346 downstream->get_response_header(http2::HD_LINK) &&
1347 downstream->get_response_http_status() == 200 &&
1348 (downstream->get_request_method() == "GET" ||
1349 downstream->get_request_method() == "POST")) {
1351 if (prepare_push_promise(downstream) != 0) {
1359 // WARNING: Never call directly or indirectly nghttp2_session_send or
1360 // nghttp2_session_recv. These calls may delete downstream.
1361 int Http2Upstream::on_downstream_body(Downstream *downstream,
1362 const uint8_t *data, size_t len,
1364 auto body = downstream->get_response_buf();
1365 body->append(data, len);
1368 nghttp2_session_resume_data(session_, downstream->get_stream_id());
1370 downstream->ensure_upstream_wtimer();
1376 // WARNING: Never call directly or indirectly nghttp2_session_send or
1377 // nghttp2_session_recv. These calls may delete downstream.
1378 int Http2Upstream::on_downstream_body_complete(Downstream *downstream) {
1379 if (LOG_ENABLED(INFO)) {
1380 DLOG(INFO, downstream) << "HTTP response completed";
1383 if (!downstream->validate_response_bodylen()) {
1384 rst_stream(downstream, NGHTTP2_PROTOCOL_ERROR);
1385 downstream->set_response_connection_close(true);
1389 nghttp2_session_resume_data(session_, downstream->get_stream_id());
1390 downstream->ensure_upstream_wtimer();
1395 bool Http2Upstream::get_flow_control() const { return flow_control_; }
1397 void Http2Upstream::pause_read(IOCtrlReason reason) {}
1399 int Http2Upstream::resume_read(IOCtrlReason reason, Downstream *downstream,
1401 if (get_flow_control()) {
1402 assert(downstream->get_request_datalen() >= consumed);
1404 if (consume(downstream->get_stream_id(), consumed) != 0) {
1408 downstream->dec_request_datalen(consumed);
1411 handler_->signal_write();
1415 int Http2Upstream::on_downstream_abort_request(Downstream *downstream,
1416 unsigned int status_code) {
1419 rv = error_reply(downstream, status_code);
1425 handler_->signal_write();
1429 int Http2Upstream::consume(int32_t stream_id, size_t len) {
1432 rv = nghttp2_session_consume(session_, stream_id, len);
1435 ULOG(WARN, this) << "nghttp2_session_consume() returned error: "
1436 << nghttp2_strerror(rv);
1444 Http2Upstream::log_response_headers(Downstream *downstream,
1445 const std::vector<nghttp2_nv> &nva) const {
1446 std::stringstream ss;
1447 for (auto &nv : nva) {
1448 ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
1450 ULOG(INFO, this) << "HTTP response headers. stream_id="
1451 << downstream->get_stream_id() << "\n" << ss.str();
1454 int Http2Upstream::on_timeout(Downstream *downstream) {
1455 if (LOG_ENABLED(INFO)) {
1456 ULOG(INFO, this) << "Stream timeout stream_id="
1457 << downstream->get_stream_id();
1460 rst_stream(downstream, NGHTTP2_NO_ERROR);
1465 void Http2Upstream::on_handler_delete() {
1466 for (auto d = downstream_queue_.get_downstreams(); d; d = d->dlnext) {
1467 if (d->get_dispatch_state() == Downstream::DISPATCH_ACTIVE &&
1468 d->accesslog_ready()) {
1469 handler_->write_accesslog(d);
1474 int Http2Upstream::on_downstream_reset(bool no_retry) {
1477 for (auto downstream = downstream_queue_.get_downstreams(); downstream;
1478 downstream = downstream->dlnext) {
1479 if (downstream->get_dispatch_state() != Downstream::DISPATCH_ACTIVE) {
1483 if (!downstream->request_submission_ready()) {
1484 rst_stream(downstream, NGHTTP2_INTERNAL_ERROR);
1485 downstream->pop_downstream_connection();
1489 downstream->pop_downstream_connection();
1491 downstream->add_retry();
1493 if (no_retry || downstream->no_more_retry()) {
1497 // downstream connection is clean; we can retry with new
1498 // downstream connection.
1500 rv = downstream->attach_downstream_connection(
1501 handler_->get_downstream_connection());
1509 if (on_downstream_abort_request(downstream, 503) != 0) {
1512 downstream->pop_downstream_connection();
1515 handler_->signal_write();
1520 int Http2Upstream::prepare_push_promise(Downstream *downstream) {
1523 memset(&u, 0, sizeof(u));
1524 rv = http_parser_parse_url(downstream->get_request_path().c_str(),
1525 downstream->get_request_path().size(), 0, &u);
1531 if (u.field_set & (1 << UF_PATH)) {
1532 auto &f = u.field_data[UF_PATH];
1533 base = downstream->get_request_path().c_str() + f.off;
1539 for (auto &kv : downstream->get_response_headers()) {
1540 if (kv.token != http2::HD_LINK) {
1544 http2::parse_link_header(kv.value.c_str(), kv.value.size())) {
1545 auto link_url = link.uri.first;
1546 auto link_urllen = link.uri.second - link.uri.first;
1550 const char *relq = nullptr;
1554 memset(&v, 0, sizeof(v));
1555 rv = http_parser_parse_url(link_url, link_urllen, 0, &v);
1557 assert(link_urllen);
1558 if (link_url[0] == '/') {
1561 // treat link_url as relative URI.
1562 auto end = std::find(link_url, link_url + link_urllen, '#');
1563 auto q = std::find(link_url, end, '?');
1565 rellen = q - link_url;
1568 relqlen = end - relq;
1571 if (v.field_set & (1 << UF_HOST)) {
1574 if (v.field_set & (1 << UF_PATH)) {
1575 auto &f = v.field_data[UF_PATH];
1576 rel = link_url + f.off;
1583 if (v.field_set & (1 << UF_QUERY)) {
1584 auto &f = v.field_data[UF_QUERY];
1585 relq = link_url + f.off;
1589 auto path = http2::path_join(base, baselen, nullptr, 0, rel, rellen, relq,
1591 rv = submit_push_promise(path, downstream);
1600 int Http2Upstream::submit_push_promise(const std::string &path,
1601 Downstream *downstream) {
1603 std::vector<nghttp2_nv> nva;
1604 nva.reserve(downstream->get_request_headers().size());
1606 // juse use "GET" for now
1607 nva.push_back(http2::make_nv_ll(":method", "GET"));
1609 http2::make_nv_ls(":scheme", downstream->get_request_http2_scheme()));
1610 nva.push_back(http2::make_nv_ls(":path", path));
1611 auto &authority = downstream->get_request_http2_authority();
1612 if (!authority.empty()) {
1613 nva.push_back(http2::make_nv_ls(":authority", authority));
1616 for (auto &kv : downstream->get_request_headers()) {
1618 // TODO generate referer
1619 case http2::HD__AUTHORITY:
1620 case http2::HD__SCHEME:
1621 case http2::HD__METHOD:
1622 case http2::HD__PATH:
1624 case http2::HD_ACCEPT_ENCODING:
1625 case http2::HD_ACCEPT_LANGUAGE:
1626 case http2::HD_CACHE_CONTROL:
1627 case http2::HD_HOST:
1628 case http2::HD_USER_AGENT:
1629 nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
1634 rv = nghttp2_submit_push_promise(session_, NGHTTP2_FLAG_NONE,
1635 downstream->get_stream_id(), nva.data(),
1636 nva.size(), nullptr);
1639 if (LOG_ENABLED(INFO)) {
1640 ULOG(INFO, this) << "nghttp2_submit_push_promise() failed: "
1641 << nghttp2_strerror(rv);
1643 if (nghttp2_is_fatal(rv)) {
1649 if (LOG_ENABLED(INFO)) {
1650 std::stringstream ss;
1651 for (auto &nv : nva) {
1652 ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
1654 ULOG(INFO, this) << "HTTP push request headers. promised_stream_id=" << rv
1655 << "\n" << ss.str();
1661 } // namespace shrpx