Skip to content

fix: ignore the reserved bit of an incoming HTTP/2 stream identifier - #1261

Open
pjfanning wants to merge 1 commit into
apache:mainfrom
pjfanning:mask-http2-reserved-stream-id-bit
Open

fix: ignore the reserved bit of an incoming HTTP/2 stream identifier#1261
pjfanning wants to merge 1 commit into
apache:mainfrom
pjfanning:mask-http2-reserved-stream-id-bit

Conversation

@pjfanning

Copy link
Copy Markdown
Member

Motivation

Http2FrameParsing read the stream identifier with a plain readIntBE(), keeping the reserved high bit, and carried a TODO saying the bit should be checked:

val streamId = reader.readIntBE()
// TODO: assert that reserved bit is 0 by checking if streamId > 0

RFC 9113 §5.1.1 says the bit is reserved and MUST be ignored when receiving. Keeping it means a peer that sets it produces a negative stream id, which never matches the stream the frame is really for: streamFor treats it as closed and the connection is failed with a GOAWAY instead of the frame being handled on its stream.

Modification

Mask the reserved bit off (& 0x7FFFFFFF) when reading the identifier, and replace the TODO with the rule it was standing in for.

Result

A frame whose stream identifier carries the reserved bit is handled on the stream it names, as the spec requires, rather than failing the connection.

Tests

  • sbt "http2-tests/testOnly org.apache.pekko.http.impl.engine.http2.Http2ServerSpec org.apache.pekko.http.impl.engine.http2.Http2ClientSpec org.apache.pekko.http.impl.engine.http2.framing.Http2FramingSpec" — pass (189 tests). A new test sends HEADERS for stream 1 with the reserved bit set and expects the request to be dispatched. Verified it fails with the fix stashed (the connection is failed instead).
  • sbt http-core/mimaReportBinaryIssues — pass (internal impl.engine.http2 change, no public API).
  • Native scalafmt on the changed files — clean.

References

None - ignores the reserved stream identifier bit per RFC 9113 §5.1.1

🤖 Generated with Claude Code

Motivation:
`Http2FrameParsing` read the stream identifier with a plain
`readIntBE()`, keeping the reserved high bit, and carried a TODO saying
the bit should be checked. RFC 9113 5.1.1 says the bit is reserved and
MUST be ignored when receiving. Keeping it means a peer that sets it
produces a negative stream id, which never matches the stream the frame
is really for: `streamFor` treats it as closed and the connection is
failed with a GOAWAY instead of the frame being handled on its stream.

Modification:
Mask the reserved bit off (`& 0x7FFFFFFF`) when reading the identifier
and replace the TODO with the rule it was standing in for.

Result:
A frame whose stream identifier carries the reserved bit is handled on
the stream it names, as the spec requires, rather than failing the
connection.

Tests:
- sbt "http2-tests/testOnly org.apache.pekko.http.impl.engine.http2.Http2ServerSpec org.apache.pekko.http.impl.engine.http2.Http2ClientSpec org.apache.pekko.http.impl.engine.http2.framing.Http2FramingSpec" - pass (189 tests); a new test sends HEADERS for stream 1 with the reserved bit set and expects the request to be dispatched. Verified it fails with the fix stashed (the connection is failed instead).
- sbt http-core/mimaReportBinaryIssues - pass (internal impl.engine.http2 change, no public API).

References:
None - ignores the reserved stream identifier bit per RFC 9113 5.1.1
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