Draft: draft-ietf-masque-h3-datagram

Commentary: uses HTTP Datagrams but does n't currently have a need for datagram contexts . Because of this , some members of the WebTransport community prefer to not have to implement datagram contexts . This PR changes how datagram contexts are negotiated to make them optional to implement . One important design goal of this change was to allow optimistic use of contexts : in other words , the client should n't have to wait a round trip to find out whether contexts are supported before being able to optimistically use them . Before this PR , contexts were mandatory to implement and the client would decide whether to use them by sending either REGISTERDATAGRAMCONTEXT or REGISTERDATAGRAMNOCONTEXT . With this PR , endpoints use a new Sec - Use - Datagram - Contexts header to indicate support . The PR makes a few small tweaks to capsules in order to allow the optimistic use described above . In particular , it incorporates the DATAGRAM capsule split from as that allows the client to use contexts before knowing whether the server supports them because the server can just drop the variant of the capsule with contexts . . 
 I 've held my finger over the " close PR " button a few times on that one : facewithspiral_eyes : 
 LGTM now , thanks !
datagram-contexts defines datagram contexts, an optional end-
to-end multiplexing concept scoped to each HTTP request.
datagram-contexts defines datagram contexts, an optional end-
to-end multiplexing concept scoped to each HTTP request.
Whether contexts are in use is defined in context-hdr.
When an endpoint registers a datagram context (or the lack of
contexts), it communicates the format (i.e., the semantics and
encoding) of datagrams sent using this context.  This is
acccomplished by sending a Datagram Format Type as part of the
registration capsule, see register-capsule and register-no-context-
capsule.  This type identifier is registered with IANA (see iana-
format-types) and allows applications that use HTTP Datagrams to
indicate what the content of datagrams are.  Registration capsules
carry a Datagram Format Additional Data field which allows sending
some additional information that would impact the format of
datagrams.
Contexts are OPTIONAL to implement for both endpoints.
Intermediaries do not require any context-specific software to enable
contexts.  When contexts are supported by the implementation, their
use is optional and can be selected on each stream.  Endpoints inform
their peer of whether they wish to use contexts via the Sec-Use-
Datagram-Contexts HTTP header, see context-hdr.
When an endpoint registers a datagram context (or the lack of
contexts), it communicates the format (i.e., the semantics and
encoding) of datagrams sent using this context.  This is
acccomplished by sending a Datagram Format Type as part of the
datagram registration capsule, see register-capsule.  This type
identifier is registered with IANA (see iana-format-types) and allows
applications that use HTTP Datagrams to indicate what the content of
datagrams are.  Registration capsules carry a Datagram Format
Additional Data field which allows sending some additional
information that would impact the format of datagrams.
Implementations of HTTP Datagrams MUST provide a context ID
allocation service.  That service will allow applications co-located
with HTTP to request a unique context ID that they can subsequently
use for their own purposes.  The HTTP implementation will then parse
the context ID of incoming HTTP Datagrams and use it to deliver the
frame to the appropriate application context.
Implementations of HTTP Datagrams that support datagram contexts MUST
provide a context ID allocation service.  That service will allow
applications co-located with HTTP to request a unique context ID that
they can subsequently use for their own purposes.  The HTTP
implementation will then parse the context ID of incoming HTTP
Datagrams and use it to deliver the frame to the appropriate
application context.
A variable-length integer indicating the context ID of the
datagram (see datagram-contexts).  Whether or not this field is
present depends on whether datagram contexts are in use on this
stream, see context-hdr.  If this QUIC DATAGRAM frame is reordered
and arrives before the receiver knows whether datagram contexts
are in use on this stream, then the receiver cannot parse this
datagram and the receiver MUST either drop that datagram silently
or buffer it temporarily.
Intermediaries parse the Quarter Stream ID field in order to
associate the QUIC DATAGRAM frame with a stream.  If an intermediary
receives a QUIC DATAGRAM frame whose payload is too short to allow
parsing the Quarter Stream ID field, the intermediary MUST treat it
as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR.  The
Context ID field is optional and whether it is present or not is
decided end-to-end by the client, see register-no-context-capsule.
Therefore intermediaries cannot know whether the Context ID field is
present or absent and they MUST ignore any HTTP/3 Datagram fields
after the Quarter Stream ID.
Intermediaries parse the Quarter Stream ID field in order to
associate the QUIC DATAGRAM frame with a stream.  If an intermediary
receives a QUIC DATAGRAM frame whose payload is too short to allow
parsing the Quarter Stream ID field, the intermediary MUST treat it
as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR.  The
Context ID field is optional and whether it is present or not is
decided end-to-end by the endpoints, see context-hdr.  Therefore
intermediaries cannot know whether the Context ID field is present or
absent and they MUST ignore any HTTP/3 Datagram fields after the
Quarter Stream ID.
Unless otherwise specified, all Capsule Types are defined as opaque
to intermediaries.  Intermediaries MUST forward all received opaque
CAPSULE frames in their unmodified entirety.  Intermediaries MUST NOT
send any opaque CAPSULE frames other than the ones it is forwarding.
All Capsule Types defined in this document are opaque, with the
exception of the DATAGRAM Capsule, see datagram-capsule.  Definitions
of new Capsule Types MAY specify that the newly introduced type is
transparent.  Intermediaries MUST treat unknown Capsule Types as
opaque.
Unless otherwise specified, all Capsule Types are defined as opaque
to intermediaries.  Intermediaries MUST forward all received opaque
CAPSULE frames in their unmodified entirety.  Intermediaries MUST NOT
send any opaque CAPSULE frames other than the ones it is forwarding.
All Capsule Types defined in this document are opaque, with the
exception of the datagram capsules, see datagram-capsule.
Definitions of new Capsule Types MAY specify that the newly
introduced type is transparent.  Intermediaries MUST treat unknown
Capsule Types as opaque.
The REGISTER_DATAGRAM_CONTEXT capsule (see iana-types for the value
of the capsule type) allows an endpoint to inform its peer of the
encoding and semantics of datagrams associated with a given context
ID.
The context ID to register.
This document defines the REGISTER_DATAGRAM and
REGISTER_DATAGRAM_CONTEXT capsules types, known collectively as the
datagram registration capsules (see iana-types for the value of the
capsule types).  The REGISTER_DATAGRAM capsule is used by endpoints
to inform their peer of the encoding and semantics of all datagrams
associated with a stream.  The REGISTER_DATAGRAM_CONTEXT capsule is
used by endpoints to inform their peer of the encoding and semantics
of all datagrams associated with a given context ID on this stream.
A variable-length integer indicating the context ID to register
(see datagram-contexts).  This field is present in
REGISTER_DATAGRAM_CONTEXT capsules but not in REGISTER_DATAGRAM
capsules.  If a REGISTER_DATAGRAM capsule is used on a stream
where datagram contexts are in use, it is associated with context
ID 0.  REGISTER_DATAGRAM_CONTEXT capsules MUST NOT carry context
ID 0 as that context ID is conveyed using the REGISTER_DATAGRAM
capsule.
Note that these registrations are unilateral and bidirectional: the
sender of the frame unilaterally defines the semantics it will apply
to the datagrams it sends and receives using this context ID.  Once a
context ID is registered, it can be used in both directions.
Endpoints MUST NOT send DATAGRAM frames using a Context ID until they
have either sent or received a REGISTER_DATAGRAM_CONTEXT Capsule with
the same Context ID.  However, reordering can cause DATAGRAM frames
to be received with an unknown Context ID.  Receipt of such frames
MUST NOT be treated as an error.  Endpoints SHALL drop the DATAGRAM
frame silently, or buffer it temporarily while awaiting the
corresponding REGISTER_DATAGRAM_CONTEXT Capsule.  Intermediaries
SHALL drop the DATAGRAM frame silently, MAY buffer it, or forward it
on immediately.
Note that these registrations are unilateral and bidirectional: the
sender of the capsule unilaterally defines the semantics it will
apply to the datagrams it sends and receives using this context ID.
Once a context ID is registered, it can be used in both directions.
Endpoints MUST NOT send HTTP Datagrams until they have either sent or
received a datagram registration capsule with the same Context ID.
However, reordering can cause HTTP Datagrams to be received with an
unknown Context ID.  Receipt of such HTTP datagrams MUST NOT be
treated as an error.  Endpoints SHALL drop the HTTP Datagram
silently, or buffer it temporarily while awaiting the corresponding
datagram registration capsule.  Intermediaries SHALL drop the HTTP
Datagram silently, MAY buffer it, or forward it on immediately.
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.
The REGISTER_DATAGRAM_NO_CONTEXT capsule (see iana-types for the
value of the capsule type) allows a client to inform the server that
datagram contexts will not be used with this stream.  It also informs
the server of the encoding and semantics of datagrams associated with
this stream.
A variable-length integer that defines the semantics and encoding
of the HTTP Datagram Payload field of datagrams, see datagram-
formats.
This field carries additional information that impact the format
of datagrams, see datagram-formats.
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 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.
If datagrams contexts are not in use, the client is responsible for
choosing the datagram format and informing the server via a
REGISTER_DATAGRAM capsule.  Servers MUST NOT send the
REGISTER_DATAGRAM capsule.  If a client receives a REGISTER_DATAGRAM
capsule, the client MUST abruptly terminate the corresponding stream
with a stream error of type H3_GENERAL_PROTOCOL_ERROR.
After an endpoint has either sent or received a
CLOSE_DATAGRAM_CONTEXT frame, it MUST NOT send any DATAGRAM frames
with that Context ID.  However, due to reordering, an endpoint that
receives a DATAGRAM frame with a closed Context ID MUST NOT treat it
as an error, it SHALL instead drop the DATAGRAM frame silently.
After an endpoint has either sent or received a
CLOSE_DATAGRAM_CONTEXT frame, it MUST NOT send any HTTP Datagrams
with that Context ID.  However, due to reordering, an endpoint that
receives an HTTP Datagram with a closed Context ID MUST NOT treat it
as an error, it SHALL instead drop the HTTP Datagram silently.
The DATAGRAM capsule (see iana-types for the value of the capsule
type) allows an endpoint to send a datagram frame over an HTTP
stream.  This is particularly useful when using a version of HTTP
that does not support QUIC DATAGRAM frames.
Datagrams sent using the DATAGRAM Capsule have the exact same
semantics as datagrams sent in QUIC DATAGRAM frames.  In particular,
the restrictions on when it is allowed to send an HTTP Datagram and
how to process them from format also apply to HTTP Datagrams sent and
received using the DATAGRAM capsule.
The DATAGRAM Capsule is transparent to intermediaries, meaning that
intermediaries MAY parse it and send DATAGRAM Capsules that they did
not receive.  This allows an intermediary to reencode HTTP Datagrams
as it forwards them: in other words, an intermediary MAY send a
DATAGRAM Capsule to forward an HTTP Datagram which was received in a
QUIC DATAGRAM frame, and vice versa.
This document defines the DATAGRAM and DATAGRAM_WITH_CONTEXT capsules
types, known collectively as the datagram capsules (see iana-types
for the value of the capsule types).  These capsules allow an
endpoint to send a datagram frame over an HTTP stream.  This is
particularly useful when using a version of HTTP that does not
support QUIC DATAGRAM frames.
A variable-length integer indicating the context ID of the
datagram (see datagram-contexts).  This field is present in
DATAGRAM_WITH_CONTEXT capsules but not in DATAGRAM capsules.  If a
DATAGRAM capsule is used on a stream where datagram contexts are
in use, it is associated with context ID 0.  DATAGRAM_WITH_CONTEXT
capsules MUST NOT carry context ID 0 as that context ID is
conveyed using the DATAGRAM capsule.
Datagrams sent using the datagram capsule have the exact same
semantics as datagrams sent in QUIC DATAGRAM frames.  In particular,
the restrictions on when it is allowed to send an HTTP Datagram and
how to process them from format also apply to HTTP Datagrams sent and
received using the datagram capsules.
The datagram capsules are transparent to intermediaries, meaning that
intermediaries MAY parse them and send datagram capsules that they
did not receive.  This allows an intermediary to reencode HTTP
Datagrams as it forwards them: in other words, an intermediary MAY
send a datagram capsule to forward an HTTP Datagram which was
received in a QUIC DATAGRAM frame, and vice versa.
Endpoints indicate their support for datagram contexts by sending the
Sec-Use-Datagram-Contexts header with a value of ?1.  If the header
is missing or has a value different from ?1, that indicates that its
sender does not wish to use datagram contexts.  Endpoints that wish
to use datagram contexts SHALL send the Sec-Use-Datagram-Contexts
header with a value of ?1 on requests and responses that use the
capsule protocol.
The REGISTER_DATAGRAM_CONTEXT, DATAGRAM_WITH_CONTEXT, and
CLOSE_DATAGRAM_CONTEXT capsules as refered to as context-related
capsules.  Endpoints which do not wish to use contexts MUST NOT send
context-related capsules, and MUST silently ignore any received
context-related capsules.
Both endpoints unilaterally decide whether they wish to use datagram
contexts on a given stream.  Contexts are used on a given stream if
and only if both endpoints indicate they wish to use them on this
stream.  Once an endpoint has received the HTTP request or response,
it knows whether datagram contexts are in use on this stream or not.
Conceptually, when datagram contexts are not in use on a stream, all
datagrams use context ID 0, which is client-initiated.  This means
that the client chooses the datagram format for all datagrams when
datagram contexts are not in use.
If datagram contexts are not in use on a stream, endpoints MUST NOT
send context-related capsules to the peer on that stream.  Clients
MAY optimistically send context-related capsules before learning
whether the server wishes to support datagram contexts or not.
This allows a client to optimistically use extensions that rely on
datagram contexts without knowing a priori whether the server
supports them, and without incurring a latency cost to negotiate
extension support.  In this scenario, the client would send its
request with the Sec-Use-Datagram-Contexts header set to ?1, and
register two datagram contexts: the main context would use context ID
0 and the extension context would use context ID 2.  The client then
sends a REGISTER_DATAGRAM capsule to register the main context, and a
REGISTER_DATAGRAM_CONTEXT to register the extension context.  The
client can then immediately send DATAGRAM capsules to send main
datagrams and DATAGRAM_WITH_CONTEXT capsules to send extension
datagrams.
If the server wishes to use datagram contexts, it will set Sec-
Use-Datagram-Contexts to ?1 on its response and correctly parse
all the received capsules.
If the server does not wish to use datagram contexts (for example
if the server implementation does not support them), it will not
set Sec-Use-Datagram-Contexts to ?1 on its response.  It will then
parse the REGISTER_DATAGRAM and DATAGRAM capsules without datagram
contexts being in use on this stream, and parse the main datagrams
correctly while silently dropping the extension datagrams.  Once
the client receives the server's response, it will know datagram
contexts are not in use, and then will be able to send HTTP
Datagrams via the QUIC DATAGRAM frame.