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