diff --git a/src/node_http2.cc b/src/node_http2.cc index fca840c0fa03ad..58c69238d183d7 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -958,11 +958,13 @@ void Http2Session::ConsumeHTTP2Data() { nghttp2_session_want_read(session_.get())); set_receive_paused(false); custom_recv_error_code_ = nullptr; + set_receiving(); ssize_t ret = nghttp2_session_mem_recv(session_.get(), reinterpret_cast(stream_buf_.base) + stream_buf_offset_, read_len); + set_receiving(false); CHECK_NE(ret, NGHTTP2_ERR_NOMEM); CHECK_IMPLIES(custom_recv_error_code_ != nullptr, ret < 0); @@ -2534,6 +2536,19 @@ void Http2Stream::SubmitRstStream(const uint32_t code) { return code == NGHTTP2_CANCEL; }; + // Do not call `nghttp2_session_mem_send()` while nghttp2 is processing + // incoming data. Sending may close the stream and free nghttp2 state + // that is still in use by `nghttp2_session_mem_recv()`. + if (session_->is_receiving() && + available_outbound_length_ == 0) { + if (is_stream_cancel(code)) { + session_->AddPendingRstStream(id_); + return; + } + FlushRstStream(); + return; + } + // If RST_STREAM frame is received with error code NGHTTP2_CANCEL, // add it to the pending list and don't force purge the data. It is // to avoids the double free error due to unwanted behavior of nghttp2. diff --git a/src/node_http2.h b/src/node_http2.h index c9957cb559b323..e5ad6afb92f331 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -77,6 +77,7 @@ constexpr int kSessionStateSending = 0x10; constexpr int kSessionStateWriteInProgress = 0x20; constexpr int kSessionStateReadingStopped = 0x40; constexpr int kSessionStateReceivePaused = 0x80; +constexpr int kSessionStateReceiving = 0x100; // The Padding Strategy determines the method by which extra padding is // selected for HEADERS and DATA frames. These are configurable via the @@ -669,6 +670,7 @@ class Http2Session : public AsyncWrap, IS_FLAG(write_in_progress, kSessionStateWriteInProgress) IS_FLAG(reading_stopped, kSessionStateReadingStopped) IS_FLAG(receive_paused, kSessionStateReceivePaused) + IS_FLAG(receiving, kSessionStateReceiving) #undef IS_FLAG