• 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 
350   auto lgconf = log_config();
351   lgconf->update_tstamp(std::chrono::system_clock::now());
352   req.tstamp = lgconf->tstamp;
353 
354   req.http_major = htp->http_major;
355   req.http_minor = htp->http_minor;
356 
357   req.connection_close = !llhttp_should_keep_alive(htp);
358 
359   handler->stop_read_timer();
360 
361   auto method = req.method;
362 
363   if (LOG_ENABLED(INFO)) {
364     std::stringstream ss;
365     ss << http2::to_method_string(method) << " "
366        << (method == HTTP_CONNECT ? req.authority : req.path) << " "
367        << "HTTP/" << req.http_major << "." << req.http_minor << "\n";
368 
369     for (const auto &kv : req.fs.headers()) {
370       if (kv.name == "authorization") {
371         ss << TTY_HTTP_HD << kv.name << TTY_RST << ": <redacted>\n";
372         continue;
373       }
374       ss << TTY_HTTP_HD << kv.name << TTY_RST << ": " << kv.value << "\n";
375     }
376 
377     ULOG(INFO, upstream) << "HTTP request headers\n" << ss.str();
378   }
379 
380   // set content-length if method is not CONNECT, and no
381   // transfer-encoding is given.  If transfer-encoding is given, leave
382   // req.fs.content_length to -1.
383   if (method != HTTP_CONNECT && !req.fs.header(http2::HD_TRANSFER_ENCODING)) {
384     // llhttp sets 0 to htp->content_length if there is no
385     // content-length header field.  If we don't have both
386     // transfer-encoding and content-length header field, we assume
387     // that there is no request body.
388     req.fs.content_length = htp->content_length;
389   }
390 
391   auto host = req.fs.header(http2::HD_HOST);
392 
393   if (req.http_major > 1 || req.http_minor > 1) {
394     req.http_major = 1;
395     req.http_minor = 1;
396     return -1;
397   }
398 
399   if (req.http_major == 1 && req.http_minor == 1 && !host) {
400     return -1;
401   }
402 
403   if (host) {
404     const auto &value = host->value;
405     // Not allow at least '"' or '\' in host.  They are illegal in
406     // authority component, also they cause headaches when we put them
407     // in quoted-string.
408     if (std::find_if(std::begin(value), std::end(value), [](char c) {
409           return c == '"' || c == '\\';
410         }) != std::end(value)) {
411       return -1;
412     }
413   }
414 
415   downstream->inspect_http1_request();
416 
417   auto faddr = handler->get_upstream_addr();
418   auto config = get_config();
419 
420   if (method != HTTP_CONNECT) {
421     http_parser_url u{};
422     rv = http_parser_parse_url(req.path.c_str(), req.path.size(), 0, &u);
423     if (rv != 0) {
424       // Expect to respond with 400 bad request
425       return -1;
426     }
427     // checking UF_HOST could be redundant, but just in case ...
428     if (!(u.field_set & (1 << UF_SCHEMA)) || !(u.field_set & (1 << UF_HOST))) {
429       req.no_authority = true;
430 
431       if (method == HTTP_OPTIONS && req.path == StringRef::from_lit("*")) {
432         req.path = StringRef{};
433       } else {
434         req.path = http2::rewrite_clean_path(balloc, req.path);
435       }
436 
437       if (host) {
438         req.authority = host->value;
439       }
440 
441       if (handler->get_ssl()) {
442         req.scheme = StringRef::from_lit("https");
443       } else {
444         req.scheme = StringRef::from_lit("http");
445       }
446     } else {
447       rewrite_request_host_path_from_uri(balloc, req, req.path, u);
448     }
449   }
450 
451   downstream->set_request_state(DownstreamState::HEADER_COMPLETE);
452 
453   auto &resp = downstream->response();
454 
455   if (config->http.require_http_scheme &&
456       !http::check_http_scheme(req.scheme, handler->get_ssl() != nullptr)) {
457     resp.http_status = 400;
458     return -1;
459   }
460 
461 #ifdef HAVE_MRUBY
462   auto worker = handler->get_worker();
463   auto mruby_ctx = worker->get_mruby_context();
464 
465   if (mruby_ctx->run_on_request_proc(downstream) != 0) {
466     resp.http_status = 500;
467     return -1;
468   }
469 #endif // HAVE_MRUBY
470 
471   // mruby hook may change method value
472 
473   if (req.no_authority && config->http2_proxy &&
474       faddr->alt_mode == UpstreamAltMode::NONE) {
475     // Request URI should be absolute-form for client proxy mode
476     return -1;
477   }
478 
479   if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
480     return 0;
481   }
482 
483 #ifdef HAVE_MRUBY
484   DownstreamConnection *dconn_ptr;
485 #endif // HAVE_MRUBY
486 
487   for (;;) {
488     auto dconn = handler->get_downstream_connection(rv, downstream);
489 
490     if (!dconn) {
491       if (rv == SHRPX_ERR_TLS_REQUIRED) {
492         upstream->redirect_to_https(downstream);
493       }
494       downstream->set_request_state(DownstreamState::CONNECT_FAIL);
495       return -1;
496     }
497 
498 #ifdef HAVE_MRUBY
499     dconn_ptr = dconn.get();
500 #endif // HAVE_MRUBY
501     if (downstream->attach_downstream_connection(std::move(dconn)) == 0) {
502       break;
503     }
504   }
505 
506 #ifdef HAVE_MRUBY
507   const auto &group = dconn_ptr->get_downstream_addr_group();
508   if (group) {
509     const auto &dmruby_ctx = group->shared_addr->mruby_ctx;
510 
511     if (dmruby_ctx->run_on_request_proc(downstream) != 0) {
512       resp.http_status = 500;
513       return -1;
514     }
515 
516     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
517       return 0;
518     }
519   }
520 #endif // HAVE_MRUBY
521 
522   rv = downstream->push_request_headers();
523 
524   if (rv != 0) {
525     return -1;
526   }
527 
528   if (faddr->alt_mode != UpstreamAltMode::NONE) {
529     // Normally, we forward expect: 100-continue to backend server,
530     // and let them decide whether responds with 100 Continue or not.
531     // For alternative mode, we have no backend, so just send 100
532     // Continue here to make the client happy.
533     if (downstream->get_expect_100_continue()) {
534       auto output = downstream->get_response_buf();
535       constexpr auto res = StringRef::from_lit("HTTP/1.1 100 Continue\r\n\r\n");
536       output->append(res);
537       handler->signal_write();
538     }
539   }
540 
541   return 0;
542 }
543 } // namespace
544 
545 namespace {
htp_bodycb(llhttp_t * htp,const char * data,size_t len)546 int htp_bodycb(llhttp_t *htp, const char *data, size_t len) {
547   int rv;
548   auto upstream = static_cast<HttpsUpstream *>(htp->data);
549   auto downstream = upstream->get_downstream();
550   rv = downstream->push_upload_data_chunk(
551       reinterpret_cast<const uint8_t *>(data), len);
552   if (rv != 0) {
553     // Ignore error if response has been completed.  We will end up in
554     // htp_msg_completecb, and request will end gracefully.
555     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
556       return 0;
557     }
558 
559     llhttp_set_error_reason(htp, "could not process request body");
560     return HPE_USER;
561   }
562   return 0;
563 }
564 } // namespace
565 
566 namespace {
htp_msg_completecb(llhttp_t * htp)567 int htp_msg_completecb(llhttp_t *htp) {
568   int rv;
569   auto upstream = static_cast<HttpsUpstream *>(htp->data);
570   if (LOG_ENABLED(INFO)) {
571     ULOG(INFO, upstream) << "HTTP request completed";
572   }
573   auto handler = upstream->get_client_handler();
574   auto downstream = upstream->get_downstream();
575   auto &req = downstream->request();
576   auto &balloc = downstream->get_block_allocator();
577 
578   for (auto &kv : req.fs.trailers()) {
579     kv.value = util::rstrip(balloc, kv.value);
580   }
581 
582   downstream->set_request_state(DownstreamState::MSG_COMPLETE);
583   rv = downstream->end_upload_data();
584   if (rv != 0) {
585     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
586       // Here both response and request were completed.  One of the
587       // reason why end_upload_data() failed is when we sent response
588       // in request phase hook.  We only delete and proceed to the
589       // next request handling (if we don't close the connection).  We
590       // first pause parser here just as we normally do, and call
591       // signal_write() to run on_write().
592       return HPE_PAUSED;
593     }
594     return -1;
595   }
596 
597   if (handler->get_http2_upgrade_allowed() &&
598       downstream->get_http2_upgrade_request() &&
599       handler->perform_http2_upgrade(upstream) != 0) {
600     if (LOG_ENABLED(INFO)) {
601       ULOG(INFO, upstream) << "HTTP Upgrade to HTTP/2 failed";
602     }
603   }
604 
605   // Stop further processing to complete this request
606   return HPE_PAUSED;
607 }
608 } // namespace
609 
610 // on_read() does not consume all available data in input buffer if
611 // one http request is fully received.
on_read()612 int HttpsUpstream::on_read() {
613   auto rb = handler_->get_rb();
614   auto rlimit = handler_->get_rlimit();
615   auto downstream = get_downstream();
616 
617   if (rb->rleft() == 0 || handler_->get_should_close_after_write()) {
618     return 0;
619   }
620 
621   // downstream can be nullptr here, because it is initialized in the
622   // callback chain called by llhttp_execute()
623   if (downstream && downstream->get_upgraded()) {
624 
625     auto rv = downstream->push_upload_data_chunk(rb->pos(), rb->rleft());
626 
627     if (rv != 0) {
628       return -1;
629     }
630 
631     rb->reset();
632     rlimit->startw();
633 
634     if (downstream->request_buf_full()) {
635       if (LOG_ENABLED(INFO)) {
636         ULOG(INFO, this) << "Downstream request buf is full";
637       }
638       pause_read(SHRPX_NO_BUFFER);
639 
640       return 0;
641     }
642 
643     return 0;
644   }
645 
646   if (downstream) {
647     // To avoid reading next pipelined request
648     switch (downstream->get_request_state()) {
649     case DownstreamState::INITIAL:
650     case DownstreamState::HEADER_COMPLETE:
651       break;
652     default:
653       return 0;
654     }
655   }
656 
657   // llhttp_execute() does nothing once it entered error state.
658   auto htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()),
659                                rb->rleft());
660 
661   if (htperr == HPE_PAUSED_UPGRADE &&
662       rb->pos() ==
663           reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_))) {
664     llhttp_resume_after_upgrade(&htp_);
665 
666     htperr = llhttp_execute(&htp_, reinterpret_cast<const char *>(rb->pos()),
667                             rb->rleft());
668   }
669 
670   auto nread =
671       htperr == HPE_OK
672           ? rb->rleft()
673           : reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_)) -
674                 rb->pos();
675   rb->drain(nread);
676   rlimit->startw();
677 
678   // Well, actually header length + some body bytes
679   current_header_length_ += nread;
680 
681   // Get downstream again because it may be initialized in http parser
682   // execution
683   downstream = get_downstream();
684 
685   if (htperr == HPE_PAUSED) {
686     // We may pause parser in htp_msg_completecb when both side are
687     // completed.  Signal write, so that we can run on_write().
688     if (downstream &&
689         downstream->get_request_state() == DownstreamState::MSG_COMPLETE &&
690         downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
691       handler_->signal_write();
692     }
693     return 0;
694   }
695 
696   if (htperr != HPE_OK) {
697     if (LOG_ENABLED(INFO)) {
698       ULOG(INFO, this) << "HTTP parse failure: "
699                        << "(" << llhttp_errno_name(htperr) << ") "
700                        << llhttp_get_error_reason(&htp_);
701     }
702 
703     if (downstream &&
704         downstream->get_response_state() != DownstreamState::INITIAL) {
705       handler_->set_should_close_after_write(true);
706       handler_->signal_write();
707       return 0;
708     }
709 
710     unsigned int status_code;
711 
712     if (htperr == HPE_INVALID_METHOD) {
713       status_code = 501;
714     } else if (downstream) {
715       status_code = downstream->response().http_status;
716       if (status_code == 0) {
717         if (downstream->get_request_state() == DownstreamState::CONNECT_FAIL) {
718           status_code = 502;
719         } else if (downstream->get_request_state() ==
720                    DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE) {
721           status_code = 431;
722         } else {
723           status_code = 400;
724         }
725       }
726     } else {
727       status_code = 400;
728     }
729 
730     error_reply(status_code);
731 
732     handler_->signal_write();
733 
734     return 0;
735   }
736 
737   // downstream can be NULL here.
738   if (downstream && downstream->request_buf_full()) {
739     if (LOG_ENABLED(INFO)) {
740       ULOG(INFO, this) << "Downstream request buffer is full";
741     }
742 
743     pause_read(SHRPX_NO_BUFFER);
744 
745     return 0;
746   }
747 
748   return 0;
749 }
750 
on_write()751 int HttpsUpstream::on_write() {
752   auto downstream = get_downstream();
753   if (!downstream) {
754     return 0;
755   }
756 
757   auto output = downstream->get_response_buf();
758   const auto &resp = downstream->response();
759 
760   if (output->rleft() > 0) {
761     return 0;
762   }
763 
764   // We need to postpone detachment until all data are sent so that
765   // we can notify nghttp2 library all data consumed.
766   if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
767     if (downstream->can_detach_downstream_connection()) {
768       // Keep-alive
769       downstream->detach_downstream_connection();
770     } else {
771       // Connection close
772       downstream->pop_downstream_connection();
773       // dconn was deleted
774     }
775     // We need this if response ends before request.
776     if (downstream->get_request_state() == DownstreamState::MSG_COMPLETE) {
777       delete_downstream();
778 
779       if (handler_->get_should_close_after_write()) {
780         return 0;
781       }
782 
783       auto conn = handler_->get_connection();
784       auto &upstreamconf = get_config()->conn.upstream;
785 
786       conn->rt.repeat = upstreamconf.timeout.idle_read;
787 
788       handler_->repeat_read_timer();
789 
790       return resume_read(SHRPX_NO_BUFFER, nullptr, 0);
791     } else {
792       // If the request is not complete, close the connection.
793       delete_downstream();
794 
795       handler_->set_should_close_after_write(true);
796 
797       return 0;
798     }
799   }
800 
801   return downstream->resume_read(SHRPX_NO_BUFFER, resp.unconsumed_body_length);
802 }
803 
on_event()804 int HttpsUpstream::on_event() { return 0; }
805 
get_client_handler() const806 ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; }
807 
pause_read(IOCtrlReason reason)808 void HttpsUpstream::pause_read(IOCtrlReason reason) {
809   ioctrl_.pause_read(reason);
810 }
811 
resume_read(IOCtrlReason reason,Downstream * downstream,size_t consumed)812 int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream,
813                                size_t consumed) {
814   // downstream could be nullptr
815   if (downstream && downstream->request_buf_full()) {
816     return 0;
817   }
818   if (ioctrl_.resume_read(reason)) {
819     // Process remaining data in input buffer here because these bytes
820     // are not notified by readcb until new data arrive.
821     llhttp_resume(&htp_);
822 
823     auto conn = handler_->get_connection();
824     ev_feed_event(conn->loop, &conn->rev, EV_READ);
825     return 0;
826   }
827 
828   return 0;
829 }
830 
downstream_read(DownstreamConnection * dconn)831 int HttpsUpstream::downstream_read(DownstreamConnection *dconn) {
832   auto downstream = dconn->get_downstream();
833   int rv;
834 
835   rv = downstream->on_read();
836 
837   if (rv == SHRPX_ERR_EOF) {
838     if (downstream->get_request_header_sent()) {
839       return downstream_eof(dconn);
840     }
841     return SHRPX_ERR_RETRY;
842   }
843 
844   if (rv == SHRPX_ERR_DCONN_CANCELED) {
845     downstream->pop_downstream_connection();
846     goto end;
847   }
848 
849   if (rv < 0) {
850     return downstream_error(dconn, Downstream::EVENT_ERROR);
851   }
852 
853   if (downstream->get_response_state() == DownstreamState::MSG_RESET) {
854     return -1;
855   }
856 
857   if (downstream->get_response_state() == DownstreamState::MSG_BAD_HEADER) {
858     error_reply(502);
859     downstream->pop_downstream_connection();
860     goto end;
861   }
862 
863   if (downstream->can_detach_downstream_connection()) {
864     // Keep-alive
865     downstream->detach_downstream_connection();
866   }
867 
868 end:
869   handler_->signal_write();
870 
871   return 0;
872 }
873 
downstream_write(DownstreamConnection * dconn)874 int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
875   int rv;
876   rv = dconn->on_write();
877   if (rv == SHRPX_ERR_NETWORK) {
878     return downstream_error(dconn, Downstream::EVENT_ERROR);
879   }
880 
881   if (rv != 0) {
882     return rv;
883   }
884 
885   return 0;
886 }
887 
downstream_eof(DownstreamConnection * dconn)888 int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
889   auto downstream = dconn->get_downstream();
890 
891   if (LOG_ENABLED(INFO)) {
892     DCLOG(INFO, dconn) << "EOF";
893   }
894 
895   if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
896     goto end;
897   }
898 
899   if (downstream->get_response_state() == DownstreamState::HEADER_COMPLETE) {
900     // Server may indicate the end of the request by EOF
901     if (LOG_ENABLED(INFO)) {
902       DCLOG(INFO, dconn) << "The end of the response body was indicated by "
903                          << "EOF";
904     }
905     on_downstream_body_complete(downstream);
906     downstream->set_response_state(DownstreamState::MSG_COMPLETE);
907     downstream->pop_downstream_connection();
908     goto end;
909   }
910 
911   if (downstream->get_response_state() == DownstreamState::INITIAL) {
912     // we did not send any response headers, so we can reply error
913     // message.
914     if (LOG_ENABLED(INFO)) {
915       DCLOG(INFO, dconn) << "Return error reply";
916     }
917     error_reply(502);
918     downstream->pop_downstream_connection();
919     goto end;
920   }
921 
922   // Otherwise, we don't know how to recover from this situation. Just
923   // drop connection.
924   return -1;
925 end:
926   handler_->signal_write();
927 
928   return 0;
929 }
930 
downstream_error(DownstreamConnection * dconn,int events)931 int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
932   auto downstream = dconn->get_downstream();
933   if (LOG_ENABLED(INFO)) {
934     if (events & Downstream::EVENT_ERROR) {
935       DCLOG(INFO, dconn) << "Network error/general error";
936     } else {
937       DCLOG(INFO, dconn) << "Timeout";
938     }
939   }
940   if (downstream->get_response_state() != DownstreamState::INITIAL) {
941     return -1;
942   }
943 
944   unsigned int status;
945   if (events & Downstream::EVENT_TIMEOUT) {
946     if (downstream->get_request_header_sent()) {
947       status = 504;
948     } else {
949       status = 408;
950     }
951   } else {
952     status = 502;
953   }
954   error_reply(status);
955 
956   downstream->pop_downstream_connection();
957 
958   handler_->signal_write();
959   return 0;
960 }
961 
send_reply(Downstream * downstream,const uint8_t * body,size_t bodylen)962 int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
963                               size_t bodylen) {
964   const auto &req = downstream->request();
965   auto &resp = downstream->response();
966   auto &balloc = downstream->get_block_allocator();
967   auto config = get_config();
968   auto &httpconf = config->http;
969 
970   auto connection_close = false;
971 
972   auto worker = handler_->get_worker();
973 
974   if (httpconf.max_requests <= num_requests_ ||
975       worker->get_graceful_shutdown()) {
976     resp.fs.add_header_token(StringRef::from_lit("connection"),
977                              StringRef::from_lit("close"), false,
978                              http2::HD_CONNECTION);
979     connection_close = true;
980   } else if (req.http_major <= 0 ||
981              (req.http_major == 1 && req.http_minor == 0)) {
982     connection_close = true;
983   } else {
984     auto c = resp.fs.header(http2::HD_CONNECTION);
985     if (c && util::strieq_l("close", c->value)) {
986       connection_close = true;
987     }
988   }
989 
990   if (connection_close) {
991     resp.connection_close = true;
992     handler_->set_should_close_after_write(true);
993   }
994 
995   auto output = downstream->get_response_buf();
996 
997   output->append("HTTP/1.1 ");
998   output->append(http2::stringify_status(balloc, resp.http_status));
999   output->append(' ');
1000   output->append(http2::get_reason_phrase(resp.http_status));
1001   output->append("\r\n");
1002 
1003   for (auto &kv : resp.fs.headers()) {
1004     if (kv.name.empty() || kv.name[0] == ':') {
1005       continue;
1006     }
1007     http2::capitalize(output, kv.name);
1008     output->append(": ");
1009     output->append(kv.value);
1010     output->append("\r\n");
1011   }
1012 
1013   if (!resp.fs.header(http2::HD_SERVER)) {
1014     output->append("Server: ");
1015     output->append(config->http.server_name);
1016     output->append("\r\n");
1017   }
1018 
1019   for (auto &p : httpconf.add_response_headers) {
1020     output->append(p.name);
1021     output->append(": ");
1022     output->append(p.value);
1023     output->append("\r\n");
1024   }
1025 
1026   output->append("\r\n");
1027 
1028   output->append(body, bodylen);
1029 
1030   downstream->response_sent_body_length += bodylen;
1031   downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1032 
1033   return 0;
1034 }
1035 
error_reply(unsigned int status_code)1036 void HttpsUpstream::error_reply(unsigned int status_code) {
1037   auto downstream = get_downstream();
1038 
1039   if (!downstream) {
1040     attach_downstream(
1041         std::make_unique<Downstream>(this, handler_->get_mcpool(), 1));
1042     downstream = get_downstream();
1043   }
1044 
1045   auto &resp = downstream->response();
1046   auto &balloc = downstream->get_block_allocator();
1047 
1048   auto html = http::create_error_html(balloc, status_code);
1049 
1050   resp.http_status = status_code;
1051   // we are going to close connection for both frontend and backend in
1052   // error condition.  This is safest option.
1053   resp.connection_close = true;
1054   handler_->set_should_close_after_write(true);
1055 
1056   auto output = downstream->get_response_buf();
1057 
1058   output->append("HTTP/1.1 ");
1059   output->append(http2::stringify_status(balloc, status_code));
1060   output->append(' ');
1061   output->append(http2::get_reason_phrase(status_code));
1062   output->append("\r\nServer: ");
1063   output->append(get_config()->http.server_name);
1064   output->append("\r\nContent-Length: ");
1065   std::array<uint8_t, NGHTTP2_MAX_UINT64_DIGITS> intbuf;
1066   output->append(StringRef{std::begin(intbuf),
1067                            util::utos(std::begin(intbuf), html.size())});
1068   output->append("\r\nDate: ");
1069   auto lgconf = log_config();
1070   lgconf->update_tstamp(std::chrono::system_clock::now());
1071   output->append(lgconf->tstamp->time_http);
1072   output->append("\r\nContent-Type: text/html; "
1073                  "charset=UTF-8\r\nConnection: close\r\n\r\n");
1074   output->append(html);
1075 
1076   downstream->response_sent_body_length += html.size();
1077   downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1078 }
1079 
attach_downstream(std::unique_ptr<Downstream> downstream)1080 void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) {
1081   assert(!downstream_);
1082   downstream_ = std::move(downstream);
1083 }
1084 
delete_downstream()1085 void HttpsUpstream::delete_downstream() {
1086   if (downstream_ && downstream_->accesslog_ready()) {
1087     handler_->write_accesslog(downstream_.get());
1088   }
1089 
1090   downstream_.reset();
1091 }
1092 
get_downstream() const1093 Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); }
1094 
pop_downstream()1095 std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
1096   return std::unique_ptr<Downstream>(downstream_.release());
1097 }
1098 
on_downstream_header_complete(Downstream * downstream)1099 int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
1100   if (LOG_ENABLED(INFO)) {
1101     if (downstream->get_non_final_response()) {
1102       DLOG(INFO, downstream) << "HTTP non-final response header";
1103     } else {
1104       DLOG(INFO, downstream) << "HTTP response header completed";
1105     }
1106   }
1107 
1108   const auto &req = downstream->request();
1109   auto &resp = downstream->response();
1110   auto &balloc = downstream->get_block_allocator();
1111   auto dconn = downstream->get_downstream_connection();
1112   // dconn might be nullptr if this is non-final response from mruby.
1113 
1114   if (downstream->get_non_final_response() &&
1115       !downstream->supports_non_final_response()) {
1116     resp.fs.clear_headers();
1117     return 0;
1118   }
1119 
1120 #ifdef HAVE_MRUBY
1121   if (!downstream->get_non_final_response()) {
1122     assert(dconn);
1123     const auto &group = dconn->get_downstream_addr_group();
1124     if (group) {
1125       const auto &dmruby_ctx = group->shared_addr->mruby_ctx;
1126 
1127       if (dmruby_ctx->run_on_response_proc(downstream) != 0) {
1128         error_reply(500);
1129         return -1;
1130       }
1131 
1132       if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1133         return -1;
1134       }
1135     }
1136 
1137     auto worker = handler_->get_worker();
1138     auto mruby_ctx = worker->get_mruby_context();
1139 
1140     if (mruby_ctx->run_on_response_proc(downstream) != 0) {
1141       error_reply(500);
1142       return -1;
1143     }
1144 
1145     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1146       return -1;
1147     }
1148   }
1149 #endif // HAVE_MRUBY
1150 
1151   auto connect_method = req.method == HTTP_CONNECT;
1152 
1153   auto buf = downstream->get_response_buf();
1154   buf->append("HTTP/");
1155   buf->append('0' + req.http_major);
1156   buf->append('.');
1157   buf->append('0' + req.http_minor);
1158   buf->append(' ');
1159   if (req.connect_proto != ConnectProto::NONE && downstream->get_upgraded()) {
1160     buf->append(http2::stringify_status(balloc, 101));
1161     buf->append(' ');
1162     buf->append(http2::get_reason_phrase(101));
1163   } else {
1164     buf->append(http2::stringify_status(balloc, resp.http_status));
1165     buf->append(' ');
1166     buf->append(http2::get_reason_phrase(resp.http_status));
1167   }
1168   buf->append("\r\n");
1169 
1170   auto config = get_config();
1171   auto &httpconf = config->http;
1172 
1173   if (!config->http2_proxy && !httpconf.no_location_rewrite) {
1174     downstream->rewrite_location_response_header(
1175         get_client_handler()->get_upstream_scheme());
1176   }
1177 
1178   if (downstream->get_non_final_response()) {
1179     http2::build_http1_headers_from_headers(buf, resp.fs.headers(),
1180                                             http2::HDOP_STRIP_ALL);
1181 
1182     buf->append("\r\n");
1183 
1184     if (LOG_ENABLED(INFO)) {
1185       log_response_headers(buf);
1186     }
1187 
1188     resp.fs.clear_headers();
1189 
1190     return 0;
1191   }
1192 
1193   auto build_flags = (http2::HDOP_STRIP_ALL & ~http2::HDOP_STRIP_VIA) |
1194                      (!http2::legacy_http1(req.http_major, req.http_minor)
1195                           ? 0
1196                           : http2::HDOP_STRIP_TRANSFER_ENCODING);
1197 
1198   http2::build_http1_headers_from_headers(buf, resp.fs.headers(), build_flags);
1199 
1200   auto worker = handler_->get_worker();
1201 
1202   // after graceful shutdown commenced, add connection: close header
1203   // field.
1204   if (httpconf.max_requests <= num_requests_ ||
1205       worker->get_graceful_shutdown()) {
1206     resp.connection_close = true;
1207   }
1208 
1209   // We check downstream->get_response_connection_close() in case when
1210   // the Content-Length is not available.
1211   if (!req.connection_close && !resp.connection_close) {
1212     if (req.http_major <= 0 || req.http_minor <= 0) {
1213       // We add this header for HTTP/1.0 or HTTP/0.9 clients
1214       buf->append("Connection: Keep-Alive\r\n");
1215     }
1216   } else if (!downstream->get_upgraded()) {
1217     buf->append("Connection: close\r\n");
1218   }
1219 
1220   if (!connect_method && downstream->get_upgraded()) {
1221     if (req.connect_proto == ConnectProto::WEBSOCKET &&
1222         resp.http_status / 100 == 2) {
1223       buf->append("Upgrade: websocket\r\nConnection: Upgrade\r\n");
1224       auto key = req.fs.header(http2::HD_SEC_WEBSOCKET_KEY);
1225       if (!key || key->value.size() != base64::encode_length(16)) {
1226         return -1;
1227       }
1228       std::array<uint8_t, base64::encode_length(20)> out;
1229       auto accept = http2::make_websocket_accept_token(out.data(), key->value);
1230       if (accept.empty()) {
1231         return -1;
1232       }
1233       buf->append("Sec-WebSocket-Accept: ");
1234       buf->append(accept);
1235       buf->append("\r\n");
1236     } else {
1237       auto connection = resp.fs.header(http2::HD_CONNECTION);
1238       if (connection) {
1239         buf->append("Connection: ");
1240         buf->append((*connection).value);
1241         buf->append("\r\n");
1242       }
1243 
1244       auto upgrade = resp.fs.header(http2::HD_UPGRADE);
1245       if (upgrade) {
1246         buf->append("Upgrade: ");
1247         buf->append((*upgrade).value);
1248         buf->append("\r\n");
1249       }
1250     }
1251   }
1252 
1253   if (!resp.fs.header(http2::HD_ALT_SVC)) {
1254     // We won't change or alter alt-svc from backend for now
1255     if (!httpconf.altsvcs.empty()) {
1256       buf->append("Alt-Svc: ");
1257       buf->append(httpconf.altsvc_header_value);
1258       buf->append("\r\n");
1259     }
1260   }
1261 
1262   if (!config->http2_proxy && !httpconf.no_server_rewrite) {
1263     buf->append("Server: ");
1264     buf->append(httpconf.server_name);
1265     buf->append("\r\n");
1266   } else {
1267     auto server = resp.fs.header(http2::HD_SERVER);
1268     if (server) {
1269       buf->append("Server: ");
1270       buf->append((*server).value);
1271       buf->append("\r\n");
1272     }
1273   }
1274 
1275   if (req.method != HTTP_CONNECT || !downstream->get_upgraded()) {
1276     auto affinity_cookie = downstream->get_affinity_cookie_to_send();
1277     if (affinity_cookie) {
1278       auto &group = dconn->get_downstream_addr_group();
1279       auto &shared_addr = group->shared_addr;
1280       auto &cookieconf = shared_addr->affinity.cookie;
1281       auto secure =
1282           http::require_cookie_secure_attribute(cookieconf.secure, req.scheme);
1283       auto cookie_str = http::create_affinity_cookie(
1284           balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure);
1285       buf->append("Set-Cookie: ");
1286       buf->append(cookie_str);
1287       buf->append("\r\n");
1288     }
1289   }
1290 
1291   auto via = resp.fs.header(http2::HD_VIA);
1292   if (httpconf.no_via) {
1293     if (via) {
1294       buf->append("Via: ");
1295       buf->append((*via).value);
1296       buf->append("\r\n");
1297     }
1298   } else {
1299     buf->append("Via: ");
1300     if (via) {
1301       buf->append((*via).value);
1302       buf->append(", ");
1303     }
1304     std::array<char, 16> viabuf;
1305     auto end = http::create_via_header_value(viabuf.data(), resp.http_major,
1306                                              resp.http_minor);
1307     buf->append(viabuf.data(), end - std::begin(viabuf));
1308     buf->append("\r\n");
1309   }
1310 
1311   for (auto &p : httpconf.add_response_headers) {
1312     buf->append(p.name);
1313     buf->append(": ");
1314     buf->append(p.value);
1315     buf->append("\r\n");
1316   }
1317 
1318   buf->append("\r\n");
1319 
1320   if (LOG_ENABLED(INFO)) {
1321     log_response_headers(buf);
1322   }
1323 
1324   return 0;
1325 }
1326 
on_downstream_body(Downstream * downstream,const uint8_t * data,size_t len,bool flush)1327 int HttpsUpstream::on_downstream_body(Downstream *downstream,
1328                                       const uint8_t *data, size_t len,
1329                                       bool flush) {
1330   if (len == 0) {
1331     return 0;
1332   }
1333   auto output = downstream->get_response_buf();
1334   if (downstream->get_chunked_response()) {
1335     output->append(util::utox(len));
1336     output->append("\r\n");
1337   }
1338   output->append(data, len);
1339 
1340   downstream->response_sent_body_length += len;
1341 
1342   if (downstream->get_chunked_response()) {
1343     output->append("\r\n");
1344   }
1345   return 0;
1346 }
1347 
on_downstream_body_complete(Downstream * downstream)1348 int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
1349   const auto &req = downstream->request();
1350   auto &resp = downstream->response();
1351 
1352   if (downstream->get_chunked_response()) {
1353     auto output = downstream->get_response_buf();
1354     const auto &trailers = resp.fs.trailers();
1355     if (trailers.empty()) {
1356       output->append("0\r\n\r\n");
1357     } else {
1358       output->append("0\r\n");
1359       http2::build_http1_headers_from_headers(output, trailers,
1360                                               http2::HDOP_STRIP_ALL);
1361       output->append("\r\n");
1362     }
1363   }
1364   if (LOG_ENABLED(INFO)) {
1365     DLOG(INFO, downstream) << "HTTP response completed";
1366   }
1367 
1368   if (!downstream->validate_response_recv_body_length()) {
1369     resp.connection_close = true;
1370   }
1371 
1372   if (req.connection_close || resp.connection_close ||
1373       // To avoid to stall upload body
1374       downstream->get_request_state() != DownstreamState::MSG_COMPLETE) {
1375     auto handler = get_client_handler();
1376     handler->set_should_close_after_write(true);
1377   }
1378   return 0;
1379 }
1380 
on_downstream_abort_request(Downstream * downstream,unsigned int status_code)1381 int HttpsUpstream::on_downstream_abort_request(Downstream *downstream,
1382                                                unsigned int status_code) {
1383   error_reply(status_code);
1384   handler_->signal_write();
1385   return 0;
1386 }
1387 
on_downstream_abort_request_with_https_redirect(Downstream * downstream)1388 int HttpsUpstream::on_downstream_abort_request_with_https_redirect(
1389     Downstream *downstream) {
1390   redirect_to_https(downstream);
1391   handler_->signal_write();
1392   return 0;
1393 }
1394 
redirect_to_https(Downstream * downstream)1395 int HttpsUpstream::redirect_to_https(Downstream *downstream) {
1396   auto &req = downstream->request();
1397   if (req.method == HTTP_CONNECT || req.scheme != "http" ||
1398       req.authority.empty()) {
1399     error_reply(400);
1400     return 0;
1401   }
1402 
1403   auto authority = util::extract_host(req.authority);
1404   if (authority.empty()) {
1405     error_reply(400);
1406     return 0;
1407   }
1408 
1409   auto &balloc = downstream->get_block_allocator();
1410   auto config = get_config();
1411   auto &httpconf = config->http;
1412 
1413   StringRef loc;
1414   if (httpconf.redirect_https_port == StringRef::from_lit("443")) {
1415     loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
1416                             req.path);
1417   } else {
1418     loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
1419                             StringRef::from_lit(":"),
1420                             httpconf.redirect_https_port, req.path);
1421   }
1422 
1423   auto &resp = downstream->response();
1424   resp.http_status = 308;
1425   resp.fs.add_header_token(StringRef::from_lit("location"), loc, false,
1426                            http2::HD_LOCATION);
1427   resp.fs.add_header_token(StringRef::from_lit("connection"),
1428                            StringRef::from_lit("close"), false,
1429                            http2::HD_CONNECTION);
1430 
1431   return send_reply(downstream, nullptr, 0);
1432 }
1433 
log_response_headers(DefaultMemchunks * buf) const1434 void HttpsUpstream::log_response_headers(DefaultMemchunks *buf) const {
1435   std::string nhdrs;
1436   for (auto chunk = buf->head; chunk; chunk = chunk->next) {
1437     nhdrs.append(chunk->pos, chunk->last);
1438   }
1439   if (log_config()->errorlog_tty) {
1440     nhdrs = http::colorizeHeaders(nhdrs.c_str());
1441   }
1442   ULOG(INFO, this) << "HTTP response headers\n" << nhdrs;
1443 }
1444 
on_handler_delete()1445 void HttpsUpstream::on_handler_delete() {
1446   if (downstream_ && downstream_->accesslog_ready()) {
1447     handler_->write_accesslog(downstream_.get());
1448   }
1449 }
1450 
on_downstream_reset(Downstream * downstream,bool no_retry)1451 int HttpsUpstream::on_downstream_reset(Downstream *downstream, bool no_retry) {
1452   int rv;
1453   std::unique_ptr<DownstreamConnection> dconn;
1454 
1455   assert(downstream == downstream_.get());
1456 
1457   downstream_->pop_downstream_connection();
1458 
1459   if (!downstream_->request_submission_ready()) {
1460     switch (downstream_->get_response_state()) {
1461     case DownstreamState::MSG_COMPLETE:
1462       // We have got all response body already.  Send it off.
1463       return 0;
1464     case DownstreamState::INITIAL:
1465       if (on_downstream_abort_request(downstream_.get(), 502) != 0) {
1466         return -1;
1467       }
1468       return 0;
1469     default:
1470       break;
1471     }
1472     // Return error so that caller can delete handler
1473     return -1;
1474   }
1475 
1476   downstream_->add_retry();
1477 
1478   rv = 0;
1479 
1480   if (no_retry || downstream_->no_more_retry()) {
1481     goto fail;
1482   }
1483 
1484   for (;;) {
1485     auto dconn = handler_->get_downstream_connection(rv, downstream_.get());
1486     if (!dconn) {
1487       goto fail;
1488     }
1489 
1490     rv = downstream_->attach_downstream_connection(std::move(dconn));
1491     if (rv == 0) {
1492       break;
1493     }
1494   }
1495 
1496   rv = downstream_->push_request_headers();
1497   if (rv != 0) {
1498     goto fail;
1499   }
1500 
1501   return 0;
1502 
1503 fail:
1504   if (rv == SHRPX_ERR_TLS_REQUIRED) {
1505     rv = on_downstream_abort_request_with_https_redirect(downstream);
1506   } else {
1507     rv = on_downstream_abort_request(downstream_.get(), 502);
1508   }
1509   if (rv != 0) {
1510     return -1;
1511   }
1512   downstream_->pop_downstream_connection();
1513 
1514   return 0;
1515 }
1516 
initiate_push(Downstream * downstream,const StringRef & uri)1517 int HttpsUpstream::initiate_push(Downstream *downstream, const StringRef &uri) {
1518   return 0;
1519 }
1520 
response_riovec(struct iovec * iov,int iovcnt) const1521 int HttpsUpstream::response_riovec(struct iovec *iov, int iovcnt) const {
1522   if (!downstream_) {
1523     return 0;
1524   }
1525 
1526   auto buf = downstream_->get_response_buf();
1527 
1528   return buf->riovec(iov, iovcnt);
1529 }
1530 
response_drain(size_t n)1531 void HttpsUpstream::response_drain(size_t n) {
1532   if (!downstream_) {
1533     return;
1534   }
1535 
1536   auto buf = downstream_->get_response_buf();
1537 
1538   buf->drain(n);
1539 }
1540 
response_empty() const1541 bool HttpsUpstream::response_empty() const {
1542   if (!downstream_) {
1543     return true;
1544   }
1545 
1546   auto buf = downstream_->get_response_buf();
1547 
1548   return buf->rleft() == 0;
1549 }
1550 
1551 Downstream *
on_downstream_push_promise(Downstream * downstream,int32_t promised_stream_id)1552 HttpsUpstream::on_downstream_push_promise(Downstream *downstream,
1553                                           int32_t promised_stream_id) {
1554   return nullptr;
1555 }
1556 
on_downstream_push_promise_complete(Downstream * downstream,Downstream * promised_downstream)1557 int HttpsUpstream::on_downstream_push_promise_complete(
1558     Downstream *downstream, Downstream *promised_downstream) {
1559   return -1;
1560 }
1561 
push_enabled() const1562 bool HttpsUpstream::push_enabled() const { return false; }
1563 
cancel_premature_downstream(Downstream * promised_downstream)1564 void HttpsUpstream::cancel_premature_downstream(
1565     Downstream *promised_downstream) {}
1566 
1567 } // namespace shrpx
1568