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