nghttpx: Store empty string to path for server-wide OPTIONS request
This change is required to show path attribute to mruby script. It is desirable to construct URI from parts. Just checking method and path is "*" is awkward.
This commit is contained in:
parent
02bb2c3e83
commit
200217d8ea
|
@ -739,41 +739,23 @@ namespace {
|
|||
// HttpDownstreamConnection::push_request_headers(), but vastly
|
||||
// simplified since we only care about absolute URI.
|
||||
std::string construct_absolute_request_uri(Downstream *downstream) {
|
||||
const char *authority = nullptr, *host = nullptr;
|
||||
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();
|
||||
}
|
||||
if (!authority && !host) {
|
||||
auto &authority = downstream->get_request_http2_authority();
|
||||
if (authority.empty()) {
|
||||
return downstream->get_request_path();
|
||||
}
|
||||
std::string uri;
|
||||
if (downstream->get_request_http2_scheme().empty()) {
|
||||
auto &scheme = downstream->get_request_http2_scheme();
|
||||
if (scheme.empty()) {
|
||||
// We may have to log the request which lacks scheme (e.g.,
|
||||
// http/1.1 with origin form).
|
||||
uri += "http://";
|
||||
} else {
|
||||
uri += downstream->get_request_http2_scheme();
|
||||
uri += scheme;
|
||||
uri += "://";
|
||||
}
|
||||
if (authority) {
|
||||
uri += authority;
|
||||
} else {
|
||||
uri += host;
|
||||
}
|
||||
uri += authority;
|
||||
uri += downstream->get_request_path();
|
||||
|
||||
// Server-wide OPTIONS takes following form in proxy request:
|
||||
//
|
||||
// OPTIONS http://example.org HTTP/1.1
|
||||
//
|
||||
// Notice that no slash after authority. See
|
||||
// http://tools.ietf.org/html/rfc7230#section-5.3.4
|
||||
if (downstream->get_request_path() != "*") {
|
||||
uri += downstream->get_request_path();
|
||||
}
|
||||
return uri;
|
||||
}
|
||||
} // namespace
|
||||
|
@ -787,12 +769,15 @@ void ClientHandler::write_accesslog(Downstream *downstream) {
|
|||
downstream, ipaddr_.c_str(),
|
||||
http2::to_method_string(downstream->get_request_method()),
|
||||
|
||||
(downstream->get_request_method() != HTTP_CONNECT &&
|
||||
(get_config()->http2_proxy || get_config()->client_proxy))
|
||||
? construct_absolute_request_uri(downstream).c_str()
|
||||
: downstream->get_request_path().empty()
|
||||
? downstream->get_request_http2_authority().c_str()
|
||||
: downstream->get_request_path().c_str(),
|
||||
downstream->get_request_method() == HTTP_CONNECT
|
||||
? downstream->get_request_http2_authority().c_str()
|
||||
: (get_config()->http2_proxy || get_config()->client_proxy)
|
||||
? construct_absolute_request_uri(downstream).c_str()
|
||||
: downstream->get_request_path().empty()
|
||||
? downstream->get_request_method() == HTTP_OPTIONS
|
||||
? "*"
|
||||
: "-"
|
||||
: downstream->get_request_path().c_str(),
|
||||
|
||||
alpn_.c_str(),
|
||||
nghttp2::ssl::get_tls_session_info(&tls_info, conn_.tls.ssl),
|
||||
|
|
|
@ -251,10 +251,10 @@ int Http2DownstreamConnection::push_request_headers() {
|
|||
|
||||
downstream_->set_request_pending(false);
|
||||
|
||||
auto method = downstream_->get_request_method();
|
||||
auto no_host_rewrite = get_config()->no_host_rewrite ||
|
||||
get_config()->http2_proxy ||
|
||||
get_config()->client_proxy ||
|
||||
downstream_->get_request_method() == HTTP_CONNECT;
|
||||
get_config()->client_proxy || method == HTTP_CONNECT;
|
||||
|
||||
// http2session_ has already in CONNECTED state, so we can get
|
||||
// addr_idx here.
|
||||
|
@ -299,17 +299,23 @@ int Http2DownstreamConnection::push_request_headers() {
|
|||
nva.reserve(nheader + 8 + cookies.size() +
|
||||
get_config()->add_request_headers.size());
|
||||
|
||||
nva.push_back(http2::make_nv_lc(
|
||||
":method", http2::to_method_string(downstream_->get_request_method())));
|
||||
nva.push_back(http2::make_nv_lc(":method", http2::to_method_string(method)));
|
||||
|
||||
auto &scheme = downstream_->get_request_http2_scheme();
|
||||
|
||||
nva.push_back(http2::make_nv_lc(":authority", authority));
|
||||
|
||||
if (downstream_->get_request_method() != HTTP_CONNECT) {
|
||||
if (method != HTTP_CONNECT) {
|
||||
assert(!scheme.empty());
|
||||
|
||||
nva.push_back(http2::make_nv_ls(":scheme", scheme));
|
||||
nva.push_back(http2::make_nv_ls(":path", downstream_->get_request_path()));
|
||||
|
||||
auto &path = downstream_->get_request_path();
|
||||
if (method == HTTP_OPTIONS && path.empty()) {
|
||||
nva.push_back(http2::make_nv_ll(":path", "*"));
|
||||
} else {
|
||||
nva.push_back(http2::make_nv_ls(":path", path));
|
||||
}
|
||||
}
|
||||
|
||||
http2::copy_headers_to_nva(nva, downstream_->get_request_headers());
|
||||
|
|
|
@ -299,7 +299,9 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
|
|||
downstream->set_request_http2_authority(http2::value_to_str(authority));
|
||||
|
||||
if (path) {
|
||||
if (get_config()->http2_proxy || get_config()->client_proxy) {
|
||||
if (method_token == HTTP_OPTIONS && path->value == "*") {
|
||||
// Server-wide OPTIONS request. Path is empty.
|
||||
} else if (get_config()->http2_proxy || get_config()->client_proxy) {
|
||||
downstream->set_request_path(http2::value_to_str(path));
|
||||
} else {
|
||||
auto &value = path->value;
|
||||
|
|
|
@ -213,7 +213,8 @@ int HttpDownstreamConnection::push_request_headers() {
|
|||
->downstream_addr_groups[group_]
|
||||
.addrs[addr_idx_]
|
||||
.hostport.get();
|
||||
auto connect_method = downstream_->get_request_method() == HTTP_CONNECT;
|
||||
auto method = downstream_->get_request_method();
|
||||
auto connect_method = method == HTTP_CONNECT;
|
||||
|
||||
// For HTTP/1.0 request, there is no authority in request. In that
|
||||
// case, we use backend server's host nonetheless.
|
||||
|
@ -232,10 +233,11 @@ int HttpDownstreamConnection::push_request_headers() {
|
|||
downstream_->assemble_request_cookie();
|
||||
|
||||
// Assume that method and request path do not contain \r\n.
|
||||
std::string hdrs = http2::to_method_string(downstream_->get_request_method());
|
||||
std::string hdrs = http2::to_method_string(method);
|
||||
hdrs += ' ';
|
||||
|
||||
auto &scheme = downstream_->get_request_http2_scheme();
|
||||
auto &path = downstream_->get_request_path();
|
||||
|
||||
if (connect_method) {
|
||||
hdrs += authority;
|
||||
|
@ -246,19 +248,12 @@ int HttpDownstreamConnection::push_request_headers() {
|
|||
hdrs += scheme;
|
||||
hdrs += "://";
|
||||
hdrs += authority;
|
||||
|
||||
// Server-wide OPTIONS takes following form in proxy request:
|
||||
//
|
||||
// OPTIONS http://example.org HTTP/1.1
|
||||
//
|
||||
// Notice that no slash after authority. See
|
||||
// http://tools.ietf.org/html/rfc7230#section-5.3.4
|
||||
if (downstream_->get_request_path() != "*") {
|
||||
hdrs += downstream_->get_request_path();
|
||||
}
|
||||
hdrs += path;
|
||||
} else if (method == HTTP_OPTIONS && path.empty()) {
|
||||
// Server-wide OPTIONS
|
||||
hdrs += "*";
|
||||
} else {
|
||||
// No proxy case.
|
||||
hdrs += downstream_->get_request_path();
|
||||
hdrs += path;
|
||||
}
|
||||
hdrs += " HTTP/1.1\r\nHost: ";
|
||||
hdrs += authority;
|
||||
|
|
|
@ -224,7 +224,7 @@ void rewrite_request_host_path_from_uri(Downstream *downstream, const char *uri,
|
|||
//
|
||||
// Notice that no slash after authority. See
|
||||
// http://tools.ietf.org/html/rfc7230#section-5.3.4
|
||||
downstream->set_request_path("*");
|
||||
downstream->set_request_path("");
|
||||
// we ignore query component here
|
||||
return;
|
||||
} else {
|
||||
|
@ -258,10 +258,13 @@ int htp_hdrs_completecb(http_parser *htp) {
|
|||
|
||||
downstream->set_request_connection_close(!http_should_keep_alive(htp));
|
||||
|
||||
auto method = downstream->get_request_method();
|
||||
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
std::stringstream ss;
|
||||
ss << http2::to_method_string(downstream->get_request_method()) << " "
|
||||
<< downstream->get_request_path() << " "
|
||||
ss << http2::to_method_string(method) << " "
|
||||
<< (method == HTTP_CONNECT ? downstream->get_request_http2_authority()
|
||||
: downstream->get_request_path()) << " "
|
||||
<< "HTTP/" << downstream->get_request_major() << "."
|
||||
<< downstream->get_request_minor() << "\n";
|
||||
const auto &headers = downstream->get_request_headers();
|
||||
|
@ -284,13 +287,12 @@ int htp_hdrs_completecb(http_parser *htp) {
|
|||
|
||||
downstream->inspect_http1_request();
|
||||
|
||||
if (downstream->get_request_method() != HTTP_CONNECT) {
|
||||
if (method != HTTP_CONNECT) {
|
||||
http_parser_url u{};
|
||||
// make a copy of request path, since we may set request path
|
||||
// while we are refering to original request path.
|
||||
auto uri = downstream->get_request_path();
|
||||
rv = http_parser_parse_url(uri.c_str(),
|
||||
downstream->get_request_path().size(), 0, &u);
|
||||
auto path = downstream->get_request_path();
|
||||
rv = http_parser_parse_url(path.c_str(), path.size(), 0, &u);
|
||||
if (rv != 0) {
|
||||
// Expect to respond with 400 bad request
|
||||
return -1;
|
||||
|
@ -302,8 +304,12 @@ int htp_hdrs_completecb(http_parser *htp) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
downstream->set_request_path(
|
||||
http2::rewrite_clean_path(std::begin(uri), std::end(uri)));
|
||||
if (method == HTTP_OPTIONS && path == "*") {
|
||||
downstream->set_request_path("");
|
||||
} else {
|
||||
downstream->set_request_path(
|
||||
http2::rewrite_clean_path(std::begin(path), std::end(path)));
|
||||
}
|
||||
|
||||
auto host = downstream->get_request_header(http2::HD_HOST);
|
||||
if (host) {
|
||||
|
@ -316,7 +322,7 @@ int htp_hdrs_completecb(http_parser *htp) {
|
|||
downstream->set_request_http2_scheme("http");
|
||||
}
|
||||
} else {
|
||||
rewrite_request_host_path_from_uri(downstream, uri.c_str(), u);
|
||||
rewrite_request_host_path_from_uri(downstream, path.c_str(), u);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -331,6 +337,8 @@ int htp_hdrs_completecb(http_parser *htp) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
// mruby hook may change method value
|
||||
|
||||
if (downstream->get_response_state() == Downstream::MSG_COMPLETE) {
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -227,6 +227,8 @@ void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
|
|||
downstream->set_request_http2_authority(host->value);
|
||||
if (get_config()->http2_proxy || get_config()->client_proxy) {
|
||||
downstream->set_request_path(path->value);
|
||||
} else if (method_token == HTTP_OPTIONS && path->value == "*") {
|
||||
// Server-wide OPTIONS request. Path is empty.
|
||||
} else {
|
||||
downstream->set_request_path(http2::rewrite_clean_path(
|
||||
std::begin(path->value), std::end(path->value)));
|
||||
|
|
Loading…
Reference in New Issue