Repository navigation
http1connection,websocket: Avoid event loop starvation from small chunks - #3773
Merged
bdarnell merged 3 commits intoOct 7, 2026
Merged
Conversation
Reads of body data that has already arrived complete without returning control to the IOLoop, so a client sending a chunked body made of many tiny chunks (which cost ~6us each to parse) could block the event loop for the entire body (minutes, with the default max_body_size). - Yield to the IOLoop periodically while reading any body (every 256KB, with each chunk of a chunked body counting as 1KB). - Coalesce consecutive small chunks before calling data_received. Pending data is flushed whenever we would wait for the network, so streaming latency is unaffected. - Accumulate non-streaming bodies in a bytearray instead of a list of bytes objects, which used ~120 bytes of memory per 1-byte chunk. - Raise HTTPInputError instead of using assert for a chunk that is not followed by CRLF. - Document the baseline for denial-of-service reports in SECURITY.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XKZM6XMVNYGibRyDU6QZW
Measures CPU per byte, event loop stalls, and memory for adversarial inputs (tiny chunks, pipelined requests, tiny websocket messages and fragments, ping floods) to serve as the baseline described in SECURITY.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XKZM6XMVNYGibRyDU6QZW
Reads of frames that have already arrived complete without returning control to the IOLoop, so a peer sending many small frames could block the event loop indefinitely. Yield every 256KB, with each frame counting as 1KB. A peer that sends pings without reading the pongs could make the server's write buffer (and the per-write Futures, ~500 bytes each) grow without limit. As permitted by RFC 6455 section 5.5.3, keep at most one pong outstanding and answer only the most recent ping received while it is pending. Pongs are also no longer sent after a close frame. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019XKZM6XMVNYGibRyDU6QZW
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Connections that send many tiny chunks of data in either
Transfer-Encoding: chunkedor websockets could monopolize the IOLoop for an uninterrupted time. With this PR, we yield after every 256KB so that other requests can be handled.Websockets are now limited to one outstanding "pong" response at a time to mitigate ping floods (this is suggested in the RFC).
Finally, small chunks in
Transfer-Encoding: chunkedmay be combined in batches before giving them to the application to reduce overhead.