speculative fix for #5158

This commit is contained in:
Maximilian Hils 2022-02-27 07:58:20 +01:00
parent 5cdd2bc6ec
commit 65773cc9c0
2 changed files with 12 additions and 7 deletions

View File

@ -28,6 +28,7 @@
Processing will only resume once the event hook has finished. (@Prinzhorn) Processing will only resume once the event hook has finished. (@Prinzhorn)
* Allow addon hooks to be async (@nneonneo, #4207) * Allow addon hooks to be async (@nneonneo, #4207)
* Reintroduce `Flow.live`, which signals if a flow belongs to a currently active connection. (@mhils, #4207) * Reintroduce `Flow.live`, which signals if a flow belongs to a currently active connection. (@mhils, #4207)
* Speculative fix for some rare HTTP/2 connection stalls (#5158, @EndUser509)
## 28 September 2021: mitmproxy 7.0.4 ## 28 September 2021: mitmproxy 7.0.4

View File

@ -88,6 +88,9 @@ class ConnectionHandler(metaclass=abc.ABCMeta):
self.layer = layer.NextLayer(context, ask_on_start=True) self.layer = layer.NextLayer(context, ask_on_start=True)
self.timeout_watchdog = TimeoutWatchdog(self.on_timeout) self.timeout_watchdog = TimeoutWatchdog(self.on_timeout)
# workaround for https://bugs.python.org/issue40124 / https://bugs.python.org/issue29930
self._drain_lock = asyncio.Lock()
async def handle_client(self) -> None: async def handle_client(self) -> None:
watch = asyncio_utils.create_task( watch = asyncio_utils.create_task(
self.timeout_watchdog.watch(), self.timeout_watchdog.watch(),
@ -253,13 +256,14 @@ class ConnectionHandler(metaclass=abc.ABCMeta):
Drain all writers to create some backpressure. We won't continue reading until there's space available in our Drain all writers to create some backpressure. We won't continue reading until there's space available in our
write buffers, so if we cannot write fast enough our own read buffers run full and the TCP recv stream is throttled. write buffers, so if we cannot write fast enough our own read buffers run full and the TCP recv stream is throttled.
""" """
for transport in self.transports.values(): async with self._drain_lock:
if transport.writer is not None: for transport in self.transports.values():
try: if transport.writer is not None:
await transport.writer.drain() try:
except OSError as e: await transport.writer.drain()
if transport.handler is not None: except OSError as e:
asyncio_utils.cancel_task(transport.handler, f"Error sending data: {e}") if transport.handler is not None:
asyncio_utils.cancel_task(transport.handler, f"Error sending data: {e}")
async def on_timeout(self) -> None: async def on_timeout(self) -> None:
self.log(f"Closing connection due to inactivity: {self.client}") self.log(f"Closing connection due to inactivity: {self.client}")