@@ -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