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_session.h"
27 #include <netinet/tcp.h>
30 #endif // HAVE_UNISTD_H
34 #include <openssl/err.h>
36 #include "shrpx_upstream.h"
37 #include "shrpx_downstream.h"
38 #include "shrpx_config.h"
39 #include "shrpx_error.h"
40 #include "shrpx_http2_downstream_connection.h"
41 #include "shrpx_client_handler.h"
42 #include "shrpx_ssl.h"
43 #include "shrpx_http.h"
44 #include "shrpx_worker.h"
45 #include "shrpx_connect_blocker.h"
50 using namespace nghttp2;
55 const ev_tstamp CONNCHK_TIMEOUT = 5.;
56 const ev_tstamp CONNCHK_PING_TIMEOUT = 1.;
60 void connchk_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
61 auto http2session = static_cast<Http2Session *>(w->data);
63 ev_timer_stop(loop, w);
65 switch (http2session->get_connection_check_state()) {
66 case Http2Session::CONNECTION_CHECK_STARTED:
67 // ping timeout; disconnect
68 if (LOG_ENABLED(INFO)) {
69 SSLOG(INFO, http2session) << "ping timeout";
71 http2session->disconnect();
74 if (LOG_ENABLED(INFO)) {
75 SSLOG(INFO, http2session) << "connection check required";
77 http2session->set_connection_check_state(
78 Http2Session::CONNECTION_CHECK_REQUIRED);
84 void settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
85 auto http2session = static_cast<Http2Session *>(w->data);
86 http2session->stop_settings_timer();
87 SSLOG(INFO, http2session) << "SETTINGS timeout";
88 if (http2session->terminate_session(NGHTTP2_SETTINGS_TIMEOUT) != 0) {
89 http2session->disconnect();
92 http2session->signal_write();
97 void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
98 auto conn = static_cast<Connection *>(w->data);
99 auto http2session = static_cast<Http2Session *>(conn->data);
101 if (LOG_ENABLED(INFO)) {
102 SSLOG(INFO, http2session) << "Timeout";
105 http2session->disconnect(http2session->get_state() ==
106 Http2Session::CONNECTING);
111 void readcb(struct ev_loop *loop, ev_io *w, int revents) {
113 auto conn = static_cast<Connection *>(w->data);
114 auto http2session = static_cast<Http2Session *>(conn->data);
115 rv = http2session->do_read();
117 http2session->disconnect(http2session->should_hard_fail());
120 http2session->connection_alive();
122 rv = http2session->do_write();
124 http2session->disconnect(http2session->should_hard_fail());
131 void writecb(struct ev_loop *loop, ev_io *w, int revents) {
133 auto conn = static_cast<Connection *>(w->data);
134 auto http2session = static_cast<Http2Session *>(conn->data);
135 rv = http2session->do_write();
137 http2session->disconnect(http2session->should_hard_fail());
140 http2session->reset_connection_check_timer_if_not_checking();
144 Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
145 ConnectBlocker *connect_blocker, Worker *worker)
146 : conn_(loop, -1, nullptr, get_config()->downstream_write_timeout,
147 get_config()->downstream_read_timeout, 0, 0, 0, 0, writecb, readcb,
149 worker_(worker), connect_blocker_(connect_blocker), ssl_ctx_(ssl_ctx),
150 session_(nullptr), data_pending_(nullptr), data_pendinglen_(0),
151 addr_idx_(0), state_(DISCONNECTED),
152 connection_check_state_(CONNECTION_CHECK_NONE), flow_control_(false) {
154 read_ = write_ = &Http2Session::noop;
155 on_read_ = on_write_ = &Http2Session::noop;
157 // We will resuse this many times, so use repeat timeout value. The
158 // timeout value is set later.
159 ev_timer_init(&connchk_timer_, connchk_timeout_cb, 0., 0.);
161 connchk_timer_.data = this;
163 // SETTINGS ACK timeout is 10 seconds for now. We will resuse this
164 // many times, so use repeat timeout value.
165 ev_timer_init(&settings_timer_, settings_timeout_cb, 0., 10.);
167 settings_timer_.data = this;
170 Http2Session::~Http2Session() { disconnect(); }
172 int Http2Session::disconnect(bool hard) {
173 if (LOG_ENABLED(INFO)) {
174 SSLOG(INFO, this) << "Disconnecting";
176 nghttp2_session_del(session_);
182 conn_.rlimit.stopw();
183 conn_.wlimit.stopw();
185 ev_timer_stop(conn_.loop, &settings_timer_);
186 ev_timer_stop(conn_.loop, &connchk_timer_);
188 read_ = write_ = &Http2Session::noop;
189 on_read_ = on_write_ = &Http2Session::noop;
199 connection_check_state_ = CONNECTION_CHECK_NONE;
200 state_ = DISCONNECTED;
202 // Delete all client handler associated to Downstream. When deleting
203 // Http2DownstreamConnection, it calls this object's
204 // remove_downstream_connection(). The multiple
205 // Http2DownstreamConnection objects belong to the same
206 // ClientHandler object. So first dump ClientHandler objects. We
207 // want to allow creating new pending Http2DownstreamConnection with
208 // this object. In order to achieve this, we first swap dconns_ and
209 // streams_. Upstream::on_downstream_reset() may add
210 // Http2DownstreamConnection.
211 auto dconns = std::move(dconns_);
212 auto streams = std::move(streams_);
214 std::set<ClientHandler *> handlers;
215 for (auto dc = dconns.head; dc; dc = dc->dlnext) {
216 if (!dc->get_client_handler()) {
219 handlers.insert(dc->get_client_handler());
221 for (auto h : handlers) {
222 if (h->get_upstream()->on_downstream_reset(hard) != 0) {
227 for (auto s = streams.head; s;) {
228 auto next = s->dlnext;
236 int Http2Session::check_cert() { return ssl::check_cert(conn_.tls.ssl); }
238 int Http2Session::initiate_connection() {
241 if (state_ == DISCONNECTED) {
242 if (connect_blocker_->blocked()) {
243 if (LOG_ENABLED(INFO)) {
245 << "Downstream connection was blocked by connect_blocker";
250 auto worker_stat = worker_->get_worker_stat();
251 addr_idx_ = worker_stat->next_downstream;
252 ++worker_stat->next_downstream;
253 worker_stat->next_downstream %= get_config()->downstream_addrs.size();
255 if (LOG_ENABLED(INFO)) {
256 SSLOG(INFO, this) << "Using downstream address idx=" << addr_idx_
257 << " out of " << get_config()->downstream_addrs.size();
261 auto &downstream_addr = get_config()->downstream_addrs[addr_idx_];
263 if (get_config()->downstream_http_proxy_host && state_ == DISCONNECTED) {
264 if (LOG_ENABLED(INFO)) {
265 SSLOG(INFO, this) << "Connecting to the proxy "
266 << get_config()->downstream_http_proxy_host.get() << ":"
267 << get_config()->downstream_http_proxy_port;
270 conn_.fd = util::create_nonblock_socket(
271 get_config()->downstream_http_proxy_addr.storage.ss_family);
273 if (conn_.fd == -1) {
274 connect_blocker_->on_failure();
278 rv = connect(conn_.fd, &get_config()->downstream_http_proxy_addr.sa,
279 get_config()->downstream_http_proxy_addrlen);
280 if (rv != 0 && errno != EINPROGRESS) {
281 SSLOG(ERROR, this) << "Failed to connect to the proxy "
282 << get_config()->downstream_http_proxy_host.get()
283 << ":" << get_config()->downstream_http_proxy_port;
284 connect_blocker_->on_failure();
288 ev_io_set(&conn_.rev, conn_.fd, EV_READ);
289 ev_io_set(&conn_.wev, conn_.fd, EV_WRITE);
291 conn_.wlimit.startw();
293 // TODO we should have timeout for connection establishment
294 ev_timer_again(conn_.loop, &conn_.wt);
296 write_ = &Http2Session::connected;
298 on_read_ = &Http2Session::downstream_read_proxy;
299 on_write_ = &Http2Session::downstream_connect_proxy;
301 proxy_htp_ = make_unique<http_parser>();
302 http_parser_init(proxy_htp_.get(), HTTP_RESPONSE);
303 proxy_htp_->data = this;
305 state_ = PROXY_CONNECTING;
310 if (state_ == DISCONNECTED || state_ == PROXY_CONNECTED) {
311 if (LOG_ENABLED(INFO)) {
312 SSLOG(INFO, this) << "Connecting to downstream server";
315 // We are establishing TLS connection.
316 conn_.tls.ssl = SSL_new(ssl_ctx_);
317 if (!conn_.tls.ssl) {
318 SSLOG(ERROR, this) << "SSL_new() failed: "
319 << ERR_error_string(ERR_get_error(), NULL);
323 const char *sni_name = nullptr;
324 if (get_config()->backend_tls_sni_name) {
325 sni_name = get_config()->backend_tls_sni_name.get();
327 sni_name = downstream_addr.host.get();
330 if (sni_name && !util::numeric_host(sni_name)) {
331 // TLS extensions: SNI. There is no documentation about the return
332 // code for this function (actually this is macro wrapping SSL_ctrl
333 // at the time of this writing).
334 SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name);
336 // If state_ == PROXY_CONNECTED, we has connected to the proxy
337 // using conn_.fd and tunnel has been established.
338 if (state_ == DISCONNECTED) {
339 assert(conn_.fd == -1);
341 conn_.fd = util::create_nonblock_socket(
342 downstream_addr.addr.storage.ss_family);
343 if (conn_.fd == -1) {
344 connect_blocker_->on_failure();
348 rv = connect(conn_.fd,
349 // TODO maybe not thread-safe?
350 const_cast<sockaddr *>(&downstream_addr.addr.sa),
351 downstream_addr.addrlen);
352 if (rv != 0 && errno != EINPROGRESS) {
353 connect_blocker_->on_failure();
357 ev_io_set(&conn_.rev, conn_.fd, EV_READ);
358 ev_io_set(&conn_.wev, conn_.fd, EV_WRITE);
361 if (SSL_set_fd(conn_.tls.ssl, conn_.fd) == 0) {
365 SSL_set_connect_state(conn_.tls.ssl);
367 if (state_ == DISCONNECTED) {
368 // Without TLS and proxy.
369 assert(conn_.fd == -1);
371 conn_.fd = util::create_nonblock_socket(
372 downstream_addr.addr.storage.ss_family);
374 if (conn_.fd == -1) {
375 connect_blocker_->on_failure();
379 rv = connect(conn_.fd, const_cast<sockaddr *>(&downstream_addr.addr.sa),
380 downstream_addr.addrlen);
381 if (rv != 0 && errno != EINPROGRESS) {
382 connect_blocker_->on_failure();
386 ev_io_set(&conn_.rev, conn_.fd, EV_READ);
387 ev_io_set(&conn_.wev, conn_.fd, EV_WRITE);
391 write_ = &Http2Session::connected;
393 on_write_ = &Http2Session::downstream_write;
394 on_read_ = &Http2Session::downstream_read;
396 // We have been already connected when no TLS and proxy is used.
397 if (state_ != CONNECTED) {
399 conn_.wlimit.startw();
400 // TODO we should have timeout for connection establishment
401 ev_timer_again(conn_.loop, &conn_.wt);
403 conn_.rlimit.startw();
404 ev_timer_again(conn_.loop, &conn_.rt);
416 int htp_hdrs_completecb(http_parser *htp) {
417 auto http2session = static_cast<Http2Session *>(htp->data);
419 // We only read HTTP header part. If tunneling succeeds, response
420 // body is a different protocol (HTTP/2 in this case), we don't read
423 // Here is a caveat: http-parser returns 1 less bytes if we pause
424 // here. The reason why they do this is probably they want to eat
425 // last 1 byte in s_headers_done state, on the other hand, this
426 // callback is called its previous state s_headers_almost_done. We
427 // will do "+ 1" to the return value to workaround this.
428 http_parser_pause(htp, 1);
430 // We just check status code here
431 if (htp->status_code == 200) {
432 if (LOG_ENABLED(INFO)) {
433 SSLOG(INFO, http2session) << "Tunneling success";
435 http2session->set_state(Http2Session::PROXY_CONNECTED);
440 SSLOG(WARN, http2session) << "Tunneling failed: " << htp->status_code;
441 http2session->set_state(Http2Session::PROXY_FAILED);
448 http_parser_settings htp_hooks = {
449 nullptr, // http_cb on_message_begin;
450 nullptr, // http_data_cb on_url;
451 nullptr, // http_data_cb on_status;
452 nullptr, // http_data_cb on_header_field;
453 nullptr, // http_data_cb on_header_value;
454 htp_hdrs_completecb, // http_cb on_headers_complete;
455 nullptr, // http_data_cb on_body;
456 nullptr // http_cb on_message_complete;
460 int Http2Session::downstream_read_proxy() {
461 if (rb_.rleft() == 0) {
466 http_parser_execute(proxy_htp_.get(), &htp_hooks,
467 reinterpret_cast<const char *>(rb_.pos), rb_.rleft());
471 auto htperr = HTTP_PARSER_ERRNO(proxy_htp_.get());
473 if (htperr == HPE_PAUSED) {
475 case Http2Session::PROXY_CONNECTED:
476 // we need to increment nread by 1 since http_parser_execute()
477 // returns 1 less value we expect. This means taht
478 // rb_.pos[nread] points to \x0a (LF), which is last byte of
479 // empty line to terminate headers. We want to eat that byte
483 // Initiate SSL/TLS handshake through established tunnel.
484 if (initiate_connection() != 0) {
488 case Http2Session::PROXY_FAILED:
491 // should not be here
495 if (htperr != HPE_OK) {
502 int Http2Session::downstream_connect_proxy() {
503 if (LOG_ENABLED(INFO)) {
504 SSLOG(INFO, this) << "Connected to the proxy";
506 auto &downstream_addr = get_config()->downstream_addrs[addr_idx_];
508 std::string req = "CONNECT ";
509 req += downstream_addr.hostport.get();
510 if (downstream_addr.port == 80 || downstream_addr.port == 443) {
512 req += util::utos(downstream_addr.port);
514 req += " HTTP/1.1\r\nHost: ";
515 req += downstream_addr.host.get();
517 if (get_config()->downstream_http_proxy_userinfo) {
518 req += "Proxy-Authorization: Basic ";
519 size_t len = strlen(get_config()->downstream_http_proxy_userinfo.get());
520 req += base64::encode(get_config()->downstream_http_proxy_userinfo.get(),
521 get_config()->downstream_http_proxy_userinfo.get() +
526 if (LOG_ENABLED(INFO)) {
527 SSLOG(INFO, this) << "HTTP proxy request headers\n" << req;
529 auto nwrite = wb_.write(req.c_str(), req.size());
530 if (nwrite != req.size()) {
531 SSLOG(WARN, this) << "HTTP proxy request is too large";
534 on_write_ = &Http2Session::noop;
540 void Http2Session::add_downstream_connection(Http2DownstreamConnection *dconn) {
541 dconns_.append(dconn);
545 Http2Session::remove_downstream_connection(Http2DownstreamConnection *dconn) {
546 dconns_.remove(dconn);
547 dconn->detach_stream_data();
550 void Http2Session::remove_stream_data(StreamData *sd) {
553 sd->dconn->detach_stream_data();
558 int Http2Session::submit_request(Http2DownstreamConnection *dconn, int32_t pri,
559 const nghttp2_nv *nva, size_t nvlen,
560 const nghttp2_data_provider *data_prd) {
561 assert(state_ == CONNECTED);
562 auto sd = make_unique<StreamData>();
563 sd->dlnext = sd->dlprev = nullptr;
564 // TODO Specify nullptr to pri_spec for now
566 nghttp2_submit_request(session_, nullptr, nva, nvlen, data_prd, sd.get());
568 SSLOG(FATAL, this) << "nghttp2_submit_request() failed: "
569 << nghttp2_strerror(stream_id);
573 dconn->attach_stream_data(sd.get());
574 dconn->get_downstream()->set_downstream_stream_id(stream_id);
575 streams_.append(sd.release());
580 int Http2Session::submit_rst_stream(int32_t stream_id, uint32_t error_code) {
581 assert(state_ == CONNECTED);
582 if (LOG_ENABLED(INFO)) {
583 SSLOG(INFO, this) << "RST_STREAM stream_id=" << stream_id
584 << " with error_code=" << error_code;
586 int rv = nghttp2_submit_rst_stream(session_, NGHTTP2_FLAG_NONE, stream_id,
589 SSLOG(FATAL, this) << "nghttp2_submit_rst_stream() failed: "
590 << nghttp2_strerror(rv);
596 int Http2Session::submit_priority(Http2DownstreamConnection *dconn,
598 assert(state_ == CONNECTED);
604 // TODO Disabled temporarily
606 // rv = nghttp2_submit_priority(session_, NGHTTP2_FLAG_NONE,
607 // dconn->get_downstream()->
608 // get_downstream_stream_id(), pri);
612 if (rv < NGHTTP2_ERR_FATAL) {
613 SSLOG(FATAL, this) << "nghttp2_submit_priority() failed: "
614 << nghttp2_strerror(rv);
620 nghttp2_session *Http2Session::get_session() const { return session_; }
622 bool Http2Session::get_flow_control() const { return flow_control_; }
624 int Http2Session::resume_data(Http2DownstreamConnection *dconn) {
625 assert(state_ == CONNECTED);
626 auto downstream = dconn->get_downstream();
627 int rv = nghttp2_session_resume_data(session_,
628 downstream->get_downstream_stream_id());
631 case NGHTTP2_ERR_INVALID_ARGUMENT:
634 SSLOG(FATAL, this) << "nghttp2_resume_session() failed: "
635 << nghttp2_strerror(rv);
641 void call_downstream_readcb(Http2Session *http2session,
642 Downstream *downstream) {
643 auto upstream = downstream->get_upstream();
647 if (upstream->downstream_read(downstream->get_downstream_connection()) != 0) {
648 delete upstream->get_client_handler();
654 int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
655 uint32_t error_code, void *user_data) {
656 auto http2session = static_cast<Http2Session *>(user_data);
657 if (LOG_ENABLED(INFO)) {
658 SSLOG(INFO, http2session) << "Stream stream_id=" << stream_id
659 << " is being closed with error code "
662 auto sd = static_cast<StreamData *>(
663 nghttp2_session_get_stream_user_data(session, stream_id));
665 // We might get this close callback when pushed streams are
669 auto dconn = sd->dconn;
671 auto downstream = dconn->get_downstream();
672 if (downstream && downstream->get_downstream_stream_id() == stream_id) {
674 if (downstream->get_upgraded() &&
675 downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
676 // For tunneled connection, we have to submit RST_STREAM to
677 // upstream *after* whole response body is sent. We just set
678 // MSG_COMPLETE here. Upstream will take care of that.
679 downstream->get_upstream()->on_downstream_body_complete(downstream);
680 downstream->set_response_state(Downstream::MSG_COMPLETE);
681 } else if (error_code == NGHTTP2_NO_ERROR) {
682 switch (downstream->get_response_state()) {
683 case Downstream::MSG_COMPLETE:
684 case Downstream::MSG_BAD_HEADER:
687 downstream->set_response_state(Downstream::MSG_RESET);
689 } else if (downstream->get_response_state() !=
690 Downstream::MSG_BAD_HEADER) {
691 downstream->set_response_state(Downstream::MSG_RESET);
693 if (downstream->get_response_state() == Downstream::MSG_RESET &&
694 downstream->get_response_rst_stream_error_code() ==
696 downstream->set_response_rst_stream_error_code(error_code);
698 call_downstream_readcb(http2session, downstream);
699 // dconn may be deleted
702 // The life time of StreamData ends here
703 http2session->remove_stream_data(sd);
708 void Http2Session::start_settings_timer() {
709 ev_timer_again(conn_.loop, &settings_timer_);
712 void Http2Session::stop_settings_timer() {
713 ev_timer_stop(conn_.loop, &settings_timer_);
717 int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
718 const uint8_t *name, size_t namelen,
719 const uint8_t *value, size_t valuelen, uint8_t flags,
721 auto sd = static_cast<StreamData *>(
722 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
723 if (!sd || !sd->dconn) {
726 auto downstream = sd->dconn->get_downstream();
731 if (frame->hd.type != NGHTTP2_HEADERS) {
735 auto trailer = frame->headers.cat != NGHTTP2_HCAT_RESPONSE &&
736 !downstream->get_expect_final_response();
738 if (downstream->get_response_headers_sum() + namelen + valuelen >
739 get_config()->header_field_buffer ||
740 downstream->get_response_headers().size() >=
741 get_config()->max_header_fields) {
742 if (LOG_ENABLED(INFO)) {
743 DLOG(INFO, downstream)
744 << "Too large or many header field size="
745 << downstream->get_response_headers_sum() + namelen + valuelen
746 << ", num=" << downstream->get_response_headers().size() + 1;
750 // we don't care trailer part exceeds header size limit; just
755 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
759 // just store header fields for trailer part
760 downstream->add_response_trailer(name, namelen, value, valuelen,
761 flags & NGHTTP2_NV_FLAG_NO_INDEX, -1);
765 auto token = http2::lookup_token(name, namelen);
767 downstream->add_response_header(name, namelen, value, valuelen,
768 flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
774 int on_begin_headers_callback(nghttp2_session *session,
775 const nghttp2_frame *frame, void *user_data) {
776 auto http2session = static_cast<Http2Session *>(user_data);
777 if (frame->hd.type != NGHTTP2_HEADERS ||
778 frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
781 auto sd = static_cast<StreamData *>(
782 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
783 if (!sd || !sd->dconn) {
784 http2session->submit_rst_stream(frame->hd.stream_id,
785 NGHTTP2_INTERNAL_ERROR);
788 auto downstream = sd->dconn->get_downstream();
790 downstream->get_downstream_stream_id() != frame->hd.stream_id) {
791 http2session->submit_rst_stream(frame->hd.stream_id,
792 NGHTTP2_INTERNAL_ERROR);
800 int on_response_headers(Http2Session *http2session, Downstream *downstream,
801 nghttp2_session *session, const nghttp2_frame *frame) {
804 auto upstream = downstream->get_upstream();
806 auto &nva = downstream->get_response_headers();
808 downstream->set_expect_final_response(false);
810 auto status = downstream->get_response_header(http2::HD__STATUS);
811 // libnghttp2 guarantees this exists and can be parsed
812 auto status_code = http2::parse_http_status_code(status->value);
814 downstream->set_response_http_status(status_code);
815 downstream->set_response_major(2);
816 downstream->set_response_minor(0);
818 if (LOG_ENABLED(INFO)) {
819 std::stringstream ss;
820 for (auto &nv : nva) {
821 ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
823 SSLOG(INFO, http2session)
824 << "HTTP response headers. stream_id=" << frame->hd.stream_id << "\n"
828 if (downstream->get_non_final_response()) {
830 if (LOG_ENABLED(INFO)) {
831 SSLOG(INFO, http2session) << "This is non-final response.";
834 downstream->set_expect_final_response(true);
835 rv = upstream->on_downstream_header_complete(downstream);
837 // Now Dowstream's response headers are erased.
840 http2session->submit_rst_stream(frame->hd.stream_id,
841 NGHTTP2_PROTOCOL_ERROR);
842 downstream->set_response_state(Downstream::MSG_RESET);
848 downstream->set_response_state(Downstream::HEADER_COMPLETE);
849 downstream->check_upgrade_fulfilled();
851 if (downstream->get_upgraded()) {
852 downstream->set_response_connection_close(true);
853 // On upgrade sucess, both ends can send data
854 if (upstream->resume_read(SHRPX_NO_BUFFER, downstream, 0) != 0) {
855 // If resume_read fails, just drop connection. Not ideal.
856 delete upstream->get_client_handler();
859 downstream->set_request_state(Downstream::HEADER_COMPLETE);
860 if (LOG_ENABLED(INFO)) {
861 SSLOG(INFO, http2session)
862 << "HTTP upgrade success. stream_id=" << frame->hd.stream_id;
865 auto content_length =
866 downstream->get_response_header(http2::HD_CONTENT_LENGTH);
867 if (content_length) {
868 // libnghttp2 guarantees this can be parsed
869 auto len = util::parse_uint(content_length->value);
870 downstream->set_response_content_length(len);
873 if (downstream->get_response_content_length() == -1 &&
874 downstream->expect_response_body()) {
875 // Here we have response body but Content-Length is not known in
877 if (downstream->get_request_major() <= 0 ||
878 (downstream->get_request_major() == 1 &&
879 downstream->get_request_minor() == 0)) {
880 // We simply close connection for pre-HTTP/1.1 in this case.
881 downstream->set_response_connection_close(true);
883 // Otherwise, use chunked encoding to keep upstream connection
884 // open. In HTTP2, we are supporsed not to receive
885 // transfer-encoding.
886 downstream->add_response_header("transfer-encoding", "chunked",
887 http2::HD_TRANSFER_ENCODING);
888 downstream->set_chunked_response(true);
893 rv = upstream->on_downstream_header_complete(downstream);
895 http2session->submit_rst_stream(frame->hd.stream_id,
896 NGHTTP2_PROTOCOL_ERROR);
897 downstream->set_response_state(Downstream::MSG_RESET);
905 int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
908 auto http2session = static_cast<Http2Session *>(user_data);
910 switch (frame->hd.type) {
912 auto sd = static_cast<StreamData *>(
913 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
914 if (!sd || !sd->dconn) {
917 auto downstream = sd->dconn->get_downstream();
919 downstream->get_downstream_stream_id() != frame->hd.stream_id) {
923 auto upstream = downstream->get_upstream();
924 rv = upstream->on_downstream_body(downstream, nullptr, 0, true);
926 http2session->submit_rst_stream(frame->hd.stream_id,
927 NGHTTP2_INTERNAL_ERROR);
928 downstream->set_response_state(Downstream::MSG_RESET);
930 } else if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
932 downstream->disable_downstream_rtimer();
934 if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
936 downstream->set_response_state(Downstream::MSG_COMPLETE);
938 rv = upstream->on_downstream_body_complete(downstream);
941 downstream->set_response_state(Downstream::MSG_RESET);
946 call_downstream_readcb(http2session, downstream);
949 case NGHTTP2_HEADERS: {
950 auto sd = static_cast<StreamData *>(
951 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
952 if (!sd || !sd->dconn) {
955 auto downstream = sd->dconn->get_downstream();
961 if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
962 rv = on_response_headers(http2session, downstream, session, frame);
967 } else if (frame->headers.cat == NGHTTP2_HCAT_HEADERS) {
968 if (downstream->get_expect_final_response()) {
969 rv = on_response_headers(http2session, downstream, session, frame);
977 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
978 downstream->disable_downstream_rtimer();
980 if (downstream->get_response_state() == Downstream::HEADER_COMPLETE) {
981 downstream->set_response_state(Downstream::MSG_COMPLETE);
983 auto upstream = downstream->get_upstream();
985 rv = upstream->on_downstream_body_complete(downstream);
988 downstream->set_response_state(Downstream::MSG_RESET);
992 downstream->reset_downstream_rtimer();
995 // This may delete downstream
996 call_downstream_readcb(http2session, downstream);
1000 case NGHTTP2_RST_STREAM: {
1001 auto sd = static_cast<StreamData *>(
1002 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1003 if (sd && sd->dconn) {
1004 auto downstream = sd->dconn->get_downstream();
1006 downstream->get_downstream_stream_id() == frame->hd.stream_id) {
1008 downstream->set_response_rst_stream_error_code(
1009 frame->rst_stream.error_code);
1010 call_downstream_readcb(http2session, downstream);
1015 case NGHTTP2_SETTINGS:
1016 if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
1019 http2session->stop_settings_timer();
1022 if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
1023 if (LOG_ENABLED(INFO)) {
1024 LOG(INFO) << "PING ACK received";
1026 http2session->connection_alive();
1029 case NGHTTP2_PUSH_PROMISE:
1030 if (LOG_ENABLED(INFO)) {
1031 SSLOG(INFO, http2session)
1032 << "Received downstream PUSH_PROMISE stream_id="
1033 << frame->hd.stream_id
1034 << ", promised_stream_id=" << frame->push_promise.promised_stream_id;
1036 // We just respond with RST_STREAM.
1037 http2session->submit_rst_stream(frame->push_promise.promised_stream_id,
1038 NGHTTP2_REFUSED_STREAM);
1047 int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
1048 int32_t stream_id, const uint8_t *data,
1049 size_t len, void *user_data) {
1051 auto http2session = static_cast<Http2Session *>(user_data);
1052 auto sd = static_cast<StreamData *>(
1053 nghttp2_session_get_stream_user_data(session, stream_id));
1054 if (!sd || !sd->dconn) {
1055 http2session->submit_rst_stream(stream_id, NGHTTP2_INTERNAL_ERROR);
1057 if (http2session->consume(stream_id, len) != 0) {
1058 return NGHTTP2_ERR_CALLBACK_FAILURE;
1063 auto downstream = sd->dconn->get_downstream();
1064 if (!downstream || downstream->get_downstream_stream_id() != stream_id ||
1065 !downstream->expect_response_body()) {
1067 http2session->submit_rst_stream(stream_id, NGHTTP2_INTERNAL_ERROR);
1069 if (http2session->consume(stream_id, len) != 0) {
1070 return NGHTTP2_ERR_CALLBACK_FAILURE;
1076 // We don't want DATA after non-final response, which is illegal in
1078 if (downstream->get_non_final_response()) {
1079 http2session->submit_rst_stream(stream_id, NGHTTP2_PROTOCOL_ERROR);
1081 if (http2session->consume(stream_id, len) != 0) {
1082 return NGHTTP2_ERR_CALLBACK_FAILURE;
1088 downstream->reset_downstream_rtimer();
1090 downstream->add_response_bodylen(len);
1092 auto upstream = downstream->get_upstream();
1093 rv = upstream->on_downstream_body(downstream, data, len, false);
1095 http2session->submit_rst_stream(stream_id, NGHTTP2_INTERNAL_ERROR);
1097 if (http2session->consume(stream_id, len) != 0) {
1098 return NGHTTP2_ERR_CALLBACK_FAILURE;
1101 downstream->set_response_state(Downstream::MSG_RESET);
1104 downstream->add_response_datalen(len);
1106 call_downstream_readcb(http2session, downstream);
1112 int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
1114 auto http2session = static_cast<Http2Session *>(user_data);
1116 if (frame->hd.type == NGHTTP2_DATA || frame->hd.type == NGHTTP2_HEADERS) {
1117 if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
1121 auto sd = static_cast<StreamData *>(
1122 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1124 if (!sd || !sd->dconn) {
1128 auto downstream = sd->dconn->get_downstream();
1131 downstream->get_downstream_stream_id() != frame->hd.stream_id) {
1135 downstream->reset_downstream_rtimer();
1140 if (frame->hd.type == NGHTTP2_SETTINGS &&
1141 (frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
1142 http2session->start_settings_timer();
1149 int on_frame_not_send_callback(nghttp2_session *session,
1150 const nghttp2_frame *frame, int lib_error_code,
1152 auto http2session = static_cast<Http2Session *>(user_data);
1153 if (LOG_ENABLED(INFO)) {
1154 SSLOG(INFO, http2session) << "Failed to send control frame type="
1155 << static_cast<uint32_t>(frame->hd.type)
1156 << "lib_error_code=" << lib_error_code << ":"
1157 << nghttp2_strerror(lib_error_code);
1159 if (frame->hd.type == NGHTTP2_HEADERS &&
1160 lib_error_code != NGHTTP2_ERR_STREAM_CLOSED &&
1161 lib_error_code != NGHTTP2_ERR_STREAM_CLOSING) {
1162 // To avoid stream hanging around, flag Downstream::MSG_RESET.
1163 auto sd = static_cast<StreamData *>(
1164 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1171 auto downstream = sd->dconn->get_downstream();
1173 downstream->get_downstream_stream_id() != frame->hd.stream_id) {
1176 downstream->set_response_state(Downstream::MSG_RESET);
1177 call_downstream_readcb(http2session, downstream);
1183 nghttp2_session_callbacks *create_http2_downstream_callbacks() {
1185 nghttp2_session_callbacks *callbacks;
1187 rv = nghttp2_session_callbacks_new(&callbacks);
1193 nghttp2_session_callbacks_set_on_stream_close_callback(
1194 callbacks, on_stream_close_callback);
1196 nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
1197 on_frame_recv_callback);
1199 nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
1200 callbacks, on_data_chunk_recv_callback);
1202 nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
1203 on_frame_send_callback);
1205 nghttp2_session_callbacks_set_on_frame_not_send_callback(
1206 callbacks, on_frame_not_send_callback);
1208 nghttp2_session_callbacks_set_on_header_callback(callbacks,
1209 on_header_callback);
1211 nghttp2_session_callbacks_set_on_begin_headers_callback(
1212 callbacks, on_begin_headers_callback);
1214 if (get_config()->padding) {
1215 nghttp2_session_callbacks_set_select_padding_callback(
1216 callbacks, http::select_padding_callback);
1222 int Http2Session::connection_made() {
1225 state_ = Http2Session::CONNECTED;
1228 const unsigned char *next_proto = nullptr;
1229 unsigned int next_proto_len;
1230 SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
1231 for (int i = 0; i < 2; ++i) {
1233 if (LOG_ENABLED(INFO)) {
1234 std::string proto(next_proto, next_proto + next_proto_len);
1235 SSLOG(INFO, this) << "Negotiated next protocol: " << proto;
1237 if (!util::check_h2_is_selected(next_proto, next_proto_len)) {
1242 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
1243 SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
1244 #else // OPENSSL_VERSION_NUMBER < 0x10002000L
1246 #endif // OPENSSL_VERSION_NUMBER < 0x10002000L
1253 rv = nghttp2_session_client_new2(&session_,
1254 get_config()->http2_downstream_callbacks,
1255 this, get_config()->http2_client_option);
1261 flow_control_ = true;
1263 std::array<nghttp2_settings_entry, 3> entry;
1264 entry[0].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
1266 entry[1].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
1267 entry[1].value = get_config()->http2_max_concurrent_streams;
1269 entry[2].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1270 entry[2].value = (1 << get_config()->http2_downstream_window_bits) - 1;
1272 rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(),
1278 if (get_config()->http2_downstream_connection_window_bits > 16) {
1280 (1 << get_config()->http2_downstream_connection_window_bits) - 1 -
1281 NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
1282 rv = nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, 0, delta);
1288 auto must_terminate = !get_config()->downstream_no_tls &&
1289 !ssl::check_http2_requirement(conn_.tls.ssl);
1291 if (must_terminate) {
1292 rv = terminate_session(NGHTTP2_INADEQUATE_SECURITY);
1299 if (must_terminate) {
1303 reset_connection_check_timer(CONNCHK_TIMEOUT);
1305 submit_pending_requests();
1311 int Http2Session::do_read() { return read_(*this); }
1312 int Http2Session::do_write() { return write_(*this); }
1314 int Http2Session::on_read() { return on_read_(*this); }
1315 int Http2Session::on_write() { return on_write_(*this); }
1317 int Http2Session::downstream_read() {
1320 if (rb_.rleft() > 0) {
1321 rv = nghttp2_session_mem_recv(
1322 session_, reinterpret_cast<const uint8_t *>(rb_.pos), rb_.rleft());
1325 SSLOG(ERROR, this) << "nghttp2_session_recv() returned error: "
1326 << nghttp2_strerror(rv);
1330 // nghttp2_session_mem_recv() should consume all input data in
1335 if (nghttp2_session_want_read(session_) == 0 &&
1336 nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) {
1337 if (LOG_ENABLED(INFO)) {
1338 SSLOG(INFO, this) << "No more read/write for this HTTP2 session";
1347 int Http2Session::downstream_write() {
1348 if (data_pending_) {
1349 auto n = std::min(wb_.wleft(), data_pendinglen_);
1350 wb_.write(data_pending_, n);
1351 if (n < data_pendinglen_) {
1353 data_pendinglen_ -= n;
1357 data_pending_ = nullptr;
1358 data_pendinglen_ = 0;
1362 const uint8_t *data;
1363 auto datalen = nghttp2_session_mem_send(session_, &data);
1366 SSLOG(ERROR, this) << "nghttp2_session_mem_send() returned error: "
1367 << nghttp2_strerror(datalen);
1373 auto n = wb_.write(data, datalen);
1374 if (n < static_cast<decltype(n)>(datalen)) {
1375 data_pending_ = data + n;
1376 data_pendinglen_ = datalen - n;
1381 if (nghttp2_session_want_read(session_) == 0 &&
1382 nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) {
1383 if (LOG_ENABLED(INFO)) {
1384 SSLOG(INFO, this) << "No more read/write for this session";
1392 void Http2Session::signal_write() {
1394 case Http2Session::DISCONNECTED:
1395 if (LOG_ENABLED(INFO)) {
1396 LOG(INFO) << "Start connecting to backend server";
1398 if (initiate_connection() != 0) {
1399 if (LOG_ENABLED(INFO)) {
1400 SSLOG(INFO, this) << "Could not initiate backend connection";
1405 case Http2Session::CONNECTED:
1406 conn_.wlimit.startw();
1411 struct ev_loop *Http2Session::get_loop() const {
1415 ev_io *Http2Session::get_wev() { return &conn_.wev; }
1417 int Http2Session::get_state() const { return state_; }
1419 void Http2Session::set_state(int state) { state_ = state; }
1421 int Http2Session::terminate_session(uint32_t error_code) {
1423 rv = nghttp2_session_terminate_session(session_, error_code);
1430 SSL *Http2Session::get_ssl() const { return conn_.tls.ssl; }
1432 int Http2Session::consume(int32_t stream_id, size_t len) {
1439 rv = nghttp2_session_consume(session_, stream_id, len);
1442 SSLOG(WARN, this) << "nghttp2_session_consume() returned error: "
1443 << nghttp2_strerror(rv);
1451 bool Http2Session::can_push_request() const {
1452 return state_ == CONNECTED &&
1453 connection_check_state_ == CONNECTION_CHECK_NONE;
1456 void Http2Session::start_checking_connection() {
1457 if (state_ != CONNECTED ||
1458 connection_check_state_ != CONNECTION_CHECK_REQUIRED) {
1461 connection_check_state_ = CONNECTION_CHECK_STARTED;
1463 SSLOG(INFO, this) << "Start checking connection";
1464 // If connection is down, we may get error when writing data. Issue
1465 // ping frame to see whether connection is alive.
1466 nghttp2_submit_ping(session_, NGHTTP2_FLAG_NONE, NULL);
1468 // set ping timeout and start timer again
1469 reset_connection_check_timer(CONNCHK_PING_TIMEOUT);
1474 void Http2Session::reset_connection_check_timer(ev_tstamp t) {
1475 connchk_timer_.repeat = t;
1476 ev_timer_again(conn_.loop, &connchk_timer_);
1479 void Http2Session::reset_connection_check_timer_if_not_checking() {
1480 if (connection_check_state_ != CONNECTION_CHECK_NONE) {
1484 reset_connection_check_timer(CONNCHK_TIMEOUT);
1487 void Http2Session::connection_alive() {
1488 reset_connection_check_timer(CONNCHK_TIMEOUT);
1490 if (connection_check_state_ == CONNECTION_CHECK_NONE) {
1494 if (LOG_ENABLED(INFO)) {
1495 SSLOG(INFO, this) << "Connection alive";
1498 connection_check_state_ = CONNECTION_CHECK_NONE;
1500 submit_pending_requests();
1503 void Http2Session::submit_pending_requests() {
1504 for (auto dconn = dconns_.head; dconn; dconn = dconn->dlnext) {
1505 auto downstream = dconn->get_downstream();
1507 if (!downstream || !downstream->request_submission_ready()) {
1511 auto upstream = downstream->get_upstream();
1513 if (dconn->push_request_headers() != 0) {
1514 if (LOG_ENABLED(INFO)) {
1515 SSLOG(INFO, this) << "backend request failed";
1518 upstream->on_downstream_abort_request(downstream, 400);
1523 upstream->resume_read(SHRPX_NO_BUFFER, downstream, 0);
1527 void Http2Session::set_connection_check_state(int state) {
1528 connection_check_state_ = state;
1531 int Http2Session::get_connection_check_state() const {
1532 return connection_check_state_;
1535 int Http2Session::noop() { return 0; }
1537 int Http2Session::connected() {
1538 if (!util::check_socket_connected(conn_.fd)) {
1542 connect_blocker_->on_success();
1544 if (LOG_ENABLED(INFO)) {
1545 SSLOG(INFO, this) << "Connection established";
1548 conn_.rlimit.startw();
1550 if (conn_.tls.ssl) {
1551 read_ = &Http2Session::tls_handshake;
1552 write_ = &Http2Session::tls_handshake;
1557 read_ = &Http2Session::read_clear;
1558 write_ = &Http2Session::write_clear;
1560 if (state_ == PROXY_CONNECTING) {
1564 if (connection_made() != 0) {
1565 state_ = CONNECT_FAILING;
1572 int Http2Session::read_clear() {
1573 ev_timer_again(conn_.loop, &conn_.rt);
1576 // we should process buffered data first before we read EOF.
1577 if (rb_.rleft() && on_read() != 0) {
1585 auto nread = conn_.read_clear(rb_.last, rb_.wleft());
1599 int Http2Session::write_clear() {
1600 ev_timer_again(conn_.loop, &conn_.rt);
1603 if (wb_.rleft() > 0) {
1604 auto nwrite = conn_.write_clear(wb_.pos, wb_.rleft());
1619 if (on_write() != 0) {
1622 if (wb_.rleft() == 0) {
1627 conn_.wlimit.stopw();
1628 ev_timer_stop(conn_.loop, &conn_.wt);
1633 int Http2Session::tls_handshake() {
1634 ev_timer_again(conn_.loop, &conn_.rt);
1638 auto rv = conn_.tls_handshake();
1640 if (rv == SHRPX_ERR_INPROGRESS) {
1648 if (LOG_ENABLED(INFO)) {
1649 SSLOG(INFO, this) << "SSL/TLS handshake completed";
1652 if (!get_config()->downstream_no_tls && !get_config()->insecure &&
1653 check_cert() != 0) {
1657 read_ = &Http2Session::read_tls;
1658 write_ = &Http2Session::write_tls;
1660 if (connection_made() != 0) {
1661 state_ = CONNECT_FAILING;
1668 int Http2Session::read_tls() {
1669 ev_timer_again(conn_.loop, &conn_.rt);
1674 // we should process buffered data first before we read EOF.
1675 if (rb_.rleft() && on_read() != 0) {
1683 auto nread = conn_.read_tls(rb_.last, rb_.wleft());
1697 int Http2Session::write_tls() {
1698 ev_timer_again(conn_.loop, &conn_.rt);
1703 if (wb_.rleft() > 0) {
1704 auto nwrite = conn_.write_tls(wb_.pos, wb_.rleft());
1719 if (on_write() != 0) {
1722 if (wb_.rleft() == 0) {
1727 conn_.wlimit.stopw();
1728 ev_timer_stop(conn_.loop, &conn_.wt);
1733 bool Http2Session::should_hard_fail() const {
1735 case PROXY_CONNECTING:
1738 case CONNECT_FAILING:
1745 size_t Http2Session::get_addr_idx() const { return addr_idx_; }
1747 } // namespace shrpx