Subject: Consistency in Stream Beginnings in HTTP/3

From: Mike Bishop <[email-masked]>
Date: Thu, 13 Jun 2019 17:30:02 +0000

This discussion has happened across a collection of GitHub issues with largely the same participants, and I'd like to get a sense of the larger working group's opinion before I work on any of these directions (or close all the related issues).

To recap the current state:

  *   Unidirectional streams begin with a type byte; interpretation of the remainder of the stream data depends on the type
  *   Push streams continue with a header - the Push ID as a varint - followed by frames as usual
  *   Control streams don't have a header; frames begin immediately after the type byte.  However, a SETTINGS frame is required to be the first frame of the stream.
  *   SETTINGS cannot be sent again thereafter or on any other stream

That means there are currently two different models of how you put required-to-be-first information:  As a required-initial frame or as a header before framing begins.

There are a couple of paths forward that have been discussed:

  *   Stay as-is.  SETTINGS is a frame in HTTP/2, so we're keeping it that way for consistency.  We've previously decided not to permit changes to settings to avoid the question of synchronization.  The reasons to change are not urgent.
  *   Make the Push ID a required-initial frame.  Proposed in #2526; rejected in London.
  *   Make SETTINGS a stream header.  Proposed in #2783.
     *   Argument for:  Gets rid of the concept of required-initial frames, in combination with #2781.  Consistent with the Push Stream header.
     *   Argument against:  Push ID isn't a length-prefixed structure, just a single varint.  We already have facilities for reading length-prefixed structures in frame handling.
  *   Allow multiple SETTINGS.  The synchronization requirement on SETTINGS is hairy when values are reduced, because in-flight activity might now violate a peer's restriction.  Allowing SETTINGS to be sent at any time, but only increase values, would also mean they need not be the first frame, eliminating the concept of required-initial frames.
     *   Complication:  What does this mean for clients' remembered settings and server's remembered settings as stored in NSTs?  If a client updates stored settings but retains a NST from earlier in the connection, the server and client could have divergent views of the server's settings on a future 0-RTT connection.
  *   Allow omitting SETTINGS.  If the server doesn't need to change anything from the client's initial settings, then the server can just not send a SETTINGS frame.  Once you've sent something else on the control stream, though, you can't send one later if you change your mind.

Thoughts?

---

From: Lucas Pardue <[email-masked]>
Date: Thu, 13 Jun 2019 19:15:05 +0100

Thanks for summarising all of this individual discussions Mike.

I have a derivative design on the SETTINGS stream header which would
replace length-prefix with count. So rather than Express total length of
parameter ID and value, you tell the receiver how many variant pairs to
process before processing frames.

I dont think that strongly pushes the needle in one direction though.

If we reject changing the control stream, I'm presently 50/50 split between
revisiting push stream framing and just living with what we have.

On Thu, 13 Jun 2019, 18:30 Mike Bishop, <[email-masked]> wrote:

> This discussion has happened across a collection of GitHub issues with
> largely the same participants, and I’d like to get a sense of the larger
> working group’s opinion before I work on any of these directions (or close
> all the related issues).
>
>
>
>    - Unidirectional streams begin with a type byte; interpretation of the
>    remainder of the stream data depends on the type
>    - Push streams continue with a header – the Push ID as a varint –
>    followed by frames as usual
>    - Control streams don’t have a header; frames begin immediately after
>    the type byte.  However, a SETTINGS frame is required to be the first frame
>    of the stream.
>    - SETTINGS cannot be sent again thereafter or on any other stream
>
>
>
> That means there are currently two different models of how you put
> required-to-be-first information:  As a required-initial frame or as a
> header before framing begins.
>
>
>
>    - *Stay as-is.*  SETTINGS is a frame in HTTP/2, so we’re keeping it
>    that way for consistency.  We’ve previously decided not to permit changes
>    to settings to avoid the question of synchronization.  The reasons to
>    change are not urgent.
>    - *Make the Push ID a required-initial frame.  *Proposed in #2526;
>    rejected in London.
>    - *Make SETTINGS a stream header.*  Proposed in #2783.
>       - *Argument for:*  Gets rid of the concept of required-initial
>       frames, in combination with #2781.  Consistent with the Push Stream header.
>       - *Argument against:*  Push ID isn’t a length-prefixed structure,
>       just a single varint.  We already have facilities for reading
>       length-prefixed structures in frame handling.
>    - *Allow multiple SETTINGS.*  The synchronization requirement on
>    SETTINGS is hairy when values are reduced, because in-flight activity might
>    now violate a peer’s restriction.  Allowing SETTINGS to be sent at any
>    time, but only increase values, would also mean they need not be the first
>    frame, eliminating the concept of required-initial frames.
>       - Complication:  What does this mean for clients’ remembered
>       settings and server’s remembered settings as stored in NSTs?  If a client
>       updates stored settings but retains a NST from earlier in the connection,
>       the server and client could have divergent views of the server’s settings
>       on a future 0-RTT connection.
>    - *Allow omitting SETTINGS.*  If the server doesn’t need to change
>    anything from the client’s initial settings, then the server can just not
>    send a SETTINGS frame.  Once you’ve sent something else on the control
>    stream, though, you can’t send one later if you change your mind.
>
>
>
> Thoughts?
>

---

From: Ryan Hamilton <[email-masked]>
Date: Thu, 13 Jun 2019 14:19:27 -0700

Of the options, I'd personally prefer revisiting #2526 and making push ID a
required first frame on a push stream.

On Thu, Jun 13, 2019 at 11:47 AM Lucas Pardue <[email-masked]>
wrote:

> If we reject changing the control stream, I'm presently 50/50 split
> between revisiting push stream framing and just living with what we have.
>
>
>>    - Unidirectional streams begin with a type byte; interpretation of
>>    the remainder of the stream data depends on the type

---

From: Kazuho Oku <[email-masked]>
Date: Fri, 14 Jun 2019 09:50:20 +0900

2019年6月14日(金) 6:19 Ryan Hamilton <rch=[email-masked]>:
>
> Of the options, I'd personally prefer revisiting #2526 and making push ID a required first frame on a push stream.

+1.

As I've commented on #2783, I prefer using one TLV structure (called
HTTP/3 frame) consistently, rather than inventing different structures
for different purposes.

We have states that expect particular frame; it's the design pattern
we have. The request stream decoder has a state that waits for HEADERS
frame.

I prefer consistently using one design pattern, unless there is a
practical benefit in using something special.

>
> On Thu, Jun 13, 2019 at 11:47 AM Lucas Pardue <[email-masked]> wrote:
>>
>> I have a derivative design on the SETTINGS stream header which would replace length-prefix with count.. So rather than Express total length of parameter ID and value, you tell the receiver how many variant pairs to process before processing frames.
>>
>> If we reject changing the control stream, I'm presently 50/50 split between revisiting push stream framing and just living with what we have.
>>
>>
>>> This discussion has happened across a collection of GitHub issues with largely the same participants, and I’d like to get a sense of the larger working group’s opinion before I work on any of these directions (or close all the related issues).
>>>
>>>
>>>
>>> Unidirectional streams begin with a type byte; interpretation of the remainder of the stream data depends on the type
>>> Push streams continue with a header – the Push ID as a varint – followed by frames as usual
>>> Control streams don’t have a header; frames begin immediately after the type byte.  However, a SETTINGS frame is required to be the first frame of the stream.
>>> SETTINGS cannot be sent again thereafter or on any other stream
>>>
>>>
>>>
>>> Stay as-is.  SETTINGS is a frame in HTTP/2, so we’re keeping it that way for consistency.  We’ve previously decided not to permit changes to settings to avoid the question of synchronization.  The reasons to change are not urgent.
>>> Make the Push ID a required-initial frame.  Proposed in #2526; rejected in London.
>>> Make SETTINGS a stream header.  Proposed in #2783.
>>>
>>> Argument for:  Gets rid of the concept of required-initial frames, in combination with #2781.  Consistent with the Push Stream header.
>>> Argument against:  Push ID isn’t a length-prefixed structure, just a single varint..  We already have facilities for reading length-prefixed structures in frame handling.
>>>
>>> Allow multiple SETTINGS.  The synchronization requirement on SETTINGS is hairy when values are reduced, because in-flight activity might now violate a peer’s restriction.  Allowing SETTINGS to be sent at any time, but only increase values, would also mean they need not be the first frame, eliminating the concept of required-initial frames.
>>>
>>> Complication:  What does this mean for clients’ remembered settings and server’s remembered settings as stored in NSTs?  If a client updates stored settings but retains a NST from earlier in the connection, the server and client could have divergent views of the server’s settings on a future 0-RTT connection.
>>>
>>> Allow omitting SETTINGS.  If the server doesn’t need to change anything from the client’s initial settings, then the server can just not send a SETTINGS frame.  Once you’ve sent something else on the control stream, though, you can’t send one later if you change your mind.
>>>
>>>
>>>
>>> Thoughts?

-- 
Kazuho Oku