quic: update http3 impl details · nodejs/node@edeed43
@@ -319,14 +319,20 @@ class Http3ApplicationImpl final : public Session::Application {
319319320320void 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 }
325331326332 SessionTicket::AppData::Status ExtractSessionTicketAppData(
327333const 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.
330336return 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 {
448454return false;
449455 }
450456457+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;
453485if (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).
455493switch (pri.urgency) {
456494case NGHTTP3_URGENCY_HIGH:
457495return StreamPriority::HIGH;
@@ -673,22 +711,23 @@ class Http3ApplicationImpl final : public Session::Application {
673711 stream->ReceiveStreamReset(0, QuicError::ForApplication(app_error_code));
674712 }
675713676-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 }
693732694733void OnReceiveSettings(const nghttp3_settings* settings) {
@@ -747,9 +786,55 @@ class Http3ApplicationImpl final : public Session::Application {
747786uint32_t* pflags,
748787void* conn_user_data,
749788void* 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 }
752836837+753838static int on_acked_stream_data(nghttp3_conn* conn,
754839int64_t stream_id,
755840uint64_t datalen,
@@ -934,7 +1019,7 @@ class Http3ApplicationImpl final : public Session::Application {
93410199351020static int on_shutdown(nghttp3_conn* conn, int64_t id, void* conn_user_data) {
9361021NGHTTP3_CALLBACK_SCOPE(app);
937- app.OnShutdown();
1022+ app.OnShutdown(id);
9381023return NGTCP2_SUCCESS;
9391024 }
9401025@@ -950,14 +1035,14 @@ class Http3ApplicationImpl final : public Session::Application {
9501035const uint8_t* origin,
9511036size_t originlen,
9521037void* 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.
9551041return NGTCP2_SUCCESS;
9561042 }
95710439581044static 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.
9611046return NGTCP2_SUCCESS;
9621047 }
9631048