• 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_https_upstream.h"
26 
27 #include <cassert>
28 #include <set>
29 #include <sstream>
30 
31 #include "shrpx_client_handler.h"
32 #include "shrpx_downstream.h"
33 #include "shrpx_downstream_connection.h"
34 #include "shrpx_http.h"
35 #include "shrpx_config.h"
36 #include "shrpx_error.h"
37 #include "shrpx_log_config.h"
38 #include "shrpx_worker.h"
39 #include "shrpx_http2_session.h"
40 #include "shrpx_log.h"
41 #ifdef HAVE_MRUBY
42 #  include "shrpx_mruby.h"
43 #endif // HAVE_MRUBY
44 #include "http2.h"
45 #include "util.h"
46 #include "template.h"
47 #include "base64.h"
48 #include "url-parser/url_parser.h"
49 
50 using namespace nghttp2;
51 
52 namespace shrpx {
53 
54 namespace {
55 int htp_msg_begin(llhttp_t *htp);
56 int htp_uricb(llhttp_t *htp, const char *data, size_t len);
57 int htp_hdr_keycb(llhttp_t *htp, const char *data, size_t len);
58 int htp_hdr_valcb(llhttp_t *htp, const char *data, size_t len);
59 int htp_hdrs_completecb(llhttp_t *htp);
60 int htp_bodycb(llhttp_t *htp, const char *data, size_t len);
61 int htp_msg_completecb(llhttp_t *htp);
62 } // namespace
63 
64 namespace {
65 constexpr llhttp_settings_t htp_hooks = {
66     htp_msg_begin,       // llhttp_cb      on_message_begin;
67     htp_uricb,           // llhttp_data_cb on_url;
68     nullptr,             // llhttp_data_cb on_status;
69     nullptr,             // llhttp_data_cb on_method;
70     nullptr,             // llhttp_data_cb on_version;
71     htp_hdr_keycb,       // llhttp_data_cb on_header_field;
72     htp_hdr_valcb,       // llhttp_data_cb on_header_value;
73     nullptr,             // llhttp_data_cb on_chunk_extension_name;
74     nullptr,             // llhttp_data_cb on_chunk_extension_value;
75     htp_hdrs_completecb, // llhttp_cb      on_headers_complete;
76     htp_bodycb,          // llhttp_data_cb on_body;
77     htp_msg_completecb,  // llhttp_cb      on_message_complete;
78     nullptr,             // llhttp_cb      on_url_complete;
79     nullptr,             // llhttp_cb      on_status_complete;
80     nullptr,             // llhttp_cb      on_method_complete;
81     nullptr,             // llhttp_cb      on_version_complete;
82     nullptr,             // llhttp_cb      on_header_field_complete;
83     nullptr,             // llhttp_cb      on_header_value_complete;
84     nullptr,             // llhttp_cb      on_chunk_extension_name_complete;
85     nullptr,             // llhttp_cb      on_chunk_extension_value_complete;
86     nullptr,             // llhttp_cb      on_chunk_header;
87     nullptr,             // llhttp_cb      on_chunk_complete;
88     nullptr,             // llhttp_cb      on_reset;
89 };
90 } // namespace
91 
HttpsUpstream(ClientHandler * handler)92 HttpsUpstream::HttpsUpstream(ClientHandler *handler)
93     : handler_(handler),
94       current_header_length_(0),
95       ioctrl_(handler->get_rlimit()),
96       num_requests_(0) {
97   llhttp_init(&htp_, HTTP_REQUEST, &htp_hooks);
98   htp_.data = this;
99 }
100 
~HttpsUpstream()101 HttpsUpstream::~HttpsUpstream() {}
102 
reset_current_header_length()103 void HttpsUpstream::reset_current_header_length() {
104   current_header_length_ = 0;
105 }
106 
on_start_request()107 void HttpsUpstream::on_start_request() {
108   if (LOG_ENABLED(INFO)) {
109     ULOG(INFO, this) << "HTTP request started";
110   }
111   reset_current_header_length();
112 
113   auto downstream =
114       std::make_unique<Downstream>(this, handler_->get_mcpool(), 0);
115 
116   attach_downstream(std::move(downstream));
117 
118   auto conn = handler_->get_connection();
119   auto &upstreamconf = get_config()->conn.upstream;
120 
121   conn->rt.repeat = upstreamconf.timeout.read;
122 
123   handler_->repeat_read_timer();
124 
125   ++num_requests_;
126 }
127 
128 namespace {
htp_msg_begin(llhttp_t * htp)129 int htp_msg_begin(llhttp_t *htp) {
130   auto upstream = static_cast<HttpsUpstream *>(htp->data);
131   upstream->on_start_request();
132   return 0;
133 }
134 } // namespace
135 
136 namespace {
htp_uricb(llhttp_t * htp,const char * data,size_t len)137 int htp_uricb(llhttp_t *htp, const char *data, size_t len) {
138   auto upstream = static_cast<HttpsUpstream *>(htp->data);
139   auto downstream = upstream->get_downstream();
140   auto &req = downstream->request();
141 
142   auto &balloc = downstream->get_block_allocator();
143 
144   // We happen to have the same value for method token.
145   req.method = htp->method;
146 
147   if (req.fs.buffer_size() + len >
148       get_config()->http.request_header_field_buffer) {
149     if (LOG_ENABLED(INFO)) {
150       ULOG(INFO, upstream) << "Too large URI size="
151                            << req.fs.buffer_size() + len;
152     }
153     assert(downstream->get_request_state() == DownstreamState::INITIAL);
154     downstream->set_request_state(
155         DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE);
156     llhttp_set_error_reason(htp, "too long request URI");
157     return HPE_USER;
158   }
159 
160   req.fs.add_extra_buffer_size(len);
161 
162   if (req.method == HTTP_CONNECT) {
163     req.authority =
164         concat_string_ref(balloc, req.authority, StringRef{data, len});
165   } else {
166     req.path = concat_string_ref(balloc, req.path, StringRef{data, len});
167   }
168 
169   return 0;
170 }
171 } // namespace
172 
173 namespace {
htp_hdr_keycb(llhttp_t * htp,const char * data,size_t len)174 int htp_hdr_keycb(llhttp_t *htp, const char *data, size_t len) {
175   auto upstream = static_cast<HttpsUpstream *>(htp->data);
176   auto downstream = upstream->get_downstream();
177   auto &req = downstream->request();
178   auto &httpconf = get_config()->http;
179 
180   if (req.fs.buffer_size() + len > httpconf.request_header_field_buffer) {
181     if (LOG_ENABLED(INFO)) {
182       ULOG(INFO, upstream) << "Too large header block size="
183                            << req.fs.buffer_size() + len;
184     }
185     if (downstream->get_request_state() == DownstreamState::INITIAL) {
186       downstream->set_request_state(
187           DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE);
188     }
189     llhttp_set_error_reason(htp, "too large header");
190     return HPE_USER;
191   }
192   if (downstream->get_request_state() == DownstreamState::INITIAL) {
193     if (req.fs.header_key_prev()) {
194       req.fs.append_last_header_key(data, len);
195     } else {
196       if (req.fs.num_fields() >= httpconf.max_request_header_fields) {
197         if (LOG_ENABLED(INFO)) {
198           ULOG(INFO, upstream)
199               << "Too many header field num=" << req.fs.num_fields() + 1;
200         }
201         downstream->set_request_state(
202             DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE);
203         llhttp_set_error_reason(htp, "too many headers");
204         return HPE_USER;
205       }
206       req.fs.alloc_add_header_name(StringRef{data, len});
207     }
208   } else {
209     // trailer part
210     if (req.fs.trailer_key_prev()) {
211       req.fs.append_last_trailer_key(data, len);
212     } else {
213       if (req.fs.num_fields() >= httpconf.max_request_header_fields) {
214         if (LOG_ENABLED(INFO)) {
215           ULOG(INFO, upstream)
216               << "Too many header field num=" << req.fs.num_fields() + 1;
217         }
218         llhttp_set_error_reason(htp, "too many headers");
219         return HPE_USER;
220       }
221       req.fs.alloc_add_trailer_name(StringRef{data, len});
222     }
223   }
224   return 0;
225 }
226 } // namespace
227 
228 namespace {
htp_hdr_valcb(llhttp_t * htp,const char * data,size_t len)229 int htp_hdr_valcb(llhttp_t *htp, const char *data, size_t len) {
230   auto upstream = static_cast<HttpsUpstream *>(htp->data);
231   auto downstream = upstream->get_downstream();
232   auto &req = downstream->request();
233 
234   if (req.fs.buffer_size() + len >
235       get_config()->http.request_header_field_buffer) {
236     if (LOG_ENABLED(INFO)) {
237       ULOG(INFO, upstream) << "Too large header block size="
238                            << req.fs.buffer_size() + len;
239     }
240     if (downstream->get_request_state() == DownstreamState::INITIAL) {
241       downstream->set_request_state(
242           DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE);
243     }
244     llhttp_set_error_reason(htp, "too large header");
245     return HPE_USER;
246   }
247   if (downstream->get_request_state() == DownstreamState::INITIAL) {
248     req.fs.append_last_header_value(data, len);
249   } else {
250     req.fs.append_last_trailer_value(data, len);
251   }
252   return 0;
253 }
254 } // namespace
255 
256 namespace {
rewrite_request_host_path_from_uri(BlockAllocator & balloc,Request & req,const StringRef & uri,http_parser_url & u)257 void rewrite_request_host_path_from_uri(BlockAllocator &balloc, Request &req,
258                                         const StringRef &uri,
259                                         http_parser_url &u) {
260   assert(u.field_set & (1 << UF_HOST));
261 
262   // As per https://tools.ietf.org/html/rfc7230#section-5.4, we
263   // rewrite host header field with authority component.
264   auto authority = util::get_uri_field(uri.c_str(), u, UF_HOST);
265   // TODO properly check IPv6 numeric address
266   auto ipv6 = std::find(std::begin(authority), std::end(authority), ':') !=
267               std::end(authority);
268   auto authoritylen = authority.size();
269   if (ipv6) {
270     authoritylen += 2;
271   }
272   if (u.field_set & (1 << UF_PORT)) {
273     authoritylen += 1 + str_size("65535");
274   }
275   if (authoritylen > authority.size()) {
276     auto iovec = make_byte_ref(balloc, authoritylen + 1);
277     auto p = iovec.base;
278     if (ipv6) {
279       *p++ = '[';
280     }
281     p = std::copy(std::begin(authority), std::end(authority), p);
282     if (ipv6) {
283       *p++ = ']';
284     }
285 
286     if (u.field_set & (1 << UF_PORT)) {
287       *p++ = ':';
288       p = util::utos(p, u.port);
289     }
290     *p = '\0';
291 
292     req.authority = StringRef{iovec.base, p};
293   } else {
294     req.authority = authority;
295   }
296 
297   req.scheme = util::get_uri_field(uri.c_str(), u, UF_SCHEMA);
298 
299   StringRef path;
300   if (u.field_set & (1 << UF_PATH)) {
301     path = util::get_uri_field(uri.c_str(), u, UF_PATH);
302   } else if (req.method == HTTP_OPTIONS) {
303     // Server-wide OPTIONS takes following form in proxy request:
304     //
305     // OPTIONS http://example.org HTTP/1.1
306     //
307     // Notice that no slash after authority. See
308     // http://tools.ietf.org/html/rfc7230#section-5.3.4
309     req.path = StringRef::from_lit("");
310     // we ignore query component here
311     return;
312   } else {
313     path = StringRef::from_lit("/");
314   }
315 
316   if (u.field_set & (1 << UF_QUERY)) {
317     auto &fdata = u.field_data[UF_QUERY];
318 
319     if (u.field_set & (1 << UF_PATH)) {
320       auto q = util::get_uri_field(uri.c_str(), u, UF_QUERY);
321       path = StringRef{std::begin(path), std::end(q)};
322     } else {
323       path = concat_string_ref(balloc, path, StringRef::from_lit("?"),
324                                StringRef{&uri[fdata.off], fdata.len});
325     }
326   }
327 
328   req.path = http2::rewrite_clean_path(balloc, path);
329 }
330 } // namespace
331 
332 namespace {
htp_hdrs_completecb(llhttp_t * htp)333 int htp_hdrs_completecb(llhttp_t *htp) {
334   int rv;
335   auto upstream = static_cast<HttpsUpstream *>(htp->data);
336   if (LOG_ENABLED(INFO)) {
337     ULOG(INFO, upstream) << "HTTP request headers completed";
338   }
339 
340   auto handler = upstream->get_client_handler();
341 
342   auto downstream = upstream->get_downstream();
343   auto &req = downstream->request();
344   auto &balloc = downstream->get_block_allocator();
345 
346   for (auto &kv : req.fs.headers()) {
347     kv.value = util::rstrip(balloc, kv.value);
348 
349     if (kv.token == http2::HD_TRANSFER_ENCODING &&
350         !http2::check_transfer_encoding(kv.value)) {
351       return -1;
352     }
353   }
354 
355   auto lgconf = log_config();
356   lgconf->update_tstamp(std::chrono::system_clock::now());
357   req.tstamp = lgconf->tstamp;
358 
359   req.http_major = htp->http_major;
360   req.http_minor = htp->http_minor;
361 
362   req.connection_close = !llhttp_should_keep_alive(htp);
363 
364   handler->stop_read_timer();
365 
366   auto method = req.method;
367 
368   if (LOG_ENABLED(INFO)) {
369     std::stringstream ss;
370     ss << http2::to_method_string(method) << " "
371        << (method == HTTP_CONNECT ? req.authority : req.path) << " "
372        << "HTTP/" << req.http_major << "." << req.http_minor << "\n";
373 
374     for (const auto &kv : req.fs.headers()) {
375       if (kv.name == "authorization") {
376         ss << TTY_HTTP_HD << kv.name << TTY_RST << ": <redacted>\n";
377         continue;
378       }
379       ss << TTY_HTTP_HD << kv.name << TTY_RST << ": " << kv.value << "\n";
380     }
381 
382     ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
383   }
384 
385   // set content-length if method is not CONNECT, and no
386   // transfer-encoding is given.  If transfer-encoding is given, leave
387   // req.fs.content_length to -1.
388   if (method != HTTP_CONNECT && !req.fs.header(http2::HD_TRANSFER_ENCODING)) {
389     // llhttp sets 0 to htp->content_length if there is no
390     // content-length header field.  If we don't have both
391     // transfer-encoding and content-length header field, we assume
392     // that there is no request body.
393     req.fs.content_length = htp->content_length;
394   }
395 
396   auto host = req.fs.header(http2::HD_HOST);
397 
398   if (req.http_major > 1 || req.http_minor > 1) {
399     req.http_major = 1;
400     req.http_minor = 1;
401     return -1;
402   }
403 
404   if (req.http_major == 1 && req.http_minor == 1 && !host) {
405     return -1;
406   }
407 
408   if (host) {
409     const auto &value = host->value;
410     // Not allow at least '"' or '\' in host.  They are illegal in
411     // authority component, also they cause headaches when we put them
412     // in quoted-string.
413     if (std::find_if(std::begin(value), std::end(value), [](char c) {
414           return c == '"' || c == '\\';
415         }) != std::end(value)) {
416       return -1;
417     }
418   }
419 
420   downstream->inspect_http1_request();
421 
422   if (htp->flags & F_CHUNKED) {
423     downstream->set_chunked_request(true);
424   }
425 
426   auto transfer_encoding = req.fs.header(http2::HD_TRANSFER_ENCODING);
427   if (transfer_encoding &&
428       http2::legacy_http1(req.http_major, req.http_minor)) {
429     return -1;
430   }
431 
432   auto faddr = handler->get_upstream_addr();
433   auto config = get_config();
434 
435   if (method != HTTP_CONNECT) {
436     http_parser_url u{};
437     rv = http_parser_parse_url(req.path.c_str(), req.path.size(), 0, &u);
438     if (rv != 0) {
439       // Expect to respond with 400 bad request
440       return -1;
441     }
442     // checking UF_HOST could be redundant, but just in case ...
443     if (!(u.field_set & (1 << UF_SCHEMA)) || !(u.field_set & (1 << UF_HOST))) {
444       req.no_authority = true;
445 
446       if (method == HTTP_OPTIONS && req.path == StringRef::from_lit("*")) {
447         req.path = StringRef{};
448       } else {
449         req.path = http2::rewrite_clean_path(balloc, req.path);
450       }
451 
452       if (host) {
453         req.authority = host->value;
454       }
455 
456       if (handler->get_ssl()) {
457         req.scheme = StringRef::from_lit("https");
458       } else {
459         req.scheme = StringRef::from_lit("http");
460       }
461     } else {
462       rewrite_request_host_path_from_uri(balloc, req, req.path, u);
463     }
464   }
465 
466   downstream->set_request_state(DownstreamState::HEADER_COMPLETE);
467 
468   auto &resp = downstream->response();
469 
470   if (config->http.require_http_scheme &&
471       !http::check_http_scheme(req.scheme, handler->get_ssl() != nullptr)) {
472     resp.http_status = 400;
473     return -1;
474   }
475 
476 #ifdef HAVE_MRUBY
477   auto worker = handler->get_worker();
478   auto mruby_ctx = worker->get_mruby_context();
479 
480   if (mruby_ctx->run_on_request_proc(downstream) != 0) {
481     resp.http_status = 500;
482     return -1;
483   }
484 #endif // HAVE_MRUBY
485 
486   // mruby hook may change method value
487 
488   if (req.no_authority && config->http2_proxy &&
489       faddr->alt_mode == UpstreamAltMode::NONE) {
490     // Request URI should be absolute-form for client proxy mode
491     return -1;
492   }
493 
494   if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
495     return 0;
496   }
497 
498 #ifdef HAVE_MRUBY
499   DownstreamConnection *dconn_ptr;
500 #endif // HAVE_MRUBY
501 
502   for (;;) {
503     auto dconn = handler->get_downstream_connection(rv, downstream);
504 
505     if (!dconn) {
506       if (rv == SHRPX_ERR_TLS_REQUIRED) {
507         upstream->redirect_to_https(downstream);
508       }
509       downstream->set_request_state(DownstreamState::CONNECT_FAIL);
510       return -1;
511     }
512 
513 #ifdef HAVE_MRUBY
514     dconn_ptr = dconn.get();
515 #endif // HAVE_MRUBY
516     if (downstream->attach_downstream_connection(std::move(dconn)) == 0) {
517       break;
518     }
519   }
520 
521 #ifdef HAVE_MRUBY
522   const auto &group = dconn_ptr->get_downstream_addr_group();
523   if (group) {
524     const auto &dmruby_ctx = group->shared_addr->mruby_ctx;
525 
526     if (dmruby_ctx->run_on_request_proc(downstream) != 0) {
527       resp.http_status = 500;
528       return -1;
529     }
530 
531     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
532       return 0;
533     }
534   }
535 #endif // HAVE_MRUBY
536 
537   rv = downstream->push_request_headers();
538 
539   if (rv != 0) {
540     return -1;
541   }
542 
543   if (faddr->alt_mode != UpstreamAltMode::NONE) {
544     // Normally, we forward expect: 100-continue to backend server,
545     // and let them decide whether responds with 100 Continue or not.
546     // For alternative mode, we have no backend, so just send 100
547     // Continue here to make the client happy.
548     if (downstream->get_expect_100_continue()) {
549       auto output = downstream->get_response_buf();
550       constexpr auto res = StringRef::from_lit("HTTP/1.1 100 Continue\r\n\r\n");
551       output->append(res);
552       handler->signal_write();
553     }
554   }
555 
556   return 0;
557 }
558 } // namespace
559 
560 namespace {
htp_bodycb(llhttp_t * htp,const char * data,size_t len)561 int htp_bodycb(llhttp_t *htp, const char *data, size_t len) {
562   int rv;
563   auto upstream = static_cast<HttpsUpstream *>(htp->data);
564   auto downstream = upstream->get_downstream();
565   rv = downstream->push_upload_data_chunk(
566       reinterpret_cast<const uint8_t *>(data), len);
567   if (rv != 0) {
568     // Ignore error if response has been completed.  We will end up in
569     // htp_msg_completecb, and request will end gracefully.
570     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
571       return 0;
572     }
573 
574     llhttp_set_error_reason(htp, "could not process request body");
575     return HPE_USER;
576   }
577   return 0;
578 }
579 } // namespace
580 
581 namespace {
htp_msg_completecb(llhttp_t * htp)582 int htp_msg_completecb(llhttp_t *htp) {
583   int rv;
584   auto upstream = static_cast<HttpsUpstream *>(htp->data);
585   if (LOG_ENABLED(INFO)) {
586     ULOG(INFO, upstream) << "HTTP request completed";
587   }
588   auto handler = upstream->get_client_handler();
589   auto downstream = upstream->get_downstream();
590   auto &req = downstream->request();
591   auto &balloc = downstream->get_block_allocator();
592 
593   for (auto &kv : req.fs.trailers()) {
594     kv.value = util::rstrip(balloc, kv.value);
595   }
596 
597   downstream->set_request_state(DownstreamState::MSG_COMPLETE);
598   rv = downstream->end_upload_data();
599   if (rv != 0) {
600     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
601       // Here both response and request were completed.  One of the
602       // reason why end_upload_data() failed is when we sent response
603       // in request phase hook.  We only delete and proceed to the
604       // next request handling (if we don't close the connection).  We
605       // first pause parser here just as we normally do, and call
606       // signal_write() to run on_write().
607       return HPE_PAUSED;
608     }
609     return -1;
610   }
611 
612   if (handler->get_http2_upgrade_allowed() &&
613       downstream->get_http2_upgrade_request() &&
614       handler->perform_http2_upgrade(upstream) != 0) {
615     if (LOG_ENABLED(INFO)) {
616       ULOG(INFO, upstream) << "HTTP Upgrade to HTTP/2 failed";
617     }
618   }
619 
620   // Stop further processing to complete this request
621   return HPE_PAUSED;
622 }
623 } // namespace
624 
625 // on_read() does not consume all available data in input buffer if
626 // one http request is fully received.
on_read()627 int HttpsUpstream::on_read() {
628   auto rb = handler_->get_rb();
629   auto rlimit = handler_->get_rlimit();
630   auto downstream = get_downstream();
631 
632   if (rb->rleft() == 0 || handler_->get_should_close_after_write()) {
633     return 0;
634   }
635 
636   // downstream can be nullptr here, because it is initialized in the
637   // callback chain called by llhttp_execute()
638   if (downstream && downstream->get_upgraded()) {
639 
640     auto rv = downstream->push_upload_data_chunk(rb->pos(), rb->rleft());
641 
642     if (rv != 0) {
643       return -1;
644     }
645 
646     rb->reset();
647     rlimit->startw();
648 
649     if (downstream->request_buf_full()) {
650       if (LOG_ENABLED(INFO)) {
651         ULOG(INFO, this) << "Downstream request buf is full";
652       }
653       pause_read(SHRPX_NO_BUFFER);
654 
655       return 0;
656     }
657 
658     return 0;
659   }
660 
661   if (downstream) {
662     // To avoid reading next pipelined request
663     switch (downstream->get_request_state()) {
664     case DownstreamState::INITIAL:
665     case DownstreamState::HEADER_COMPLETE:
666       break;
667     default:
668       return 0;
669     }
670   }
671 
672   // llhttp_execute() does nothing once it entered error state.
673   auto htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()),
674                                rb->rleft());
675 
676   if (htperr == HPE_PAUSED_UPGRADE &&
677       rb->pos() ==
678           reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_))) {
679     llhttp_resume_after_upgrade(&htp_);
680 
681     htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()),
682                             rb->rleft());
683   }
684 
685   auto nread =
686       htperr == HPE_OK
687           ? rb->rleft()
688           : reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_)) -
689                 rb->pos();
690   rb->drain(nread);
691   rlimit->startw();
692 
693   // Well, actually header length + some body bytes
694   current_header_length_ += nread;
695 
696   // Get downstream again because it may be initialized in http parser
697   // execution
698   downstream = get_downstream();
699 
700   if (htperr == HPE_PAUSED) {
701     // We may pause parser in htp_msg_completecb when both side are
702     // completed.  Signal write, so that we can run on_write().
703     if (downstream &&
704         downstream->get_request_state() == DownstreamState::MSG_COMPLETE &&
705         downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
706       handler_->signal_write();
707     }
708     return 0;
709   }
710 
711   if (htperr != HPE_OK) {
712     if (LOG_ENABLED(INFO)) {
713       ULOG(INFO, this) << "HTTP parse failure: "
714                        << "(" << llhttp_errno_name(htperr) << ") "
715                        << llhttp_get_error_reason(&htp_);
716     }
717 
718     if (downstream &&
719         downstream->get_response_state() != DownstreamState::INITIAL) {
720       handler_->set_should_close_after_write(true);
721       handler_->signal_write();
722       return 0;
723     }
724 
725     unsigned int status_code;
726 
727     if (htperr == HPE_INVALID_METHOD) {
728       status_code = 501;
729     } else if (downstream) {
730       status_code = downstream->response().http_status;
731       if (status_code == 0) {
732         if (downstream->get_request_state() == DownstreamState::CONNECT_FAIL) {
733           status_code = 502;
734         } else if (downstream->get_request_state() ==
735                    DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE) {
736           status_code = 431;
737         } else {
738           status_code = 400;
739         }
740       }
741     } else {
742       status_code = 400;
743     }
744 
745     error_reply(status_code);
746 
747     handler_->signal_write();
748 
749     return 0;
750   }
751 
752   // downstream can be NULL here.
753   if (downstream && downstream->request_buf_full()) {
754     if (LOG_ENABLED(INFO)) {
755       ULOG(INFO, this) << "Downstream request buffer is full";
756     }
757 
758     pause_read(SHRPX_NO_BUFFER);
759 
760     return 0;
761   }
762 
763   return 0;
764 }
765 
on_write()766 int HttpsUpstream::on_write() {
767   auto downstream = get_downstream();
768   if (!downstream) {
769     return 0;
770   }
771 
772   auto output = downstream->get_response_buf();
773   const auto &resp = downstream->response();
774 
775   if (output->rleft() > 0) {
776     return 0;
777   }
778 
779   // We need to postpone detachment until all data are sent so that
780   // we can notify nghttp2 library all data consumed.
781   if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
782     if (downstream->can_detach_downstream_connection()) {
783       // Keep-alive
784       downstream->detach_downstream_connection();
785     } else {
786       // Connection close
787       downstream->pop_downstream_connection();
788       // dconn was deleted
789     }
790     // We need this if response ends before request.
791     if (downstream->get_request_state() == DownstreamState::MSG_COMPLETE) {
792       delete_downstream();
793 
794       if (handler_->get_should_close_after_write()) {
795         return 0;
796       }
797 
798       auto conn = handler_->get_connection();
799       auto &upstreamconf = get_config()->conn.upstream;
800 
801       conn->rt.repeat = upstreamconf.timeout.idle_read;
802 
803       handler_->repeat_read_timer();
804 
805       return resume_read(SHRPX_NO_BUFFER, nullptr, 0);
806     } else {
807       // If the request is not complete, close the connection.
808       delete_downstream();
809 
810       handler_->set_should_close_after_write(true);
811 
812       return 0;
813     }
814   }
815 
816   return downstream->resume_read(SHRPX_NO_BUFFER, resp.unconsumed_body_length);
817 }
818 
on_event()819 int HttpsUpstream::on_event() { return 0; }
820 
get_client_handler() const821 ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; }
822 
pause_read(IOCtrlReason reason)823 void HttpsUpstream::pause_read(IOCtrlReason reason) {
824   ioctrl_.pause_read(reason);
825 }
826 
resume_read(IOCtrlReason reason,Downstream * downstream,size_t consumed)827 int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream,
828                                size_t consumed) {
829   // downstream could be nullptr
830   if (downstream && downstream->request_buf_full()) {
831     return 0;
832   }
833   if (ioctrl_.resume_read(reason)) {
834     // Process remaining data in input buffer here because these bytes
835     // are not notified by readcb until new data arrive.
836     llhttp_resume(&htp_);
837 
838     auto conn = handler_->get_connection();
839     ev_feed_event(conn->loop, &conn->rev, EV_READ);
840     return 0;
841   }
842 
843   return 0;
844 }
845 
downstream_read(DownstreamConnection * dconn)846 int HttpsUpstream::downstream_read(DownstreamConnection *dconn) {
847   auto downstream = dconn->get_downstream();
848   int rv;
849 
850   rv = downstream->on_read();
851 
852   if (rv == SHRPX_ERR_EOF) {
853     if (downstream->get_request_header_sent()) {
854       return downstream_eof(dconn);
855     }
856     return SHRPX_ERR_RETRY;
857   }
858 
859   if (rv == SHRPX_ERR_DCONN_CANCELED) {
860     downstream->pop_downstream_connection();
861     goto end;
862   }
863 
864   if (rv < 0) {
865     return downstream_error(dconn, Downstream::EVENT_ERROR);
866   }
867 
868   if (downstream->get_response_state() == DownstreamState::MSG_RESET) {
869     return -1;
870   }
871 
872   if (downstream->get_response_state() == DownstreamState::MSG_BAD_HEADER) {
873     error_reply(502);
874     downstream->pop_downstream_connection();
875     goto end;
876   }
877 
878   if (downstream->can_detach_downstream_connection()) {
879     // Keep-alive
880     downstream->detach_downstream_connection();
881   }
882 
883 end:
884   handler_->signal_write();
885 
886   return 0;
887 }
888 
downstream_write(DownstreamConnection * dconn)889 int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
890   int rv;
891   rv = dconn->on_write();
892   if (rv == SHRPX_ERR_NETWORK) {
893     return downstream_error(dconn, Downstream::EVENT_ERROR);
894   }
895 
896   if (rv != 0) {
897     return rv;
898   }
899 
900   return 0;
901 }
902 
downstream_eof(DownstreamConnection * dconn)903 int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
904   auto downstream = dconn->get_downstream();
905 
906   if (LOG_ENABLED(INFO)) {
907     DCLOG(INFO, dconn) << "EOF";
908   }
909 
910   if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
911     goto end;
912   }
913 
914   if (downstream->get_response_state() == DownstreamState::HEADER_COMPLETE) {
915     // Server may indicate the end of the request by EOF
916     if (LOG_ENABLED(INFO)) {
917       DCLOG(INFO, dconn) << "The end of the response body was indicated by "
918                          << "EOF";
919     }
920     on_downstream_body_complete(downstream);
921     downstream->set_response_state(DownstreamState::MSG_COMPLETE);
922     downstream->pop_downstream_connection();
923     goto end;
924   }
925 
926   if (downstream->get_response_state() == DownstreamState::INITIAL) {
927     // we did not send any response headers, so we can reply error
928     // message.
929     if (LOG_ENABLED(INFO)) {
930       DCLOG(INFO, dconn) << "Return error reply";
931     }
932     error_reply(502);
933     downstream->pop_downstream_connection();
934     goto end;
935   }
936 
937   // Otherwise, we don't know how to recover from this situation. Just
938   // drop connection.
939   return -1;
940 end:
941   handler_->signal_write();
942 
943   return 0;
944 }
945 
downstream_error(DownstreamConnection * dconn,int events)946 int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
947   auto downstream = dconn->get_downstream();
948   if (LOG_ENABLED(INFO)) {
949     if (events & Downstream::EVENT_ERROR) {
950       DCLOG(INFO, dconn) << "Network error/general error";
951     } else {
952       DCLOG(INFO, dconn) << "Timeout";
953     }
954   }
955   if (downstream->get_response_state() != DownstreamState::INITIAL) {
956     return -1;
957   }
958 
959   unsigned int status;
960   if (events & Downstream::EVENT_TIMEOUT) {
961     if (downstream->get_request_header_sent()) {
962       status = 504;
963     } else {
964       status = 408;
965     }
966   } else {
967     status = 502;
968   }
969   error_reply(status);
970 
971   downstream->pop_downstream_connection();
972 
973   handler_->signal_write();
974   return 0;
975 }
976 
send_reply(Downstream * downstream,const uint8_t * body,size_t bodylen)977 int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
978                               size_t bodylen) {
979   const auto &req = downstream->request();
980   auto &resp = downstream->response();
981   auto &balloc = downstream->get_block_allocator();
982   auto config = get_config();
983   auto &httpconf = config->http;
984 
985   auto connection_close = false;
986 
987   auto worker = handler_->get_worker();
988 
989   if (httpconf.max_requests <= num_requests_ ||
990       worker->get_graceful_shutdown()) {
991     resp.fs.add_header_token(StringRef::from_lit("connection"),
992                              StringRef::from_lit("close"), false,
993                              http2::HD_CONNECTION);
994     connection_close = true;
995   } else if (req.http_major <= 0 ||
996              (req.http_major == 1 && req.http_minor == 0)) {
997     connection_close = true;
998   } else {
999     auto c = resp.fs.header(http2::HD_CONNECTION);
1000     if (c && util::strieq_l("close", c->value)) {
1001       connection_close = true;
1002     }
1003   }
1004 
1005   if (connection_close) {
1006     resp.connection_close = true;
1007     handler_->set_should_close_after_write(true);
1008   }
1009 
1010   auto output = downstream->get_response_buf();
1011 
1012   output->append("HTTP/1.1 ");
1013   output->append(http2::stringify_status(balloc, resp.http_status));
1014   output->append(' ');
1015   output->append(http2::get_reason_phrase(resp.http_status));
1016   output->append("\r\n");
1017 
1018   for (auto &kv : resp.fs.headers()) {
1019     if (kv.name.empty() || kv.name[0] == ':') {
1020       continue;
1021     }
1022     http2::capitalize(output, kv.name);
1023     output->append(": ");
1024     output->append(kv.value);
1025     output->append("\r\n");
1026   }
1027 
1028   if (!resp.fs.header(http2::HD_SERVER)) {
1029     output->append("Server: ");
1030     output->append(config->http.server_name);
1031     output->append("\r\n");
1032   }
1033 
1034   for (auto &p : httpconf.add_response_headers) {
1035     output->append(p.name);
1036     output->append(": ");
1037     output->append(p.value);
1038     output->append("\r\n");
1039   }
1040 
1041   output->append("\r\n");
1042 
1043   output->append(body, bodylen);
1044 
1045   downstream->response_sent_body_length += bodylen;
1046   downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1047 
1048   return 0;
1049 }
1050 
error_reply(unsigned int status_code)1051 void HttpsUpstream::error_reply(unsigned int status_code) {
1052   auto downstream = get_downstream();
1053 
1054   if (!downstream) {
1055     attach_downstream(
1056         std::make_unique<Downstream>(this, handler_->get_mcpool(), 1));
1057     downstream = get_downstream();
1058   }
1059 
1060   auto &resp = downstream->response();
1061   auto &balloc = downstream->get_block_allocator();
1062 
1063   auto html = http::create_error_html(balloc, status_code);
1064 
1065   resp.http_status = status_code;
1066   // we are going to close connection for both frontend and backend in
1067   // error condition.  This is safest option.
1068   resp.connection_close = true;
1069   handler_->set_should_close_after_write(true);
1070 
1071   auto output = downstream->get_response_buf();
1072 
1073   output->append("HTTP/1.1 ");
1074   output->append(http2::stringify_status(balloc, status_code));
1075   output->append(' ');
1076   output->append(http2::get_reason_phrase(status_code));
1077   output->append("\r\nServer: ");
1078   output->append(get_config()->http.server_name);
1079   output->append("\r\nContent-Length: ");
1080   std::array<uint8_t, NGHTTP2_MAX_UINT64_DIGITS> intbuf;
1081   output->append(StringRef{std::begin(intbuf),
1082                            util::utos(std::begin(intbuf), html.size())});
1083   output->append("\r\nDate: ");
1084   auto lgconf = log_config();
1085   lgconf->update_tstamp(std::chrono::system_clock::now());
1086   output->append(lgconf->tstamp->time_http);
1087   output->append("\r\nContent-Type: text/html; "
1088                  "charset=UTF-8\r\nConnection: close\r\n\r\n");
1089   output->append(html);
1090 
1091   downstream->response_sent_body_length += html.size();
1092   downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1093 }
1094 
attach_downstream(std::unique_ptr<Downstream> downstream)1095 void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) {
1096   assert(!downstream_);
1097   downstream_ = std::move(downstream);
1098 }
1099 
delete_downstream()1100 void HttpsUpstream::delete_downstream() {
1101   if (downstream_ && downstream_->accesslog_ready()) {
1102     handler_->write_accesslog(downstream_.get());
1103   }
1104 
1105   downstream_.reset();
1106 }
1107 
get_downstream() const1108 Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); }
1109 
pop_downstream()1110 std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
1111   return std::unique_ptr<Downstream>(downstream_.release());
1112 }
1113 
on_downstream_header_complete(Downstream * downstream)1114 int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
1115   if (LOG_ENABLED(INFO)) {
1116     if (downstream->get_non_final_response()) {
1117       DLOG(INFO, downstream) << "HTTP non-final response header";
1118     } else {
1119       DLOG(INFO, downstream) << "HTTP response header completed";
1120     }
1121   }
1122 
1123   const auto &req = downstream->request();
1124   auto &resp = downstream->response();
1125   auto &balloc = downstream->get_block_allocator();
1126   auto dconn = downstream->get_downstream_connection();
1127   // dconn might be nullptr if this is non-final response from mruby.
1128 
1129   if (downstream->get_non_final_response() &&
1130       !downstream->supports_non_final_response()) {
1131     resp.fs.clear_headers();
1132     return 0;
1133   }
1134 
1135 #ifdef HAVE_MRUBY
1136   if (!downstream->get_non_final_response()) {
1137     assert(dconn);
1138     const auto &group = dconn->get_downstream_addr_group();
1139     if (group) {
1140       const auto &dmruby_ctx = group->shared_addr->mruby_ctx;
1141 
1142       if (dmruby_ctx->run_on_response_proc(downstream) != 0) {
1143         error_reply(500);
1144         return -1;
1145       }
1146 
1147       if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1148         return -1;
1149       }
1150     }
1151 
1152     auto worker = handler_->get_worker();
1153     auto mruby_ctx = worker->get_mruby_context();
1154 
1155     if (mruby_ctx->run_on_response_proc(downstream) != 0) {
1156       error_reply(500);
1157       return -1;
1158     }
1159 
1160     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1161       return -1;
1162     }
1163   }
1164 #endif // HAVE_MRUBY
1165 
1166   auto connect_method = req.method == HTTP_CONNECT;
1167 
1168   auto buf = downstream->get_response_buf();
1169   buf->append("HTTP/");
1170   buf->append('0' + req.http_major);
1171   buf->append('.');
1172   buf->append('0' + req.http_minor);
1173   buf->append(' ');
1174   if (req.connect_proto != ConnectProto::NONE && downstream->get_upgraded()) {
1175     buf->append(http2::stringify_status(balloc, 101));
1176     buf->append(' ');
1177     buf->append(http2::get_reason_phrase(101));
1178   } else {
1179     buf->append(http2::stringify_status(balloc, resp.http_status));
1180     buf->append(' ');
1181     buf->append(http2::get_reason_phrase(resp.http_status));
1182   }
1183   buf->append("\r\n");
1184 
1185   auto config = get_config();
1186   auto &httpconf = config->http;
1187 
1188   if (!config->http2_proxy && !httpconf.no_location_rewrite) {
1189     downstream->rewrite_location_response_header(
1190         get_client_handler()->get_upstream_scheme());
1191   }
1192 
1193   if (downstream->get_non_final_response()) {
1194     http2::build_http1_headers_from_headers(buf, resp.fs.headers(),
1195                                             http2::HDOP_STRIP_ALL);
1196 
1197     buf->append("\r\n");
1198 
1199     if (LOG_ENABLED(INFO)) {
1200       log_response_headers(buf);
1201     }
1202 
1203     resp.fs.clear_headers();
1204 
1205     return 0;
1206   }
1207 
1208   auto build_flags = (http2::HDOP_STRIP_ALL & ~http2::HDOP_STRIP_VIA) |
1209                      (!http2::legacy_http1(req.http_major, req.http_minor)
1210                           ? 0
1211                           : http2::HDOP_STRIP_TRANSFER_ENCODING);
1212 
1213   http2::build_http1_headers_from_headers(buf, resp.fs.headers(), build_flags);
1214 
1215   auto worker = handler_->get_worker();
1216 
1217   // after graceful shutdown commenced, add connection: close header
1218   // field.
1219   if (httpconf.max_requests <= num_requests_ ||
1220       worker->get_graceful_shutdown()) {
1221     resp.connection_close = true;
1222   }
1223 
1224   // We check downstream->get_response_connection_close() in case when
1225   // the Content-Length is not available.
1226   if (!req.connection_close && !resp.connection_close) {
1227     if (req.http_major <= 0 || req.http_minor <= 0) {
1228       // We add this header for HTTP/1.0 or HTTP/0.9 clients
1229       buf->append("Connection: Keep-Alive\r\n");
1230     }
1231   } else if (!downstream->get_upgraded()) {
1232     buf->append("Connection: close\r\n");
1233   }
1234 
1235   if (!connect_method && downstream->get_upgraded()) {
1236     if (req.connect_proto == ConnectProto::WEBSOCKET &&
1237         resp.http_status / 100 == 2) {
1238       buf->append("Upgrade: websocket\r\nConnection: Upgrade\r\n");
1239       auto key = req.fs.header(http2::HD_SEC_WEBSOCKET_KEY);
1240       if (!key || key->value.size() != base64::encode_length(16)) {
1241         return -1;
1242       }
1243       std::array<uint8_t, base64::encode_length(20)> out;
1244       auto accept = http2::make_websocket_accept_token(out.data(), key->value);
1245       if (accept.empty()) {
1246         return -1;
1247       }
1248       buf->append("Sec-WebSocket-Accept: ");
1249       buf->append(accept);
1250       buf->append("\r\n");
1251     } else {
1252       auto connection = resp.fs.header(http2::HD_CONNECTION);
1253       if (connection) {
1254         buf->append("Connection: ");
1255         buf->append((*connection).value);
1256         buf->append("\r\n");
1257       }
1258 
1259       auto upgrade = resp.fs.header(http2::HD_UPGRADE);
1260       if (upgrade) {
1261         buf->append("Upgrade: ");
1262         buf->append((*upgrade).value);
1263         buf->append("\r\n");
1264       }
1265     }
1266   }
1267 
1268   if (!resp.fs.header(http2::HD_ALT_SVC)) {
1269     // We won't change or alter alt-svc from backend for now
1270     if (!httpconf.altsvcs.empty()) {
1271       buf->append("Alt-Svc: ");
1272       buf->append(httpconf.altsvc_header_value);
1273       buf->append("\r\n");
1274     }
1275   }
1276 
1277   if (!config->http2_proxy && !httpconf.no_server_rewrite) {
1278     buf->append("Server: ");
1279     buf->append(httpconf.server_name);
1280     buf->append("\r\n");
1281   } else {
1282     auto server = resp.fs.header(http2::HD_SERVER);
1283     if (server) {
1284       buf->append("Server: ");
1285       buf->append((*server).value);
1286       buf->append("\r\n");
1287     }
1288   }
1289 
1290   if (req.method != HTTP_CONNECT || !downstream->get_upgraded()) {
1291     auto affinity_cookie = downstream->get_affinity_cookie_to_send();
1292     if (affinity_cookie) {
1293       auto &group = dconn->get_downstream_addr_group();
1294       auto &shared_addr = group->shared_addr;
1295       auto &cookieconf = shared_addr->affinity.cookie;
1296       auto secure =
1297           http::require_cookie_secure_attribute(cookieconf.secure, req.scheme);
1298       auto cookie_str = http::create_affinity_cookie(
1299           balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure);
1300       buf->append("Set-Cookie: ");
1301       buf->append(cookie_str);
1302       buf->append("\r\n");
1303     }
1304   }
1305 
1306   auto via = resp.fs.header(http2::HD_VIA);
1307   if (httpconf.no_via) {
1308     if (via) {
1309       buf->append("Via: ");
1310       buf->append((*via).value);
1311       buf->append("\r\n");
1312     }
1313   } else {
1314     buf->append("Via: ");
1315     if (via) {
1316       buf->append((*via).value);
1317       buf->append(", ");
1318     }
1319     std::array<char, 16> viabuf;
1320     auto end = http::create_via_header_value(viabuf.data(), resp.http_major,
1321                                              resp.http_minor);
1322     buf->append(viabuf.data(), end - std::begin(viabuf));
1323     buf->append("\r\n");
1324   }
1325 
1326   for (auto &p : httpconf.add_response_headers) {
1327     buf->append(p.name);
1328     buf->append(": ");
1329     buf->append(p.value);
1330     buf->append("\r\n");
1331   }
1332 
1333   buf->append("\r\n");
1334 
1335   if (LOG_ENABLED(INFO)) {
1336     log_response_headers(buf);
1337   }
1338 
1339   return 0;
1340 }
1341 
on_downstream_body(Downstream * downstream,const uint8_t * data,size_t len,bool flush)1342 int HttpsUpstream::on_downstream_body(Downstream *downstream,
1343                                       const uint8_t *data, size_t len,
1344                                       bool flush) {
1345   if (len == 0) {
1346     return 0;
1347   }
1348   auto output = downstream->get_response_buf();
1349   if (downstream->get_chunked_response()) {
1350     output->append(util::utox(len));
1351     output->append("\r\n");
1352   }
1353   output->append(data, len);
1354 
1355   downstream->response_sent_body_length += len;
1356 
1357   if (downstream->get_chunked_response()) {
1358     output->append("\r\n");
1359   }
1360   return 0;
1361 }
1362 
on_downstream_body_complete(Downstream * downstream)1363 int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
1364   const auto &req = downstream->request();
1365   auto &resp = downstream->response();
1366 
1367   if (downstream->get_chunked_response()) {
1368     auto output = downstream->get_response_buf();
1369     const auto &trailers = resp.fs.trailers();
1370     if (trailers.empty()) {
1371       output->append("0\r\n\r\n");
1372     } else {
1373       output->append("0\r\n");
1374       http2::build_http1_headers_from_headers(output, trailers,
1375                                               http2::HDOP_STRIP_ALL);
1376       output->append("\r\n");
1377     }
1378   }
1379   if (LOG_ENABLED(INFO)) {
1380     DLOG(INFO, downstream) << "HTTP response completed";
1381   }
1382 
1383   if (!downstream->validate_response_recv_body_length()) {
1384     resp.connection_close = true;
1385   }
1386 
1387   if (req.connection_close || resp.connection_close ||
1388       // To avoid to stall upload body
1389       downstream->get_request_state() != DownstreamState::MSG_COMPLETE) {
1390     auto handler = get_client_handler();
1391     handler->set_should_close_after_write(true);
1392   }
1393   return 0;
1394 }
1395 
on_downstream_abort_request(Downstream * downstream,unsigned int status_code)1396 int HttpsUpstream::on_downstream_abort_request(Downstream *downstream,
1397                                                unsigned int status_code) {
1398   error_reply(status_code);
1399   handler_->signal_write();
1400   return 0;
1401 }
1402 
on_downstream_abort_request_with_https_redirect(Downstream * downstream)1403 int HttpsUpstream::on_downstream_abort_request_with_https_redirect(
1404     Downstream *downstream) {
1405   redirect_to_https(downstream);
1406   handler_->signal_write();
1407   return 0;
1408 }
1409 
redirect_to_https(Downstream * downstream)1410 int HttpsUpstream::redirect_to_https(Downstream *downstream) {
1411   auto &req = downstream->request();
1412   if (req.method == HTTP_CONNECT || req.scheme != "http" ||
1413       req.authority.empty()) {
1414     error_reply(400);
1415     return 0;
1416   }
1417 
1418   auto authority = util::extract_host(req.authority);
1419   if (authority.empty()) {
1420     error_reply(400);
1421     return 0;
1422   }
1423 
1424   auto &balloc = downstream->get_block_allocator();
1425   auto config = get_config();
1426   auto &httpconf = config->http;
1427 
1428   StringRef loc;
1429   if (httpconf.redirect_https_port == StringRef::from_lit("443")) {
1430     loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
1431                             req.path);
1432   } else {
1433     loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
1434                             StringRef::from_lit(":"),
1435                             httpconf.redirect_https_port, req.path);
1436   }
1437 
1438   auto &resp = downstream->response();
1439   resp.http_status = 308;
1440   resp.fs.add_header_token(StringRef::from_lit("location"), loc, false,
1441                            http2::HD_LOCATION);
1442   resp.fs.add_header_token(StringRef::from_lit("connection"),
1443                            StringRef::from_lit("close"), false,
1444                            http2::HD_CONNECTION);
1445 
1446   return send_reply(downstream, nullptr, 0);
1447 }
1448 
log_response_headers(DefaultMemchunks * buf) const1449 void HttpsUpstream::log_response_headers(DefaultMemchunks *buf) const {
1450   std::string nhdrs;
1451   for (auto chunk = buf->head; chunk; chunk = chunk->next) {
1452     nhdrs.append(chunk->pos, chunk->last);
1453   }
1454   if (log_config()->errorlog_tty) {
1455     nhdrs = http::colorizeHeaders(nhdrs.c_str());
1456   }
1457   ULOG(INFO, this) << "HTTP response headers\n" << nhdrs;
1458 }
1459 
on_handler_delete()1460 void HttpsUpstream::on_handler_delete() {
1461   if (downstream_ && downstream_->accesslog_ready()) {
1462     handler_->write_accesslog(downstream_.get());
1463   }
1464 }
1465 
on_downstream_reset(Downstream * downstream,bool no_retry)1466 int HttpsUpstream::on_downstream_reset(Downstream *downstream, bool no_retry) {
1467   int rv;
1468   std::unique_ptr<DownstreamConnection> dconn;
1469 
1470   assert(downstream == downstream_.get());
1471 
1472   downstream_->pop_downstream_connection();
1473 
1474   if (!downstream_->request_submission_ready()) {
1475     switch (downstream_->get_response_state()) {
1476     case DownstreamState::MSG_COMPLETE:
1477       // We have got all response body already.  Send it off.
1478       return 0;
1479     case DownstreamState::INITIAL:
1480       if (on_downstream_abort_request(downstream_.get(), 502) != 0) {
1481         return -1;
1482       }
1483       return 0;
1484     default:
1485       break;
1486     }
1487     // Return error so that caller can delete handler
1488     return -1;
1489   }
1490 
1491   downstream_->add_retry();
1492 
1493   rv = 0;
1494 
1495   if (no_retry || downstream_->no_more_retry()) {
1496     goto fail;
1497   }
1498 
1499   for (;;) {
1500     auto dconn = handler_->get_downstream_connection(rv, downstream_.get());
1501     if (!dconn) {
1502       goto fail;
1503     }
1504 
1505     rv = downstream_->attach_downstream_connection(std::move(dconn));
1506     if (rv == 0) {
1507       break;
1508     }
1509   }
1510 
1511   rv = downstream_->push_request_headers();
1512   if (rv != 0) {
1513     goto fail;
1514   }
1515 
1516   return 0;
1517 
1518 fail:
1519   if (rv == SHRPX_ERR_TLS_REQUIRED) {
1520     rv = on_downstream_abort_request_with_https_redirect(downstream);
1521   } else {
1522     rv = on_downstream_abort_request(downstream_.get(), 502);
1523   }
1524   if (rv != 0) {
1525     return -1;
1526   }
1527   downstream_->pop_downstream_connection();
1528 
1529   return 0;
1530 }
1531 
initiate_push(Downstream * downstream,const StringRef & uri)1532 int HttpsUpstream::initiate_push(Downstream *downstream, const StringRef &uri) {
1533   return 0;
1534 }
1535 
response_riovec(struct iovec * iov,int iovcnt) const1536 int HttpsUpstream::response_riovec(struct iovec *iov, int iovcnt) const {
1537   if (!downstream_) {
1538     return 0;
1539   }
1540 
1541   auto buf = downstream_->get_response_buf();
1542 
1543   return buf->riovec(iov, iovcnt);
1544 }
1545 
response_drain(size_t n)1546 void HttpsUpstream::response_drain(size_t n) {
1547   if (!downstream_) {
1548     return;
1549   }
1550 
1551   auto buf = downstream_->get_response_buf();
1552 
1553   buf->drain(n);
1554 }
1555 
response_empty() const1556 bool HttpsUpstream::response_empty() const {
1557   if (!downstream_) {
1558     return true;
1559   }
1560 
1561   auto buf = downstream_->get_response_buf();
1562 
1563   return buf->rleft() == 0;
1564 }
1565 
1566 Downstream *
on_downstream_push_promise(Downstream * downstream,int32_t promised_stream_id)1567 HttpsUpstream::on_downstream_push_promise(Downstream *downstream,
1568                                           int32_t promised_stream_id) {
1569   return nullptr;
1570 }
1571 
on_downstream_push_promise_complete(Downstream * downstream,Downstream * promised_downstream)1572 int HttpsUpstream::on_downstream_push_promise_complete(
1573     Downstream *downstream, Downstream *promised_downstream) {
1574   return -1;
1575 }
1576 
push_enabled() const1577 bool HttpsUpstream::push_enabled() const { return false; }
1578 
cancel_premature_downstream(Downstream * promised_downstream)1579 void HttpsUpstream::cancel_premature_downstream(
1580     Downstream *promised_downstream) {}
1581 
1582 } // namespace shrpx
1583