Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PRIORITY_UPDATE can be used for initial priority, split H3 frames into two types #1167

Merged
merged 26 commits into from
Sep 9, 2020
Merged
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f8640ef
Fill out TODOs in PRIORITY_UPDATE, split H3 frames into two types
LPardue Apr 30, 2020
56415dc
Allow PRIORITY_UPDATE as initial signal
LPardue May 4, 2020
187a8e2
Apply Ian's suggestions
LPardue May 5, 2020
2bc1227
Incorporate a tweaked version of Roy's suggestion
LPardue May 6, 2020
000e4c8
Kazuho's suggested test for frame signalling
LPardue May 15, 2020
782bda7
Define control stream term and use it
LPardue May 15, 2020
6a9ec9a
Big numbers for H3 frame type
LPardue May 15, 2020
84a4424
fix double 0x
LPardue May 18, 2020
e7cf2b6
fix missing 0
LPardue May 18, 2020
437b0a2
h2 frame should always be 0xF
LPardue May 18, 2020
23e66e5
Kazuho's suggestion
LPardue May 18, 2020
ee65018
stream ID value in frame drawing
LPardue May 22, 2020
9a2f9e4
s/MUST/SHOULD when stream IDs are beyond limits
LPardue May 22, 2020
41432cb
frame type starts at 0x10, and goes up to 0x11!
LPardue May 22, 2020
e1a5f17
Stronger qualification of frame types and rules
LPardue May 22, 2020
ca71a49
avoid discussing that clients might just use frames
kazuho May 27, 2020
021e7ca
Define H2 frame in it's customary format
LPardue Sep 7, 2020
ae7ef87
consistently use new H3 frame type value
LPardue Sep 7, 2020
357b2ae
remove erroneous term
LPardue Sep 7, 2020
b007e93
shorten PRIORITY_UPDATE type value
LPardue Sep 8, 2020
f441d5f
Kazuho's field appendum
LPardue Sep 8, 2020
c45f532
change PRIORITY_UPDATES to PRIORITY_UPDATE frames
LPardue Sep 8, 2020
805e5c5
Apply Mike's suggestions
LPardue Sep 8, 2020
0c35a0e
More Mike's suggestions
LPardue Sep 8, 2020
01414f5
disambiguate HTTP/2 frame payload by using Prioritized Stream ID
LPardue Sep 8, 2020
fd1c710
has been
LPardue Sep 9, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 95 additions & 71 deletions draft-ietf-httpbis-priority.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ Example HTTP requests and responses use the HTTP/2-style formatting from
This document uses the variable-length integer encoding from
{{!I-D.ietf-quic-transport}}.

The term control stream is used to describe the HTTP/2 stream with identifier
0x0, and HTTP/3 control stream; see {{!I-D.ietf-quic-http}}, Section 6.2.1.


# Motivation for Replacing HTTP/2 Priorities {#motivation}

Expand Down Expand Up @@ -319,37 +322,45 @@ references the new JavaScript file, while the prefetch is in progress, the
browser would send a reprioritization frame with the priority field value
set to `u=0`.

In HTTP/2 and HTTP/3, after a request message is sent on a stream, the stream
transitions to a state that prevents the client from sending additional
frames on the stream. Therefore, a client cannot reprioritize a response by
using the Priority header field. Modifying this behavior would require a
semantic change to the protocol, but this is avoided by restricting the
stream on which a PRIORITY_UPDATE frame can be sent. In HTTP/2 the frame
is on stream zero and in HTTP/3 it is sent on the control stream
({{!I-D.ietf-quic-http}}, Section 6.2.1).

This document specifies a new PRIORITY_UPDATE frame type for HTTP/2
({{!RFC7540}}) and HTTP/3 ({{!I-D.ietf-quic-http}}) which enables
reprioritization. It carries updated priority parameters and references the
target of the reprioritization based on a version-specific identifier; in
HTTP/2 this is the Stream ID, in HTTP/3 this is either the Stream ID or Push ID.

Unlike the header field, the reprioritization frame is a hop-by-hop signal.
This document specifies a new PRIORITY_UPDATE frame for HTTP/2 ({{!RFC7540}})
and HTTP/3 ({{!I-D.ietf-quic-http}}). It carries priority parameters and
references the target of the prioritization based on a version-specific
identifier. In HTTP/2, this identifier is the Stream ID; in HTTP/3, the
identifier is either the Stream ID or Push ID. Unlike the Priority header field,
the PRIORITY_UPDATE frame is a hop-by-hop signal.

PRIORITY_UPDATE frames are sent by clients on the control stream, and therefore
can be sent even after the sending part of the request stream is being closed. This
also allows the PRIORITY_UPDATE frame to be sent as soon as the stream it
references is created. Depending on the transmission logic of the endpoints and
on the network condition in case of HTTP/3, servers might receive a
PRIORITY_UPDATE frame that references a request stream that is yet to be opened.
Furthermore, clients might omit the Priority request header field, using
PRIORITY_UPDATE frames to indicate both the initial priority and the updated
priority.

When a server receives a PRIORITY_UPDATE frame referring to a client-initiated
request that has not yet been opened, the server buffers the priorities carried
by the received frame and applies them once the request has been processed. The
signal carried by a PRIORITY_UPDATE frame overrides that carried by the Priority
header field, even when the frame was received before the request headers.
LPardue marked this conversation as resolved.
Show resolved Hide resolved

## HTTP/2 PRIORITY_UPDATE Frame {#h2-update-frame}

The HTTP/2 PRIORITY_UPDATE frame (type=0xF) carries the stream ID of the
response that is being reprioritized, and the updated priority in ASCII text,
using the same representation as that of the Priority header field value.
The HTTP/2 PRIORITY_UPDATE frame (type=0x10) is used by clients to signal the
initial priority of a response, or to reprioritize a response or push stream. It
carries the stream ID of the response and the priority in ASCII text, using the
same representation as the Priority header field value.

The Stream Identifier field ({{!RFC7540}}, Section 4.1) in the PRIORITY_UPDATE
frame header MUST be zero (0x0).
frame header MUST be zero (0x0). Receiving a PRIORITY_UPDATE frame with a field
of any other value MUST be treated as a connection error of type PROTOCOL_ERROR.

~~~ drawing
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+---------------------------------------------------------------+
|R| Stream ID (31) |
|R| Prioritized Stream ID (31) |
+---------------------------------------------------------------+
| Priority Field Value (*) ...
+---------------------------------------------------------------+
Expand All @@ -362,77 +373,90 @@ R:
: A reserved 1-bit field. The semantics of this bit are undefined, and the bit
MUST remain unset (0x0) when sending and MUST be ignored when receiving.

Stream ID:
Prioritized Stream ID:
: A 31-bit stream identifier for the stream that is the target of the priority
update.

Priority Field Value:
: The priority update value in ASCII text, encoded using Structured Headers.

The HTTP/2 PRIORITY_UPDATE frame MUST NOT be sent prior to opening the
stream. If a PRIORITY_UPDATE is received prior to the stream being opened,
it MAY be treated as a connection error of type PROTOCOL_ERROR.
The PRIORITY_UPDATE frame MAY be sent before the stream that it references has
been created. The Prioritized Stream ID MUST be within the stream limit. If a
server receives a PRIORITY_UPDATE with a Prioritized Stream ID that is beyond
the stream limits, this SHOULD be treated as a connection error of type
PROTOCOL_ERROR. PRIORITY_UPDATE frames received before the request or response
has started SHOULD be buffered until the stream is opened and applied
immediately after the request message has been processed. Holding
PRIORITY_UPDATE frames consumes extra state on the peer, although the size of
the state is bounded by stream limits. There is no bound on the number of
PRIORITY_UPDATE frames that can be sent, so an endpoint SHOULD store only the
most recently received frame.

TODO: add more description of how to handle things like receiving
PRIORITY_UPDATE on wrong stream, a PRIORITY_UPDATE with an invalid ID, etc.
If a PRIORITY_UPDATE frame is received with a Prioritized Stream ID of 0x0, the
recipient MUST respond with a connection error of type PROTOCOL_ERROR.

If a client receives a PRIORITY_UPDATE frame, it MUST respond with a connection
error of type PROTOCOL_ERROR.

## HTTP/3 PRIORITY_UPDATE Frame {#h3-update-frame}

The HTTP/3 PRIORITY_UPDATE frame (type=0xF) carries the identifier of the
element that is being reprioritized, and the updated priority in ASCII text,
using the same representation as that of the Priority header field value.
The HTTP/3 PRIORITY_UPDATE frame (type=0xF0700 or 0xF0701) is used by clients to
signal the initial priority of a response, or to reprioritize a response or push
stream. It carries the identifer of the element that is being prioritized, and
the updated priority in ASCII text, using the same representation as that of the
Priority header field value. PRIORITY_UPDATE with a frame type of 0xF0700 is
used for request streams, while PRIORITY_UPDATE with a frame type of 0xF0701 is
used for push streams.

The PRIORITY_UPDATE frame MUST be sent on the control stream
({{!I-D.ietf-quic-http}}, Section 6.2.1).
The PRIORITY_UPDATE frame MUST be sent on the client control stream
({{!I-D.ietf-quic-http}}, Section 6.2.1). Receiving a PRIORITY_UPDATE frame on a
stream other than the client control stream MUST be treated as a connection
error of type H3_FRAME_UNEXPECTED.

~~~ drawing
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|T| Empty | Prioritized Element ID (i) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Priority Field Value (*) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
HTTP/3 PRIORITY_UPDATE Frame {
Type (i) = 0xF0700..0xF0701,
Length (i),
Prioritized Element ID (i),
Priority Field Value (..),
}
~~~
{: #fig-h3-reprioritization-frame title="HTTP/3 PRIORITY_UPDATE Frame Payload"}
{: #fig-h3-reprioritization-frame title="HTTP/3 PRIORITY_UPDATE Frame"}

The PRIORITY_UPDATE frame payload has the following fields:

T (Prioritized Element Type):
: A one-bit field indicating the type of element
being prioritized. A value of 0 indicates a reprioritization for a Request
Stream, so the Prioritized Element ID is interpreted as a Stream ID. A
value of 1 indicates a reprioritization for a Push stream, so the Prioritized
Element ID is interpreted as a Push ID.

Empty:
: A seven-bit field that has no semantic value.

Prioritized Element ID:
: The stream ID or push ID that is the target of the priority update.

Priority Field Value:
: The priority update value in ASCII text, encoded using Structured Headers.

The HTTP/3 PRIORITY_UPDATE frame MUST NOT be sent with an invalid identifier,
including before the request stream has been opened or before a promised
request has been received. If a server receives a PRIORITY_UPDATE specifying
a push ID that has not been promised, it SHOULD be treated as a connection
error of type H3_ID_ERROR.

Because the HTTP/3 PRIORITY_UPDATE frame is sent on the control stream and
there are no ordering guarantees between streams, a client that reprioritizes
a request before receiving the response data might cause the server to receive
a PRIORITY_UPDATE for an unknown request. If the request stream ID is within
bidirectional stream limits, the PRIORITY_UPDATE frame SHOULD be buffered
until the stream is opened and applied immediately after the request message
has been processed. Holding PRIORITY_UPDATES consumes extra state on the peer,
although the size of the state is bounded by bidirectional stream limits. There
is no bound on the number of PRIORITY_UPDATES that can be sent, so an
endpoint SHOULD store only the most recently received frame.

TODO: add more description of how to handle things like receiving
PRIORITY_UPDATE on wrong stream, a PRIORITY_UPDATE with an invalid ID, etc.
The request-stream variant of PRIORITY_UPDATE (type=0xF0700) MUST reference a
request stream. If a server receives a PRIORITY_UPDATE (type=0xF0700) for a
Stream ID that is not a request stream, this MUST be treated as a connection
error of type H3_ID_ERROR. PRIORITY_UPDATE (type=0xF0700) MAY be sent before the
request stream that it references has been created. The Stream ID MUST be within
the client-initiated bidirectional stream limit. If a server receives a
PRIORITY_UPDATE (type=0xF0700) with a Stream ID that is beyond the stream
limits, this SHOULD be treated as a connection error of type H3_ID_ERROR.

Request-stream variant PRIORITY_UPDATE frames (type=0xF0700) received before the
request or response has started SHOULD be buffered until the stream is opened
and applied immediately after the request message has been processed. Holding
LPardue marked this conversation as resolved.
Show resolved Hide resolved
PRIORITY_UPDATE frames consumes extra state on the peer, although the size of
the state is bounded by bidirectional stream limits. There is no bound on the
number of PRIORITY_UPDATE frames that can be sent, so an endpoint SHOULD store
only the most recently received frame.

The push-stream variant PRIORITY_UPDATE (type=0xF0701) MUST reference a promised
push stream. If a server receives a PRIORITY_UPDATE (type=0xF0701) with a Push ID
that is greater than the maximum Push ID or which has not yet been promised, this
MUST be treated as a connection error of type H3_ID_ERROR.

PRIORITY_UPDATE frames of either type are only sent by clients. If a client
receives a PRIORITY_UPDATE frame, this MUST be treated as a connection error of
type H3_FRAME_UNEXPECTED.


# Merging Client- and Server-Driven Parameters {#merging}

Expand Down Expand Up @@ -634,7 +658,7 @@ Frame Type:
: PRIORITY_UPDATE

Code:
: 0xF
: 0x10

Specification:
: This document
Expand All @@ -646,7 +670,7 @@ Frame Type:
: PRIORITY_UPDATE

Code:
: 0xF
: 0xF0700 and 0xF0701

Specification:
: This document
Expand Down