Subject: Re: [quicwg/base-drafts] HTTP/3 references QUIC Stream IDs directly, allowing illegal references (#3273)

From: Lars Eggert <[email-masked]>
Date: Tue, 03 Dec 2019 23:02:54 -0800

Closed with no action, as indicated by @ianswett 

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-561506933

---

From: Lars Eggert <[email-masked]>
Date: Tue, 03 Dec 2019 23:02:55 -0800

Closed #3273.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#event-2852856337

---

From: Mike Bishop <[email-masked]>
Date: Wed, 04 Dec 2019 09:50:08 -0800

> This seems a bit at odd with our design principles, since it requires the HTTP/3 implementation to understand the QUIC Stream ID numbering scheme.

While the issue is closed, I wanted to point out that it does not imply this requirement.  I've held very strictly to this mental model:

- HTTP/3 can ask QUIC for a stream of a given type
- HTTP/3 can query the newly-received stream for its ID
- HTTP/3 can thereafter use the ID to refer to the stream
- HTTP/3 can query QUIC for the type of a given Stream ID and/or retrieve a stream by ID and then query its type

If QUIC were to change how Stream IDs are allocated, the changes could be entirely within the transport.  Now, it's a fair critique to say that this model is not explicitly stated in the draft, and so it's not guaranteed that any given implementation would actually preserve this flexibility.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-561763014

---

From: ianswett <[email-masked]>
Date: Wed, 04 Dec 2019 11:17:46 -0800

I was aware of the first 3, but It's the last requirement that I wasn't sure of:

* HTTP/3 can query QUIC for the type of a given Stream ID and/or retrieve a stream by ID and then query its type

In this case, in order to ensure the GOAWAY doesn't reference an invalid Stream ID, you need to be able to query the type of a Stream ID even if the stream hasn't been created.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-561797755

---

From: Kazuho Oku <[email-masked]>
Date: Wed, 04 Dec 2019 17:20:38 -0800

I think I agree with @ianswett.

One trivial example is the value of GOAWAY.stream_id when the server closes an HTTP/3 connection that has carried no request. In such case, it is my understanding that GOAWAY.stream_id should be zero. But how does the server determine that value?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-561922788

---

From: Martin Thomson <[email-masked]>
Date: Wed, 04 Dec 2019 19:07:28 -0800

There is I think an additional assumption here: that stream IDs are allocated in ascending order.  More or less.  That isn't a hard requirement, but it informs how effective GOAWAY is.

```
global varint max_request_stream_id = 0;

on handling(request):
    max_request_stream_id = max(max_request_stream_id, request.stream_id)

on sending(goaway):
    goaway.stream_id = max_request_stream_id
    for r in open requests:
        if r.stream_id < max_request_stream_id:
            r.reset()
```

See, not especially complicated, but the extent to which you have to reset streams depends on the order in which stream IDs are allocated.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-561946811

---

From: Lucas Pardue <[email-masked]>
Date: Thu, 05 Dec 2019 06:54:08 -0800

@ianswett 
> In this case, in order to ensure the GOAWAY doesn't reference an invalid Stream ID, you need to be able to query the type of a Stream ID even if the stream hasn't been created.

I don't see why this is a problem - the stream ID value indicates the type even if an instance of that stream does not exist in a connection. In fact, we rely on this when GOAWAY with MAX_CLIENT_INITIATED_BIDI is sent. 

@kazuho 

Spec says: 

> This identifier MAY be zero if no requests were processed.

 I think MT's example is pretty straightforward way to account

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-562163460

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 05 Dec 2019 17:16:37 -0800

@martinthomson I'm not sure if the logic is correct. It is my understanding that the server need to set GOAWAY.stream_id to the largest request stream ID it has processed, __added by 4__.

This is because the rules are:
* The GOAWAY frame indicates that client-initiated requests on lower stream IDs were or might be processed in this connection, while requests on the indicated stream ID and greater were rejected ([section 5.2](https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-connection-shutdown)).
* It carries a QUIC Stream ID for a client-initiated bidirectional stream encoded as a variable-length integer ([section 7.2.6](https://quicwg.org/base-drafts/draft-ietf-quic-http.html#name-goaway)).

@LPardue My point is that the specification requires a server to send an stream ID it has never seen, when there are no requests inflight.

I thought that it would be good to use as an example the case where no requests have ever been sent, and that the spec has to call out what should happen in that particular case is a leak.

But that might not have been the best example. Maybe I should have given the example when one request is exchanged then the server idle-timeouts. In such case, GOAWAY.stream_id is expected to be 4, which is a stream ID that the server has never seen.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-562389672

---

From: Martin Thomson <[email-masked]>
Date: Thu, 05 Dec 2019 18:54:19 -0800

As long as we don't rely on the stream ID carrying its type (that is, we rely on GOAWAY implicitly identifying the type of stream) we can use +1 rather than +4.  Otherwise, yeah, that exposes the internals of the transport.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-562410591

---

From: Kazuho Oku <[email-masked]>
Date: Thu, 05 Dec 2019 21:25:39 -0800

> we can use +1 rather than +4

That might be the reasonable thing to do. Though I do not care much, because there would be other hidden assumptions regardless: e.g., request stream ID can be represented using a 62-bit unsigned number starting from zero, request stream ID monotonically increases as the client uses them.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-562437543

---

From: Martin Thomson <[email-masked]>
Date: Sun, 08 Dec 2019 14:54:55 -0800

There is an assumption that only stream IDs that fit in a 62-bit number work, sure.  The monotonic increase isn't a strong assumption, only that there is some advantage to dividing the space into two with GOAWAY is useful.  You can do that split with totally random allocation of stream IDs and get some advantage; it's only if the stream IDs are monotonically *decreasing* that we get zero utility from GOAWAY.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3273#issuecomment-563005610