@@ -561,7 +561,8 @@ Http2Session::Http2Session(Http2State* http2_state,
561561 : AsyncWrap(http2_state->env (), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
562562 js_fields_(http2_state->env ()->isolate()),
563563 session_type_(type),
564- http2_state_(http2_state) {
564+ http2_state_(http2_state),
565+ graceful_close_initiated_(false ) {
565566 MakeWeak ();
566567 statistics_.session_type = type;
567568 statistics_.start_time = uv_hrtime ();
@@ -767,6 +768,24 @@ void Http2Stream::EmitStatistics() {
767768 });
768769}
769770
771+ void Http2Session::HasPendingData (const FunctionCallbackInfo<Value>& args) {
772+ Http2Session* session;
773+ ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
774+ args.GetReturnValue ().Set (session->HasPendingData ());
775+ }
776+
777+ bool Http2Session::HasPendingData () const {
778+ nghttp2_session* session = session_.get ();
779+ int want_write = nghttp2_session_want_write (session);
780+ // It is expected that want_read will alway be 0 if graceful
781+ // session close is initiated and goaway frame is sent.
782+ int want_read = nghttp2_session_want_read (session);
783+ if (want_write == 0 && want_read == 0 ) {
784+ return false ;
785+ }
786+ return true ;
787+ }
788+
770789void Http2Session::EmitStatistics () {
771790 if (!HasHttp2Observer (env ())) [[likely]] {
772791 return ;
@@ -1745,6 +1764,7 @@ void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) {
17451764void Http2Session::OnStreamAfterWrite (WriteWrap* w, int status) {
17461765 Debug (this , " write finished with status %d" , status);
17471766
1767+ MaybeNotifyGracefulCloseComplete ();
17481768 CHECK (is_write_in_progress ());
17491769 set_write_in_progress (false );
17501770
@@ -1967,6 +1987,7 @@ uint8_t Http2Session::SendPendingData() {
19671987 if (!res.async ) {
19681988 set_write_in_progress (false );
19691989 ClearOutgoing (res.err );
1990+ MaybeNotifyGracefulCloseComplete ();
19701991 }
19711992
19721993 MaybeStopReading ();
@@ -3478,6 +3499,8 @@ void Initialize(Local<Object> target,
34783499 SetProtoMethod (isolate, session, " receive" , Http2Session::Receive);
34793500 SetProtoMethod (isolate, session, " destroy" , Http2Session::Destroy);
34803501 SetProtoMethod (isolate, session, " goaway" , Http2Session::Goaway);
3502+ SetProtoMethod (
3503+ isolate, session, " hasPendingData" , Http2Session::HasPendingData);
34813504 SetProtoMethod (isolate, session, " settings" , Http2Session::Settings);
34823505 SetProtoMethod (isolate, session, " request" , Http2Session::Request);
34833506 SetProtoMethod (
@@ -3498,6 +3521,8 @@ void Initialize(Local<Object> target,
34983521 " remoteSettings" ,
34993522 Http2Session::RefreshSettings<nghttp2_session_get_remote_settings,
35003523 false >);
3524+ SetProtoMethod (
3525+ isolate, session, " setGracefulClose" , Http2Session::SetGracefulClose);
35013526 SetConstructorFunction (context, target, " Http2Session" , session);
35023527
35033528 Local<Object> constants = Object::New (isolate);
@@ -3552,6 +3577,38 @@ void Initialize(Local<Object> target,
35523577 nghttp2_set_debug_vprintf_callback (NgHttp2Debug);
35533578#endif
35543579}
3580+
3581+ void Http2Session::SetGracefulClose (const FunctionCallbackInfo<Value>& args) {
3582+ Http2Session* session;
3583+ ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
3584+ CHECK_NOT_NULL (session);
3585+ // Set the graceful close flag
3586+ session->SetGracefulCloseInitiated (true );
3587+
3588+ Debug (session, " Setting graceful close initiated flag" );
3589+ }
3590+
3591+ void Http2Session::MaybeNotifyGracefulCloseComplete () {
3592+ nghttp2_session* session = session_.get ();
3593+
3594+ if (!IsGracefulCloseInitiated ()) {
3595+ return ;
3596+ }
3597+
3598+ int want_write = nghttp2_session_want_write (session);
3599+ int want_read = nghttp2_session_want_read (session);
3600+ bool should_notify = (want_write == 0 && want_read == 0 );
3601+
3602+ if (should_notify) {
3603+ Debug (this , " Notifying JS after write in graceful close mode" );
3604+
3605+ // Make the callback to JavaScript
3606+ HandleScope scope (env ()->isolate ());
3607+ MakeCallback (env ()->ongracefulclosecomplete_string (), 0 , nullptr );
3608+ }
3609+
3610+ return ;
3611+ }
35553612} // namespace http2
35563613} // namespace node
35573614
0 commit comments