◐ Shell
clean mode source ↗

quic: update http3 impl details · nodejs/node@edeed43

@@ -319,14 +319,20 @@ class Http3ApplicationImpl final : public Session::Application {

319319320320

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

}

325331326332

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

}

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;

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

}

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

}

693732694733

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

}

752836837+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 {

93410199351020

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

}

95710439581044

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