@@ -559,7 +559,8 @@ Http2Session::Http2Session(Http2State* http2_state,
559
559
: AsyncWrap(http2_state->env (), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
560
560
js_fields_(http2_state->env ()->isolate()),
561
561
session_type_(type),
562
- http2_state_(http2_state) {
562
+ http2_state_(http2_state),
563
+ graceful_close_initiated_(false ) {
563
564
MakeWeak ();
564
565
statistics_.session_type = type;
565
566
statistics_.start_time = uv_hrtime ();
@@ -765,6 +766,24 @@ void Http2Stream::EmitStatistics() {
765
766
});
766
767
}
767
768
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
+
768
787
void Http2Session::EmitStatistics () {
769
788
if (!HasHttp2Observer (env ())) [[likely]] {
770
789
return ;
@@ -1743,6 +1762,7 @@ void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) {
1743
1762
void Http2Session::OnStreamAfterWrite (WriteWrap* w, int status) {
1744
1763
Debug (this , " write finished with status %d" , status);
1745
1764
1765
+ MaybeNotifyGracefulCloseComplete ();
1746
1766
CHECK (is_write_in_progress ());
1747
1767
set_write_in_progress (false );
1748
1768
@@ -1965,6 +1985,7 @@ uint8_t Http2Session::SendPendingData() {
1965
1985
if (!res.async ) {
1966
1986
set_write_in_progress (false );
1967
1987
ClearOutgoing (res.err );
1988
+ MaybeNotifyGracefulCloseComplete ();
1968
1989
}
1969
1990
1970
1991
MaybeStopReading ();
@@ -3476,6 +3497,8 @@ void Initialize(Local<Object> target,
3476
3497
SetProtoMethod (isolate, session, " receive" , Http2Session::Receive);
3477
3498
SetProtoMethod (isolate, session, " destroy" , Http2Session::Destroy);
3478
3499
SetProtoMethod (isolate, session, " goaway" , Http2Session::Goaway);
3500
+ SetProtoMethod (
3501
+ isolate, session, " hasPendingData" , Http2Session::HasPendingData);
3479
3502
SetProtoMethod (isolate, session, " settings" , Http2Session::Settings);
3480
3503
SetProtoMethod (isolate, session, " request" , Http2Session::Request);
3481
3504
SetProtoMethod (
@@ -3496,6 +3519,8 @@ void Initialize(Local<Object> target,
3496
3519
" remoteSettings" ,
3497
3520
Http2Session::RefreshSettings<nghttp2_session_get_remote_settings,
3498
3521
false >);
3522
+ SetProtoMethod (
3523
+ isolate, session, " setGracefulClose" , Http2Session::SetGracefulClose);
3499
3524
SetConstructorFunction (context, target, " Http2Session" , session);
3500
3525
3501
3526
Local<Object> constants = Object::New (isolate);
@@ -3550,6 +3575,38 @@ void Initialize(Local<Object> target,
3550
3575
nghttp2_set_debug_vprintf_callback (NgHttp2Debug);
3551
3576
#endif
3552
3577
}
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
+ }
3553
3610
} // namespace http2
3554
3611
} // namespace node
3555
3612
0 commit comments