@@ -151,7 +151,7 @@ Http3Settings::operator const nghttp3_settings() const {
151151 .enable_connect_protocol = enable_connect_protocol,
152152 .h3_datagram = enable_datagrams,
153153 // origin_list is nullptr here because it is set directly on the
154- // nghttp3_settings in Http3ApplicationImpl ::InitializeConnection()
154+ // nghttp3_settings in Http3Application ::InitializeConnection()
155155 // from the SNI configuration.
156156 .origin_list = nullptr ,
157157 .glitch_ratelim_burst = 1000 ,
@@ -323,9 +323,9 @@ using Http3Header = NgHeader<Http3HeaderTraits>;
323323
324324// The Session::Application implementation for HTTP/3, which owns the nghttp3
325325// connection and all HTTP/3 protocol logic and state.
326- class Http3ApplicationImpl final : public Session::Application {
326+ class Http3Application final : public Session::Application {
327327 public:
328- Http3ApplicationImpl (Session* session, const Http3Settings& settings)
328+ Http3Application (Session* session, const Http3Settings& settings)
329329 : Application(session),
330330 allocator_ (BindingData::Get(session->env ()).nghttp3_allocator()),
331331 options_(settings),
@@ -340,6 +340,59 @@ class Http3ApplicationImpl final : public Session::Application {
340340 session->set_priority_supported ();
341341 }
342342
343+ // ==========================================================================
344+ // HTTP/3 events reported up to the session/JS layer. Each routes through
345+ // Session::DeferOrRun, so an event raised before the session is surfaced to
346+ // JS (in 0-RTT first-flight frames) is held and replayed after attach.
347+
348+ void EmitGoaway (stream_id last_stream_id) {
349+ session ().DeferOrRun ([this , last_stream_id]() {
350+ Session& s = session ();
351+ if (s.is_destroyed () || !s.env ()->can_call_into_js ()) return ;
352+ CallbackScope<Session> cb_scope (&s);
353+ Local<Value> argv[] = {BigInt::New (s.env ()->isolate (), last_stream_id)};
354+ s.MakeCallback (BindingData::Get (s.env ()).session_goaway_callback (),
355+ arraysize (argv),
356+ argv);
357+ });
358+ }
359+
360+ void EmitOrigins (std::vector<std::string>&& origins) {
361+ auto held = std::make_shared<std::vector<std::string>>(std::move (origins));
362+ session ().DeferOrRun ([this , held]() {
363+ Session& s = session ();
364+ if (s.is_destroyed () || !s.env ()->can_call_into_js ()) return ;
365+ if (!s.has_origin_listener ()) return ;
366+ CallbackScope<Session> cb_scope (&s);
367+ auto * isolate = s.env ()->isolate ();
368+ LocalVector<Value> elements (isolate, held->size ());
369+ for (size_t i = 0 ; i < held->size (); i++) {
370+ Local<Value> str;
371+ if (!ToV8Value (s.env ()->context (), (*held)[i]).ToLocal (&str))
372+ [[unlikely]] {
373+ return ;
374+ }
375+ elements[i] = str;
376+ }
377+ Local<Value> argv[] = {
378+ Array::New (isolate, elements.data (), elements.size ())};
379+ s.MakeCallback (BindingData::Get (s.env ()).session_origin_callback (),
380+ arraysize (argv),
381+ argv);
382+ });
383+ }
384+
385+ void EmitApplicationSettings () {
386+ session ().DeferOrRun ([this ]() {
387+ Session& s = session ();
388+ if (s.is_destroyed () || !s.env ()->can_call_into_js ()) return ;
389+ CallbackScope<Session> cb_scope (&s);
390+ s.MakeCallback (BindingData::Get (s.env ()).session_application_callback (),
391+ 0 ,
392+ nullptr );
393+ });
394+ }
395+
343396 // ==========================================================================
344397 // Session::Application
345398
@@ -474,9 +527,9 @@ class Http3ApplicationImpl final : public Session::Application {
474527 stream_id emit_id = is_notice ? -1 : goaway_id;
475528
476529 if (!is_notice) {
477- // Final GOAWAY: destroy client-initiated bidi streams with
478- // IDs > goaway_id. These were not processed by the peer and
479- // can be retried. Copy the map because Destroy modifies it.
530+ // Final GOAWAY: destroy client-initiated bidi streams with IDs >
531+ // goaway_id. These were not processed by the peer and can be retried.
532+ // Copy the map because Destroy() modifies it.
480533 auto streams = session ().streams ();
481534 for (auto & [id, stream] : streams) {
482535 if (session ().is_destroyed ()) return ;
@@ -498,7 +551,7 @@ class Http3ApplicationImpl final : public Session::Application {
498551 // when the peer sends CONNECTION_CLOSE after all streams finish.
499552 // Calling Close(GRACEFUL) would send a GOAWAY back and trigger
500553 // BeginShutdown, which can interfere with in-progress streams.
501- session (). EmitGoaway (emit_id);
554+ EmitGoaway (emit_id);
502555 }
503556
504557 bool ReceiveStreamData (stream_id id,
@@ -638,9 +691,9 @@ class Http3ApplicationImpl final : public Session::Application {
638691 }
639692
640693 int rv = nghttp3_conn_close_stream (*this , stream->id (), code);
641- // If the call is successful, the Http3ApplicationImpl ::OnStreamClose callback will
642- // be invoked when the stream is ready to be closed. We'll handle
643- // destroying the actual Stream object there.
694+ // If the call is successful, the Http3Application ::OnStreamClose
695+ // callback will be invoked when the stream is ready to be closed. We'll
696+ // handle destroying the actual Stream object there.
644697 if (rv == 0 ) return ;
645698
646699 if (rv == NGHTTP3_ERR_STREAM_NOT_FOUND ) {
@@ -880,8 +933,8 @@ class Http3ApplicationImpl final : public Session::Application {
880933 }
881934
882935 SET_NO_MEMORY_INFO ()
883- SET_MEMORY_INFO_NAME(Http3ApplicationImpl )
884- SET_SELF_SIZE(Http3ApplicationImpl )
936+ SET_MEMORY_INFO_NAME(Http3Application )
937+ SET_SELF_SIZE(Http3Application )
885938
886939 private:
887940 inline operator nghttp3_conn*() const {
@@ -1168,8 +1221,8 @@ class Http3ApplicationImpl final : public Session::Application {
11681221 Debug (&session (),
11691222 " HTTP/3 application received updated settings: %s" ,
11701223 options_);
1171- // Report the negotiated settings up to the JS application layer.
1172- session (). EmitApplication ();
1224+ // Report the negotiated settings up to the session/JS layer.
1225+ EmitApplicationSettings ();
11731226 }
11741227
11751228 // Inbound header-block accumulation, keyed by stream id. Entries are
@@ -1210,9 +1263,9 @@ class Http3ApplicationImpl final : public Session::Application {
12101263 // ==========================================================================
12111264 // Static callbacks
12121265
1213- static Http3ApplicationImpl * From (nghttp3_conn* conn, void * user_data) {
1266+ static Http3Application * From (nghttp3_conn* conn, void * user_data) {
12141267 DCHECK_NOT_NULL (user_data);
1215- auto app = static_cast <Http3ApplicationImpl *>(user_data);
1268+ auto app = static_cast <Http3Application *>(user_data);
12161269 DCHECK_EQ (conn, app->conn_ .get ());
12171270 return app;
12181271 }
@@ -1329,7 +1382,7 @@ class Http3ApplicationImpl final : public Session::Application {
13291382 void * conn_user_data,
13301383 void * stream_user_data) {
13311384 // This callback is invoked by nghttp3_conn_add_ack_offset() (called
1332- // from Http3ApplicationImpl ::AcknowledgeStreamData). We must NOT call
1385+ // from Http3Application ::AcknowledgeStreamData). We must NOT call
13331386 // AcknowledgeStreamData here — that would re-enter nghttp3 via
13341387 // nghttp3_conn_add_ack_offset, triggering the NgHttp3CallbackScope
13351388 // re-entrancy assertion. Instead, directly notify the stream that data
@@ -1553,7 +1606,7 @@ class Http3ApplicationImpl final : public Session::Application {
15531606 static int on_end_origin (nghttp3_conn* conn, void * conn_user_data) {
15541607 NGHTTP3_CALLBACK_SCOPE (app);
15551608 if (!app.received_origins_ .empty ()) {
1556- app.session (). EmitOrigins (std::move (app.received_origins_ ));
1609+ app.EmitOrigins (std::move (app.received_origins_ ));
15571610 app.received_origins_ .clear ();
15581611 }
15591612 return NGTCP2_SUCCESS ;
@@ -1598,7 +1651,7 @@ Http3Settings ResolveHttp3Settings(const Session::Options& options) {
15981651
15991652std::unique_ptr<Session::Application> CreateHttp3Application (Session* session) {
16001653 Debug (session, " Installing HTTP/3 application" );
1601- return std::make_unique<Http3ApplicationImpl >(
1654+ return std::make_unique<Http3Application >(
16021655 session,
16031656 ResolveHttp3Settings (std::as_const (*session).config ().options ));
16041657}
0 commit comments