@@ -545,7 +545,8 @@ Http2Session::Http2Session(Http2State* http2_state,
545545 : AsyncWrap(http2_state->env (), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
546546 js_fields_(http2_state->env ()->isolate()),
547547 session_type_(type),
548-  http2_state_(http2_state) {
548+  http2_state_(http2_state),
549+  graceful_close_initiated_(false ) {
549550 MakeWeak ();
550551 statistics_.session_type  = type;
551552 statistics_.start_time  = uv_hrtime ();
@@ -749,6 +750,24 @@ void Http2Stream::EmitStatistics() {
749750 });
750751}
751752
753+ void  Http2Session::HasPendingData (const  FunctionCallbackInfo<Value>& args) {
754+  Http2Session* session;
755+  ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
756+  args.GetReturnValue ().Set (session->HasPendingData ());
757+ }
758+ 
759+ bool  Http2Session::HasPendingData () const  {
760+  nghttp2_session* session = session_.get ();
761+  int  want_write = nghttp2_session_want_write (session);
762+  //  It is expected that want_read will alway be 0 if graceful
763+  //  session close is initiated and goaway frame is sent.
764+  int  want_read = nghttp2_session_want_read (session);
765+  if  (want_write == 0  && want_read == 0 ) {
766+  return  false ;
767+  }
768+  return  true ;
769+ }
770+ 
752771void  Http2Session::EmitStatistics () {
753772 if  (LIKELY (!HasHttp2Observer (env ())))
754773 return ;
@@ -1725,6 +1744,7 @@ void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) {
17251744void  Http2Session::OnStreamAfterWrite (WriteWrap* w, int  status) {
17261745 Debug (this , " write finished with status %d"  , status);
17271746
1747+  MaybeNotifyGracefulCloseComplete ();
17281748 CHECK (is_write_in_progress ());
17291749 set_write_in_progress (false );
17301750
@@ -1945,6 +1965,7 @@ uint8_t Http2Session::SendPendingData() {
19451965 if  (!res.async ) {
19461966 set_write_in_progress (false );
19471967 ClearOutgoing (res.err );
1968+  MaybeNotifyGracefulCloseComplete ();
19481969 }
19491970
19501971 MaybeStopReading ();
@@ -3418,6 +3439,8 @@ void Initialize(Local<Object> target,
34183439 SetProtoMethod (isolate, session, " receive"  , Http2Session::Receive);
34193440 SetProtoMethod (isolate, session, " destroy"  , Http2Session::Destroy);
34203441 SetProtoMethod (isolate, session, " goaway"  , Http2Session::Goaway);
3442+  SetProtoMethod (
3443+  isolate, session, " hasPendingData"  , Http2Session::HasPendingData);
34213444 SetProtoMethod (isolate, session, " settings"  , Http2Session::Settings);
34223445 SetProtoMethod (isolate, session, " request"  , Http2Session::Request);
34233446 SetProtoMethod (
@@ -3438,6 +3461,8 @@ void Initialize(Local<Object> target,
34383461 " remoteSettings"  ,
34393462 Http2Session::RefreshSettings<nghttp2_session_get_remote_settings,
34403463 false >);
3464+  SetProtoMethod (
3465+  isolate, session, " setGracefulClose"  , Http2Session::SetGracefulClose);
34413466 SetConstructorFunction (context, target, " Http2Session"  , session);
34423467
34433468 Local<Object> constants = Object::New (isolate);
@@ -3492,6 +3517,38 @@ void Initialize(Local<Object> target,
34923517 nghttp2_set_debug_vprintf_callback (NgHttp2Debug);
34933518#endif 
34943519}
3520+ 
3521+ void  Http2Session::SetGracefulClose (const  FunctionCallbackInfo<Value>& args) {
3522+  Http2Session* session;
3523+  ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
3524+  CHECK_NOT_NULL (session);
3525+  //  Set the graceful close flag
3526+  session->SetGracefulCloseInitiated (true );
3527+ 
3528+  Debug (session, " Setting graceful close initiated flag"  );
3529+ }
3530+ 
3531+ void  Http2Session::MaybeNotifyGracefulCloseComplete () {
3532+  nghttp2_session* session = session_.get ();
3533+ 
3534+  if  (!IsGracefulCloseInitiated ()) {
3535+  return ;
3536+  }
3537+ 
3538+  int  want_write = nghttp2_session_want_write (session);
3539+  int  want_read = nghttp2_session_want_read (session);
3540+  bool  should_notify = (want_write == 0  && want_read == 0 );
3541+ 
3542+  if  (should_notify) {
3543+  Debug (this , " Notifying JS after write in graceful close mode"  );
3544+ 
3545+  //  Make the callback to JavaScript
3546+  HandleScope scope (env ()->isolate ());
3547+  MakeCallback (env ()->ongracefulclosecomplete_string (), 0 , nullptr );
3548+  }
3549+ 
3550+  return ;
3551+ }
34953552} //  namespace http2
34963553} //  namespace node
34973554
0 commit comments