and response do not carry HTTP content.  A future extension MAY define a new capsule type to carry HTTP content.  The Capsule Protocol MUST NOT be used with messages that contain Content-Length, Content-Type, or Transfer-Encoding header fields. Additionally, HTTP status codes 204 (No Content), 205 (Reset 3.3. <del> When an error occurs in processing the Capsule Protocol, the receiver MUST treat the message as malformed or incomplete, according to the underlying transport protocol.  For HTTP/3, the handling of malformed </del>  messages is described in H3.  For HTTP/2, the handling of malformed messages is described in H2.  For HTTP/1.1, the handling of incomplete messages is described in H1. Each capsule's payload MUST contain exactly the fields identified in its description.  A capsule payload that contains additional bytes after the identified fields or a capsule payload that terminates <del> before the end of the identified fields MUST be treated as a malformed or incomplete message.  In particular, redundant length </del>  encodings MUST be verified to be self-consistent. If the receive side of a stream carrying capsules is terminated cleanly (for example, in HTTP/3 this is defined as receiving a QUIC STREAM frame with the FIN bit set) and the last capsule on the stream <del> was truncated, this MUST be treated as a malformed or incomplete message. </del>  3.4.

Explicitly replicates parts of H2 and H3 CONNECT stream definition to make it clear what frame types are/are not allowed on a stream. Mostly anything else can't happen but if it does, approach error handling as if it were like a malformed message (I.e whether to terminate the stream or whatever).
Found it and fixed, thanks Martin!
In Sec 3.3: When an error occurs in processing the Capsule Protocol, the receiver MUST treat the message as malformed or incomplete... there are 2 other reference to malformed "messages" as a result of Capsule shenanigans. but in the introduction it says that datagrams "are not part of message content". So what is "the message" that should be treated this way? I think you mean the Request or Response that initiated the Capsule protocol. If that's correct, a more precise phrasing might be "MUST act as if the message that initiated the capsule protocol was malformed".
Agree we can probably tighten things up here. For one, the definition of "data stream" in 3.1 presently says In isolation, this statement leaves it a little unclear whether trailing headers can appear after the data stream. In , that defines how CONNECT works, things are a lot clearer: My working assumption has been that data streams have similar requirements, but we don't explicitly state that anywhere, which is not great. If we tighten that up then it should become clearer that, once the capsule protocol is successfully negotiated, the HTTP message ended after the first HEADERS frames. We would still expect endpoints to apply some rules to frame processing on these data streams, and if there was a problem the data stream is malformed. Today we equate malformed data streams to malformed requests, and therefore delegate the handling of such problems (reset stream + error code) to the respect section in H2 or H3. I wonder actually if we should just state some explicit stream termination requirements. This does not change the actions that endpoint might take, but it does clarify the circumstances under which they should happen. I'll prepare a PR for this to help illustrate my thinking. To summarise: 1) If an endpoint screws up meeting the requirements of request or response field sections that bootstrap a capsule protocol instance, that is clearly a standard "malformed message" 2) If, after a capsule protocol instance has successully been created, an endpoint screws up anything on the data stream, that does not seem like a "malformed message"
I can understand the impulse to avoid the term "stream" because then you're in the business of defining the behavior per HTTP version, but I'm sure you'll come up with some good language.
+1 to what Lucas said above

and response do not carry HTTP content.  A future extension MAY define a new capsule type to carry HTTP content. <ins> Since the Capsule Protocol only applies to definitions of new HTTP Upgrade Tokens, in HTTP/2 and HTTP/3 it can only be used with the CONNECT method.  Therefore, once both endpoints agree to use the Capsule Protocol, the frame usage requirements of the stream change as specified in H2 and H3. </ins> The Capsule Protocol MUST NOT be used with messages that contain Content-Length, Content-Type, or Transfer-Encoding header fields. Additionally, HTTP status codes 204 (No Content), 205 (Reset 3.3.  <ins> When a receiver encounters an error processing the Capsule Protocol, the receiver MUST treat it as if it had received a malformed or incomplete HTTP message.  For HTTP/3, the handling of malformed </ins> messages is described in H3.  For HTTP/2, the handling of malformed messages is described in H2.  For HTTP/1.1, the handling of incomplete messages is described in H1. Each capsule's payload MUST contain exactly the fields identified in its description.  A capsule payload that contains additional bytes after the identified fields or a capsule payload that terminates  <ins> before the end of the identified fields MUST be treated as it if were a malformed or incomplete message.  In particular, redundant length </ins> encodings MUST be verified to be self-consistent. If the receive side of a stream carrying capsules is terminated cleanly (for example, in HTTP/3 this is defined as receiving a QUIC STREAM frame with the FIN bit set) and the last capsule on the stream  <ins> was truncated, this MUST be treated as if it were a malformed or incomplete message. </ins> 3.4.


individual applications.  Note that this field can be empty. Endpoints MUST treat receipt of a DATAGRAM frame whose payload is too <del> short to parse the flow identifier as a connection error of type PROTOCOL_VIOLATION. </del>  5.

There's some good guidance about parsing the Flow ID out of the HTTP/3 Datagram with respect to datagram payload length. But I'm not sure if the recommend error code of PROTOCOLVIOLATION is the most appropriate. This implies that the error is a Transport Error but I'd argue that at this point (parsing of the frame payload) that its an HTTP/3 Application error. Since we're not actually parsing a true HTTP/3 frame, just a view over a transport frame, H3FRAMEERROR seems too specific. So I think H3GENERALPROTOCOLERROR is the most straightforward. I wonder what others think.
I honestly am fine with any error for this, though I'd prefer to reuse an existing one to reduce complexity.

individual applications.  Note that this field can be empty. Endpoints MUST treat receipt of a DATAGRAM frame whose payload is too  <ins> short to parse the flow identifier as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR. </ins> 5.


an HTTP request. When HTTP Datagrams are conveyed on an HTTP/3 connection, the QUIC <del> DATAGRAM frame can be used to achieve these goals, including unreliable delivery; see format.  Negotiating the use of QUIC DATAGRAM frames for HTTP Datagrams is achieved via the exchange of HTTP/3 settings; see setting. </del>  When running over HTTP/2, demultiplexing is provided by the HTTP/2 framing layer, but unreliable delivery is unavailable.  HTTP

To what does "these goals" refer? Original: When HTTP Datagrams are conveyed on an HTTP/3 connection, the QUIC DATAGRAM frame can be used to achieve these goals, including unreliable delivery; see
yeah, this text seems weird. Perhaps
Or how about simply
I made typos in my suggestion that doesn't help, sorry. IIRC the original text is a roundabout way of saying - we use a special payload in QUIC datagrams in order to achieve unreliable datagram multiplexing. This makes more sense in the context of the next that then states HTTP/2 frames provide demultiplexing.
Right, how about

an HTTP request. When HTTP Datagrams are conveyed on an HTTP/3 connection, the QUIC  <ins> DATAGRAM frame can be used to provide demultiplexing and unreliable delivery; see format.  Negotiating the use of QUIC DATAGRAM frames for HTTP Datagrams is achieved via the exchange of HTTP/3 settings; see setting. </ins> When running over HTTP/2, demultiplexing is provided by the HTTP/2 framing layer, but unreliable delivery is unavailable.  HTTP


If an HTTP/3 Datagram is received and its Quarter Stream ID maps to a stream that cannot be created due to client-initiated bidirectional stream limits, it SHOULD be treated as an HTTP/3 connection error of <del> type H3_ID_ERROR.  Generating an error is not mandatory in this case because HTTP/3 implementations might have practical barriers to determining the active stream concurrency limit that is applied by the QUIC layer. </del>  Prioritization of HTTP/3 Datagrams is not defined in this document. Future extensions MAY define how to prioritize datagrams and MAY

We suggest rephrasing this sentence. The phrase "might have practical barriers to determining..." is difficult to parse. Does the suggested text below accurately convey the intended meaning? Original: Generating an error is not mandatory in this case because HTTP/3 implementations might have practical barriers to determining the active stream concurrency limit that is applied by the QUIC layer. Perhaps: Generating an error is not mandatory in this case because HTTP/3 implementations might present practical barriers when determining the active stream concurrency limit that is applied by the QUIC layer.
The point we're making here is that the implementations might encounter barriers, either because they contain them, or the API the are using presents them. The suggestion doesn't cover these two response. Alternative Perhaps: Generating an error is not mandatory in this case because there might be practical barriers that prevent HTTP/3 implementations from determining the active stream concurrency at the QUIC layer.
How about we just nuke this sentence?
I've just rememberd this text is verbatim copied from URL ADs seem to like justifcations for SHOULD requirements. If we're worried about verbosity, then how about Generating an error is not mandatory because the QUIC stream limit may be unknown to the HTTP/3 layer.
That works for me

If an HTTP/3 Datagram is received and its Quarter Stream ID maps to a stream that cannot be created due to client-initiated bidirectional stream limits, it SHOULD be treated as an HTTP/3 connection error of  <ins> type H3_ID_ERROR.  Generating an error is not mandatory because the QUIC stream limit might be unknown to the HTTP/3 layer. </ins> Prioritization of HTTP/3 Datagrams is not defined in this document. Future extensions MAY define how to prioritize datagrams and MAY


possible for HTTP Upgrade or Extended CONNECT. The Capsule-Protocol header field MUST NOT be used on HTTP responses <del> with a status code that is both different from 101 and outside the 2xx range. </del>  When using the Capsule Protocol, HTTP endpoints SHOULD send the Capsule-Protocol header field to simplify intermediary processing.

In the following text, should the names of the status codes appear as they do in the rest of the document? Original: ...a status code that is both different from 101 and outside the 2xx range. Perhaps: ...a status code that is both different from 101 (Switching Protocols) and outside the 2xx (Successful) range.
solid improvement, let's do it
That sounds good to me

possible for HTTP Upgrade or Extended CONNECT. The Capsule-Protocol header field MUST NOT be used on HTTP responses  <ins> with a status code that is both different from 101 (Switching Protocols) and outside the 2xx (Successful) range. </ins> When using the Capsule Protocol, HTTP endpoints SHOULD send the Capsule-Protocol header field to simplify intermediary processing.


commonly accessed via JavaScript in web browsers). Definitions of new HTTP Upgrade Tokens that use the Capsule Protocol <del> need to perform a security analysis that considers the impact of HTTP </del>  Datagrams and Capsules in the context of their protocol. 5.

Is it really the Definition that performs the security analysis? Original: Definitions of new HTTP Upgrade Tokens that use the Capsule Protocol need to perform a security analysis that considers the impact of HTTP Datagrams and Capsules in the context of their protocol. Perhaps: Definitions of new HTTP Upgrade Tokens that use the Capsule Protocol need to include a security analysis that considers the impact of HTTP Datagrams and Capsules in the context of their protocol.
I prefer the RFC editor suggestion here.
Same, works for me

commonly accessed via JavaScript in web browsers). Definitions of new HTTP Upgrade Tokens that use the Capsule Protocol  <ins> need to include a security analysis that considers the impact of HTTP </ins> Datagrams and Capsules in the context of their protocol. 5.


unreliable delivery (such as when the QUIC DATAGRAM extension DGRAM is available to HTTP/3 H3), HTTP Datagrams can use that capability. <del> In capsule, this document describes the HTTP Capsule Protocol, which allows the conveyance of HTTP Datagrams using reliable delivery. This addresses HTTP/3 cases where use of the QUIC DATAGRAM frame is unavailable or undesirable or where the transport protocol only provides reliable delivery, such as with HTTP/1.1 H1 or HTTP/2 H2 over TCP TCP. </del>  1.1.

We had the following questions related to the descriptions of "HTTP Datagrams" in a few places throughout the text. a) We see the following similar sentences in the Abstract, Introduction, and , respectively. Please review and let us know if this text should be made more uniform. Original (Abstract): This document describes HTTP Datagrams, a convention for conveying multiplexed, potentially unreliable datagrams inside an HTTP connection. Original (Intro): In , this document describes HTTP Datagrams, a convention that supports the bidirectional and optionally multiplexed exchange of data inside an HTTP connection. Original (): HTTP Datagrams are a convention for conveying bidirectional and potentially unreliable datagrams inside an HTTP connection, with multiplexing when possible. b) Pending changes made in (a) above, we will update the first sentence of the Abstract as follows unless we hear objection Original: This document describes HTTP Datagrams, a convention for conveying multiplexed, potentially unreliable datagrams inside an HTTP connection. Perhaps: This document describes a convention for conveying multiplexed, potentially unreliable datagrams inside an HTTP connection called “HTTP Datagrams”. c) This sentence, which is somewhat related, seems a bit odd in that it seems sending something "unreliably" is desired. Should any clarification here be added? Original: In HTTP/3, HTTP Datagrams can be sent unreliably using the QUIC DATAGRAM extension.
a) I'm happy with the abstract being succinct. I think we could probably my the Intro and Section 2 more uniform. Suggest use Section 2 text in the intro. b) I'm not a huge fan of the scary quotes suggested here. I like what we have already TBH. c) This seems fine. No change needed IMO
Fully agree with your comments

unreliable delivery (such as when the QUIC DATAGRAM extension DGRAM is available to HTTP/3 H3), HTTP Datagrams can use that capability.  <ins> In capsule, this document describes HTTP Datagrams, a convention for conveying bidirectional and potentially unreliable datagrams inside an HTTP connection, with multiplexing when possible.  This addresses HTTP/3 cases where use of the QUIC DATAGRAM frame is unavailable or undesirable or where the transport protocol only provides reliable delivery, such as with HTTP/1.1 H1 or HTTP/2 H2 over TCP TCP. </ins> 1.1.


over QUIC with a mechanism to send unreliable data while leveraging the security and congestion-control properties of QUIC.  However, QUIC DATAGRAM frames do not provide a means to demultiplex <del> application contexts.  This document defines how to use QUIC DATAGRAM frames when the application protocol running over QUIC is HTTP/3 by adding an identifier at the start of the frame payload.  This allows HTTP messages to convey related information using unreliable DATAGRAM frames, ensuring those frames are properly associated with an HTTP message. </del>  Discussion of this work is encouraged to happen on the MASQUE IETF mailing list (masque@ietf.org [1]) or on the GitHub repository which running over QUIC QUIC with a mechanism to send unreliable data while leveraging the security and congestion-control properties of QUIC. However, QUIC DATAGRAM frames do not provide a means to demultiplex <del> application contexts.  This document defines how to use QUIC DATAGRAM frames when the application protocol running over QUIC is HTTP/3 H3 by adding an identifier at the start of the frame payload.  This allows HTTP messages to convey related information using unreliable DATAGRAM frames, ensuring those frames are properly associated with an HTTP message. </del>  This design mimics the use of Stream Types in HTTP/3, which provide a demultiplexing identifier at the start of each unidirectional stream. 2. <del> Flow identifiers represent bidirectional flows of datagrams within a single QUIC connection.  These are conceptually similar to streams in the sense that they allow multiplexing of application data.  Flows lack any of the ordering or reliability guarantees of streams. </del>  Beyond this, a sender SHOULD ensure that DATAGRAM frames within a single flow are transmitted in order relative to one another.  If multiple DATAGRAM frames can be packed into a single QUIC packet, the <del> sender SHOULD group them by flow identifier to promote fate-sharing within a specific flow and improve the ability to process batches of datagram messages efficiently on the receiver. </del>  3. Implementations of HTTP/3 that support the DATAGRAM extension MUST <del> provide a flow identifier allocation service.  That service will allow applications co-located with HTTP/3 to request a unique flow identifier that they can subsequently use for their own purposes. The HTTP/3 implementation will then parse the flow identifier of incoming DATAGRAM frames and use it to deliver the frame to the appropriate application. Even-numbered flow identifiers are client-initiated, while odd- numbered flow identifiers are server-initiated.  This means that an HTTP/3 client implementation of the flow identifier allocation service MUST only provide even-numbered identifiers, while a server implementation MUST only provide odd-numbered identifiers.  Note that, once allocated, any flow identifier can be used by both client and server - only allocation carries separate namespaces to avoid requiring synchronization. The flow allocation service SHOULD also provide a mechanism for applications to indicate they have completed their usage of a flow identifier and will no longer be using that flow identifier, this process is called "retiring" a flow identifier.  Applications MUST NOT retire a flow identifier until after they have received confirmation that the peer has also stopped using that flow identifier.  The flow identifier allocation service MAY reuse previously retired flow identifiers once they have ascertained that there are no packets with DATAGRAM frames using that flow identifier still in flight.  Reusing flow identifiers can improve performance by transmitting the flow identifier using a shorter variable-length integer encoding. </del>  4. frames uses the following format (using the notation from the "Notational Conventions" section of QUIC): <del> A variable-length integer indicating the Flow Identifier of the datagram (see flow-id). </del>  The payload of the datagram, whose semantics are defined by individual applications.  Note that this field can be empty. Endpoints MUST treat receipt of a DATAGRAM frame whose payload is too <del> short to parse the flow identifier as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR. </del>  5. 6. "Datagram-Flow-Id" is a List Structured Field STRUCT-FIELD, whose <del> members MUST all be Items of type Integer.  Its ABNF is: </del>  The "Datagram-Flow-Id" header field is used to associate one or more <del> datagram flow identifiers with an HTTP message.  As a simple example using a single identifier, the definition of an HTTP method could instruct the client to use its flow identifier allocation service to allocate a new flow identifier, and then the client will add the "Datagram-Flow-Id" header field to its request to communicate that value to the server.  In this example, the resulting header field could look like: List members are flow identifier elements, which can be named or unnamed.  One element in the list is allowed to be unnamed, but all but one elements MUST carry a name.  The name of an element is encoded in the key of the first parameter of that element (parameters are defined in Section 3.1.2 of STRUCT-FIELD).  Each name MUST NOT appear more than once in the list.  The value of the first parameter of each named element (whose corresponding key conveys the element name) MUST be of type Boolean and equal to true.  The value of the first parameter of the unnamed element MUST NOT be of type Boolean. The ordering of the list does not carry any semantics.  For example, an HTTP method that wishes to use four datagram flow identifiers for the lifetime of its request stream could look like this: In this example, 42 is the unnamed flow identifier, 44 represents the name "ecn-ect0", 46 represents "ecn-ect1", and 48 represents "ecn- ce".  Note that, since the list ordering does not carry semantics, this example can be equivalently encoded as: Even if a sender attempts to communicate the meaning of a flow identifier before it uses it in an HTTP/3 datagram, it is possible that its peer will receive an HTTP/3 datagram with a flow identifier that it does not know as it has not yet received the corresponding "Datagram-Flow-Id" header field.  (For example, this could happen if the QUIC STREAM frame that contains the "Datagram-Flow-Id" header field is reordered and arrives afer the DATAGRAM frame.)  Endpoints MUST NOT treat that scenario as an error; they MUST either silently discard the datagram or buffer it until they receive the "Datagram- Flow-Id" header field. Distinct HTTP requests MAY refer to the same flow identifier in their respective "Datagram-Flow-Id" header fields. </del>  Note that integer structured fields can only encode values up to 10^15-1, therefore the maximum possible value of an element of the "Datagram-Flow-Id" header field is lower then the theoretical maximum <del> value of a flow identifier which is 2^62-1 due to the QUIC variable length integer encoding.  If the flow identifier allocation service of an endpoint runs out of values lower than 10^15-1, the endpoint MUST fail the flow identifier allocation.  An HTTP message that carries a "Datagram-Flow-Id" header field with a flow identifier value above 10^15-1 is malformed (see Section 8.1.2.6 of H2). </del>  7. <del> HTTP/3 DATAGRAM flow identifiers are specific to a given HTTP/3 connection.  However, in some cases, an HTTP request may travel across multiple HTTP connections if there are HTTP intermediaries involved; see Section 2.3 of RFC7230. </del>  If an intermediary has sent the H3_DATAGRAM SETTINGS parameter with a value of 1 on its client-facing connection, it MUST inspect all HTTP intermediaries. If an intermediary processes distinct HTTP requests that refer to the <del> same flow identifier in their respective "Datagram-Flow-Id" header fields, it MUST ensure that those requests are routed to the same backend. </del>  8. 9.3. This document will request IANA to create an "HTTP Datagram Flow <del> Identifier Parameters" registry.  Registrations in this registry MUST include the following fields: </del>  The key of a parameter that is associated with a datagram flow <del> identifier list member (see header).  Keys MUST be valid structured field parameter keys (see Section 3.1.2 of STRUCT- FIELD). </del>  A brief description of the parameter semantics, which MAY be a summary if a specification reference is provided.

This somewhat of an experiment. While trying to address I got distracted by the document's use of the "flow identifier" term. The document likes to compare "flow identifiers" with QUIC streams, which is fine. But QUIC makes the distinction between streams and stream IDs; the ID is a property of the stream but it isn't the only one, and sometimes it helps to talk about the stream in other contexts. This change tries to channel a similar editorial style. It replaces: "flow identifiers" with "flows" when talking about a logical entitiy "flow identifiers" with "flow IDs" when talking about the wire format, encoding, examples etc. This could be a change too far but I figured it would be a good discussion starter.
The draft doesn't do this. It relies on the QUIC varint encoding for non-negativity in DATAGRAM frames but could contain a negative value. Let's be clear in the spec.
Definitely agree, could you write a PR please?
I will.
fixed in URL
Thanks!

over QUIC with a mechanism to send unreliable data while leveraging the security and congestion-control properties of QUIC.  However, QUIC DATAGRAM frames do not provide a means to demultiplex  <ins> application contexts.  This document describes how to use QUIC DATAGRAM frames when the application protocol running over QUIC is HTTP/3.  It defines logical flows identified by a non-negative integer that are present at the start of the DATAGRAM frame payload. Flows are associated with HTTP messages using the Datagram-Flow-Id header field, allowing endpoints to match unreliable DATAGRAMS frames to the HTTP messages that they are related to. </ins> Discussion of this work is encouraged to happen on the MASQUE IETF mailing list (masque@ietf.org [1]) or on the GitHub repository which running over QUIC QUIC with a mechanism to send unreliable data while leveraging the security and congestion-control properties of QUIC. However, QUIC DATAGRAM frames do not provide a means to demultiplex  <ins> application contexts.  This document describes how to use QUIC DATAGRAM frames when the application protocol running over QUIC is HTTP/3 H3.  It defines logical flows identified by a non-negative integer that are present at the start of the DATAGRAM frame payload. Flows are associated with HTTP messages using the Datagram-Flow-Id header field, allowing endpoints to match unreliable DATAGRAMS frames to the HTTP messages that they are related to. </ins> This design mimics the use of Stream Types in HTTP/3, which provide a demultiplexing identifier at the start of each unidirectional stream. 2.  <ins> Flows are bidirectional exchanges of datagrams within a single QUIC connection.  These are conceptually similar to streams in the sense that they allow multiplexing of application data.  Flows are identified within a connection by a numeric value, referred to as the flow ID.  A flow ID is a 62-bit integer (0 to 2^62-1). Flows lack any of the ordering or reliability guarantees of streams. </ins> Beyond this, a sender SHOULD ensure that DATAGRAM frames within a single flow are transmitted in order relative to one another.  If multiple DATAGRAM frames can be packed into a single QUIC packet, the  <ins> sender SHOULD group them by flow to promote fate-sharing within a specific flow and improve the ability to process batches of datagram messages efficiently on the receiver. </ins> 3. Implementations of HTTP/3 that support the DATAGRAM extension MUST  <ins> provide a flow ID allocation service.  That service will allow applications co-located with HTTP/3 to request a unique flow ID that they can subsequently use for their own purposes.  The HTTP/3 implementation will then parse the flow ID of incoming DATAGRAM frames and use it to deliver the frame to the appropriate application context. Even-numbered flow IDs are client-initiated, while odd-numbered flow IDs are server-initiated.  This means that an HTTP/3 client implementation of the flow ID allocation service MUST only provide even-numbered IDs, while a server implementation MUST only provide odd-numbered IDs.  Note that, once allocated, any flow ID can be used by both client and server - only allocation carries separate namespaces to avoid requiring synchronization. The flow ID allocation service SHOULD also provide a mechanism for applications to indicate they have completed their usage of a flow ID and will no longer be using that flow ID, this process is called "retiring" a flow ID.  Applications MUST NOT retire a flow ID until after they have received confirmation that the peer has also stopped using that flow ID.  The flow ID allocation service MAY reuse previously retired flow ID once they have ascertained that there are no packets with DATAGRAM frames using that flow ID still in flight. Reusing flow IDs can improve performance by transmitting the flow ID using a shorter variable-length integer encoding. </ins> 4. frames uses the following format (using the notation from the "Notational Conventions" section of QUIC):  <ins> A variable-length integer indicating the Flow ID of the datagram (see datagram-flows). </ins> The payload of the datagram, whose semantics are defined by individual applications.  Note that this field can be empty. Endpoints MUST treat receipt of a DATAGRAM frame whose payload is too  <ins> short to parse the flow ID as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR. </ins> 5. 6. "Datagram-Flow-Id" is a List Structured Field STRUCT-FIELD, whose  <ins> members MUST all be Items of type Integer.  Integers MUST be non- negative.  Its ABNF is: </ins> The "Datagram-Flow-Id" header field is used to associate one or more  <ins> datagram flows with an HTTP message.  As a simple example using a single flow, the definition of an HTTP method could instruct the client to use its flow ID allocation service to allocate a new flow ID, and then the client will add the "Datagram-Flow-Id" header field to its request to communicate that value to the server.  In this example, the resulting header field could look like: List members are flow ID elements, which can be named or unnamed. One element in the list is allowed to be unnamed, but all but one elements MUST carry a name.  The name of an element is encoded in the key of the first parameter of that element (parameters are defined in Section 3.1.2 of STRUCT-FIELD).  Each name MUST NOT appear more than once in the list.  The value of the first parameter of each named element (whose corresponding key conveys the element name) MUST be of type Boolean and equal to true.  The value of the first parameter of the unnamed element MUST NOT be of type Boolean.  The ordering of the list does not carry any semantics.  For example, an HTTP method that wishes to use four datagram flows for the lifetime of its request stream could look like this: In this example, 42 is the unnamed flow, 44 represents the name "ecn- ect0", 46 represents "ecn-ect1", and 48 represents "ecn-ce".  Note that, since the list ordering does not carry semantics, this example can be equivalently encoded as: Even if a sender attempts to communicate the meaning of a flow before it uses it in an HTTP/3 datagram, it is possible that its peer will receive an HTTP/3 datagram with a flow ID that it does not know as it has not yet received the corresponding "Datagram-Flow-Id" header field.  (For example, this could happen if the QUIC STREAM frame that contains the "Datagram-Flow-Id" header field is reordered and arrives afer the DATAGRAM frame.)  Endpoints MUST NOT treat that scenario as an error; they MUST either silently discard the datagram or buffer it until they receive the "Datagram-Flow-Id" header field. Distinct HTTP requests MAY refer to the same flow in their respective "Datagram-Flow-Id" header fields. </ins> Note that integer structured fields can only encode values up to 10^15-1, therefore the maximum possible value of an element of the "Datagram-Flow-Id" header field is lower then the theoretical maximum  <ins> value of a flow ID which is 2^62-1 due to the QUIC variable length integer encoding.  If the flow allocation service of an endpoint runs out of flow ID values lower than 10^15-1, the endpoint MUST fail the flow ID allocation.  An HTTP message that carries a "Datagram-Flow- Id" header field with a flow ID value above 10^15-1 is malformed (see Section 8.1.2.6 of H2). </ins> 7.  <ins> HTTP/3 DATAGRAM flows are specific to a given HTTP/3 connection. However, in some cases, an HTTP request may travel across multiple HTTP connections if there are HTTP intermediaries involved; see Section 2.3 of RFC7230. </ins> If an intermediary has sent the H3_DATAGRAM SETTINGS parameter with a value of 1 on its client-facing connection, it MUST inspect all HTTP intermediaries. If an intermediary processes distinct HTTP requests that refer to the  <ins> same flow ID in their respective "Datagram-Flow-Id" header fields, it MUST ensure that those requests are routed to the same backend. </ins> 8. 9.3. This document will request IANA to create an "HTTP Datagram Flow  <ins> Parameters" registry.  Registrations in this registry MUST include the following fields: </ins> The key of a parameter that is associated with a datagram flow  <ins> list member (see header).  Keys MUST be valid structured field parameter keys (see Section 3.1.2 of STRUCT-FIELD). </ins> A brief description of the parameter semantics, which MAY be a summary if a specification reference is provided.


2.1. Flow identifiers represent bidirectional flows of datagrams within a <del> single QUIC connection.  These are conceptually similar to UDP ports and allow basic demultiplexing of application data.  The primary role of flow identifiers is to provide a standard mechanism for demultiplexing application data flows, which may be destined for different processing threads in the application, akin to UDP sockets. </del>  Beyond this, a sender SHOULD ensure that DATAGRAM frames within a single flow are transmitted in order relative to one another.  If

The comparison to UDP sockets is not as good as a comparison to streams. UDP sockets are sometimes spun up in the fashion described, but they are also often a fixed thing, such as the socket that a DNS server listens on. That evokes the wrong model in which the caller chooses and there is some possibility of persistence.

2.1. Flow identifiers represent bidirectional flows of datagrams within a  <ins> single QUIC connection.  These are conceptually similar to streams in the sense that they allow multiplexing of application data.  Of course flows lack any of the ordering or reliability guarantees of streams. </ins> Beyond this, a sender SHOULD ensure that DATAGRAM frames within a single flow are transmitted in order relative to one another.  If


by both client and server - only allocation carries separate namespaces to avoid requiring synchronization. <del> The flow ID allocation service SHOULD also provide a mechanism for applications to indicate they have completed their usage of a flow ID and will no longer be using that flow ID, this process is called "retiring" a flow ID.  Applications MUST NOT retire a flow ID until after they have received confirmation that the peer has also stopped using that flow ID.  The flow ID allocation service MAY reuse previously retired flow ID once they have ascertained that there are no packets with DATAGRAM frames using that flow ID still in flight. Reusing flow IDs can improve performance by transmitting the flow ID using a shorter variable-length integer encoding. </del> 4. When used with HTTP/3, the Datagram Data field of QUIC DATAGRAM

introduced the following text: There are 2 problems with this, in each direction: In the send-direction, this can only be ascertained in the case of no packet loss, when all packets have been acknowledged. If any packet is not acknowledged, this could be due to this packet actually having been lost or just reordered delayed. While it's possible to ascertain that all sent packets have been acknowledged, this is not possible for packets sent by the peer. Reusing a flow identifier opens up an attack vector: An attacker could delay the delivery of a packet containing the old flow identifier until it has been retired and reused. This would lead to a reinterpretation of the DATAGRAM contents in a new application context.
If your HTTP/3 code is closely coupled with your QUIC code, this can be solved by looking at QUIC packet numbers. If we take the CONNECT-UDP example, receiving a RESETSTREAM frame for the CONNECT-UDP stream ensures that the peer will not send subsequent DATAGRAM frames with this flow ID. If you record the packet number of the packet that carried the RESETSTREAM frame, you can then drop any DATAGRAM frames with that flow ID whose packet number is lower. That solves both problems you've described.
It is not, my implementation separates the two layers. In the design of QUIC transport, we went a long way to avoid looking at the packet number at all. If this design principle applied to the transport, it should even more so apply to applications built on top of QUIC. That only applies for the server side, doesn't it? The client still wouldn't know if a packet it receives was sent before or after the ID was reassigned.
This feature is optional, so you could choose to not implement it. Or are you proposing a different mechanism that works? I agree that we shouldn't violate this design principle in the mandatory parts of the spec, but doing so in optional features seems acceptable to me. This isn't really about client or server, but more about who sent the RESETSTREAM frame. The receiver of RESETSTREAM can key on the packet number that carried that frame, whereas its peer can key on the packet number of the first acknowledgement for that RESET_STREAM.
How so? How do I prevent the peer from reusing a flow identifier? Actually, I'm not quite sure I understand the issue that NAME raised in . I see flow identifiers as analogues to stream IDs. For stream IDs, we never even considered reusing them, even though that wouldn't have required a layer violation in that case. Why are the 3 additional bytes (I'm assuming you're using fewer than 1073741823/2 identifiers on a typical connection, otherwise it's 7) too expensive in one case, but not the other?
Why would you want to prevent the peer from reusing a flow identifier? The peer ensures the security properties of reuse. Because the payload of DATAGRAM frames needs to fit in a single QUIC packet, whereas STREAM frames allows splitting the payload across packets. When you're tunneling, this means that the overhead impacts your MTU when using DATAGRAMs.
I'd like to raise the attention towards the idea that reliably supporting reuse of flow identifiers can become quite complicated when in large-scale installations. Consider a large scale point of presence, where a large number of servers are sharing the same public IPs: In such scenario, multiple datagrams that share the same flow identifier may be served by several distinct physical servers. In order for these servers to be able to route the datagrams in a consistent way, the flow id allocation service must be able to provide some sort of consistency guarantees: when the flow identifier expires, any server that may serve the flow needs to agree that the flow has indeed expired. In other words, there is a consensus problem lurking behind the scenes. While there are several ways to achieve such consensus, all share some propagation delay. Clients don't have a good way to estimating such delay (except for the observation that it's unlikely to be significantly shorter than the retransmit timeout). It may be worth at least mentioning that reusing the flow identifiers rapidly is not recommended. (edit: changed the wording that has mistakenly projected an argument as a known fact).
Hi NAME , this is an interesting scenario but I'm not sure I understand it: are you saying that multiple servers can send the same datagram flow ID on the same connection? How does that work? Given that QUIC uses incremental packet numbers as the encryption nonce, you're going to need a synchronization point in the server-to-client datapath anyway, or am I misunderstanding something?
Hi NAME I was probably unclear. It is also possible that I am missing something. Let me try to clarify my comment. EDIT: I have reformatted / rephrased and clarified the comment. Again, I may be missing something, and will be glad to learn more in this case. I think the main point of my comment - if the flow id is known to the applications, then it would be hard to communicate the retirement of the flow ID. In particular, in some situations it would be impossible for an endpoint to infer that a particular flow id has been successfully "retired" by the peer endpoint, because the application can retain the state associated with that flow id.
Maybe the draft isn't clear: the idea is that the application is responsible for knowing that the flow ID is no longer in use, and ensuring that the application on the peer also knows that it is no longer in use, before retiring it - the application tells the flow allocation service to retire, the flow allocation service doesn't do it on its own.

by both client and server - only allocation carries separate namespaces to avoid requiring synchronization.  4. When used with HTTP/3, the Datagram Data field of QUIC DATAGRAM


Flows lack any of the ordering or reliability guarantees of streams. Beyond this, a sender SHOULD ensure that DATAGRAM frames within a <del> single flow are transmitted in order relative to one another.  If multiple DATAGRAM frames can be packed into a single QUIC packet, the sender SHOULD group them by flow to promote fate-sharing within a specific flow and improve the ability to process batches of datagram messages efficiently on the receiver. </del>  3.

in Section 2 "Flow Identifiers" it reads this to me seems to be in conflict with the opening statement if the flow-id is in the DATAGRAM payload, the transport is not supposed to be peeking at it. While it could be a nice (but a bit hacky) optimization in a real-world implementation, I feel like the RFC having it as a SHOULD is not ideal.
In my experience, in order to build a high performance implementation of QUIC, you have to leverage the fact that layers can share information to improve performance. Are you saying that you'd prefer not using SHOULD for this kind of optimization?
I think Luca might have a point. If we consider this as a feature that a transport provides as a service, I don't really know what the service provides. There isn't another transport mechanism that relies on the ordering, or an interoperable aspect (would the other side be able to detect this?). It seems this is an aspect more about the API that QUIC provides, which is going to be a rich field of opportunity. There could be benefits but I don't know if we need to use the SHOULD. We could probably relax the language and try to articulate the benefits or tradeoffs of packetization and frame bundling. For instance, batching might interfere with timeliness, and controlling that might start creeping into prioritisation territory. The more I think about it, the described behaviour about batch processing might assume the receiver behaves a certain way, which might not be true. Therefore this might not be a good default to recommend.
Fair enough. Perhaps we remove this for now, and add guidance once we have more implementation/deployment experience?
I can live with a less drastic edit, leaving the text in draws the reader attention to the idea that packing could be important. I'd be happy to put together an editorial replacement for review, and if we hate it, then drop the concrete recommendation?
Thanks Lucas, you framed it way better than I could. Also I believe that whether shared-fate within a flow is desirable or not may depend on the application.
I came here looking for the same information: Why is fate-sharing desired? Is there some background to this?
I think more implementation and deployment experience would help here. I can see cases like tunneling IP flows containing TCP where fate sharing is preferable, since it's better to lose two adjacent packets in one flow than one packet each in two flows. But it seems a bit use-case specific? Also, you would expect most TCP segments to be large enough you couldn't put two into a single QUIC packet.

Flows lack any of the ordering or reliability guarantees of streams. Beyond this, a sender SHOULD ensure that DATAGRAM frames within a  <ins> single flow are transmitted in order relative to one another. </ins> 3.


wishes to use four datagram flows for the lifetime of its request stream could look like this: <del> In this example, 42 is the unnamed flow, 44 represents the name "ecn- ect0", 46 represents "ecn-ect1", and 48 represents "ecn-ce".  Note that, since the list ordering does not carry semantics, this example can be equivalently encoded as: </del>  Even if a sender attempts to communicate the meaning of a flow before it uses it in an HTTP/3 datagram, it is possible that its peer will

Currently, the Datagram-Flow-Id Header Field Definition section contains examples of the Datagram-Flow-Id header, which includes a 4-flow mechanism for conveying ECN information: This example seems to be tripping people up, myself included, by attempting to solve a problem of in-band signaling of non-UDP-payload bits by providing these streams, and drawing attention to that problem rather than the capability being described. I propose we remove this example until we have a better one to replace it. If we cannot find a good example, that also lends some evidence that perhaps we don't need the feature of creating multiple Datagram-Flow-Id associations in the same request.

wishes to use four datagram flows for the lifetime of its request stream could look like this:  <ins> In this example, 42 is the unnamed flow, 44 represents the name "foo", 46 represents "bar", and 48 represents "baz".  Note that, since the list ordering does not carry semantics, this example can be equivalently encoded as: </ins> Even if a sender attempts to communicate the meaning of a flow before it uses it in an HTTP/3 datagram, it is possible that its peer will


field, the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR. <del> If a DATAGRAM frame is received and its Quarter Stream ID maps to a stream that has already been closed, the receiver MUST silently drop that frame.  If a DATAGRAM frame is received and its Quarter Stream ID maps to a stream that has not yet been created, the receiver SHALL either drop that frame silently or buffer it temporarily while awaiting the creation of the corresponding stream. </del>  4. individual applications.  Note that this field can be empty. Datagrams sent using the DATAGRAM Capsule have the exact same <del> semantics as datagrams sent in QUIC DATAGRAM frames. </del>  5.

Minor editorial clarification.
H3 datagrams are associated with a stream, so it makes sense that it is only valid to send DATAGRAMs before sending the stream FIN. These packets may be received out of order however. What should receivers do with these packets? The simplest action for the receiver is to drop any datagrams received after FIN, but I can imagine applications where the receiver would prefer to allow them to be processed for some time. Should the draft offer guidance for this? The answer might be different if we use Flow IDs as connection scoped identifiers or the 2-layer approach (Stream ID+Flow ID) discussed at the interim.
I think this might be a case for "MUST NOT send datagram after the stream is closed for sending, MAY ignore datagrams if detected they are received after the stream is closed." The challenge I've seen for implementations is that the stream read and datagram read functions operate independently. Its hard to correlate any state or actions between the two. In my case, ACK'ing a packet containing a FIN doesn't mean anything about how the receiver application will read the stream data.
Thanks for filing this. I'll add text to address this after we switch to the two-layer approach (assuming that becomes official WG consensus)
The proposal here was receiver MAY drop a datagram after receiving FIN, but the merged PR has receiver MUST drop. I prefer MAY, since I can envision a use case where the receiver would rather wait for a period to allow wayward datagrams to arrive, rather than declaring everything lost because of minor reordering. Is there a strong objection to changing this MUST to a MAY?
NAME Can you provide an example of a use-case for not dropping a datagram which arrived after the stream was closed? I'm failing to imagine an application that would benefit from this.
"Naive Partial Reliability" or NPR: Client sends a request to the server indicating it is willing to accept the response body of an HTTP message over DATAGRAM rather than in the stream. Server sends the headers on the stream, and a marker indicating the response will come via DATAGRAMs (registering a context for this perhaps) Server sends DATAGRAMs containing the response body (and offsets) Server sends stream FIN The client receives the stream FIN before the DATAGRAMs because of reordering, and assumes all response body was lost. Datagrams arrive at client shortly thereafter and per are dropped.
HTTP/2 kind of has some similar issues. It makes statements like for a short period after a DATA or HEADERS frame containing an ENDSTREAM flag is sent. Until the remote peer receives and processes RSTSTREAM or the frame bearing the ENDSTREAM flag, it might send frames of these types. Endpoints MUST ignore WINDOWUPDATE or RSTSTREAM frames received in this state, though endpoints MAY choose to treat frames that arrive a significant time after sending ENDSTREAM as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. and elsewhere prioritization state for a period after streams become closed. The longer state is retained, the lower the chance that streams are assigned incorrect or default priority values.
OK this makes sense to me, I can tweak the text to allow keeping stream state around for slightly longer.
This improvement is good enough for me. Thanks.

field, the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR.  <ins> Endpoints MUST NOT send HTTP/3 datagrams unless the corresponding stream's send side is open.  If an HTTP/3 datagram is received and its Quarter Stream ID maps to a stream whose receive side has already been closed, the receiver MUST silently drop that datagram.  If an HTTP/3 datagram is received and its Quarter Stream ID maps to a stream that has not yet been created, the receiver SHALL either drop that datagram silently or buffer it temporarily while awaiting the creation of the corresponding stream. </ins> 4. individual applications.  Note that this field can be empty. Datagrams sent using the DATAGRAM Capsule have the exact same  <ins> semantics as datagrams sent in QUIC DATAGRAM frames.  In particular, the restrictions on when it is allowed to send an HTTP/3 datagram and how to process them from format also apply to HTTP/3 datagrams sent and received using the DATAGRAM capsule. </ins> 5.


6.  We can provide DATAGRAM support in HTTP/2 by defining the CAPSULE frame in HTTP/2. TODO: Refactor this document into "HTTP Datagrams" with definitions for HTTP/1.x, HTTP/2, and HTTP/3. <del> 7. </del>  Since this feature requires sending an HTTP/3 Settings parameter, it "sticks out".  In other words, probing clients can learn whether a the fact that there are applications using HTTP/3 datagrams enabled on this endpoint. <del> 8. </del>  <del> 8.1. </del>  This document will request IANA to register the following entry in the "HTTP/3 Frames" registry: <del> 8.2. </del>  This document will request IANA to register the following entry in the "HTTP/3 Settings" registry: <del> 8.3. </del>  This document establishes a registry for HTTP/3 frame type codes. The "HTTP Capsule Types" registry governs a 62-bit space. This registry initially contains the following entries: <del> 8.4. </del>  REGISTER_DATAGRAM_CONTEXT capsules carry key-value pairs, see register-capsule.  This document will request IANA to create an "HTTP Section 4.4 of IANA-POLICY) where two registrations MUST NOT have the same Key.  This registry is initially empty. <del> 9.  References </del>  <del> 9.1.  URIs </del>  [1] mailto:masque@ietf.org

Punt prioritization to extensions like QUIC and HTTP/3 did.
I think it's be valuable for h3-datagram to be able to use the new HTTP priority draft. I think it'd be ok to say that the datagram flow has the same prioritization as the request that initiated it. I don't think anything more complex is necessary, but I could be wrong.
That seems reasonable to me, assuming that we can get some implementations of this first. I suspect that we'll want this text to live in whichever gets published last between draft-ietf-masque-h3-datagram and .
The extensible priorities draft doesn't prioritise streams, it prioritizes responses. Is it sufficient that only a client can control the relative priority of datagrams coming back to it?
oh and FWIW as an editor on priorities, we are pretty close to a WGLC. If there's merit in saying something about datagrams and priorities, putting it here feels like the right thing.
Given the client already has the ability to control the relative priority of datagrams its sending, I think that's ok? Possibly there are use cases where the server wants to indicate a priority to the client as well? My strawman use case is tunneling multiple HTTP/3 connections: One goes to the origin, one goes to a static content server, ads, etc, and the client wants to receive data from the origin at a higher priority than the other data.
I think that is a good use case! I don't know if someone will turn around and say they really want to support that server control use case, I'm keen to hear strong proponents to really understand why. Making DATAGRAM priority based on streams aids parity between CONNECT and CONNECT-UDP cases. To your mind, would datagrams be prioritized against other datagrams and other streams? There's probably something to say here, especially the edge case where there is data to be sent non-incrementally on the stream AND the datagram flow. Something to consider is also that if we go ahead with a 2-layer approach, whether we want to expose per-flow priorities. Maybe that can be done by carrying the extensible priority value as an extension field in the flow creation message. Although it does sound a bit too much complexity.
I really hope we can avoid that, since it means the proxy/intermediary would have to deal with subflows, whereas currently it doesn't have to. Also, for most of the subflow use cases I've heard, I don't think that would be valuable or necessary.
Agree about the context/subflows things. Lets avoid that. For the bigger picture stuff I'd need to think on this some more. Perhaps a mildly flexible solution is to define an extensible priorities extension that would 1) explain some of the considerations into scheduling relative priorities between streams and datagrams 2) define a parameter to allow explicit setting of datagram flow priority. For example, to have an incremental stream at urgency 1 and incremental datagram at urgency 3 We could then state that omitting the parameter means the stream's priority is used. 3) by adding more params to we could even support explicit signalling of the wish for shared priority space, or segregated.
I'd say that defining a new prioritization parameter should be left to its own document, I'd prefer not to have this in h3-datagram itself
I agree its scope creep. I would be ok with this document saying very little and punting the problem to a (which I would entertain co-writing)
I think defining priorities of sub-flows would be useful in Ian's use case if you wanted to merge the priorities of streams within the tunneled QUIC connections at the entry proxy, rather that strictly prioritize one tunnel over another. One could do this by registering a context-ID for each priority level. This context-ID could be used by the intermediary (did I break the rules again?) to determine the priority of the datagram back towards the client.
I'm going to propose closing this issue with no action, with the intent to leave this functionality to extensions.
Adding text that says by default datagrams inherit the priority of the stream they are associated with seems likely to capture the most common cases. If we can't agree on that and want to punt, it would be good to indicate in the draft that priority of datagrams is undefined/implementation specific.
I'll would be happy with Alan's suggestion. I will prepare a PR unless someone beats me too it. Edit: suggestion to state that it is undefined
NAME stating that it is undefined sounds great to me.
I prefer it inherit the priority of the associated stream as NAME suggested.
I think that sounds like an easy suggestion but in practice doesn't help implementers. Inheriting the same signal doesn't really help the multiplexing scheduling conundrum - IMO trying to make any reasonable suggestion will tie up time in this document development that could be answered elsewhere.
If I'm an intermediary l7 load balancer, and support h3-datagram but am not looking deeper into the payload, I'm going to have to make scheduling decisions, so leaving it undefined could cause large differences in how h3-datagram based applications work on different intermediaries.
Right but that's the situation the base HTTP/3 specification has right now too. And even if the L7 balancer applies scheduling logic based on the extensible priorities draft, 1) it would need to decide how to schedule ingress data (request content) itself, since that is not defined 2) we have little experience about how to schedule datagram and stream data concurrently. I would expect implementers to turn around immediately and ask us how to do that if we say explicitly here that there is a datagram priority signal. I am not saying we punt the question indefinately. But in the interest of making progress here (especially to limit feature creep) I am suggesting we write a standalone document that can capture all the concerns as completely as is useful. If that draft makes rapid progress it might be a candidate for getting incorporated back into the H3 datagram specification. I would be happy to bootstrap that document in a new repo and work with Alan, Ian or other folks that can give some opinions.
+1 to NAME The more I think about this the more I believe that H3DGRAM has to match what H3 does - in a vacuum as an implementor I don't know how to implement "datagram should inherit priority of the corresponding stream" when no one has actually defined what a priority is. There are important questions like "should higher priority completely starve lower priority or not?" that are not answered by H3. H3DGRAM itself cannot depend on a given priorities extension, because we might define a different priorities scheme later. Having a separate draft that explains how to combine draft-ietf-masque-h3-datagram and draft-ietf-httpbis-priority sounds like the best option.

6. <ins> Prioritization of HTTP/3 datagrams is not defined in this document. Future extensions MAY define how to prioritize datagrams, and MAY define signaling to allow endpoints to communicate their prioritization preferences. 7. </ins> We can provide DATAGRAM support in HTTP/2 by defining the CAPSULE frame in HTTP/2. TODO: Refactor this document into "HTTP Datagrams" with definitions for HTTP/1.x, HTTP/2, and HTTP/3.  <ins> 8. </ins> Since this feature requires sending an HTTP/3 Settings parameter, it "sticks out".  In other words, probing clients can learn whether a the fact that there are applications using HTTP/3 datagrams enabled on this endpoint.  <ins> 9. </ins>  <ins> 9.1. </ins> This document will request IANA to register the following entry in the "HTTP/3 Frames" registry:  <ins> 9.2. </ins> This document will request IANA to register the following entry in the "HTTP/3 Settings" registry:  <ins> 9.3. </ins> This document establishes a registry for HTTP/3 frame type codes. The "HTTP Capsule Types" registry governs a 62-bit space. This registry initially contains the following entries:  <ins> 9.4. </ins> REGISTER_DATAGRAM_CONTEXT capsules carry key-value pairs, see register-capsule.  This document will request IANA to create an "HTTP Section 4.4 of IANA-POLICY) where two registrations MUST NOT have the same Key.  This registry is initially empty.  <ins> 10.  References </ins>  <ins> 10.1.  URIs </ins> [1] mailto:masque@ietf.org


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 <del> as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR. Intermediaries MUST ignore any HTTP/3 Datagram fields after the Quarter Stream ID. </del>  Endpoints parse both the Quarter Stream ID field and the Context ID field in order to associate the QUIC DATAGRAM frame with a stream and MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR.  4.3. The CLOSE_DATAGRAM_CONTEXT capsule (type=0x01) allows an endpoint to

Contexts are end-to-end, and intermediaries MUST NOT parse them.
In , capsules, contexts and context IDs are explicitly defined as end-to-end and there are requirements for intermediaries to not modify them, and to not even parse them. The motivation for this was to ensure that we retain the ability to deploy extensions end-to-end without having to modify intermediaries. NAME mentioned that these requirements might be too strict, as he would like to have his intermediary be able to parse the context ID, for logging purposes.
Part of the comment from the PR is also about consistency of interface for generic HTTP libraries that can be used to build either endpoints or intermediaries. If the context ID is always present, it's overly prescriptive to say that an intermediary can't parse it, and such a requirement couldn't be enforced anyways. If context IDs are negotiated on/off, whether this is possible depends on the negotiation mechanism.
I think its fine for a component that has bytes passing through it to look at those bytes. The import thing to do is set expectations on what that means for the protocol behaviour we are defining. We don't expect intermediaries to do anything with a context ID; they should not enforce the protocol semantic rules (odd, even, reuse etc). H2 and H3 somewhat solve this problem by decoupling frame parsing from frame payload interpretation. E.g. if the form of a request or response is invalid, an intermediary shouldn't pass it on. DATAGRAM is different because it isn't defined as an actual HTTP/3 frame with frame headers and frame payload. Something that might work is to formalise that quarter stream ID is part of the envelope that intermediaries have to be able to handle the syntax of, but context ID is part of content and separate.
Unless you encrypt capsules end-to-end, I don't think any text in the spec can in practice prevent intermediaries from inspecting and modifying capsules. You can send something like GREASE capsules, though.
LGTM! :shipit:

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  <ins> as an HTTP/3 connection error of type H3_GENERAL_PROTOCOL_ERROR.  The Context ID field is optional and its use is negotiated end-to-end, 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. </ins> Endpoints parse both the Quarter Stream ID field and the Context ID field in order to associate the QUIC DATAGRAM frame with a stream and MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR. <ins> Extensions MAY define a different mechanism to negotiate the presence of contexts, and they MAY do so in a way which is opaque to intermediaries. </ins> 4.3. The CLOSE_DATAGRAM_CONTEXT capsule (type=0x01) allows an endpoint to


The context ID to register. <del> A string of comma-separated key-value pairs to enable extensibility.  Keys are registered with IANA, see iana-keys. The ABNF for the Extension String field is as follows (using syntax from Section 3.2.6 of RFC7230): </del>  Note that these registrations are unilateral and bidirectional: the sender of the frame unilaterally defines the semantics it will apply semantics of datagrams associated with this stream.  Its Capsule Data field consists of: <del> A string of comma-separated key-value pairs to enable extensibility, see the definition of the same field in register- capsule for details. </del>  Note that this registration is unilateral and bidirectional: the client unilaterally defines the semantics it will apply to the The context ID to close. <del> A string of comma-separated key-value pairs to enable extensibility, see the definition of the same field in register- capsule for details. </del>  Note that this close is unilateral and bidirectional: the sender of the frame unilaterally informs its peer of the closure.  Endpoints initially registered by either themselves, or by their peer. Endpoints MAY use the CLOSE_DATAGRAM_CONTEXT capsule to immediately reject a context that was just registered using a <del> REGISTER_DATAGRAM_CONTEXT capsule if they find its Extension String to be unacceptable. </del>  After an endpoint has either sent or received a CLOSE_DATAGRAM_CONTEXT frame, it MUST NOT send any DATAGRAM frames MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR.  4.4. The DATAGRAM capsule (type=0x02) allows an endpoint to send a 5.  Implementations of HTTP/3 that support this mechanism can indicate that to their peer by sending the H3_DATAGRAM SETTINGS parameter with a value of 1.  The value of the H3_DATAGRAM SETTINGS parameter MUST the connection with error H3_SETTINGS_ERROR.  In all cases, the maximum permitted value of the H3_DATAGRAM SETTINGS parameter is 1. <del> 6. </del>  Prioritization of HTTP/3 datagrams is not defined in this document. Future extensions MAY define how to prioritize datagrams, and MAY define signaling to allow endpoints to communicate their prioritization preferences. <del> 7. </del>  We can provide DATAGRAM support in HTTP/2 by defining the CAPSULE frame in HTTP/2. TODO: Refactor this document into "HTTP Datagrams" with definitions for HTTP/1.x, HTTP/2, and HTTP/3. <del> 8. </del>  Since this feature requires sending an HTTP/3 Settings parameter, it "sticks out".  In other words, probing clients can learn whether a the fact that there are applications using HTTP/3 datagrams enabled on this endpoint. <del> 9. </del>  <del> 9.1. </del>  This document will request IANA to register the following entry in the "HTTP/3 Frames" registry: <del> 9.2. </del>  This document will request IANA to register the following entry in the "HTTP/3 Settings" registry: <del> 9.3. </del>  <del> This document establishes a registry for HTTP/3 frame type codes. </del>  The "HTTP Capsule Types" registry governs a 62-bit space. Registrations in this registry MUST include the following fields: This registry initially contains the following entries: <del> 9.4. </del>  <del> REGISTER_DATAGRAM_CONTEXT capsules carry key-value pairs, see register-capsule.  This document will request IANA to create an "HTTP Datagram Context Extension Keys" registry.  Registrations in this registry MUST include the following fields: </del>  <del> The key (see register-capsule).  Keys MUST be valid tokens as defined in Section 3.2.6 of RFC7230. </del>  <del> A brief description of the key semantics, which MAY be a summary if a specification reference is provided. </del>  An optional reference to a specification for the parameter.  This field MAY be empty. Registrations follow the "First Come First Served" policy (see Section 4.4 of IANA-POLICY) where two registrations MUST NOT have the <del> same Key.  This registry is initially empty. </del>  <del> 10.  References </del>  <del> 10.1.  URIs </del>  [1] mailto:masque@ietf.org

This PR adds a new concept of context close codes which will allow applications that use contexts to indicate the reason for closing a context. This PR also makes the extensibility mechanism binary as that is easier to implement.
In , we introduce the CLOSEDATAGRAMCONTEXT capsule which allows endpoints to close a context. That message currently only contains the context ID to close. NAME suggests that we may want to add more information there. Should we differentiate between "context close" and "context registration rejected"? Should we add an error code? In particular, do folks have use cases for these features?
My first concern is with infinite loops. If the context was "garbage collected" by the recipient, the sender can simply re-create it if they still want it. However, if it was closed due to incompatibility (i.e. rejected) or hitting a resource limit (e.g. max # of contexts), reopening it in response will produce a tight infinite loop. This could be maybe be avoided by some kind of heuristic, but an explicit indication of what's going on seems better.
LGTM thanks

The context ID to register.  <ins> See context-ext. </ins> Note that these registrations are unilateral and bidirectional: the sender of the frame unilaterally defines the semantics it will apply semantics of datagrams associated with this stream.  Its Capsule Data field consists of:  <ins> See context-ext. </ins> Note that this registration is unilateral and bidirectional: the client unilaterally defines the semantics it will apply to the The context ID to close.  <ins> See context-ext. </ins> Note that this close is unilateral and bidirectional: the sender of the frame unilaterally informs its peer of the closure.  Endpoints initially registered by either themselves, or by their peer. Endpoints MAY use the CLOSE_DATAGRAM_CONTEXT capsule to immediately reject a context that was just registered using a  <ins> REGISTER_DATAGRAM_CONTEXT capsule if they find its Context Extensions field to be unacceptable. </ins> After an endpoint has either sent or received a CLOSE_DATAGRAM_CONTEXT frame, it MUST NOT send any DATAGRAM frames MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR. <ins> All CLOSE_DATAGRAM_CONTEXT capsules MUST contain a CLOSE_CODE context extension, see close-code.  If an endpoint receives a CLOSE_DATAGRAM_CONTEXT capsule without a CLOSE_CODE context extension, the endpoint MUST abruptly terminate the corresponding stream with a stream error of type H3_GENERAL_PROTOCOL_ERROR. </ins> 4.4. The DATAGRAM capsule (type=0x02) allows an endpoint to send a 5. <ins> In order to facilitate extensibility of contexts, the REGISTER_DATAGRAM_CONTEXT, REGISTER_DATAGRAM_NO_CONTEXT, and the CLOSE_DATAGRAM_CONTEXT capsules carry a Context Extensions field. That field contains a sequence of context extensions: Each context extension is encoded as a (type, length, value) tuple: Context Extension Types are registered with IANA, see iana-ext-types. The Context Extension Length field contains the length of the Context Extension Value field in bytes.  The semantics of the Context Extension Value field are defined by the corresponding Context Extension Type. 5.1. The CLOSE_CODE context extension type (type=0x00) allows an endpoint to provide additional information as to why a datagram context was closed.  This type SHALL only be sent in CLOSE_DATAGRAM_CONTEXT capsules.  Its Context Extension Value field consists of a single variable-length integer which contains the close code.  The following codes are defined: This indicates that the registration was closed without any additional information. This indicates that the sender has rejected the context registration based on its local policy.  The endpoint that had originally registered this context MUST NOT try to register another context with the same context extensions on this stream. This indicates that the context was closed to save resources.  The recipient SHOULD limit its future registration of resource- incentive contexts. Receipt of an unknown close code MUST be treated as if the NO_ERROR code was present.  Close codes are registered with IANA, see iana- close-codes. 5.2. The DETAILS context extension type (type=0x01) allows an endpoint to provide additional details to context capsules.  It is meant for debugging purposes.  Its Context Extension Value field consists of a human-readable string encoded in UTF-8. 6. </ins> Implementations of HTTP/3 that support this mechanism can indicate that to their peer by sending the H3_DATAGRAM SETTINGS parameter with a value of 1.  The value of the H3_DATAGRAM SETTINGS parameter MUST the connection with error H3_SETTINGS_ERROR.  In all cases, the maximum permitted value of the H3_DATAGRAM SETTINGS parameter is 1.  <ins> 7. </ins> Prioritization of HTTP/3 datagrams is not defined in this document. Future extensions MAY define how to prioritize datagrams, and MAY define signaling to allow endpoints to communicate their prioritization preferences.  <ins> 8. </ins> We can provide DATAGRAM support in HTTP/2 by defining the CAPSULE frame in HTTP/2. TODO: Refactor this document into "HTTP Datagrams" with definitions for HTTP/1.x, HTTP/2, and HTTP/3.  <ins> 9. </ins> Since this feature requires sending an HTTP/3 Settings parameter, it "sticks out".  In other words, probing clients can learn whether a the fact that there are applications using HTTP/3 datagrams enabled on this endpoint.  <ins> 10. </ins>  <ins> 10.1. </ins> This document will request IANA to register the following entry in the "HTTP/3 Frames" registry:  <ins> 10.2. </ins> This document will request IANA to register the following entry in the "HTTP/3 Settings" registry:  <ins> 10.3. </ins>  <ins> This document establishes a registry for HTTP/3 capsule type codes. </ins> The "HTTP Capsule Types" registry governs a 62-bit space. Registrations in this registry MUST include the following fields: This registry initially contains the following entries:  <ins> 10.4. This document establishes a registry for HTTP/3 datagram context extension type codes.  The "HTTP Context Extension Types" registry governs a 62-bit space.  Registrations in this registry MUST include the following fields: Type: A name or label for the context extension type. The value of the Context Extension Type field (see context-ext) is a 62bit integer. An optional reference to a specification for the parameter.  This field MAY be empty. Registrations follow the "First Come First Served" policy (see Section 4.4 of IANA-POLICY) where two registrations MUST NOT have the same Type nor Value. This registry initially contains the following entries: 10.5. This document establishes a registry for HTTP/3 context extension type codes.  The "HTTP Context Close Codes" registry governs a 62-bit space.  Registrations in this registry MUST include the following fields: </ins>  <ins> Type: </ins>  <ins> A name or label for the close code. </ins>  <ins> The value of the CLOSE_CODE Context Extension Value field (see close-code) is a 62bit integer. </ins> An optional reference to a specification for the parameter.  This field MAY be empty. Registrations follow the "First Come First Served" policy (see Section 4.4 of IANA-POLICY) where two registrations MUST NOT have the  <ins> same Type nor Value. This registry initially contains the following entries: </ins>  <ins> 11.  References </ins>  <ins> 11.1.  URIs </ins> [1] mailto:masque@ietf.org


with a stream error of type H3_GENERAL_PROTOCOL_ERROR. Endpoints MUST NOT send HTTP/3 datagrams unless the corresponding <del> stream's send side is open.  If an HTTP/3 datagram is received and its Quarter Stream ID maps to a stream whose receive side has already been closed, the receiver MUST silently drop that datagram.  If an HTTP/3 datagram is received and its Quarter Stream ID maps to a </del>  stream that has not yet been created, the receiver SHALL either drop that datagram silently or buffer it temporarily while awaiting the creation of the corresponding stream.

H3 datagrams are associated with a stream, so it makes sense that it is only valid to send DATAGRAMs before sending the stream FIN. These packets may be received out of order however. What should receivers do with these packets? The simplest action for the receiver is to drop any datagrams received after FIN, but I can imagine applications where the receiver would prefer to allow them to be processed for some time. Should the draft offer guidance for this? The answer might be different if we use Flow IDs as connection scoped identifiers or the 2-layer approach (Stream ID+Flow ID) discussed at the interim.
I think this might be a case for "MUST NOT send datagram after the stream is closed for sending, MAY ignore datagrams if detected they are received after the stream is closed." The challenge I've seen for implementations is that the stream read and datagram read functions operate independently. Its hard to correlate any state or actions between the two. In my case, ACK'ing a packet containing a FIN doesn't mean anything about how the receiver application will read the stream data.
Thanks for filing this. I'll add text to address this after we switch to the two-layer approach (assuming that becomes official WG consensus)
The proposal here was receiver MAY drop a datagram after receiving FIN, but the merged PR has receiver MUST drop. I prefer MAY, since I can envision a use case where the receiver would rather wait for a period to allow wayward datagrams to arrive, rather than declaring everything lost because of minor reordering. Is there a strong objection to changing this MUST to a MAY?
NAME Can you provide an example of a use-case for not dropping a datagram which arrived after the stream was closed? I'm failing to imagine an application that would benefit from this.
"Naive Partial Reliability" or NPR: Client sends a request to the server indicating it is willing to accept the response body of an HTTP message over DATAGRAM rather than in the stream. Server sends the headers on the stream, and a marker indicating the response will come via DATAGRAMs (registering a context for this perhaps) Server sends DATAGRAMs containing the response body (and offsets) Server sends stream FIN The client receives the stream FIN before the DATAGRAMs because of reordering, and assumes all response body was lost. Datagrams arrive at client shortly thereafter and per are dropped.
HTTP/2 kind of has some similar issues. It makes statements like for a short period after a DATA or HEADERS frame containing an ENDSTREAM flag is sent. Until the remote peer receives and processes RSTSTREAM or the frame bearing the ENDSTREAM flag, it might send frames of these types. Endpoints MUST ignore WINDOWUPDATE or RSTSTREAM frames received in this state, though endpoints MAY choose to treat frames that arrive a significant time after sending ENDSTREAM as a connection error (Section 5.4.1) of type PROTOCOL_ERROR. and elsewhere prioritization state for a period after streams become closed. The longer state is retained, the lower the chance that streams are assigned incorrect or default priority values.
OK this makes sense to me, I can tweak the text to allow keeping stream state around for slightly longer.

with a stream error of type H3_GENERAL_PROTOCOL_ERROR. Endpoints MUST NOT send HTTP/3 datagrams unless the corresponding  <ins> stream's send side is open.  On a given endpoint, once the receive side of a stream is closed, incoming datagrams for this stream are no longer expected so the endpoint can release related state.  Endpoints MAY keep state for a short time to account for reordering.  Once the state is released, the endpoint MUST silently drop received associated datagrams. If an HTTP/3 datagram is received and its Quarter Stream ID maps to a </ins> stream that has not yet been created, the receiver SHALL either drop that datagram silently or buffer it temporarily while awaiting the creation of the corresponding stream.