• 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   auto nread =
662       htperr == HPE_OK
663           ? rb->rleft()
664           : reinterpret_cast<const uint8_t *>(llhttp_get_error_pos(&htp_)) -
665                 rb->pos();
666   rb->drain(nread);
667   rlimit->startw();
668 
669   // Well, actually header length + some body bytes
670   current_header_length_ += nread;
671 
672   // Get downstream again because it may be initialized in http parser
673   // execution
674   downstream = get_downstream();
675 
676   if (htperr == HPE_PAUSED) {
677     // We may pause parser in htp_msg_completecb when both side are
678     // completed.  Signal write, so that we can run on_write().
679     if (downstream &&
680         downstream->get_request_state() == DownstreamState::MSG_COMPLETE &&
681         downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
682       handler_->signal_write();
683     }
684     return 0;
685   }
686 
687   if (htperr != HPE_OK) {
688     if (LOG_ENABLED(INFO)) {
689       ULOG(INFO, this) << "HTTP parse failure: "
690                        << "(" << llhttp_errno_name(htperr) << ") "
691                        << llhttp_get_error_reason(&htp_);
692     }
693 
694     if (downstream &&
695         downstream->get_response_state() != DownstreamState::INITIAL) {
696       handler_->set_should_close_after_write(true);
697       handler_->signal_write();
698       return 0;
699     }
700 
701     unsigned int status_code;
702 
703     if (htperr == HPE_INVALID_METHOD) {
704       status_code = 501;
705     } else if (downstream) {
706       status_code = downstream->response().http_status;
707       if (status_code == 0) {
708         if (downstream->get_request_state() == DownstreamState::CONNECT_FAIL) {
709           status_code = 502;
710         } else if (downstream->get_request_state() ==
711                    DownstreamState::HTTP1_REQUEST_HEADER_TOO_LARGE) {
712           status_code = 431;
713         } else {
714           status_code = 400;
715         }
716       }
717     } else {
718       status_code = 400;
719     }
720 
721     error_reply(status_code);
722 
723     handler_->signal_write();
724 
725     return 0;
726   }
727 
728   // downstream can be NULL here.
729   if (downstream && downstream->request_buf_full()) {
730     if (LOG_ENABLED(INFO)) {
731       ULOG(INFO, this) << "Downstream request buffer is full";
732     }
733 
734     pause_read(SHRPX_NO_BUFFER);
735 
736     return 0;
737   }
738 
739   return 0;
740 }
741 
on_write()742 int HttpsUpstream::on_write() {
743   auto downstream = get_downstream();
744   if (!downstream) {
745     return 0;
746   }
747 
748   auto output = downstream->get_response_buf();
749   const auto &resp = downstream->response();
750 
751   if (output->rleft() > 0) {
752     return 0;
753   }
754 
755   // We need to postpone detachment until all data are sent so that
756   // we can notify nghttp2 library all data consumed.
757   if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
758     if (downstream->can_detach_downstream_connection()) {
759       // Keep-alive
760       downstream->detach_downstream_connection();
761     } else {
762       // Connection close
763       downstream->pop_downstream_connection();
764       // dconn was deleted
765     }
766     // We need this if response ends before request.
767     if (downstream->get_request_state() == DownstreamState::MSG_COMPLETE) {
768       delete_downstream();
769 
770       if (handler_->get_should_close_after_write()) {
771         return 0;
772       }
773 
774       auto conn = handler_->get_connection();
775       auto &upstreamconf = get_config()->conn.upstream;
776 
777       conn->rt.repeat = upstreamconf.timeout.idle_read;
778 
779       handler_->repeat_read_timer();
780 
781       return resume_read(SHRPX_NO_BUFFER, nullptr, 0);
782     } else {
783       // If the request is not complete, close the connection.
784       delete_downstream();
785 
786       handler_->set_should_close_after_write(true);
787 
788       return 0;
789     }
790   }
791 
792   return downstream->resume_read(SHRPX_NO_BUFFER, resp.unconsumed_body_length);
793 }
794 
on_event()795 int HttpsUpstream::on_event() { return 0; }
796 
get_client_handler() const797 ClientHandler *HttpsUpstream::get_client_handler() const { return handler_; }
798 
pause_read(IOCtrlReason reason)799 void HttpsUpstream::pause_read(IOCtrlReason reason) {
800   ioctrl_.pause_read(reason);
801 }
802 
resume_read(IOCtrlReason reason,Downstream * downstream,size_t consumed)803 int HttpsUpstream::resume_read(IOCtrlReason reason, Downstream *downstream,
804                                size_t consumed) {
805   // downstream could be nullptr
806   if (downstream && downstream->request_buf_full()) {
807     return 0;
808   }
809   if (ioctrl_.resume_read(reason)) {
810     // Process remaining data in input buffer here because these bytes
811     // are not notified by readcb until new data arrive.
812     llhttp_resume(&htp_);
813 
814     auto conn = handler_->get_connection();
815     ev_feed_event(conn->loop, &conn->rev, EV_READ);
816     return 0;
817   }
818 
819   return 0;
820 }
821 
downstream_read(DownstreamConnection * dconn)822 int HttpsUpstream::downstream_read(DownstreamConnection *dconn) {
823   auto downstream = dconn->get_downstream();
824   int rv;
825 
826   rv = downstream->on_read();
827 
828   if (rv == SHRPX_ERR_EOF) {
829     if (downstream->get_request_header_sent()) {
830       return downstream_eof(dconn);
831     }
832     return SHRPX_ERR_RETRY;
833   }
834 
835   if (rv == SHRPX_ERR_DCONN_CANCELED) {
836     downstream->pop_downstream_connection();
837     goto end;
838   }
839 
840   if (rv < 0) {
841     return downstream_error(dconn, Downstream::EVENT_ERROR);
842   }
843 
844   if (downstream->get_response_state() == DownstreamState::MSG_RESET) {
845     return -1;
846   }
847 
848   if (downstream->get_response_state() == DownstreamState::MSG_BAD_HEADER) {
849     error_reply(502);
850     downstream->pop_downstream_connection();
851     goto end;
852   }
853 
854   if (downstream->can_detach_downstream_connection()) {
855     // Keep-alive
856     downstream->detach_downstream_connection();
857   }
858 
859 end:
860   handler_->signal_write();
861 
862   return 0;
863 }
864 
downstream_write(DownstreamConnection * dconn)865 int HttpsUpstream::downstream_write(DownstreamConnection *dconn) {
866   int rv;
867   rv = dconn->on_write();
868   if (rv == SHRPX_ERR_NETWORK) {
869     return downstream_error(dconn, Downstream::EVENT_ERROR);
870   }
871 
872   if (rv != 0) {
873     return rv;
874   }
875 
876   return 0;
877 }
878 
downstream_eof(DownstreamConnection * dconn)879 int HttpsUpstream::downstream_eof(DownstreamConnection *dconn) {
880   auto downstream = dconn->get_downstream();
881 
882   if (LOG_ENABLED(INFO)) {
883     DCLOG(INFO, dconn) << "EOF";
884   }
885 
886   if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
887     goto end;
888   }
889 
890   if (downstream->get_response_state() == DownstreamState::HEADER_COMPLETE) {
891     // Server may indicate the end of the request by EOF
892     if (LOG_ENABLED(INFO)) {
893       DCLOG(INFO, dconn) << "The end of the response body was indicated by "
894                          << "EOF";
895     }
896     on_downstream_body_complete(downstream);
897     downstream->set_response_state(DownstreamState::MSG_COMPLETE);
898     downstream->pop_downstream_connection();
899     goto end;
900   }
901 
902   if (downstream->get_response_state() == DownstreamState::INITIAL) {
903     // we did not send any response headers, so we can reply error
904     // message.
905     if (LOG_ENABLED(INFO)) {
906       DCLOG(INFO, dconn) << "Return error reply";
907     }
908     error_reply(502);
909     downstream->pop_downstream_connection();
910     goto end;
911   }
912 
913   // Otherwise, we don't know how to recover from this situation. Just
914   // drop connection.
915   return -1;
916 end:
917   handler_->signal_write();
918 
919   return 0;
920 }
921 
downstream_error(DownstreamConnection * dconn,int events)922 int HttpsUpstream::downstream_error(DownstreamConnection *dconn, int events) {
923   auto downstream = dconn->get_downstream();
924   if (LOG_ENABLED(INFO)) {
925     if (events & Downstream::EVENT_ERROR) {
926       DCLOG(INFO, dconn) << "Network error/general error";
927     } else {
928       DCLOG(INFO, dconn) << "Timeout";
929     }
930   }
931   if (downstream->get_response_state() != DownstreamState::INITIAL) {
932     return -1;
933   }
934 
935   unsigned int status;
936   if (events & Downstream::EVENT_TIMEOUT) {
937     if (downstream->get_request_header_sent()) {
938       status = 504;
939     } else {
940       status = 408;
941     }
942   } else {
943     status = 502;
944   }
945   error_reply(status);
946 
947   downstream->pop_downstream_connection();
948 
949   handler_->signal_write();
950   return 0;
951 }
952 
send_reply(Downstream * downstream,const uint8_t * body,size_t bodylen)953 int HttpsUpstream::send_reply(Downstream *downstream, const uint8_t *body,
954                               size_t bodylen) {
955   const auto &req = downstream->request();
956   auto &resp = downstream->response();
957   auto &balloc = downstream->get_block_allocator();
958   auto config = get_config();
959   auto &httpconf = config->http;
960 
961   auto connection_close = false;
962 
963   auto worker = handler_->get_worker();
964 
965   if (httpconf.max_requests <= num_requests_ ||
966       worker->get_graceful_shutdown()) {
967     resp.fs.add_header_token(StringRef::from_lit("connection"),
968                              StringRef::from_lit("close"), false,
969                              http2::HD_CONNECTION);
970     connection_close = true;
971   } else if (req.http_major <= 0 ||
972              (req.http_major == 1 && req.http_minor == 0)) {
973     connection_close = true;
974   } else {
975     auto c = resp.fs.header(http2::HD_CONNECTION);
976     if (c && util::strieq_l("close", c->value)) {
977       connection_close = true;
978     }
979   }
980 
981   if (connection_close) {
982     resp.connection_close = true;
983     handler_->set_should_close_after_write(true);
984   }
985 
986   auto output = downstream->get_response_buf();
987 
988   output->append("HTTP/1.1 ");
989   output->append(http2::stringify_status(balloc, resp.http_status));
990   output->append(' ');
991   output->append(http2::get_reason_phrase(resp.http_status));
992   output->append("\r\n");
993 
994   for (auto &kv : resp.fs.headers()) {
995     if (kv.name.empty() || kv.name[0] == ':') {
996       continue;
997     }
998     http2::capitalize(output, kv.name);
999     output->append(": ");
1000     output->append(kv.value);
1001     output->append("\r\n");
1002   }
1003 
1004   if (!resp.fs.header(http2::HD_SERVER)) {
1005     output->append("Server: ");
1006     output->append(config->http.server_name);
1007     output->append("\r\n");
1008   }
1009 
1010   for (auto &p : httpconf.add_response_headers) {
1011     output->append(p.name);
1012     output->append(": ");
1013     output->append(p.value);
1014     output->append("\r\n");
1015   }
1016 
1017   output->append("\r\n");
1018 
1019   output->append(body, bodylen);
1020 
1021   downstream->response_sent_body_length += bodylen;
1022   downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1023 
1024   return 0;
1025 }
1026 
error_reply(unsigned int status_code)1027 void HttpsUpstream::error_reply(unsigned int status_code) {
1028   auto downstream = get_downstream();
1029 
1030   if (!downstream) {
1031     attach_downstream(
1032         std::make_unique<Downstream>(this, handler_->get_mcpool(), 1));
1033     downstream = get_downstream();
1034   }
1035 
1036   auto &resp = downstream->response();
1037   auto &balloc = downstream->get_block_allocator();
1038 
1039   auto html = http::create_error_html(balloc, status_code);
1040 
1041   resp.http_status = status_code;
1042   // we are going to close connection for both frontend and backend in
1043   // error condition.  This is safest option.
1044   resp.connection_close = true;
1045   handler_->set_should_close_after_write(true);
1046 
1047   auto output = downstream->get_response_buf();
1048 
1049   output->append("HTTP/1.1 ");
1050   output->append(http2::stringify_status(balloc, status_code));
1051   output->append(' ');
1052   output->append(http2::get_reason_phrase(status_code));
1053   output->append("\r\nServer: ");
1054   output->append(get_config()->http.server_name);
1055   output->append("\r\nContent-Length: ");
1056   std::array<uint8_t, NGHTTP2_MAX_UINT64_DIGITS> intbuf;
1057   output->append(StringRef{std::begin(intbuf),
1058                            util::utos(std::begin(intbuf), html.size())});
1059   output->append("\r\nDate: ");
1060   auto lgconf = log_config();
1061   lgconf->update_tstamp(std::chrono::system_clock::now());
1062   output->append(lgconf->tstamp->time_http);
1063   output->append("\r\nContent-Type: text/html; "
1064                  "charset=UTF-8\r\nConnection: close\r\n\r\n");
1065   output->append(html);
1066 
1067   downstream->response_sent_body_length += html.size();
1068   downstream->set_response_state(DownstreamState::MSG_COMPLETE);
1069 }
1070 
attach_downstream(std::unique_ptr<Downstream> downstream)1071 void HttpsUpstream::attach_downstream(std::unique_ptr<Downstream> downstream) {
1072   assert(!downstream_);
1073   downstream_ = std::move(downstream);
1074 }
1075 
delete_downstream()1076 void HttpsUpstream::delete_downstream() {
1077   if (downstream_ && downstream_->accesslog_ready()) {
1078     handler_->write_accesslog(downstream_.get());
1079   }
1080 
1081   downstream_.reset();
1082 }
1083 
get_downstream() const1084 Downstream *HttpsUpstream::get_downstream() const { return downstream_.get(); }
1085 
pop_downstream()1086 std::unique_ptr<Downstream> HttpsUpstream::pop_downstream() {
1087   return std::unique_ptr<Downstream>(downstream_.release());
1088 }
1089 
on_downstream_header_complete(Downstream * downstream)1090 int HttpsUpstream::on_downstream_header_complete(Downstream *downstream) {
1091   if (LOG_ENABLED(INFO)) {
1092     if (downstream->get_non_final_response()) {
1093       DLOG(INFO, downstream) << "HTTP non-final response header";
1094     } else {
1095       DLOG(INFO, downstream) << "HTTP response header completed";
1096     }
1097   }
1098 
1099   const auto &req = downstream->request();
1100   auto &resp = downstream->response();
1101   auto &balloc = downstream->get_block_allocator();
1102   auto dconn = downstream->get_downstream_connection();
1103   // dconn might be nullptr if this is non-final response from mruby.
1104 
1105   if (downstream->get_non_final_response() &&
1106       !downstream->supports_non_final_response()) {
1107     resp.fs.clear_headers();
1108     return 0;
1109   }
1110 
1111 #ifdef HAVE_MRUBY
1112   if (!downstream->get_non_final_response()) {
1113     assert(dconn);
1114     const auto &group = dconn->get_downstream_addr_group();
1115     if (group) {
1116       const auto &dmruby_ctx = group->shared_addr->mruby_ctx;
1117 
1118       if (dmruby_ctx->run_on_response_proc(downstream) != 0) {
1119         error_reply(500);
1120         return -1;
1121       }
1122 
1123       if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1124         return -1;
1125       }
1126     }
1127 
1128     auto worker = handler_->get_worker();
1129     auto mruby_ctx = worker->get_mruby_context();
1130 
1131     if (mruby_ctx->run_on_response_proc(downstream) != 0) {
1132       error_reply(500);
1133       return -1;
1134     }
1135 
1136     if (downstream->get_response_state() == DownstreamState::MSG_COMPLETE) {
1137       return -1;
1138     }
1139   }
1140 #endif // HAVE_MRUBY
1141 
1142   auto connect_method = req.method == HTTP_CONNECT;
1143 
1144   auto buf = downstream->get_response_buf();
1145   buf->append("HTTP/");
1146   buf->append('0' + req.http_major);
1147   buf->append('.');
1148   buf->append('0' + req.http_minor);
1149   buf->append(' ');
1150   if (req.connect_proto != ConnectProto::NONE && downstream->get_upgraded()) {
1151     buf->append(http2::stringify_status(balloc, 101));
1152     buf->append(' ');
1153     buf->append(http2::get_reason_phrase(101));
1154   } else {
1155     buf->append(http2::stringify_status(balloc, resp.http_status));
1156     buf->append(' ');
1157     buf->append(http2::get_reason_phrase(resp.http_status));
1158   }
1159   buf->append("\r\n");
1160 
1161   auto config = get_config();
1162   auto &httpconf = config->http;
1163 
1164   if (!config->http2_proxy && !httpconf.no_location_rewrite) {
1165     downstream->rewrite_location_response_header(
1166         get_client_handler()->get_upstream_scheme());
1167   }
1168 
1169   if (downstream->get_non_final_response()) {
1170     http2::build_http1_headers_from_headers(buf, resp.fs.headers(),
1171                                             http2::HDOP_STRIP_ALL);
1172 
1173     buf->append("\r\n");
1174 
1175     if (LOG_ENABLED(INFO)) {
1176       log_response_headers(buf);
1177     }
1178 
1179     resp.fs.clear_headers();
1180 
1181     return 0;
1182   }
1183 
1184   auto build_flags = (http2::HDOP_STRIP_ALL & ~http2::HDOP_STRIP_VIA) |
1185                      (!http2::legacy_http1(req.http_major, req.http_minor)
1186                           ? 0
1187                           : http2::HDOP_STRIP_TRANSFER_ENCODING);
1188 
1189   http2::build_http1_headers_from_headers(buf, resp.fs.headers(), build_flags);
1190 
1191   auto worker = handler_->get_worker();
1192 
1193   // after graceful shutdown commenced, add connection: close header
1194   // field.
1195   if (httpconf.max_requests <= num_requests_ ||
1196       worker->get_graceful_shutdown()) {
1197     resp.connection_close = true;
1198   }
1199 
1200   // We check downstream->get_response_connection_close() in case when
1201   // the Content-Length is not available.
1202   if (!req.connection_close && !resp.connection_close) {
1203     if (req.http_major <= 0 || req.http_minor <= 0) {
1204       // We add this header for HTTP/1.0 or HTTP/0.9 clients
1205       buf->append("Connection: Keep-Alive\r\n");
1206     }
1207   } else if (!downstream->get_upgraded()) {
1208     buf->append("Connection: close\r\n");
1209   }
1210 
1211   if (!connect_method && downstream->get_upgraded()) {
1212     if (req.connect_proto == ConnectProto::WEBSOCKET &&
1213         resp.http_status / 100 == 2) {
1214       buf->append("Upgrade: websocket\r\nConnection: Upgrade\r\n");
1215       auto key = req.fs.header(http2::HD_SEC_WEBSOCKET_KEY);
1216       if (!key || key->value.size() != base64::encode_length(16)) {
1217         return -1;
1218       }
1219       std::array<uint8_t, base64::encode_length(20)> out;
1220       auto accept = http2::make_websocket_accept_token(out.data(), key->value);
1221       if (accept.empty()) {
1222         return -1;
1223       }
1224       buf->append("Sec-WebSocket-Accept: ");
1225       buf->append(accept);
1226       buf->append("\r\n");
1227     } else {
1228       auto connection = resp.fs.header(http2::HD_CONNECTION);
1229       if (connection) {
1230         buf->append("Connection: ");
1231         buf->append((*connection).value);
1232         buf->append("\r\n");
1233       }
1234 
1235       auto upgrade = resp.fs.header(http2::HD_UPGRADE);
1236       if (upgrade) {
1237         buf->append("Upgrade: ");
1238         buf->append((*upgrade).value);
1239         buf->append("\r\n");
1240       }
1241     }
1242   }
1243 
1244   if (!resp.fs.header(http2::HD_ALT_SVC)) {
1245     // We won't change or alter alt-svc from backend for now
1246     if (!httpconf.altsvcs.empty()) {
1247       buf->append("Alt-Svc: ");
1248       buf->append(httpconf.altsvc_header_value);
1249       buf->append("\r\n");
1250     }
1251   }
1252 
1253   if (!config->http2_proxy && !httpconf.no_server_rewrite) {
1254     buf->append("Server: ");
1255     buf->append(httpconf.server_name);
1256     buf->append("\r\n");
1257   } else {
1258     auto server = resp.fs.header(http2::HD_SERVER);
1259     if (server) {
1260       buf->append("Server: ");
1261       buf->append((*server).value);
1262       buf->append("\r\n");
1263     }
1264   }
1265 
1266   if (req.method != HTTP_CONNECT || !downstream->get_upgraded()) {
1267     auto affinity_cookie = downstream->get_affinity_cookie_to_send();
1268     if (affinity_cookie) {
1269       auto &group = dconn->get_downstream_addr_group();
1270       auto &shared_addr = group->shared_addr;
1271       auto &cookieconf = shared_addr->affinity.cookie;
1272       auto secure =
1273           http::require_cookie_secure_attribute(cookieconf.secure, req.scheme);
1274       auto cookie_str = http::create_affinity_cookie(
1275           balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure);
1276       buf->append("Set-Cookie: ");
1277       buf->append(cookie_str);
1278       buf->append("\r\n");
1279     }
1280   }
1281 
1282   auto via = resp.fs.header(http2::HD_VIA);
1283   if (httpconf.no_via) {
1284     if (via) {
1285       buf->append("Via: ");
1286       buf->append((*via).value);
1287       buf->append("\r\n");
1288     }
1289   } else {
1290     buf->append("Via: ");
1291     if (via) {
1292       buf->append((*via).value);
1293       buf->append(", ");
1294     }
1295     std::array<char, 16> viabuf;
1296     auto end = http::create_via_header_value(viabuf.data(), resp.http_major,
1297                                              resp.http_minor);
1298     buf->append(viabuf.data(), end - std::begin(viabuf));
1299     buf->append("\r\n");
1300   }
1301 
1302   for (auto &p : httpconf.add_response_headers) {
1303     buf->append(p.name);
1304     buf->append(": ");
1305     buf->append(p.value);
1306     buf->append("\r\n");
1307   }
1308 
1309   buf->append("\r\n");
1310 
1311   if (LOG_ENABLED(INFO)) {
1312     log_response_headers(buf);
1313   }
1314 
1315   return 0;
1316 }
1317 
on_downstream_body(Downstream * downstream,const uint8_t * data,size_t len,bool flush)1318 int HttpsUpstream::on_downstream_body(Downstream *downstream,
1319                                       const uint8_t *data, size_t len,
1320                                       bool flush) {
1321   if (len == 0) {
1322     return 0;
1323   }
1324   auto output = downstream->get_response_buf();
1325   if (downstream->get_chunked_response()) {
1326     output->append(util::utox(len));
1327     output->append("\r\n");
1328   }
1329   output->append(data, len);
1330 
1331   downstream->response_sent_body_length += len;
1332 
1333   if (downstream->get_chunked_response()) {
1334     output->append("\r\n");
1335   }
1336   return 0;
1337 }
1338 
on_downstream_body_complete(Downstream * downstream)1339 int HttpsUpstream::on_downstream_body_complete(Downstream *downstream) {
1340   const auto &req = downstream->request();
1341   auto &resp = downstream->response();
1342 
1343   if (downstream->get_chunked_response()) {
1344     auto output = downstream->get_response_buf();
1345     const auto &trailers = resp.fs.trailers();
1346     if (trailers.empty()) {
1347       output->append("0\r\n\r\n");
1348     } else {
1349       output->append("0\r\n");
1350       http2::build_http1_headers_from_headers(output, trailers,
1351                                               http2::HDOP_STRIP_ALL);
1352       output->append("\r\n");
1353     }
1354   }
1355   if (LOG_ENABLED(INFO)) {
1356     DLOG(INFO, downstream) << "HTTP response completed";
1357   }
1358 
1359   if (!downstream->validate_response_recv_body_length()) {
1360     resp.connection_close = true;
1361   }
1362 
1363   if (req.connection_close || resp.connection_close ||
1364       // To avoid to stall upload body
1365       downstream->get_request_state() != DownstreamState::MSG_COMPLETE) {
1366     auto handler = get_client_handler();
1367     handler->set_should_close_after_write(true);
1368   }
1369   return 0;
1370 }
1371 
on_downstream_abort_request(Downstream * downstream,unsigned int status_code)1372 int HttpsUpstream::on_downstream_abort_request(Downstream *downstream,
1373                                                unsigned int status_code) {
1374   error_reply(status_code);
1375   handler_->signal_write();
1376   return 0;
1377 }
1378 
on_downstream_abort_request_with_https_redirect(Downstream * downstream)1379 int HttpsUpstream::on_downstream_abort_request_with_https_redirect(
1380     Downstream *downstream) {
1381   redirect_to_https(downstream);
1382   handler_->signal_write();
1383   return 0;
1384 }
1385 
redirect_to_https(Downstream * downstream)1386 int HttpsUpstream::redirect_to_https(Downstream *downstream) {
1387   auto &req = downstream->request();
1388   if (req.method == HTTP_CONNECT || req.scheme != "http" ||
1389       req.authority.empty()) {
1390     error_reply(400);
1391     return 0;
1392   }
1393 
1394   auto authority = util::extract_host(req.authority);
1395   if (authority.empty()) {
1396     error_reply(400);
1397     return 0;
1398   }
1399 
1400   auto &balloc = downstream->get_block_allocator();
1401   auto config = get_config();
1402   auto &httpconf = config->http;
1403 
1404   StringRef loc;
1405   if (httpconf.redirect_https_port == StringRef::from_lit("443")) {
1406     loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
1407                             req.path);
1408   } else {
1409     loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
1410                             StringRef::from_lit(":"),
1411                             httpconf.redirect_https_port, req.path);
1412   }
1413 
1414   auto &resp = downstream->response();
1415   resp.http_status = 308;
1416   resp.fs.add_header_token(StringRef::from_lit("location"), loc, false,
1417                            http2::HD_LOCATION);
1418   resp.fs.add_header_token(StringRef::from_lit("connection"),
1419                            StringRef::from_lit("close"), false,
1420                            http2::HD_CONNECTION);
1421 
1422   return send_reply(downstream, nullptr, 0);
1423 }
1424 
log_response_headers(DefaultMemchunks * buf) const1425 void HttpsUpstream::log_response_headers(DefaultMemchunks *buf) const {
1426   std::string nhdrs;
1427   for (auto chunk = buf->head; chunk; chunk = chunk->next) {
1428     nhdrs.append(chunk->pos, chunk->last);
1429   }
1430   if (log_config()->errorlog_tty) {
1431     nhdrs = http::colorizeHeaders(nhdrs.c_str());
1432   }
1433   ULOG(INFO, this) << "HTTP response headers\n" << nhdrs;
1434 }
1435 
on_handler_delete()1436 void HttpsUpstream::on_handler_delete() {
1437   if (downstream_ && downstream_->accesslog_ready()) {
1438     handler_->write_accesslog(downstream_.get());
1439   }
1440 }
1441 
on_downstream_reset(Downstream * downstream,bool no_retry)1442 int HttpsUpstream::on_downstream_reset(Downstream *downstream, bool no_retry) {
1443   int rv;
1444   std::unique_ptr<DownstreamConnection> dconn;
1445 
1446   assert(downstream == downstream_.get());
1447 
1448   downstream_->pop_downstream_connection();
1449 
1450   if (!downstream_->request_submission_ready()) {
1451     switch (downstream_->get_response_state()) {
1452     case DownstreamState::MSG_COMPLETE:
1453       // We have got all response body already.  Send it off.
1454       return 0;
1455     case DownstreamState::INITIAL:
1456       if (on_downstream_abort_request(downstream_.get(), 502) != 0) {
1457         return -1;
1458       }
1459       return 0;
1460     default:
1461       break;
1462     }
1463     // Return error so that caller can delete handler
1464     return -1;
1465   }
1466 
1467   downstream_->add_retry();
1468 
1469   rv = 0;
1470 
1471   if (no_retry || downstream_->no_more_retry()) {
1472     goto fail;
1473   }
1474 
1475   for (;;) {
1476     auto dconn = handler_->get_downstream_connection(rv, downstream_.get());
1477     if (!dconn) {
1478       goto fail;
1479     }
1480 
1481     rv = downstream_->attach_downstream_connection(std::move(dconn));
1482     if (rv == 0) {
1483       break;
1484     }
1485   }
1486 
1487   rv = downstream_->push_request_headers();
1488   if (rv != 0) {
1489     goto fail;
1490   }
1491 
1492   return 0;
1493 
1494 fail:
1495   if (rv == SHRPX_ERR_TLS_REQUIRED) {
1496     rv = on_downstream_abort_request_with_https_redirect(downstream);
1497   } else {
1498     rv = on_downstream_abort_request(downstream_.get(), 502);
1499   }
1500   if (rv != 0) {
1501     return -1;
1502   }
1503   downstream_->pop_downstream_connection();
1504 
1505   return 0;
1506 }
1507 
initiate_push(Downstream * downstream,const StringRef & uri)1508 int HttpsUpstream::initiate_push(Downstream *downstream, const StringRef &uri) {
1509   return 0;
1510 }
1511 
response_riovec(struct iovec * iov,int iovcnt) const1512 int HttpsUpstream::response_riovec(struct iovec *iov, int iovcnt) const {
1513   if (!downstream_) {
1514     return 0;
1515   }
1516 
1517   auto buf = downstream_->get_response_buf();
1518 
1519   return buf->riovec(iov, iovcnt);
1520 }
1521 
response_drain(size_t n)1522 void HttpsUpstream::response_drain(size_t n) {
1523   if (!downstream_) {
1524     return;
1525   }
1526 
1527   auto buf = downstream_->get_response_buf();
1528 
1529   buf->drain(n);
1530 }
1531 
response_empty() const1532 bool HttpsUpstream::response_empty() const {
1533   if (!downstream_) {
1534     return true;
1535   }
1536 
1537   auto buf = downstream_->get_response_buf();
1538 
1539   return buf->rleft() == 0;
1540 }
1541 
1542 Downstream *
on_downstream_push_promise(Downstream * downstream,int32_t promised_stream_id)1543 HttpsUpstream::on_downstream_push_promise(Downstream *downstream,
1544                                           int32_t promised_stream_id) {
1545   return nullptr;
1546 }
1547 
on_downstream_push_promise_complete(Downstream * downstream,Downstream * promised_downstream)1548 int HttpsUpstream::on_downstream_push_promise_complete(
1549     Downstream *downstream, Downstream *promised_downstream) {
1550   return -1;
1551 }
1552 
push_enabled() const1553 bool HttpsUpstream::push_enabled() const { return false; }
1554 
cancel_premature_downstream(Downstream * promised_downstream)1555 void HttpsUpstream::cancel_premature_downstream(
1556     Downstream *promised_downstream) {}
1557 
1558 } // namespace shrpx
1559