From 02bb2c3e835880253078ed5a2014408bdd7e9993 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Thu, 3 Sep 2015 23:36:49 +0900 Subject: [PATCH] nghttpx: Create authority from host or authority-form for CONNECT request --- src/shrpx_downstream.cc | 4 ++ src/shrpx_downstream.h | 10 ++-- src/shrpx_http2_downstream_connection.cc | 60 ++++++------------------ src/shrpx_http2_upstream.cc | 5 ++ src/shrpx_http_downstream_connection.cc | 58 ++++++----------------- src/shrpx_https_upstream.cc | 24 ++++++++-- 6 files changed, 63 insertions(+), 98 deletions(-) diff --git a/src/shrpx_downstream.cc b/src/shrpx_downstream.cc index 9c94a2de..5948b1db 100644 --- a/src/shrpx_downstream.cc +++ b/src/shrpx_downstream.cc @@ -515,6 +515,10 @@ void Downstream::set_request_http2_authority(std::string authority) { request_http2_authority_ = std::move(authority); } +void Downstream::append_request_http2_authority(const char *data, size_t len) { + request_http2_authority_.append(data, len); +} + void Downstream::set_request_major(int major) { request_major_ = major; } void Downstream::set_request_minor(int minor) { request_minor_ = minor; } diff --git a/src/shrpx_downstream.h b/src/shrpx_downstream.h index 860934c5..f90e80ce 100644 --- a/src/shrpx_downstream.h +++ b/src/shrpx_downstream.h @@ -150,15 +150,19 @@ public: get_request_start_time() const; void append_request_path(const char *data, size_t len); // Returns request path. For HTTP/1.1, this is request-target. For - // HTTP/2, this is :path header field value. + // HTTP/2, this is :path header field value. For CONNECT request, + // this is empty. const std::string &get_request_path() const; // Returns HTTP/2 :scheme header field value. const std::string &get_request_http2_scheme() const; void set_request_http2_scheme(std::string scheme); - // Returns HTTP/2 :authority header field value. We also set the - // value retrieved from absolute-form HTTP/1 request. + // Returns :authority or host header field value. We may deduce it + // from absolute-form HTTP/1 request. We also store authority-form + // HTTP/1 request. This could be empty if request comes from + // HTTP/1.0 without Host header field and origin-form. const std::string &get_request_http2_authority() const; void set_request_http2_authority(std::string authority); + void append_request_http2_authority(const char *data, size_t len); void set_request_major(int major); void set_request_minor(int minor); int get_request_major() const; diff --git a/src/shrpx_http2_downstream_connection.cc b/src/shrpx_http2_downstream_connection.cc index f4377b44..7e7d9f20 100644 --- a/src/shrpx_http2_downstream_connection.cc +++ b/src/shrpx_http2_downstream_connection.cc @@ -265,37 +265,21 @@ int Http2DownstreamConnection::push_request_headers() { .addrs[addr_idx] .hostport.get(); - const char *authority = nullptr, *host = nullptr; - if (!no_host_rewrite) { - if (!downstream_->get_request_http2_authority().empty()) { - authority = downstream_hostport; - } - if (downstream_->get_request_header(http2::HD_HOST)) { - host = downstream_hostport; - } - } else { - if (!downstream_->get_request_http2_authority().empty()) { - authority = downstream_->get_request_http2_authority().c_str(); - } - auto h = downstream_->get_request_header(http2::HD_HOST); - if (h) { - host = h->value.c_str(); - } + // For HTTP/1.0 request, there is no authority in request. In that + // case, we use backend server's host nonetheless. + const char *authority = downstream_hostport; + auto &req_authority = downstream_->get_request_http2_authority(); + if (no_host_rewrite && !req_authority.empty()) { + authority = req_authority.c_str(); } - if (!authority && !host) { - // upstream is HTTP/1.0. We use backend server's host - // nonetheless. - host = downstream_hostport; + if (!authority) { + authority = downstream_hostport; } - if (authority) { - downstream_->set_request_downstream_host(authority); - } else { - downstream_->set_request_downstream_host(host); - } + downstream_->set_request_downstream_host(authority); - size_t nheader = downstream_->get_request_headers().size(); + auto nheader = downstream_->get_request_headers().size(); Headers cookies; if (!get_config()->http2_no_cookie_crumbling) { @@ -306,7 +290,7 @@ int Http2DownstreamConnection::push_request_headers() { // 1. :method // 2. :scheme // 3. :path - // 4. :authority or host (at least either of them exists) + // 4. :authority // 5. via (optional) // 6. x-forwarded-for (optional) // 7. x-forwarded-proto (optional) @@ -320,30 +304,14 @@ int Http2DownstreamConnection::push_request_headers() { auto &scheme = downstream_->get_request_http2_scheme(); - if (downstream_->get_request_method() == HTTP_CONNECT) { - if (authority) { - nva.push_back(http2::make_nv_lc(":authority", authority)); - } else { - nva.push_back( - http2::make_nv_ls(":authority", downstream_->get_request_path())); - } - } else { + nva.push_back(http2::make_nv_lc(":authority", authority)); + + if (downstream_->get_request_method() != HTTP_CONNECT) { assert(!scheme.empty()); nva.push_back(http2::make_nv_ls(":scheme", scheme)); - - if (authority) { - nva.push_back(http2::make_nv_lc(":authority", authority)); - } - nva.push_back(http2::make_nv_ls(":path", downstream_->get_request_path())); } - // only emit host header field if :authority is not emitted. They - // both must be the same value. - if (!authority && host) { - nva.push_back(http2::make_nv_lc("host", host)); - } - http2::copy_headers_to_nva(nva, downstream_->get_request_headers()); bool chunked_encoding = false; diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc index ee603e13..245208e0 100644 --- a/src/shrpx_http2_upstream.cc +++ b/src/shrpx_http2_upstream.cc @@ -292,7 +292,12 @@ int Http2Upstream::on_request_headers(Downstream *downstream, downstream->set_request_method(method_token); downstream->set_request_http2_scheme(http2::value_to_str(scheme)); + // nghttp2 library guarantees either :authority or host exist + if (!authority) { + authority = downstream->get_request_header(http2::HD_HOST); + } downstream->set_request_http2_authority(http2::value_to_str(authority)); + if (path) { if (get_config()->http2_proxy || get_config()->client_proxy) { downstream->set_request_path(http2::value_to_str(path)); diff --git a/src/shrpx_http_downstream_connection.cc b/src/shrpx_http_downstream_connection.cc index d27b6cd0..b039d4fa 100644 --- a/src/shrpx_http_downstream_connection.cc +++ b/src/shrpx_http_downstream_connection.cc @@ -209,42 +209,25 @@ int HttpDownstreamConnection::attach_downstream(Downstream *downstream) { } int HttpDownstreamConnection::push_request_headers() { - const char *authority = nullptr, *host = nullptr; auto downstream_hostport = get_config() ->downstream_addr_groups[group_] .addrs[addr_idx_] .hostport.get(); auto connect_method = downstream_->get_request_method() == HTTP_CONNECT; - if (!get_config()->no_host_rewrite && !get_config()->http2_proxy && - !get_config()->client_proxy && !connect_method) { - if (!downstream_->get_request_http2_authority().empty()) { - authority = downstream_hostport; - } - if (downstream_->get_request_header(http2::HD_HOST)) { - host = downstream_hostport; - } - } else { - if (!downstream_->get_request_http2_authority().empty()) { - authority = downstream_->get_request_http2_authority().c_str(); - } - auto h = downstream_->get_request_header(http2::HD_HOST); - if (h) { - host = h->value.c_str(); - } + // For HTTP/1.0 request, there is no authority in request. In that + // case, we use backend server's host nonetheless. + const char *authority = downstream_hostport; + auto &req_authority = downstream_->get_request_http2_authority(); + auto no_host_rewrite = get_config()->no_host_rewrite || + get_config()->http2_proxy || + get_config()->client_proxy || connect_method; + + if (no_host_rewrite && !req_authority.empty()) { + authority = req_authority.c_str(); } - if (!authority && !host) { - // upstream is HTTP/1.0. We use backend server's host - // nonetheless. - host = downstream_hostport; - } - - if (authority) { - downstream_->set_request_downstream_host(authority); - } else { - downstream_->set_request_downstream_host(host); - } + downstream_->set_request_downstream_host(authority); downstream_->assemble_request_cookie(); @@ -255,23 +238,14 @@ int HttpDownstreamConnection::push_request_headers() { auto &scheme = downstream_->get_request_http2_scheme(); if (connect_method) { - if (authority) { - hdrs += authority; - } else { - hdrs += downstream_->get_request_path(); - } + hdrs += authority; } else if (get_config()->http2_proxy || get_config()->client_proxy) { // Construct absolute-form request target because we are going to // send a request to a HTTP/1 proxy. assert(!scheme.empty()); hdrs += scheme; hdrs += "://"; - - if (authority) { - hdrs += authority; - } else { - hdrs += host; - } + hdrs += authority; // Server-wide OPTIONS takes following form in proxy request: // @@ -287,11 +261,7 @@ int HttpDownstreamConnection::push_request_headers() { hdrs += downstream_->get_request_path(); } hdrs += " HTTP/1.1\r\nHost: "; - if (authority) { - hdrs += authority; - } else { - hdrs += host; - } + hdrs += authority; hdrs += "\r\n"; http2::build_http1_headers_from_headers(hdrs, diff --git a/src/shrpx_https_upstream.cc b/src/shrpx_https_upstream.cc index a7a45ed2..d6ab64e1 100644 --- a/src/shrpx_https_upstream.cc +++ b/src/shrpx_https_upstream.cc @@ -70,8 +70,14 @@ int htp_msg_begin(http_parser *htp) { auto handler = upstream->get_client_handler(); // TODO specify 0 as priority for now - upstream->attach_downstream( - make_unique(upstream, handler->get_mcpool(), 0, 0)); + auto downstream = + make_unique(upstream, handler->get_mcpool(), 0, 0); + + // We happen to have the same value for method token. + downstream->set_request_method(htp->method); + + upstream->attach_downstream(std::move(downstream)); + return 0; } } // namespace @@ -91,7 +97,12 @@ int htp_uricb(http_parser *htp, const char *data, size_t len) { return -1; } downstream->add_request_headers_sum(len); - downstream->append_request_path(data, len); + if (downstream->get_request_method() == HTTP_CONNECT) { + downstream->append_request_http2_authority(data, len); + } else { + downstream->append_request_path(data, len); + } + return 0; } } // namespace @@ -242,8 +253,6 @@ int htp_hdrs_completecb(http_parser *htp) { } auto downstream = upstream->get_downstream(); - // We happen to have the same value for method token. - downstream->set_request_method(htp->method); downstream->set_request_major(htp->http_major); downstream->set_request_minor(htp->http_minor); @@ -296,6 +305,11 @@ int htp_hdrs_completecb(http_parser *htp) { downstream->set_request_path( http2::rewrite_clean_path(std::begin(uri), std::end(uri))); + auto host = downstream->get_request_header(http2::HD_HOST); + if (host) { + downstream->set_request_http2_authority(host->value); + } + if (upstream->get_client_handler()->get_ssl()) { downstream->set_request_http2_scheme("https"); } else {