Subject: Design Issue: Max Concurrent Streams Limit and Unidirectional Streams

From: James M Snell <[email-masked]>
Date: Thu, 25 Apr 2013 10:50:44 -0700

https://github.com/http2/http2-spec/issues/78

In the current draft (-02), we state that:

A. Any endpoint can initiate and half-close a fully unidirectional
stream that does not require any action or acknowledgement from the
receiving peer. Once half-closed, these remain in a constant
half-closed state with the receiving peer having the option of sending
frames for that stream at any time for the full duration of the
session.

B. An endpoint MUST NOT exceed the maximum concurrent streams limit
set by it's peer and that streams initiated by the endpoint that are
half-closed in any direction count towards this limit.

C. Unless I missed it somewhere, clients are never required to
half-close PUSH_PROMISE streams.

The potential problem here is simple:

If a client sets a limit of 4 concurrent streams, and the server
initiates 4 separate PUSH_PROMISE streams that the server half-closes
but that are never half-closed by the client, the server will not be
able to initiate new push streams for the duration of the session.

---

From: Martin Thomson <[email-masked]>
Date: Thu, 25 Apr 2013 12:25:36 -0700

On 25 April 2013 10:50, James M Snell <[email-masked]> wrote:
>...

Yep, it's a problem.  We got rid of the unidirectional flag that
addressed this.  I can't speak for others, but I was aware of the
issue at the time, but I had a solution in mind.  That never got
written down, partly because we didn't have this discussion :)

On first blush, the only way to avoid the problem is to expect the
framing layer to be aware of what is going on above, but that's
probably not sensible.  But there's a better way:

Each stream has two separate state variables, each with three state
values: no packet yet, open, half-closed.  Streams that have inbound
== open || outbound == open are "in use" and count toward the stream
limit.  Documenting this might help clarify how the accounting is
done.

Importantly, this means that promised streams do not count toward the
limit.  It does however also imply that implementations will need to
be careful about how they allocate stream resources.  Pushes
complicate that a little because the lifecycle of headers doesn't
match stream lifecycles.  Again, I'd suggest an approach where
implementations defer commitment of flow control buffers until the
first flow-controlled frame arrives (memory pre-allocation might be
advisable for performance reasons, but that would not be an actual
commitment) and to ensure that any state for send and receive don't
have the same lifecycle.

---

From: James M Snell <[email-masked]>
Date: Thu, 25 Apr 2013 12:33:35 -0700

Perhaps a simpler approach would be to just redefine the limit such
that an endpoint MUST NOT have more than MAX_CONCURRENT_STREAMS in the
Open state at any given time. We have already established that once
the stream is half-closed, new frames cannot be sent, so once the
server half-closes a steam it initiates, the counter is decremented
and the server is permitted to initiate another stream. The client can
choose to reject those additional streams if it chooses.

---

From: Martin Thomson <[email-masked]>
Date: Thu, 25 Apr 2013 16:11:31 -0700

> choose to reject those additional streams if it chooses.

Do you mean that only outward bound streams count toward the
concurrency limit.  That could be workable; it's certainly easier to
explain.

---

From: James M Snell <[email-masked]>
Date: Thu, 25 Apr 2013 16:13:51 -0700

Yes, Outward bound only.

---

From: Martin Thomson <[email-masked]>
Date: Thu, 25 Apr 2013 16:18:32 -0700

> Yes, Outward bound only.

This has the biggest impact on servers and intermediaries.  How do
they feel about having clients initiating more requests while the
server is sending responses.

Thinking on this more, it does add an interesting pipelining-like
problem.  If all I'm doing is sending GET requests, then I can
probably open up thousands of streams, but the server can only respond
to a limited subset of those requests, holding requests (or responses)
in waiting until the response logjam frees up.  I think that this is
an undesirable property of the solution.  (MAX_CONCURRENT_STREAMS
could then look very much like HTTP/1.1 with pipelining.)

---

From: James M Snell <[email-masked]>
Date: Thu, 25 Apr 2013 16:45:04 -0700

Yes, it does become a bit tricky here. Not quite sure exactly what the
solution ought to be. One possible approach would be for the
intermediary to use flow-control mechanisms to effectively rate limit
the clients requests. For instance, if the intermediary allows the
client to open 10 concurrent streams, and the client opens and
half-closes those streams at too high of a rate without giving the
server time to properly respond, the intermediary can hold new streams
for a period of time or reject the new streams until the server
catches up.

Alternatively, a secondary MAX_OPEN_STREAMS parameter can be used. The
sender would be limited to initiating no more than
MAX_CONCURRENT_STREAMS open outbound streams at any given time and
would be allowed to initiate new streams after half-closing; however,
all open and half-open streams would count against the separate
MAX_OPEN_STREAMS limit. If that limit has not been hit, the newly
initiated streams are accepted, otherwise they are either held or
rejected until the half-open streams are closed. The assumption is
that MAX_OPEN_STREAMS >= MAX_CONCURRENT_STREAMS.

Yes, with low MAX_OPEN_STREAMS values we still run the risk of
starving out pushed streams, so the idea would be to use
MAX_OPEN_STREAMS intelligently (and possibly allow the value to change
dynamically through the life of a session) so that we avoid the issue.

These, of course, aren't the only possibilities :-)

- James

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Fri, 26 Apr 2013 06:51:19 +0000

In message <[email-masked]>
, James M Snell writes:

>For instance, if the intermediary allows the

It worries me to no end, that nobody here has even mentioned "DoS" with
a single word.

Denial-Of-Service mitigation has to be built into HTTP/2.0 from the
bottom up.

The default rule should be that any frame which fails any validation
should cause instant and silent session termination.

And we might as well write that into the standard, because that's what
any high-performance implementation will be forced to implement anyway.

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
[email-masked]         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe    
Never attribute to malice what can adequately be explained by incompetence.

---

From: RUELLAN Herve <[email-masked]>
Date: Fri, 26 Apr 2013 10:30:49 +0000

I've got the feeling that we should limit in some way the number of promised streams: too many promised streams could hurt an intermediary.

One way to do this is to say that a PUSH_PROMISE creates a new stream. In this way it is counted against the SETTINGS_MAX_CONCURRENT_STREAMS. We would also have to mandate a client to half-close all PUSH_PROMISE streams.

While reading the current spec, my understanding on whether a PUSH_PROMISE created a new stream wandered back and forth, and I think some clarification could be useful.

In particular the first paragraph of 3.4.1:
"There is no coordination or shared action between the client and server required to create a stream. Rather, new streams are established by sending a frame that references a previously unused stream identifier."

The "Promised-Stream-ID" of the PUSH_PROMISE frame could be considered as being the reference to an unused stream identifier, therefore creating the stream.

The rest of 3.4.1 and 3.8.5 on the contrary say that a PUSH_PROMISE frame doesn't create a new stream.

I would propose the following edit to this first paragraph of 3.4.1:
"There is no coordination or shared action between the client and server required to create a stream. Rather, new streams are established by sending a frame that references in its "Stream Identifier" field a previously unused stream identifier."

Hervé.

> -----Original Message-----
> From: Martin Thomson [mailto:[email-masked]]
> Sent: jeudi 25 avril 2013 21:26
> To: James M Snell
> Cc: [email-masked]
> Subject: Re: Design Issue: Max Concurrent Streams Limit and Unidirectional
> Streams
> 
> Yep, it's a problem.  We got rid of the unidirectional flag that addressed this.  I
> can't speak for others, but I was aware of the issue at the time, but I had a
> solution in mind.  That never got written down, partly because we didn't
> have this discussion :)
> 
> On first blush, the only way to avoid the problem is to expect the framing
> layer to be aware of what is going on above, but that's probably not sensible.
> But there's a better way:
> 
> values: no packet yet, open, half-closed.  Streams that have inbound ==
> open || outbound == open are "in use" and count toward the stream limit.
> Documenting this might help clarify how the accounting is done.
> 
> limit.  It does however also imply that implementations will need to be
> careful about how they allocate stream resources.  Pushes complicate that a
> little because the lifecycle of headers doesn't match stream lifecycles.  Again,
> I'd suggest an approach where implementations defer commitment of flow
> control buffers until the first flow-controlled frame arrives (memory pre-
> allocation might be advisable for performance reasons, but that would not be
> an actual
> commitment) and to ensure that any state for send and receive don't have
> the same lifecycle.

---

From: James M Snell <[email-masked]>
Date: Fri, 26 Apr 2013 09:02:51 -0700

> I've got the feeling that we should limit in some way the number of promised streams: too many promised streams could hurt an intermediary.

The more I think it over (sleeping on the problem helped) the more I
think that the idea of redefining SETTINGS_MAX_CONCURRENT_STREAMS and
adding a separate SETTINGS_OPEN_STREAMS_CREDIT makes the most sense
here. It effectives gives us two distinct and flexible control points.

SETTINGS_MAX_CONCURRENT_STREAMS would set an upper limit on the number
of outbound open streams an endpoint can have at any given time.
SETTINGS_OPEN_STREAMS_CREDIT provides an upper limit on the total
number of open streams (or half-open in any direction) an endpoint can
initiate. Rather than being a hard limit, however, the recipient, if
it wishes, can allow the sender to overdraw on its credit. If the
recipient is concerned that the sender is misbehaving, flow control
mechanism can be used by the recipient to tell the sender to slow down
or stop, or it can simply choose to reject all new streams.

Example 1: Client to Sender

Client opens the connection, Server tells the client that they have a
MAX_CONCURRENT_STREAMS of 10, OPEN_STREAMS_CREDIT of 20. This means
that the browser cannot initiate more than 10 open streams at a time.
If it creates 10, then half-closes 5, it can open another five
streams. It's OPEN_STREAMS_CREDIT counter would then be at 15 until
the server half-closes items on it's end. Let's say the client
half-closes five more streams and opens another five. It's still
within it's MAX_CONCURRENT_STREAMS limit, but if the server has not
half-closed any of those streams, the client will have reached it's
OPEN_STREAMS_CREDIT limit. The recipient now has a choice: A) it can
choose to allow the client to continue opening streams, B) it can
choose to use flow-control to tell the client to chill out and slow
down, C) it can hold off on responding to newly initiated stream until
the server has had a chance to half close, or D) it can reject the new
streams with an error. If the client continues to overdraw on it's
open streams credit limit, the recipient can choose to take more
drastic action such as terminating the session.

Example 2: Sender to Client

Client opens the connection and opens a stream to the server. The
client tells the server that it has a MAX_CONCURRENT_STREAMS of 10,
and an OPEN_STREAMS_CREDIT of 20. The server sends 10 PUSH_PROMISES to
the client. These count towards the MAX_CONCURRENT_STREAMS limit and
the OPEN_STREAMS_CREDIT. Once the server half-closes a pushed stream,
it can send another PUSH_PROMISE, but unless the recipient
half-closes, it still counts against their open streams credit limit.
Once that limit is reached, the recipient has the same choices as
above.

Yes, there is a denial of service risk here, but it's no worse than
what we currently have.

- James

---

From: William Chan (陈智昌) <[email-masked]>
Date: Mon, 29 Apr 2013 14:40:38 -0300

I read this entire thread and don't really see the problem we want to
solve. Can someone clarify? Let me reviewe the paint points as I understand
them:
* Stream data buffers are expensive - flow control solves this
* Stream headers are potentially expensive - MAX_CONCURRENT_STREAMS
mitigates this, although I'm not entirely convinced this is a complete
solution, especially when you can keep adding HEADERS for a stream without
bound (headers are problematic since you have to process them due to the
shared compression context).
* Stream ids are cheap. They're ids and don't require much context.
Historically PUSH_PROMISEs were cheap, but now that they can carry header
blocks, we've regressed on that. I forget why we added the header blocks
into the PUSH_PROMISE, can someone remind me (better yet, link to the
appropriate email thread)?

As far as the potential problem above, the root problem is that when you
have limits you can have hangs. We see this all the time today with
browsers (it's only reason people do domain sharding so they can bypass
limits). I'm not sure I see the value of introducing the new proposed
limits. They don't solve the hangs, and I don't think the granularity
addresses any of the costs in a finer grained manner. I'd like to hear
clarification on what costs the new proposed limits will address.

---

From: Martin Thomson <[email-masked]>
Date: Mon, 29 Apr 2013 11:20:41 -0700

On 29 April 2013 10:40, William Chan (陈智昌) <[email-masked]> wrote:
> I read this entire thread and don't really see the problem we want to solve.
> Can someone clarify? Let me reviewe the paint points as I understand them:

s/solves/mitigates/  - they aren't free

> shared compression context).

MAX_CONCURRENT_STREAMS also helps with the buffer size problem.

> appropriate email thread)?

You have to signal what you intend to push to give the client a chance
to reject it.  That's all.  So the only things that have to be in the
promise are resource identification things (:scheme, :host, :path),
and maybe (maybe) things that help identify cache (content-type, vary,
cache-control)

> have limits you can have hangs. We see this all the time today with browsers
> (it's only reason people do domain sharding so they can bypass limits). I'm
> not sure I see the value of introducing the new proposed limits. They don't
> solve the hangs, and I don't think the granularity addresses any of the
> costs in a finer grained manner. I'd like to hear clarification on what
> costs the new proposed limits will address.

I don't believe that the proposal improves the situation enough (or at
all) to justify the additional complexity.  That's something that you
need to assess for yourself.  This proposal provides more granular
control, but it doesn't address the core problem, which is that you
and I can only observe each other actions after some delay, which
means that we can't coordinate those actions perfectly.  Nor can be
build a perfect model of the other upon which to observe and act upon.
 The usual protocol issue.

---

From: William Chan (陈智昌) <[email-masked]>
Date: Mon, 29 Apr 2013 15:36:49 -0300

On Mon, Apr 29, 2013 at 3:20 PM, Martin Thomson <[email-masked]>wrote:

> solve.

Fair enough.

> MAX_CONCURRENT_STREAMS also helps with the buffer size problem.

To a certain degree, yes, but the real thing that controls the bounds is
the session window or not calling read().

> and maybe (maybe) things that help identify cache (content-type, vary,

Oops, forgot about that. See, the issue with that is now we've made
PUSH_PROMISE as potentially expensive as a HEADERS frame, since it does
more than just simple stream id allocation. I guess it's not really a huge
issue, since if it's used correctly (in the matter you described), then it
shouldn't be too expensive. If clients attempt to abuse it, then servers
should probably treat it in a similar manner as they treat people trying to
abuse header compression in all other frames with the header block, and
kill the connection accordingly.

> browsers

OK then. My proposal is to add a new limit for PUSH_PROMISE frames though,
separately from the MAX_CONCURRENT_STREAMS limit, since PUSH_PROMISE exists
as a promise to create a stream, explicitly so we don't have to count it
toward the existing MAX_CONCURRENT_STREAMS limit (I searched the spec and
this seems to be inadequately specced). Roberto and I discussed that before
and may have written an email somewhere in spdy-dev@, but I don't think
we've ever raised it here.

---

From: James M Snell <[email-masked]>
Date: Mon, 29 Apr 2013 11:46:35 -0700

On Apr 29, 2013 11:36 AM, "William Chan (陈智昌)" <[email-masked]>
wrote:
[snip]

Not just "potentially" as expensive..   As soon as we get a push promise we
need to allocate state and hold onto it for an indefinite period of time.
We do not yet know exactly when that compression context can be let go
because it has not yet been bound to stream state.  Do push streams all
share the same compression state? Do those share the same compression state
as the originating stream? The answers might be obvious but they haven't
yet been written down.

browsers
> OK then. My proposal is to add a new limit for PUSH_PROMISE frames
though, separately from the MAX_CONCURRENT_STREAMS limit, since
PUSH_PROMISE exists as a promise to create a stream, explicitly so we don't
have to count it toward the existing MAX_CONCURRENT_STREAMS limit (I
searched the spec and this seems to be inadequately specced). Roberto and I
discussed that before and may have written an email somewhere in spdy-dev@,
but I don't think we've ever raised it here.

Well,  there is an issue tracking it in the github repo now, at least.  As
currently defined in the spec,  it definitely needs to be addressed.

---

From: William Chan (陈智昌) <[email-masked]>
Date: Mon, 29 Apr 2013 16:33:53 -0300

On Mon, Apr 29, 2013 at 3:46 PM, James M Snell <[email-masked]> wrote:

> Not just "potentially" as expensive..   As soon as we get a push promise
> we need to allocate state and hold onto it for an indefinite period of
> time. We do not yet know exactly when that compression context can be let
> go because it has not yet been bound to stream state.  Do push streams all

I guess I don't see per-stream state as being that expensive. Compression
contexts are a fixed state on a per-connection basis, meaning that
additional streams don't add to that state. The main cost, as I see it, is
the decompressed headers. I said potentially since that basically only
means the URL (unless there are other headers important for caching due to
Vary), and additional headers can come in the HEADERS frame. Also,
PUSH_PROMISE doesn't require allocating other state, like backend/DB
connections, if you only want to be able to handle
(#MAX_CONCURRENT_STREAMs) of those backend connections in parallel.

If they're not specified, then we should specify it, but I've always
understood the header compression contexts to be directional and apply to
all frames sending headers in a direction. Therefore there should be two
compression contexts in a connection, one for header blocks being sent and
one for header blocks being received. If this is controversial, let's fork
a thread and discuss it.

> currently defined in the spec,  it definitely needs to be addressed.
Great. You guys are way better than I am about tracking all known issues. I
just have it mapped fuzzily in my head :)

---

From: James M Snell <[email-masked]>
Date: Mon, 29 Apr 2013 13:58:52 -0700

On Apr 29, 2013 12:33 PM, "William Chan (陈智昌)" <[email-masked]>
wrote:
[snip]

I think we all have been working off that basic assumption but, again, it
hasn't been written down. I'll gladly take that to do...  Doing so would
help us to evaluate the proposals on the table so far...  In a separate
thread tho.

Regarding the original issue for this thread,  MAX_CONCURRENT_STREAMS as
currently defined, is simply not workable with pushed streams because of
the half closed issue.  There are several ways to address the problem,  we
just need to identify and pick one. I don't particularly care which one we
choose :-)

- James

browsers
>> >
>>
>> Well,  there is an issue tracking it in the github repo now, at least.
As currently defined in the spec,  it definitely needs to be addressed.
>
> Great. You guys are way better than I am about tracking all known issues.
I just have it mapped fuzzily in my head :)

---

From: James M Snell <[email-masked]>
Date: Mon, 29 Apr 2013 14:08:35 -0700

It does not attempt to solve the core problem completely.  If anything it
just pushes it down the road a bit.  As currently defined,  servers will
top out quickly on the number of streams they can push.  With the revised
scheme I proposed, we would give the recipient more control over the
decision making process. A server will run up to the limits just as fast,
but the recipient could allow the server to keep right on going if it
wishes. In other words,  less coordination required between the endpoints.

On Apr 29, 2013 11:20 AM, "Martin Thomson" <[email-masked]> wrote:
[snip]

---

From: William Chan (陈智昌) <[email-masked]>
Date: Mon, 29 Apr 2013 18:12:11 -0300

Why will the server top out? We set our browser advertised
MAX_CONCURRENT_STREAMS limit to 1000:
https://code.google.com/p/chromium/codesearch#chromium/src/net/spdy/spdy_session.h&sq=package:chromium&rcl=1367246521&l=49.
What receiver of push streams is going to have a low limit? Or are you
worried that it'll want to push more than 1000 streams in a roundtrip?

---

From: Roberto Peon <[email-masked]>
Date: Mon, 29 Apr 2013 14:15:29 -0700

I had thought to provide no explicit limit for PUSH_PROMISE, just as there
is no limit to the size of a webpage, or the number of links upon it.
The memory requirements for PUSH are similar or the same (push should
consume a single additional bit of overhead per url, when one considers
that the URL should be parsed, enqueued, etc.).
If the browser isn't done efficiently, or, the server is for some unknown
reason being stupid and attempting to DoS the browser with many resources
that it will never use, then the client sends RST_STREAM for the ones it
doesn't want, and makes a request on its own. all tidy.

As for PUSH'd streams, the easiest solution is likely to assume that the
stream starts out in a half-closed state.
-=R

---

From: James M Snell <[email-masked]>
Date: Mon, 29 Apr 2013 14:17:36 -0700

+1 on this.  I like this approach.
On Apr 29, 2013 2:15 PM, "Roberto Peon" <[email-masked]> wrote:

> On Mon, Apr 29, 2013 at 12:33 PM, William Chan (陈智昌) <
> [email-masked]> wrote:
>

---

From: James M Snell <[email-masked]>
Date: Mon, 29 Apr 2013 14:30:23 -0700

Oh,  and fwiw, I'm basing this on how things are captured in the spec, not
necessarily how it's actually implemented anywhere.  It may not be a
problem in in running code,  but as written there could be issues.  The
fact that push stream open is tied to originating stream state,  for
instance, is not nearly as obvious in the text as it could be.  The fact
that closing the origin stream causes pushed streams to full close,
thereby decrementing the concurrent stream counter,  is not obvious in the
current text. Perhaps it's just an editorial issue masquerading as a design
issue, but my gut is telling me that placing hard limits on push is going
to be problematic.  I'm liking Roberto's approach more the more I think
about it.

---

From: William Chan (陈智昌) <[email-masked]>
Date: Mon, 29 Apr 2013 18:32:28 -0300

On Mon, Apr 29, 2013 at 6:17 PM, James M Snell <[email-masked]> wrote:

>> I had thought to provide no explicit limit for PUSH_PROMISE, just as
>> there is no limit to the size of a webpage, or the number of links upon it.
I don't feel too strongly here. I do feel like this is more of an edge
case, possibly important for forward proxies (or reverse proxies speaking
to backends over a multiplexed channel like HTTP/2). It doesn't really
matter for my browser, so unless servers chime in and say they'd prefer a
limit, I'm fine with this.

>> stream starts out in a half-closed state.
I looked into our earlier email threads and indeed this is what we agreed
on (http://lists.w3.org/Archives/Public/ietf-http-wg/2013JanMar/1106.html).
I voiced some mild objection since if you view the HTTP/2 framing layer as
a transport for another application protocol, then bidirectional server
initiated streams might be nice. But in absence of any such protocol, this
is a nice simplification.

>>> On Mon, Apr 29, 2013 at 3:46 PM, James M Snell <[email-masked]>wrote:
>>>
>>>>
>>>> Not just "potentially" as expensive..   As soon as we get a push
>>>> promise we need to allocate state and hold onto it for an indefinite period
>>>> of time. We do not yet know exactly when that compression context can be
>>>> let go because it has not yet been bound to stream state.  Do push streams
>>>> all share the same compression state? Do those share the same compression
>>>> state as the originating stream? The answers might be obvious but they
>>>> haven't yet been written down.
>>>>
>>>
>>> I guess I don't see per-stream state as being that expensive.
>>> Compression contexts are a fixed state on a per-connection basis, meaning
>>> that additional streams don't add to that state. The main cost, as I see
>>> it, is the decompressed headers. I said potentially since that basically
>>> only means the URL (unless there are other headers important for caching
>>> due to Vary), and additional headers can come in the HEADERS frame. Also,
>>> Great. You guys are way better than I am about tracking all known
>>> issues. I just have it mapped fuzzily in my head :)
>>>
>>
>>

---

From: Roberto Peon <[email-masked]>
Date: Mon, 29 Apr 2013 14:39:39 -0700

At worst, we burn a flag which states it is half-closed or unidirectional,
or provide some other information which identifies the IANA port number for
the overlayed protocol or something.
Anyway, *shrug*.
-=R

On Mon, Apr 29, 2013 at 2:32 PM, William Chan (陈智昌)
<[email-masked]>wrote:

>>> If the browser isn't done efficiently, or, the server is for some
>>> unknown reason being stupid and attempting to DoS the browser with many
>>> resources that it will never use, then the client sends RST_STREAM for the
>>> ones it doesn't want, and makes a request on its own. all tidy.
>>>
>>
>>>>> Well,  there is an issue tracking it in the github repo now, at
>>>>> least.  As currently defined in the spec,  it definitely needs to be
>>>>> addressed.
>>>>>

---

From: William Chan (陈智昌) <[email-masked]>
Date: Mon, 29 Apr 2013 18:44:21 -0300

Remember we originally *had* a flag for UNIDIRECTIONAL, which we removed
because it was redundant in the traditional HTTP use cases.

On Mon, Apr 29, 2013 at 6:39 PM, Roberto Peon <[email-masked]> wrote:

> On Mon, Apr 29, 2013 at 2:32 PM, William Chan (陈智昌) <[email-masked]
> > wrote:
>
>>>> As for PUSH'd streams, the easiest solution is likely to assume that
>>>> the stream starts out in a half-closed state.
>>>>
>>>
>>  I looked into our earlier email threads and indeed this is what we
>> agreed on (
>> http://lists.w3.org/Archives/Public/ietf-http-wg/2013JanMar/1106.html).

---

From: Roberto Peon <[email-masked]>
Date: Mon, 29 Apr 2013 14:56:30 -0700

I do remember :)
Honestly I like the IANA port or NPN string thing or something similar,
because it gives us other information that we'd otherwise have to parse out
of the HEADERS thing, but, it is the lowest complexity alternative.
-=R

On Mon, Apr 29, 2013 at 2:44 PM, William Chan (陈智昌)
<[email-masked]>wrote:

>> At worst, we burn a flag which states it is half-closed or
>> unidirectional, or provide some other information which identifies the IANA
>> port number for the overlayed protocol or something.
>>  Anyway, *shrug*.
>> -=R
>>
>>
>> On Mon, Apr 29, 2013 at 2:32 PM, William Chan (陈智昌) <
>>> On Mon, Apr 29, 2013 at 6:17 PM, James M Snell <[email-masked]>wrote:
>>>
>>>>>>> On Apr 29, 2013 11:36 AM, "William Chan (陈智昌)" <
>>>>>>> > Oops, forgot about that. See, the issue with that is now we've
>>>>>>> made PUSH_PROMISE as potentially expensive as a HEADERS frame, since it
>>>>>>> does more than just simple stream id allocation. I guess it's not really a
>>>>>>> huge issue, since if it's used correctly (in the matter you described),
>>>>>>> then it shouldn't be too expensive. If clients attempt to abuse it, then
>>>>>>> servers should probably treat it in a similar manner as they treat people
>>>>>>> trying to abuse header compression in all other frames with the header
>>>>>>> block, and kill the connection accordingly.
>>>>>>> >
>>>>>>>

---

From: William Chan (陈智昌) <[email-masked]>
Date: Mon, 29 Apr 2013 18:58:58 -0300

OK :) Well, we can discuss that alternative if we want to revisit the
earlier decision, but I'm happy to move forward with what we already agreed
upon earlier.

On Mon, Apr 29, 2013 at 6:56 PM, Roberto Peon <[email-masked]> wrote:

> On Mon, Apr 29, 2013 at 2:44 PM, William Chan (陈智昌) <[email-masked]
> > wrote:
>
>>>>>>>> > OK then. My proposal is to add a new limit for PUSH_PROMISE
>>>>>>>> frames though, separately from the MAX_CONCURRENT_STREAMS limit, since

---

From: Roberto Peon <[email-masked]>
Date: Mon, 29 Apr 2013 14:59:27 -0700

Yup.
-=R

On Mon, Apr 29, 2013 at 2:58 PM, William Chan (陈智昌)
<[email-masked]>wrote:

>> On Mon, Apr 29, 2013 at 2:44 PM, William Chan (陈智昌) <
>>>>>>> The memory requirements for PUSH are similar or the same (push
>>>>>>> should consume a single additional bit of overhead per url, when one
>>>>>>> considers that the URL should be parsed, enqueued, etc.).
>>>>>>>> If they're not specified, then we should specify it, but I've
>>>>>>>> always understood the header compression contexts to be directional and
>>>>>>>> apply to all frames sending headers in a direction. Therefore there should
>>>>>>>> be two compression contexts in a connection, one for header blocks being
>>>>>>>> sent and one for header blocks being received. If this is controversial,
>>>>>>>> let's fork a thread and discuss it.
>>>>>>>>
>>>>>>>>
>>>>>>>>>  >>
>>>>>>>>> >>

---

From: Martin Thomson <[email-masked]>
Date: Mon, 29 Apr 2013 15:49:49 -0700

On 29 April 2013 14:15, Roberto Peon <[email-masked]> wrote:
> consume a single additional bit of overhead per url, when one considers that
> the URL should be parsed, enqueued, etc.).

I think that this is where I was going with my thinking.

> stream starts out in a half-closed state.

That works for

I think that conceptually a third state makes the most sense, but that
would be roughly equivalent to half-closed.