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