diff --git a/mitmproxy/proxy/layers/http/_http3.py b/mitmproxy/proxy/layers/http/_http3.py index 4ee46c94f..3275fcd1a 100644 --- a/mitmproxy/proxy/layers/http/_http3.py +++ b/mitmproxy/proxy/layers/http/_http3.py @@ -162,19 +162,23 @@ class Http3Connection(HttpConnection): yield from self.h3_conn.transmit() # report a protocol error for all remaining open streams when a connection is closed - elif isinstance(event, events.ConnectionClosed): + elif isinstance(event, QuicConnectionClosed): self._handle_event = self.done # type: ignore - if isinstance(event, QuicConnectionClosed): - msg = event.reason_phrase or error_code_to_str(event.error_code) - else: - msg = "peer closed connection" + msg = event.reason_phrase or error_code_to_str(event.error_code) for stream_id in self.h3_conn.get_reserved_stream_ids(): yield ReceiveHttp(self.ReceiveProtocolError(stream_id, msg)) + # turn `QuicErrorCode.NO_ERROR` into `H3ErrorCode.H3_NO_ERROR` + self.h3_conn.close_connection( + event.error_code or H3ErrorCode.H3_NO_ERROR, + event.frame_type, + event.reason_phrase, + ) + yield from self.h3_conn.transmit() else: raise AssertionError(f"Unexpected event: {event!r}") - @expect(QuicStreamEvent, HttpEvent, events.ConnectionClosed) + @expect(HttpEvent, QuicStreamEvent, QuicConnectionClosed) def done(self, _) -> layer.CommandGenerator[None]: yield from () diff --git a/mitmproxy/proxy/layers/http/_http_h3.py b/mitmproxy/proxy/layers/http/_http_h3.py index d70a44163..d4573ca85 100644 --- a/mitmproxy/proxy/layers/http/_http_h3.py +++ b/mitmproxy/proxy/layers/http/_http_h3.py @@ -143,11 +143,16 @@ class LayeredH3Connection(H3Connection): events[index] = TrailersReceived(event.headers, event.stream_id, event.stream_ended, event.push_id) return events - def close_connection(self, error_code: int = QuicErrorCode.NO_ERROR, reason_phrase: str = "") -> None: + def close_connection( + self, + error_code: int = QuicErrorCode.NO_ERROR, + frame_type: Optional[int] = None, + reason_phrase: str = "", + ) -> None: """Closes the underlying QUIC connection and ignores any incoming events.""" self._is_done = True - self._quic.close(error_code=error_code, reason_phrase=reason_phrase) + self._quic.close(error_code, frame_type, reason_phrase) def end_stream(self, stream_id: int) -> None: """Ends the given stream locally.""" diff --git a/mitmproxy/proxy/layers/quic.py b/mitmproxy/proxy/layers/quic.py index 32cac1154..b5fdb41c1 100644 --- a/mitmproxy/proxy/layers/quic.py +++ b/mitmproxy/proxy/layers/quic.py @@ -927,7 +927,7 @@ class QuicLayer(tunnel.TunnelLayer): # if `_close_event` is not set, the underlying connection has been closed # we turn this into a QUIC close event as well close_event = self.quic._close_event or quic_events.ConnectionTerminated( - QuicErrorCode.APPLICATION_ERROR, None, "Connection closed." + QuicErrorCode.NO_ERROR, None, "Connection closed." ) yield from self.event_to_child( QuicConnectionClosed(self.conn, close_event.error_code, close_event.frame_type, close_event.reason_phrase)