diff --git a/httpcore/_async/http11.py b/httpcore/_async/http11.py index fdf4c5e90..49b5367c7 100644 --- a/httpcore/_async/http11.py +++ b/httpcore/_async/http11.py @@ -172,6 +172,19 @@ async def _receive_event(self, timeout: float = None) -> H11Event: data = await self._network_stream.read( self.READ_NUM_BYTES, timeout=timeout ) + + # If we feed this case through h11 we'll raise an exception like: + # + # httpcore.RemoteProtocolError: can't handle event type + # ConnectionClosed when role=SERVER and state=SEND_RESPONSE + # + # Which is accurate, but not very informative from an end-user + # perspective. Instead we handle this case distinctly and treat + # it as a ConnectError. + if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE: + msg = "Server disconnected without sending a response." + raise RemoteProtocolError(msg) + self._h11_state.receive_data(data) else: return event diff --git a/httpcore/_sync/http11.py b/httpcore/_sync/http11.py index 1b6498a96..e629027bb 100644 --- a/httpcore/_sync/http11.py +++ b/httpcore/_sync/http11.py @@ -172,6 +172,19 @@ def _receive_event(self, timeout: float = None) -> H11Event: data = self._network_stream.read( self.READ_NUM_BYTES, timeout=timeout ) + + # If we feed this case through h11 we'll raise an exception like: + # + # httpcore.RemoteProtocolError: can't handle event type + # ConnectionClosed when role=SERVER and state=SEND_RESPONSE + # + # Which is accurate, but not very informative from an end-user + # perspective. Instead we handle this case distinctly and treat + # it as a ConnectError. + if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE: + msg = "Server disconnected without sending a response." + raise RemoteProtocolError(msg) + self._h11_state.receive_data(data) else: return event