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