summaryrefslogtreecommitdiffstats
path: root/src/shrpx_http3_upstream.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/shrpx_http3_upstream.cc')
-rw-r--r--src/shrpx_http3_upstream.cc342
1 files changed, 181 insertions, 161 deletions
diff --git a/src/shrpx_http3_upstream.cc b/src/shrpx_http3_upstream.cc
index d12d2da..0be846d 100644
--- a/src/shrpx_http3_upstream.cc
+++ b/src/shrpx_http3_upstream.cc
@@ -120,6 +120,9 @@ Http3Upstream::Http3Upstream(ClientHandler *handler)
!get_config()->http2_proxy},
tx_{
.data = std::unique_ptr<uint8_t[]>(new uint8_t[64_k]),
+#ifndef UDP_SEGMENT
+ .no_gso = true,
+#endif // UDP_SEGMENT
} {
auto conn = handler_->get_connection();
conn->conn_ref.get_conn = shrpx::get_conn;
@@ -273,7 +276,7 @@ int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
void *user_data, void *stream_user_data) {
auto upstream = static_cast<Http3Upstream *>(user_data);
- if (upstream->recv_stream_data(flags, stream_id, data, datalen) != 0) {
+ if (upstream->recv_stream_data(flags, stream_id, {data, datalen}) != 0) {
return NGTCP2_ERR_CALLBACK_FAILURE;
}
@@ -282,11 +285,12 @@ int recv_stream_data(ngtcp2_conn *conn, uint32_t flags, int64_t stream_id,
} // namespace
int Http3Upstream::recv_stream_data(uint32_t flags, int64_t stream_id,
- const uint8_t *data, size_t datalen) {
+ std::span<const uint8_t> data) {
assert(httpconn_);
- auto nconsumed = nghttp3_conn_read_stream(
- httpconn_, stream_id, data, datalen, flags & NGTCP2_STREAM_DATA_FLAG_FIN);
+ auto nconsumed =
+ nghttp3_conn_read_stream(httpconn_, stream_id, data.data(), data.size(),
+ flags & NGTCP2_STREAM_DATA_FLAG_FIN);
if (nconsumed < 0) {
ULOG(ERROR, this) << "nghttp3_conn_read_stream: "
<< nghttp3_strerror(nconsumed);
@@ -506,25 +510,22 @@ int path_validation(ngtcp2_conn *conn, uint32_t flags, const ngtcp2_path *path,
} // namespace
int Http3Upstream::send_new_token(const ngtcp2_addr *remote_addr) {
- std::array<uint8_t, NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN + 1> token;
- size_t tokenlen;
-
auto worker = handler_->get_worker();
auto conn_handler = worker->get_connection_handler();
auto &qkms = conn_handler->get_quic_keying_materials();
auto &qkm = qkms->keying_materials.front();
- if (generate_token(token.data(), tokenlen, remote_addr->addr,
- remote_addr->addrlen, qkm.secret.data(),
- qkm.secret.size()) != 0) {
+ std::array<uint8_t, NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN + 1> tokenbuf;
+
+ auto token = generate_token(tokenbuf, remote_addr->addr, remote_addr->addrlen,
+ qkm.secret, qkm.id);
+ if (!token) {
return -1;
}
- assert(tokenlen == NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN);
-
- token[tokenlen++] = qkm.id;
+ assert(token->size() == NGTCP2_CRYPTO_MAX_REGULAR_TOKENLEN + 1);
- auto rv = ngtcp2_conn_submit_new_token(conn_, token.data(), tokenlen);
+ auto rv = ngtcp2_conn_submit_new_token(conn_, token->data(), token->size());
if (rv != 0) {
ULOG(ERROR, this) << "ngtcp2_conn_submit_new_token: "
<< ngtcp2_strerror(rv);
@@ -553,8 +554,8 @@ int recv_tx_key(ngtcp2_conn *conn, ngtcp2_encryption_level level,
int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr,
const Address &local_addr,
const ngtcp2_pkt_hd &initial_hd,
- const ngtcp2_cid *odcid, const uint8_t *token,
- size_t tokenlen, ngtcp2_token_type token_type) {
+ const ngtcp2_cid *odcid, std::span<const uint8_t> token,
+ ngtcp2_token_type token_type) {
int rv;
auto worker = handler_->get_worker();
@@ -637,8 +638,8 @@ int Http3Upstream::init(const UpstreamAddr *faddr, const Address &remote_addr,
settings.max_window = http3conf.upstream.max_connection_window_size;
settings.max_stream_window = http3conf.upstream.max_window_size;
settings.rand_ctx.native_handle = &worker->get_randgen();
- settings.token = token;
- settings.tokenlen = tokenlen;
+ settings.token = token.data();
+ settings.tokenlen = token.size();
settings.token_type = token_type;
settings.initial_pkt_num = std::uniform_int_distribution<uint32_t>(
0, std::numeric_limits<int32_t>::max())(worker->get_randgen());
@@ -779,17 +780,14 @@ int Http3Upstream::on_write() {
int Http3Upstream::write_streams() {
std::array<nghttp3_vec, 16> vec;
auto max_udp_payload_size = ngtcp2_conn_get_max_tx_udp_payload_size(conn_);
-#ifdef UDP_SEGMENT
auto path_max_udp_payload_size =
ngtcp2_conn_get_path_max_tx_udp_payload_size(conn_);
-#endif // UDP_SEGMENT
- auto max_pktcnt =
- std::max(ngtcp2_conn_get_send_quantum(conn_) / max_udp_payload_size,
- static_cast<size_t>(1));
ngtcp2_pkt_info pi, prev_pi;
- uint8_t *bufpos = tx_.data.get();
+ auto txbuf =
+ std::span{tx_.data.get(), std::max(ngtcp2_conn_get_send_quantum(conn_),
+ path_max_udp_payload_size)};
+ auto buf = txbuf;
ngtcp2_path_storage ps, prev_ps;
- size_t pktcnt = 0;
int rv;
size_t gso_size = 0;
auto ts = quic_timestamp();
@@ -824,9 +822,12 @@ int Http3Upstream::write_streams() {
flags |= NGTCP2_WRITE_STREAM_FLAG_FIN;
}
+ auto buflen = buf.size() >= max_udp_payload_size
+ ? max_udp_payload_size
+ : path_max_udp_payload_size;
auto nwrite = ngtcp2_conn_writev_stream(
- conn_, &ps.path, &pi, bufpos, max_udp_payload_size, &ndatalen, flags,
- stream_id, reinterpret_cast<const ngtcp2_vec *>(v), vcnt, ts);
+ conn_, &ps.path, &pi, buf.data(), buflen, &ndatalen, flags, stream_id,
+ reinterpret_cast<const ngtcp2_vec *>(v), vcnt, ts);
if (nwrite < 0) {
switch (nwrite) {
case NGTCP2_ERR_STREAM_DATA_BLOCKED:
@@ -872,18 +873,17 @@ int Http3Upstream::write_streams() {
}
if (nwrite == 0) {
- if (bufpos - tx_.data.get()) {
+ auto data = std::span{std::begin(txbuf), std::begin(buf)};
+ if (!data.empty()) {
auto faddr = static_cast<UpstreamAddr *>(prev_ps.path.user_data);
- auto data = tx_.data.get();
- auto datalen = bufpos - data;
- rv = send_packet(faddr, prev_ps.path.remote.addr,
- prev_ps.path.remote.addrlen, prev_ps.path.local.addr,
- prev_ps.path.local.addrlen, prev_pi, data, datalen,
- gso_size);
+ auto [rest, rv] =
+ send_packet(faddr, prev_ps.path.remote.addr,
+ prev_ps.path.remote.addrlen, prev_ps.path.local.addr,
+ prev_ps.path.local.addrlen, prev_pi, data, gso_size);
if (rv == SHRPX_ERR_SEND_BLOCKED) {
on_send_blocked(faddr, prev_ps.path.remote, prev_ps.path.local,
- prev_pi, data, datalen, gso_size);
+ prev_pi, rest, gso_size);
signal_write_upstream_addr(faddr);
}
@@ -894,10 +894,11 @@ int Http3Upstream::write_streams() {
return 0;
}
- bufpos += nwrite;
+ auto last_pkt = std::begin(buf);
+
+ buf = buf.subspan(nwrite);
-#ifdef UDP_SEGMENT
- if (pktcnt == 0) {
+ if (last_pkt == std::begin(txbuf)) {
ngtcp2_path_copy(&prev_ps.path, &ps.path);
prev_pi = pi;
gso_size = nwrite;
@@ -907,35 +908,36 @@ int Http3Upstream::write_streams() {
(gso_size > path_max_udp_payload_size &&
static_cast<size_t>(nwrite) != gso_size)) {
auto faddr = static_cast<UpstreamAddr *>(prev_ps.path.user_data);
- auto data = tx_.data.get();
- auto datalen = bufpos - data - nwrite;
+ auto data = std::span{std::begin(txbuf), last_pkt};
- rv = send_packet(faddr, prev_ps.path.remote.addr,
- prev_ps.path.remote.addrlen, prev_ps.path.local.addr,
- prev_ps.path.local.addrlen, prev_pi, data, datalen,
- gso_size);
+ auto [rest, rv] =
+ send_packet(faddr, prev_ps.path.remote.addr,
+ prev_ps.path.remote.addrlen, prev_ps.path.local.addr,
+ prev_ps.path.local.addrlen, prev_pi, data, gso_size);
switch (rv) {
case SHRPX_ERR_SEND_BLOCKED:
on_send_blocked(faddr, prev_ps.path.remote, prev_ps.path.local, prev_pi,
- data, datalen, gso_size);
+ rest, gso_size);
+ data = std::span{last_pkt, std::begin(buf)};
on_send_blocked(static_cast<UpstreamAddr *>(ps.path.user_data),
- ps.path.remote, ps.path.local, pi, bufpos - nwrite,
- nwrite, 0);
+ ps.path.remote, ps.path.local, pi, data, data.size());
signal_write_upstream_addr(faddr);
break;
default: {
auto faddr = static_cast<UpstreamAddr *>(ps.path.user_data);
- auto data = bufpos - nwrite;
+ auto data = std::span{last_pkt, std::begin(buf)};
- rv = send_packet(faddr, ps.path.remote.addr, ps.path.remote.addrlen,
- ps.path.local.addr, ps.path.local.addrlen, pi, data,
- nwrite, 0);
+ auto [rest, rv] = send_packet(
+ faddr, ps.path.remote.addr, ps.path.remote.addrlen,
+ ps.path.local.addr, ps.path.local.addrlen, pi, data, data.size());
if (rv == SHRPX_ERR_SEND_BLOCKED) {
- on_send_blocked(faddr, ps.path.remote, ps.path.local, pi, data,
- nwrite, 0);
+ assert(rest.size() == data.size());
+
+ on_send_blocked(faddr, ps.path.remote, ps.path.local, pi, rest,
+ rest.size());
signal_write_upstream_addr(faddr);
}
@@ -947,16 +949,16 @@ int Http3Upstream::write_streams() {
return 0;
}
- if (++pktcnt == max_pktcnt || static_cast<size_t>(nwrite) < gso_size) {
+ if (buf.size() < path_max_udp_payload_size ||
+ static_cast<size_t>(nwrite) < gso_size) {
auto faddr = static_cast<UpstreamAddr *>(ps.path.user_data);
- auto data = tx_.data.get();
- auto datalen = bufpos - data;
+ auto data = std::span{std::begin(txbuf), std::begin(buf)};
- rv = send_packet(faddr, ps.path.remote.addr, ps.path.remote.addrlen,
- ps.path.local.addr, ps.path.local.addrlen, pi, data,
- datalen, gso_size);
+ auto [rest, rv] = send_packet(faddr, ps.path.remote.addr,
+ ps.path.remote.addrlen, ps.path.local.addr,
+ ps.path.local.addrlen, pi, data, gso_size);
if (rv == SHRPX_ERR_SEND_BLOCKED) {
- on_send_blocked(faddr, ps.path.remote, ps.path.local, pi, data, datalen,
+ on_send_blocked(faddr, ps.path.remote, ps.path.local, pi, rest,
gso_size);
signal_write_upstream_addr(faddr);
@@ -966,33 +968,6 @@ int Http3Upstream::write_streams() {
return 0;
}
-#else // !UDP_SEGMENT
- auto faddr = static_cast<UpstreamAddr *>(ps.path.user_data);
- auto data = tx_.data.get();
- auto datalen = bufpos - data;
-
- rv = send_packet(faddr, ps.path.remote.addr, ps.path.remote.addrlen,
- ps.path.local.addr, ps.path.local.addrlen, pi, data,
- datalen, 0);
- if (rv == SHRPX_ERR_SEND_BLOCKED) {
- on_send_blocked(faddr, ps.path.remote, ps.path.local, pi, data, datalen,
- 0);
-
- ngtcp2_conn_update_pkt_tx_time(conn_, ts);
-
- signal_write_upstream_addr(faddr);
-
- return 0;
- }
-
- if (++pktcnt == max_pktcnt) {
- ngtcp2_conn_update_pkt_tx_time(conn_, ts);
-
- return 0;
- }
-
- bufpos = tx_.data.get();
-#endif // !UDP_SEGMENT
}
return 0;
@@ -1329,7 +1304,7 @@ int Http3Upstream::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(http3::make_nv_ls_nocopy(":status", response_status));
+ nva.push_back(http3::make_field(":status"_sr, response_status));
http3::copy_headers_to_nva_nocopy(nva, resp.fs.headers(),
http2::HDOP_STRIP_ALL);
@@ -1361,16 +1336,16 @@ int Http3Upstream::on_downstream_header_complete(Downstream *downstream) {
response_status = http2::stringify_status(balloc, resp.http_status);
}
- nva.push_back(http3::make_nv_ls_nocopy(":status", response_status));
+ nva.push_back(http3::make_field(":status"_sr, response_status));
http3::copy_headers_to_nva_nocopy(nva, resp.fs.headers(), striphd_flags);
if (!config->http2_proxy && !httpconf.no_server_rewrite) {
- nva.push_back(http3::make_nv_ls_nocopy("server", httpconf.server_name));
+ nva.push_back(http3::make_field("server"_sr, httpconf.server_name));
} else {
auto server = resp.fs.header(http2::HD_SERVER);
if (server) {
- nva.push_back(http3::make_nv_ls_nocopy("server", (*server).value));
+ nva.push_back(http3::make_field("server"_sr, (*server).value));
}
}
@@ -1386,14 +1361,14 @@ int Http3Upstream::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(http3::make_nv_ls_nocopy("set-cookie", cookie_str));
+ nva.push_back(http3::make_field("set-cookie"_sr, cookie_str));
}
}
auto via = resp.fs.header(http2::HD_VIA);
if (httpconf.no_via) {
if (via) {
- nva.push_back(http3::make_nv_ls_nocopy("via", (*via).value));
+ nva.push_back(http3::make_field("via"_sr, (*via).value));
}
} else {
// we don't create more than 16 bytes in
@@ -1404,7 +1379,7 @@ int Http3Upstream::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, ", ");
@@ -1412,11 +1387,12 @@ int Http3Upstream::on_downstream_header_complete(Downstream *downstream) {
p = http::create_via_header_value(p, resp.http_major, resp.http_minor);
*p = '\0';
- nva.push_back(http3::make_nv_ls_nocopy("via", StringRef{iov.base, p}));
+ nva.push_back(
+ http3::make_field("via"_sr, StringRef{std::span{std::begin(iov), p}}));
}
for (auto &p : httpconf.add_response_headers) {
- nva.push_back(http3::make_nv_nocopy(p.name, p.value));
+ nva.push_back(http3::make_field(p.name, p.value));
}
if (LOG_ENABLED(INFO)) {
@@ -1582,7 +1558,7 @@ void Http3Upstream::on_handler_delete() {
send_packet(static_cast<UpstreamAddr *>(ps.path.user_data),
ps.path.remote.addr, ps.path.remote.addrlen, ps.path.local.addr,
- ps.path.local.addrlen, pi, conn_close_.data(), nwrite, 0);
+ ps.path.local.addrlen, pi, conn_close_, conn_close_.size());
}
auto d =
@@ -1700,9 +1676,15 @@ int Http3Upstream::send_reply(Downstream *downstream, const uint8_t *body,
nghttp3_data_reader data_read, *data_read_ptr = nullptr;
- if (bodylen) {
+ const auto &req = downstream->request();
+
+ if (req.method != HTTP_HEAD && bodylen) {
data_read.read_data = downstream_read_data_callback;
data_read_ptr = &data_read;
+
+ auto buf = downstream->get_response_buf();
+
+ buf->append(body, bodylen);
}
const auto &resp = downstream->response();
@@ -1718,7 +1700,7 @@ int Http3Upstream::send_reply(Downstream *downstream, const uint8_t *body,
auto response_status = http2::stringify_status(balloc, resp.http_status);
- nva.push_back(http3::make_nv_ls_nocopy(":status", response_status));
+ nva.push_back(http3::make_field(":status"_sr, response_status));
for (auto &kv : headers) {
if (kv.name.empty() || kv.name[0] == ':') {
@@ -1733,15 +1715,16 @@ int Http3Upstream::send_reply(Downstream *downstream, const uint8_t *body,
case http2::HD_UPGRADE:
continue;
}
- nva.push_back(http3::make_nv_nocopy(kv.name, kv.value, kv.no_index));
+ nva.push_back(
+ http3::make_field(kv.name, kv.value, http3::never_index(kv.no_index)));
}
if (!resp.fs.header(http2::HD_SERVER)) {
- nva.push_back(http3::make_nv_ls_nocopy("server", config->http.server_name));
+ nva.push_back(http3::make_field("server"_sr, config->http.server_name));
}
for (auto &p : httpconf.add_response_headers) {
- nva.push_back(http3::make_nv_nocopy(p.name, p.value));
+ nva.push_back(http3::make_field(p.name, p.value));
}
rv = nghttp3_conn_submit_response(httpconn_, downstream->get_stream_id(),
@@ -1752,10 +1735,6 @@ int Http3Upstream::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_read_ptr) {
@@ -1801,7 +1780,7 @@ void Http3Upstream::cancel_premature_downstream(
int Http3Upstream::on_read(const UpstreamAddr *faddr,
const Address &remote_addr,
const Address &local_addr, const ngtcp2_pkt_info &pi,
- const uint8_t *data, size_t datalen) {
+ std::span<const uint8_t> data) {
int rv;
auto path = ngtcp2_path{
@@ -1816,7 +1795,8 @@ int Http3Upstream::on_read(const UpstreamAddr *faddr,
const_cast<UpstreamAddr *>(faddr),
};
- rv = ngtcp2_conn_read_pkt(conn_, &path, &pi, data, datalen, quic_timestamp());
+ rv = ngtcp2_conn_read_pkt(conn_, &path, &pi, data.data(), data.size(),
+ quic_timestamp());
if (rv != 0) {
switch (rv) {
case NGTCP2_ERR_DRAINING:
@@ -1834,8 +1814,8 @@ int Http3Upstream::on_read(const UpstreamAddr *faddr,
ngtcp2_version_cid vc;
- rv =
- ngtcp2_pkt_decode_version_cid(&vc, data, datalen, SHRPX_QUIC_SCIDLEN);
+ rv = ngtcp2_pkt_decode_version_cid(&vc, data.data(), data.size(),
+ SHRPX_QUIC_SCIDLEN);
if (rv != 0) {
return -1;
}
@@ -1843,9 +1823,9 @@ int Http3Upstream::on_read(const UpstreamAddr *faddr,
// Overwrite error if any is set
ngtcp2_ccerr_set_liberr(&last_error_, rv, nullptr, 0);
- quic_conn_handler->send_retry(handler_->get_upstream_addr(), vc.version,
- vc.dcid, vc.dcidlen, vc.scid, vc.scidlen,
- remote_addr, local_addr, datalen * 3);
+ quic_conn_handler->send_retry(
+ handler_->get_upstream_addr(), vc.version, {vc.dcid, vc.dcidlen},
+ {vc.scid, vc.scidlen}, remote_addr, local_addr, data.size() * 3);
return -1;
}
@@ -1874,16 +1854,40 @@ int Http3Upstream::on_read(const UpstreamAddr *faddr,
return 0;
}
-int Http3Upstream::send_packet(const UpstreamAddr *faddr,
- const sockaddr *remote_sa, size_t remote_salen,
- const sockaddr *local_sa, size_t local_salen,
- const ngtcp2_pkt_info &pi, const uint8_t *data,
- size_t datalen, size_t gso_size) {
+std::pair<std::span<const uint8_t>, int>
+Http3Upstream::send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa,
+ size_t remote_salen, const sockaddr *local_sa,
+ size_t local_salen, const ngtcp2_pkt_info &pi,
+ std::span<const uint8_t> data, size_t gso_size) {
+ if (tx_.no_gso) {
+ for (; !data.empty();) {
+ auto len = std::min(gso_size, data.size());
+ auto rv =
+ quic_send_packet(faddr, remote_sa, remote_salen, local_sa,
+ local_salen, pi, {std::begin(data), len}, gso_size);
+ if (rv != 0) {
+ switch (rv) {
+ case -EAGAIN:
+#if EAGAIN != EWOULDBLOCK
+ case -EWOULDBLOCK:
+#endif // EAGAIN != EWOULDBLOCK
+ return {data, SHRPX_ERR_SEND_BLOCKED};
+ default:
+ return {data, -1};
+ }
+ }
+
+ data = data.subspan(len);
+ }
+
+ return {{}, 0};
+ }
+
auto rv = quic_send_packet(faddr, remote_sa, remote_salen, local_sa,
- local_salen, pi, data, datalen, gso_size);
+ local_salen, pi, data, gso_size);
switch (rv) {
case 0:
- return 0;
+ return {{}, 0};
// With GSO, sendmsg may fail with EINVAL if UDP payload is too
// large.
case -EINVAL:
@@ -1894,22 +1898,32 @@ int Http3Upstream::send_packet(const UpstreamAddr *faddr,
#if EAGAIN != EWOULDBLOCK
case -EWOULDBLOCK:
#endif // EAGAIN != EWOULDBLOCK
- return SHRPX_ERR_SEND_BLOCKED;
+ return {data, SHRPX_ERR_SEND_BLOCKED};
+ case -EIO:
+ if (tx_.no_gso) {
+ break;
+ }
+
+ tx_.no_gso = true;
+
+ return send_packet(faddr, remote_sa, remote_salen, local_sa, local_salen,
+ pi, data, gso_size);
default:
break;
}
- return -1;
+ return {{}, -1};
}
void Http3Upstream::on_send_blocked(const UpstreamAddr *faddr,
const ngtcp2_addr &remote_addr,
const ngtcp2_addr &local_addr,
const ngtcp2_pkt_info &pi,
- const uint8_t *data, size_t datalen,
+ std::span<const uint8_t> data,
size_t gso_size) {
assert(tx_.num_blocked || !tx_.send_blocked);
assert(tx_.num_blocked < 2);
+ assert(gso_size);
tx_.send_blocked = true;
@@ -1923,22 +1937,21 @@ void Http3Upstream::on_send_blocked(const UpstreamAddr *faddr,
p.faddr = faddr;
p.pi = pi;
p.data = data;
- p.datalen = datalen;
p.gso_size = gso_size;
}
int Http3Upstream::send_blocked_packet() {
- int rv;
-
assert(tx_.send_blocked);
for (; tx_.num_blocked_sent < tx_.num_blocked; ++tx_.num_blocked_sent) {
auto &p = tx_.blocked[tx_.num_blocked_sent];
- rv = send_packet(p.faddr, &p.remote_addr.su.sa, p.remote_addr.len,
- &p.local_addr.su.sa, p.local_addr.len, p.pi, p.data,
- p.datalen, p.gso_size);
+ auto [rest, rv] = send_packet(p.faddr, &p.remote_addr.su.sa,
+ p.remote_addr.len, &p.local_addr.su.sa,
+ p.local_addr.len, p.pi, p.data, p.gso_size);
if (rv == SHRPX_ERR_SEND_BLOCKED) {
+ p.data = rest;
+
signal_write_upstream_addr(p.faddr);
return 0;
@@ -1998,7 +2011,7 @@ int Http3Upstream::handle_error() {
send_packet(static_cast<UpstreamAddr *>(ps.path.user_data),
ps.path.remote.addr, ps.path.remote.addrlen, ps.path.local.addr,
- ps.path.local.addrlen, pi, conn_close_.data(), nwrite, 0);
+ ps.path.local.addrlen, pi, conn_close_, conn_close_.size());
return -1;
}
@@ -2185,22 +2198,20 @@ int Http3Upstream::http_recv_request_header(Downstream *downstream,
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 & NGHTTP3_NV_FLAG_NEVER_INDEX;
downstream->add_rcbuf(name);
downstream->add_rcbuf(value);
if (trailer) {
- 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;
}
@@ -2240,7 +2251,7 @@ int Http3Upstream::http_end_request_headers(Downstream *downstream, int fin) {
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;
}
@@ -2254,7 +2265,8 @@ int Http3Upstream::http_end_request_headers(Downstream *downstream, int fin) {
auto content_length = req.fs.header(http2::HD_CONTENT_LENGTH);
if (content_length) {
// libnghttp3 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 libnghttp3.
@@ -2298,8 +2310,7 @@ int Http3Upstream::http_end_request_headers(Downstream *downstream, int fin) {
}
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) {
@@ -2312,7 +2323,7 @@ int Http3Upstream::http_end_request_headers(Downstream *downstream, int fin) {
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 -1;
}
@@ -2452,7 +2463,7 @@ int http_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data,
auto upstream = static_cast<Http3Upstream *>(user_data);
auto downstream = static_cast<Downstream *>(stream_user_data);
- if (upstream->http_recv_data(downstream, data, datalen) != 0) {
+ if (upstream->http_recv_data(downstream, {data, datalen}) != 0) {
return NGHTTP3_ERR_CALLBACK_FAILURE;
}
@@ -2460,16 +2471,16 @@ int http_recv_data(nghttp3_conn *conn, int64_t stream_id, const uint8_t *data,
}
} // namespace
-int Http3Upstream::http_recv_data(Downstream *downstream, const uint8_t *data,
- size_t datalen) {
+int Http3Upstream::http_recv_data(Downstream *downstream,
+ std::span<const uint8_t> data) {
downstream->reset_upstream_rtimer();
- if (downstream->push_upload_data_chunk(data, datalen) != 0) {
+ if (downstream->push_upload_data_chunk(data.data(), data.size()) != 0) {
if (downstream->get_response_state() != DownstreamState::MSG_COMPLETE) {
shutdown_stream(downstream, NGHTTP3_H3_INTERNAL_ERROR);
}
- consume(downstream->get_stream_id(), datalen);
+ consume(downstream->get_stream_id(), data.size());
return 0;
}
@@ -2724,12 +2735,21 @@ int Http3Upstream::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);
- nghttp3_data_reader data_read;
- data_read.read_data = downstream_read_data_callback;
+ nghttp3_data_reader data_read, *data_read_ptr = nullptr;
+
+ const auto &req = downstream->request();
+
+ if (req.method != HTTP_HEAD) {
+ data_read.read_data = downstream_read_data_callback;
+ data_read_ptr = &data_read;
+
+ 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());
@@ -2738,15 +2758,15 @@ int Http3Upstream::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<nghttp3_nv, 5>{
- {http3::make_nv_ls_nocopy(":status", response_status),
- http3::make_nv_ll("content-type", "text/html; charset=UTF-8"),
- http3::make_nv_ls_nocopy("server", get_config()->http.server_name),
- http3::make_nv_ls_nocopy("content-length", content_length),
- http3::make_nv_ls_nocopy("date", date)}};
+ auto nva = std::to_array(
+ {http3::make_field(":status"_sr, response_status),
+ http3::make_field("content-type"_sr, "text/html; charset=UTF-8"_sr),
+ http3::make_field("server"_sr, get_config()->http.server_name),
+ http3::make_field("content-length"_sr, content_length),
+ http3::make_field("date"_sr, date)});
rv = nghttp3_conn_submit_response(httpconn_, downstream->get_stream_id(),
- nva.data(), nva.size(), &data_read);
+ nva.data(), nva.size(), data_read_ptr);
if (nghttp3_err_is_fatal(rv)) {
ULOG(FATAL, this) << "nghttp3_conn_submit_response() failed: "
<< nghttp3_strerror(rv);
@@ -2891,12 +2911,12 @@ int Http3Upstream::open_qlog_file(const StringRef &dir,
const ngtcp2_cid &scid) const {
std::array<char, sizeof("20141115T125824.741+0900")> buf;
- auto path = dir.str();
+ auto path = std::string{dir};
path += '/';
path +=
util::format_iso8601_basic(buf.data(), std::chrono::system_clock::now());
path += '-';
- path += util::format_hex(scid.data, scid.datalen);
+ path += util::format_hex(std::span{scid.data, scid.datalen});
path += ".sqlog";
int fd;