1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2012 Tatsuhiro Tsujikawa
5 *
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:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
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.
24 */
25 #include "shrpx_http2_session.h"
26
27 #include <netinet/tcp.h>
28 #ifdef HAVE_UNISTD_H
29 # include <unistd.h>
30 #endif // HAVE_UNISTD_H
31
32 #include <vector>
33
34 #include <openssl/err.h>
35
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_tls.h"
43 #include "shrpx_http.h"
44 #include "shrpx_worker.h"
45 #include "shrpx_connect_blocker.h"
46 #include "shrpx_log.h"
47 #include "http2.h"
48 #include "util.h"
49 #include "base64.h"
50 #include "tls.h"
51
52 using namespace nghttp2;
53
54 namespace shrpx {
55
56 namespace {
57 constexpr ev_tstamp CONNCHK_TIMEOUT = 5.;
58 constexpr ev_tstamp CONNCHK_PING_TIMEOUT = 1.;
59 } // namespace
60
61 namespace {
62 constexpr size_t MAX_BUFFER_SIZE = 32_k;
63 } // namespace
64
65 namespace {
connchk_timeout_cb(struct ev_loop * loop,ev_timer * w,int revents)66 void connchk_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
67 auto http2session = static_cast<Http2Session *>(w->data);
68
69 ev_timer_stop(loop, w);
70
71 switch (http2session->get_connection_check_state()) {
72 case ConnectionCheck::STARTED:
73 // ping timeout; disconnect
74 if (LOG_ENABLED(INFO)) {
75 SSLOG(INFO, http2session) << "ping timeout";
76 }
77
78 delete http2session;
79
80 return;
81 default:
82 if (LOG_ENABLED(INFO)) {
83 SSLOG(INFO, http2session) << "connection check required";
84 }
85 http2session->set_connection_check_state(ConnectionCheck::REQUIRED);
86 }
87 }
88 } // namespace
89
90 namespace {
settings_timeout_cb(struct ev_loop * loop,ev_timer * w,int revents)91 void settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
92 auto http2session = static_cast<Http2Session *>(w->data);
93
94 if (LOG_ENABLED(INFO)) {
95 SSLOG(INFO, http2session) << "SETTINGS timeout";
96 }
97
98 downstream_failure(http2session->get_addr(), http2session->get_raddr());
99
100 if (http2session->terminate_session(NGHTTP2_SETTINGS_TIMEOUT) != 0) {
101 delete http2session;
102
103 return;
104 }
105 http2session->signal_write();
106 }
107 } // namespace
108
109 namespace {
timeoutcb(struct ev_loop * loop,ev_timer * w,int revents)110 void timeoutcb(struct ev_loop *loop, ev_timer *w, int revents) {
111 auto conn = static_cast<Connection *>(w->data);
112 auto http2session = static_cast<Http2Session *>(conn->data);
113
114 if (w == &conn->rt && !conn->expired_rt()) {
115 return;
116 }
117
118 if (LOG_ENABLED(INFO)) {
119 SSLOG(INFO, http2session) << "Timeout";
120 }
121
122 http2session->on_timeout();
123
124 delete http2session;
125 }
126 } // namespace
127
128 namespace {
readcb(struct ev_loop * loop,ev_io * w,int revents)129 void readcb(struct ev_loop *loop, ev_io *w, int revents) {
130 int rv;
131 auto conn = static_cast<Connection *>(w->data);
132 auto http2session = static_cast<Http2Session *>(conn->data);
133 rv = http2session->do_read();
134 if (rv != 0) {
135 delete http2session;
136
137 return;
138 }
139 http2session->connection_alive();
140 }
141 } // namespace
142
143 namespace {
writecb(struct ev_loop * loop,ev_io * w,int revents)144 void writecb(struct ev_loop *loop, ev_io *w, int revents) {
145 int rv;
146 auto conn = static_cast<Connection *>(w->data);
147 auto http2session = static_cast<Http2Session *>(conn->data);
148 rv = http2session->do_write();
149 if (rv != 0) {
150 delete http2session;
151
152 return;
153 }
154 http2session->reset_connection_check_timer_if_not_checking();
155 }
156 } // namespace
157
158 namespace {
initiate_connection_cb(struct ev_loop * loop,ev_timer * w,int revents)159 void initiate_connection_cb(struct ev_loop *loop, ev_timer *w, int revents) {
160 auto http2session = static_cast<Http2Session *>(w->data);
161 ev_timer_stop(loop, w);
162 if (http2session->initiate_connection() != 0) {
163 if (LOG_ENABLED(INFO)) {
164 SSLOG(INFO, http2session) << "Could not initiate backend connection";
165 }
166
167 delete http2session;
168
169 return;
170 }
171 }
172 } // namespace
173
174 namespace {
prepare_cb(struct ev_loop * loop,ev_prepare * w,int revents)175 void prepare_cb(struct ev_loop *loop, ev_prepare *w, int revents) {
176 auto http2session = static_cast<Http2Session *>(w->data);
177 http2session->check_retire();
178 }
179 } // namespace
180
Http2Session(struct ev_loop * loop,SSL_CTX * ssl_ctx,Worker * worker,const std::shared_ptr<DownstreamAddrGroup> & group,DownstreamAddr * addr)181 Http2Session::Http2Session(struct ev_loop *loop, SSL_CTX *ssl_ctx,
182 Worker *worker,
183 const std::shared_ptr<DownstreamAddrGroup> &group,
184 DownstreamAddr *addr)
185 : dlnext(nullptr),
186 dlprev(nullptr),
187 conn_(loop, -1, nullptr, worker->get_mcpool(),
188 group->shared_addr->timeout.write, group->shared_addr->timeout.read,
189 {}, {}, writecb, readcb, timeoutcb, this,
190 get_config()->tls.dyn_rec.warmup_threshold,
191 get_config()->tls.dyn_rec.idle_timeout, Proto::HTTP2),
192 wb_(worker->get_mcpool()),
193 worker_(worker),
194 ssl_ctx_(ssl_ctx),
195 group_(group),
196 addr_(addr),
197 session_(nullptr),
198 raddr_(nullptr),
199 state_(Http2SessionState::DISCONNECTED),
200 connection_check_state_(ConnectionCheck::NONE),
201 freelist_zone_(FreelistZone::NONE),
202 settings_recved_(false),
203 allow_connect_proto_(false) {
204 read_ = write_ = &Http2Session::noop;
205
206 on_read_ = &Http2Session::read_noop;
207 on_write_ = &Http2Session::write_noop;
208
209 // We will resuse this many times, so use repeat timeout value. The
210 // timeout value is set later.
211 ev_timer_init(&connchk_timer_, connchk_timeout_cb, 0., 0.);
212
213 connchk_timer_.data = this;
214
215 // SETTINGS ACK timeout is 10 seconds for now. We will resuse this
216 // many times, so use repeat timeout value.
217 ev_timer_init(&settings_timer_, settings_timeout_cb, 0., 0.);
218
219 settings_timer_.data = this;
220
221 ev_timer_init(&initiate_connection_timer_, initiate_connection_cb, 0., 0.);
222 initiate_connection_timer_.data = this;
223
224 ev_prepare_init(&prep_, prepare_cb);
225 prep_.data = this;
226 ev_prepare_start(loop, &prep_);
227 }
228
~Http2Session()229 Http2Session::~Http2Session() {
230 exclude_from_scheduling();
231 disconnect(should_hard_fail());
232 }
233
disconnect(bool hard)234 int Http2Session::disconnect(bool hard) {
235 if (LOG_ENABLED(INFO)) {
236 SSLOG(INFO, this) << "Disconnecting";
237 }
238 nghttp2_session_del(session_);
239 session_ = nullptr;
240
241 wb_.reset();
242
243 if (dns_query_) {
244 auto dns_tracker = worker_->get_dns_tracker();
245 dns_tracker->cancel(dns_query_.get());
246 }
247
248 conn_.rlimit.stopw();
249 conn_.wlimit.stopw();
250
251 ev_prepare_stop(conn_.loop, &prep_);
252
253 ev_timer_stop(conn_.loop, &initiate_connection_timer_);
254 ev_timer_stop(conn_.loop, &settings_timer_);
255 ev_timer_stop(conn_.loop, &connchk_timer_);
256
257 read_ = write_ = &Http2Session::noop;
258
259 on_read_ = &Http2Session::read_noop;
260 on_write_ = &Http2Session::write_noop;
261
262 conn_.disconnect();
263
264 if (proxy_htp_) {
265 proxy_htp_.reset();
266 }
267
268 connection_check_state_ = ConnectionCheck::NONE;
269 state_ = Http2SessionState::DISCONNECTED;
270
271 // When deleting Http2DownstreamConnection, it calls this object's
272 // remove_downstream_connection(). The multiple
273 // Http2DownstreamConnection objects belong to the same
274 // ClientHandler object if upstream is h2. So be careful when you
275 // delete ClientHandler here.
276 //
277 // We allow creating new pending Http2DownstreamConnection with this
278 // object. Upstream::on_downstream_reset() may add
279 // Http2DownstreamConnection to another Http2Session.
280
281 for (auto dc = dconns_.head; dc;) {
282 auto next = dc->dlnext;
283 auto downstream = dc->get_downstream();
284 auto upstream = downstream->get_upstream();
285
286 // Failure is allowed only for HTTP/1 upstream where upstream is
287 // not shared by multiple Downstreams.
288 if (upstream->on_downstream_reset(downstream, hard) != 0) {
289 delete upstream->get_client_handler();
290 }
291
292 // dc was deleted
293 dc = next;
294 }
295
296 auto streams = std::move(streams_);
297 for (auto s = streams.head; s;) {
298 auto next = s->dlnext;
299 delete s;
300 s = next;
301 }
302
303 return 0;
304 }
305
resolve_name()306 int Http2Session::resolve_name() {
307 auto dns_query = std::make_unique<DNSQuery>(
308 addr_->host, [this](DNSResolverStatus status, const Address *result) {
309 int rv;
310
311 if (status == DNSResolverStatus::OK) {
312 *resolved_addr_ = *result;
313 util::set_port(*this->resolved_addr_, this->addr_->port);
314 }
315
316 rv = this->initiate_connection();
317 if (rv != 0) {
318 delete this;
319 }
320 });
321 resolved_addr_ = std::make_unique<Address>();
322 auto dns_tracker = worker_->get_dns_tracker();
323 switch (dns_tracker->resolve(resolved_addr_.get(), dns_query.get())) {
324 case DNSResolverStatus::ERROR:
325 return -1;
326 case DNSResolverStatus::RUNNING:
327 dns_query_ = std::move(dns_query);
328 state_ = Http2SessionState::RESOLVING_NAME;
329 return 0;
330 case DNSResolverStatus::OK:
331 util::set_port(*resolved_addr_, addr_->port);
332 return 0;
333 default:
334 assert(0);
335 abort();
336 }
337 }
338
339 namespace {
340 int htp_hdrs_completecb(llhttp_t *htp);
341 } // namespace
342
343 namespace {
344 constexpr llhttp_settings_t htp_hooks = {
345 nullptr, // llhttp_cb on_message_begin;
346 nullptr, // llhttp_data_cb on_url;
347 nullptr, // llhttp_data_cb on_status;
348 nullptr, // llhttp_data_cb on_header_field;
349 nullptr, // llhttp_data_cb on_header_value;
350 htp_hdrs_completecb, // llhttp_cb on_headers_complete;
351 nullptr, // llhttp_data_cb on_body;
352 nullptr, // llhttp_cb on_message_complete;
353 nullptr, // llhttp_cb on_chunk_header
354 nullptr, // llhttp_cb on_chunk_complete
355 };
356 } // namespace
357
initiate_connection()358 int Http2Session::initiate_connection() {
359 int rv = 0;
360
361 auto worker_blocker = worker_->get_connect_blocker();
362
363 if (state_ == Http2SessionState::DISCONNECTED ||
364 state_ == Http2SessionState::RESOLVING_NAME) {
365 if (worker_blocker->blocked()) {
366 if (LOG_ENABLED(INFO)) {
367 SSLOG(INFO, this)
368 << "Worker wide backend connection was blocked temporarily";
369 }
370 return -1;
371 }
372 }
373
374 auto &downstreamconf = *get_config()->conn.downstream;
375
376 const auto &proxy = get_config()->downstream_http_proxy;
377 if (!proxy.host.empty() && state_ == Http2SessionState::DISCONNECTED) {
378 if (LOG_ENABLED(INFO)) {
379 SSLOG(INFO, this) << "Connecting to the proxy " << proxy.host << ":"
380 << proxy.port;
381 }
382
383 conn_.fd = util::create_nonblock_socket(proxy.addr.su.storage.ss_family);
384
385 if (conn_.fd == -1) {
386 auto error = errno;
387 SSLOG(WARN, this) << "Backend proxy socket() failed; addr="
388 << util::to_numeric_addr(&proxy.addr)
389 << ", errno=" << error;
390
391 worker_blocker->on_failure();
392 return -1;
393 }
394
395 rv = connect(conn_.fd, &proxy.addr.su.sa, proxy.addr.len);
396 if (rv != 0 && errno != EINPROGRESS) {
397 auto error = errno;
398 SSLOG(WARN, this) << "Backend proxy connect() failed; addr="
399 << util::to_numeric_addr(&proxy.addr)
400 << ", errno=" << error;
401
402 worker_blocker->on_failure();
403
404 return -1;
405 }
406
407 raddr_ = &proxy.addr;
408
409 worker_blocker->on_success();
410
411 ev_io_set(&conn_.rev, conn_.fd, EV_READ);
412 ev_io_set(&conn_.wev, conn_.fd, EV_WRITE);
413
414 conn_.wlimit.startw();
415
416 conn_.wt.repeat = downstreamconf.timeout.connect;
417 ev_timer_again(conn_.loop, &conn_.wt);
418
419 write_ = &Http2Session::connected;
420
421 on_read_ = &Http2Session::downstream_read_proxy;
422 on_write_ = &Http2Session::downstream_connect_proxy;
423
424 proxy_htp_ = std::make_unique<llhttp_t>();
425 llhttp_init(proxy_htp_.get(), HTTP_RESPONSE, &htp_hooks);
426 proxy_htp_->data = this;
427
428 state_ = Http2SessionState::PROXY_CONNECTING;
429
430 return 0;
431 }
432
433 if (state_ == Http2SessionState::DISCONNECTED ||
434 state_ == Http2SessionState::PROXY_CONNECTED ||
435 state_ == Http2SessionState::RESOLVING_NAME) {
436 if (LOG_ENABLED(INFO)) {
437 if (state_ != Http2SessionState::RESOLVING_NAME) {
438 SSLOG(INFO, this) << "Connecting to downstream server";
439 }
440 }
441 if (addr_->tls) {
442 assert(ssl_ctx_);
443
444 if (state_ != Http2SessionState::RESOLVING_NAME) {
445 auto ssl = tls::create_ssl(ssl_ctx_);
446 if (!ssl) {
447 return -1;
448 }
449
450 tls::setup_downstream_http2_alpn(ssl);
451
452 conn_.set_ssl(ssl);
453 conn_.tls.client_session_cache = &addr_->tls_session_cache;
454
455 auto sni_name =
456 addr_->sni.empty() ? StringRef{addr_->host} : StringRef{addr_->sni};
457
458 if (!util::numeric_host(sni_name.c_str())) {
459 // TLS extensions: SNI. There is no documentation about the return
460 // code for this function (actually this is macro wrapping SSL_ctrl
461 // at the time of this writing).
462 SSL_set_tlsext_host_name(conn_.tls.ssl, sni_name.c_str());
463 }
464
465 auto tls_session = tls::reuse_tls_session(addr_->tls_session_cache);
466 if (tls_session) {
467 SSL_set_session(conn_.tls.ssl, tls_session);
468 SSL_SESSION_free(tls_session);
469 }
470 }
471
472 if (state_ == Http2SessionState::DISCONNECTED) {
473 if (addr_->dns) {
474 rv = resolve_name();
475 if (rv != 0) {
476 downstream_failure(addr_, nullptr);
477 return -1;
478 }
479 if (state_ == Http2SessionState::RESOLVING_NAME) {
480 return 0;
481 }
482 raddr_ = resolved_addr_.get();
483 } else {
484 raddr_ = &addr_->addr;
485 }
486 }
487
488 if (state_ == Http2SessionState::RESOLVING_NAME) {
489 if (dns_query_->status == DNSResolverStatus::ERROR) {
490 downstream_failure(addr_, nullptr);
491 return -1;
492 }
493 assert(dns_query_->status == DNSResolverStatus::OK);
494 state_ = Http2SessionState::DISCONNECTED;
495 dns_query_.reset();
496 raddr_ = resolved_addr_.get();
497 }
498
499 // If state_ == Http2SessionState::PROXY_CONNECTED, we have
500 // connected to the proxy using conn_.fd and tunnel has been
501 // established.
502 if (state_ == Http2SessionState::DISCONNECTED) {
503 assert(conn_.fd == -1);
504
505 conn_.fd = util::create_nonblock_socket(raddr_->su.storage.ss_family);
506 if (conn_.fd == -1) {
507 auto error = errno;
508 SSLOG(WARN, this)
509 << "socket() failed; addr=" << util::to_numeric_addr(raddr_)
510 << ", errno=" << error;
511
512 worker_blocker->on_failure();
513 return -1;
514 }
515
516 worker_blocker->on_success();
517
518 rv = connect(conn_.fd,
519 // TODO maybe not thread-safe?
520 const_cast<sockaddr *>(&raddr_->su.sa), raddr_->len);
521 if (rv != 0 && errno != EINPROGRESS) {
522 auto error = errno;
523 SSLOG(WARN, this)
524 << "connect() failed; addr=" << util::to_numeric_addr(raddr_)
525 << ", errno=" << error;
526
527 downstream_failure(addr_, raddr_);
528 return -1;
529 }
530
531 ev_io_set(&conn_.rev, conn_.fd, EV_READ);
532 ev_io_set(&conn_.wev, conn_.fd, EV_WRITE);
533 }
534
535 conn_.prepare_client_handshake();
536 } else {
537 if (state_ == Http2SessionState::DISCONNECTED) {
538 // Without TLS and proxy.
539 if (addr_->dns) {
540 rv = resolve_name();
541 if (rv != 0) {
542 downstream_failure(addr_, nullptr);
543 return -1;
544 }
545 if (state_ == Http2SessionState::RESOLVING_NAME) {
546 return 0;
547 }
548 raddr_ = resolved_addr_.get();
549 } else {
550 raddr_ = &addr_->addr;
551 }
552 }
553
554 if (state_ == Http2SessionState::RESOLVING_NAME) {
555 if (dns_query_->status == DNSResolverStatus::ERROR) {
556 downstream_failure(addr_, nullptr);
557 return -1;
558 }
559 assert(dns_query_->status == DNSResolverStatus::OK);
560 state_ = Http2SessionState::DISCONNECTED;
561 dns_query_.reset();
562 raddr_ = resolved_addr_.get();
563 }
564
565 if (state_ == Http2SessionState::DISCONNECTED) {
566 // Without TLS and proxy.
567 assert(conn_.fd == -1);
568
569 conn_.fd = util::create_nonblock_socket(raddr_->su.storage.ss_family);
570
571 if (conn_.fd == -1) {
572 auto error = errno;
573 SSLOG(WARN, this)
574 << "socket() failed; addr=" << util::to_numeric_addr(raddr_)
575 << ", errno=" << error;
576
577 worker_blocker->on_failure();
578 return -1;
579 }
580
581 worker_blocker->on_success();
582
583 rv = connect(conn_.fd, const_cast<sockaddr *>(&raddr_->su.sa),
584 raddr_->len);
585 if (rv != 0 && errno != EINPROGRESS) {
586 auto error = errno;
587 SSLOG(WARN, this)
588 << "connect() failed; addr=" << util::to_numeric_addr(raddr_)
589 << ", errno=" << error;
590
591 downstream_failure(addr_, raddr_);
592 return -1;
593 }
594
595 ev_io_set(&conn_.rev, conn_.fd, EV_READ);
596 ev_io_set(&conn_.wev, conn_.fd, EV_WRITE);
597 }
598 }
599
600 // We have been already connected when no TLS and proxy is used.
601 if (state_ == Http2SessionState::PROXY_CONNECTED) {
602 on_read_ = &Http2Session::read_noop;
603 on_write_ = &Http2Session::write_noop;
604
605 return connected();
606 }
607
608 write_ = &Http2Session::connected;
609
610 state_ = Http2SessionState::CONNECTING;
611 conn_.wlimit.startw();
612
613 conn_.wt.repeat = downstreamconf.timeout.connect;
614 ev_timer_again(conn_.loop, &conn_.wt);
615
616 return 0;
617 }
618
619 // Unreachable
620 assert(0);
621
622 return 0;
623 }
624
625 namespace {
htp_hdrs_completecb(llhttp_t * htp)626 int htp_hdrs_completecb(llhttp_t *htp) {
627 auto http2session = static_cast<Http2Session *>(htp->data);
628
629 // We only read HTTP header part. If tunneling succeeds, response
630 // body is a different protocol (HTTP/2 in this case), we don't read
631 // them here.
632
633 // We just check status code here
634 if (htp->status_code / 100 == 2) {
635 if (LOG_ENABLED(INFO)) {
636 SSLOG(INFO, http2session) << "Tunneling success";
637 }
638 http2session->set_state(Http2SessionState::PROXY_CONNECTED);
639
640 return HPE_PAUSED;
641 }
642
643 SSLOG(WARN, http2session) << "Tunneling failed: " << htp->status_code;
644 http2session->set_state(Http2SessionState::PROXY_FAILED);
645
646 return HPE_PAUSED;
647 }
648 } // namespace
649
downstream_read_proxy(const uint8_t * data,size_t datalen)650 int Http2Session::downstream_read_proxy(const uint8_t *data, size_t datalen) {
651 auto htperr = llhttp_execute(proxy_htp_.get(),
652 reinterpret_cast<const char *>(data), datalen);
653 if (htperr == HPE_PAUSED) {
654 switch (state_) {
655 case Http2SessionState::PROXY_CONNECTED:
656 // Initiate SSL/TLS handshake through established tunnel.
657 if (initiate_connection() != 0) {
658 return -1;
659 }
660 return 0;
661 case Http2SessionState::PROXY_FAILED:
662 return -1;
663 default:
664 break;
665 }
666 // should not be here
667 assert(0);
668 }
669
670 if (htperr != HPE_OK) {
671 return -1;
672 }
673
674 return 0;
675 }
676
downstream_connect_proxy()677 int Http2Session::downstream_connect_proxy() {
678 if (LOG_ENABLED(INFO)) {
679 SSLOG(INFO, this) << "Connected to the proxy";
680 }
681
682 std::string req = "CONNECT ";
683 req.append(addr_->hostport.c_str(), addr_->hostport.size());
684 if (addr_->port == 80 || addr_->port == 443) {
685 req += ':';
686 req += util::utos(addr_->port);
687 }
688 req += " HTTP/1.1\r\nHost: ";
689 req += addr_->host;
690 req += "\r\n";
691 const auto &proxy = get_config()->downstream_http_proxy;
692 if (!proxy.userinfo.empty()) {
693 req += "Proxy-Authorization: Basic ";
694 req += base64::encode(std::begin(proxy.userinfo), std::end(proxy.userinfo));
695 req += "\r\n";
696 }
697 req += "\r\n";
698 if (LOG_ENABLED(INFO)) {
699 SSLOG(INFO, this) << "HTTP proxy request headers\n" << req;
700 }
701 wb_.append(req);
702
703 on_write_ = &Http2Session::write_noop;
704
705 signal_write();
706 return 0;
707 }
708
add_downstream_connection(Http2DownstreamConnection * dconn)709 void Http2Session::add_downstream_connection(Http2DownstreamConnection *dconn) {
710 dconns_.append(dconn);
711 ++addr_->num_dconn;
712 }
713
remove_downstream_connection(Http2DownstreamConnection * dconn)714 void Http2Session::remove_downstream_connection(
715 Http2DownstreamConnection *dconn) {
716 --addr_->num_dconn;
717 dconns_.remove(dconn);
718 dconn->detach_stream_data();
719
720 if (LOG_ENABLED(INFO)) {
721 SSLOG(INFO, this) << "Remove downstream";
722 }
723
724 if (freelist_zone_ == FreelistZone::NONE && !max_concurrency_reached()) {
725 if (LOG_ENABLED(INFO)) {
726 SSLOG(INFO, this) << "Append to http2_extra_freelist, addr=" << addr_
727 << ", freelist.size="
728 << addr_->http2_extra_freelist.size();
729 }
730
731 add_to_extra_freelist();
732 }
733 }
734
remove_stream_data(StreamData * sd)735 void Http2Session::remove_stream_data(StreamData *sd) {
736 streams_.remove(sd);
737 if (sd->dconn) {
738 sd->dconn->detach_stream_data();
739 }
740 delete sd;
741 }
742
submit_request(Http2DownstreamConnection * dconn,const nghttp2_nv * nva,size_t nvlen,const nghttp2_data_provider * data_prd)743 int Http2Session::submit_request(Http2DownstreamConnection *dconn,
744 const nghttp2_nv *nva, size_t nvlen,
745 const nghttp2_data_provider *data_prd) {
746 assert(state_ == Http2SessionState::CONNECTED);
747 auto sd = std::make_unique<StreamData>();
748 sd->dlnext = sd->dlprev = nullptr;
749 // TODO Specify nullptr to pri_spec for now
750 auto stream_id =
751 nghttp2_submit_request(session_, nullptr, nva, nvlen, data_prd, sd.get());
752 if (stream_id < 0) {
753 SSLOG(FATAL, this) << "nghttp2_submit_request() failed: "
754 << nghttp2_strerror(stream_id);
755 return -1;
756 }
757
758 dconn->attach_stream_data(sd.get());
759 dconn->get_downstream()->set_downstream_stream_id(stream_id);
760 streams_.append(sd.release());
761
762 return 0;
763 }
764
submit_rst_stream(int32_t stream_id,uint32_t error_code)765 int Http2Session::submit_rst_stream(int32_t stream_id, uint32_t error_code) {
766 assert(state_ == Http2SessionState::CONNECTED);
767 if (LOG_ENABLED(INFO)) {
768 SSLOG(INFO, this) << "RST_STREAM stream_id=" << stream_id
769 << " with error_code=" << error_code;
770 }
771 int rv = nghttp2_submit_rst_stream(session_, NGHTTP2_FLAG_NONE, stream_id,
772 error_code);
773 if (rv != 0) {
774 SSLOG(FATAL, this) << "nghttp2_submit_rst_stream() failed: "
775 << nghttp2_strerror(rv);
776 return -1;
777 }
778 return 0;
779 }
780
get_session() const781 nghttp2_session *Http2Session::get_session() const { return session_; }
782
resume_data(Http2DownstreamConnection * dconn)783 int Http2Session::resume_data(Http2DownstreamConnection *dconn) {
784 assert(state_ == Http2SessionState::CONNECTED);
785 auto downstream = dconn->get_downstream();
786 int rv = nghttp2_session_resume_data(session_,
787 downstream->get_downstream_stream_id());
788 switch (rv) {
789 case 0:
790 case NGHTTP2_ERR_INVALID_ARGUMENT:
791 return 0;
792 default:
793 SSLOG(FATAL, this) << "nghttp2_resume_session() failed: "
794 << nghttp2_strerror(rv);
795 return -1;
796 }
797 }
798
799 namespace {
call_downstream_readcb(Http2Session * http2session,Downstream * downstream)800 void call_downstream_readcb(Http2Session *http2session,
801 Downstream *downstream) {
802 auto upstream = downstream->get_upstream();
803 if (!upstream) {
804 return;
805 }
806 if (upstream->downstream_read(downstream->get_downstream_connection()) != 0) {
807 delete upstream->get_client_handler();
808 }
809 }
810 } // namespace
811
812 namespace {
on_stream_close_callback(nghttp2_session * session,int32_t stream_id,uint32_t error_code,void * user_data)813 int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
814 uint32_t error_code, void *user_data) {
815 auto http2session = static_cast<Http2Session *>(user_data);
816 if (LOG_ENABLED(INFO)) {
817 SSLOG(INFO, http2session)
818 << "Stream stream_id=" << stream_id
819 << " is being closed with error code " << error_code;
820 }
821 auto sd = static_cast<StreamData *>(
822 nghttp2_session_get_stream_user_data(session, stream_id));
823 if (sd == 0) {
824 // We might get this close callback when pushed streams are
825 // closed.
826 return 0;
827 }
828 auto dconn = sd->dconn;
829 if (dconn) {
830 auto downstream = dconn->get_downstream();
831 auto upstream = downstream->get_upstream();
832
833 if (downstream->get_downstream_stream_id() % 2 == 0 &&
834 downstream->get_request_state() == DownstreamState::INITIAL) {
835 // Downstream is canceled in backend before it is submitted in
836 // frontend session.
837
838 // This will avoid to send RST_STREAM to backend
839 downstream->set_response_state(DownstreamState::MSG_RESET);
840 upstream->cancel_premature_downstream(downstream);
841 } else {
842 if (downstream->get_upgraded() && downstream->get_response_state() ==
843 DownstreamState::HEADER_COMPLETE) {
844 // For tunneled connection, we have to submit RST_STREAM to
845 // upstream *after* whole response body is sent. We just set
846 // MSG_COMPLETE here. Upstream will take care of that.
847 downstream->get_upstream()->on_downstream_body_complete(downstream);
848 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
849 } else if (error_code == NGHTTP2_NO_ERROR) {
850 switch (downstream->get_response_state()) {
851 case DownstreamState::MSG_COMPLETE:
852 case DownstreamState::MSG_BAD_HEADER:
853 break;
854 default:
855 downstream->set_response_state(DownstreamState::MSG_RESET);
856 }
857 } else if (downstream->get_response_state() !=
858 DownstreamState::MSG_BAD_HEADER) {
859 downstream->set_response_state(DownstreamState::MSG_RESET);
860 }
861 if (downstream->get_response_state() == DownstreamState::MSG_RESET &&
862 downstream->get_response_rst_stream_error_code() ==
863 NGHTTP2_NO_ERROR) {
864 downstream->set_response_rst_stream_error_code(error_code);
865 }
866 call_downstream_readcb(http2session, downstream);
867 }
868 // dconn may be deleted
869 }
870 // The life time of StreamData ends here
871 http2session->remove_stream_data(sd);
872 return 0;
873 }
874 } // namespace
875
start_settings_timer()876 void Http2Session::start_settings_timer() {
877 auto &downstreamconf = get_config()->http2.downstream;
878
879 ev_timer_set(&settings_timer_, downstreamconf.timeout.settings, 0.);
880 ev_timer_start(conn_.loop, &settings_timer_);
881 }
882
stop_settings_timer()883 void Http2Session::stop_settings_timer() {
884 ev_timer_stop(conn_.loop, &settings_timer_);
885 }
886
887 namespace {
on_header_callback2(nghttp2_session * session,const nghttp2_frame * frame,nghttp2_rcbuf * name,nghttp2_rcbuf * value,uint8_t flags,void * user_data)888 int on_header_callback2(nghttp2_session *session, const nghttp2_frame *frame,
889 nghttp2_rcbuf *name, nghttp2_rcbuf *value,
890 uint8_t flags, void *user_data) {
891 auto http2session = static_cast<Http2Session *>(user_data);
892 auto sd = static_cast<StreamData *>(
893 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
894 if (!sd || !sd->dconn) {
895 return 0;
896 }
897 auto downstream = sd->dconn->get_downstream();
898
899 auto namebuf = nghttp2_rcbuf_get_buf(name);
900 auto valuebuf = nghttp2_rcbuf_get_buf(value);
901
902 auto &resp = downstream->response();
903 auto &httpconf = get_config()->http;
904
905 switch (frame->hd.type) {
906 case NGHTTP2_HEADERS: {
907 auto trailer = frame->headers.cat == NGHTTP2_HCAT_HEADERS &&
908 !downstream->get_expect_final_response();
909
910 if (resp.fs.buffer_size() + namebuf.len + valuebuf.len >
911 httpconf.response_header_field_buffer ||
912 resp.fs.num_fields() >= httpconf.max_response_header_fields) {
913 if (LOG_ENABLED(INFO)) {
914 DLOG(INFO, downstream)
915 << "Too large or many header field size="
916 << resp.fs.buffer_size() + namebuf.len + valuebuf.len
917 << ", num=" << resp.fs.num_fields() + 1;
918 }
919
920 if (trailer) {
921 // We don't care trailer part exceeds header size limit; just
922 // discard it.
923 return 0;
924 }
925
926 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
927 }
928
929 auto token = http2::lookup_token(namebuf.base, namebuf.len);
930 auto no_index = flags & NGHTTP2_NV_FLAG_NO_INDEX;
931
932 downstream->add_rcbuf(name);
933 downstream->add_rcbuf(value);
934
935 if (trailer) {
936 // just store header fields for trailer part
937 resp.fs.add_trailer_token(StringRef{namebuf.base, namebuf.len},
938 StringRef{valuebuf.base, valuebuf.len},
939 no_index, token);
940 return 0;
941 }
942
943 resp.fs.add_header_token(StringRef{namebuf.base, namebuf.len},
944 StringRef{valuebuf.base, valuebuf.len}, no_index,
945 token);
946 return 0;
947 }
948 case NGHTTP2_PUSH_PROMISE: {
949 auto promised_stream_id = frame->push_promise.promised_stream_id;
950 auto promised_sd = static_cast<StreamData *>(
951 nghttp2_session_get_stream_user_data(session, promised_stream_id));
952 if (!promised_sd || !promised_sd->dconn) {
953 http2session->submit_rst_stream(promised_stream_id, NGHTTP2_CANCEL);
954 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
955 }
956
957 auto promised_downstream = promised_sd->dconn->get_downstream();
958
959 auto namebuf = nghttp2_rcbuf_get_buf(name);
960 auto valuebuf = nghttp2_rcbuf_get_buf(value);
961
962 assert(promised_downstream);
963
964 auto &promised_req = promised_downstream->request();
965
966 // We use request header limit for PUSH_PROMISE
967 if (promised_req.fs.buffer_size() + namebuf.len + valuebuf.len >
968 httpconf.request_header_field_buffer ||
969 promised_req.fs.num_fields() >= httpconf.max_request_header_fields) {
970 if (LOG_ENABLED(INFO)) {
971 DLOG(INFO, downstream)
972 << "Too large or many header field size="
973 << promised_req.fs.buffer_size() + namebuf.len + valuebuf.len
974 << ", num=" << promised_req.fs.num_fields() + 1;
975 }
976
977 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
978 }
979
980 promised_downstream->add_rcbuf(name);
981 promised_downstream->add_rcbuf(value);
982
983 auto token = http2::lookup_token(namebuf.base, namebuf.len);
984 promised_req.fs.add_header_token(StringRef{namebuf.base, namebuf.len},
985 StringRef{valuebuf.base, valuebuf.len},
986 flags & NGHTTP2_NV_FLAG_NO_INDEX, token);
987
988 return 0;
989 }
990 }
991
992 return 0;
993 }
994 } // namespace
995
996 namespace {
on_invalid_header_callback2(nghttp2_session * session,const nghttp2_frame * frame,nghttp2_rcbuf * name,nghttp2_rcbuf * value,uint8_t flags,void * user_data)997 int on_invalid_header_callback2(nghttp2_session *session,
998 const nghttp2_frame *frame, nghttp2_rcbuf *name,
999 nghttp2_rcbuf *value, uint8_t flags,
1000 void *user_data) {
1001 auto http2session = static_cast<Http2Session *>(user_data);
1002 auto sd = static_cast<StreamData *>(
1003 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1004 if (!sd || !sd->dconn) {
1005 return 0;
1006 }
1007
1008 int32_t stream_id;
1009
1010 if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
1011 stream_id = frame->push_promise.promised_stream_id;
1012 } else {
1013 stream_id = frame->hd.stream_id;
1014 }
1015
1016 if (LOG_ENABLED(INFO)) {
1017 auto namebuf = nghttp2_rcbuf_get_buf(name);
1018 auto valuebuf = nghttp2_rcbuf_get_buf(value);
1019
1020 SSLOG(INFO, http2session)
1021 << "Invalid header field for stream_id=" << stream_id
1022 << " in frame type=" << static_cast<uint32_t>(frame->hd.type)
1023 << ": name=[" << StringRef{namebuf.base, namebuf.len} << "], value=["
1024 << StringRef{valuebuf.base, valuebuf.len} << "]";
1025 }
1026
1027 http2session->submit_rst_stream(stream_id, NGHTTP2_PROTOCOL_ERROR);
1028
1029 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1030 }
1031 } // namespace
1032
1033 namespace {
on_begin_headers_callback(nghttp2_session * session,const nghttp2_frame * frame,void * user_data)1034 int on_begin_headers_callback(nghttp2_session *session,
1035 const nghttp2_frame *frame, void *user_data) {
1036 auto http2session = static_cast<Http2Session *>(user_data);
1037
1038 switch (frame->hd.type) {
1039 case NGHTTP2_HEADERS: {
1040 if (frame->headers.cat != NGHTTP2_HCAT_RESPONSE &&
1041 frame->headers.cat != NGHTTP2_HCAT_PUSH_RESPONSE) {
1042 return 0;
1043 }
1044 auto sd = static_cast<StreamData *>(
1045 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1046 if (!sd || !sd->dconn) {
1047 http2session->submit_rst_stream(frame->hd.stream_id,
1048 NGHTTP2_INTERNAL_ERROR);
1049 return 0;
1050 }
1051 return 0;
1052 }
1053 case NGHTTP2_PUSH_PROMISE: {
1054 auto promised_stream_id = frame->push_promise.promised_stream_id;
1055 auto sd = static_cast<StreamData *>(
1056 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1057 if (!sd || !sd->dconn) {
1058 http2session->submit_rst_stream(promised_stream_id, NGHTTP2_CANCEL);
1059 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1060 }
1061
1062 auto downstream = sd->dconn->get_downstream();
1063
1064 assert(downstream);
1065 assert(downstream->get_downstream_stream_id() == frame->hd.stream_id);
1066
1067 if (http2session->handle_downstream_push_promise(downstream,
1068 promised_stream_id) != 0) {
1069 http2session->submit_rst_stream(promised_stream_id, NGHTTP2_CANCEL);
1070 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1071 }
1072
1073 return 0;
1074 }
1075 }
1076
1077 return 0;
1078 }
1079 } // namespace
1080
1081 namespace {
on_response_headers(Http2Session * http2session,Downstream * downstream,nghttp2_session * session,const nghttp2_frame * frame)1082 int on_response_headers(Http2Session *http2session, Downstream *downstream,
1083 nghttp2_session *session, const nghttp2_frame *frame) {
1084 int rv;
1085
1086 auto upstream = downstream->get_upstream();
1087 auto handler = upstream->get_client_handler();
1088 const auto &req = downstream->request();
1089 auto &resp = downstream->response();
1090
1091 auto &nva = resp.fs.headers();
1092
1093 auto config = get_config();
1094 auto &loggingconf = config->logging;
1095
1096 downstream->set_expect_final_response(false);
1097
1098 auto status = resp.fs.header(http2::HD__STATUS);
1099 // libnghttp2 guarantees this exists and can be parsed
1100 assert(status);
1101 auto status_code = http2::parse_http_status_code(status->value);
1102
1103 resp.http_status = status_code;
1104 resp.http_major = 2;
1105 resp.http_minor = 0;
1106
1107 downstream->set_downstream_addr_group(
1108 http2session->get_downstream_addr_group());
1109 downstream->set_addr(http2session->get_addr());
1110
1111 if (LOG_ENABLED(INFO)) {
1112 std::stringstream ss;
1113 for (auto &nv : nva) {
1114 ss << TTY_HTTP_HD << nv.name << TTY_RST << ": " << nv.value << "\n";
1115 }
1116 SSLOG(INFO, http2session)
1117 << "HTTP response headers. stream_id=" << frame->hd.stream_id << "\n"
1118 << ss.str();
1119 }
1120
1121 if (downstream->get_non_final_response()) {
1122
1123 if (LOG_ENABLED(INFO)) {
1124 SSLOG(INFO, http2session) << "This is non-final response.";
1125 }
1126
1127 downstream->set_expect_final_response(true);
1128 rv = upstream->on_downstream_header_complete(downstream);
1129
1130 // Now Dowstream's response headers are erased.
1131
1132 if (rv != 0) {
1133 http2session->submit_rst_stream(frame->hd.stream_id,
1134 NGHTTP2_PROTOCOL_ERROR);
1135 downstream->set_response_state(DownstreamState::MSG_RESET);
1136 }
1137
1138 return 0;
1139 }
1140
1141 downstream->set_response_state(DownstreamState::HEADER_COMPLETE);
1142 downstream->check_upgrade_fulfilled_http2();
1143
1144 if (downstream->get_upgraded()) {
1145 resp.connection_close = true;
1146 // On upgrade success, both ends can send data
1147 if (upstream->resume_read(SHRPX_NO_BUFFER, downstream, 0) != 0) {
1148 // If resume_read fails, just drop connection. Not ideal.
1149 delete handler;
1150 return -1;
1151 }
1152 downstream->set_request_state(DownstreamState::HEADER_COMPLETE);
1153 if (LOG_ENABLED(INFO)) {
1154 SSLOG(INFO, http2session)
1155 << "HTTP upgrade success. stream_id=" << frame->hd.stream_id;
1156 }
1157 } else {
1158 auto content_length = resp.fs.header(http2::HD_CONTENT_LENGTH);
1159 if (content_length) {
1160 // libnghttp2 guarantees this can be parsed
1161 resp.fs.content_length = util::parse_uint(content_length->value);
1162 }
1163
1164 if (resp.fs.content_length == -1 && downstream->expect_response_body()) {
1165 // Here we have response body but Content-Length is not known in
1166 // advance.
1167 if (req.http_major <= 0 || (req.http_major == 1 && req.http_minor == 0)) {
1168 // We simply close connection for pre-HTTP/1.1 in this case.
1169 resp.connection_close = true;
1170 } else {
1171 // Otherwise, use chunked encoding to keep upstream connection
1172 // open. In HTTP2, we are supposed not to receive
1173 // transfer-encoding.
1174 resp.fs.add_header_token(StringRef::from_lit("transfer-encoding"),
1175 StringRef::from_lit("chunked"), false,
1176 http2::HD_TRANSFER_ENCODING);
1177 downstream->set_chunked_response(true);
1178 }
1179 }
1180 }
1181
1182 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1183 resp.headers_only = true;
1184 }
1185
1186 if (loggingconf.access.write_early && downstream->accesslog_ready()) {
1187 handler->write_accesslog(downstream);
1188 downstream->set_accesslog_written(true);
1189 }
1190
1191 rv = upstream->on_downstream_header_complete(downstream);
1192 if (rv != 0) {
1193 // Handling early return (in other words, response was hijacked by
1194 // mruby scripting).
1195 if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1196 http2session->submit_rst_stream(frame->hd.stream_id, NGHTTP2_CANCEL);
1197 } else {
1198 http2session->submit_rst_stream(frame->hd.stream_id,
1199 NGHTTP2_INTERNAL_ERROR);
1200 downstream->set_response_state(DownstreamState::MSG_RESET);
1201 }
1202 }
1203
1204 return 0;
1205 }
1206 } // namespace
1207
1208 namespace {
on_frame_recv_callback(nghttp2_session * session,const nghttp2_frame * frame,void * user_data)1209 int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
1210 void *user_data) {
1211 int rv;
1212 auto http2session = static_cast<Http2Session *>(user_data);
1213
1214 switch (frame->hd.type) {
1215 case NGHTTP2_DATA: {
1216 auto sd = static_cast<StreamData *>(
1217 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1218 if (!sd || !sd->dconn) {
1219 return 0;
1220 }
1221 auto downstream = sd->dconn->get_downstream();
1222 auto upstream = downstream->get_upstream();
1223 rv = upstream->on_downstream_body(downstream, nullptr, 0, true);
1224 if (rv != 0) {
1225 http2session->submit_rst_stream(frame->hd.stream_id,
1226 NGHTTP2_INTERNAL_ERROR);
1227 downstream->set_response_state(DownstreamState::MSG_RESET);
1228
1229 } else if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1230
1231 downstream->disable_downstream_rtimer();
1232
1233 if (downstream->get_response_state() ==
1234 DownstreamState::HEADER_COMPLETE) {
1235
1236 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1237
1238 rv = upstream->on_downstream_body_complete(downstream);
1239
1240 if (rv != 0) {
1241 downstream->set_response_state(DownstreamState::MSG_RESET);
1242 }
1243 }
1244 }
1245
1246 call_downstream_readcb(http2session, downstream);
1247 return 0;
1248 }
1249 case NGHTTP2_HEADERS: {
1250 auto sd = static_cast<StreamData *>(
1251 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1252 if (!sd || !sd->dconn) {
1253 return 0;
1254 }
1255 auto downstream = sd->dconn->get_downstream();
1256
1257 if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE ||
1258 frame->headers.cat == NGHTTP2_HCAT_PUSH_RESPONSE) {
1259 rv = on_response_headers(http2session, downstream, session, frame);
1260
1261 if (rv != 0) {
1262 return 0;
1263 }
1264 } else if (frame->headers.cat == NGHTTP2_HCAT_HEADERS) {
1265 if (downstream->get_expect_final_response()) {
1266 rv = on_response_headers(http2session, downstream, session, frame);
1267
1268 if (rv != 0) {
1269 return 0;
1270 }
1271 }
1272 }
1273
1274 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1275 downstream->disable_downstream_rtimer();
1276
1277 if (downstream->get_response_state() ==
1278 DownstreamState::HEADER_COMPLETE) {
1279 downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1280
1281 auto upstream = downstream->get_upstream();
1282
1283 rv = upstream->on_downstream_body_complete(downstream);
1284
1285 if (rv != 0) {
1286 downstream->set_response_state(DownstreamState::MSG_RESET);
1287 }
1288 }
1289 } else {
1290 downstream->reset_downstream_rtimer();
1291 }
1292
1293 // This may delete downstream
1294 call_downstream_readcb(http2session, downstream);
1295
1296 return 0;
1297 }
1298 case NGHTTP2_RST_STREAM: {
1299 auto sd = static_cast<StreamData *>(
1300 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1301 if (sd && sd->dconn) {
1302 auto downstream = sd->dconn->get_downstream();
1303 downstream->set_response_rst_stream_error_code(
1304 frame->rst_stream.error_code);
1305 call_downstream_readcb(http2session, downstream);
1306 }
1307 return 0;
1308 }
1309 case NGHTTP2_SETTINGS: {
1310 if ((frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
1311 http2session->on_settings_received(frame);
1312 return 0;
1313 }
1314
1315 http2session->stop_settings_timer();
1316
1317 auto addr = http2session->get_addr();
1318 auto &connect_blocker = addr->connect_blocker;
1319
1320 connect_blocker->on_success();
1321
1322 return 0;
1323 }
1324 case NGHTTP2_PING:
1325 if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
1326 if (LOG_ENABLED(INFO)) {
1327 LOG(INFO) << "PING ACK received";
1328 }
1329 http2session->connection_alive();
1330 }
1331 return 0;
1332 case NGHTTP2_PUSH_PROMISE: {
1333 auto promised_stream_id = frame->push_promise.promised_stream_id;
1334
1335 if (LOG_ENABLED(INFO)) {
1336 SSLOG(INFO, http2session)
1337 << "Received downstream PUSH_PROMISE stream_id="
1338 << frame->hd.stream_id
1339 << ", promised_stream_id=" << promised_stream_id;
1340 }
1341
1342 auto sd = static_cast<StreamData *>(
1343 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1344 if (!sd || !sd->dconn) {
1345 http2session->submit_rst_stream(promised_stream_id, NGHTTP2_CANCEL);
1346 return 0;
1347 }
1348
1349 auto downstream = sd->dconn->get_downstream();
1350
1351 assert(downstream);
1352 assert(downstream->get_downstream_stream_id() == frame->hd.stream_id);
1353
1354 auto promised_sd = static_cast<StreamData *>(
1355 nghttp2_session_get_stream_user_data(session, promised_stream_id));
1356 if (!promised_sd || !promised_sd->dconn) {
1357 http2session->submit_rst_stream(promised_stream_id, NGHTTP2_CANCEL);
1358 return 0;
1359 }
1360
1361 auto promised_downstream = promised_sd->dconn->get_downstream();
1362
1363 assert(promised_downstream);
1364
1365 if (http2session->handle_downstream_push_promise_complete(
1366 downstream, promised_downstream) != 0) {
1367 http2session->submit_rst_stream(promised_stream_id, NGHTTP2_CANCEL);
1368 return 0;
1369 }
1370
1371 return 0;
1372 }
1373 case NGHTTP2_GOAWAY:
1374 if (LOG_ENABLED(INFO)) {
1375 auto debug_data = util::ascii_dump(frame->goaway.opaque_data,
1376 frame->goaway.opaque_data_len);
1377
1378 SSLOG(INFO, http2session)
1379 << "GOAWAY received: last-stream-id=" << frame->goaway.last_stream_id
1380 << ", error_code=" << frame->goaway.error_code
1381 << ", debug_data=" << debug_data;
1382 }
1383 return 0;
1384 default:
1385 return 0;
1386 }
1387 }
1388 } // namespace
1389
1390 namespace {
on_data_chunk_recv_callback(nghttp2_session * session,uint8_t flags,int32_t stream_id,const uint8_t * data,size_t len,void * user_data)1391 int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
1392 int32_t stream_id, const uint8_t *data,
1393 size_t len, void *user_data) {
1394 int rv;
1395 auto http2session = static_cast<Http2Session *>(user_data);
1396 auto sd = static_cast<StreamData *>(
1397 nghttp2_session_get_stream_user_data(session, stream_id));
1398 if (!sd || !sd->dconn) {
1399 http2session->submit_rst_stream(stream_id, NGHTTP2_INTERNAL_ERROR);
1400
1401 if (http2session->consume(stream_id, len) != 0) {
1402 return NGHTTP2_ERR_CALLBACK_FAILURE;
1403 }
1404
1405 return 0;
1406 }
1407 auto downstream = sd->dconn->get_downstream();
1408 if (!downstream->expect_response_body()) {
1409 http2session->submit_rst_stream(stream_id, NGHTTP2_INTERNAL_ERROR);
1410
1411 if (http2session->consume(stream_id, len) != 0) {
1412 return NGHTTP2_ERR_CALLBACK_FAILURE;
1413 }
1414
1415 return 0;
1416 }
1417
1418 // We don't want DATA after non-final response, which is illegal in
1419 // HTTP.
1420 if (downstream->get_non_final_response()) {
1421 http2session->submit_rst_stream(stream_id, NGHTTP2_PROTOCOL_ERROR);
1422
1423 if (http2session->consume(stream_id, len) != 0) {
1424 return NGHTTP2_ERR_CALLBACK_FAILURE;
1425 }
1426
1427 return 0;
1428 }
1429
1430 downstream->reset_downstream_rtimer();
1431
1432 auto &resp = downstream->response();
1433
1434 resp.recv_body_length += len;
1435 resp.unconsumed_body_length += len;
1436
1437 auto upstream = downstream->get_upstream();
1438 rv = upstream->on_downstream_body(downstream, data, len, false);
1439 if (rv != 0) {
1440 http2session->submit_rst_stream(stream_id, NGHTTP2_INTERNAL_ERROR);
1441
1442 if (http2session->consume(stream_id, len) != 0) {
1443 return NGHTTP2_ERR_CALLBACK_FAILURE;
1444 }
1445
1446 downstream->set_response_state(DownstreamState::MSG_RESET);
1447 }
1448
1449 call_downstream_readcb(http2session, downstream);
1450 return 0;
1451 }
1452 } // namespace
1453
1454 namespace {
on_frame_send_callback(nghttp2_session * session,const nghttp2_frame * frame,void * user_data)1455 int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
1456 void *user_data) {
1457 auto http2session = static_cast<Http2Session *>(user_data);
1458
1459 if (frame->hd.type == NGHTTP2_DATA || frame->hd.type == NGHTTP2_HEADERS) {
1460 auto sd = static_cast<StreamData *>(
1461 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1462
1463 if (!sd || !sd->dconn) {
1464 return 0;
1465 }
1466
1467 auto downstream = sd->dconn->get_downstream();
1468
1469 if (frame->hd.type == NGHTTP2_HEADERS &&
1470 frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
1471 downstream->set_request_header_sent(true);
1472 auto src = downstream->get_blocked_request_buf();
1473 if (src->rleft()) {
1474 auto dest = downstream->get_request_buf();
1475 src->remove(*dest);
1476 if (http2session->resume_data(sd->dconn) != 0) {
1477 return NGHTTP2_ERR_CALLBACK_FAILURE;
1478 }
1479 downstream->ensure_downstream_wtimer();
1480 }
1481 }
1482
1483 if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
1484 return 0;
1485 }
1486
1487 downstream->reset_downstream_rtimer();
1488
1489 return 0;
1490 }
1491
1492 if (frame->hd.type == NGHTTP2_SETTINGS &&
1493 (frame->hd.flags & NGHTTP2_FLAG_ACK) == 0) {
1494 http2session->start_settings_timer();
1495 }
1496 return 0;
1497 }
1498 } // namespace
1499
1500 namespace {
on_frame_not_send_callback(nghttp2_session * session,const nghttp2_frame * frame,int lib_error_code,void * user_data)1501 int on_frame_not_send_callback(nghttp2_session *session,
1502 const nghttp2_frame *frame, int lib_error_code,
1503 void *user_data) {
1504 auto http2session = static_cast<Http2Session *>(user_data);
1505 if (LOG_ENABLED(INFO)) {
1506 SSLOG(INFO, http2session) << "Failed to send control frame type="
1507 << static_cast<uint32_t>(frame->hd.type)
1508 << ", lib_error_code=" << lib_error_code << ": "
1509 << nghttp2_strerror(lib_error_code);
1510 }
1511 if (frame->hd.type != NGHTTP2_HEADERS ||
1512 lib_error_code == NGHTTP2_ERR_STREAM_CLOSED ||
1513 lib_error_code == NGHTTP2_ERR_STREAM_CLOSING) {
1514 return 0;
1515 }
1516
1517 auto sd = static_cast<StreamData *>(
1518 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1519 if (!sd) {
1520 return 0;
1521 }
1522 if (!sd->dconn) {
1523 return 0;
1524 }
1525 auto downstream = sd->dconn->get_downstream();
1526
1527 if (lib_error_code == NGHTTP2_ERR_START_STREAM_NOT_ALLOWED) {
1528 // Migrate to another downstream connection.
1529 auto upstream = downstream->get_upstream();
1530
1531 if (upstream->on_downstream_reset(downstream, false)) {
1532 // This should be done for h1 upstream only. Deleting
1533 // ClientHandler for h2 upstream may lead to crash.
1534 delete upstream->get_client_handler();
1535 }
1536
1537 return 0;
1538 }
1539
1540 // To avoid stream hanging around, flag DownstreamState::MSG_RESET.
1541 downstream->set_response_state(DownstreamState::MSG_RESET);
1542 call_downstream_readcb(http2session, downstream);
1543
1544 return 0;
1545 }
1546 } // namespace
1547
1548 namespace {
1549 constexpr auto PADDING = std::array<uint8_t, 256>{};
1550 } // namespace
1551
1552 namespace {
send_data_callback(nghttp2_session * session,nghttp2_frame * frame,const uint8_t * framehd,size_t length,nghttp2_data_source * source,void * user_data)1553 int send_data_callback(nghttp2_session *session, nghttp2_frame *frame,
1554 const uint8_t *framehd, size_t length,
1555 nghttp2_data_source *source, void *user_data) {
1556 auto http2session = static_cast<Http2Session *>(user_data);
1557 auto sd = static_cast<StreamData *>(
1558 nghttp2_session_get_stream_user_data(session, frame->hd.stream_id));
1559
1560 if (sd == nullptr) {
1561 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1562 }
1563
1564 auto dconn = sd->dconn;
1565 auto downstream = dconn->get_downstream();
1566 auto input = downstream->get_request_buf();
1567 auto wb = http2session->get_request_buf();
1568
1569 size_t padlen = 0;
1570
1571 wb->append(framehd, 9);
1572 if (frame->data.padlen > 0) {
1573 padlen = frame->data.padlen - 1;
1574 wb->append(static_cast<uint8_t>(padlen));
1575 }
1576
1577 input->remove(*wb, length);
1578
1579 wb->append(PADDING.data(), padlen);
1580
1581 if (input->rleft() == 0) {
1582 downstream->disable_downstream_wtimer();
1583 } else {
1584 downstream->reset_downstream_wtimer();
1585 }
1586
1587 if (length > 0) {
1588 // This is important because it will handle flow control
1589 // stuff.
1590 if (downstream->get_upstream()->resume_read(SHRPX_NO_BUFFER, downstream,
1591 length) != 0) {
1592 // In this case, downstream may be deleted.
1593 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1594 }
1595
1596 // Here sd->dconn could be nullptr, because
1597 // Upstream::resume_read() may delete downstream which will delete
1598 // dconn. Is this still really true?
1599 }
1600
1601 return 0;
1602 }
1603 } // namespace
1604
create_http2_downstream_callbacks()1605 nghttp2_session_callbacks *create_http2_downstream_callbacks() {
1606 int rv;
1607 nghttp2_session_callbacks *callbacks;
1608
1609 rv = nghttp2_session_callbacks_new(&callbacks);
1610
1611 if (rv != 0) {
1612 return nullptr;
1613 }
1614
1615 nghttp2_session_callbacks_set_on_stream_close_callback(
1616 callbacks, on_stream_close_callback);
1617
1618 nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
1619 on_frame_recv_callback);
1620
1621 nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
1622 callbacks, on_data_chunk_recv_callback);
1623
1624 nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
1625 on_frame_send_callback);
1626
1627 nghttp2_session_callbacks_set_on_frame_not_send_callback(
1628 callbacks, on_frame_not_send_callback);
1629
1630 nghttp2_session_callbacks_set_on_header_callback2(callbacks,
1631 on_header_callback2);
1632
1633 nghttp2_session_callbacks_set_on_invalid_header_callback2(
1634 callbacks, on_invalid_header_callback2);
1635
1636 nghttp2_session_callbacks_set_on_begin_headers_callback(
1637 callbacks, on_begin_headers_callback);
1638
1639 nghttp2_session_callbacks_set_send_data_callback(callbacks,
1640 send_data_callback);
1641
1642 if (get_config()->padding) {
1643 nghttp2_session_callbacks_set_select_padding_callback(
1644 callbacks, http::select_padding_callback);
1645 }
1646
1647 return callbacks;
1648 }
1649
connection_made()1650 int Http2Session::connection_made() {
1651 int rv;
1652
1653 state_ = Http2SessionState::CONNECTED;
1654
1655 on_write_ = &Http2Session::downstream_write;
1656 on_read_ = &Http2Session::downstream_read;
1657
1658 if (addr_->tls) {
1659 const unsigned char *next_proto = nullptr;
1660 unsigned int next_proto_len = 0;
1661
1662 #ifndef OPENSSL_NO_NEXTPROTONEG
1663 SSL_get0_next_proto_negotiated(conn_.tls.ssl, &next_proto, &next_proto_len);
1664 #endif // !OPENSSL_NO_NEXTPROTONEG
1665 #if OPENSSL_VERSION_NUMBER >= 0x10002000L
1666 if (!next_proto) {
1667 SSL_get0_alpn_selected(conn_.tls.ssl, &next_proto, &next_proto_len);
1668 }
1669 #endif // OPENSSL_VERSION_NUMBER >= 0x10002000L
1670
1671 if (!next_proto) {
1672 downstream_failure(addr_, raddr_);
1673 return -1;
1674 }
1675
1676 auto proto = StringRef{next_proto, next_proto_len};
1677 if (LOG_ENABLED(INFO)) {
1678 SSLOG(INFO, this) << "Negotiated next protocol: " << proto;
1679 }
1680 if (!util::check_h2_is_selected(proto)) {
1681 downstream_failure(addr_, raddr_);
1682 return -1;
1683 }
1684 }
1685
1686 auto config = get_config();
1687 auto &http2conf = config->http2;
1688
1689 rv = nghttp2_session_client_new2(&session_, http2conf.downstream.callbacks,
1690 this, http2conf.downstream.option);
1691
1692 if (rv != 0) {
1693 return -1;
1694 }
1695
1696 std::array<nghttp2_settings_entry, 4> entry;
1697 size_t nentry = 2;
1698 entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
1699 entry[0].value = http2conf.downstream.max_concurrent_streams;
1700
1701 entry[1].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
1702 entry[1].value = http2conf.downstream.window_size;
1703
1704 if (http2conf.no_server_push || config->http2_proxy) {
1705 entry[nentry].settings_id = NGHTTP2_SETTINGS_ENABLE_PUSH;
1706 entry[nentry].value = 0;
1707 ++nentry;
1708 }
1709
1710 if (http2conf.downstream.decoder_dynamic_table_size !=
1711 NGHTTP2_DEFAULT_HEADER_TABLE_SIZE) {
1712 entry[nentry].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
1713 entry[nentry].value = http2conf.downstream.decoder_dynamic_table_size;
1714 ++nentry;
1715 }
1716
1717 rv = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(),
1718 nentry);
1719 if (rv != 0) {
1720 return -1;
1721 }
1722
1723 rv = nghttp2_session_set_local_window_size(
1724 session_, NGHTTP2_FLAG_NONE, 0,
1725 http2conf.downstream.connection_window_size);
1726 if (rv != 0) {
1727 return -1;
1728 }
1729
1730 reset_connection_check_timer(CONNCHK_TIMEOUT);
1731
1732 submit_pending_requests();
1733
1734 signal_write();
1735 return 0;
1736 }
1737
do_read()1738 int Http2Session::do_read() { return read_(*this); }
do_write()1739 int Http2Session::do_write() { return write_(*this); }
1740
on_read(const uint8_t * data,size_t datalen)1741 int Http2Session::on_read(const uint8_t *data, size_t datalen) {
1742 return on_read_(*this, data, datalen);
1743 }
1744
on_write()1745 int Http2Session::on_write() { return on_write_(*this); }
1746
downstream_read(const uint8_t * data,size_t datalen)1747 int Http2Session::downstream_read(const uint8_t *data, size_t datalen) {
1748 ssize_t rv;
1749
1750 rv = nghttp2_session_mem_recv(session_, data, datalen);
1751 if (rv < 0) {
1752 SSLOG(ERROR, this) << "nghttp2_session_mem_recv() returned error: "
1753 << nghttp2_strerror(rv);
1754 return -1;
1755 }
1756
1757 if (nghttp2_session_want_read(session_) == 0 &&
1758 nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) {
1759 if (LOG_ENABLED(INFO)) {
1760 SSLOG(INFO, this) << "No more read/write for this HTTP2 session";
1761 }
1762 return -1;
1763 }
1764
1765 signal_write();
1766 return 0;
1767 }
1768
downstream_write()1769 int Http2Session::downstream_write() {
1770 for (;;) {
1771 const uint8_t *data;
1772 auto datalen = nghttp2_session_mem_send(session_, &data);
1773 if (datalen < 0) {
1774 SSLOG(ERROR, this) << "nghttp2_session_mem_send() returned error: "
1775 << nghttp2_strerror(datalen);
1776 return -1;
1777 }
1778 if (datalen == 0) {
1779 break;
1780 }
1781 wb_.append(data, datalen);
1782
1783 if (wb_.rleft() >= MAX_BUFFER_SIZE) {
1784 break;
1785 }
1786 }
1787
1788 if (nghttp2_session_want_read(session_) == 0 &&
1789 nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) {
1790 if (LOG_ENABLED(INFO)) {
1791 SSLOG(INFO, this) << "No more read/write for this session";
1792 }
1793 return -1;
1794 }
1795
1796 return 0;
1797 }
1798
signal_write()1799 void Http2Session::signal_write() {
1800 switch (state_) {
1801 case Http2SessionState::DISCONNECTED:
1802 if (!ev_is_active(&initiate_connection_timer_)) {
1803 if (LOG_ENABLED(INFO)) {
1804 LOG(INFO) << "Start connecting to backend server";
1805 }
1806 // Since the timer is set to 0., these will feed 2 events. We
1807 // will stop the timer in the initiate_connection_timer_ to void
1808 // 2nd event.
1809 ev_timer_start(conn_.loop, &initiate_connection_timer_);
1810 ev_feed_event(conn_.loop, &initiate_connection_timer_, 0);
1811 }
1812 break;
1813 case Http2SessionState::CONNECTED:
1814 conn_.wlimit.startw();
1815 break;
1816 default:
1817 break;
1818 }
1819 }
1820
get_loop() const1821 struct ev_loop *Http2Session::get_loop() const {
1822 return conn_.loop;
1823 }
1824
get_wev()1825 ev_io *Http2Session::get_wev() { return &conn_.wev; }
1826
get_state() const1827 Http2SessionState Http2Session::get_state() const { return state_; }
1828
set_state(Http2SessionState state)1829 void Http2Session::set_state(Http2SessionState state) { state_ = state; }
1830
terminate_session(uint32_t error_code)1831 int Http2Session::terminate_session(uint32_t error_code) {
1832 int rv;
1833 rv = nghttp2_session_terminate_session(session_, error_code);
1834 if (rv != 0) {
1835 return -1;
1836 }
1837 return 0;
1838 }
1839
get_ssl() const1840 SSL *Http2Session::get_ssl() const { return conn_.tls.ssl; }
1841
consume(int32_t stream_id,size_t len)1842 int Http2Session::consume(int32_t stream_id, size_t len) {
1843 int rv;
1844
1845 if (!session_) {
1846 return 0;
1847 }
1848
1849 rv = nghttp2_session_consume(session_, stream_id, len);
1850
1851 if (rv != 0) {
1852 SSLOG(WARN, this) << "nghttp2_session_consume() returned error: "
1853 << nghttp2_strerror(rv);
1854
1855 return -1;
1856 }
1857
1858 return 0;
1859 }
1860
can_push_request(const Downstream * downstream) const1861 bool Http2Session::can_push_request(const Downstream *downstream) const {
1862 auto &req = downstream->request();
1863 return state_ == Http2SessionState::CONNECTED &&
1864 connection_check_state_ == ConnectionCheck::NONE &&
1865 (req.connect_proto == ConnectProto::NONE || settings_recved_);
1866 }
1867
start_checking_connection()1868 void Http2Session::start_checking_connection() {
1869 if (state_ != Http2SessionState::CONNECTED ||
1870 connection_check_state_ != ConnectionCheck::REQUIRED) {
1871 return;
1872 }
1873 connection_check_state_ = ConnectionCheck::STARTED;
1874
1875 SSLOG(INFO, this) << "Start checking connection";
1876 // If connection is down, we may get error when writing data. Issue
1877 // ping frame to see whether connection is alive.
1878 nghttp2_submit_ping(session_, NGHTTP2_FLAG_NONE, NULL);
1879
1880 // set ping timeout and start timer again
1881 reset_connection_check_timer(CONNCHK_PING_TIMEOUT);
1882
1883 signal_write();
1884 }
1885
reset_connection_check_timer(ev_tstamp t)1886 void Http2Session::reset_connection_check_timer(ev_tstamp t) {
1887 connchk_timer_.repeat = t;
1888 ev_timer_again(conn_.loop, &connchk_timer_);
1889 }
1890
reset_connection_check_timer_if_not_checking()1891 void Http2Session::reset_connection_check_timer_if_not_checking() {
1892 if (connection_check_state_ != ConnectionCheck::NONE) {
1893 return;
1894 }
1895
1896 reset_connection_check_timer(CONNCHK_TIMEOUT);
1897 }
1898
connection_alive()1899 void Http2Session::connection_alive() {
1900 reset_connection_check_timer(CONNCHK_TIMEOUT);
1901
1902 if (connection_check_state_ == ConnectionCheck::NONE) {
1903 return;
1904 }
1905
1906 if (LOG_ENABLED(INFO)) {
1907 SSLOG(INFO, this) << "Connection alive";
1908 }
1909
1910 connection_check_state_ = ConnectionCheck::NONE;
1911
1912 submit_pending_requests();
1913 }
1914
submit_pending_requests()1915 void Http2Session::submit_pending_requests() {
1916 for (auto dconn = dconns_.head; dconn; dconn = dconn->dlnext) {
1917 auto downstream = dconn->get_downstream();
1918
1919 if (!downstream->get_request_pending() ||
1920 !downstream->request_submission_ready()) {
1921 continue;
1922 }
1923
1924 auto &req = downstream->request();
1925 if (req.connect_proto != ConnectProto::NONE && !settings_recved_) {
1926 continue;
1927 }
1928
1929 auto upstream = downstream->get_upstream();
1930
1931 if (dconn->push_request_headers() != 0) {
1932 if (LOG_ENABLED(INFO)) {
1933 SSLOG(INFO, this) << "backend request failed";
1934 }
1935
1936 upstream->on_downstream_abort_request(downstream, 400);
1937
1938 continue;
1939 }
1940
1941 upstream->resume_read(SHRPX_NO_BUFFER, downstream, 0);
1942 }
1943 }
1944
set_connection_check_state(ConnectionCheck state)1945 void Http2Session::set_connection_check_state(ConnectionCheck state) {
1946 connection_check_state_ = state;
1947 }
1948
get_connection_check_state() const1949 ConnectionCheck Http2Session::get_connection_check_state() const {
1950 return connection_check_state_;
1951 }
1952
noop()1953 int Http2Session::noop() { return 0; }
1954
read_noop(const uint8_t * data,size_t datalen)1955 int Http2Session::read_noop(const uint8_t *data, size_t datalen) { return 0; }
1956
write_noop()1957 int Http2Session::write_noop() { return 0; }
1958
connected()1959 int Http2Session::connected() {
1960 auto sock_error = util::get_socket_error(conn_.fd);
1961 if (sock_error != 0) {
1962 SSLOG(WARN, this) << "Backend connect failed; addr="
1963 << util::to_numeric_addr(raddr_)
1964 << ": errno=" << sock_error;
1965
1966 downstream_failure(addr_, raddr_);
1967
1968 return -1;
1969 }
1970
1971 if (LOG_ENABLED(INFO)) {
1972 SSLOG(INFO, this) << "Connection established";
1973 }
1974
1975 // Reset timeout for write. Previously, we set timeout for connect.
1976 conn_.wt.repeat = group_->shared_addr->timeout.write;
1977 ev_timer_again(conn_.loop, &conn_.wt);
1978
1979 conn_.rlimit.startw();
1980 conn_.again_rt();
1981
1982 read_ = &Http2Session::read_clear;
1983 write_ = &Http2Session::write_clear;
1984
1985 if (state_ == Http2SessionState::PROXY_CONNECTING) {
1986 return do_write();
1987 }
1988
1989 if (conn_.tls.ssl) {
1990 read_ = &Http2Session::tls_handshake;
1991 write_ = &Http2Session::tls_handshake;
1992
1993 return do_write();
1994 }
1995
1996 if (connection_made() != 0) {
1997 state_ = Http2SessionState::CONNECT_FAILING;
1998 return -1;
1999 }
2000
2001 return 0;
2002 }
2003
read_clear()2004 int Http2Session::read_clear() {
2005 conn_.last_read = ev_now(conn_.loop);
2006
2007 std::array<uint8_t, 16_k> buf;
2008
2009 for (;;) {
2010 auto nread = conn_.read_clear(buf.data(), buf.size());
2011
2012 if (nread == 0) {
2013 return write_clear();
2014 }
2015
2016 if (nread < 0) {
2017 return nread;
2018 }
2019
2020 if (on_read(buf.data(), nread) != 0) {
2021 return -1;
2022 }
2023 }
2024 }
2025
write_clear()2026 int Http2Session::write_clear() {
2027 conn_.last_read = ev_now(conn_.loop);
2028
2029 std::array<struct iovec, MAX_WR_IOVCNT> iov;
2030
2031 for (;;) {
2032 if (wb_.rleft() > 0) {
2033 auto iovcnt = wb_.riovec(iov.data(), iov.size());
2034 auto nwrite = conn_.writev_clear(iov.data(), iovcnt);
2035
2036 if (nwrite == 0) {
2037 return 0;
2038 }
2039
2040 if (nwrite < 0) {
2041 // We may have pending data in receive buffer which may
2042 // contain part of response body. So keep reading. Invoke
2043 // read event to get read(2) error just in case.
2044 ev_feed_event(conn_.loop, &conn_.rev, EV_READ);
2045 write_ = &Http2Session::write_void;
2046 break;
2047 }
2048
2049 wb_.drain(nwrite);
2050 continue;
2051 }
2052
2053 if (on_write() != 0) {
2054 return -1;
2055 }
2056 if (wb_.rleft() == 0) {
2057 break;
2058 }
2059 }
2060
2061 conn_.wlimit.stopw();
2062 ev_timer_stop(conn_.loop, &conn_.wt);
2063
2064 return 0;
2065 }
2066
tls_handshake()2067 int Http2Session::tls_handshake() {
2068 conn_.last_read = ev_now(conn_.loop);
2069
2070 ERR_clear_error();
2071
2072 auto rv = conn_.tls_handshake();
2073
2074 if (rv == SHRPX_ERR_INPROGRESS) {
2075 return 0;
2076 }
2077
2078 if (rv < 0) {
2079 downstream_failure(addr_, raddr_);
2080
2081 return rv;
2082 }
2083
2084 if (LOG_ENABLED(INFO)) {
2085 SSLOG(INFO, this) << "SSL/TLS handshake completed";
2086 }
2087
2088 if (!get_config()->tls.insecure &&
2089 tls::check_cert(conn_.tls.ssl, addr_, raddr_) != 0) {
2090 downstream_failure(addr_, raddr_);
2091
2092 return -1;
2093 }
2094
2095 read_ = &Http2Session::read_tls;
2096 write_ = &Http2Session::write_tls;
2097
2098 if (connection_made() != 0) {
2099 state_ = Http2SessionState::CONNECT_FAILING;
2100 return -1;
2101 }
2102
2103 return 0;
2104 }
2105
read_tls()2106 int Http2Session::read_tls() {
2107 conn_.last_read = ev_now(conn_.loop);
2108
2109 std::array<uint8_t, 16_k> buf;
2110
2111 ERR_clear_error();
2112
2113 for (;;) {
2114 auto nread = conn_.read_tls(buf.data(), buf.size());
2115
2116 if (nread == 0) {
2117 return write_tls();
2118 }
2119
2120 if (nread < 0) {
2121 return nread;
2122 }
2123
2124 if (on_read(buf.data(), nread) != 0) {
2125 return -1;
2126 }
2127 }
2128 }
2129
write_tls()2130 int Http2Session::write_tls() {
2131 conn_.last_read = ev_now(conn_.loop);
2132
2133 ERR_clear_error();
2134
2135 struct iovec iov;
2136
2137 for (;;) {
2138 if (wb_.rleft() > 0) {
2139 auto iovcnt = wb_.riovec(&iov, 1);
2140 if (iovcnt != 1) {
2141 assert(0);
2142 return -1;
2143 }
2144 auto nwrite = conn_.write_tls(iov.iov_base, iov.iov_len);
2145
2146 if (nwrite == 0) {
2147 return 0;
2148 }
2149
2150 if (nwrite < 0) {
2151 // We may have pending data in receive buffer which may
2152 // contain part of response body. So keep reading. Invoke
2153 // read event to get read(2) error just in case.
2154 ev_feed_event(conn_.loop, &conn_.rev, EV_READ);
2155 write_ = &Http2Session::write_void;
2156 break;
2157 }
2158
2159 wb_.drain(nwrite);
2160
2161 continue;
2162 }
2163
2164 if (on_write() != 0) {
2165 return -1;
2166 }
2167 if (wb_.rleft() == 0) {
2168 conn_.start_tls_write_idle();
2169 break;
2170 }
2171 }
2172
2173 conn_.wlimit.stopw();
2174 ev_timer_stop(conn_.loop, &conn_.wt);
2175
2176 return 0;
2177 }
2178
write_void()2179 int Http2Session::write_void() {
2180 conn_.wlimit.stopw();
2181 return 0;
2182 }
2183
should_hard_fail() const2184 bool Http2Session::should_hard_fail() const {
2185 switch (state_) {
2186 case Http2SessionState::PROXY_CONNECTING:
2187 case Http2SessionState::PROXY_FAILED:
2188 return true;
2189 case Http2SessionState::DISCONNECTED: {
2190 const auto &proxy = get_config()->downstream_http_proxy;
2191 return !proxy.host.empty();
2192 }
2193 default:
2194 return false;
2195 }
2196 }
2197
get_addr() const2198 DownstreamAddr *Http2Session::get_addr() const { return addr_; }
2199
handle_downstream_push_promise(Downstream * downstream,int32_t promised_stream_id)2200 int Http2Session::handle_downstream_push_promise(Downstream *downstream,
2201 int32_t promised_stream_id) {
2202 auto upstream = downstream->get_upstream();
2203 if (!upstream->push_enabled()) {
2204 return -1;
2205 }
2206
2207 auto promised_downstream =
2208 upstream->on_downstream_push_promise(downstream, promised_stream_id);
2209 if (!promised_downstream) {
2210 return -1;
2211 }
2212
2213 // Now we have Downstream object for pushed stream.
2214 // promised_downstream->get_stream() still returns 0.
2215
2216 auto handler = upstream->get_client_handler();
2217
2218 auto promised_dconn = std::make_unique<Http2DownstreamConnection>(this);
2219 promised_dconn->set_client_handler(handler);
2220
2221 auto ptr = promised_dconn.get();
2222
2223 if (promised_downstream->attach_downstream_connection(
2224 std::move(promised_dconn)) != 0) {
2225 return -1;
2226 }
2227
2228 auto promised_sd = std::make_unique<StreamData>();
2229
2230 nghttp2_session_set_stream_user_data(session_, promised_stream_id,
2231 promised_sd.get());
2232
2233 ptr->attach_stream_data(promised_sd.get());
2234 streams_.append(promised_sd.release());
2235
2236 return 0;
2237 }
2238
handle_downstream_push_promise_complete(Downstream * downstream,Downstream * promised_downstream)2239 int Http2Session::handle_downstream_push_promise_complete(
2240 Downstream *downstream, Downstream *promised_downstream) {
2241 auto &promised_req = promised_downstream->request();
2242
2243 auto &promised_balloc = promised_downstream->get_block_allocator();
2244
2245 auto authority = promised_req.fs.header(http2::HD__AUTHORITY);
2246 auto path = promised_req.fs.header(http2::HD__PATH);
2247 auto method = promised_req.fs.header(http2::HD__METHOD);
2248 auto scheme = promised_req.fs.header(http2::HD__SCHEME);
2249
2250 if (!authority) {
2251 authority = promised_req.fs.header(http2::HD_HOST);
2252 }
2253
2254 auto method_token = http2::lookup_method_token(method->value);
2255 if (method_token == -1) {
2256 if (LOG_ENABLED(INFO)) {
2257 SSLOG(INFO, this) << "Unrecognized method: " << method->value;
2258 }
2259
2260 return -1;
2261 }
2262
2263 // TODO Rewrite authority if we enabled rewrite host. But we
2264 // really don't know how to rewrite host. Should we use the same
2265 // host in associated stream?
2266 if (authority) {
2267 promised_req.authority = authority->value;
2268 }
2269 promised_req.method = method_token;
2270 // libnghttp2 ensures that we don't have CONNECT method in
2271 // PUSH_PROMISE, and guarantees that :scheme exists.
2272 if (scheme) {
2273 promised_req.scheme = scheme->value;
2274 }
2275
2276 // For server-wide OPTIONS request, path is empty.
2277 if (method_token != HTTP_OPTIONS || path->value != "*") {
2278 promised_req.path = http2::rewrite_clean_path(promised_balloc, path->value);
2279 }
2280
2281 promised_downstream->inspect_http2_request();
2282
2283 auto upstream = promised_downstream->get_upstream();
2284
2285 promised_downstream->set_request_state(DownstreamState::MSG_COMPLETE);
2286 promised_downstream->set_request_header_sent(true);
2287
2288 if (upstream->on_downstream_push_promise_complete(downstream,
2289 promised_downstream) != 0) {
2290 return -1;
2291 }
2292
2293 return 0;
2294 }
2295
get_num_dconns() const2296 size_t Http2Session::get_num_dconns() const { return dconns_.size(); }
2297
max_concurrency_reached(size_t extra) const2298 bool Http2Session::max_concurrency_reached(size_t extra) const {
2299 if (!session_) {
2300 return dconns_.size() + extra >= 100;
2301 }
2302
2303 // If session does not allow further requests, it effectively means
2304 // that maximum concurrency is reached.
2305 return !nghttp2_session_check_request_allowed(session_) ||
2306 dconns_.size() + extra >=
2307 nghttp2_session_get_remote_settings(
2308 session_, NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS);
2309 }
2310
2311 const std::shared_ptr<DownstreamAddrGroup> &
get_downstream_addr_group() const2312 Http2Session::get_downstream_addr_group() const {
2313 return group_;
2314 }
2315
add_to_extra_freelist()2316 void Http2Session::add_to_extra_freelist() {
2317 if (freelist_zone_ != FreelistZone::NONE) {
2318 return;
2319 }
2320
2321 if (LOG_ENABLED(INFO)) {
2322 SSLOG(INFO, this) << "Append to http2_extra_freelist, addr=" << addr_
2323 << ", freelist.size="
2324 << addr_->http2_extra_freelist.size();
2325 }
2326
2327 freelist_zone_ = FreelistZone::EXTRA;
2328 addr_->http2_extra_freelist.append(this);
2329 }
2330
remove_from_freelist()2331 void Http2Session::remove_from_freelist() {
2332 switch (freelist_zone_) {
2333 case FreelistZone::NONE:
2334 return;
2335 case FreelistZone::EXTRA:
2336 if (LOG_ENABLED(INFO)) {
2337 SSLOG(INFO, this) << "Remove from http2_extra_freelist, addr=" << addr_
2338 << ", freelist.size="
2339 << addr_->http2_extra_freelist.size();
2340 }
2341 addr_->http2_extra_freelist.remove(this);
2342 break;
2343 case FreelistZone::GONE:
2344 return;
2345 }
2346
2347 freelist_zone_ = FreelistZone::NONE;
2348 }
2349
exclude_from_scheduling()2350 void Http2Session::exclude_from_scheduling() {
2351 remove_from_freelist();
2352 freelist_zone_ = FreelistZone::GONE;
2353 }
2354
get_request_buf()2355 DefaultMemchunks *Http2Session::get_request_buf() { return &wb_; }
2356
on_timeout()2357 void Http2Session::on_timeout() {
2358 switch (state_) {
2359 case Http2SessionState::PROXY_CONNECTING: {
2360 auto worker_blocker = worker_->get_connect_blocker();
2361 worker_blocker->on_failure();
2362 break;
2363 }
2364 case Http2SessionState::CONNECTING:
2365 SSLOG(WARN, this) << "Connect time out; addr="
2366 << util::to_numeric_addr(raddr_);
2367
2368 downstream_failure(addr_, raddr_);
2369 break;
2370 default:
2371 break;
2372 }
2373 }
2374
check_retire()2375 void Http2Session::check_retire() {
2376 if (!group_->retired) {
2377 return;
2378 }
2379
2380 ev_prepare_stop(conn_.loop, &prep_);
2381
2382 if (!session_) {
2383 return;
2384 }
2385
2386 auto last_stream_id = nghttp2_session_get_last_proc_stream_id(session_);
2387 nghttp2_submit_goaway(session_, NGHTTP2_FLAG_NONE, last_stream_id,
2388 NGHTTP2_NO_ERROR, nullptr, 0);
2389
2390 signal_write();
2391 }
2392
get_raddr() const2393 const Address *Http2Session::get_raddr() const { return raddr_; }
2394
on_settings_received(const nghttp2_frame * frame)2395 void Http2Session::on_settings_received(const nghttp2_frame *frame) {
2396 // TODO This effectively disallows nghttpx to change its behaviour
2397 // based on the 2nd SETTINGS.
2398 if (settings_recved_) {
2399 return;
2400 }
2401
2402 settings_recved_ = true;
2403
2404 for (size_t i = 0; i < frame->settings.niv; ++i) {
2405 auto &ent = frame->settings.iv[i];
2406 if (ent.settings_id == NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL) {
2407 allow_connect_proto_ = true;
2408 break;
2409 }
2410 }
2411
2412 submit_pending_requests();
2413 }
2414
get_allow_connect_proto() const2415 bool Http2Session::get_allow_connect_proto() const {
2416 return allow_connect_proto_;
2417 }
2418
2419 } // namespace shrpx
2420