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

James M Snell <> Sat, 04 May 2013 01:22 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 958E921F8F32 for <>; Fri, 3 May 2013 18:22:18 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -10.082
X-Spam-Status: No, score=-10.082 tagged_above=-999 required=5 tests=[AWL=0.517, BAYES_00=-2.599, RCVD_IN_DNSWL_HI=-8]
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id panzrbllIW8W for <>; Fri, 3 May 2013 18:22:13 -0700 (PDT)
Received: from ( []) by (Postfix) with ESMTP id 1071A21F8F02 for <>; Fri, 3 May 2013 18:22:12 -0700 (PDT)
Received: from lists by with local (Exim 4.72) (envelope-from <>) id 1UYR9P-0007xX-GO for; Sat, 04 May 2013 01:20:35 +0000
Resent-Date: Sat, 04 May 2013 01:20:35 +0000
Resent-Message-Id: <>
Received: from ([]) by with esmtp (Exim 4.72) (envelope-from <>) id 1UYR9F-0007we-59 for; Sat, 04 May 2013 01:20:25 +0000
Received: from ([]) by with esmtps (TLS1.0:RSA_ARCFOUR_SHA1:16) (Exim 4.72) (envelope-from <>) id 1UYR95-00029N-Mb for; Sat, 04 May 2013 01:20:19 +0000
Received: by with SMTP id xk17so1908556obc.31 for <>; Fri, 03 May 2013 18:19:49 -0700 (PDT)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20120113; h=x-received:mime-version:in-reply-to:references:from:date:message-id :subject:to:cc:content-type:content-transfer-encoding; bh=y/ZYEc/esTbGg1kvoAhsj3m6qBtjtrgT5N4aLEAqlIU=; b=XOdlbtq9y2sZiRqSECp5eATt9LnifjQchE4Lq+64Oag+NHwja3h5f/VP19jXVHDDT6 kvTm1uoF2JgycbFK1G2kcIDZC/Mc5BOepBkYcJg8y/QPuLlXU8ZX7Rbq9l0+qUgW76c1 VU7U8xdaInQgFJ0CYaUwA9SFXo+XcrFB0wRTTkMYY31KMNxRMY89BirO2ddlyXwg4S0l KzUm3lVpUnFHwKmU+NxN3qikbhfe62l56cyWZZlzCgmKPukXVg592rCvqc5DiQ/Twnip PqOpaYRe5towK9CVMsk6IVBkd3+LYziFBe1kQeunrE2/gv2oIwIaVFknBvOarlaRb7UM mWbA==
X-Received: by with SMTP id e5mr815645oed.46.1367630389555; Fri, 03 May 2013 18:19:49 -0700 (PDT)
MIME-Version: 1.0
Received: by with HTTP; Fri, 3 May 2013 18:19:28 -0700 (PDT)
In-Reply-To: <>
References: <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <> <>
From: James M Snell <>
Date: Fri, 03 May 2013 18:19:28 -0700
Message-ID: <>
To: Roberto Peon <>
Cc: "William Chan (陈智昌)" <>, Martin Thomson <>, HTTP Working Group <>
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
Received-SPF: pass client-ip=;;
X-W3C-Hub-Spam-Status: No, score=-3.4
X-W3C-Hub-Spam-Report: AWL=-2.642, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_LOW=-0.7, SPF_PASS=-0.001
X-W3C-Scan-Sig: 1UYR95-00029N-Mb 5262119fc04e07a3b7ec8d482e8e1bfe
Subject: Re: Design Issue: Max Concurrent Streams Limit and Unidirectional Streams
Archived-At: <>
X-Mailing-List: <> archive/latest/17828
Precedence: list
List-Id: <>
List-Help: <>
List-Post: <>
List-Unsubscribe: <>

Ok.. going back over the thread in detail and over the spec again, one
approach to addressing the overall concern here (and hopefully bring a
bit more rigor to the overall design) is to redefine the stream states
slightly along the same lines already suggested by Martin. Each
endpoint would maintain its own view of the current activity state of
every stream in a session, however, the state would only reflect the
actions taken by the peer endpoint. There are five possible activity

  The peer endpoint has not reserved or used the stream in any way.

  The endpoint has received frames on the stream from the peer, none
of which are type RST_STREAM or have the FINAL flag set.

  The endpoint has received an RST_STREAM frame, or any frame with the
FINAL flag set from the peer

  The peer has reserved the stream identifier for future use but
frames have not yet been received on that stream. The receiving
endpoint is expected to send its own frames on the same stream.

  The peer has reserved the stream identifier for future use but
frames have not yet been received on that stream. The receiving
endpoint is not expected to send its own frames on the same stream.

MAX_CONCURRENT_STREAMS == The number of streams in the Open state the
endpoint will permit the peer to initiate at any given time. Once that
limit is reached, the receiving endpoint will likely begin rejecting
new streams using RST_STREAM. In other words, right now,
MAX_CONCURRENT_STREAMS is defined in terms of what the sending
endpoint must not do. This changes the definition to an indication of
what the receiving endpoint will do once a particular threshold is
reached. Any endpoint that wants to be able to keep creating streams
must be diligent about sending FINAL frames, etc.

As for the Request-Response bounding issue, that's really an HTTP
semantic layer notion. I'm not fully convinced we really need to
handle that issue in the framing layer at all.

On Fri, May 3, 2013 at 2:20 PM, Roberto Peon <> wrote:
> The biggest rub in Martin's suggestion is that, as a stream initiator, I no
> longer know for how long I should keep the original "request" headers
> around.
> I view that as an annoying problem (I want every response to be attributable
> to a request).
> I also think it is a bit confusing-- how would it be used in cases where
> I've sent all my data on what I thought was a unidirectional stream, and
> then receive bytes from the other side on that stream. That'd be... weird.
> With the unidirectional bit (or similar declaration of half-closed
> start-state), I now know (by fiat, essentially) that I will not receive a
> response on that stream ID, and so I don't need to keep the "request"
> headers around after I've finished pushing the stream. Logging accomplished.
> I think this is an easy issue to solve by reinstating the unidirectional bit
> (for now). It is certainly minimal work to have servers which do server push
> set that bit.
> To Will's point, I agree that an "ENHANCE YOUR CALM" code seems redundant.
> In my case I believe it redundant because the remote side has already
> received my settings frame, or is sending without having known it (i.e.
> within the initial RTT), and will be receiving the SETTINGS frame before it
> could process this new code anyway (assuming I'm following spec and sending
> SETTINGS immediately upon session establishment).
> -=R
> On Fri, May 3, 2013 at 11:28 AM, William Chan (陈智昌) <>
> wrote:
>> I guess I kinda think that we're worrying too much about this corner of
>> the spec. I don't view it as a big deal in practice. The problem described
>> happens when MAX_CONCURRENT_STREAMS is too low to allow enough parallelism
>> per roundtrip. I would advise people to simply increase their
>> MAX_CONCURRENT_STREAMS in that case. I kinda think this is only problematic
>> when we have very high latencies and devices that can't handle high
>> parallelism, like an interplanetary refrigerator that speaks HTTP/2 for some
>> reason. <shrug>
>> I am unsure how to feel about a ENHANCE YOUR CALM code as it's not well
>> defined. I don't mind RST_STREAMs on exceeding limits, like the initial
>> MAX_CONCURRENT_STREAMS, since they're usually the result of a race (the
>> possible initial SETTINGS frame race) and we won't have to keep continually
>> sending RST_STREAMs to rate limit appropriately.
>> On Fri, May 3, 2013 at 3:02 PM, James M Snell <> wrote:
>>> The impact on client-to-server initiated streams is another reason why
>>> I suggested the credit-based approach and why it would likely be good
>>> to have an RST_STREAM "ENHANCE YOUR CALM" error code [1]. If the
>>> client misbehaves and sends too much too quickly, we have flow
>>> control, settings, rst_stream and goaway options to deal with it.
>>> [1]
>>> On Fri, May 3, 2013 at 10:34 AM, William Chan (陈智昌)
>>> <> wrote:
>>> > As I understand the proposal, which I believe ties into the issue James
>>> > raised at the beginning here, the goal is to be able to open and close
>>> > a
>>> > directional stream without an ACK, which I am nervous about as I said
>>> > above
>>> > without much detail. Concretely speaking, a HTTP GET is a
>>> > frame with a FINAL flag or an extra DATA frame with FINAL flag. This
>>> > means
>>> > that the request effectively never gets counted against the directional
>>> > stream limit, as controlled by the receiver which sends a
>>> > MAX_CONCURRENT_STREAMS setting, since it open and closes the direction
>>> > in
>>> > the same frame (or closes in the subsequent empty DATA frame).
>>> >
>>> >
>>> > On Fri, May 3, 2013 at 1:52 PM, Martin Thomson
>>> > <>
>>> > wrote:
>>> >>
>>> >> On 3 May 2013 09:44, William Chan (陈智昌) <> wrote:
>>> >> > I'd like server folks to chime in, but doing this makes me feel a
>>> >> > bit
>>> >> > nervous. I feel this effectively disables the directional concurrent
>>> >> > streams
>>> >> > limit. The bidirectional full-close essentially acts like an ACK, so
>>> >> > removing it might result in an unbounded number of streams.
>>> >>
>>> >> I think that I know what you mean here, but can you try to expand a
>>> >> little?  Do you refer to the possible gap between close on the
>>> >> initiating direction and the first frame on the responding direction;
>>> >> a gap that might cause the stream to escape accounting?  I think that
>>> >> is a tractable problem - any unbounded-ness is under the control of
>>> >> the initiating peer.
>>> >
>>> >