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