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