From cf5ac0f36370504510d94a19c7ef109c23bca3e0 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 1 Mar 2015 11:03:48 +0900 Subject: [PATCH] nghttpx: Fix broken server push after HTTP upgrade --- src/shrpx_http2_upstream.cc | 52 ++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 7 deletions(-) diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 5306403d..f81593cc 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -106,6 +106,35 @@ int on_stream_close_callback(nghttp2_session *session, int32_t stream_id, int Http2Upstream::upgrade_upstream(HttpsUpstream *http) { int rv; + // to deduce :scheme and :authority, first we have to parse request + // URI. + http_parser_url u = {}; + auto &url = http->get_downstream()->get_request_path(); + + std::string scheme, authority; + rv = http_parser_parse_url(url.c_str(), url.size(), 0, &u); + if (rv == 0) { + http2::copy_url_component(scheme, &u, UF_SCHEMA, url.c_str()); + http2::copy_url_component(authority, &u, UF_HOST, url.c_str()); + } + if (scheme.empty()) { + if (handler_->get_ssl()) { + scheme = "https"; + } else { + scheme = "http"; + } + } + if (!authority.empty()) { + if (authority.find(":") != std::string::npos) { + authority = "[" + authority; + authority += "]"; + } + if (u.field_set & (1 << UF_PORT)) { + authority += ":"; + authority += util::utos(u.port); + } + } + auto http2_settings = http->get_downstream()->get_http2_settings(); util::to_base64(http2_settings); @@ -129,6 +158,8 @@ int Http2Upstream::upgrade_upstream(HttpsUpstream *http) { downstream->reset_upstream_rtimer(); downstream->set_stream_id(1); downstream->set_priority(0); + downstream->set_request_http2_authority(authority); + downstream->set_request_http2_scheme(scheme); downstream_queue_.add_active(std::move(downstream)); @@ -1525,11 +1556,25 @@ int Http2Upstream::submit_push_promise(const std::string &path, int rv; std::vector nva; nva.reserve(downstream->get_request_headers().size()); + + // juse use "GET" for now + nva.push_back(http2::make_nv_ll(":method", "GET")); + nva.push_back( + http2::make_nv(":scheme", downstream->get_request_http2_scheme())); + nva.push_back(http2::make_nv_ls(":path", path)); + auto &authority = downstream->get_request_http2_authority(); + if (!authority.empty()) { + nva.push_back(http2::make_nv(":authority", authority)); + } + for (auto &kv : downstream->get_request_headers()) { switch (kv.token) { // TODO generate referer case http2::HD__AUTHORITY: case http2::HD__SCHEME: + case http2::HD__METHOD: + case http2::HD__PATH: + continue; case http2::HD_ACCEPT_ENCODING: case http2::HD_ACCEPT_LANGUAGE: case http2::HD_CACHE_CONTROL: @@ -1537,13 +1582,6 @@ int Http2Upstream::submit_push_promise(const std::string &path, case http2::HD_USER_AGENT: nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index)); break; - case http2::HD__METHOD: - // juse use "GET" for now - nva.push_back(http2::make_nv_lc(":method", "GET")); - continue; - case http2::HD__PATH: - nva.push_back(http2::make_nv_ls(":path", path)); - continue; } }