12c593315Sopenharmony_ci/*
22c593315Sopenharmony_ci * nghttp2 - HTTP/2 C Library
32c593315Sopenharmony_ci *
42c593315Sopenharmony_ci * Copyright (c) 2012 Tatsuhiro Tsujikawa
52c593315Sopenharmony_ci *
62c593315Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining
72c593315Sopenharmony_ci * a copy of this software and associated documentation files (the
82c593315Sopenharmony_ci * "Software"), to deal in the Software without restriction, including
92c593315Sopenharmony_ci * without limitation the rights to use, copy, modify, merge, publish,
102c593315Sopenharmony_ci * distribute, sublicense, and/or sell copies of the Software, and to
112c593315Sopenharmony_ci * permit persons to whom the Software is furnished to do so, subject to
122c593315Sopenharmony_ci * the following conditions:
132c593315Sopenharmony_ci *
142c593315Sopenharmony_ci * The above copyright notice and this permission notice shall be
152c593315Sopenharmony_ci * included in all copies or substantial portions of the Software.
162c593315Sopenharmony_ci *
172c593315Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
182c593315Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
192c593315Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
202c593315Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
212c593315Sopenharmony_ci * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
222c593315Sopenharmony_ci * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
232c593315Sopenharmony_ci * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
242c593315Sopenharmony_ci */
252c593315Sopenharmony_ci#include "shrpx_http2_downstream_connection.h"
262c593315Sopenharmony_ci
272c593315Sopenharmony_ci#ifdef HAVE_UNISTD_H
282c593315Sopenharmony_ci#  include <unistd.h>
292c593315Sopenharmony_ci#endif // HAVE_UNISTD_H
302c593315Sopenharmony_ci
312c593315Sopenharmony_ci#include "llhttp.h"
322c593315Sopenharmony_ci
332c593315Sopenharmony_ci#include "shrpx_client_handler.h"
342c593315Sopenharmony_ci#include "shrpx_upstream.h"
352c593315Sopenharmony_ci#include "shrpx_downstream.h"
362c593315Sopenharmony_ci#include "shrpx_config.h"
372c593315Sopenharmony_ci#include "shrpx_error.h"
382c593315Sopenharmony_ci#include "shrpx_http.h"
392c593315Sopenharmony_ci#include "shrpx_http2_session.h"
402c593315Sopenharmony_ci#include "shrpx_worker.h"
412c593315Sopenharmony_ci#include "shrpx_log.h"
422c593315Sopenharmony_ci#include "http2.h"
432c593315Sopenharmony_ci#include "util.h"
442c593315Sopenharmony_ci#include "ssl_compat.h"
452c593315Sopenharmony_ci
462c593315Sopenharmony_ciusing namespace nghttp2;
472c593315Sopenharmony_ci
482c593315Sopenharmony_cinamespace shrpx {
492c593315Sopenharmony_ci
502c593315Sopenharmony_ciHttp2DownstreamConnection::Http2DownstreamConnection(Http2Session *http2session)
512c593315Sopenharmony_ci    : dlnext(nullptr),
522c593315Sopenharmony_ci      dlprev(nullptr),
532c593315Sopenharmony_ci      http2session_(http2session),
542c593315Sopenharmony_ci      sd_(nullptr) {}
552c593315Sopenharmony_ci
562c593315Sopenharmony_ciHttp2DownstreamConnection::~Http2DownstreamConnection() {
572c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
582c593315Sopenharmony_ci    DCLOG(INFO, this) << "Deleting";
592c593315Sopenharmony_ci  }
602c593315Sopenharmony_ci  if (downstream_) {
612c593315Sopenharmony_ci    downstream_->disable_downstream_rtimer();
622c593315Sopenharmony_ci    downstream_->disable_downstream_wtimer();
632c593315Sopenharmony_ci
642c593315Sopenharmony_ci    uint32_t error_code;
652c593315Sopenharmony_ci    if (downstream_->get_request_state() == DownstreamState::STREAM_CLOSED &&
662c593315Sopenharmony_ci        downstream_->get_upgraded()) {
672c593315Sopenharmony_ci      // For upgraded connection, send NO_ERROR.  Should we consider
682c593315Sopenharmony_ci      // request states other than DownstreamState::STREAM_CLOSED ?
692c593315Sopenharmony_ci      error_code = NGHTTP2_NO_ERROR;
702c593315Sopenharmony_ci    } else {
712c593315Sopenharmony_ci      error_code = NGHTTP2_INTERNAL_ERROR;
722c593315Sopenharmony_ci    }
732c593315Sopenharmony_ci
742c593315Sopenharmony_ci    if (http2session_->get_state() == Http2SessionState::CONNECTED &&
752c593315Sopenharmony_ci        downstream_->get_downstream_stream_id() != -1) {
762c593315Sopenharmony_ci      submit_rst_stream(downstream_, error_code);
772c593315Sopenharmony_ci
782c593315Sopenharmony_ci      auto &resp = downstream_->response();
792c593315Sopenharmony_ci
802c593315Sopenharmony_ci      http2session_->consume(downstream_->get_downstream_stream_id(),
812c593315Sopenharmony_ci                             resp.unconsumed_body_length);
822c593315Sopenharmony_ci
832c593315Sopenharmony_ci      resp.unconsumed_body_length = 0;
842c593315Sopenharmony_ci
852c593315Sopenharmony_ci      http2session_->signal_write();
862c593315Sopenharmony_ci    }
872c593315Sopenharmony_ci  }
882c593315Sopenharmony_ci  http2session_->remove_downstream_connection(this);
892c593315Sopenharmony_ci
902c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
912c593315Sopenharmony_ci    DCLOG(INFO, this) << "Deleted";
922c593315Sopenharmony_ci  }
932c593315Sopenharmony_ci}
942c593315Sopenharmony_ci
952c593315Sopenharmony_ciint Http2DownstreamConnection::attach_downstream(Downstream *downstream) {
962c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
972c593315Sopenharmony_ci    DCLOG(INFO, this) << "Attaching to DOWNSTREAM:" << downstream;
982c593315Sopenharmony_ci  }
992c593315Sopenharmony_ci  http2session_->add_downstream_connection(this);
1002c593315Sopenharmony_ci  http2session_->signal_write();
1012c593315Sopenharmony_ci
1022c593315Sopenharmony_ci  downstream_ = downstream;
1032c593315Sopenharmony_ci  downstream_->reset_downstream_rtimer();
1042c593315Sopenharmony_ci
1052c593315Sopenharmony_ci  auto &req = downstream_->request();
1062c593315Sopenharmony_ci
1072c593315Sopenharmony_ci  // HTTP/2 disables HTTP Upgrade.
1082c593315Sopenharmony_ci  if (req.method != HTTP_CONNECT && req.connect_proto == ConnectProto::NONE) {
1092c593315Sopenharmony_ci    req.upgrade_request = false;
1102c593315Sopenharmony_ci  }
1112c593315Sopenharmony_ci
1122c593315Sopenharmony_ci  return 0;
1132c593315Sopenharmony_ci}
1142c593315Sopenharmony_ci
1152c593315Sopenharmony_civoid Http2DownstreamConnection::detach_downstream(Downstream *downstream) {
1162c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
1172c593315Sopenharmony_ci    DCLOG(INFO, this) << "Detaching from DOWNSTREAM:" << downstream;
1182c593315Sopenharmony_ci  }
1192c593315Sopenharmony_ci
1202c593315Sopenharmony_ci  auto &resp = downstream_->response();
1212c593315Sopenharmony_ci
1222c593315Sopenharmony_ci  if (downstream_->get_downstream_stream_id() != -1) {
1232c593315Sopenharmony_ci    if (submit_rst_stream(downstream) == 0) {
1242c593315Sopenharmony_ci      http2session_->signal_write();
1252c593315Sopenharmony_ci    }
1262c593315Sopenharmony_ci
1272c593315Sopenharmony_ci    http2session_->consume(downstream_->get_downstream_stream_id(),
1282c593315Sopenharmony_ci                           resp.unconsumed_body_length);
1292c593315Sopenharmony_ci
1302c593315Sopenharmony_ci    resp.unconsumed_body_length = 0;
1312c593315Sopenharmony_ci
1322c593315Sopenharmony_ci    http2session_->signal_write();
1332c593315Sopenharmony_ci  }
1342c593315Sopenharmony_ci
1352c593315Sopenharmony_ci  downstream->disable_downstream_rtimer();
1362c593315Sopenharmony_ci  downstream->disable_downstream_wtimer();
1372c593315Sopenharmony_ci  downstream_ = nullptr;
1382c593315Sopenharmony_ci}
1392c593315Sopenharmony_ci
1402c593315Sopenharmony_ciint Http2DownstreamConnection::submit_rst_stream(Downstream *downstream,
1412c593315Sopenharmony_ci                                                 uint32_t error_code) {
1422c593315Sopenharmony_ci  int rv = -1;
1432c593315Sopenharmony_ci  if (http2session_->get_state() == Http2SessionState::CONNECTED &&
1442c593315Sopenharmony_ci      downstream->get_downstream_stream_id() != -1) {
1452c593315Sopenharmony_ci    switch (downstream->get_response_state()) {
1462c593315Sopenharmony_ci    case DownstreamState::MSG_RESET:
1472c593315Sopenharmony_ci    case DownstreamState::MSG_BAD_HEADER:
1482c593315Sopenharmony_ci    case DownstreamState::MSG_COMPLETE:
1492c593315Sopenharmony_ci      break;
1502c593315Sopenharmony_ci    default:
1512c593315Sopenharmony_ci      if (LOG_ENABLED(INFO)) {
1522c593315Sopenharmony_ci        DCLOG(INFO, this) << "Submit RST_STREAM for DOWNSTREAM:" << downstream
1532c593315Sopenharmony_ci                          << ", stream_id="
1542c593315Sopenharmony_ci                          << downstream->get_downstream_stream_id()
1552c593315Sopenharmony_ci                          << ", error_code=" << error_code;
1562c593315Sopenharmony_ci      }
1572c593315Sopenharmony_ci      rv = http2session_->submit_rst_stream(
1582c593315Sopenharmony_ci          downstream->get_downstream_stream_id(), error_code);
1592c593315Sopenharmony_ci    }
1602c593315Sopenharmony_ci  }
1612c593315Sopenharmony_ci  return rv;
1622c593315Sopenharmony_ci}
1632c593315Sopenharmony_ci
1642c593315Sopenharmony_cinamespace {
1652c593315Sopenharmony_cissize_t http2_data_read_callback(nghttp2_session *session, int32_t stream_id,
1662c593315Sopenharmony_ci                                 uint8_t *buf, size_t length,
1672c593315Sopenharmony_ci                                 uint32_t *data_flags,
1682c593315Sopenharmony_ci                                 nghttp2_data_source *source, void *user_data) {
1692c593315Sopenharmony_ci  int rv;
1702c593315Sopenharmony_ci  auto sd = static_cast<StreamData *>(
1712c593315Sopenharmony_ci      nghttp2_session_get_stream_user_data(session, stream_id));
1722c593315Sopenharmony_ci  if (!sd || !sd->dconn) {
1732c593315Sopenharmony_ci    return NGHTTP2_ERR_DEFERRED;
1742c593315Sopenharmony_ci  }
1752c593315Sopenharmony_ci  auto dconn = sd->dconn;
1762c593315Sopenharmony_ci  auto downstream = dconn->get_downstream();
1772c593315Sopenharmony_ci  if (!downstream) {
1782c593315Sopenharmony_ci    // In this case, RST_STREAM should have been issued. But depending
1792c593315Sopenharmony_ci    // on the priority, DATA frame may come first.
1802c593315Sopenharmony_ci    return NGHTTP2_ERR_DEFERRED;
1812c593315Sopenharmony_ci  }
1822c593315Sopenharmony_ci  const auto &req = downstream->request();
1832c593315Sopenharmony_ci  auto input = downstream->get_request_buf();
1842c593315Sopenharmony_ci
1852c593315Sopenharmony_ci  auto nread = std::min(input->rleft(), length);
1862c593315Sopenharmony_ci  auto input_empty = input->rleft() == nread;
1872c593315Sopenharmony_ci
1882c593315Sopenharmony_ci  *data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
1892c593315Sopenharmony_ci
1902c593315Sopenharmony_ci  if (input_empty &&
1912c593315Sopenharmony_ci      downstream->get_request_state() == DownstreamState::MSG_COMPLETE &&
1922c593315Sopenharmony_ci      // If connection is upgraded, don't set EOF flag, since HTTP/1
1932c593315Sopenharmony_ci      // will set MSG_COMPLETE to request state after upgrade response
1942c593315Sopenharmony_ci      // header is seen.
1952c593315Sopenharmony_ci      (!req.upgrade_request ||
1962c593315Sopenharmony_ci       (downstream->get_response_state() == DownstreamState::HEADER_COMPLETE &&
1972c593315Sopenharmony_ci        !downstream->get_upgraded()))) {
1982c593315Sopenharmony_ci
1992c593315Sopenharmony_ci    *data_flags |= NGHTTP2_DATA_FLAG_EOF;
2002c593315Sopenharmony_ci
2012c593315Sopenharmony_ci    const auto &trailers = req.fs.trailers();
2022c593315Sopenharmony_ci    if (!trailers.empty()) {
2032c593315Sopenharmony_ci      std::vector<nghttp2_nv> nva;
2042c593315Sopenharmony_ci      nva.reserve(trailers.size());
2052c593315Sopenharmony_ci      http2::copy_headers_to_nva_nocopy(nva, trailers, http2::HDOP_STRIP_ALL);
2062c593315Sopenharmony_ci      if (!nva.empty()) {
2072c593315Sopenharmony_ci        rv = nghttp2_submit_trailer(session, stream_id, nva.data(), nva.size());
2082c593315Sopenharmony_ci        if (rv != 0) {
2092c593315Sopenharmony_ci          if (nghttp2_is_fatal(rv)) {
2102c593315Sopenharmony_ci            return NGHTTP2_ERR_CALLBACK_FAILURE;
2112c593315Sopenharmony_ci          }
2122c593315Sopenharmony_ci        } else {
2132c593315Sopenharmony_ci          *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
2142c593315Sopenharmony_ci        }
2152c593315Sopenharmony_ci      }
2162c593315Sopenharmony_ci    }
2172c593315Sopenharmony_ci  }
2182c593315Sopenharmony_ci
2192c593315Sopenharmony_ci  if (nread == 0 && (*data_flags & NGHTTP2_DATA_FLAG_EOF) == 0) {
2202c593315Sopenharmony_ci    downstream->disable_downstream_wtimer();
2212c593315Sopenharmony_ci
2222c593315Sopenharmony_ci    return NGHTTP2_ERR_DEFERRED;
2232c593315Sopenharmony_ci  }
2242c593315Sopenharmony_ci
2252c593315Sopenharmony_ci  return nread;
2262c593315Sopenharmony_ci}
2272c593315Sopenharmony_ci} // namespace
2282c593315Sopenharmony_ci
2292c593315Sopenharmony_ciint Http2DownstreamConnection::push_request_headers() {
2302c593315Sopenharmony_ci  int rv;
2312c593315Sopenharmony_ci  if (!downstream_) {
2322c593315Sopenharmony_ci    return 0;
2332c593315Sopenharmony_ci  }
2342c593315Sopenharmony_ci  if (!http2session_->can_push_request(downstream_)) {
2352c593315Sopenharmony_ci    // The HTTP2 session to the backend has not been established or
2362c593315Sopenharmony_ci    // connection is now being checked.  This function will be called
2372c593315Sopenharmony_ci    // again just after it is established.
2382c593315Sopenharmony_ci    downstream_->set_request_pending(true);
2392c593315Sopenharmony_ci    http2session_->start_checking_connection();
2402c593315Sopenharmony_ci    return 0;
2412c593315Sopenharmony_ci  }
2422c593315Sopenharmony_ci
2432c593315Sopenharmony_ci  downstream_->set_request_pending(false);
2442c593315Sopenharmony_ci
2452c593315Sopenharmony_ci  const auto &req = downstream_->request();
2462c593315Sopenharmony_ci
2472c593315Sopenharmony_ci  if (req.connect_proto != ConnectProto::NONE &&
2482c593315Sopenharmony_ci      !http2session_->get_allow_connect_proto()) {
2492c593315Sopenharmony_ci    return -1;
2502c593315Sopenharmony_ci  }
2512c593315Sopenharmony_ci
2522c593315Sopenharmony_ci  auto &balloc = downstream_->get_block_allocator();
2532c593315Sopenharmony_ci
2542c593315Sopenharmony_ci  auto config = get_config();
2552c593315Sopenharmony_ci  auto &httpconf = config->http;
2562c593315Sopenharmony_ci  auto &http2conf = config->http2;
2572c593315Sopenharmony_ci
2582c593315Sopenharmony_ci  auto no_host_rewrite = httpconf.no_host_rewrite || config->http2_proxy ||
2592c593315Sopenharmony_ci                         req.regular_connect_method();
2602c593315Sopenharmony_ci
2612c593315Sopenharmony_ci  // http2session_ has already in CONNECTED state, so we can get
2622c593315Sopenharmony_ci  // addr_idx here.
2632c593315Sopenharmony_ci  const auto &downstream_hostport = http2session_->get_addr()->hostport;
2642c593315Sopenharmony_ci
2652c593315Sopenharmony_ci  // For HTTP/1.0 request, there is no authority in request.  In that
2662c593315Sopenharmony_ci  // case, we use backend server's host nonetheless.
2672c593315Sopenharmony_ci  auto authority = StringRef(downstream_hostport);
2682c593315Sopenharmony_ci
2692c593315Sopenharmony_ci  if (no_host_rewrite && !req.authority.empty()) {
2702c593315Sopenharmony_ci    authority = req.authority;
2712c593315Sopenharmony_ci  }
2722c593315Sopenharmony_ci
2732c593315Sopenharmony_ci  downstream_->set_request_downstream_host(authority);
2742c593315Sopenharmony_ci
2752c593315Sopenharmony_ci  size_t num_cookies = 0;
2762c593315Sopenharmony_ci  if (!http2conf.no_cookie_crumbling) {
2772c593315Sopenharmony_ci    num_cookies = downstream_->count_crumble_request_cookie();
2782c593315Sopenharmony_ci  }
2792c593315Sopenharmony_ci
2802c593315Sopenharmony_ci  // 11 means:
2812c593315Sopenharmony_ci  // 1. :method
2822c593315Sopenharmony_ci  // 2. :scheme
2832c593315Sopenharmony_ci  // 3. :path
2842c593315Sopenharmony_ci  // 4. :authority (or host)
2852c593315Sopenharmony_ci  // 5. :protocol (optional)
2862c593315Sopenharmony_ci  // 6. via (optional)
2872c593315Sopenharmony_ci  // 7. x-forwarded-for (optional)
2882c593315Sopenharmony_ci  // 8. x-forwarded-proto (optional)
2892c593315Sopenharmony_ci  // 9. te (optional)
2902c593315Sopenharmony_ci  // 10. forwarded (optional)
2912c593315Sopenharmony_ci  // 11. early-data (optional)
2922c593315Sopenharmony_ci  auto nva = std::vector<nghttp2_nv>();
2932c593315Sopenharmony_ci  nva.reserve(req.fs.headers().size() + 11 + num_cookies +
2942c593315Sopenharmony_ci              httpconf.add_request_headers.size());
2952c593315Sopenharmony_ci
2962c593315Sopenharmony_ci  if (req.connect_proto == ConnectProto::WEBSOCKET) {
2972c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ll(":method", "CONNECT"));
2982c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ll(":protocol", "websocket"));
2992c593315Sopenharmony_ci  } else {
3002c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ls_nocopy(
3012c593315Sopenharmony_ci        ":method", http2::to_method_string(req.method)));
3022c593315Sopenharmony_ci  }
3032c593315Sopenharmony_ci
3042c593315Sopenharmony_ci  if (!req.regular_connect_method()) {
3052c593315Sopenharmony_ci    assert(!req.scheme.empty());
3062c593315Sopenharmony_ci
3072c593315Sopenharmony_ci    auto addr = http2session_->get_addr();
3082c593315Sopenharmony_ci    assert(addr);
3092c593315Sopenharmony_ci    // We will handle more protocol scheme upgrade in the future.
3102c593315Sopenharmony_ci    if (addr->tls && addr->upgrade_scheme && req.scheme == "http") {
3112c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ll(":scheme", "https"));
3122c593315Sopenharmony_ci    } else {
3132c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy(":scheme", req.scheme));
3142c593315Sopenharmony_ci    }
3152c593315Sopenharmony_ci
3162c593315Sopenharmony_ci    if (req.method == HTTP_OPTIONS && req.path.empty()) {
3172c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ll(":path", "*"));
3182c593315Sopenharmony_ci    } else {
3192c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy(":path", req.path));
3202c593315Sopenharmony_ci    }
3212c593315Sopenharmony_ci
3222c593315Sopenharmony_ci    if (!req.no_authority || req.connect_proto != ConnectProto::NONE) {
3232c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy(":authority", authority));
3242c593315Sopenharmony_ci    } else {
3252c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy("host", authority));
3262c593315Sopenharmony_ci    }
3272c593315Sopenharmony_ci  } else {
3282c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ls_nocopy(":authority", authority));
3292c593315Sopenharmony_ci  }
3302c593315Sopenharmony_ci
3312c593315Sopenharmony_ci  auto &fwdconf = httpconf.forwarded;
3322c593315Sopenharmony_ci  auto &xffconf = httpconf.xff;
3332c593315Sopenharmony_ci  auto &xfpconf = httpconf.xfp;
3342c593315Sopenharmony_ci  auto &earlydataconf = httpconf.early_data;
3352c593315Sopenharmony_ci
3362c593315Sopenharmony_ci  uint32_t build_flags =
3372c593315Sopenharmony_ci      (fwdconf.strip_incoming ? http2::HDOP_STRIP_FORWARDED : 0) |
3382c593315Sopenharmony_ci      (xffconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_FOR : 0) |
3392c593315Sopenharmony_ci      (xfpconf.strip_incoming ? http2::HDOP_STRIP_X_FORWARDED_PROTO : 0) |
3402c593315Sopenharmony_ci      (earlydataconf.strip_incoming ? http2::HDOP_STRIP_EARLY_DATA : 0) |
3412c593315Sopenharmony_ci      http2::HDOP_STRIP_SEC_WEBSOCKET_KEY;
3422c593315Sopenharmony_ci
3432c593315Sopenharmony_ci  http2::copy_headers_to_nva_nocopy(nva, req.fs.headers(), build_flags);
3442c593315Sopenharmony_ci
3452c593315Sopenharmony_ci  if (!http2conf.no_cookie_crumbling) {
3462c593315Sopenharmony_ci    downstream_->crumble_request_cookie(nva);
3472c593315Sopenharmony_ci  }
3482c593315Sopenharmony_ci
3492c593315Sopenharmony_ci  auto upstream = downstream_->get_upstream();
3502c593315Sopenharmony_ci  auto handler = upstream->get_client_handler();
3512c593315Sopenharmony_ci
3522c593315Sopenharmony_ci#if OPENSSL_1_1_1_API
3532c593315Sopenharmony_ci  auto conn = handler->get_connection();
3542c593315Sopenharmony_ci
3552c593315Sopenharmony_ci  if (conn->tls.ssl && !SSL_is_init_finished(conn->tls.ssl)) {
3562c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ll("early-data", "1"));
3572c593315Sopenharmony_ci  }
3582c593315Sopenharmony_ci#endif // OPENSSL_1_1_1_API
3592c593315Sopenharmony_ci
3602c593315Sopenharmony_ci  auto fwd =
3612c593315Sopenharmony_ci      fwdconf.strip_incoming ? nullptr : req.fs.header(http2::HD_FORWARDED);
3622c593315Sopenharmony_ci
3632c593315Sopenharmony_ci  if (fwdconf.params) {
3642c593315Sopenharmony_ci    auto params = fwdconf.params;
3652c593315Sopenharmony_ci
3662c593315Sopenharmony_ci    if (config->http2_proxy || req.regular_connect_method()) {
3672c593315Sopenharmony_ci      params &= ~FORWARDED_PROTO;
3682c593315Sopenharmony_ci    }
3692c593315Sopenharmony_ci
3702c593315Sopenharmony_ci    auto value = http::create_forwarded(
3712c593315Sopenharmony_ci        balloc, params, handler->get_forwarded_by(),
3722c593315Sopenharmony_ci        handler->get_forwarded_for(), req.authority, req.scheme);
3732c593315Sopenharmony_ci
3742c593315Sopenharmony_ci    if (fwd || !value.empty()) {
3752c593315Sopenharmony_ci      if (fwd) {
3762c593315Sopenharmony_ci        if (value.empty()) {
3772c593315Sopenharmony_ci          value = fwd->value;
3782c593315Sopenharmony_ci        } else {
3792c593315Sopenharmony_ci          value = concat_string_ref(balloc, fwd->value,
3802c593315Sopenharmony_ci                                    StringRef::from_lit(", "), value);
3812c593315Sopenharmony_ci        }
3822c593315Sopenharmony_ci      }
3832c593315Sopenharmony_ci
3842c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy("forwarded", value));
3852c593315Sopenharmony_ci    }
3862c593315Sopenharmony_ci  } else if (fwd) {
3872c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ls_nocopy("forwarded", fwd->value));
3882c593315Sopenharmony_ci  }
3892c593315Sopenharmony_ci
3902c593315Sopenharmony_ci  auto xff = xffconf.strip_incoming ? nullptr
3912c593315Sopenharmony_ci                                    : req.fs.header(http2::HD_X_FORWARDED_FOR);
3922c593315Sopenharmony_ci
3932c593315Sopenharmony_ci  if (xffconf.add) {
3942c593315Sopenharmony_ci    StringRef xff_value;
3952c593315Sopenharmony_ci    const auto &addr = upstream->get_client_handler()->get_ipaddr();
3962c593315Sopenharmony_ci    if (xff) {
3972c593315Sopenharmony_ci      xff_value = concat_string_ref(balloc, xff->value,
3982c593315Sopenharmony_ci                                    StringRef::from_lit(", "), addr);
3992c593315Sopenharmony_ci    } else {
4002c593315Sopenharmony_ci      xff_value = addr;
4012c593315Sopenharmony_ci    }
4022c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", xff_value));
4032c593315Sopenharmony_ci  } else if (xff) {
4042c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-for", xff->value));
4052c593315Sopenharmony_ci  }
4062c593315Sopenharmony_ci
4072c593315Sopenharmony_ci  if (!config->http2_proxy && !req.regular_connect_method()) {
4082c593315Sopenharmony_ci    auto xfp = xfpconf.strip_incoming
4092c593315Sopenharmony_ci                   ? nullptr
4102c593315Sopenharmony_ci                   : req.fs.header(http2::HD_X_FORWARDED_PROTO);
4112c593315Sopenharmony_ci
4122c593315Sopenharmony_ci    if (xfpconf.add) {
4132c593315Sopenharmony_ci      StringRef xfp_value;
4142c593315Sopenharmony_ci      // We use same protocol with :scheme header field
4152c593315Sopenharmony_ci      if (xfp) {
4162c593315Sopenharmony_ci        xfp_value = concat_string_ref(balloc, xfp->value,
4172c593315Sopenharmony_ci                                      StringRef::from_lit(", "), req.scheme);
4182c593315Sopenharmony_ci      } else {
4192c593315Sopenharmony_ci        xfp_value = req.scheme;
4202c593315Sopenharmony_ci      }
4212c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", xfp_value));
4222c593315Sopenharmony_ci    } else if (xfp) {
4232c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy("x-forwarded-proto", xfp->value));
4242c593315Sopenharmony_ci    }
4252c593315Sopenharmony_ci  }
4262c593315Sopenharmony_ci
4272c593315Sopenharmony_ci  auto via = req.fs.header(http2::HD_VIA);
4282c593315Sopenharmony_ci  if (httpconf.no_via) {
4292c593315Sopenharmony_ci    if (via) {
4302c593315Sopenharmony_ci      nva.push_back(http2::make_nv_ls_nocopy("via", (*via).value));
4312c593315Sopenharmony_ci    }
4322c593315Sopenharmony_ci  } else {
4332c593315Sopenharmony_ci    size_t vialen = 16;
4342c593315Sopenharmony_ci    if (via) {
4352c593315Sopenharmony_ci      vialen += via->value.size() + 2;
4362c593315Sopenharmony_ci    }
4372c593315Sopenharmony_ci
4382c593315Sopenharmony_ci    auto iov = make_byte_ref(balloc, vialen + 1);
4392c593315Sopenharmony_ci    auto p = iov.base;
4402c593315Sopenharmony_ci
4412c593315Sopenharmony_ci    if (via) {
4422c593315Sopenharmony_ci      p = std::copy(std::begin(via->value), std::end(via->value), p);
4432c593315Sopenharmony_ci      p = util::copy_lit(p, ", ");
4442c593315Sopenharmony_ci    }
4452c593315Sopenharmony_ci    p = http::create_via_header_value(p, req.http_major, req.http_minor);
4462c593315Sopenharmony_ci    *p = '\0';
4472c593315Sopenharmony_ci
4482c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ls_nocopy("via", StringRef{iov.base, p}));
4492c593315Sopenharmony_ci  }
4502c593315Sopenharmony_ci
4512c593315Sopenharmony_ci  auto te = req.fs.header(http2::HD_TE);
4522c593315Sopenharmony_ci  // HTTP/1 upstream request can contain keyword other than
4532c593315Sopenharmony_ci  // "trailers".  We just forward "trailers".
4542c593315Sopenharmony_ci  // TODO more strict handling required here.
4552c593315Sopenharmony_ci  if (te && http2::contains_trailers(te->value)) {
4562c593315Sopenharmony_ci    nva.push_back(http2::make_nv_ll("te", "trailers"));
4572c593315Sopenharmony_ci  }
4582c593315Sopenharmony_ci
4592c593315Sopenharmony_ci  for (auto &p : httpconf.add_request_headers) {
4602c593315Sopenharmony_ci    nva.push_back(http2::make_nv_nocopy(p.name, p.value));
4612c593315Sopenharmony_ci  }
4622c593315Sopenharmony_ci
4632c593315Sopenharmony_ci  if (LOG_ENABLED(INFO)) {
4642c593315Sopenharmony_ci    std::stringstream ss;
4652c593315Sopenharmony_ci    for (auto &nv : nva) {
4662c593315Sopenharmony_ci      if (util::streq_l("authorization", nv.name, nv.namelen)) {
4672c593315Sopenharmony_ci        ss << TTY_HTTP_HD << StringRef{nv.name, nv.namelen} << TTY_RST
4682c593315Sopenharmony_ci           << ": <redacted>\n";
4692c593315Sopenharmony_ci        continue;
4702c593315Sopenharmony_ci      }
4712c593315Sopenharmony_ci      ss << TTY_HTTP_HD << StringRef{nv.name, nv.namelen} << TTY_RST << ": "
4722c593315Sopenharmony_ci         << StringRef{nv.value, nv.valuelen} << "\n";
4732c593315Sopenharmony_ci    }
4742c593315Sopenharmony_ci    DCLOG(INFO, this) << "HTTP request headers\n" << ss.str();
4752c593315Sopenharmony_ci  }
4762c593315Sopenharmony_ci
4772c593315Sopenharmony_ci  auto transfer_encoding = req.fs.header(http2::HD_TRANSFER_ENCODING);
4782c593315Sopenharmony_ci
4792c593315Sopenharmony_ci  nghttp2_data_provider *data_prdptr = nullptr;
4802c593315Sopenharmony_ci  nghttp2_data_provider data_prd;
4812c593315Sopenharmony_ci
4822c593315Sopenharmony_ci  // Add body as long as transfer-encoding is given even if
4832c593315Sopenharmony_ci  // req.fs.content_length == 0 to forward trailer fields.
4842c593315Sopenharmony_ci  if (req.method == HTTP_CONNECT || req.connect_proto != ConnectProto::NONE ||
4852c593315Sopenharmony_ci      transfer_encoding || req.fs.content_length > 0 || req.http2_expect_body) {
4862c593315Sopenharmony_ci    // Request-body is expected.
4872c593315Sopenharmony_ci    data_prd = {{}, http2_data_read_callback};
4882c593315Sopenharmony_ci    data_prdptr = &data_prd;
4892c593315Sopenharmony_ci  }
4902c593315Sopenharmony_ci
4912c593315Sopenharmony_ci  rv = http2session_->submit_request(this, nva.data(), nva.size(), data_prdptr);
4922c593315Sopenharmony_ci  if (rv != 0) {
4932c593315Sopenharmony_ci    DCLOG(FATAL, this) << "nghttp2_submit_request() failed";
4942c593315Sopenharmony_ci    return -1;
4952c593315Sopenharmony_ci  }
4962c593315Sopenharmony_ci
4972c593315Sopenharmony_ci  if (data_prdptr) {
4982c593315Sopenharmony_ci    downstream_->reset_downstream_wtimer();
4992c593315Sopenharmony_ci  }
5002c593315Sopenharmony_ci
5012c593315Sopenharmony_ci  http2session_->signal_write();
5022c593315Sopenharmony_ci  return 0;
5032c593315Sopenharmony_ci}
5042c593315Sopenharmony_ci
5052c593315Sopenharmony_ciint Http2DownstreamConnection::push_upload_data_chunk(const uint8_t *data,
5062c593315Sopenharmony_ci                                                      size_t datalen) {
5072c593315Sopenharmony_ci  if (!downstream_->get_request_header_sent()) {
5082c593315Sopenharmony_ci    auto output = downstream_->get_blocked_request_buf();
5092c593315Sopenharmony_ci    auto &req = downstream_->request();
5102c593315Sopenharmony_ci    output->append(data, datalen);
5112c593315Sopenharmony_ci    req.unconsumed_body_length += datalen;
5122c593315Sopenharmony_ci    return 0;
5132c593315Sopenharmony_ci  }
5142c593315Sopenharmony_ci
5152c593315Sopenharmony_ci  int rv;
5162c593315Sopenharmony_ci  auto output = downstream_->get_request_buf();
5172c593315Sopenharmony_ci  output->append(data, datalen);
5182c593315Sopenharmony_ci  if (downstream_->get_downstream_stream_id() != -1) {
5192c593315Sopenharmony_ci    rv = http2session_->resume_data(this);
5202c593315Sopenharmony_ci    if (rv != 0) {
5212c593315Sopenharmony_ci      return -1;
5222c593315Sopenharmony_ci    }
5232c593315Sopenharmony_ci
5242c593315Sopenharmony_ci    downstream_->ensure_downstream_wtimer();
5252c593315Sopenharmony_ci
5262c593315Sopenharmony_ci    http2session_->signal_write();
5272c593315Sopenharmony_ci  }
5282c593315Sopenharmony_ci  return 0;
5292c593315Sopenharmony_ci}
5302c593315Sopenharmony_ci
5312c593315Sopenharmony_ciint Http2DownstreamConnection::end_upload_data() {
5322c593315Sopenharmony_ci  if (!downstream_->get_request_header_sent()) {
5332c593315Sopenharmony_ci    downstream_->set_blocked_request_data_eof(true);
5342c593315Sopenharmony_ci    return 0;
5352c593315Sopenharmony_ci  }
5362c593315Sopenharmony_ci
5372c593315Sopenharmony_ci  int rv;
5382c593315Sopenharmony_ci  if (downstream_->get_downstream_stream_id() != -1) {
5392c593315Sopenharmony_ci    rv = http2session_->resume_data(this);
5402c593315Sopenharmony_ci    if (rv != 0) {
5412c593315Sopenharmony_ci      return -1;
5422c593315Sopenharmony_ci    }
5432c593315Sopenharmony_ci
5442c593315Sopenharmony_ci    downstream_->ensure_downstream_wtimer();
5452c593315Sopenharmony_ci
5462c593315Sopenharmony_ci    http2session_->signal_write();
5472c593315Sopenharmony_ci  }
5482c593315Sopenharmony_ci  return 0;
5492c593315Sopenharmony_ci}
5502c593315Sopenharmony_ci
5512c593315Sopenharmony_ciint Http2DownstreamConnection::resume_read(IOCtrlReason reason,
5522c593315Sopenharmony_ci                                           size_t consumed) {
5532c593315Sopenharmony_ci  int rv;
5542c593315Sopenharmony_ci
5552c593315Sopenharmony_ci  if (http2session_->get_state() != Http2SessionState::CONNECTED) {
5562c593315Sopenharmony_ci    return 0;
5572c593315Sopenharmony_ci  }
5582c593315Sopenharmony_ci
5592c593315Sopenharmony_ci  if (!downstream_ || downstream_->get_downstream_stream_id() == -1) {
5602c593315Sopenharmony_ci    return 0;
5612c593315Sopenharmony_ci  }
5622c593315Sopenharmony_ci
5632c593315Sopenharmony_ci  if (consumed > 0) {
5642c593315Sopenharmony_ci    rv = http2session_->consume(downstream_->get_downstream_stream_id(),
5652c593315Sopenharmony_ci                                consumed);
5662c593315Sopenharmony_ci
5672c593315Sopenharmony_ci    if (rv != 0) {
5682c593315Sopenharmony_ci      return -1;
5692c593315Sopenharmony_ci    }
5702c593315Sopenharmony_ci
5712c593315Sopenharmony_ci    auto &resp = downstream_->response();
5722c593315Sopenharmony_ci
5732c593315Sopenharmony_ci    resp.unconsumed_body_length -= consumed;
5742c593315Sopenharmony_ci
5752c593315Sopenharmony_ci    http2session_->signal_write();
5762c593315Sopenharmony_ci  }
5772c593315Sopenharmony_ci
5782c593315Sopenharmony_ci  return 0;
5792c593315Sopenharmony_ci}
5802c593315Sopenharmony_ci
5812c593315Sopenharmony_ciint Http2DownstreamConnection::on_read() { return 0; }
5822c593315Sopenharmony_ci
5832c593315Sopenharmony_ciint Http2DownstreamConnection::on_write() { return 0; }
5842c593315Sopenharmony_ci
5852c593315Sopenharmony_civoid Http2DownstreamConnection::attach_stream_data(StreamData *sd) {
5862c593315Sopenharmony_ci  // It is possible sd->dconn is not NULL. sd is detached when
5872c593315Sopenharmony_ci  // on_stream_close_callback. Before that, after MSG_COMPLETE is set
5882c593315Sopenharmony_ci  // to Downstream::set_response_state(), upstream's readcb is called
5892c593315Sopenharmony_ci  // and execution path eventually could reach here. Since the
5902c593315Sopenharmony_ci  // response was already handled, we just detach sd.
5912c593315Sopenharmony_ci  detach_stream_data();
5922c593315Sopenharmony_ci  sd_ = sd;
5932c593315Sopenharmony_ci  sd_->dconn = this;
5942c593315Sopenharmony_ci}
5952c593315Sopenharmony_ci
5962c593315Sopenharmony_ciStreamData *Http2DownstreamConnection::detach_stream_data() {
5972c593315Sopenharmony_ci  if (sd_) {
5982c593315Sopenharmony_ci    auto sd = sd_;
5992c593315Sopenharmony_ci    sd_ = nullptr;
6002c593315Sopenharmony_ci    sd->dconn = nullptr;
6012c593315Sopenharmony_ci    return sd;
6022c593315Sopenharmony_ci  }
6032c593315Sopenharmony_ci  return nullptr;
6042c593315Sopenharmony_ci}
6052c593315Sopenharmony_ci
6062c593315Sopenharmony_ciint Http2DownstreamConnection::on_timeout() {
6072c593315Sopenharmony_ci  if (!downstream_) {
6082c593315Sopenharmony_ci    return 0;
6092c593315Sopenharmony_ci  }
6102c593315Sopenharmony_ci
6112c593315Sopenharmony_ci  return submit_rst_stream(downstream_, NGHTTP2_NO_ERROR);
6122c593315Sopenharmony_ci}
6132c593315Sopenharmony_ci
6142c593315Sopenharmony_ciconst std::shared_ptr<DownstreamAddrGroup> &
6152c593315Sopenharmony_ciHttp2DownstreamConnection::get_downstream_addr_group() const {
6162c593315Sopenharmony_ci  return http2session_->get_downstream_addr_group();
6172c593315Sopenharmony_ci}
6182c593315Sopenharmony_ci
6192c593315Sopenharmony_ciDownstreamAddr *Http2DownstreamConnection::get_addr() const { return nullptr; }
6202c593315Sopenharmony_ci
6212c593315Sopenharmony_ci} // namespace shrpx
622