Re: Stream State and PRIORITY Frames

On 19/01/2017 3:57 p.m., Kazuho Oku wrote:
> 2017-01-19 9:53 GMT+09:00 Scott Mitchell <scott.k.mitch1@gmail.com>:
>>
>>
>> On Wed, Jan 18, 2017 at 11:50 AM, Cory Benfield <cory@lukasa.co.uk> wrote:
>>>
>>>
>>> On 18 Jan 2017, at 16:38, Scott Mitchell <scott.k.mitch1@gmail.com> wrote:
>>>
>>> This is interesting. If FF is using streams 1-7 then as soon as stream 9
>>> is used for a HEADERS request that will close streams 1-7 according to
>>> section 5.1.1:
>>>
>>>> first use of a new stream identifier implicitly closes all streams in
>>>> the "idle" state that might have been initiated by that peer with a
>>>> lower-valued stream identifier
>>>
>>>
>>> Only if they are not opened via HEADERS frames, which they are. FF sent (I
>>> haven’t checked recently) PRIORITY frames for the first few stream IDs, and
>>> then started sending HEADERS from 1 onwards.
>>>
>>>
>>
>>
>> I just ran FF 50.1.0 against a simple local server (TLS+ALPN) and here is
>> the behavior I observe:
>>
>> 1. Client PRIORITY [StreamId=3,StreamDependency=0,
>> Weight=201,Exclusive=False] -> Server
>> 2. Client PRIORITY [StreamId=5,StreamDependency=0,
>> Weight=101,Exclusive=False] -> Server
>> 3. Client PRIORITY [StreamId=7,StreamDependency=0, Weight=1,Exclusive=False]
>> -> Server
>> 4. Client PRIORITY [StreamId=9,StreamDependency=7, Weight=1,Exclusive=False]
>> -> Server
>> 5. Client PRIORITY [StreamId=11,StreamDependency=3,
>> Weight=1,Exclusive=False] -> Server
>> 6. Client HEADERS [StreamId=13,StreamDependency=11,
>> Weight=2,Exclusive=False] -> Server (a GET "/" request)
>> 7. Client HEADERS [StreamId=15,StreamDependency=0,
>> Weight=16,Exclusive=False] -> Server (a GET "/favicon.ico" request)
>>
>> There were other frames (SETTINGS, DATA, PING, WINDOW_UPDATE, GO_AWAY) which
>> were omitted for the purposes of this discussion.
>>
>> Based on the RFC it seems like stream ids {3, 5, 7, 11} should be closed at
>> step (6).
> 
> I had the same discussion with Cory, and now I agree with him that we
> should _not_ interpret the specification that way.
> 

IIRC the intention behind the closing behaviour for idle streams was to
ensure that we could optimize away the need to maintain a list or array
of 2^31 state entries.

Omitting PRIORITY from the MAX_STREAMS voids that benefit.


> As Cory points out on
> https://github.com/h2o/h2o/pull/1136#issuecomment-266213322, the
> normative definition is
> 
>    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.
> 
> Therefore, a PRIORITY frame does not implicitly close the streams with
> smaller IDs.
> 
> The following text that discusses when a stream gets implicitly closed
> is written immediately after the formal description show above, so it
> is fair to assume that the word _use_ in the sentence means when the
> stream is opened or reserved (and not when a PRIORITY frame is
> received).
> 
>    The first use of a new stream identifier implicitly closes all
>    streams in the "idle" state that might have been initiated by that
>    peer with a lower-valued stream identifier.
> 
> 
>> Note that FF is not doing anything wrong here. It shouldn't have
>> to care that the streams are CLOSED in this scenario (assuming these streams
>> only ever have PRIORITY frames exchanged).

It is causing state to be allocated on the server and on every
intermediary along the way which accepts it.

Consider the effects of 2^31 PRIORITY frames being sent with different
IDs before the first HEADERS is used.
 Notice how even this one case is markedly worse than sending just one
HEADERS with stream ID == 2^31 to waste server sockets.

Add some other factors:
 * repeated frames are extremely cheap for sender.
 * random order on the frames.
 * encoding data in the sequence of stream-ids.
 * variance in the frequency of delay between frames.

One suddenly finds there is a whole category (or three) of attacks
available unless PRIORITY on an idle stream is drop/ignored (at worst)
or GOAWAY (at best).


> It would be interesting to get a
>> FF dev to comment on the expected stream state here just to be sure these
>> streams will only be used for PRIORITY. Either way maintaining/interpreting
>> the priority is at the discretion of the server and these streams being
>> closed does not impact the server's ability to do this (as discussed
>> previously the RFC suggests retaining priority for closed streams).

see above. Any server which does accept is opening itself to a world of
problems with complex workarounds. Allocating state for them makes it
even worse.

What I'd like from Firefox is an explanation of why exactly PRIORITY is
the first thing(s) happening here at all?

What exactly does it mean for them to set PRIORITY on a non-existent stream?


Amos

Received on Thursday, 19 January 2017 09:01:27 UTC