feat: allow empty HTTP/2 DATA frames to be throttled - #1265
Open
pjfanning wants to merge 1 commit into
Open
Conversation
Motivation: A DATA frame carrying no payload has `sizeInWindow == 0`, so it consumes no flow-control window. The number of such frames is therefore not bounded by flow control at all, and on an open stream a peer can send them continuously, each one costing a pass through the stream state machine and a flow-control recompute. The `frame-type-throttle` mechanism could not be pointed at them: it maps an alias to a frame type name and had no alias for DATA, so DATA frames were unthrottleable by configuration. Adding a plain "data" alias would not have helped. Throttling every DATA frame at the configured rate throttles legitimate throughput with it, so nobody could enable it for this purpose. Only the empty frames need it, because the data-carrying ones are already bounded by flow control. Modification: Add an "empty-data" alias for the throttle that charges DATA frames whose payload is empty. It resolves to a name that is deliberately not a real frame type name, which `frameCost` recognises and applies to empty DATA frames only. Off by default, like every throttle target other than "reset". Result: An operator can throttle a flood of empty DATA frames without throttling data-carrying ones. Tests: - sbt "http-core/testOnly org.apache.pekko.http.impl.engine.http2.Http2BlueprintSpec" - pass (11 tests), with a new case for the alias. - sbt "http2-tests/testOnly org.apache.pekko.http.impl.engine.http2.Http2ServerEmptyDataThrottleSpec org.apache.pekko.http.impl.engine.http2.Http2ServerEnableFrameTypeThrottleSpec org.apache.pekko.http.impl.engine.http2.Http2ServerDisableFrameTypeThrottleSpec" - pass (3 tests); the new spec floods empty DATA frames with the throttle configured for them and requires the connection to be torn down. Verified it fails when the alias resolves to None, which is the behaviour before this change. - sbt http-core/mimaReportBinaryIssues - pass References: Refs apache#332 - extends the frame type throttle to empty DATA frames
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.
Motivation
A DATA frame carrying no payload has
sizeInWindow == 0, so it consumes no flow-control window. The number of such frames is therefore not bounded by flow control at all, and on an open stream a peer can send them continuously — each one costing a pass through the stream state machine, abuffer ++= empty, and a flow-control recompute.The
frame-type-throttlemechanism could not be pointed at them. It maps an alias to a frame type name:and had no alias for DATA, so DATA frames were unthrottleable by configuration.
Adding a plain
"data"alias would not have helped. Throttling every DATA frame at the configured rate throttles legitimate throughput along with it, so nobody could realistically enable it for this purpose — which is presumably why the config documents the throttle as being for "non-data frame types". Only the empty frames need it, because data-carrying ones are already bounded by flow control.Modification
Add an
"empty-data"alias that charges DATA frames whose payload is empty. It resolves to a name that is deliberately not a realframeTypeName, whichframeCostrecognises and applies to empty DATA frames only:Off by default, like every throttle target other than
"reset".Result
An operator can throttle a flood of empty DATA frames without throttling data-carrying ones.
Tests
sbt "http-core/testOnly org.apache.pekko.http.impl.engine.http2.Http2BlueprintSpec"— pass (11 tests), with a new case for the alias.sbt "http2-tests/testOnly ...Http2ServerEmptyDataThrottleSpec ...Http2ServerEnableFrameTypeThrottleSpec ...Http2ServerDisableFrameTypeThrottleSpec"— pass (3 tests). The new spec floods empty DATA frames with the throttle configured for them and requires the connection to be torn down. Verified it fails when the alias resolves toNone, which is the behaviour before this change.sbt http-core/mimaReportBinaryIssues— pass.sbt headerCreateAll; nativescalafmtclean.References
Refs #332 - extends the frame type throttle to empty DATA frames
🤖 Generated with Claude Code