Re: Stream State and PRIORITY Frames

Cory Benfield <> Tue, 17 January 2017 12:46 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 0B1001270B4 for <>; Tue, 17 Jan 2017 04:46:02 -0800 (PST)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -9.619
X-Spam-Status: No, score=-9.619 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HEADER_FROM_DIFFERENT_DOMAINS=0.001, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_HI=-5, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_SORBS_SPAM=0.5, RP_MATCHES_RCVD=-3.199, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001] autolearn=ham autolearn_force=no
Authentication-Results: (amavisd-new); dkim=pass (2048-bit key)
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id s9HydfDaQLsv for <>; Tue, 17 Jan 2017 04:45:59 -0800 (PST)
Received: from ( []) (using TLSv1.2 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by (Postfix) with ESMTPS id 34BBE129AA1 for <>; Tue, 17 Jan 2017 04:45:59 -0800 (PST)
Received: from lists by with local (Exim 4.80) (envelope-from <>) id 1cTT6w-0004xX-Ux for; Tue, 17 Jan 2017 12:43:38 +0000
Resent-Date: Tue, 17 Jan 2017 12:43:38 +0000
Resent-Message-Id: <>
Received: from ([]) by with esmtps (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.80) (envelope-from <>) id 1cTT6t-0004wU-PE for; Tue, 17 Jan 2017 12:43:35 +0000
Received: from ([]) by with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.84_2) (envelope-from <>) id 1cTT6n-0004aR-4l for; Tue, 17 Jan 2017 12:43:30 +0000
Received: by with SMTP id c85so198318684wmi.1 for <>; Tue, 17 Jan 2017 04:43:08 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20150623; h=from:message-id:mime-version:subject:date:in-reply-to:cc:to :references; bh=Kz7dHvZUCLmsLQrRLkGmjSvA0u/2WxN7j7o/OC8j0Gg=; b=hT/Kq5seEtAmdN1ps1Q26sFeHqXN7DAnvJhTxZzQ4r9V+xJapu14Av85xnlrmXddCq M6IIRW42jhk4z5emO8b9bCj3H/NsMHvKA1+7ix12zO9k2WdiC3IB4tiHVXXjdz6km37k H3EqhBM6PWB2913M168SpnOUfkGqGgsHqkRpxdJGYfoohEBKyxnYfgS2NsfwsVcEsDxy BB24PtuwCRfLWkZ6KylRTOIl1IJwcBXdSJt+teAkRFgJrgKPnRseemY9qnh6FfQAI5dK cviBdACKY6vGE7+TVzQ0gZoH5W5ozgzFLJDqdh+nG1r6rEqGZ32X9FlB4ZTLwwHLmUfA eCFQ==
X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;; s=20161025; h=x-gm-message-state:from:message-id:mime-version:subject:date :in-reply-to:cc:to:references; bh=Kz7dHvZUCLmsLQrRLkGmjSvA0u/2WxN7j7o/OC8j0Gg=; b=csblznh1kp2NKX7qoIMc9oFm9UeLc4JGs4UQChhL0QnyvIsaRywR0/SIHlXwl0IwIP 2t3g7cRZsBKiIc2l8jnqkbR8VX1g6OlIhagICiRIVa8aE+a5HhzMx5acc+gZJeL0pJsB Bu2xOyhskCS3wxmZeOPV4da+T/CzR7257ZhvbYo39ZSxO/G9I6HptcfDH5yTNU3JxfFd hl/IXuwsSZsFDSqwA1mv9HKuRKBaDtWrd1kJ5v9miS79ncAWd02zDaV0GUYk62227nwx D2Tz3Ary9Da3u2SHrVhrSxZiE08U6bRAPTq/nQPpJU/Qj9OAe1ocByx9VWFh/Yi/mloB Xnjg==
X-Gm-Message-State: AIkVDXKEvZUXkgr9K/Peb2ZW5/4qKynu+HL/divL4G8Jmk+XQYe08ABAKg0QptwhML4AOw==
X-Received: by with SMTP id 4mr19115033wrh.176.1484656982043; Tue, 17 Jan 2017 04:43:02 -0800 (PST)
Received: from [] ( []) by with ESMTPSA id r6sm36678521wmd.4.2017. (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Jan 2017 04:43:00 -0800 (PST)
From: Cory Benfield <>
Message-Id: <>
Content-Type: multipart/alternative; boundary="Apple-Mail=_73B57978-A80C-4AB0-9CB9-EC830D81AF17"
Mime-Version: 1.0 (Mac OS X Mail 10.2 \(3259\))
Date: Tue, 17 Jan 2017 12:42:58 +0000
In-Reply-To: <>
Cc: Scott Mitchell <>, HTTP Working Group <>
To: Benedikt Christoph Wolters <>
References: <> <>
X-Mailer: Apple Mail (2.3259)
Received-SPF: pass client-ip=;;
X-W3C-Hub-Spam-Status: No, score=-4.8
X-W3C-Hub-Spam-Report: AWL=-1.408, BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, HTML_MESSAGE=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H3=-0.01, RCVD_IN_MSPIKE_WL=-0.01, RCVD_IN_SORBS_SPAM=0.5, SPF_PASS=-0.001, W3C_AA=-1, W3C_WL=-1
X-W3C-Scan-Sig: 1cTT6n-0004aR-4l 0dabdae9b6217d875ceb712ea941dbd6
Subject: Re: Stream State and PRIORITY Frames
Archived-At: <>
X-Mailing-List: <> archive/latest/33304
Precedence: list
List-Id: <>
List-Help: <>
List-Post: <>
List-Unsubscribe: <>

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

In fact, I think it’s the same issue. Scott linked to <>, which is referenced from and opened by the same person who opened <>, which links to <>, which is related to <> 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.