@@ -1566,7 +1566,7 @@ defmodule Mint.HTTP2 do
15661566 responses = [ { :data , stream . ref , data } | responses ]
15671567
15681568 if flag_set? ( flags , :data , :end_stream ) do
1569- conn = close_stream! ( conn , stream . id , :no_error )
1569+ conn = close_stream! ( conn , stream . id , :remote_end_stream )
15701570 { conn , [ { :done , stream . ref } | responses ] }
15711571 else
15721572 { conn , responses }
@@ -1675,7 +1675,7 @@ defmodule Mint.HTTP2 do
16751675 { conn , responses }
16761676
16771677 end_stream? ->
1678- conn = close_stream! ( conn , stream . id , :no_error )
1678+ conn = close_stream! ( conn , stream . id , :remote_end_stream )
16791679 { conn , [ { :done , ref } | new_responses ] }
16801680
16811681 true ->
@@ -1685,7 +1685,7 @@ defmodule Mint.HTTP2 do
16851685 end
16861686
16871687 end_stream? ->
1688- conn = close_stream! ( conn , stream . id , :no_error )
1688+ conn = close_stream! ( conn , stream . id , :remote_end_stream )
16891689 { conn , [ { :done , ref } | new_responses ] }
16901690
16911691 true ->
@@ -1695,7 +1695,7 @@ defmodule Mint.HTTP2 do
16951695 # Trailer headers. We don't care about the :status header here.
16961696 headers when received_first_headers? ->
16971697 if end_stream? do
1698- conn = close_stream! ( conn , stream . id , :no_error )
1698+ conn = close_stream! ( conn , stream . id , :remote_end_stream )
16991699 headers = headers |> Headers . remove_unallowed_trailer ( ) |> join_cookie_headers ( )
17001700 { conn , [ { :done , ref } , { :headers , ref , headers } | responses ] }
17011701 else
@@ -2094,18 +2094,27 @@ defmodule Mint.HTTP2 do
20942094 throw ( { :mint , % { conn | state: :closed } , wrap_error ( { error_code , debug_data } ) } )
20952095 end
20962096
2097- defp close_stream! ( conn , stream_id , error_code ) do
2097+ # Reason is either an error code or `remote_end_stream`
2098+ defp close_stream! ( conn , stream_id , reason ) do
20982099 stream = Map . fetch! ( conn . streams , stream_id )
20992100
2100- # First of all we send a RST_STREAM with the given error code so that we
2101- # move the stream to the :closed state (that is, we remove it).
2102- rst_stream_frame = rst_stream ( stream_id: stream_id , error_code: error_code )
2103-
21042101 conn =
2105- if open? ( conn ) do
2106- send! ( conn , Frame . encode ( rst_stream_frame ) )
2107- else
2108- conn
2102+ cond do
2103+ # If the stream is ended on both sides, it is already deemed closed and
2104+ # there's no need to send a RST_STREAM frame
2105+ reason == :remote_end_stream and stream . state == :half_closed_local ->
2106+ conn
2107+
2108+ # We send a RST_STREAM with the given error code so that we move the
2109+ # stream to the :closed state (that is, we remove it).
2110+ open? ( conn ) ->
2111+ error_code = if reason == :remote_end_stream , do: :no_error , else: reason
2112+ rst_stream_frame = rst_stream ( stream_id: stream_id , error_code: error_code )
2113+ send! ( conn , Frame . encode ( rst_stream_frame ) )
2114+
2115+ # If the connection is already closed, no-op
2116+ true ->
2117+ conn
21092118 end
21102119
21112120 delete_stream ( conn , stream )
0 commit comments