Skip to content

Commit 79b960a

Browse files
committed
quic: update http3 impl details
Signed-off-by: James M Snell <jasnell@gmail.com> Assisted-by: Opencode/Opus 4.6 PR-URL: #62387 Reviewed-By: Stephen Belanger <admin@stephenbelanger.com>
1 parent 57186e5 commit 79b960a

File tree

1 file changed

+111
-26
lines changed

1 file changed

+111
-26
lines changed

src/quic/http3.cc

Lines changed: 111 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -319,14 +319,20 @@ class Http3ApplicationImpl final : public Session::Application {
319319

320320
void CollectSessionTicketAppData(
321321
SessionTicket::AppData* app_data) const override {
322-
// TODO(@jasnell): There's currently nothing to store but there may be
323-
// later.
322+
// TODO(@jasnell): When HTTP/3 settings become dynamic or
323+
// configurable per-connection, store them here so they can be
324+
// validated on 0-RTT resumption. Candidates include:
325+
// max_field_section_size, qpack_max_dtable_capacity,
326+
// qpack_encoder_max_dtable_capacity, qpack_blocked_streams,
327+
// enable_connect_protocol, and enable_datagrams. On extraction,
328+
// compare stored values against current settings and return
329+
// TICKET_IGNORE_RENEW if incompatible.
324330
}
325331

326332
SessionTicket::AppData::Status ExtractSessionTicketAppData(
327333
const SessionTicket::AppData& app_data,
328334
SessionTicket::AppData::Source::Flag flag) override {
329-
// There's currently nothing stored here but we might do so later.
335+
// See CollectSessionTicketAppData above.
330336
return flag == SessionTicket::AppData::Source::Flag::STATUS_RENEW
331337
? SessionTicket::AppData::Status::TICKET_USE_RENEW
332338
: SessionTicket::AppData::Status::TICKET_USE;
@@ -448,10 +454,42 @@ class Http3ApplicationImpl final : public Session::Application {
448454
return false;
449455
}
450456

457+
void SetStreamPriority(const Stream& stream,
458+
StreamPriority priority,
459+
StreamPriorityFlags flags) override {
460+
nghttp3_pri pri;
461+
pri.inc = (flags == StreamPriorityFlags::NON_INCREMENTAL) ? 0 : 1;
462+
switch (priority) {
463+
case StreamPriority::HIGH:
464+
pri.urgency = NGHTTP3_URGENCY_HIGH;
465+
break;
466+
case StreamPriority::LOW:
467+
pri.urgency = NGHTTP3_URGENCY_LOW;
468+
break;
469+
default:
470+
pri.urgency = NGHTTP3_DEFAULT_URGENCY;
471+
break;
472+
}
473+
if (session().is_server()) {
474+
nghttp3_conn_set_server_stream_priority(
475+
*this, stream.id(), &pri);
476+
}
477+
// Client-side priority is set at request submission time via
478+
// nghttp3_conn_submit_request and is not typically changed
479+
// after the fact. The client API takes a serialized RFC 9218
480+
// field value rather than an nghttp3_pri struct.
481+
}
482+
451483
StreamPriority GetStreamPriority(const Stream& stream) override {
452484
nghttp3_pri pri;
453485
if (nghttp3_conn_get_stream_priority(*this, &pri, stream.id()) == 0) {
454-
// TODO(@jasnell): Support the incremental flag
486+
// TODO(@jasnell): The nghttp3_pri.inc (incremental) flag is
487+
// not yet exposed. When priority-based stream scheduling is
488+
// implemented, GetStreamPriority should return both urgency
489+
// and the incremental flag (making get/set symmetrical).
490+
// The inc flag determines whether the server should interleave
491+
// data from this stream with others of the same urgency
492+
// (inc=1) or complete it first (inc=0).
455493
switch (pri.urgency) {
456494
case NGHTTP3_URGENCY_HIGH:
457495
return StreamPriority::HIGH;
@@ -673,22 +711,23 @@ class Http3ApplicationImpl final : public Session::Application {
673711
stream->ReceiveStreamReset(0, QuicError::ForApplication(app_error_code));
674712
}
675713

676-
void OnShutdown() {
677-
// This callback is invoked when we receive a request to gracefully shutdown
678-
// the http3 connection. For client, the id is the stream id of a client
679-
// initiated stream. For server, the id is the stream id of a server
680-
// initiated stream. Once received, the other side is guaranteed not to
681-
// process any more data.
682-
683-
// On the client side, if id is equal to NGHTTP3_SHUTDOWN_NOTICE_STREAM_ID,
684-
// or on the server if the id is equal to NGHTTP3_SHUTDOWN_NOTICE_PUSH_ID,
685-
// then this is a request to begin a graceful shutdown.
686-
687-
// This can be called multiple times but the id can only stay the same or
688-
// *decrease*.
689-
690-
// TODO(@jasnell): Need to determine exactly how to handle.
691-
Debug(&session(), "HTTP/3 application received shutdown notice");
714+
void OnShutdown(int64_t id) {
715+
// The peer has sent a GOAWAY frame initiating a graceful shutdown.
716+
// For a client, id is the stream ID beyond which the server will
717+
// not process requests. For a server, id is a push ID (server
718+
// push is not implemented). Streams/pushes with IDs >= id will
719+
// not be processed by the peer.
720+
//
721+
// When id equals NGHTTP3_SHUTDOWN_NOTICE_STREAM_ID (client) or
722+
// NGHTTP3_SHUTDOWN_NOTICE_PUSH_ID (server), this is a notice of
723+
// intent to shut down rather than an immediate refusal.
724+
//
725+
// This can be called multiple times with a decreasing id as the
726+
// peer progressively reduces the set of streams it will process.
727+
Debug(&session(),
728+
"HTTP/3 received GOAWAY (id=%" PRIi64 ")",
729+
id);
730+
session().Close(Session::CloseMethod::GRACEFUL);
692731
}
693732

694733
void OnReceiveSettings(const nghttp3_settings* settings) {
@@ -747,9 +786,55 @@ class Http3ApplicationImpl final : public Session::Application {
747786
uint32_t* pflags,
748787
void* conn_user_data,
749788
void* stream_user_data) {
750-
return NGTCP2_SUCCESS;
789+
auto ptr = From(conn, conn_user_data);
790+
CHECK_NOT_NULL(ptr);
791+
auto& app = *ptr;
792+
NgHttp3CallbackScope scope(app.env());
793+
794+
auto stream = app.session().FindStream(stream_id);
795+
if (!stream) return NGHTTP3_ERR_CALLBACK_FAILURE;
796+
797+
if (stream->is_eos()) {
798+
*pflags |= NGHTTP3_DATA_FLAG_EOF;
799+
return 0;
800+
}
801+
802+
size_t max_count = std::min(veccnt,
803+
static_cast<size_t>(kMaxVectorCount));
804+
nghttp3_ssize result = 0;
805+
806+
auto next = [&](int status,
807+
const ngtcp2_vec* data,
808+
size_t count,
809+
bob::Done done) {
810+
switch (status) {
811+
case bob::Status::STATUS_BLOCK:
812+
case bob::Status::STATUS_WAIT:
813+
result = NGHTTP3_ERR_WOULDBLOCK;
814+
return;
815+
case bob::Status::STATUS_EOS:
816+
*pflags |= NGHTTP3_DATA_FLAG_EOF;
817+
break;
818+
}
819+
count = std::min(count, max_count);
820+
for (size_t n = 0; n < count; n++) {
821+
vec[n].base = data[n].base;
822+
vec[n].len = data[n].len;
823+
}
824+
result = static_cast<nghttp3_ssize>(count);
825+
};
826+
827+
ngtcp2_vec data[kMaxVectorCount];
828+
stream->Pull(std::move(next),
829+
bob::Options::OPTIONS_SYNC,
830+
data,
831+
max_count,
832+
max_count);
833+
834+
return result;
751835
}
752836

837+
753838
static int on_acked_stream_data(nghttp3_conn* conn,
754839
int64_t stream_id,
755840
uint64_t datalen,
@@ -934,7 +1019,7 @@ class Http3ApplicationImpl final : public Session::Application {
9341019

9351020
static int on_shutdown(nghttp3_conn* conn, int64_t id, void* conn_user_data) {
9361021
NGHTTP3_CALLBACK_SCOPE(app);
937-
app.OnShutdown();
1022+
app.OnShutdown(id);
9381023
return NGTCP2_SUCCESS;
9391024
}
9401025

@@ -950,14 +1035,14 @@ class Http3ApplicationImpl final : public Session::Application {
9501035
const uint8_t* origin,
9511036
size_t originlen,
9521037
void* conn_user_data) {
953-
// TODO(@jasnell): Handle the origin callback. This is called
954-
// when a single origin in an ORIGIN frame is received.
1038+
// ORIGIN frames (RFC 8336) are used for connection coalescing
1039+
// across multiple origins. Not yet implemented u2014 requires
1040+
// connection pooling and multi-origin reuse support.
9551041
return NGTCP2_SUCCESS;
9561042
}
9571043

9581044
static int on_end_origin(nghttp3_conn* conn, void* conn_user_data) {
959-
// TODO(@jasnell): Handle the end of origin callback. This is called
960-
// when the end of an ORIGIN frame is received.
1045+
// See on_receive_origin above.
9611046
return NGTCP2_SUCCESS;
9621047
}
9631048

0 commit comments

Comments
 (0)