Any way to obtain HTTP2StreamID?

one of our server applications has a problem where users will experience intermittent disconnections due to ungraceful closure of HTTP/2 connections. after some investigation, i determined that the cause of the problem was that we were sending a constant value of Int32.max for the GOAWAY frame, when we should have been following that up with a second GOAWAY frame containing an ID associated with one of the streams actually initiated by a client.

GOAWAY frames don’t seem to be represented at all in the “modern” async APIs, which i found surprising because having not implementing GOAWAY (or a more-crude drop-on-rotate equivalent, like what we are currently using) is a plain and simple security vulnerability.

interestingly, the legacy API did have a way of representing StreamID, but for some reason these code paths have been progressively carved out of the modern APIs, and as far as i can tell, the HTTP2StreamMultiplexer (which had GOAWAY awareness) is no longer being added to the HTTP/2 pipeline at all.

i am at a loss for how to correctly implement GOAWAY using the latest version of SwiftNIO. and i find it hard to believe that i am the first person to encounter this limitation, as it is a pretty basic requirement of using server-side swift in a security-sensitive context.

GOAWAY frames are represented in the async API, they are delivered on the connection channel.

You can use the following channel option on stream channels to retrieve the stream ID: swift-nio-http2/Sources/NIOHTTP2/HTTP2StreamChannel.swift at 0904bf0feb5122b7e5c3f15db7df0eabe623dd87 · apple/swift-nio-http2 · GitHub

Alternatively you can surface the relevant information from a channel handler in the connection channel as described in another post.

The stream IDs have been purposefully removed from the stream channel init and data path. See Lift requirement to create streams in order · Issue #214 · apple/swift-nio-http2 · GitHub for more info.

2 Likes

thanks, that looks like what i needed. i did not think to query options on the any Channel instance, as i saw that HTTP2StreamChannel was internal and did not know that you could query options from non-public channels.

as a followup, is it safe to access syncOptions from a http2StreamInitializer? it worked when i tried it. but the documentation for configureAsyncHTTPServerPipeline(http2Configuration:http1ConnectionInitializer:http2ConnectionInitializer:http2StreamInitializer:) never explains what event loop the closures run on.

Yes, the child channels run on the same event loop as the parent channel, and the initializer will always be called on the EL that the channel belongs to.

1 Like