diff --git a/src/node_http2.cc b/src/node_http2.cc index 3b8d87a2215b..85d34e06f6fb 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -1321,15 +1321,22 @@ int Http2Session::OnFrameSent(nghttp2_session* handle, // error like oversized frames, padding errors, or HPACK compression // failures), it calls nghttp2_session_terminate_session() directly which // queues a GOAWAY but does not invoke any application-level callback. - // Detect that case here: a GOAWAY was sent but we never initiated it - // (no Close(), no session.close(), no session.goaway()). + // Detect that case here: a GOAWAY was sent but it was not the one we + // initiated through session.goaway() / session.close(). Note that those + // methods can be reached without application code when a peer sends + // GOAWAY, so goaway_initiated_ and graceful_close_initiated_ can both be + // set even though the GOAWAY we are seeing here was not requested by us. + // A GOAWAY we submitted carries the error code we passed, so if nghttp2 + // sends a frame with a different code it was not requested by us and is + // the result of an internal termination. // // We set a flag here, and then throw the error at the end of // SendPendingData, to wait until the GOAWAY is written before the session // is torn down. if (frame->hd.type == NGHTTP2_GOAWAY && !session->is_closing() && - !session->is_destroyed() && !session->IsGracefulCloseInitiated() && - !session->goaway_initiated_) { + !session->is_destroyed() && + (!session->goaway_initiated_ || + frame->goaway.error_code != session->goaway_code())) { Debug(session, "nghttp2 session terminated internally"); session->internal_goaway_sent_ = true; } @@ -3084,6 +3091,7 @@ void Http2Session::Goaway(uint32_t code, return; goaway_initiated_ = true; + goaway_code_ = code; Http2Scope h2scope(this); // the last proc stream id is the most recently created Http2Stream. if (lastStreamID <= 0) diff --git a/src/node_http2.h b/src/node_http2.h index c042c46ab595..c228f179eed6 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -850,6 +850,9 @@ class Http2Session : public AsyncWrap, void SetGracefulCloseInitiated(bool value) { graceful_close_initiated_ = value; } + uint32_t goaway_code() const { + return goaway_code_; + } private: void EmitStatistics(); @@ -1031,6 +1034,9 @@ class Http2Session : public AsyncWrap, bool graceful_close_initiated_ = false; bool goaway_initiated_ = false; bool internal_goaway_sent_ = false; + // Error code passed to the last session.goaway()/session.close() call; + // used by OnFrameSent to tell an internal nghttp2 GOAWAY from ours. + uint32_t goaway_code_ = NGHTTP2_NO_ERROR; }; struct Http2SessionPerformanceEntryTraits {