diff --git a/h11/_connection.py b/h11/_connection.py index e37d82a..d8ede96 100644 --- a/h11/_connection.py +++ b/h11/_connection.py @@ -478,6 +478,7 @@ def next_event(self) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: if self.their_state is ERROR: raise RemoteProtocolError("Can't receive data when peer state is ERROR") try: + receive_buffer_len_before = len(self._receive_buffer) event = self._extract_next_receive_event() if event not in [NEED_DATA, PAUSED]: self._process_event(self.their_role, cast(Event, event)) @@ -492,6 +493,15 @@ def next_event(self) -> Union[Event, Type[NEED_DATA], Type[PAUSED]]: # We're still trying to complete some event, but that's # never going to happen because no more data is coming raise RemoteProtocolError("peer unexpectedly closed connection") + + if isinstance(event, (Request, InformationalResponse, Response)): + read_from_buffer = receive_buffer_len_before - len(self._receive_buffer) + if read_from_buffer > self._max_incomplete_event_size + 1: + # 431 is "Request header fields too large" which is pretty + # much the only situation where we can get here + raise RemoteProtocolError( + "Receive buffer too long", error_status_hint=431 + ) return event except BaseException as exc: self._process_error(self.their_role) diff --git a/h11/tests/test_connection.py b/h11/tests/test_connection.py index 01260dc..b7923c3 100644 --- a/h11/tests/test_connection.py +++ b/h11/tests/test_connection.py @@ -486,6 +486,22 @@ def test_max_incomplete_event_size_countermeasure() -> None: c.next_event() +@pytest.mark.parametrize("chunking", [False, True]) +def test_max_incomplete_event_size_enforced_regardless_of_chunking(chunking) -> None: + buffer = b"GET / HTTP/1.0\r\nBig: " + b"a" * 4000 + b"\r\n\r\n" + c = Connection(SERVER, max_incomplete_event_size=(len(buffer) - 2)) + + if chunking: + chunks = [buffer[:-1], buffer[-1:]] + else: + chunks = [buffer] + + with pytest.raises(RemoteProtocolError): + for chunk in chunks: + c.receive_data(chunk) + get_all_events(c) + + def test_reuse_simple() -> None: p = ConnectionPair() p.send(