@@ -545,7 +545,8 @@ Http2Session::Http2Session(Http2State* http2_state,
545
545
: AsyncWrap(http2_state->env (), wrap, AsyncWrap::PROVIDER_HTTP2SESSION),
546
546
js_fields_(http2_state->env ()->isolate()),
547
547
session_type_(type),
548
- http2_state_(http2_state) {
548
+ http2_state_(http2_state),
549
+ graceful_close_initiated_(false ) {
549
550
MakeWeak ();
550
551
statistics_.session_type = type;
551
552
statistics_.start_time = uv_hrtime ();
@@ -749,6 +750,24 @@ void Http2Stream::EmitStatistics() {
749
750
});
750
751
}
751
752
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
+
752
771
void Http2Session::EmitStatistics () {
753
772
if (LIKELY (!HasHttp2Observer (env ())))
754
773
return ;
@@ -1725,6 +1744,7 @@ void Http2Session::HandleSettingsFrame(const nghttp2_frame* frame) {
1725
1744
void Http2Session::OnStreamAfterWrite (WriteWrap* w, int status) {
1726
1745
Debug (this , " write finished with status %d" , status);
1727
1746
1747
+ MaybeNotifyGracefulCloseComplete ();
1728
1748
CHECK (is_write_in_progress ());
1729
1749
set_write_in_progress (false );
1730
1750
@@ -1945,6 +1965,7 @@ uint8_t Http2Session::SendPendingData() {
1945
1965
if (!res.async ) {
1946
1966
set_write_in_progress (false );
1947
1967
ClearOutgoing (res.err );
1968
+ MaybeNotifyGracefulCloseComplete ();
1948
1969
}
1949
1970
1950
1971
MaybeStopReading ();
@@ -3418,6 +3439,8 @@ void Initialize(Local<Object> target,
3418
3439
SetProtoMethod (isolate, session, " receive" , Http2Session::Receive);
3419
3440
SetProtoMethod (isolate, session, " destroy" , Http2Session::Destroy);
3420
3441
SetProtoMethod (isolate, session, " goaway" , Http2Session::Goaway);
3442
+ SetProtoMethod (
3443
+ isolate, session, " hasPendingData" , Http2Session::HasPendingData);
3421
3444
SetProtoMethod (isolate, session, " settings" , Http2Session::Settings);
3422
3445
SetProtoMethod (isolate, session, " request" , Http2Session::Request);
3423
3446
SetProtoMethod (
@@ -3438,6 +3461,8 @@ void Initialize(Local<Object> target,
3438
3461
" remoteSettings" ,
3439
3462
Http2Session::RefreshSettings<nghttp2_session_get_remote_settings,
3440
3463
false >);
3464
+ SetProtoMethod (
3465
+ isolate, session, " setGracefulClose" , Http2Session::SetGracefulClose);
3441
3466
SetConstructorFunction (context, target, " Http2Session" , session);
3442
3467
3443
3468
Local<Object> constants = Object::New (isolate);
@@ -3492,6 +3517,38 @@ void Initialize(Local<Object> target,
3492
3517
nghttp2_set_debug_vprintf_callback (NgHttp2Debug);
3493
3518
#endif
3494
3519
}
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
+ }
3495
3552
} // namespace http2
3496
3553
} // namespace node
3497
3554
0 commit comments