@@ -559,7 +559,8 @@ Http2Session::Http2Session(Http2State* http2_state,
559559 : AsyncWrap(http2_state->env (), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
560560 js_fields_(http2_state->env ()->isolate()),
561561 session_type_(type),
562- http2_state_(http2_state) {
562+ http2_state_(http2_state),
563+ graceful_close_initiated_(false ) {
563564 MakeWeak ();
564565 statistics_.session_type = type;
565566 statistics_.start_time = uv_hrtime ();
@@ -765,6 +766,24 @@ void Http2Stream::EmitStatistics() {
765766 });
766767}
767768
769+ void Http2Session::HasPendingData (const FunctionCallbackInfo<Value>& args) {
770+ Http2Session* session;
771+ ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
772+ args.GetReturnValue ().Set (session->HasPendingData ());
773+ }
774+
775+ bool Http2Session::HasPendingData () const {
776+ nghttp2_session* session = session_.get ();
777+ int want_write = nghttp2_session_want_write (session);
778+ // It is expected that want_read will alway be 0 if graceful
779+ // session close is initiated and goaway frame is sent.
780+ int want_read = nghttp2_session_want_read (session);
781+ if (want_write == 0 && want_read == 0 ) {
782+ return false ;
783+ }
784+ return true ;
785+ }
786+
768787void Http2Session::EmitStatistics () {
769788 if (!HasHttp2Observer (env ())) [[likely]] {
770789 return ;
@@ -1743,6 +1762,7 @@ void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) {
17431762void Http2Session::OnStreamAfterWrite (WriteWrap* w, int status) {
17441763 Debug (this , " write finished with status %d" , status);
17451764
1765+ MaybeNotifyGracefulCloseComplete ();
17461766 CHECK (is_write_in_progress ());
17471767 set_write_in_progress (false );
17481768
@@ -1965,6 +1985,7 @@ uint8_t Http2Session::SendPendingData() {
19651985 if (!res.async ) {
19661986 set_write_in_progress (false );
19671987 ClearOutgoing (res.err );
1988+ MaybeNotifyGracefulCloseComplete ();
19681989 }
19691990
19701991 MaybeStopReading ();
@@ -3476,6 +3497,8 @@ void Initialize(Local<Object> target,
34763497 SetProtoMethod (isolate, session, " receive" , Http2Session::Receive);
34773498 SetProtoMethod (isolate, session, " destroy" , Http2Session::Destroy);
34783499 SetProtoMethod (isolate, session, " goaway" , Http2Session::Goaway);
3500+ SetProtoMethod (
3501+ isolate, session, " hasPendingData" , Http2Session::HasPendingData);
34793502 SetProtoMethod (isolate, session, " settings" , Http2Session::Settings);
34803503 SetProtoMethod (isolate, session, " request" , Http2Session::Request);
34813504 SetProtoMethod (
@@ -3496,6 +3519,8 @@ void Initialize(Local<Object> target,
34963519 " remoteSettings" ,
34973520 Http2Session::RefreshSettings<nghttp2_session_get_remote_settings,
34983521 false >);
3522+ SetProtoMethod (
3523+ isolate, session, " setGracefulClose" , Http2Session::SetGracefulClose);
34993524 SetConstructorFunction (context, target, " Http2Session" , session);
35003525
35013526 Local<Object> constants = Object::New (isolate);
@@ -3550,6 +3575,38 @@ void Initialize(Local<Object> target,
35503575 nghttp2_set_debug_vprintf_callback (NgHttp2Debug);
35513576#endif
35523577}
3578+
3579+ void Http2Session::SetGracefulClose (const FunctionCallbackInfo<Value>& args) {
3580+ Http2Session* session;
3581+ ASSIGN_OR_RETURN_UNWRAP (&session, args.Holder ());
3582+ CHECK_NOT_NULL (session);
3583+ // Set the graceful close flag
3584+ session->SetGracefulCloseInitiated (true );
3585+
3586+ Debug (session, " Setting graceful close initiated flag" );
3587+ }
3588+
3589+ void Http2Session::MaybeNotifyGracefulCloseComplete () {
3590+ nghttp2_session* session = session_.get ();
3591+
3592+ if (!IsGracefulCloseInitiated ()) {
3593+ return ;
3594+ }
3595+
3596+ int want_write = nghttp2_session_want_write (session);
3597+ int want_read = nghttp2_session_want_read (session);
3598+ bool should_notify = (want_write == 0 && want_read == 0 );
3599+
3600+ if (should_notify) {
3601+ Debug (this , " Notifying JS after write in graceful close mode" );
3602+
3603+ // Make the callback to JavaScript
3604+ HandleScope scope (env ()->isolate ());
3605+ MakeCallback (env ()->ongracefulclosecomplete_string (), 0 , nullptr );
3606+ }
3607+
3608+ return ;
3609+ }
35533610} // namespace http2
35543611} // namespace node
35553612
0 commit comments