Subject: What are the semantics of a client sent GOAWAY?

From: Alan Frindell <[email-masked]>
Date: Thu, 23 May 2019 13:51:29 +0000

This discussion came up in the QUIC working group with respect to https://github.com/quicwg/base-drafts/issues/2632.

My understanding of 7540 is that a GOAWAY sent by the client will prevent the server from opening any additional push streams, without waiting to receive the push streams and then reset them.  It may also convey which pushes in flight were definitely not processed at the client.  Is this interpretation correct?

Thanks

-Alan

---

From: Cory Benfield <[email-masked]>
Date: Thu, 23 May 2019 15:52:33 +0100

My reading of this is that RFC 7540 pretty clearly specifies the
semantics of client-sent GOAWAY, and that it matches your
understanding Alan.

Section 5.1.1:

   Streams are identified with an unsigned 31-bit integer.  Streams
   initiated by a client MUST use odd-numbered stream identifiers; those
   initiated by the server MUST use even-numbered stream identifiers.

This implies that pushed streams are initiated by the server.
Section 6.8 (GOAWAY):

   Once sent, the sender will ignore frames sent on streams initiated by
   the receiver if the stream has an identifier higher than the included
   last stream identifier.

Also in 5.1.1:

   The identifier of a newly established stream MUST be numerically
   greater than all streams that the initiating endpoint has opened or
   reserved.

This seems pretty clear: once GOAWAY has been sent, any pushes that
have not yet been reserved will be ignored.
Additionally, if “last-stream-id” is lower than a previously reserved
stream’s stream ID, that stream will be ignored as well.

Cory

---

From: Stefan Eissing <[email-masked]>
Date: Fri, 24 May 2019 09:14:21 +0200

I agree with Corey.

> Am 23.05.2019 um 16:52 schrieb Cory Benfield <[email-masked]>:
>

---

From: "Martin Thomson" <[email-masked]>
Date: Fri, 24 May 2019 11:24:30 +0100

This interpretation is correct as others have noted.  The client sending GOAWAY prevents the server from opening any new push streams and causes any above the described limit to be considered "cancelled".

Of course, cancellation of a push in the sense that the client has "processed" them is meaningless as they are all (safe) responses.

But this question doesn't really help us get any further with respect to resolving the question QUIC is facing.  We have to consider the range of different models you might attribute to the use of server push before you can answer the core question.

In the model that I think Alan (and Cory) are assuming, pushes are largely used for optimization.  A server sends them to prime the cache.  They might be related to the original request, but it is only a loose relationship.  This fits for the pushing of JS, images, and other subresources in the category of  "other customers who viewed this product bought the following items".

If that loose arrangement were the only model, then I would easily agree that having a clean way to stem the flow of pushes makes sense.  In this model, the client might want to ensure that it completes the requests that it has outstanding in the most expeditious way possible.  MAX_PUSH_ID in h3 might limit the number of pushes the server can send, but that doesn't prevent it from using up to that limit, "wasting" bandwidth on things that the client might not be interested in.

The other model that we're starting to see, particularly from people building APIs, is one where the request is not just a request for a response in the classic sense, but a means of triggering pushes.  This might be to establish an open channel for server-driven communications (as in RFC 8030), or it might be that pushes are an inherent part of the response.  In the latter form, which we discussed at the recent HTTP workshop around the Prefer: push proposal (draft-pot-prefer-push), this allows better composition of resources without adding extra latency for fetching them.  There, the client requests a main resource and the server is asked to push discrete resources rather than inlining information. 

In that model, a signal that prevents the server from opening new (unidirectional) push streams would effectively prevent those requests from being completed.

Taking a big step back here, the problem here is that the design in h2 is poor.  While the equivalence request and stream is often a convenience we rely on, we should be careful to recognize what the boundaries of a transaction are.  h2 failed to do that because we were largely fixated on the server-driven case, even though we had this idea that the mechanism could be symmetrical.

If you adopt the model of a loose coupling between requests and pushes, then it makes sense to be able to draw an arbitrary line after which you block pushes based on stream numbers.  However, that is not the only model we have.

Also, we don't need to further entrench the idea that streams are a good proxy for identifying the quanta of application state.  In the recent meeting Roberto likened streams to TCP connections in that they could be refused.  I think that's a dangerous assumption that could prevent us from using QUIC to its full potential.  Refusing connections is fine, but that is denying an association; refusing requests is also valid; but streams need to be seen more as tools that are used to fulfill higher-level goals.

My view is that we could add a signal to the protocol that allowed a client to block further pushes.  However, to call it GOAWAY would be misleading.  GOAWAY exists to facilitate graceful shutdown, but that signal couldn't be graceful in the same way that a GOAWAY frame from the server is.  I don't think that we can fix h2 now, but we can avoid repeating its mistakes.

Cheers,
Martin

On Thu, May 23, 2019, at 15:13, Alan Frindell wrote:
>  
> This discussion came up in the QUIC working group with respect to 
> https://github.com/quicwg/base-drafts/issues/2632.
> 
>  My understanding of 7540 is that a GOAWAY sent by the client will 
> prevent the server from opening any additional push streams, without 
> waiting to receive the push streams and then reset them. It may also 
> convey which pushes in flight were definitely not processed at the 
> client. Is this interpretation correct?
> 
> 
> Thanks
> 
> 
> -Alan
>

---

From: Lucas Pardue <[email-masked]>
Date: Fri, 24 May 2019 11:42:57 +0100

On Fri, May 24, 2019 at 11:28 AM Martin Thomson <[email-masked]> wrote:

>
> My view is that we could add a signal to the protocol that allowed a
> client to block further pushes.  However, to call it GOAWAY would be
> misleading.  GOAWAY exists to facilitate graceful shutdown, but that signal
> couldn't be graceful in the same way that a GOAWAY frame from the server
> is.  I don't think that we can fix h2 now, but we can avoid repeating its
> mistakes.
>

On the HTTP/3 ticket that Alan linked [1], I advocated for a signal like
this. That could be a specialised extension frame for server push (e.g.
STOP_PUSHING), which contains an identifier for the maximum value that is
accepted. With the identifier representing a stream ID in H2, or a push ID
in H3. For push, a signal for what-was-or-maybe-will-be processed is
marginally useful for the safety reasons Martin stated.

Lucas

[1] - https://github.com/quicwg/base-drafts/issues/2632