Subject: Re: New Version Notification for draft-benfield-http2-p2p-00.txt

From: Cory Benfield <[email-masked]>
Date: Wed, 30 Sep 2015 11:05:36 +0100

(Sorry, dropped the CCs from this originally)

On 27 September 2015 at 10:26, Juan Benet <[email-masked]> wrote:
>> 2.2.  CLIENT_AUTHORITY Frame
>>
>>    This document introduces the CLIENT_AUTHORITY frame.  This frame MUST
>>    be emitted by a client after it sends a value of
>>    SETTINGS_PEER_TO_PEER of 1, and MAY be emitted by a client any time
>>    after.  The purpose of this frame is to allow a client to advertise
>>    the authority or authorities for which it is prepared to accept
>>    requests.
>>
>>    This frame always applies to a whole connection.  Therefore, the
>>    stream identifier for CLIENT_AUTHORITY frames MUST be 0.  If a server
>>    receives a CLIENT_AUTHORITY frame whose stream identifier field is
>>    anything other than 0, it MUST respond with a connection error
>>    ([RFC7540] Section 5.4.1) of type PROTOCOL_ERROR.
>
> So this rules out entirely the notion of multiple virtual hosts, correct?
> (Am not sure if these are supported in http2 at all, or the restriction is
> the same). It is probably good to scope each authority to a new connection,
> though worth clarifying for myself here what this means.

Not at all: the frame allows for specifying multiple authorities for a
client. In this context, 'authority' is roughly equivalent to 'virtual
host'. Each client and each server may offer any number of
authorities, but the client is required to explicitly enumerate its
authorities. This is a consequence of the way connections are
established: the client already has reason to believe the remote peer
is authoritative for a given host because of the TLS handshake.

>> 2.2.2.  Semantics
>>
>>    Generally speaking, a server or coalescing intermediary has no in-
>>    band method of validating that a client's authority claims are valid.
>>    Therefore, a conforming server MUST confirm a client's authority
>>    claims using some out-of-band method: see Section 3 for more.
>>
>>    A client MAY send a CLIENT_AUTHORITY frame at any time after the
>>    HTTP/2 preamble is complete.  Each CLIENT_AUTHORITY frame is
>>    considered to be a complete list of authorities: therefore, a server
>>    MUST disregard all prior CLIENT_AUTHORITY frames when a new one is
>>    received.  Also, servers MUST validate the asserted authorities for
>>    all CLIENT_AUTHORITY frames, not just the first one.
>
> Oh interesting, so the authority may change during the connection? It may
> be useful to point to why this is useful, linking to the HTTP2 spec or
> elsewhere.

Yeah, in the current version of the spec. I have mixed feelings about
this and may remove it, because it doesn't strike me as entirely
useful, but I was making a defensive decision. I may remove this in
the next draft.

>> 2.4.  Client Behavioral Changes
>>
>>    When a client emits the SETTINGS_PEER_TO_PEER setting with a value of
>>    1, it is informing the server that it is willing to accept HTTP
>>    requests from the server, allowing the server to open streams with
>>    HEADERS frames.  This lifts some of the restrictions of RFC 7540
>>    [RFC7540] Section 8.
>>
>>    If a client has sent the SETTINGS_PEER_TO_PEER setting with a value
>>    of 1, the client MUST NOT reject an attempt by the server to change
>>    the value of SETTINGS_ENABLE_PUSH to 1.
>
> I wonder if it is possible to use SETTINGS_ENABLE_PUSH from client to
> server instead of using a new value. I imagine it isn't, and you had
> already considered it. But if it were, it would likely simplify some
> implementations. (At the risk of being a bit more ambiguous, maybe it
> is good to be explicit.)

I am disinclined to override SETTINGS_ENABLE_PUSH in this manner for
two reasons. Firstly, RFC 7540 explicitly forbids SETTINGS_ENABLE_PUSH
being sent by clients, which means that using it in this manner would
cause connection teardown if a remote server does not understand this
extension. A new setting will simply be ignored, which has a slightly
better UX. Secondly, it is still perfectly valid for the dialer to
want to send SETTINGS_PEER_TO_PEER 1 and SETTINGS_ENABLE_PUSH 0: that
is, it will accept streams initiated by the listener with HEADERS
frames, but not with PUSH_PROMISE frames.

>>    If the client, subsequent to sending SETTINGS_PEER_TO_PEER with value
>>    1, receives from the server a value of SETTINGS_ENABLE_PUSH of 1, it
>>    MAY open streams by sending PUSH_PROMISE frames.  The client MUST NOT
>>    send a PUSH_PROMISE frame on a stream that it opened by means of a
>>    HEADERS frame: only server-initiated streams may be used for sending
>>    PUSH_PROMISE frames.  All other limitations about PUSH_PROMISE frames
>>    in RFC 7540 [RFC7540] continue to apply, except that the words
>>    'server' and 'client' are defined on a per-stream basis.
>>
>> 2.5.  Server Behavioral Changes
>>
>>    When a server receives the SETTINGS_PEER_TO_PEER setting from the
>>    client with a value of 1, it MAY at any point afterwards issue a non-
>>    zero value for SETTINGS_ENABLE_PUSH.  This allows clients to open
>
> It took me a while to grasp the relationship between these two settings.
> Perhaps it may be useful to motivate the need for SETTINGS_ENABLE_PUSH
> from server to client, and why it's not needed client to server (namely,
> in client-to-server, it begins enabled, and is turned off. in server-to-
> client, it begins off, and is turned on. -- if i'm wrong about this,
> then that's more evidence this is a bit convfusing :/ ).

Yeah, this is a good idea.

>>    streams with PUSH_PROMISE and also lifts some of the restrictions of
>>    RFC 7540 [RFC7540] Section 8: specifically those sections that only
>>    allow servers to send PUSH_PROMISE frames, and only allow clients to
>>    receive them.
>>
>>    If the client attempts to send a PUSH_PROMISE frame on a stream that
>>    was opened by the client (by sending a HEADERS frame), the server
>>    MUST treat this event as a connection error ([RFC7540] Section 5.4.1)
>>    of type PROTOCOL_ERROR.
>>
>> 2.6.  Other Extensions
>>
>>    When this extension is deployed with other extensions to HTTP/2, the
>>    behaviour of this extension does not change.  All other extensions
>>    that refer to 'client' or 'server' SHOULD be treated as though those
>>    terms apply on a per-stream basis.
>>
>>    If other extensions apply 'server' or 'client' to the whole
>>    connection (e.g.  for settings in SETTINGS frames, which are sent on
>>    stream 0), then both peers SHOULD be considered clients and both
>>    peers should be considered servers.
>
> Ok i worry about this wording because there are a few things in the HTTP2
> spec that are mant to be done by a client or server merely to coordinate,
> like numbering the streams even and odd. Which number would a peer pick,
> if they're considered the same? This seems like a spec bug to me, as I
> think it is unclear how to pick stream ids now. (maybe i'm missing
> something). I suspect there may be other such ambiguities.

Good spot on this one. I think I may have to call this out explicitly:
dialers use odd-numbered stream IDs, listeners use even-numbered ones.
I'm not sure about other ambiguities here: none leap out at me, but I
think I'll bump into some as I whip up a PoC of this.

>> 5.  Acknowledgements
>>
>>    Thanks to Fedor Indutny for the original idea, and Amos Jeffries,
>>    Mike Bishop, and Ilari Liusvaara for their follow-up.
>
> Not to toot our own vuvuzela, but i think David Dias and I helped
> originate this idea :) -- this whole story began with our asking
> Fedor to implement this in his spdy/http2 node module, as some Go
> implementations of SPDY function in a similar way.

For now I shall add you and David to the acknowledgements. I'm going
to hold off on referencing specific implementations for the time
being, unless their experiences substantially shape the final RFC.

> perhaps someone should try changing some HTTP2 implementation
> to add this extension and see if any ambiguities emerge.

I plan to do exactly that! I'm working on an implementation that
should be well suited to this kind of change: when it's in a good
state for it (a week or two probably) I'll spike out an example
implementation of some kind of basic form of this for people to play
with.