From f25fd09bbbf4f16b17392e79362dc74d6649741e Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sat, 16 Jan 2016 21:12:51 +0900 Subject: [PATCH] nghttpx: Don't emit :authority if request dones not contain authority info RFC 7540 says that proxy should not emit :authority when translating HTTP/1 request in origin or asterisk form to HTTP/2. To keep this semantics in tact, we should also refrain from emitting :authority if it is missing (host header field is required in this case). --- src/shrpx_downstream.h | 6 +++++- src/shrpx_http2_downstream_connection.cc | 12 +++++++++--- src/shrpx_http2_upstream.cc | 1 + src/shrpx_https_upstream.cc | 2 ++ 4 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index 739e139b..7bc7f0ce 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -127,7 +127,7 @@ struct Request { : fs(16), recv_body_length(0), unconsumed_body_length(0), method(-1), http_major(1), http_minor(1), upgrade_request(false), http2_upgrade_seen(false), connection_close(false), - http2_expect_body(false) {} + http2_expect_body(false), no_authority(false) {} void consume(size_t len) { assert(unconsumed_body_length >= len); @@ -165,6 +165,10 @@ struct Request { // true if this is HTTP/2, and request body is expected. Note that // we don't take into account HTTP method here. bool http2_expect_body; + // true if request does not have any information about authority. + // This happens when: For HTTP/2 request, :authority is missing. + // For HTTP/1 request, origin or asterisk form is used. + bool no_authority; }; struct Response { diff --git a/src/shrpx_http2_downstream_connection.cc b/src/shrpx_http2_downstream_connection.cc index 57db8141..730370cc 100644 --- a/src/shrpx_http2_downstream_connection.cc +++ b/src/shrpx_http2_downstream_connection.cc @@ -287,7 +287,7 @@ int Http2DownstreamConnection::push_request_headers() { // 1. :method // 2. :scheme // 3. :path - // 4. :authority + // 4. :authority (or host) // 5. via (optional) // 6. x-forwarded-for (optional) // 7. x-forwarded-proto (optional) @@ -300,8 +300,6 @@ int Http2DownstreamConnection::push_request_headers() { nva.push_back( http2::make_nv_lc_nocopy(":method", http2::to_method_string(req.method))); - nva.push_back(http2::make_nv_lc_nocopy(":authority", authority)); - if (req.method != HTTP_CONNECT) { assert(!req.scheme.empty()); @@ -312,6 +310,14 @@ int Http2DownstreamConnection::push_request_headers() { } else { nva.push_back(http2::make_nv_ls_nocopy(":path", req.path)); } + + if (!req.no_authority) { + nva.push_back(http2::make_nv_lc_nocopy(":authority", authority)); + } else { + nva.push_back(http2::make_nv_lc_nocopy("host", authority)); + } + } else { + nva.push_back(http2::make_nv_lc_nocopy(":authority", authority)); } http2::copy_headers_to_nva_nocopy(nva, req.fs.headers()); diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index c6779d7d..8cdbbdd7 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -298,6 +298,7 @@ int Http2Upstream::on_request_headers(Downstream *downstream, // nghttp2 library guarantees either :authority or host exist if (!authority) { + req.no_authority = true; authority = req.fs.header(http2::HD_HOST); } diff --git a/src/shrpx_https_upstream.cc b/src/shrpx_https_upstream.cc index 59dfcdaf..18cbab30 100644 --- a/src/shrpx_https_upstream.cc +++ b/src/shrpx_https_upstream.cc @@ -308,6 +308,8 @@ int htp_hdrs_completecb(http_parser *htp) { return -1; } + req.no_authority = true; + if (method == HTTP_OPTIONS && path == "*") { req.path = ""; } else {