Code change:
6. <del> "Datagram-Flow-Id" is a List Structured Field STRUCT-FIELD, whose members MUST all be Items of type Integer.  Integers MUST be non- negative.  Its ABNF is: The "Datagram-Flow-Id" header field is used to associate one or more 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 "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: 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. 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 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). </del> <ins> We can provide DATAGRAM support in HTTP/2 by defining the CAPSULE frame in HTTP/2. </ins> <del> 7. </del> <ins> We can provide DATAGRAM support in HTTP/1.x by defining its data stream format to a sequence of length-value capsules. </ins> <del> 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. 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 requests from that connection and check for the presence of the "Datagram-Flow-Id" header field.  If the HTTP method of the request is not supported by the intermediary, it MUST remove the "Datagram- Flow-Id" header field before forwarding the request.  If the intermediary supports the method, it MUST either remove the header field or adhere to the requirements leveraged by that method on intermediaries. If an intermediary has sent the H3_DATAGRAM SETTINGS parameter with a value of 1 on its server-facing connection, it MUST inspect all HTTP responses from that connection and check for the presence of the "Datagram-Flow-Id" header field.  If the HTTP method of the request is not supported by the intermediary, it MUST remove the "Datagram- Flow-Id" header field before forwarding the response.  If the intermediary supports the method, it MUST either remove the header field or adhere to the requirements leveraged by that method on intermediaries. If an intermediary processes distinct HTTP requests that refer to the same flow ID in their respective "Datagram-Flow-Id" header fields, it MUST ensure that those requests are routed to the same backend. </del> <ins> TODO: Refactor this document into "HTTP Datagrams" with definitions for HTTP/1.x, HTTP/2, and HTTP/3. </ins> <del> 8. </del> <ins> 7. </ins> Since this feature requires sending an HTTP/3 Settings parameter, it "sticks out".  In other words, probing clients can learn whether a

Related discussion:
text: 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.
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.
This issue assumes that decide to go with the two-layer design described in . Given that design, some applications might not need the multiplexing provided by context IDs. We have multiple options here: Make context ID mandatory Applications that don't need it waste a byte per datagram Negotiate the presence of context IDs using an HTTP header Context IDs would still be mandatory to implement on servers because the client might send that header Have the method determine whether context IDs are present or not This would prevent extensibility on those methods Create a REGISTERNOCONTEXT message This assumes we use the Message design from We add a register message that means that this stream does not use context IDs This allows avoiding the byte overhead without sacrificing extensibility
Making the context ID mandatory is simple, although slightly wasteful. For the variations where it is optional, I prefer the one that uses a header. It could work with a variant of where we do Header + Message, and the Header determines whether or not you have contexts, and whether or not they can be dynamic.
What are the benefits of message over header to make it optional?