Re: Stream State and PRIORITY Frames

> On 17 Jan 2017, at 08:38, Benedikt Christoph Wolters <benedikt.wolters@rwth-aachen.de> wrote:
> 
> This question reminds me of a similiar issue we had a while ago at
> mitmproxy: https://github.com/mitmproxy/mitmproxy/issues/1498
> 
> As far as I understand this, sending PRIORITY does not initiate a
> stream or change the stream state.
> HEADERS and PUSH_PROMISE initiate a stream. PRIORITY can be sent and
> received in any stream state.

In fact, I think it’s the same issue. Scott linked to https://github.com/summerwind/h2spec/pull/67 <https://github.com/summerwind/h2spec/pull/67>, which is referenced from and opened by the same person who opened https://github.com/h2o/h2o/pull/1136 <https://github.com/h2o/h2o/pull/1136>, which links to https://github.com/mitmproxy/mitmproxy/issues/1824 <https://github.com/mitmproxy/mitmproxy/issues/1824>, which is related to https://github.com/mitmproxy/mitmproxy/issues/1498 <https://github.com/mitmproxy/mitmproxy/issues/1498> because both cases were sites deployed behind Fastly.

For those who want background and don’t want to follow all those links, mitmproxy bumped into problems with sites deployed behind Fastly. mitmproxy encountered these because it was forwarding on traffic from Firefox, which would on connection-setup send a whole bunch of PRIORITY frames. hyper-h2 (which powers mitmproxy’s HTTP/2 support) would allow this. h2o would not.

The crux of the discussion boils down to a few apparently contradictory sections in the specification. Scott linked to the first two:

Section 5.1.1:

- The first use of a new stream identifier implicitly closes all streams in the “idle” state that may have been initiated by that peer with a lower-valued stream identifier.
- An endpoint that receives an unexpected stream identifier must respond with a connection error of type PROTOCOL_ERROR.

*However*, there are a few other notes. The first thing to note is that the PRIORITY frame does not transition a stream out of the idle state. A stream that has only had PRIORITY frames sent on it is still in the IDLE state. That means that the Firefox-style priority setup (sending priority for stream IDs 1, 3, 5, and 7 immediate after the preamble) would have the effect of immediately closing streams 1, 3, and 5, if section 5.1.1 applied. This is not what most people expect.

More importantly, though, section 5.1.1 says this:

- The identifier of a newly established stream MUST be numerically greater than all streams that the initiating endpoint has opened or reserved. This governs streams that are opened using a HEADERS frame and streams that are reserved using PUSH_PROMISE.

This is not absolutely clear, but it seems to suggest that implementations may establish a stream with an ID lower than streams that have had PRIORITY frames sent on them. Put another way, it seems to suggest that only HEADERS and PUSH_PROMISE frames affect the lowest-acceptable stream ID. That seems to me to suggest that PRIORITY frames are not expected to force-close all streams with lower IDs that are in the idle state.

As an implementers note, I have found it much more helpful to think of PRIORITY frames not as frames that are sent on a stream, but as frames that are implicitly sent on stream zero and are just tagged with a stream ID. PRIORITY frames ignore basically all restrictions on stream behaviour: they can be sent on idle streams, on closed streams. In practice, they can basically be sent whenever, and except for the case where they establish a loop in the priority tree must basically always be accepted.

Cory

Received on Tuesday, 17 January 2017 12:43:35 UTC