@@ -561,7 +561,8 @@ Http2Session::Http2Session(Http2State* http2_state,
561
561
: AsyncWrap(http2_state->env (), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
562
562
js_fields_(http2_state->env ()->isolate()),
563
563
session_type_(type),
564
- http2_state_(http2_state) {
564
+ http2_state_(http2_state),
565
+ graceful_close_initiated_(false ) {
565
566
MakeWeak ();
566
567
statistics_.session_type = type;
567
568
statistics_.start_time = uv_hrtime ();
@@ -767,6 +768,24 @@ void Http2Stream::EmitStatistics() {
767
768
});
768
769
}
769
770
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
+
770
789
void Http2Session::EmitStatistics () {
771
790
if (!HasHttp2Observer (env ())) [[likely]] {
772
791
return ;
@@ -1745,6 +1764,7 @@ void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) {
1745
1764
void Http2Session::OnStreamAfterWrite (WriteWrap* w, int status) {
1746
1765
Debug (this , " write finished with status %d" , status);
1747
1766
1767
+ MaybeNotifyGracefulCloseComplete ();
1748
1768
CHECK (is_write_in_progress ());
1749
1769
set_write_in_progress (false );
1750
1770
@@ -1967,6 +1987,7 @@ uint8_t Http2Session::SendPendingData() {
1967
1987
if (!res.async ) {
1968
1988
set_write_in_progress (false );
1969
1989
ClearOutgoing (res.err );
1990
+ MaybeNotifyGracefulCloseComplete ();
1970
1991
}
1971
1992
1972
1993
MaybeStopReading ();
@@ -3478,6 +3499,8 @@ void Initialize(Local<Object> target,
3478
3499
SetProtoMethod (isolate, session, " receive" , Http2Session::Receive);
3479
3500
SetProtoMethod (isolate, session, " destroy" , Http2Session::Destroy);
3480
3501
SetProtoMethod (isolate, session, " goaway" , Http2Session::Goaway);
3502
+ SetProtoMethod (
3503
+ isolate, session, " hasPendingData" , Http2Session::HasPendingData);
3481
3504
SetProtoMethod (isolate, session, " settings" , Http2Session::Settings);
3482
3505
SetProtoMethod (isolate, session, " request" , Http2Session::Request);
3483
3506
SetProtoMethod (
@@ -3498,6 +3521,8 @@ void Initialize(Local<Object> target,
3498
3521
" remoteSettings" ,
3499
3522
Http2Session::RefreshSettings<nghttp2_session_get_remote_settings,
3500
3523
false >);
3524
+ SetProtoMethod (
3525
+ isolate, session, " setGracefulClose" , Http2Session::SetGracefulClose);
3501
3526
SetConstructorFunction (context, target, " Http2Session" , session);
3502
3527
3503
3528
Local<Object> constants = Object::New (isolate);
@@ -3552,6 +3577,38 @@ void Initialize(Local<Object> target,
3552
3577
nghttp2_set_debug_vprintf_callback (NgHttp2Debug);
3553
3578
#endif
3554
3579
}
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
+ }
3555
3612
} // namespace http2
3556
3613
} // namespace node
3557
3614
0 commit comments