Skip to content

feat: allow empty HTTP/2 DATA frames to be throttled - #1265

Open
pjfanning wants to merge 1 commit into
apache:mainfrom
pjfanning:throttle-http2-data-frames
Open

feat: allow empty HTTP/2 DATA frames to be throttled#1265
pjfanning wants to merge 1 commit into
apache:mainfrom
pjfanning:throttle-http2-data-frames

Conversation

@pjfanning

Copy link
Copy Markdown
Member

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, a buffer ++= empty, 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:

case "reset" => Some("RstStreamFrame")
...
case _       => None

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 real frameTypeName, which frameCost recognises and applies to empty DATA frames only:

case d: DataFrame if d.payload.isEmpty && frameTypesForThrottle.contains(EmptyDataFrameThrottleName) => 1

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 to None, which is the behaviour before this change.
  • sbt http-core/mimaReportBinaryIssues — pass.
  • Header on the new file generated with sbt headerCreateAll; native scalafmt clean.

References

Refs #332 - extends the frame type throttle to empty DATA frames

🤖 Generated with Claude Code

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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant