Subject: Stream State and PRIORITY Frames

From: Scott Mitchell <[email-masked]>
Date: Mon, 16 Jan 2017 22:32:16 -0800

(originally posted here: https://github.com/http2/http2-spec/issues/759)

What is the expected result in terms of stream state and any potential
errors that should be generated from the following scenario:

```
1. Client [PRIORITY, id: 5] -> Server
2. Client [HEADERS, id: 3] -> Server
```

## Option 1
The server accepts both frames. Stream `3` is OPEN and stream `5` remains
in IDLE.

This behavior is verified in the h2spec verification tool via
https://github.com/summerwind/h2spec/pull/67. Also see additional
discussion there.

## Option 2
Should the use of stream ID `5` cause stream ID `3` (and all lower stream
IDs) to be implicitly closed according to the section-5.1.1 (see [1])? This
would mean after the server receives the frame from step (1) it thinks that
stream ID `3` has been closed, and when the server receives the frame from
step (2) it will respond with a connection error of type PROTOCOL_ERROR
(see [2])?

[1] https://tools.ietf.org/html/rfc7540#section-5.1.1
> 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.

[2] https://tools.ietf.org/html/rfc7540#section-5.1.1
> An endpoint that
   receives an unexpected stream identifier MUST respond with a
   connection error (Section 5.4.1) of type PROTOCOL_ERROR.

---

From: Benedikt Christoph Wolters <[email-masked]>
Date: Tue, 17 Jan 2017 09:38:44 +0100

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.

2017-01-17 7:32 GMT+01:00 Scott Mitchell <[email-masked]>:
> The server accepts both frames. Stream `3` is OPEN and stream `5` remains in
> IDLE.
>
> https://github.com/summerwind/h2spec/pull/67. Also see additional discussion
> there.
>
> ## Option 2
> step (2) it will respond with a connection error of type PROTOCOL_ERROR (see
> [2])?
>

---

From: Tatsuhiro Tsujikawa <[email-masked]>
Date: Tue, 17 Jan 2017 21:37:40 +0900

Hi,

> step (2) it will respond with a connection error of type PROTOCOL_ERROR
​
​I think Option 1 is the expected result.

>    peer with a lower-valued stream identifier.
​If my understanding is correct, this only refers to the new stream ID used
by HEADERS, and PUSH_PROMISE frames which open or reserve streams.  The
example text following that statement uses HEADERS which opens new stream.
PRIORITY frame does not change stream state, and there is no reason to
close all unused streams lower than bearing stream ID.  That said, I agree
that this is not crystal clear in the document.  In practice, this is
probably rather rare case.

Best regards,
Tatsuhiro Tsujikawa

---

From: Cory Benfield <[email-masked]>
Date: Tue, 17 Jan 2017 12:42:58 +0000

> On 17 Jan 2017, at 08:38, Benedikt Christoph Wolters <[email-masked]> wrote:
> 

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

---

From: Scott Mitchell <[email-masked]>
Date: Tue, 17 Jan 2017 10:16:16 -0800

Thanks for responses everyone. There seems to be recognition that the
specification lacks clarity but there also seems to be momentum behind
"Option 1".

This leads to the practical concern of bounding the amount of memory
committed to streams in this state. SETTINGS_MAX_CONCURRENT_STREAMS limits
number of streams in "open" or "half-closed", but the specification doesn't
(to my knowledge) define a way to limit the number of "reserved" streams or
"idle"/"closed" streams which have had only PRIORITY frames exchanged. The
specification allows for implementations to discard PRIORITY more or less
at their discretion [3], but limiting "reserved" streams is another issue. "
SETTINGS_ENABLE_PUSH" is limited to 0 or 1 [4] so there is no way for a
client to advertise how many "reserved" streams it is willing to accept.
What are the practical approaches folks have taken to address these issues?

[3] https://tools.ietf.org/html/rfc7540#section-5.3.4
> The retention of priority information for streams that are not counted
toward the limit set by SETTINGS_MAX_CONCURRENT_STREAMS could create a
large state burden for an endpoint. Therefore, the amount of prioritization
state that is retained MAY be limited.
[4] https://tools.ietf.org/html/rfc7540#section-6.5.2

> The initial value is 1, which indicates that server push is permitted.  Any value other than 0 or 1 MUST be treated as a connection error (Section 5.4.1 <https://tools.ietf.org/html/rfc7540#section-5.4.1>) of type PROTOCOL_ERROR.

On Tue, Jan 17, 2017 at 4:42 AM, Cory Benfield <[email-masked]> wrote:

> In fact, I think it’s the same issue. Scott linked to 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, which links
> to https://github.com/mitmproxy/mitmproxy/issues/1824, which is related
> to 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.
>
> - 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
>

---

From: Cory Benfield <[email-masked]>
Date: Tue, 17 Jan 2017 18:25:49 +0000

> On 17 Jan 2017, at 18:16, Scott Mitchell <[email-masked]> wrote:
> 
> Thanks for responses everyone. There seems to be recognition that the specification lacks clarity but there also seems to be momentum behind "Option 1".
> 
> This leads to the practical concern of bounding the amount of memory committed to streams in this state. SETTINGS_MAX_CONCURRENT_STREAMS limits number of streams in "open" or "half-closed", but the specification doesn't (to my knowledge) define a way to limit the number of "reserved" streams or "idle"/"closed" streams which have had only PRIORITY frames exchanged. The specification allows for implementations to discard PRIORITY more or less at their discretion [3], but limiting "reserved" streams is another issue. "SETTINGS_ENABLE_PUSH" is limited to 0 or 1 [4] so there is no way for a client to advertise how many "reserved" streams it is willing to accept. What are the practical approaches folks have taken to address these issues?
> 
> [3] https://tools.ietf.org/html/rfc7540#section-5.3.4 <https://tools.ietf.org/html/rfc7540#section-5.3.4>
> > The retention of priority information for streams that are not counted toward the limit set by SETTINGS_MAX_CONCURRENT_STREAMS could create a large state burden for an endpoint. Therefore, the amount of prioritization state that is retained MAY be limited.
> [4] https://tools.ietf.org/html/rfc7540#section-6.5.2 <https://tools.ietf.org/html/rfc7540#section-6.5.2>

SETTINGS_MAX_CONCURRENT_STREAMS is used to limit the number of pushed streams.

The key thing to understand is that there are *two* values of SETTINGS_MAX_CONCURRENT_STREAMS on each connection: one set by the client and one set by the server. The one set by the server limits the number of client-initiated streams there may be (that is, streams initiated by HEADERS frames). The one set by the client limits the number of server-initiated streams there may be (that is, streams initiated by PUSH_PROMISE frames).

This is laid out explicitly in RFC 7540 Section 8.2.2:

> A client can use the SETTINGS_MAX_CONCURRENT_STREAMS setting to limit
> the number of responses that can be concurrently pushed by a server.
> Advertising a SETTINGS_MAX_CONCURRENT_STREAMS value of zero disables
> server push by preventing the server from creating the necessary
> streams.  This does not prohibit a server from sending PUSH_PROMISE
> frames; clients need to reset any promised streams that are not
> wanted.

Cory

---

From: Scott Mitchell <[email-masked]>
Date: Tue, 17 Jan 2017 10:35:42 -0800

On Tue, Jan 17, 2017 at 10:25 AM, Cory Benfield <[email-masked]> wrote:

> large state burden for an endpoint. Therefore, the amount of
> prioritization state that is retained MAY be limited.
> The key thing to understand is that there are *two* values of
> SETTINGS_MAX_CONCURRENT_STREAMS on each connection: one set by the client
> and one set by the server. The one set by the server limits the number of
> client-initiated streams there may be (that is, streams initiated by
> HEADERS frames). The one set by the client limits the number of
> server-initiated streams there may be (that is, streams initiated by
> PUSH_PROMISE frames).
>

Ahh yes I forgot about this. Thanks for reminding me.

Any thoughts on limiting the stream priority?

---

From: Matthew Kerwin <[email-masked]>
Date: Wed, 18 Jan 2017 05:26:53 +1000

> Any thoughts on limiting the stream priority?

​It's a hint. If you run out of resources to maintain it, discard it?

Cheers
-- 
  Matthew Kerwin
  http://matthew.kerwin.net.au/

---

From: Scott Mitchell <[email-masked]>
Date: Tue, 17 Jan 2017 12:13:03 -0800

On Tue, Jan 17, 2017 at 10:35 AM, Scott Mitchell <[email-masked]>
wrote:

>> SETTINGS_MAX_CONCURRENT_STREAMS on each connection: one set by the
>> client and one set by the server. The one set by the server limits the
>> number of client-initiated streams there may be (that is, streams initiated
>> by HEADERS frames). The one set by the client limits the number of
I recall where my confusion stems from. Section 5.1.2 contradicts the
statements in Section 8.2.2 you referenced. Section 5.1.2 explicitly states
that "reserved" streams do not count toward SETTINGS_MAX_CONCURRENT_STREAM
S [5].

[5] https://tools.ietf.org/html/rfc7540#section-5.1.2
> Streams that are in the "open" state or in either of the "half-closed"
states count toward the maximum number of streams that an endpoint is
permitted to open. Streams in any of these three states count toward the
limit advertised in the SETTINGS_MAX_CONCURRENT_STREAMS setting. Streams in
either of the "reserved" states do not count toward the stream limit.

---

From: Scott Mitchell <[email-masked]>
Date: Tue, 17 Jan 2017 12:16:24 -0800

> ​It's a hint. If you run out of resources to maintain it, discard it?

Of course. I was curious if anyone can share successful policies/heuristics
they have employed to limit the number of streams in this state, but still
try to honor a client's desire to prioritize streams. For example a policy
like "discard lowest stream ID" may be limiting if the client initially
creates the most important QoS streams upfront, but then at a later time
exceeds the peer's implementation defined limit on priority streams.

---

From: Martin Thomson <[email-masked]>
Date: Wed, 18 Jan 2017 11:27:24 +1300

On 18 January 2017 at 01:37, Tatsuhiro Tsujikawa <[email-masked]> wrote:
> If my understanding is correct, this only refers to the new stream ID used
> PRIORITY frame does not change stream state, and there is no reason to close
> all unused streams lower than bearing stream ID.  That said, I agree that
> this is not crystal clear in the document.  In practice, this is probably
> rather rare case.

This is, I think, the expectation.

I think that we probably want to clarify the point by explicitly
saying that PRIORITY doesn't affect stream states.  We say that it can
be sent in any state, but we don't also mention that important point.
Do people here agree that an erratum on this point is appropriate
here?

---

From: Scott Mitchell <[email-masked]>
Date: Tue, 17 Jan 2017 14:43:34 -0800

>From my perspective I would like to see two clarifications:

1. It is clear to me that PRIORITY doesn't impact state. However Section
5.1.1 states "first use of a new stream identifier" which makes no
reference to stream state. If stream state is important/implied here better
to be specific about it. I don't think the one-off example below this text
is sufficient to convey the intended implications of this statement.

2. Section 5.1.2 states "Streams in either of the 'reserved' states do not
count toward the stream limit." which seems to conflict with section 8.2.2 "A
client can use the SETTINGS_MAX_CONCURRENT_STREAMS setting to limit the
number of responses that can be concurrently pushed by a server.". These
two statements appear to contradict each other. Since
SETTINGS_MAX_CONCURRENT_STREAMS
is really the only mechanism to limit resources due to server push I'm
assuming section 5.1.2 is overly restrictive.

On Tue, Jan 17, 2017 at 2:27 PM, Martin Thomson <[email-masked]>
wrote:

> close

---

From: Daurnimator <[email-masked]>
Date: Wed, 18 Jan 2017 11:34:17 +1100

> Do people here agree that an erratum on this point is appropriate

Yes. I recently ran into this issue myself
https://github.com/daurnimator/lua-http/issues/63

---

From: Tom Bergan <[email-masked]>
Date: Tue, 17 Jan 2017 22:10:36 -0800

On Tue, Jan 17, 2017 at 2:43 PM, Scott Mitchell <[email-masked]>
wrote:

> 2. Section 5.1.2 states "Streams in either of the 'reserved' states do
> not count toward the stream limit." which seems to conflict with section
> 8.2.2 "A client can use the SETTINGS_MAX_CONCURRENT_STREAMS setting to
> limit the number of responses that can be concurrently pushed by a server.".
> These two statements appear to contradict each other. Since
> SETTINGS_MAX_CONCURRENT_STREAMS is really the only mechanism to limit
> resources due to server push I'm assuming section 5.1.2 is overly
> restrictive.
>

This is surprising (to me, at least) but I don't believe there is a
contradiction. You can send an infinite number of PUSH_PROMISEs without
hitting SETTINGS_MAX_CONCURRENT_STREAMS. A pushed stream doesn't count
against the concurrent stream limit until you've sent the response HEADERS
on that pushed stream. See the related question I asked previously:
https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0599.html

---

From: Cory Benfield <[email-masked]>
Date: Wed, 18 Jan 2017 09:06:20 +0000

> On 17 Jan 2017, at 22:27, Martin Thomson <[email-masked]> wrote:
> 

Yeah. The community has managed to coalesce around the “right” answer, I think, but it would help to have it stated more explicitly in the specification.

Cory

---

From: Scott Mitchell <[email-masked]>
Date: Wed, 18 Jan 2017 08:38:54 -0800

> applied. This is not what most people expect.
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

If these streams are not CLOSED, then what is the purpose for this special
exception? They are not allowed to transition state at a later point in
time because of 5.1.1:

> newly established stream MUST be numerically greater

"Option 1" requires special exception for stream ID allocation to
accommodate "PRIORITY streams remaining in IDLE" and I don't see the
benefit. The specification already allows (and even suggests) retaining
priority state for CLOSED streams in section 5.3.4:

> If it has retained enough state to do so, an endpoint receiving a PRIORITY
frame that changes the priority of a closed stream SHOULD alter the
dependencies of the streams that depend on it.

So in terms of priority just because a stream is CLOSED doesn't necessarily
mean any priority information is lost. Even if the streams remain in IDLE
implementations will have to impose some limit on how much memory is can be
consumed by these "PRIORITY streams in IDLE" so it just seems like
additional complexity to make this exception.

---

From: Scott Mitchell <[email-masked]>
Date: Wed, 18 Jan 2017 09:15:24 -0800

On Tue, Jan 17, 2017 at 10:10 PM, Tom Bergan <[email-masked]> wrote:

>> limit the number of responses that can be concurrently pushed by a
>> server.". These two statements appear to contradict each other. Since
> on that pushed stream.

If you don't include RESERVED streams in the count for
SETTINGS_MAX_CONCURRENT_STREAMS
then how do you limit the amount of RESERVED streams, and how does your
peer know about this limit? I have imposed an implementation specific
metric in the past, but this seems less preferable than relying on
something in the RFC that the peer is aware of. Either way having infinite
of something doesn't work in practice.

Because of the asymmetry of stream creation in h2 it makes more sense to me
to clarify how streams should be counted toward
SETTINGS_MAX_CONCURRENT_STREAMS.
For example:
Creating a stream in the "reserved" state will consume resources on the
client and therefore SHOULD be counted against SETTINGS_MAX_CONCURRENT_STREAMS
advertised by the client. The server MUST be prepared to accept a
RST_STREAM frame from the client in response to PUSH_PROMISE frame (if this
limit is exceeded or at any time).

> See the related question I asked previously:

Interesting.

https://lists.w3.org/Archives/Public/ietf-http-wg/2016JulSep/0601.html
> If you limit server push by applying a stream limit, then you prevent it
from being used in time for the client to use it.

I understand the rational/motivation but practically speaking there will
have to be some limit imposed on PUSHed streams. The client can send a
RST_STREAM in response to a PUSH_PROMISE at any time. So I'm not sure why
having the server pretend like a limit doesn't exist improves the
situation. Pretending a limit doesn't exist may result in additional
network traffic that is avoidable.

---

From: Cory Benfield <[email-masked]>
Date: Wed, 18 Jan 2017 19:50:43 +0000

> On 18 Jan 2017, at 16:38, Scott Mitchell <[email-masked]> 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.

Cory

---

From: Scott Mitchell <[email-masked]>
Date: Wed, 18 Jan 2017 16:53:43 -0800

On Wed, Jan 18, 2017 at 11:50 AM, Cory Benfield <[email-masked]> 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
> 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). 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 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).

Cory

---

From: Scott Mitchell <[email-masked]>
Date: Wed, 18 Jan 2017 17:21:13 -0800

On Tue, Jan 17, 2017 at 2:43 PM, Scott Mitchell <[email-masked]>
wrote:

> 1. It is clear to me that PRIORITY doesn't impact state.
>

Just to clarify ... it is clear that a PRIORITY frame doesn't impact the
state of the stream  it is carrying priority information for. The impacts
PRIORITY frames have on other streams is not clear due to the wording in
section 5.1.1.

> However Section 5.1.1 states "first use of a new stream identifier" which
> makes no reference to stream state. If stream state is important/implied
> here better to be specific about it. I don't think the one-off example
> below this text is sufficient to convey the intended implications of this
> statement.
>

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 19 Jan 2017 11:57:13 +0900

2017-01-19 9:53 GMT+09:00 Scott Mitchell <[email-masked]>:
> 3. Client PRIORITY [StreamId=7,StreamDependency=0, Weight=1,Exclusive=False]
> -> Server
> 4. Client PRIORITY [StreamId=9,StreamDependency=7, Weight=1,Exclusive=False]
> -> Server
> There were other frames (SETTINGS, DATA, PING, WINDOW_UPDATE, GO_AWAY) which
> were omitted for the purposes of this discussion.
>
> step (6).

I had the same discussion with Cory, and now I agree with him that we
should _not_ interpret the specification that way.

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).

> 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 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).
>
>
>> Cory
>>
>

-- 
Kazuho Oku

---

From: Amos Jeffries <[email-masked]>
Date: Thu, 19 Jan 2017 22:00:25 +1300

> 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.

>> 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

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

---

From: Cory Benfield <[email-masked]>
Date: Thu, 19 Jan 2017 14:11:31 +0000

> On 19 Jan 2017, at 09:00, Amos Jeffries <[email-masked]> wrote:
> 

No it doesn’t.

Firstly, let’s note that the PRIORITY frame is defined not to change stream state. Receiving a PRIORITY frame on stream N leaves it in the idle state. A server implementation can thus treat the receipt of a PRIORITY frame on any stream that has a higher ID than the last stream on which it received a HEADERS frame as having the *exact* same effect on state retention as receiving a PING frame. It doesn’t *require* the insertion of any stream state data.

Specific implementations may require the insertion of stream state data if priority information is stored on the same structure as stream state information, but that is certainly not required. For example, receiving a bunch of PRIORITY frames does not cause the Python HTTP/2 implementation to allocate any more state information than receiving a bunch of PING frames.

> HEADERS with stream ID == 2^31 to waste server sockets.

This problem is orthogonal to the one we’re discussing.

So far I haven’t seen a proposal to say that PRIORITY frames should transition a stream out of the idle state. If we continue to leave RFC 7540 saying that PRIORITY frames leave streams in the idle state, then definitionally they are excluded from the restrictions on MAX_CONCURRENT_STREAMS. So if you are allocating stream state for idle streams, then you are open to this DoS vector, but none of the proposals here are trying to address it.

Additionally, I should note that the unbounded insertion of priority information into priority trees was discussed as an attack vector in this paper: https://www.imperva.com/docs/Imperva_HII_HTTP2.pdf. The paper was published in August of last year, and several implementations took steps to reduce their vulnerability to it (the Python priority implementation even filed a CVE, CVE-2016-6580).

I absolutely support adding an erratum to indicate that implementations should resist unbounded insertion of PRIORITY information. But unless you’re willing to say that idle streams should be counted against MAX_CONCURRENT_STREAMS (which is a tricky thing to state), then the only way to resolve this problem at the spec level is to force PRIORITY frames to make state transitions, further complicating the state diagram for streams.

It means exactly what RFC 7540 says it means. Quoting from Section 5.3.4 of RFC 7540:

> Similarly, streams that are in the "idle" state can be assigned priority or become a parent of other streams. This allows for the creation of a grouping node in the dependency tree, which enables more flexible expressions of priority. Idle streams begin with a default priority (Section 5.3.5).

> The retention of priority information for streams that are not counted toward the limit set by SETTINGS_MAX_CONCURRENT_STREAMS could create a large state burden for an endpoint. Therefore, the amou…

To this end, the Python priority implementation allows a user-configured maximum amount of data retention for priority information. This priority information is held separately from stream state information because they are entirely orthogonal concerns: in fact, the bits of code that manage priority information and those that manage stream state information are in entirely separate installable packages with no dependency relationship to each other.

To my eye, there is a clear intent to allow setting of priority information on streams that are in the idle state, without that affecting the stream itself.

Cory

---

From: Patrick McManus <[email-masked]>
Date: Thu, 19 Jan 2017 10:51:11 -0500

On Tue, Jan 17, 2017 at 7:37 AM, Tatsuhiro Tsujikawa <[email-masked]>
wrote:

> ​If my understanding is correct, this only refers to the new stream ID
> used by HEADERS, and PUSH_PROMISE frames which open or reserve streams.
> The example text following that statement uses HEADERS which opens new
> stream.  PRIORITY frame does not change stream state, and there is no
> reason to close all unused streams lower than bearing stream ID.  That
> said, I agree that this is not crystal clear in the document.  In practice,
> this is probably rather rare case.
>
>
> I believe that is correct.

---

From: Patrick McManus <[email-masked]>
Date: Thu, 19 Jan 2017 10:51:51 -0500

On Tue, Jan 17, 2017 at 7:42 AM, Cory Benfield <[email-masked]> wrote:

> In fact, I think it’s the same issue. Scott linked to
> 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, which links to https://github.com/mitmprox
> y/mitmproxy/issues/1824, which is related to
> https://github.com/mitmproxy/mitmproxy/issues/1498 because both cases
Hey Cory, this is a bit of a back alley - but can you help me understand
the scenario here. Priority is not an end to end concept - the dependencies
are clearly connection based and only make sense relevant to each other. So
is hyper-h2 just forwarding client Priority frames directly? How would that
work? (I know its not your project.. you just seem to grok what's going
on..)

---

From: Patrick McManus <[email-masked]>
Date: Thu, 19 Jan 2017 10:54:14 -0500

ack

---

From: Patrick McManus <[email-masked]>
Date: Thu, 19 Jan 2017 10:55:05 -0500

> then started sending HEADERS from 1 onwards.

That was never true (unless there is a bug I'm unaware of). Grouping nodes
are formed for streams 3, 5, 7, 9, B and the first 'normal' stream is
formed via HEADERS on D with a dependency on one of those grouping nodes.
Stream 1 is never used.

---

From: Patrick McManus <[email-masked]>
Date: Thu, 19 Jan 2017 10:55:57 -0500

On Wed, Jan 18, 2017 at 7:53 PM, Scott Mitchell <[email-masked]>
wrote:

>
>
> Based on the RFC it seems like stream ids {3, 5, 7, 11} should be closed
> at step (6). 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
> sure these streams will only be used for PRIORITY.
>

Yes, they are grouping nodes and serve no other purpose. I personally
believe they are in the idle state, but I know some people believe they are
closed with a priority attached. That doesn't seem to matter in practice.

> 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).
>
>

So yes, and no. Certainly the server is in compliance in just ignoring
everything it knows about priority indications from the client. OTOH,
things can get very very screwed performance wise if dependencies are
disregarded and the state of priority is just determined by the local
weights on each stream. I've seen servers do this and create terrible
results.

---

From: Patrick McManus <[email-masked]>
Date: Thu, 19 Jan 2017 11:23:12 -0500

> the first thing(s) happening here at all?
sure - see below. First, I think we need to revisit the primary motivation
for dependencies at all in h2:

When any client needs to forward requests from two or more contexts it
needs to balance them according to some policy. maybe that's fairness (each
user gets 1/2) or maybe that's some kind of class of service (foreground
tab gets 90%, other ones get 10%).. you can try and weight the streams to
make that happen, but there are N streams for each 'user' and that number
varies quickly over time, which would mean constantly reprioritizing the
weights.

The problem is solved with dependencies and grouping nodes (i.e. idle
streams). Each use can get equal weight (or whatever your policy) in
aggregate no matter how many streams come and go as long as they are rooted
in the same group.

The client in this scenario might be a proxy, looking for fairness among
users, or it might be a user-agent looking for a fair policy for balancing
different tabs. It doesn't matter.

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

tl;dr; streams 3,5,7,9,b only ever have PRIORITY sent on them (and I
believe this leaves them idle). Subsequent 'normal' streams (of the HEADERS
ilk) are dependent on one of these 5 streams (generally directly, but
sometimes via a layer of indirection through another HEADERS based stream.)

These low numbered streams are 'grouping nodes' in the priority graph -
they have different weights and represent different classes of service
(things like background loads in the download manager are separated from
more low-latency things like css, etc..). As your session goes on over time
the HEADERS based streams close normally, but new navigations and uses root
themselves in the graph to those same low numbered grouping nodes - which
are meant to be persistent. They need not have full stream state (they are
after all still idle) - they are just a part of the dependency graph.. any
kind of LRU based eviction algorithm should easily keep them around in
practice.

I'm sure it will evolve over time.

It might be helpful if we had a mechanism where we could signal if one peer
made a PRIORITY assertion with a dependency that couldn't be resolved on
the other end because it evicted the relevant information.. that would let
the original peer reprioritize the stream.

---

From: Cory Benfield <[email-masked]>
Date: Thu, 19 Jan 2017 17:36:38 +0000

> On 19 Jan 2017, at 15:51, Patrick McManus <[email-masked]> wrote:
> 
> Hey Cory, this is a bit of a back alley - but can you help me understand the scenario here. Priority is not an end to end concept - the dependencies are clearly connection based and only make sense relevant to each other. So is hyper-h2 just forwarding client Priority frames directly? How would that work? (I know its not your project.. you just seem to grok what's going on..)

Definitely a side-alley: I suspect we may want to take this off-list.

The short version is that mitmproxy is an intercepting web proxy. This means it has slightly different goals than most intermediaries do: in particular, it wants to be able to understand the content of a HTTP connection without manipulating it. It doesn’t do connection coalescing, or caching, or any of the things that would require that it actually do anything with priorities: it just logs the data and presents it in a handy-dandy debuggable form. Incidentally, it also does connection-replay and a whole host of other fun stuff.

As a result, it handles the bytestream of a HTTP/2 connection a bit weirdly. Specifically, as far as I understand it, when it receives a HTTP/2 connection it sets up a data pipe between the client and server, essentially forwarding their data onto each other. But, in addition to that, it runs a pair of HTTP/2 stacks as basically a B2BUA: it treats itself as the server for the client and it treats itself as the client for the server. This is mostly a correctness concern, helping it make semantic sense of the HTTP/2 connection. However, the HTTP/2 stack it uses (mine) tries to be fastidious about correctness, so I tend to get tagged in on bug reports when connections go awry. That included this one.

Does that clarify, or did I just make it all murkier?

Cory

---

From: Scott Mitchell <[email-masked]>
Date: Thu, 19 Jan 2017 14:47:14 -0800

> > Omitting PRIORITY from the MAX_STREAMS voids that benefit.

Agreed. There is no mechanism defined in the specification to communicate a
limit for the state retained due to prioritization/dependency information.
This is currently limited to implementation specific heuristics.

> Firstly, let’s note that the PRIORITY frame is defined not to change
> stream state. Receiving a PRIORITY frame on stream N leaves it in the idle
> state.

A server implementation can thus treat the receipt of a PRIORITY frame on
> any stream that has a higher ID than the last stream on which it received a
> HEADERS frame as having the *exact* same effect on state retention as
> receiving a PING frame. It doesn’t *require* the insertion of any stream
> state data.
>
> Specific implementations may require the insertion of stream state data if
> priority information is stored on the same structure as stream state
> information, but that is certainly not required. For example, receiving a
> bunch of PRIORITY frames does not cause the Python HTTP/2 implementation to
> allocate any more state information than receiving a bunch of PING frames.
>
> So far I haven’t seen a proposal to say that PRIORITY frames should
> transition a stream out of the idle state. If we continue to leave RFC 7540
> saying that PRIORITY frames leave streams in the idle state, then
> definitionally they are excluded from the restrictions on
> MAX_CONCURRENT_STREAMS. So if you are allocating stream state for idle
> streams, then you are open to this DoS vector, but none of the proposals
> here are trying to address it.
>
> Additionally, I should note that the unbounded insertion of priority
> information into priority trees was discussed as an attack vector in this
> paper: https://www.imperva.com/docs/Imperva_HII_HTTP2.pdf. The paper was
> published in August of last year, and several implementations took steps to
> reduce their vulnerability to it (the Python priority implementation even
> filed a CVE, CVE-2016-6580).
>
> I absolutely support adding an erratum to indicate that implementations
> should resist unbounded insertion of PRIORITY information. But unless
> you’re willing to say that idle streams should be counted against
> MAX_CONCURRENT_STREAMS (which is a tricky thing to state), then the only
> way to resolve this problem at the spec level is to force PRIORITY frames
> to make state transitions, further complicating the state diagram for
> streams.
>
> > Similarly, streams that are in the "idle" state can be assigned priority
> or become a parent of other streams. This allows for the creation of a
> grouping node in the dependency tree, which enables more flexible
> expressions of priority. Idle streams begin with a default priority
> (Section 5.3.5).
>
> To this end, the Python priority implementation allows a user-configured
> maximum amount of data retention for priority information. This priority
> information is held separately from stream state information because they
> are entirely orthogonal concerns: in fact, the bits of code that manage
> priority information and those that manage stream state information are in
> entirely separate installable packages with no dependency relationship to
> each other.
>
> To my eye, there is a clear intent to allow setting of priority
> information on streams that are in the idle state, without that affecting
> the stream itself.
>
> Cory
>
>
>
>
>
>
>
>

---

From: Scott Mitchell <[email-masked]>
Date: Thu, 19 Jan 2017 14:58:53 -0800

> closed with a priority attached. That doesn't seem to matter in practice.

The state transition I mentioned above is triggered by a HEADERS frame. So
far I have not heard any dispute over this. It seem to be clearly defined
in section 5.1.1 (see below). Do you have a different interpretation of
this section?

https://tools.ietf.org/html/rfc7540#section-5.1.1

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.  For example, if a client sends a
HEADERS frame on stream 7 without ever sending a frame on stream 5,
then stream 5 transitions to the "closed" state when the first frame
for stream 7 is sent or received.

> weights on each stream. I've seen servers do this and create terrible

I'm not suggesting that servers should ignore priority, and I agree this
can be detrimental to page load times and general performance. My point was
meant to clarify the actual behavior of FF since it was used as an example
of "transitioning the stream state would be unexpected". The way FF
currently behaves these streams should be closed because a HEADERS frame is
used anyways.

---

From: laike9m <[email-masked]>
Date: Fri, 20 Jan 2017 21:17:02 +0800

If you don’t include RESERVED streams in the count for
SETTINGS_MAX_CONCURRENT_STREAMS then how do you limit the amount of
RESERVED streams, and how does your peer know about this limit? I have
imposed an implementation specific metric in the past, but this seems less
preferable than relying on something in the RFC that the peer is aware of.
Either way having infinite of something doesn’t work in practice.

As Martin has explained, H2 doesn’t limit the amount of RESERVED streams,
based on the notion that HEADERS are close to free. It’s true that one
trying to send infinite number of PUSH_PROMISEs to client can cause
problems, but 1. This only happens if the server is malicious, and if it’s
malicious, having a limit in the RFC won’t prevent anything, and 2. Not
counting PUSH_PROMISEs is a tradeoff for fast delivery of PUSH_PROMISEs,
which stops client from sending more requests. I guess this is what Martin
meant by “If you limit server push by applying a stream limit, then you
prevent it from being used in time for the client to use it.”

（Forgot to reply to all :P）

On Thu, Jan 19, 2017 at 9:21 AM, Scott Mitchell <[email-masked]>
wrote:

>> However Section 5.1.1 states "first use of a new stream identifier"
>> which makes no reference to stream state. If stream state is
>> important/implied here better to be specific about it. I don't think the
>> one-off example below this text is sufficient to convey the intended
>> implications of this statement.
>>
>> On Tue, Jan 17, 2017 at 2:27 PM, Martin Thomson <[email-masked]
>> > wrote:
>>

---

From: Scott Mitchell <[email-masked]>
Date: Fri, 20 Jan 2017 09:01:10 -0800

On Fri, Jan 20, 2017 at 5:17 AM, laike9m <[email-masked]> wrote:

> based on the notion that HEADERS are close to free.
>

"HEADERS are free" sounds like an over simplification which becomes more
apparent as the concurrency of streams and connections grows. There are
other provisions in the RFC to limit the amount of state consumed by
HEADERS (SETTINGS_HEADER_TABLE_SIZE, SETTINGS_MAX_HEADER_LIST_SIZE).

In addition to headers this may require additional state to be allocated
for stream management. The specification also has mechanisms to limit state
consumed by streams.

It’s true that one trying to send infinite number of PUSH_PROMISEs to
> client can cause problems, but 1. This only happens if the server is
> malicious, and if it’s malicious,having a limit in the RFC won’t prevent
> anything, and 2. Not counting PUSH_PROMISEs is a tradeoff for fast delivery
> of PUSH_PROMISEs, which stops client from sending more requests. I guess
> this is what Martin meant by “If you limit server push by applying a stream
> limit, then you prevent it from being used in time for the client to use
> it.”
>

Malicious actors is a concern and must be dealt with. However there may be
proxy-like systems with large amounts of concurrency or other memory
constraint systems that already control their resources but the peer's only
mechanism to know about these limits is to try-then-fail. Assuming clients
impose some limit to their state (infinite state isn't practical) then the
problem of "the client won't accept this push" exists if the server knows
about it before hand or not. Knowing about it before hand gives the server
the ability to potentially prioritize which resources it wants to push or
make other more informed decisions.

>> On Tue, Jan 17, 2017 at 2:43 PM, Scott Mitchell <[email-masked]
>> > wrote:
>>
>>> On Tue, Jan 17, 2017 at 2:27 PM, Martin Thomson <
>>> [email-masked]> wrote:
>>>

---

From: Tom Bergan <[email-masked]>
Date: Fri, 20 Jan 2017 10:28:59 -0800

IIUC, PUSH_PROMISEs don't count against the stream limit due to a
(hypothetical) scenario like the following: A server currently has 199
streams open on a connection, with limit of 200 per connection, and the
client makes another request. Now the server has 200 streams open. The
server wants to push a resource. Since the PUSH_PROMISE does not count
against the stream limit, the server is allowed to send a PUSH_PROMISE,
which notifies the client that the resource will be pushed (the client does
not need to request it).

I submit that this is a nearly-pointless optimization. Broadly speaking,
there are two reasons a server might want to push a resource:

1. The server speculates that the client will need that resource shortly.
If the pushed resource is not more important than basically all of the 200
streams currently in flight, there is little reason to push that resource.
This is a speculative push, meaning the goal is to reduce latency, but we
can't reduce latency if the push will be queued behind 200 other streams
anyway -- we might as well wait for the client to make the request.

2. The server is participating in a notification protocol where the push
used to notify the client of some event. In this case, the PUSH_PROMISE
does not need to be sent immediately because the server is not speculating
about a future client request. It would be fine to queue the PUSH_PROMISE
in the server until one of the 200 concurrent streams is closed.

Therefore, I propose the following convention: servers should count
PUSH_PROMISEs towards the concurrent stream limit. This doesn't
necessarily help clients, since a client cannot rely on every server to
implement this behavior, but overall it seems like a much simpler
situation. FWIW, this is what I have implemented in Go's HTTP/2 server:
https://github.com/golang/net/blob/77412025ac6f6821b4938edeb45af939de5cccec/http2/http2.go#L85

On Fri, Jan 20, 2017 at 9:01 AM, Scott Mitchell <[email-masked]>
wrote:

>> On Thu, Jan 19, 2017 at 9:21 AM, Scott Mitchell <[email-masked]
>> > wrote:
>>
>>>
>>>
>>> On Tue, Jan 17, 2017 at 2:43 PM, Scott Mitchell <
>>> [email-masked]> wrote:
>>>

---

From: Scott Mitchell <[email-masked]>
Date: Fri, 20 Jan 2017 11:54:50 -0800

> 39de5cccec/http2/http2.go#L85
To clarify my original intention (given the spec has already been released)
is to have the limit be "advisory". The goal would be to preserve existing
behavior but also allow the client to inform the server of its limitations.
The server would have the option to use that information, or ignore it for
reserved streams. An important factor here is the end result for
violating SETTINGS_MAX_CONCURRENT_STREAMS
and the client resetting a PUSH_PROMISE is the same (stream error aka
RST_STREAM).

Although SETTINGS_MAX_CONCURRENT_STREAMS seems like a natural choice for
this there is one potential challenge. Section 5.1.2 includes the
language "Endpoints
MUST NOT exceed the limit set by their peer". The end result of "sending
too many push promises" and "violating SETTINGS_MAX_CONCURRENT_STREAMS" may
be the same (a stream error), but counting pushed streams
against SETTINGS_MAX_CONCURRENT_STREAMS may violate this MUST NOT clause
for existing implementations which don't count pushed streams against
SETTINGS_MAX_CONCURRENT_STREAMS. To be consistent the MUST NOT would have
to be relaxed and clarified.

https://tools.ietf.org/html/rfc7540#section-5.1.2

Endpoints MUST NOT exceed the limit set by their peer.  An endpoint
that receives a HEADERS frame that causes its advertised concurrent
stream limit to be exceeded MUST treat this as a stream error (Section
5.4.2 <https://tools.ietf.org/html/rfc7540#section-5.4.2>) of type
PROTOCOL_ERROR or REFUSED_STREAM.  The choice of error code determines
whether the endpoint wishes to enable automatic retry (see Section
8.1.4 <https://tools.ietf.org/html/rfc7540#section-8.1.4>) for
details).

>>> As Martin has explained, H2 doesn’t limit the amount of RESERVED
>>> streams, based on the notion that HEADERS are close to free.
>>>
>>
>>> malicious, and if it’s malicious,having a limit in the RFC won’t
>>> prevent anything, and 2. Not counting PUSH_PROMISEs is a tradeoff for fast
>>> delivery of PUSH_PROMISEs, which stops client from sending more requests. I
>>> guess this is what Martin meant by “If you limit server push by applying a
>>> stream limit, then you prevent it from being used in time for the client to
>>> use it.”
>>>
>> Malicious actors is a concern and must be dealt with. However there may
>> be proxy-like systems with large amounts of concurrency or other memory
>>> On Thu, Jan 19, 2017 at 9:21 AM, Scott Mitchell <
>>>> Just to clarify ... it is clear that a PRIORITY frame doesn't impact
>>>> the state of the stream  it is carrying priority information for. The
>>>> impacts PRIORITY frames have on other streams is not clear due to the
>>>> wording in section 5.1.1.
>>>>
>>>>
>>>>> 2. Section 5.1.2 states "Streams in either of the 'reserved' states
>>>>> do not count toward the stream limit." which seems to conflict with section
>>>>> 8.2.2 "A client can use the SETTINGS_MAX_CONCURRENT_STREAMS setting
>>>>> to limit the number of responses that can be concurrently pushed by a