diff --git a/doc/nghttpx.h2r b/doc/nghttpx.h2r index 2ad8da76..ac089c37 100644 --- a/doc/nghttpx.h2r +++ b/doc/nghttpx.h2r @@ -59,17 +59,12 @@ header field to initiate server push: Link: ; rel=preload Link: ; rel=preload -Currently, the following restrictions are applied for server push: +Currently, the following restriction is applied for server push: -1. URI-reference must not contain authority. If it exists, it is not - pushed. ``/fonts/font.woff`` and ``css/theme.css`` are eligible to - be pushed. ``https://example.org/fonts/font.woff`` and - ``//example.org/css/theme.css`` are not. - -2. The associated stream must have method "GET" or "POST". The +1. The associated stream must have method "GET" or "POST". The associated stream's status code must be 200. -These limitations may be loosened in the future release. +This limitation may be loosened in the future release. UNIX DOMAIN SOCKET ------------------ diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index 9659596c..a1700e44 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -1501,6 +1501,7 @@ int Http2Upstream::prepare_push_promise(Downstream *downstream) { const char *relq = nullptr; size_t relqlen = 0; + std::string authority, scheme; http_parser_url v{}; rv = http_parser_parse_url(link_url, link_urllen, 0, &v); if (rv != 0) { @@ -1518,9 +1519,18 @@ int Http2Upstream::prepare_push_promise(Downstream *downstream) { relqlen = end - relq; } } else { - if (v.field_set & (1 << UF_HOST)) { - continue; + if (v.field_set & (1 << UF_SCHEMA)) { + http2::copy_url_component(scheme, &v, UF_SCHEMA, link_url); } + + if (v.field_set & (1 << UF_HOST)) { + http2::copy_url_component(authority, &v, UF_HOST, link_url); + if (v.field_set & (1 << UF_PORT)) { + authority += ":"; + authority += util::utos(v.port); + } + } + if (v.field_set & (1 << UF_PATH)) { auto &f = v.field_data[UF_PATH]; rel = link_url + f.off; @@ -1536,9 +1546,18 @@ int Http2Upstream::prepare_push_promise(Downstream *downstream) { relqlen = f.len; } } + + if (scheme.empty()) { + scheme = downstream->get_request_http2_scheme(); + } + + if (authority.empty()) { + authority = downstream->get_request_http2_authority(); + } + auto path = http2::path_join(base, baselen, nullptr, 0, rel, rellen, relq, relqlen); - rv = submit_push_promise(path, downstream); + rv = submit_push_promise(scheme, authority, path, downstream); if (rv != 0) { return -1; } @@ -1547,7 +1566,9 @@ int Http2Upstream::prepare_push_promise(Downstream *downstream) { return 0; } -int Http2Upstream::submit_push_promise(const std::string &path, +int Http2Upstream::submit_push_promise(const std::string &scheme, + const std::string &authority, + const std::string &path, Downstream *downstream) { int rv; std::vector nva; @@ -1555,13 +1576,9 @@ int Http2Upstream::submit_push_promise(const std::string &path, // juse use "GET" for now nva.push_back(http2::make_nv_ll(":method", "GET")); - nva.push_back( - http2::make_nv_ls(":scheme", downstream->get_request_http2_scheme())); + nva.push_back(http2::make_nv_ls(":scheme", 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_ls(":authority", authority)); - } + nva.push_back(http2::make_nv_ls(":authority", authority)); for (auto &kv : downstream->get_request_headers()) { switch (kv.token) { diff --git a/src/shrpx_http2_upstream.h b/src/shrpx_http2_upstream.h index ef8c0bee..564f71f5 100644 --- a/src/shrpx_http2_upstream.h +++ b/src/shrpx_http2_upstream.h @@ -96,7 +96,9 @@ public: void check_shutdown(); int prepare_push_promise(Downstream *downstream); - int submit_push_promise(const std::string &path, Downstream *downstream); + int submit_push_promise(const std::string &scheme, + const std::string &authority, const std::string &path, + Downstream *downstream); int on_request_headers(Downstream *downstream, const nghttp2_frame *frame);