summaryrefslogtreecommitdiffstats
path: root/src/shrpx_http2_upstream.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/shrpx_http2_upstream.cc')
-rw-r--r--src/shrpx_http2_upstream.cc134
1 files changed, 72 insertions, 62 deletions
diff --git a/src/shrpx_http2_upstream.cc b/src/shrpx_http2_upstream.cc
index 7816f5f..4c59ddc 100644
--- a/src/shrpx_http2_upstream.cc
+++ b/src/shrpx_http2_upstream.cc
@@ -118,7 +118,7 @@ int Http2Upstream::upgrade_upstream(HttpsUpstream *http) {
std::end(http2_settings));
rv = nghttp2_session_upgrade2(
- session_, settings_payload.byte(), settings_payload.size(),
+ session_, settings_payload.data(), settings_payload.size(),
http->get_downstream()->request().method == HTTP_HEAD, nullptr);
if (rv != 0) {
if (LOG_ENABLED(INFO)) {
@@ -209,7 +209,9 @@ int on_header_callback2(nghttp2_session *session, const nghttp2_frame *frame,
return 0;
}
- auto token = http2::lookup_token(namebuf.base, namebuf.len);
+ auto nameref = StringRef{namebuf.base, namebuf.len};
+ auto valueref = StringRef{valuebuf.base, valuebuf.len};
+ auto token = http2::lookup_token(nameref);
auto no_index = flags & NGHTTP2_NV_FLAG_NO_INDEX;
downstream->add_rcbuf(name);
@@ -217,15 +219,11 @@ int on_header_callback2(nghttp2_session *session, const nghttp2_frame *frame,
if (frame->headers.cat == NGHTTP2_HCAT_HEADERS) {
// just store header fields for trailer part
- req.fs.add_trailer_token(StringRef{namebuf.base, namebuf.len},
- StringRef{valuebuf.base, valuebuf.len}, no_index,
- token);
+ req.fs.add_trailer_token(nameref, valueref, no_index, token);
return 0;
}
- req.fs.add_header_token(StringRef{namebuf.base, namebuf.len},
- StringRef{valuebuf.base, valuebuf.len}, no_index,
- token);
+ req.fs.add_header_token(nameref, valueref, no_index, token);
return 0;
}
} // namespace
@@ -322,7 +320,7 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
if (LOG_ENABLED(INFO)) {
std::stringstream ss;
for (auto &nv : nva) {
- if (nv.name == "authorization") {
+ if (nv.name == "authorization"_sr) {
ss << TTY_HTTP_HD << nv.name << TTY_RST << ": <redacted>\n";
continue;
}
@@ -343,7 +341,8 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
auto content_length = req.fs.header(http2::HD_CONTENT_LENGTH);
if (content_length) {
// libnghttp2 guarantees this can be parsed
- req.fs.content_length = util::parse_uint(content_length->value);
+ req.fs.content_length =
+ util::parse_uint(content_length->value).value_or(-1);
}
// presence of mandatory header fields are guaranteed by libnghttp2.
@@ -385,8 +384,7 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
}
if (path) {
- if (method_token == HTTP_OPTIONS &&
- path->value == StringRef::from_lit("*")) {
+ if (method_token == HTTP_OPTIONS && path->value == "*"_sr) {
// Server-wide OPTIONS request. Path is empty.
} else if (config->http2_proxy &&
faddr->alt_mode == UpstreamAltMode::NONE) {
@@ -399,7 +397,7 @@ int Http2Upstream::on_request_headers(Downstream *downstream,
auto connect_proto = req.fs.header(http2::HD__PROTOCOL);
if (connect_proto) {
- if (connect_proto->value != "websocket") {
+ if (connect_proto->value != "websocket"_sr) {
if (error_reply(downstream, 400) != 0) {
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
}
@@ -744,7 +742,7 @@ int on_frame_send_callback(nghttp2_session *session, const nghttp2_frame *frame,
auto value =
make_string_ref(promised_balloc, StringRef{nv.value, nv.valuelen});
- auto token = http2::lookup_token(nv.name, nv.namelen);
+ auto token = http2::lookup_token(name);
switch (token) {
case http2::HD__METHOD:
req.method = http2::lookup_method_token(value);
@@ -1510,10 +1508,16 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
nghttp2_data_provider2 data_prd, *data_prd_ptr = nullptr;
- if (bodylen) {
+ const auto &req = downstream->request();
+
+ if (req.method != HTTP_HEAD && bodylen) {
data_prd.source.ptr = downstream;
data_prd.read_callback = downstream_data_read_callback;
data_prd_ptr = &data_prd;
+
+ auto buf = downstream->get_response_buf();
+
+ buf->append(body, bodylen);
}
const auto &resp = downstream->response();
@@ -1529,7 +1533,7 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
auto response_status = http2::stringify_status(balloc, resp.http_status);
- nva.push_back(http2::make_nv_ls_nocopy(":status", response_status));
+ nva.push_back(http2::make_field(":status"_sr, response_status));
for (auto &kv : headers) {
if (kv.name.empty() || kv.name[0] == ':') {
@@ -1544,15 +1548,16 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
case http2::HD_UPGRADE:
continue;
}
- nva.push_back(http2::make_nv_nocopy(kv.name, kv.value, kv.no_index));
+ nva.push_back(
+ http2::make_field(kv.name, kv.value, http2::no_index(kv.no_index)));
}
if (!resp.fs.header(http2::HD_SERVER)) {
- nva.push_back(http2::make_nv_ls_nocopy("server", config->http.server_name));
+ nva.push_back(http2::make_field("server"_sr, config->http.server_name));
}
for (auto &p : httpconf.add_response_headers) {
- nva.push_back(http2::make_nv_nocopy(p.name, p.value));
+ nva.push_back(http2::make_field(p.name, p.value));
}
rv = nghttp2_submit_response2(session_, downstream->get_stream_id(),
@@ -1563,10 +1568,6 @@ int Http2Upstream::send_reply(Downstream *downstream, const uint8_t *body,
return -1;
}
- auto buf = downstream->get_response_buf();
-
- buf->append(body, bodylen);
-
downstream->set_response_state(DownstreamState::MSG_COMPLETE);
if (data_prd_ptr) {
@@ -1585,13 +1586,22 @@ int Http2Upstream::error_reply(Downstream *downstream,
auto html = http::create_error_html(balloc, status_code);
resp.http_status = status_code;
- auto body = downstream->get_response_buf();
- body->append(html);
- downstream->set_response_state(DownstreamState::MSG_COMPLETE);
- nghttp2_data_provider2 data_prd;
- data_prd.source.ptr = downstream;
- data_prd.read_callback = downstream_data_read_callback;
+ nghttp2_data_provider2 data_prd, *data_prd_ptr = nullptr;
+
+ const auto &req = downstream->request();
+
+ if (req.method != HTTP_HEAD) {
+ data_prd.source.ptr = downstream;
+ data_prd.read_callback = downstream_data_read_callback;
+ data_prd_ptr = &data_prd;
+
+ auto body = downstream->get_response_buf();
+
+ body->append(html);
+ }
+
+ downstream->set_response_state(DownstreamState::MSG_COMPLETE);
auto lgconf = log_config();
lgconf->update_tstamp(std::chrono::system_clock::now());
@@ -1600,15 +1610,15 @@ int Http2Upstream::error_reply(Downstream *downstream,
auto content_length = util::make_string_ref_uint(balloc, html.size());
auto date = make_string_ref(balloc, lgconf->tstamp->time_http);
- auto nva = std::array<nghttp2_nv, 5>{
- {http2::make_nv_ls_nocopy(":status", response_status),
- http2::make_nv_ll("content-type", "text/html; charset=UTF-8"),
- http2::make_nv_ls_nocopy("server", get_config()->http.server_name),
- http2::make_nv_ls_nocopy("content-length", content_length),
- http2::make_nv_ls_nocopy("date", date)}};
+ auto nva = std::to_array(
+ {http2::make_field(":status"_sr, response_status),
+ http2::make_field("content-type"_sr, "text/html; charset=UTF-8"_sr),
+ http2::make_field("server"_sr, get_config()->http.server_name),
+ http2::make_field("content-length"_sr, content_length),
+ http2::make_field("date"_sr, date)});
rv = nghttp2_submit_response2(session_, downstream->get_stream_id(),
- nva.data(), nva.size(), &data_prd);
+ nva.data(), nva.size(), data_prd_ptr);
if (rv < NGHTTP2_ERR_FATAL) {
ULOG(FATAL, this) << "nghttp2_submit_response2() failed: "
<< nghttp2_strerror(rv);
@@ -1747,7 +1757,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
if (downstream->get_non_final_response()) {
auto response_status = http2::stringify_status(balloc, resp.http_status);
- nva.push_back(http2::make_nv_ls_nocopy(":status", response_status));
+ nva.push_back(http2::make_field(":status"_sr, response_status));
http2::copy_headers_to_nva_nocopy(nva, resp.fs.headers(),
http2::HDOP_STRIP_ALL);
@@ -1780,16 +1790,16 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
response_status = http2::stringify_status(balloc, resp.http_status);
}
- nva.push_back(http2::make_nv_ls_nocopy(":status", response_status));
+ nva.push_back(http2::make_field(":status"_sr, response_status));
http2::copy_headers_to_nva_nocopy(nva, resp.fs.headers(), striphd_flags);
if (!config->http2_proxy && !httpconf.no_server_rewrite) {
- nva.push_back(http2::make_nv_ls_nocopy("server", httpconf.server_name));
+ nva.push_back(http2::make_field("server"_sr, httpconf.server_name));
} else {
auto server = resp.fs.header(http2::HD_SERVER);
if (server) {
- nva.push_back(http2::make_nv_ls_nocopy("server", (*server).value));
+ nva.push_back(http2::make_field("server"_sr, (*server).value));
}
}
@@ -1805,22 +1815,22 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
http::require_cookie_secure_attribute(cookieconf.secure, req.scheme);
auto cookie_str = http::create_affinity_cookie(
balloc, cookieconf.name, affinity_cookie, cookieconf.path, secure);
- nva.push_back(http2::make_nv_ls_nocopy("set-cookie", cookie_str));
+ nva.push_back(http2::make_field("set-cookie"_sr, cookie_str));
}
}
if (!resp.fs.header(http2::HD_ALT_SVC)) {
// We won't change or alter alt-svc from backend for now
if (!httpconf.http2_altsvc_header_value.empty()) {
- nva.push_back(http2::make_nv_ls_nocopy(
- "alt-svc", httpconf.http2_altsvc_header_value));
+ nva.push_back(
+ http2::make_field("alt-svc"_sr, httpconf.http2_altsvc_header_value));
}
}
auto via = resp.fs.header(http2::HD_VIA);
if (httpconf.no_via) {
if (via) {
- nva.push_back(http2::make_nv_ls_nocopy("via", (*via).value));
+ nva.push_back(http2::make_field("via"_sr, (*via).value));
}
} else {
// we don't create more than 16 bytes in
@@ -1831,7 +1841,7 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
}
auto iov = make_byte_ref(balloc, len + 1);
- auto p = iov.base;
+ auto p = std::begin(iov);
if (via) {
p = std::copy(std::begin(via->value), std::end(via->value), p);
p = util::copy_lit(p, ", ");
@@ -1839,17 +1849,18 @@ int Http2Upstream::on_downstream_header_complete(Downstream *downstream) {
p = http::create_via_header_value(p, resp.http_major, resp.http_minor);
*p = '\0';
- nva.push_back(http2::make_nv_ls_nocopy("via", StringRef{iov.base, p}));
+ nva.push_back(
+ http2::make_field("via"_sr, StringRef{std::span{std::begin(iov), p}}));
}
for (auto &p : httpconf.add_response_headers) {
- nva.push_back(http2::make_nv_nocopy(p.name, p.value));
+ nva.push_back(http2::make_field(p.name, p.value));
}
if (downstream->get_stream_id() % 2 == 0) {
// This header field is basically for human on client side to
// figure out that the resource is pushed.
- nva.push_back(http2::make_nv_ll("x-http2-push", "1"));
+ nva.push_back(http2::make_field("x-http2-push"_sr, "1"_sr));
}
if (LOG_ENABLED(INFO)) {
@@ -1993,7 +2004,7 @@ int Http2Upstream::on_downstream_abort_request_with_https_redirect(
int Http2Upstream::redirect_to_https(Downstream *downstream) {
auto &req = downstream->request();
- if (req.regular_connect_method() || req.scheme != "http") {
+ if (req.regular_connect_method() || req.scheme != "http"_sr) {
return error_reply(downstream, 400);
}
@@ -2007,19 +2018,16 @@ int Http2Upstream::redirect_to_https(Downstream *downstream) {
auto &httpconf = config->http;
StringRef loc;
- if (httpconf.redirect_https_port == StringRef::from_lit("443")) {
- loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
- req.path);
+ if (httpconf.redirect_https_port == "443"_sr) {
+ loc = concat_string_ref(balloc, "https://"_sr, authority, req.path);
} else {
- loc = concat_string_ref(balloc, StringRef::from_lit("https://"), authority,
- StringRef::from_lit(":"),
+ loc = concat_string_ref(balloc, "https://"_sr, authority, ":"_sr,
httpconf.redirect_https_port, req.path);
}
auto &resp = downstream->response();
resp.http_status = 308;
- resp.fs.add_header_token(StringRef::from_lit("location"), loc, false,
- http2::HD_LOCATION);
+ resp.fs.add_header_token("location"_sr, loc, false, http2::HD_LOCATION);
return send_reply(downstream, nullptr, 0);
}
@@ -2216,10 +2224,10 @@ int Http2Upstream::submit_push_promise(const StringRef &scheme,
nva.reserve(4 + req.fs.headers().size());
// just use "GET" for now
- nva.push_back(http2::make_nv_ll(":method", "GET"));
- nva.push_back(http2::make_nv_ls_nocopy(":scheme", scheme));
- nva.push_back(http2::make_nv_ls_nocopy(":path", path));
- nva.push_back(http2::make_nv_ls_nocopy(":authority", authority));
+ nva.push_back(http2::make_field(":method"_sr, "GET"_sr));
+ nva.push_back(http2::make_field(":scheme"_sr, scheme));
+ nva.push_back(http2::make_field(":path"_sr, path));
+ nva.push_back(http2::make_field(":authority"_sr, authority));
for (auto &kv : req.fs.headers()) {
switch (kv.token) {
@@ -2234,7 +2242,8 @@ int Http2Upstream::submit_push_promise(const StringRef &scheme,
case http2::HD_CACHE_CONTROL:
case http2::HD_HOST:
case http2::HD_USER_AGENT:
- nva.push_back(http2::make_nv_nocopy(kv.name, kv.value, kv.no_index));
+ nva.push_back(
+ http2::make_field(kv.name, kv.value, http2::no_index(kv.no_index)));
break;
}
}
@@ -2378,7 +2387,8 @@ int Http2Upstream::on_downstream_push_promise_complete(
nva.reserve(headers.size());
for (auto &kv : headers) {
- nva.push_back(http2::make_nv(kv.name, kv.value, kv.no_index));
+ nva.push_back(
+ http2::make_field_nv(kv.name, kv.value, http2::no_index(kv.no_index)));
}
auto promised_stream_id = nghttp2_submit_push_promise(