Re: Streams after receiving GOAWAY

> On 15 Nov 2015, at 18:48, Glen Knowles <gknowles@ieee.org> wrote:
> 
> On Sun, Nov 15, 2015 at 2:52 AM, Cory Benfield <cory@lukasa.co.uk> wrote:
> 
> GOAWAY is not intended as a mechanism for saying “I will process no more than n further streams”.
> 
> But that is exactly a stated purpose of GOAWAY(noerror):
> "To deal with this case, the GOAWAY contains the stream identifier of the last peer-initiated stream that was or might be processed on the sending endpoint in this connection.”

This purpose is subordinate to the normative language in the section, which really clearly says that a peer that has received a GOAWAY frame MUST NOT open new frames. This normative language overrides the language in the section you quoted.

The way to reconcile these things is that the last_stream_id flag indicates the sending peer’s best guess about what information the application has acted on. The server promises that for any stream id > last_stream_id, no action has been taken: for any other stream, they’re potentially in a state of limbo where some action may or may not have been taken. It is not a license to continue to open new streams up to last_stream_id, and I doubt any server would accept you doing so.

> If it were, it would be totally acceptable to open all connections with the preamble, followed immediately by GOAWAY(last_stream_id=100). This is not the intended use of GOAWAY.
> 
> Reinterpreting last_stream_id to mean "last I will send" instead of "last of your streams I may process" would be clearly wrong, and is not what I'm doing. I'm merely giving the listener the option to widen the existing "inherent race condition between an endpoint starting new streams and the remote sending a GOAWAY frame.”

I apologise, I wasn’t clear enough. You could have had this flow:

Client: PREAMBLE + SETTINGS
Server: SETTINGS + SETTINGS(ACK)
Client: SETTINGS(ACK)
Server: GOAWAY(last_stream_id=101)

This is *exactly* the flow you’re proposing, taken to an extreme: here, the server is saying that the last of the client streams streams it may process is stream ID 101 (put another way, the server promises to serve 51 streams opened by the client). This is not at all the intended semantic of the GOAWAY frame, and using it like this is totally misleading. Any client that complies with RFC 7540 will see this GOAWAY and immediately refuse to open further streams.

Your client is not widening the existing race condition. That race condition applies to when the GOAWAY frame is in flight between client and server. Your client is essentially pretending that it did not receive the GOAWAY frame, deferring receipt of it until some later time.

In the above example, the server is acting incorrectly (last_stream_id does not correspond to a stream it has even seen, let alone begun to process). However, if the client follows up on this by sending a HEADERS frame, it is directly violating the normative language of RFC 7540.

> If your server sends a GOAWAY(no error) with the last stream id set to the last one it's processed then my client will not open any more streams on that connection. It will only continue to open additional streams if the last stream you report is "in the future". I see how this could be a problem if the server doesn't set the last stream id according to the spec, but otherwise?

It’s a problem because RFC 7540 quite clearly says "Receivers of a GOAWAY frame MUST NOT open additional streams on the connection”. This is not MAY, or even SHOULD NOT, it’s MUST NOT. Let me quote from RFC 2119[0], which defines the normative language of IETF drafts:

> MUST NOT   This phrase, or the phrase "SHALL NOT", mean that the definition is an absolute prohibition of the specification.

RFC 7540 says that a client MUST NOT open further streams once it has received a GOAWAY frame. This is not negotiable, and any peer that does so is not a compliant HTTP/2 peer. It is reasonably to discuss whether the semantics of GOAWAY should be extended to allow what you’re proposing here, or to propose an extension that allows this behaviour. However, if you ignore this MUST NOT in favour of non-normative language elsewhere in the specification, you are not building a HTTP/2 peer.

[0]: https://www.ietf.org/rfc/rfc2119.txt

Received on Sunday, 15 November 2015 21:26:09 UTC