Subject: Clarification on HTTP/QUIC Unidirectional Streams

From: Samuel Hurst <[email-masked]>
Date: Wed, 17 Oct 2018 17:23:36 +0100

Hi All,

Apologies if this question has been asked before, but I'd just like to 
check that my understanding of something is correct and searching back 
through the list has not answered my question.

Given that HTTP/QUIC requires each peer in a connection to open a 
unidirectional control stream when a connection begins, I think it's 
safe to assume that streams 2 and 3 will be the control streams.

Now, a client will make a request on Stream 0, which will include some 
QPACK HEADERS, and the odds are that some of those headers will be poked 
into the dynamic table (I'm thinking of the User-Agent as a prime 
candidate for this).

However, as I understand it, QPACK requires two unidirectional control 
streams for the encode (type 'H') and decode (type 'h'). And this is per 
encode-decode pair, so there will be another pair of unidirectional 
control streams for the encode and decode of the server's response headers.

So in my head, the current state of streams in use is thus:

Stream 0 - Client Request
Stream 2 - Client Control Stream
Stream 3 - Server Control Stream
Stream 6 - Client Headers QPACK Encoder Stream
Stream 7 - Client Headers QPACK Decoder Stream
Stream 10 - Server Headers QPACK Decoder Stream
Stream 11 - Server Headers QPACK Encoder Stream

So, if as part of the request made in stream 0, the server decides to 
send a PUSH_PROMISE frame, and then once acknowledged by the client the 
server begins the server push immediately, is is a safe assumption to 
make that the first server push stream will be on stream 15?

I also don't think there's anything to stop a server from sending a 
PUSH_PROMISE frame before it's even sent a HEADERS frame back for the 
initial request, so in that case would the server push end up on stream 
11, the server headers encoder stream ends up on stream 15 and the 
decoder stream stays on stream 10?

I'm just trying to get it into my head exactly what the expected lay of 
the land will be during a running HTTP/QUIC session. It's been a while 
since I last looked at the QUIC drafts and I'm jumping ahead through 
several revisions so it's possible that I've missed something.

Best Regards,
Sam

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Wed, 17 Oct 2018 10:42:24 -0700

I’m not at all into all the details of HQ/QPACK

but you cannot assume anything about stream identifiers before you see them.

If stream 2 is an obvious control streams, some implementation will make
stream 8 the initial control stream because it will have some idea idea
about forcing the earlier streams open so the peer can do something evil to
them before it even begins sending data. Or they might just do it for the
heck of it to break applications making such assumptions (like ping of
death).

Some implementation could have fewer streams because they are
micro-controllers that do not want to use QPACK compression at all, so
assuming server push on stream 15 would possibly work most of the time at
best.

On 17 October 2018 at 18.23.57, Samuel Hurst ([email-masked]) wrote:

Hi All,

Best Regards,
Sam

---

From: Dmitri Tikhonov <[email-masked]>
Date: Wed, 17 Oct 2018 13:52:04 -0400

On Wed, Oct 17, 2018 at 10:42:24AM -0700, Mikkel Fahnøe Jørgensen wrote:
> but you cannot assume anything about stream identifiers before you see them..

Amen.  This is the WG consensus: do not rely on stream IDs being
assigned to particular streams in HTTP/QUIC.

  - Dmitri.

---

From: Samuel Hurst <[email-masked]>
Date: Thu, 18 Oct 2018 09:46:15 +0100

On 17/10/2018 18:42, Mikkel Fahnøe Jørgensen wrote:
> about forcing the earlier streams open so the peer can do something evil 
> to them before it even begins sending data. Or they might just do it for 
> the heck of it to break applications making such assumptions (like ping 
> of death).

Oh absolutely, but I was more thinking of an example flow with a client 
behaving in an at least somewhat predictable and not malicious manner. 
I'm mostly trying to sort out in my head how the QPACK encoder/decoder 
streams work together, apologies if that wasn't as clear as it could've 
been.

I'm fully aware that a client could open as many unidirectional streams 
as it likes and as long as it doesn't do anything else on those streams 
before starting a control stream somewhere.

And if something opens a control stream on Stream 8, shouldn't that be a 
protocol error, as stream 8 is not a unidirectional stream?

> assuming server push on stream 15 would possibly work most of the time 
> at best.

There's nothing in the specs that specifies when the QPACK 
encoder/decoder streams are opened, so I was going on the assumption 
that they are only opened when a client wants to use the dynamic table. 
If a client only wants to send literal headers or reference in the 
static table, or if the table size is set to zero in the SETTINGS frame, 
I'd assume the QPACK streams will not be opened. In which case, the 
first server push could be stream 7.

-Sam

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Thu, 18 Oct 2018 10:49:31 +0200

On 18 October 2018 at 10.46.34, Samuel Hurst ([email-masked]) wrote:

That was a typo, I meant 10.

---

From: Mikkel Fahnøe Jørgensen <[email-masked]>
Date: Thu, 18 Oct 2018 10:54:41 +0200

I’m not really sure where this landed, but there was some discussion here:
https://github.com/quicwg/base-drafts/issues/1747