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:
Tatsuhiro Tsujikawa 2015-09-04 00:14:09 +09:00
parent 02bb2c3e83
commit 200217d8ea
6 changed files with 60 additions and 62 deletions

View File

@ -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),

View File

@ -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());

View File

@ -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;

View File

@ -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;

View File

@ -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;
}

View File

@ -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)));