Subject: [quicwg/base-drafts] Rejection of 0-RTT: start over? (#761)

From: Martin Thomson <[email-masked]>
Date: Wed, 06 Sep 2017 01:00:16 +0000 (UTC)

If 0-RTT is rejected should the client:

1. start over at the application layer
2. close all streams that it initiated (can't do that because stream 1 is special)
3. just pretend that the packets were lost and need retransmission

Previously, people (@RyanAtGoogle) advocated for 3.  So far the preponderance of feedback on the list has been in favour of 1, which is at least consistent with the approach in TLS.

-- 
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/761

---

From: MikkelFJ <[email-masked]>
Date: Tue, 19 Sep 2017 23:25:57 -0700

At least 2. would seem wrong because arbitrarily closing a stream at transport layer breaks application context.

1. Seems fair, but it complicates application development. Why should developers really care.
3. Might cause unexpected delays, and application might prefer connecting elsewhere.

The API could have an open flag indicating whether they want an error on 0-RTT, or treat the failed connect as a packet loss.

Thus, both 1. and 3. makes sense and might be selectable by application choise. In QUIC terms this means the transport should either fail connection with a specific error on 0-RTT or alternatively silently use 1-RTT via packet loss without disrupting the application depending on the users API configuration.

A 4th option could be to start over but having the API think it is the same connection. This is not a good idea because the API might have data buffers linked to the connection and moving those associations to a new connection might be complicated. Suddenly API connection and transport connection becomes different things.

-- 
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/761#issuecomment-330757047

---

From: Ryan Hamilton <[email-masked]>
Date: Wed, 20 Sep 2017 07:09:33 -0700

On Tue, Sep 5, 2017 at 6:00 PM, Martin Thomson <[email-masked]>
wrote:

> Previously, people (@RyanAtGoogle <https://github.com/ryanatgoogle>)
> advocated for 3. So far the preponderance of feedback on the list has been
> in favour of 1, which is at least consistent with the approach in TLS.
>
​Yeah, we do #3 in Google's QUIC implementation which is super simple. Yay
for simple. Until recently I thought everyone should just do the simple
thing.

Alas, it can also be incorrect :(​ In particular, if there are any
properties of the request which depend on the connection's key (for example
Token Binding headers) then they will not be updated to reflect the new
keys. So in our implementation we're going to eventually move away from #3.

That being said, can you clarify the difference between 1 and 2? For
example, in the case of HTTP over QUIC using Token Binding, we need to
request headers to be regenerated which (in the case of Chrome's network
stack) means that the request needs to be restarted up in the application
and hence. Would this be an example of 1 or 2? (2 could definitely work,
but I'm not sure I understand the details of 1)

-- 
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/761#issuecomment-330863379

---

From: MikkelFJ <[email-masked]>
Date: Wed, 20 Sep 2017 07:26:00 -0700

So I didn't define 1 or 2, but my understanding is:

Option 1 cancels the connection attempt with a specific error allowing the application at a high level loop to start a new connection with different arguments.

Option 2 just cancels streams, meaning the application remains, but suddenly certain streams start to fail. For some applications this might just be pulling a new stream, but for others complicated application state must be managed - for example some protocols might never fail the first 10 streams because, short of connection failure, there is nothing inherent that can fail - this because the transport layer does not arbitrarily fail streams - it at most blocks them on flow.

Thus, having transport cancelling a stream is highly disruptive whereas giving up a new connection attemt as in option 1, is to be expected for many reasons, and comparatively easy to deal with.

-- 
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/761#issuecomment-330868376

---

From: Martin Thomson <[email-masked]>
Date: Mon, 25 Sep 2017 05:15:50 +0000 (UTC)

@mikkelfj got it right.  This is what we do for TLS 1.3 now.  Simple example: we want to send "GET /favicon.ico", we have a 0-RTT capable ticket.  We start TLS 1.3 and h2 and send the request.  If we get a reject, we will mark the request as needing retry and try again.  We throw away all h2 state at that point.  The same connection can be used, but all the other intermediate stuff goes away.  The request is matched to the "new" connection and it starts over, even reassessing the protocol.  That is, if we get http/1.1 (which is possible), it works.

That's a bit of a pain to implement correctly, but not too bad if you get the abstractions right.  I think that the way we do it (@ddragana can confirm) is to add the connection back to the connection pool so that it gets picked up as though it were a new one.

-- 
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/761#issuecomment-331779142