From 373dfcc257a71867113dda79314e30f1cb0015db Mon Sep 17 00:00:00 2001 From: Edsko de Vries Date: Sat, 3 Feb 2024 09:32:15 +0100 Subject: [PATCH 1/2] Deal with `RST_STREAM` in `HalfClosedLocal` state See detailed justification in the code itself. --- Network/HTTP2/H2/Receiver.hs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/Network/HTTP2/H2/Receiver.hs b/Network/HTTP2/H2/Receiver.hs index a3dde6f7..87bb1d5a 100644 --- a/Network/HTTP2/H2/Receiver.hs +++ b/Network/HTTP2/H2/Receiver.hs @@ -558,16 +558,27 @@ stream FrameRSTStream header@FrameHeader{streamId} bs ctx s strm = do RSTStreamFrame err <- guardIt $ decodeRSTStreamFrame header bs let cc = Reset err - -- The spec mandates (section 8.1): + -- HTTP2 spec, section 5.1, "Stream States": -- - -- > When this is true, a server MAY request that the client abort - -- > transmission of a request without error by sending a RST_STREAM with an - -- > error code of NO_ERROR after sending a complete response (i.e., a frame - -- > with the END_STREAM flag). + -- > A stream in the "open" state may be used by both peers to send frames + -- > of any type. (..) From this state, either endpoint can send a frame + -- > with an END_STREAM flag set, which causes the stream to transition into + -- > one of the "half-closed" states. An endpoint sending an END_STREAM + -- > flag causes the stream state to become "half-closed (local)"; an + -- > endpoint receiving an END_STREAM flag causes the stream state to become + -- > "half-closed (remote)". -- - -- We check the first part ("after sending a complete response") by checking - -- the current stream state. + -- Crucially (for the specific case we're dealing with here), it continues: + -- + -- > /Either endpoint/ can send a RST_STREAM frame from this state, causing + -- > it to transition immediately to "closed". + -- + -- (emphasis not in original). This justifies the two non-error cases, + -- below. (Section 8.1 of the spec is also relevant, but it is less explicit + -- about the /either endpoint/ part.) case (s, err) of + (Open (Just _) _, NoError) -> -- HalfClosedLocal + return (Closed cc) (HalfClosedRemote, NoError) -> return (Closed cc) _otherwise -> do From 0b638883788fec42a7dd1aae105ee2f97b6a4235 Mon Sep 17 00:00:00 2001 From: Edsko de Vries Date: Tue, 6 Feb 2024 13:19:27 +0100 Subject: [PATCH 2/2] Make sure connection is always closed --- Network/HTTP2/H2/Receiver.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Network/HTTP2/H2/Receiver.hs b/Network/HTTP2/H2/Receiver.hs index 87bb1d5a..4ced970a 100644 --- a/Network/HTTP2/H2/Receiver.hs +++ b/Network/HTTP2/H2/Receiver.hs @@ -557,6 +557,7 @@ stream FrameRSTStream header@FrameHeader{streamId} bs ctx s strm = do ConnectionErrorIsSent EnhanceYourCalm streamId "too many rst_stream" RSTStreamFrame err <- guardIt $ decodeRSTStreamFrame header bs let cc = Reset err + closed ctx strm cc -- HTTP2 spec, section 5.1, "Stream States": -- @@ -582,7 +583,6 @@ stream FrameRSTStream header@FrameHeader{streamId} bs ctx s strm = do (HalfClosedRemote, NoError) -> return (Closed cc) _otherwise -> do - closed ctx strm cc E.throwIO $ StreamErrorIsReceived err streamId -- (No state transition)