Draft: draft-ietf-masque-h3-datagram

Commentary: This change allows clients to disable contexts for a given stream . This uses a new REGISTERDATAGRAMNO_CONTEXT capsule for negotiation . The important property here is that it requires capsule support even when contexts are not required . This is critical to the health of the ecosystem as it will ensure that intermediaries that support datagrams but not capsules can not be deployed , as that would prevent future extensibility . 
 Editorial comments aside , I support the protocol feature of an optional DATAGRAM Context ID . Using a registration capsule , as proposed in this PR , is a very logical way of achieving that . I plan to implement this in my WIP code . 
 Looks like there 's support for merging this . Some additional editorial work is needed , but we 'll do that in followups . 
 This issue assumes that decide to go with the two - layer design described in . Given that design , some applications might not need the multiplexing provided by context IDs . We have multiple options here : Make context ID mandatory Applications that do n't need it waste a byte per datagram Negotiate the presence of context IDs using an HTTP header  IDs would still be mandatory to implement on servers because the client might send that header Have the method determine whether context IDs are present or not This would prevent extensibility on those methods Create a REGISTERNOCONTEXT message This assumes we use the Message design from We add a register message that means that this stream does not use context IDs This allows avoiding the byte overhead without sacrificing extensibility 
 Making the context ID mandatory is simple , although slightly wasteful . For the variations where it is optional , I prefer the one that uses a header . It could work with a variant of where we do    , and the  determines whether or not you have contexts , and whether or not they can be dynamic . 
 What are the benefits of message over header to make it optional ? To me it seems like header is sufficient , because the context IDs are end - to - end , and should not affect intermediaries , making the header a natural place to put it . I think having the context ID be the default behavior and the header is to opt - out is the right decision if we were to allow removing it . 
 This is a bit of a bike - shed , but why would it default to having context - IDs instead of not having them ? 
 I think the second option " Negotiate the presence of context IDs using an HTTP header " is the best personally . In terms of : " Context IDs would still be mandatory to implement on servers because the client might send that header " , I assume server in this context is the final application server , not a proxy ? Even so , I 'd argue it 's applications which decide if they need this functionality , so if a server only implemented one application and it did n't use Context - IDs , then I do n't see why it would need to implement it . 
  , in your comment , are you talking about an intermediary when you say " proxy " ? If so , then an intermediary need not implement anything based on the payload of than H3 DATAGRAM , it only has to pass the data along . That may be worth a clarification . 
 Having context ID optional has a nice future - proof property - other uses of datagrams in HTTP/3 can decide if they want the second layer or not . I would n't even state it as application needing multiplexing or not . Other applications might find it very useful to include a second ( ( third , fourth , fifth ) layer of frame header . I think its fine for us to state as much in this in the spec , while also defining an explicit second layer for multiplexing . 
 Yes , by proxy I meant intermediary . And I agree about what intermediaries need to do , I just wanted to ensure I understood what server meant when  used it above . Yup , whenever all this gets written up , we can make it clear that intermediaries can ignore much of this . 
 The method defines the semantics of datagrams for a particular request , thus I think the third option makes most sense . I do n't see a point in using explicit negotiation , since in the two cases I can think of the top of the head , the answer is always clear from the method ( CONNECT - IP seems to always want context IDs , WebTransport does not ever want context IDs ) . If some method starts out without context , but wants to add context later , it can add its own negotiation . 
 One set of use cases for which the method approach(3 ) is best are those where there are multiple context IDs but they 're predefined by the method and do n't need negotiation . My strawman is WebRTC . 
 Looks good overall .
In order to allow multiple exchanges of datagrams to coexist on a
given QUIC connection, HTTP datagrams contain two layers of
multiplexing.  First, the QUIC DATAGRAM frame payload starts with an
encoded stream identifier that associates the datagram with a given
QUIC stream.  Second, datagrams carry a context identifier (see
datagram-contexts) that allows multiplexing multiple datagram
contexts related to a given HTTP request.  Conceptually, the first
layer of multiplexing is per-hop, while the second is end-to-end.
In order to allow multiple exchanges of datagrams to coexist on a
given QUIC connection, HTTP datagrams contain two layers of
multiplexing.  First, the QUIC DATAGRAM frame payload starts with an
encoded stream identifier that associates the datagram with a given
QUIC stream.  Second, datagrams optionally carry a context identifier
(see datagram-contexts) that allows multiplexing multiple datagram
contexts related to a given HTTP request.  Conceptually, the first
layer of multiplexing is per-hop, while the second is end-to-end.
Contexts are identified within the scope of a given request by a
numeric value, referred to as the context ID.  A context ID is a
62-bit integer (0 to 2^62-1).
Contexts are optional, their use is negotiated on each request stream
using registration capsules, see register-capsule and register-no-
context-capsule.  When contexts are used, they are identified within
the scope of a given request by a numeric value, referred to as the
context ID.  A context ID is a 62-bit integer (0 to 2^62-1).
Servers MUST NOT send a REGISTER_DATAGRAM_CONTEXT capsule on a stream
before they have received at least one REGISTER_DATAGRAM_CONTEXT
capsule from the client on that stream.  This ensures that clients
control whether datagrams are allowed for a given request.  If a
client receives a REGISTER_DATAGRAM_CONTEXT capsule on a stream where
the client has not yet sent a REGISTER_DATAGRAM_CONTEXT capsule, the
client MUST abruptly terminate the corresponding stream with a stream
error of type H3_GENERAL_PROTOCOL_ERROR.
Servers MUST NOT send a REGISTER_DATAGRAM_CONTEXT capsule on a stream
before they have received at least one REGISTER_DATAGRAM_CONTEXT
capsule or one REGISTER_DATAGRAM_NO_CONTEXT capsule from the client
on that stream.  This ensures that clients control whether datagrams
are allowed for a given request.  If a client receives a
REGISTER_DATAGRAM_CONTEXT capsule on a stream where the client has
not yet sent a REGISTER_DATAGRAM_CONTEXT capsule, the client MUST
abruptly terminate the corresponding stream with a stream error of
type H3_GENERAL_PROTOCOL_ERROR.
Servers MUST NOT send a REGISTER_DATAGRAM_CONTEXT capsule on a stream
where it has received a REGISTER_DATAGRAM_NO_CONTEXT capsule.  If a
client receives a REGISTER_DATAGRAM_CONTEXT capsule on a stream where
the client has sent a REGISTER_DATAGRAM_NO_CONTEXT capsule, the
client MUST abruptly terminate the corresponding stream with a stream
error of type H3_GENERAL_PROTOCOL_ERROR.
A string of comma-separated key-value pairs to enable
extensibility, see the definition of the same field in register-
capsule for details.
Note that this registration is unilateral and bidirectional: the
client unilaterally defines the semantics it will apply to the
datagrams it sends and receives with this stream.
Endpoints MUST NOT send DATAGRAM frames without a Context ID until
they have either sent or received a REGISTER_DATAGRAM_NO_CONTEXT
Capsule.  However, due to reordering, an endpoint that receives a
DATAGRAM frame before receiving either a REGISTER_DATAGRAM_CONTEXT
capsule or a REGISTER_DATAGRAM_NO_CONTEXT capsule MUST NOT treat it
as an error, it SHALL instead drop the DATAGRAM frame silently, or
buffer it temporarily while awaiting a REGISTER_DATAGRAM_NO_CONTEXT
capsule or the corresponding REGISTER_DATAGRAM_CONTEXT capsule.
Servers MUST NOT send the REGISTER_DATAGRAM_NO_CONTEXT capsule.  If a
client receives a REGISTER_DATAGRAM_NO_CONTEXT capsule, the client
MUST abruptly terminate the corresponding stream with a stream error
of type H3_GENERAL_PROTOCOL_ERROR.
Clients MUST NOT send more than one REGISTER_DATAGRAM_NO_CONTEXT
capsule on a stream.  If a server receives a second
REGISTER_DATAGRAM_NO_CONTEXT capsule on the same stream, the server
MUST abruptly terminate the corresponding stream with a stream error
of type H3_GENERAL_PROTOCOL_ERROR.
Clients MUST NOT send a REGISTER_DATAGRAM_NO_CONTEXT capsule on a
stream before they have sent at least one HEADERS frame on that
stream.  This removes the need to buffer REGISTER_DATAGRAM_CONTEXT
capsules when the server needs information from headers to determine
how to react to the capsule.  If a server receives a
REGISTER_DATAGRAM_NO_CONTEXT capsule on a stream that hasn't yet
received a HEADERS frame, the server MUST abruptly terminate the
corresponding stream with a stream error of type
H3_GENERAL_PROTOCOL_ERROR.
Clients MUST NOT send both REGISTER_DATAGRAM_CONTEXT capsules and
REGISTER_DATAGRAM_NO_CONTEXT capsules on the same stream.  If a
server receives both a REGISTER_DATAGRAM_CONTEXT capsule and a
REGISTER_DATAGRAM_NO_CONTEXT capsule on the same stream, the server
MUST abruptly terminate the corresponding stream with a stream error
of type H3_GENERAL_PROTOCOL_ERROR.