<del> The CONNECT-UDP HTTP Method </del>  draft-ietf-masque-connect-udp-latest Abstract <del> This document describes the CONNECT-UDP HTTP method.  CONNECT-UDP is similar to the HTTP CONNECT method, but it uses UDP instead of TCP. </del>  1. <del> This document describes the CONNECT-UDP HTTP method.  CONNECT-UDP is similar to the HTTP CONNECT method (see section 4.3.6 of RFC7231), but it uses UDP UDP instead of TCP TCP. </del>  1.1. as shown here. In this document, we use the term "proxy" to refer to the HTTP server <del> that opens the UDP socket and responds to the CONNECT-UDP request. If there are HTTP intermediaries (as defined in Section 2.3 of RFC7230) between the client and the proxy, those are referred to as </del>  "intermediaries" in this document.  2. <del> The CONNECT-UDP method is defined for all versions of HTTP.  UDP payloads are sent using HTTP Datagrams HTTP-DGRAM.  Note that, when the HTTP version in use does not support multiplexing streams (such as HTTP/1.1), then any reference to "stream" in this document is meant to represent the entire connection. </del>  3. <del> The CONNECT-UDP method requests that the recipient establish a tunnel over a single HTTP stream to the destination origin server identified by the request-target and, if successful, thereafter restrict its behavior to blind forwarding of packets, in both directions, until the tunnel is closed.  Tunnels are commonly used to create an end-to- end virtual connection, which can then be secured using QUIC QUIC or another protocol running over UDP. </del>  <del> The request-target of a CONNECT-UDP request is a URI RFC3986 which uses the "masque" scheme and an immutable path of "/".  For example: </del>  <del> When using HTTP/2 H2 or later, CONNECT-UDP requests use HTTP pseudo- headers with the following requirements: </del>  <del> The ":method" pseudo-header field is set to "CONNECT-UDP". </del>  <del> The ":scheme" pseudo-header field is set to "masque". </del>  <del> The ":path" pseudo-header field is set to "/". </del>  <del> The ":authority" pseudo-header field contains the host and port to connect to (similar to the authority-form of the request-target of CONNECT requests; see RFC7230, Section 5.3). </del>  <del> A CONNECT-UDP request that does not conform to these restrictions is malformed (see H2, Section 8.1.2.6). </del>  <del> The recipient proxy establishes a tunnel by directly opening a UDP socket to the request-target.  Any 2xx (Successful) response indicates that the proxy has opened a socket to the request-target and is willing to proxy UDP payloads.  Any response other than a successful response indicates that the tunnel has not yet been formed. </del>  <del> A proxy MUST NOT send any Transfer-Encoding or Content-Length header fields in a 2xx (Successful) response to CONNECT-UDP.  A client MUST treat a response to CONNECT-UDP containing any Content-Length or Transfer-Encoding header fields as malformed. </del>  <del> A payload within a CONNECT-UDP request message has no defined semantics; a CONNECT-UDP request with a non-empty payload is malformed. </del>  <del> Responses to the CONNECT-UDP method are not cacheable. </del>  4. UDP packets are encoded using HTTP Datagrams HTTP-DGRAM.  The payload of a UDP packet (referred to as "data octets" in UDP) is sent unmodified in the "HTTP Datagram Payload" field of an HTTP Datagram. <del> In order to use HTTP Datagrams, the CONNECT-UDP client will first decide whether or not to use HTTP Datagram Contexts and then register its context ID (or lack thereof) using the corresponding registration capsule, see HTTP-DGRAM. Since HTTP Datagrams require prior negotiation (for example, in HTTP/3 it is necessary to both send and receive the H3_DATAGRAM SETTINGS Parameter), clients MUST NOT send any HTTP Datagrams until they have established support on a given connection. The proxy that is creating the UDP socket to the destination responds to the CONNECT-UDP request with a 2xx (Successful) response. </del>  Clients MAY optimistically start sending proxied UDP packets before <del> receiving the response to its CONNECT-UDP request, noting however </del>  that those may not be processed by the proxy if it responds to the <del> CONNECT-UDP request with a failure, or if the datagrams arrive before the CONNECT-UDP request. </del>  <del> Extensions to CONNECT-UDP MAY leverage the "Context Extensions" field of registration capsules in order to negotiate different semantics or encoding for UDP payloads. </del>  5. <del> Unlike TCP, UDP is connection-less.  The proxy that opens the UDP socket has no way of knowing whether the destination is reachable. Therefore it needs to respond to the CONNECT-UDP request without waiting for a TCP SYN-ACK. Proxies can use connected UDP sockets if their operating system supports them, as that allows the proxy to rely on the kernel to only send it UDP packets that match the correct 5-tuple.  If the proxy uses a non-connected socket, it MUST validate the IP source address and UDP source port on received packets to ensure they match the client's CONNECT-UDP request.  Packets that do not match MUST be discarded by the proxy. The lifetime of the socket is tied to the CONNECT-UDP stream.  The proxy MUST keep the socket open while the CONNECT-UDP stream is open. Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close the CONNECT-UDP stream before closing the socket. If a proxy is notified by its operating system that its socket is no longer usable, it MUST close the CONNECT-UDP stream. 6. </del> Proxies SHOULD strive to avoid increasing burstiness of UDP traffic: they SHOULD NOT queue packets in order to increase batching. control unless it has an out-of-band way of knowing with absolute certainty that the inner traffic is congestion-controlled. <del> If a client or proxy with a connection containing a CONNECT-UDP stream disables congestion control, it MUST NOT signal ECN support on that connection.  That is, it MUST mark all IP headers with the Not- ECT codepoint.  It MAY continue to report ECN feedback via ACK_ECN frames, as the peer may not have disabled congestion control. </del>  When the protocol running over UDP that is being proxied uses loss recovery (e.g., QUIC), and the underlying HTTP connection runs over independently retransmit the same data.  To avoid this, HTTP/3 datagrams SHOULD be used. <del> 6.1. </del>  <del> CONNECT-UDP does not create an IP-in-IP tunnel, so the guidance in </del>  RFC6040 about transferring ECN marks between inner and outer IP <del> headers does not apply.  There is no inner IP header in CONNECT-UDP </del>  tunnels. <del> Note that CONNECT-UDP clients do not have the ability in this </del>  specification to control the ECN codepoints on UDP packets the proxy sends to the server, nor can proxies communicate the markings of each UDP packet from server to proxy. <del> A CONNECT-UDP proxy MUST ignore ECN bits in the IP header of UDP packets received from the server, and MUST set the ECN bits to Not- ECT on UDP packets it sends to the server.  These do not relate to the ECN markings of packets sent between client and proxy in any way. </del>  <del> 7. </del>  There are significant risks in allowing arbitrary clients to establish a tunnel to arbitrary servers, as that could allow bad actors to send traffic and have it attributed to the proxy.  Proxies <del> that support CONNECT-UDP SHOULD restrict its use to authenticated </del>  users. Because the CONNECT method creates a TCP connection to the target, the target has to indicate its willingness to accept TCP connections by responding with a TCP SYN-ACK before the proxy can send it <del> application data.  UDP doesn't have this property, so a CONNECT-UDP proxy could send more data to an unwilling target than a CONNECT proxy.  However, in practice denial of service attacks target open TCP ports so the TCP SYN-ACK does not offer much protection in real scenarios.  Proxies MUST NOT introspect the contents of UDP payloads as that would lead to ossification of UDP-based protocols by proxies. </del>  <del> 8. </del>  <del> 8.1. </del>  <del> This document will request IANA to register "CONNECT-UDP" in the HTTP Method Registry (IETF review) maintained at <<https://www.iana.org/assignments/http-methods>>. </del>  <del> 8.2. </del>  <del> This document will request IANA to register the URI scheme "masque". </del>  <del> The syntax definition below uses Augmented Backus-Naur Form (ABNF) RFC5234.  The definitions of "host" and "port" are adopted from RFC3986.  The syntax of a MASQUE URI is: </del>  <del> The "host" and "port" component MUST NOT be empty, and the "port" component MUST NOT be 0. </del>

As discussed on the list, there appears to be agreement to replace a custom method with extended CONNECT.
Some potential bikesheds/comments from (which generally looks good): 1) For HTTP/1.1, should the method be "GET" or "CONNECT"? WebSockets uses GET -- are there any uses of "Extended CONNECT" that use CONNECT rather than GET? 2) Should the default URI template have a /.well-known prefix? For example, "/.well-known/masque/udp/{targethost}/{targetport}/" ? 3) Should the upgrade token be "connect-udp" or "masque-udp" ?
Great questions, but let's keep one issue per topic, I've opened , , and to track these individual points.
With the switch to use Extended CONNECT in for UDP, it seems logical to shift TCP to also use the same model. Two approaches would either be for a new draft (draft-ietf-masque-connect-tcp?), or to generalize the connect-udp draft since there is lots in-common given how things are now factored.
I was thinking about that when I wrote the PR and I agree
I'd worry accommodating TCP is scope creep for this draft. H2 and H3 CONNECT already support TCP. Extended CONNECT might be nicer but then we'd probably want text to explain why endpoints might choose one or another. That seems better suited to some other document to me right now. edit: I also think the HTTP WG could probably own that work
I'm realizing my "I agree" wasn't very specific, I meant: I agree that we should do the same for TCP. I didn't have a strong opinion for this draft vs a new draft, but based on URL I think a separate draft might be best
Yeah, this should probably be a separate draft, but defining connect-tcp would be nice to make things more parallel.
Closing this issue since we'll want to do this in a separate draft
draft 03 states indicates that the proxy has opened a socket to the request-target and is willing to proxy UDP payloads. Any response other than a successful response indicates that the tunnel has not yet been formed. the use of "not yet" seems a little hand waving. What's the intent of the statement, I think it would help to be more specific. We could presume that a non-final 1xx response could indicate that the tunnel is possibly yet to be created. Whereas a 4xx could mean that the client erred and that no tunnel is ever going to be created.
This text was lifted from the but I'm sure we can be even more clear. Can you propose some text?
touché Semantics still says it, so it must mean something URL But both the H2 and H3 definitions don't really do any handwaving and just say URL [RFC0793] to the server identified in the ":authority" pseudo- header field. Once this connection is successfully established, the proxy sends a HEADERS frame containing a 2xx series status code to the client, as defined in Section 15.3 of [SEMANTICS]. Since CONNECT-UDP is trying to cover all 3 known major versions, it has to be careful. If I had to write a PR, I might try to combine the most up to date Semantics text with H2/H3, and in the process drop this "not yet been fully formed" clause. However, maybe I'm missing something that HTTP WG aficionados will tell be is really important.
So I think it's pretty clear that 2xx means "yes send me your UDP" and 4xx/5xx means "nope don't send your UDP". I think the points that might need clarification are: are 1xx responses allowed? if 1xx is allowed, how does the client react? are 3xx allowed? if 3xx is allowed, how does the client react?
This was fixed by , closing.
So the URI scheme registration rules (URL) have a number of things to consider. Thus, at a minimal the definition needs its own section where that is properly covered. My experience is that the template and definition needs its own sections to make it easy to define clearly and know where things reside. I would also note that issue depending on the semantics is for masque scheme and how it relates to the proxied protocol it might make sense to split this scheme out into its own document even if it will be a short one.
Or, better yet, we don't define any scheme, and just use https for the CONNECT-UDP requests!
requires that CONNECT requests omit the pseudo-header: Why does this draft need to define a URI scheme and then include that in ? There are already two different definitions for URI scheme. Both seem - at least on face value - fairly sensible, but they both come with considerable baggage. The question I'd like to ask is whether this protocol even needs a URI scheme at all. My first inclination is very much that it does not.
I added the scheme because I thought it was required (and ), but maybe it isn't. Unfortunately, CONNECT-UDP is distinct from CONNECT, so it cannot benefit from the exception that CONNECT has. This is pretty explicit in : This means that, unlike CONNECT, CONNECT-UDP needs a URI reference. However, according to : So, if we go the route of I think we can legally say that CONNECT-UDP request targets are of the form and require the and pseudo-headers to not be sent. This would allow us to use URIs without schemes for CONNECT-UDP. Can someone who's more of an HTTP guru comment on this please? NAME NAME NAME
It's an intriguing approach, but I'm not sure it works. SEMANTICS 4.1 says: I don't see anywhere in SEMANTICS it specifies that a method's target URI can't be relative. However, for HTTP/1.1 at least: does not permit the use of relative URIs. Since support for this method is negotiated in SETTINGS for HTTP/2 and HTTP/3, it's possible for it to depart from the general requirements for which pseudo-headers to send and specify something that looks more like CONNECT (omit and , for example). However, I'm not convinced that can be generalized. NAME and NAME thoughts?
NAME support for CONNECT-UDP is not gated by a SETTINGS parameter. Only the datagram mode in h3 has a setting.
Ah, then it would need to include and pseudo-headers; I'm not sure off-hand if it's valid for those to be empty.
I think that I would prefer a setting. It's probably true that this doesn't require special handling, but there are intermediaries that do crazy things like buffer request bodies. A setting would avoid any potential for misunderstanding. It makes this unusable in HTTP/1.1, but I might see that as more of a feature than a bug.
I would strongly prefer to avoid a setting, as it breaks the use-case.
I tend to think that defining a URI scheme (perhaps not ) is the path of least resistance here, and I don't see any immediate harm in doing so. As a thought experiment, consider how the Web would work if CONNECT had a URI scheme; that would give a distinct way to convey proxy configuration, for example. Based on the above I also think we need to clarify in Semantics that a target-uri is always absolute, even if it is transmitted as a relative uri.
For your obfuscation goals, the client needs to initiate any feature detection and do so after or in parallel with authentication. So you're right, probably that precludes a setting unless you're using client certs to authenticate (which would itself be visible on a probe, though not clear evidence of Masque). Then I agree with NAME that your path of least resistance is to mint a scheme for a UDP connection. The fact that has been used to describe other services available over UDP is regrettable, since those services actually intended to convey certain protocol endpoints. In this instance, you are literally describing a UDP connection with no protocol-specific properties; I'd consider asking NAME if he'd be willing to have the provisional registration (which ) replaced by a permanent one that simply designates as describing a UDP endpoint without conveying application-layer protocol expectations.
Thinking about this some more, could we use the "https" scheme? I really like NAME to use a URI for proxy configuration, as that could allow future extensibility. and the "https" scheme there already maps TCP to the CONNECT method. I think it would make sense to have that also map UDP to CONNECT-UDP. And with that mindset, having the scheme sent over the wire as "https" seems natural, and bypasses the need to define a new URI scheme. Thoughts?
Can you explain a bit more please David? I'm vaguely familiar with Chrome's URI format of proxy configuration. I note that the link you provide also defines THR "quic" scheme. And I presume that it would be nice to ditch that some something more consistent. IIRC it is possible for a proxy identified by "http" or "https" schemes to offer H3 as an Alt-Svc. And then it's upon the client to decide how to tunnel requests through such a proxy that might be capable of talking CONNECT and CONNECT-UDP. If this is too far off tangent (because of discovery) , we don't need to explore it here.
NAME I totally agree with you, Chrome's "quic" scheme is historical and I think it should now be deprecated in favor of "https" (and rely on Alt-Svc to use h3). But yes this is somewhat of a tangent that we may want to discuss offline. I was simply trying to make the case that there was some sort of precedent to consider proxying using CONNECT as "https". Back to the scheme discussion, since the scheme carries no useful information on CONNECT-UDP requests, I'm proposing to simply use "https".
That all works for me. It doesn't adhere to any sort of architectural purity, but CONNECT has no hope of achieving that; hoping to include some notion of purity along other design constraints would only make things worse. I like the idea that you can just use "https" and work out the rest using the protocol negotiation tools we have (Alt-Svc, HTTPS, settings).
I think some discussion in this thread, but likely not fully what the intended semantics of the URI scheme should be. I think there are two basic ones that I can think of and the first one is: A) Use a MASQUE proxy to send packets to "target address" However, I would think that outside of the MASQUE protocol a more useful URI semantics would be: B) Use this MASQUE proxy to send traffic to this target address. I also think we have to take a step back and ask ourselves if MASQUE URI scheme implies UDP or it it should use parameters to encode which protocol that should be proxied over the MASQUE proxy? The other aspect in this country I think the A) semantics in the -03 connect-udp draft is that is it doesn't discuss the identity of the proxy. For the security aspect the MASQUE client need to know the identity of the proxy so that it can verify the initial H/3 connection to the MASQUE proxy.
Can we simply recommend using as the scheme, but allow clients to specify a different scheme if appropriate?
After discussion at the meeting, my understanding is that the target resource CONNECT-UDP might be an origin that speaks CONNECT-UDP, or it might be a 'raw' UDP endpoint. In the former case, a HTTPS schemed target URI makes sense; in the latter, something new is necessary (e.g., , if we can make that interoperable).
given that the authority component of an URI would not need to be aware of CONNECT-UDP, I am not sure that this reasoning for works for me. IOW, it implies that a new scheme is good. I think that is doubly burned already, unfortunately.
NAME if we required a new scheme for every new method introduced, we'd have some problems. Why is that necessary?
I wasn't arguing for anything in particular, just looking for you (or someone) to address the problem somehow.
Given that we don't care about the scheme for now, and want to make sure people ignore it on receipt, how about we do https:// by default, but say that clients SHOULD grease the scheme?
FWIW, I tend to think that we should omit scheme, path, and use SETTINGS for HTTP/2 and HTTP/3. As NAME points out, we have to make sure that servers unaware of CONNECT-UDP do not mishandle CONNECT-UDP requests. For HTTP/2 and /3, we can go with either using sending SETTINGS or send set to something else than or as well as sending a fake . But in HTTP/1, there's no way of sending a scheme, therefore, we'd have to use a connect-style request line (i.e. `CONNECT-UDP host:port HTTP/1.1). Otherwise, servers unaware of the method would handle it as an ordinary request. The latter point means that there's practical advantage in following the style of CONNECT method. Then, why not use a SETTINGS on H2 and H3 to minimize the difference between H1 and H2/H3?
It's actually legal to send a fully-qualified URI in HTTP/1.1; that's just not the common case when you're talking to an origin server. I don't think it's a problem to be considering a full URI for CONNECT-UDP in HTTP/1.1. Of course, if we know there's a lack of support for that form, that's a different issue.
NAME That's a good point. Regarding the concern that you point out, I'm not sure if that would actually be an issue because a request in absolute-URI form will be considered malformed and rejected by a server that only supports HTTP/1.0-style requests. However, there's the other failure mode, and that is servers ignoring the scheme. IIUC, most origin servers do not have the incentive to consult and reject requests based on the scheme. When I send to some host, I do see 200 responses, from servers hosted by large IaaS operators / multiple CDNsnote 1. When sending to those servers, I do see 4xx errors. Therefore, if we are to care about how existing HTTP/1.1 servers would respond to masque, I think that using the form of is going to provide us better results. note 1: I'd take part of the blame, because h2o simply drops the scheme when receiving an HTTP/1.1 request. I'm glad that we are not alone!
The more I'm thinking about this, the more I'm leaning towards the simplest solution: no SETTING, and simply use a scheme of . That works perfectly for everything we need, and carries the least complexity.
NAME I'm not sure if we'd be fine with the failure mode associated to that approach? HTTP servers (or applications) often buffer the entire request, before they start processing it. Even the method is being checked after all the request body is being received. When a client connects to such a server, sending a CONNECT-UDP request with an https URI, the server will hang forever, as the client never closes the request stream. Eventually, a timeout would kick in, but I do not think it's preferable to keep the client waiting until a timeout? Am I missing something, or is it the case that you are fine with relying on a timeout?
NAME thanks for clarifying - that's a good argument for a SETTING (at least in the server-to-client direction). However, I really dislike the idea that every new HTTP method needs its own SETTING... But apart from switching to extended CONNECT I'm not seeing a lot of alternate solutions.
None of this makes any sense. If you can't send a valid request, then this protocol does not belong anywhere near an HTTP stream. Figure out how to send a valid request or build your own protocol.
NAME how do you define a valid request? The issue here is that a CONNECT (or CONNECT-UDP) request is valid as far as our understanding of the HTTP specs, but that doesn't mean that servers handle them correctly - the important difference is that these requests are not followed by a FIN on the stream, and some servers don't handle that well, even if it's valid.
I have never met a server that didn't handle an HTTP request "well", for its own definition of well. A server that doesn't know the method will use the standard parsing algorithm and respond at the end of the header section with a 405 or 501, depending on taste. If you want that to be faster, send fewer header fields. This is not a concern in practice. There is no option to send host:port with CONNECT-UDP. That is not HTTP. Stop bringing it up. Obviously, sending a GET request to a server is not the same as sending CONNECT-UDP to a server. The two have entirely different backwards-compatibility algorithms. Likewise, sending an absolute URI within a CONNECT-UDP request works just fine for every server chain that might be expected to support such a request, and the response is going to be 501, 405, or 400 for those that don't. If you find a deployed server that evidences any other form of behavior, send the developers a bug report. The IETF is not the place to work around every possible fool's implementation of bad parsing. By the time you finish writing the spec, there will be at least three more ways to fail to implement that spec correctly. Focus instead on making it work for servers that implement HTTP correctly.
No HTTP requests are followed by a FIN on the stream. FIN is part of TCP. Clients do not half-close their sockets in HTTP/1.1 -- the end of a request is indicated by either the end of the header section or by the end of the request Content-Length's amount of data, and the server doesn't read past that until it looks for the next request (on a persistent connection). A server sends FIN after closing their end of the TCP connection. For HTTP/2 and HTTP/3, both requests and response occur within protocol frames. A FIN only occurs when the underlying connection breaks.
NAME my comment about the FIN was specific to HTTP/2+. With those versions, the client sends a FIN on the request stream when it is done sending the body (or the headers when there is no body) for non-CONNECT requests. Some servers have unfortunately come to expect that of all request types, leading to timeouts for CONNECT.
NAME I get your argument that sending CONNECT-style host:port is an act of breaking HTTP. Though, I would argue that if we are to stay within HTTP, we have to use a hop-by-hop opt-in mechanism for CONNECT-UDP, because it breaks existing assumption within HTTP that servers can wait for a complete request before processing it. To that end, I tend to believe that we have to do the following: For HTTP/2 and /3, use SETTINGS, like we did in RFC 8441. If we need support for HTTP/1.1, use upgrade, like we did in RFC 6455, RFC 7540. NAME We do not have to add a new SETTING parameter for every new type of tunnel. Assuming that we are fine with using SETTINGS, I tend to wonder if we could reuse RFC 8441. With that opt-in UDP tunnels can be created by using a CONNECT request (rather than a new method), with a scheme used for identifying that the payload is UDP datagrams?
There is no such assumption in HTTP. The request is complete when the header section is complete.
IOW, if a server doesn't start processing a request message as soon as the header section is complete, it cannot correctly implement Expect and it probably doesn't support request content delimited by Transfer-Encoding or Content-Length. HTTP is designed for infinite length content streams, so there are no cases where we assume a recipient will wait until the end of the message body before starting to process the request. There would be no distinction between that and a denial-of-service vulnerability.
NAME Sorry my phrasing was incorrect. What I meant to say was that HTTP does not assume servers to start sending a final response before receiving end of the stream . EDIT. After initially posting this comment, I realized that for HTTP/1.1, lack of CL or TE indicates that the end of request headers is the end of the request. But for HTTP/2 and HTTP/3, the method being CONNECT is the only indicator that changes where the request ends, isn't it?
FWIW, if all you need is something that is a valid URI (and the content does not matter), a URN might work perfectly well: urn:ietf:rfc:xxxx (see URL). (I think Ted Hardie mentioned this in the IETF meeting chat)
NAME mentioned elsewhere that a locator that identifies the server providing the connect tunnel would be much better than the current design, which effectively puts the target host as an authority. I'm not yet sure what I think of that, but it's an interesting thought worth considering.
Here is the example from NAME :
That specific example makes my RFC 8820 sense itch, but it's an OK illustration of the idea.
NAME do you have an alternate encoding that would appease your itch?
With the https scheme, we might be able to use a URI template (which might lead to that exact example if people so chose). Or we could define a new scheme...
NAME pointed out that draft-pauly-dprive-oblivious-doh does something similar. It may make sense to have some consistency. Maybe: (perhaps adjusting the path somehow, or using a URI template?)
I like the idea of keeping the https scheme and using the path to convey the target
No need to abuse .well-known when we can use a URI template.
URL in something using curly brackets...?
URL
So something like ?
That would be an easy way of doing it. Or .
But that would be an invalid path.
Would it be invalid after RFC 6570 substitution?
After substitution is of course ok. So where do you want to put the template?
The template goes the same place you might put a URL. Right now, that is configuration.
Ah, I thought you wanted to put it into the ":path" pseudo header.
Closely related to this is whether: 1) Use a method per protocol (CONNECT-UDP, CONNECT-IP, etc) 2) Use a new common method (eg, CONNECTX) with protocol in either a pseudoheader or path component 3) Use Extended CONNECT with a ":protocol" psuedoheader Given all of the baggage with CONNECT, I'd lean towards (2)
(This issue probably wants a more general name covering the set of interrelated topics here.)
NAME As said at the meeting, to avoid intermediaries unaware of masque waiting for FIN before doing anything, I think it would be a good idea to make this an opt-in. For that, we need to use an ALPN, SETTING, or something that it being exchanged prior to the HTTP requests. The problem with option 1 is that we'd need to introduce a new negotiation scheme for every protocol. Option 2 is better in that respect because we need to introduce one negotiation scheme, and reuse it for different protocols. But I'm not sure if hawing a new negotiation scheme is necessary, when option (3), i.e., the Extended CONNECT method, already provides us the necessary negotiation scheme with the ":protocol" psuedo header acting as a way of specifying the protocol.
Extended CONNECT does have the advantage of targeting a resource. The challenge then is in how the target (for UDP, that would be a hostname or IP plus a port) is encoded into that target URI. We have URI templates that have been successfully used elsewhere, so that might work. Webtransport can just use an arbitrary target URI. The main complaint I have is that :protocol is terrible. HTTP Upgrade Tokens aren't ALPN, but that's almost what we want here: a unified protocol identification system. Of course, as a tunneled protocol, ALPN isn't right either, so maybe we can just reclaim upgrade tokens for this tunneling stuff.
Yeah, I share the temptation to use ALPN. Though, talking specifically about masque, I'm not sure if it's an application protocol. Rather, it is a combination of an encapsulated datagram protocol and a way of specifying the remote address. Let's say we want to use SRTP on top of a HTTP tunnel with support for datagrams. In such case, SRTP would be the ALPN, and we'd need another identifier for specifying that the transport carries datagrams, rather than a bidirectional stream. Based on that, I am inclined to say that ":protocol" might be a better fit for masque, and separately, we could discuss adding a non-pseudo header field for specifying ALPN. PS. And the other benefit of using Upgrade Tokens is that we can support HTTP/1.1 as well (though I'm not entirely sure if we want to officially support HTTP/1.1).
I keep forgetting that I wrote RFC 7639. Still, I agree on all counts. ALPN has a purpose, but it isn't quite right here. Update tokens are a little weird, but I think that they are actually perfect. We just need to reclaim them for use.
One thing I do find appealing about using Upgrade Tokens is that it means that HTTP/1.1 support becomes easy: we just use Upgrade and keep the target in the path like in h2 and h3. And conceptually an upgrade is what we're doing: we're replacing the DATA stream with a new protocol that uses capsules/stream chunks. That's not too dissimilar to WebSocket. Following up on today's question on what should be used for scheme and authority for CONNECT-UDP, I am thinking we may want to reconsider the overall approach for scheme, authority, and path for CONNECT-UDP and any other new CONNECT- methods. We may even wish to consider defining a new CONNECT-TCP method for QUIC. As a service operator, the CONNECT method has problematic semantics that don't work well for providing a multi-tenant service. It is defined (in H2 at least) to have no scheme and no path, and its authority is the same name as the hostname of the connect target. This makes it problematic: there's effectively no Host header in the sense that all other HTTP requests have a Host header (or H2 :authority) that will match the TLS ServerName. Given that many HTTP servers apply policy on an Origin basis (scheme+authority+port) this policy isn't applicable to CONNECT in a meaningful way. ie, what you generally want to apply configuration / authentication / policy on is the server Host name, not on the target name. We clearly can't change the CONNECT semantics here, but we should avoid introducing another new weird case that varies from HTTP semantics and which makes providing a multi-tenant service hard. What I'd propose for CONNECT-UDP is: We keep :scheme as "https" We keep :authority as the Host header / TLS ServerName for the connection to the proxy We encode the target in :path So as an example: :method = CONNECT-UDP :authority = masque-URL :path = URL :scheme = https (There are a few different ways to encode :path) We may wish to consider defining a parallel CONNECT-TCP in MASQUE that provides similar semantics to CONNECT but which uses this structure, that will be much more conducive to running services. Best, Erik

<ins> UDP Proxying Support for HTTP </ins> draft-ietf-masque-connect-udp-latest Abstract  <ins> This document describes how to proxy UDP over HTTP.  Similar to how the CONNECT method allows proxying TCP over HTTP, this document defines a new mechanism to proxy UDP.  It is built using HTTP Extended CONNECT. </ins> 1.  <ins> This document describes how to proxy UDP over HTTP.  Similar to how the CONNECT method (see Section 9.3.6 of SEMANTICS) allows proxying TCP TCP over HTTP, this document defines a new mechanism to proxy UDP UDP. UDP Proxying supports all versions of HTTP and uses HTTP Datagrams HTTP-DGRAM.  When using HTTP/2 or HTTP/3, UDP proxying uses HTTP Extended CONNECT as described in EXT-CONNECT2 and EXT-CONNECT3.  When using HTTP/1.x, UDP proxying uses HTTP Upgrade as defined in Section 7.8 of SEMANTICS. </ins> 1.1. as shown here. In this document, we use the term "proxy" to refer to the HTTP server  <ins> that opens the UDP socket and responds to the UDP proxying request. If there are HTTP intermediaries (as defined in Section 3.7 of SEMANTICS) between the client and the proxy, those are referred to as </ins> "intermediaries" in this document. <ins> Note that, when the HTTP version in use does not support multiplexing streams (such as HTTP/1.1), any reference to "stream" in this document represents the entire connection. </ins> 2.  <ins> Clients are configured to use UDP Proxying over HTTP via an URI Template TEMPLATE.  The URI template MUST contain exactly two variables: "target_host" and "target_port".  Examples are shown below: Since the original HTTP CONNECT method allowed conveying the target host and port but not the scheme, proxy authority, path, nor query, there exist proxy configuration interfaces that only allow the user to configure the proxy host and the proxy port.  Client implementations of this specification that are constrained by such limitations MUST use the default template which is defined as: "https://{proxy_host}:{proxy_port}/{target_host}/{target_port}/" where "proxy_host" and "proxy_port" are the configured host and port of the proxy respectively.  Proxy deployments SHOULD use the default template to facilitate interoperability with such clients. </ins> 3.  <ins> This document defines the "masque-udp" HTTP Upgrade Token. "masque- udp" uses the Capsule Protocol as defined in HTTP-DGRAM. A "masque-udp" request requests that the recipient establish a tunnel over a single HTTP stream to the destination target server identified by the "target_host" and "target_port" variables of the URI template (see client-config).  If the request is successful, the proxy commits to converting received HTTP Datagrams into UDP packets and vice versa until the tunnel is closed.  Tunnels are commonly used to create an end-to-end virtual connection, which can then be secured using QUIC QUIC or another protocol running over UDP. When sending its UDP proxying request, the client SHALL perform URI template expansion to determine the path and query of its request. target_host supports using DNS names, IPv6 literals and IPv4 literals.  Note that this URI template expansion requires using pct- encoding, so for example if the target_host is "2001:db8::42", it will be encoded in the URI as "2001%3Adb8%3A%3A42". A payload within a UDP proxying request message has no defined semantics; a UDP proxying request with a non-empty payload is malformed. </ins>  <ins> Responses to UDP proxying requests are not cacheable. </ins>  <ins> 3.1. </ins>  <ins> Upon receiving a UDP proxying request, the recipient proxy extracts the "target_host" and "target_port" variables from the URI it has reconstructed from the request headers, and establishes a tunnel by directly opening a UDP socket to the requested target. </ins>  <ins> Unlike TCP, UDP is connection-less.  The proxy that opens the UDP socket has no way of knowing whether the destination is reachable. Therefore it needs to respond to the request without waiting for a packet from the target.  However, if the target_host is a DNS name, the proxy MUST perform DNS resolution before replying to the HTTP request.  If DNS resolution fails, the proxy MUST fail the request and SHOULD send details using the Proxy-Status header PROXY-STATUS. </ins>  <ins> Proxies can use connected UDP sockets if their operating system supports them, as that allows the proxy to rely on the kernel to only send it UDP packets that match the correct 5-tuple.  If the proxy uses a non-connected socket, it MUST validate the IP source address and UDP source port on received packets to ensure they match the client's request.  Packets that do not match MUST be discarded by the proxy. </ins>  <ins> The lifetime of the socket is tied to the request stream.  The proxy MUST keep the socket open while the request stream is open.  Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close the request stream before closing the socket.  If a proxy is notified by its operating system that its socket is no longer usable, it MUST close the request stream. </ins>  <ins> A successful response (as defined in resp1 and resp23) indicates that the proxy has opened a socket to the requested target and is willing to proxy UDP payloads.  Any response other than a successful response indicates that the request has failed, and the client MUST therefore abort the request. </ins>  <ins> 3.2. </ins>  <ins> When using HTTP/1.1, a UDP proxying request will meet the following requirements: </ins>  <ins> the method SHALL be "CONNECT". the request-target SHALL use absolute-form (see Section 3.2.2 of MESSAGING). the request SHALL include a single Host header containing the origin of the proxy. the request SHALL include a single "Connection" header with value "Upgrade". the request SHALL include a single "Upgrade" header with value "masque-udp". For example, if the client is configured with URI template "https://proxy.example.org/{target_host}/{target_port}/" and wishes to open a UDP proxying tunnel to target 192.0.2.42:443, it could send the following request: 3.3. The proxy SHALL indicate a successful response by replying with the following requirements: the HTTP status code on the response SHALL be 101 (Switching Protocols). the reponse SHALL include a single "Connection" header with value "Upgrade". the response SHALL include a single "Upgrade" header with value "masque-udp". the response SHALL NOT include any Transfer-Encoding or Content- Length header fields. If any of these requirements are not met, the client MUST treat this proxying attempt as failed and abort the connection. For example, the proxy could respond with: 3.4. When using HTTP/2 H2 or HTTP/3 H3, UDP proxying requests use HTTP pseudo-headers with the following requirements: </ins>  <ins> The ":method" pseudo-header field SHALL be "CONNECT". The ":protocol" pseudo-header field SHALL be "masque-udp". The ":authority" pseudo-header field SHALL contain the authority of the proxy. The ":path" and ":scheme" pseudo-header fields SHALL NOT be empty. Their values SHALL contain the scheme and path from the URI template after the URI template expansion process has been completed. A UDP proxying request that does not conform to these restrictions is malformed (see Section 8.1.2.6 of H2). For example, if the client is configured with URI template "https://proxy.example.org/{target_host}/{target_port}/" and wishes to open a UDP proxying tunnel to target 192.0.2.42:443, it could send the following request: 3.5. The proxy SHALL indicate a successful response by replying with any 2xx (Successful) HTTP status code, without any Transfer-Encoding or Content-Length header fields. If any of these requirements are not met, the client MUST treat this proxying attempt as failed and abort the connection. For example, the proxy could respond with: </ins> 4. UDP packets are encoded using HTTP Datagrams HTTP-DGRAM.  The payload of a UDP packet (referred to as "data octets" in UDP) is sent unmodified in the "HTTP Datagram Payload" field of an HTTP Datagram.  <ins> In order to use HTTP Datagrams, the client will first decide whether or not to use HTTP Datagram Contexts and then register its context ID (or lack thereof) using the corresponding registration capsule, see HTTP-DGRAM. </ins> Clients MAY optimistically start sending proxied UDP packets before  <ins> receiving the response to its UDP proxying request, noting however </ins> that those may not be processed by the proxy if it responds to the  <ins> request with a failure, or if the datagrams are received by the proxy before the request. </ins>  <ins> Extensions to this mechanism MAY leverage the "Context Extensions" field of registration capsules in order to negotiate different semantics or encoding for UDP payloads. </ins> 5.  Proxies SHOULD strive to avoid increasing burstiness of UDP traffic: they SHOULD NOT queue packets in order to increase batching. control unless it has an out-of-band way of knowing with absolute certainty that the inner traffic is congestion-controlled.  <ins> If a client or proxy with a connection containing a UDP proxying request stream disables congestion control, it MUST NOT signal ECN support on that connection.  That is, it MUST mark all IP headers with the Not-ECT codepoint.  It MAY continue to report ECN feedback via ACK_ECN frames, as the peer may not have disabled congestion control. </ins> When the protocol running over UDP that is being proxied uses loss recovery (e.g., QUIC), and the underlying HTTP connection runs over independently retransmit the same data.  To avoid this, HTTP/3 datagrams SHOULD be used.  <ins> 5.1. </ins>  <ins> UDP proxying does not create an IP-in-IP tunnel, so the guidance in </ins> RFC6040 about transferring ECN marks between inner and outer IP  <ins> headers does not apply.  There is no inner IP header in UDP proxying </ins> tunnels.  <ins> Note that UDP proxying clients do not have the ability in this </ins> specification to control the ECN codepoints on UDP packets the proxy sends to the server, nor can proxies communicate the markings of each UDP packet from server to proxy.  <ins> A UDP proxy MUST ignore ECN bits in the IP header of UDP packets received from the server, and MUST set the ECN bits to Not-ECT on UDP packets it sends to the server.  These do not relate to the ECN markings of packets sent between client and proxy in any way. </ins>  <ins> 6. </ins> There are significant risks in allowing arbitrary clients to establish a tunnel to arbitrary servers, as that could allow bad actors to send traffic and have it attributed to the proxy.  Proxies  <ins> that support UDP proxying SHOULD restrict its use to authenticated </ins> users. Because the CONNECT method creates a TCP connection to the target, the target has to indicate its willingness to accept TCP connections by responding with a TCP SYN-ACK before the proxy can send it  <ins> application data.  UDP doesn't have this property, so a UDP proxy could send more data to an unwilling target than a CONNECT proxy. However, in practice denial of service attacks target open TCP ports so the TCP SYN-ACK does not offer much protection in real scenarios. Proxies MUST NOT introspect the contents of UDP payloads as that would lead to ossification of UDP-based protocols by proxies. </ins>  <ins> 7. </ins>  <ins> 7.1. </ins>  <ins> This document will request IANA to register "masque-udp" in the HTTP Upgrade Token Registry maintained at <<https://www.iana.org/assignments/http-upgrade-tokens>>. </ins>  <ins> masque-udp </ins>  <ins> Proxying of UDP Payloads. </ins>  <ins> None. </ins>  <ins> This document. </ins>


proxy. The lifetime of the socket is tied to the request stream.  The proxy <del> MUST keep the socket open while the request stream is open.  Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close the request stream before closing the socket.  If a proxy is notified by its operating system that its socket is no longer usable, it MUST close the request stream. </del>  A successful response (as defined in resp1 and resp23) indicates that the proxy has opened a socket to the requested target and is willing

RFC 4787 (URL) does define some default timeouts for NAT bindings for UDP. Over general Internet I would not expect that UDP flow state is mainstained longer than these default values. Thus, I think it makes sense to indicate that if the MASQUE server is recovering state for inactive UDP flows, it SHOULD NOT recover them faster than the timeout recommendation in the behave UDP RFC.
That makes sense to me, can you send a PR? Otherwise I'll add it in the next batch.

proxy. The lifetime of the socket is tied to the request stream.  The proxy  <ins> MUST keep the socket open while the request stream is open.  If a proxy is notified by its operating system that its socket is no longer usable, it MUST close the request stream.  Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close the request stream before closing the socket.  Proxies that close sockets after a period of inactivity SHOULD NOT use a period lower than two minutes, see Section 4.3 of BEHAVE. </ins> A successful response (as defined in resp1 and resp23) indicates that the proxy has opened a socket to the requested target and is willing


4.  When associated with UDP proxying request streams, the HTTP Datagram Payload field of HTTP Datagrams (see HTTP-DGRAM) has the following format: <del> The design team meetings will continue until morale improves. </del>  The payload of the datagram, whose semantics depend on value of the previous field.  Note that this field can be empty. <del> UDP packets are encoded using HTTP Datagrams with the To Be Determined field set to TBD0.  When the To Be Determined is set to TBD0, the Context Payload field contains the unmodified payload of a UDP packet (referred to as "data octets" in UDP). </del>  Clients MAY optimistically start sending proxied UDP packets before receiving the response to its UDP proxying request, noting however request with a failure, or if the datagrams are received by the proxy before the request. <del> 5. </del>  Proxies SHOULD strive to avoid increasing burstiness of UDP traffic: they SHOULD NOT queue packets in order to increase batching. independently retransmit the same data.  To avoid this, HTTP/3 datagrams SHOULD be used. <del> 5.1. </del>  When using HTTP/3 with the QUIC Datagram extension DGRAM, UDP payloads are transmitted in QUIC DATAGRAM frames.  Since those cannot on RFC8899.  In this scenario, the proxy SHOULD drop the UDP payload and send an ICMP "Packet Too Big" message to the target RFC4443. <del> 5.2. </del>  UDP proxying does not create an IP-in-IP tunnel, so the guidance in RFC6040 about transferring ECN marks between inner and outer IP packets it sends to the server.  These do not relate to the ECN markings of packets sent between client and proxy in any way. <del> 6. </del>  There are significant risks in allowing arbitrary clients to establish a tunnel to arbitrary servers, as that could allow bad Proxies MUST NOT introspect the contents of UDP payloads as that would lead to ossification of UDP-based protocols by proxies. <del> 7. </del>  <del> 7.1. </del>  This document will request IANA to register "connect-udp" in the HTTP Upgrade Token Registry maintained at

This is one potential design for the identifier at the start of the CONNECT-UDP datagram payload. Note that this PR is against the design team consensus branch, not main. . .
During the HTTP Datagrams Design Team meeting on 2022-01-20, we reached consensus to move forward with the dynamic approach, so I'm merging this PR.

4. <ins> This protocol allows future extensions to exchange HTTP Datagrams which carry different semantics from UDP payloads.  Some of these extensions can augment UDP payloads with additional data, while others can exchange data that is completely separate from UDP payloads.  In order to accomplish this, all HTTP Datagrams associated with UDP Proxying request streams start with a context ID, see format. Context IDs are 62-bit integers (0 to 2 -1).  The context ID value of zero is reserved for UDP payloads, while non-zero values are dynamically allocated: non-zero even- numbered context IDs are client-initiated, and odd-numbered context IDs are server-initiated.  Extensions can use the next available context ID for their own purposes.  Note that, once allocated, any context ID can be used by both client and server - only allocation carries separate namespaces to avoid requiring synchronization. Additionally, note that the context ID namespace is tied to a given HTTP request: it is possible for the same numeral context ID to be used simultaneously in distinct requests. 5. </ins> When associated with UDP proxying request streams, the HTTP Datagram Payload field of HTTP Datagrams (see HTTP-DGRAM) has the following format:  <ins> A variable-length integer that contains the value of the Context ID.  Endpoints MUST silently drop any received HTTP Datagram which carries an unknown Context ID. </ins> The payload of the datagram, whose semantics depend on value of the previous field.  Note that this field can be empty.  <ins> UDP packets are encoded using HTTP Datagrams with the Context ID set to zero.  When the Context ID is set to zero, the Context Payload field contains the unmodified payload of a UDP packet (referred to as "data octets" in UDP). </ins> Clients MAY optimistically start sending proxied UDP packets before receiving the response to its UDP proxying request, noting however request with a failure, or if the datagrams are received by the proxy before the request.  <ins> 6. </ins> Proxies SHOULD strive to avoid increasing burstiness of UDP traffic: they SHOULD NOT queue packets in order to increase batching. independently retransmit the same data.  To avoid this, HTTP/3 datagrams SHOULD be used.  <ins> 6.1. </ins> When using HTTP/3 with the QUIC Datagram extension DGRAM, UDP payloads are transmitted in QUIC DATAGRAM frames.  Since those cannot on RFC8899.  In this scenario, the proxy SHOULD drop the UDP payload and send an ICMP "Packet Too Big" message to the target RFC4443.  <ins> 6.2. </ins> UDP proxying does not create an IP-in-IP tunnel, so the guidance in RFC6040 about transferring ECN marks between inner and outer IP packets it sends to the server.  These do not relate to the ECN markings of packets sent between client and proxy in any way.  <ins> 7. </ins> There are significant risks in allowing arbitrary clients to establish a tunnel to arbitrary servers, as that could allow bad Proxies MUST NOT introspect the contents of UDP payloads as that would lead to ossification of UDP-based protocols by proxies.  <ins> 8. </ins>  <ins> 8.1. </ins> This document will request IANA to register "connect-udp" in the HTTP Upgrade Token Registry maintained at


Section 16 of QUIC.  The context ID value of 0 is reserved for UDP payloads, while non-zero values are dynamically allocated: non-zero even-numbered context IDs are client-allocated, and odd-numbered <del> context IDs are server-allocated.  Implementations will provide a context ID allocation service.  That service will allow extensions to request a unique context ID that they can subsequently use for their own purposes.  This means that an HTTP client implementation of the context ID allocation service MUST only provide even-numbered IDs, while a server implementation MUST only provide odd-numbered IDs. The context allocation service MUST NOT return the same context ID twice, however it MAY return IDs in any order.  Once allocated, any context ID can be used by both client and server - only allocation carries separate namespaces to avoid requiring synchronization. Additionally, note that the context ID namespace is tied to a given HTTP request: it is possible for a context ID with the same numeric value to be simultaneously assigned different semantics in distinct requests, potentially with different semantics. </del>  Registration is the action by which an endpoint informs its peer of the semantics and format of a given context ID.  This document does

Can you elaborate on what the motivation for this is? Introducing the "context ID allocation service" concept means that extensions can conveniently say "Then request a context ID from the allocation service and doo foo with it". If we remove this text, it'll make extension specs harder to write.
Occam's Razor. It's unnecessary complication that makes this text harder to read. I don't agree. The job of the specification is to document external behavior. I don't agree that it makes future specs more difficult. They can just say "allocate a context ID". It's an internal detail of the implementation that there is a context ID allocation service.
How about the following? It removes the concept but keeps the requirements we need.
I prefer removing the allocation service as a concept and specifying the requirements. I did find this a bit confusing in David's proposed text I think the point is clear already and the rationale is not required. Maybe remove this clause?
This text still has the problem that it first says you can allocate each context ID once and then later it says actually you can allocate it once per namespace. Why not say this upfront as in my PR?
My apologies NAME I think I had missed the added sentence in the middle when looking at this the first time. This LGTM modulo removal of the optional sentence at the end.

Section 16 of QUIC.  The context ID value of 0 is reserved for UDP payloads, while non-zero values are dynamically allocated: non-zero even-numbered context IDs are client-allocated, and odd-numbered  <ins> context IDs are server-allocated.  The context ID namespace is tied to a given HTTP request: it is possible for a context ID with the same numeric value to be simultaneously assigned different semantics in distinct requests, potentially with different semantics.  Context IDs must not be re-allocated within a given HTTP namespace but MAY be allocated in any order.  Once allocated, any context ID can be used by both client and server - only allocation carries separate namespaces to avoid requiring synchronization. </ins> Registration is the action by which an endpoint informs its peer of the semantics and format of a given context ID.  This document does


could send more data to an unwilling target than a CONNECT proxy. However, in practice denial of service attacks target open TCP ports so the TCP SYN-ACK does not offer much protection in real scenarios. <del> Proxies MUST NOT introspect the contents of UDP payloads as that would lead to ossification of UDP-based protocols by proxies. </del> 8.

the target has to indicate its willingness to accept TCP connections by responding with a TCP SYN-ACK before the proxy can send it application data. UDP doesn't have this property, so a UDP proxy could send more data to an unwilling target than a CONNECT proxy. However, in practice denial of service attacks target open TCP ports so the TCP SYN-ACK does not offer much protection in real scenarios. Proxies MUST NOT introspect the contents of UDP payloads as that would lead to ossification of UDP-based protocols by proxies. This seems like an RFC 6919 "MUST (but we know you won't)"
Agreed. Are you proposing a change to the draft?
Yes. I would remove the last sentence. OTOH, given that the status of proxies is still under discussion maybe we just wait on this one.

could send more data to an unwilling target than a CONNECT proxy. However, in practice denial of service attacks target open TCP ports so the TCP SYN-ACK does not offer much protection in real scenarios.  8.


version: 0, 2").  When sent by the proxy, it contains a single draft number selected by the proxy from the list provided by the client (e.g., "connect-udp-version: 2").  Sending this header is RECOMMENDED <del> but not required. </del>  4.

The doc has a development versioning header but it omits the ABNF. The format is described as a list of values on request headers and a single item on response headers. I'm going to assume this is an sf-list, can we state that to avoid uncertainty?

version: 0, 2").  When sent by the proxy, it contains a single draft number selected by the proxy from the list provided by the client (e.g., "connect-udp-version: 2").  Sending this header is RECOMMENDED  <ins> but not required.  Its ABNF is: </ins> 4.


proxy is notified by its operating system that its socket is no longer usable, it MUST close the request stream.  Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close <del> the request stream before closing the socket.  Proxies that close </del>  sockets after a period of inactivity SHOULD NOT use a period lower than two minutes, see Section 4.3 of BEHAVE.

For some kinds of implementations, the action of closing a QUIC stream is not immediate. Do we really want to make this ordering so strong? There's not really any way to enforce it.
That makes sense. I'd like to keep the "MUST close the request stream" but we can remove the ordering requirement or make it a SHOULD.
Either of those options works for me. I can make a PR tomorrow.

proxy is notified by its operating system that its socket is no longer usable, it MUST close the request stream.  Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close  <ins> the request stream when closing the socket.  Proxies that close </ins> sockets after a period of inactivity SHOULD NOT use a period lower than two minutes, see Section 4.3 of BEHAVE.


request with a failure, or if the datagrams are received by the proxy before the request.  6. Proxies SHOULD strive to avoid increasing burstiness of UDP traffic:

When the client proxy hop is HTTP/3, and HTTP/3 datagrams are in use, the practical limit of datagrams is the maximum size of a QUIC packet minus header overheads. When DATAGRAM capsules are used, the logical limit is increased to that of an entire data stream. For the UDP proxying use case, a proxy that converts capsules into UDP datagrams will have a practical limit to the size of UDP datagrams that it can send. And it most likely wants to avoid fragmentation. When fragmentation is to be avoided, I would expect many proxy implementations to have a practical limit of less than 2000 for the size they would be willing to send. Such proxies can drop the contents of too-large datagrams but they would be required to drain them completely in order to continue reading the data stream. This seems like a possible avenue for DoS, because a client could send a verylarge datagram in theory, it would need to buffer the entirety of the datagram before sending it. We might be tempted to try to create some way for endpoints to communicate the practical limit of datagram capsules. But that could be hard due to the end-to-end version-indendent design. Instead we might just provide some guidance that $very_large capsules might cause problems for implementations, and that receivers might have local (or implementation-specific) limits that they want to enforce, which they could do by closing the stream or closing the connection.
According to RFC 768, the maximum length of a UDP payload is 65527. I would add some text to draft-ietf-masque-connect-udp along the lines of: Additionally, I think we could add some guidance text to draft-ietf-masque-h3-datagram along the lines of: I would leave the communication of actual limits to an extension.
Yeah we don't need to be 100% prescriptive, just spelling out foothold WFM

request with a failure, or if the datagrams are received by the proxy before the request. <ins> Endpoints MUST NOT send HTTP Datagrams with payloads longer than 65527 using Context ID zero.  An endpoint that receives a DATAGRAM capsule using Context ID zero whose payload is longer than 65527 MUST abort the stream.  If a proxy knows it can only send out UDP packets of a certain length due to its underlying link MTU, it SHOULD discard incoming DATAGRAM capsules using Context ID zero whose payload is longer than that limit without buffering the capsule contents. </ins> 6. Proxies SHOULD strive to avoid increasing burstiness of UDP traffic:


indicates that the request has failed, and the client MUST therefore abort the request.  3.2. When using HTTP/1.1, a UDP proxying request will meet the following

An application that tunnels UDP may rely on certain properties or features of the socket that the proxy creates. The draft covers some of these but doesn't seem to mention the UDP fragmentation. TURN has a whole section on this URL QUIC, for example, requires that and recommends the Don't Fragment (DF) bit MUST be set if possible. Since a proxy is agnostic to the application protocol in use (I'm assuming that because we don't mention the anywhere) perhaps CONNECT-UDP would benefit from a signal the client can send to the proxy to state it's DF preferences.
This sounds like a worthwhile extension draft? I don't think it's required to have a functional CONNECT-UDP protocol
One argument for doing it here is that one of the common uses of CONNECT-UDP will be to tunnel QUIC, and this is an obvious footgun in consideration of RFC 9000 requirements. The opposite way to solve the problem could be to add MUST/SHOULD language about proxies setting DF by default. And then require an extension to signal to disable it. But this is solutionizing a bit. Really, I want to be able to write a client that can have consistent expectations about the way datagram payload gets sent on UDP. Otherwise when things go wrong I'm left guessing and I might not have the information that the proxy did. I could even live with text in this document that raises this as a consideration but punts on the problem.
Note that this isn't just about setting in IPv4. It's also about whether to apply sender fragmentation, in IPv6. I would be OK with declaring that all fragmentation is off by default, and leave it to extensions to turn it on.
Good point Ben!
I'd be OK with saying proxies MUST NOT explicitly add fragmentation and SHOULD set the DF bit. We can't say MUST set DF because not all operating systems allow setting the DF bit on UDP sockets.
RFC 9000 says , not a fan?
"MUST ... if possible" is the same as "SHOULD" for me, I don't much care between them.

indicates that the request has failed, and the client MUST therefore abort the request. <ins> Proxies MUST NOT introduce fragmentation at the IP layer when forwarding HTTP Datagrams onto a UDP socket.  In IPv4, the Don't Fragment (DF) bit MUST be set if possible, to prevent fragmentation on the path.  Future extensions MAY remove these requirements. </ins> 3.2. When using HTTP/1.1, a UDP proxying request will meet the following


The lifetime of the socket is tied to the request stream.  The proxy MUST keep the socket open while the request stream is open.  If a proxy is notified by its operating system that its socket is no <del> longer usable, it MUST close the request stream.  Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close the request stream when closing the socket.  Proxies that close sockets after a period of inactivity SHOULD NOT use a period lower than two minutes, see BEHAVE. </del>  A successful response (as defined in resp1 and resp23) indicates that the proxy has opened a socket to the requested target and is willing defeats the end-to-end unreliability characteristic that methods such as Datagram Packetization Layer Path MTU Discovery (DPLPMTUD) depend on DPLPMTUD.  In this scenario, the proxy SHOULD drop the UDP payload <del> and send an ICMP "Packet Too Big" message to the target ICMP6. </del>  6.2.

With the CONNECT UDP, a proxy will send and receive UDP datagrams on behalf of a client. However, in addition to these UDP datagrams, it could also receive ICMP messages. The current draft does not discuss how these ICMP messages should be handled by a proxy and how they would need to be conveyed to the client. It probably makes sense to at least discuss how ICMP destination/network/port unreachable should be handled by the proxy (ignore, terminate the HTTP connection, ...)
I agree. I'm not yet sure what the best solution is (closing the stream on port unreachable would improve reliability but does introduce a way for an attacker to deny service) but we should figure that out and provide guidance in the doc.
FWIW, the way TURN handles this is by having a way for the server to forward ICMP indications. URL Obviously, in order to have this in MASQUE we would need to have some sort of type indicator in the datagram.
I do want the relevant information in the ICMP to make it to the client. However, ICMP falls into the asynchronous information that is not directly associated with a forwarded packet. It can clearly be a forwarded packet per EKR's suggestion. We have other cases where we have information that is related to the associated packet, for example ECN. So I think this there is an important high level design choice here that we need to sorted out. I think for the general extensibility lets consider a content identifier so that just UDP payloads can be separated from additional types with additional fields.

The lifetime of the socket is tied to the request stream.  The proxy MUST keep the socket open while the request stream is open.  If a proxy is notified by its operating system that its socket is no  <ins> longer usable (for example, this can happen when an ICMP "Destination Unreachable" message is received, see ICMP6), it MUST close the request stream.  Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close the request stream when closing the socket.  Proxies that close sockets after a period of inactivity SHOULD NOT use a period lower than two minutes, see BEHAVE. </ins> A successful response (as defined in resp1 and resp23) indicates that the proxy has opened a socket to the requested target and is willing defeats the end-to-end unreliability characteristic that methods such as Datagram Packetization Layer Path MTU Discovery (DPLPMTUD) depend on DPLPMTUD.  In this scenario, the proxy SHOULD drop the UDP payload  <ins> and send an ICMP "Packet Too Big" message to the target, see ICMP6. </ins> 6.2.


2. Clients are configured to use UDP Proxying over HTTP via an URI <del> Template TEMPLATE.  The URI template MUST contain exactly two variables: "target_host" and "target_port".  Examples are shown below: </del>  Since the original HTTP CONNECT method allowed conveying the target host and port but not the scheme, proxy authority, path, nor query,

. That template contains the and variables which convey the target host/port in the pseudo-header. This has the following benefits: allows custom schemes allows proxy to pick path they use However it has downsides: it requires parsing URI templates which is more of a pain than it seems it prevents reusing the same configuration between CONNECT-UDP and CONNECT-IP Alternatively, we could replace the configuration URI template with a configuration URL, and instead convey the target host/port in separate HTTP headers. This has the same benefits of the URI template without the downsides.
Discussed this issue at IETF 112, consensus in the room was to keep the URI template but to tighten the template restrictions.

2. Clients are configured to use UDP Proxying over HTTP via an URI  <ins> Template TEMPLATE with the variables "target_host" and "target_port". Examples are shown below: The URI template MUST be a level 3 template or lower.  The URI template MUST be in absolute form, and MUST include non-empty scheme, authority and path components.  The path component of the URI template MUST start with a slash "/".  All template variables MUST be within the path component of the URI.  The URI template MUST contain the two variables "target_host" and "target_port" and MAY contain other variables.  The URI template MUST NOT contain any non-ASCII unicode characters and MUST only contain ASCII characters in the range 0x21-0x7E inclusive (note that percent-encoding is allowed). The URI template MUST NOT use Reserved Expansion ("+" operator), Fragment Expansion ("#" operator), Label Expansion with Dot-Prefix, Path Segment Expansion with Slash-Prefix, nor Path-Style Parameter Expansion with Semicolon-Prefix.  If any of the requirements above are not met by a URI template, the client MUST reject its configuration and fail the request without sending it to the proxy. </ins> Since the original HTTP CONNECT method allowed conveying the target host and port but not the scheme, proxy authority, path, nor query,


When using HTTP/1.1, a UDP proxying request will meet the following requirements: <del> the method SHALL be "CONNECT". </del>  the request-target SHALL use absolute-form (see H1).

For HTTP/1.1, should the method be "GET" or "CONNECT"? WebSockets uses GET -- are there any uses of "Extended CONNECT" that use CONNECT rather than GET? (issue based on by NAME
In my experience, H1.1 CONNECT for anything but it's intended purpose of proxying will see some deployment problems. The last HTTP spec admits some origins might respect it, but I suspect many HTTP components won't like it. I think sticking with GET plus Upgrade header field is a good choice
At IETF 113, after lengthy discussion the consensus is the room appeared to be to switch to GET so I'm merging so we have a version of the draft ready for WGLC

When using HTTP/1.1, a UDP proxying request will meet the following requirements:  <ins> the method SHALL be "GET". </ins> the request-target SHALL use absolute-form (see H1).


The context ID to close. The close code allows an endpoint to provide additional <del> information as to why a datagram context was closed.  The codes are defined in close-codes. </del>  This is meant for debugging purposes.  It consists of a human- readable string encoded in UTF-8. 4.4.3.1.  This specification defines the close codes below.  Their numeric <del> values are in iana-close-codes. </del>  <del> This indicates that the registration was closed without any additional information. </del>  This indicates that the sender does not know how to interpret the datagram format type associated with this context.  The endpoint

This borrows some of the spin off suggestions made during the discussion on . It does not address the issue itself. See that issue for next steps.
There may be cases (imagine new capsule types) where somthing went wrong but none of the existing codes are appropriate. Signalling NO_ERROR is not appropriate and may be misleading.
Close context capsules carry two items of information about the reason for closing: close codes and close details. In my mind, the close code is meant for software (if you receive this close code instead of that one, the implementation will behave differently) whereas the close details are for humans trying to debug things. So when we're thinking of adding a new close code (as opposed to sending more prose in close details), it begs the question: how would software treat GENERALERROR differently from NOERROR?
good question! We should probably try to capture the ethos of these error codes so everyone has the same expectation. For instance HTTP/3 says from HTTP status codes which indicate error conditions. Stream errors indicate that the sender did not transfer or consume the full request or response, while HTTP status codes indicate the result of a request that was successfully received. Is a close code more like a HTTP status code or a stream error code? It feels like the latter, so to use your examples, when thinking about retry registration, it sounds like we have categories where it is safe to retry registration (NOERROR), most definitely not allowed to retry (UNKNOWNFORMAT, DENIED), maybe retry (RESOURCELIMIT). So I guess a GENERALERROR type would fit into a maybe retry bucket. And if some new use of capsules requires "don't retry" where the existing codes aren't suited, they really should define a new code. Alternatively, we seem to just be reinventing HTTP status codes - so we could, y'know, just use that value range here :laughing:
I agree writing some text about the ethos and intended use of closes codes is a good idea. Perhaps something like: Close codes are intended to allow implementations to react differently when they receive them - for example, some close codes require the receiver to not open another context under certain conditions. Extensions to this mechanism MAY define new close codes if they wish to have receivers react differently. I don't think NOERROR is in the "safe to retry" category, because unknown codes are meant to be treated as NOERROR. Perhaps we merge NOERROR and GENERALERROR and rename the result UNKNOWN_ERROR?
How about we spin off "ethos and intention" to a new ticket? Ah good point. I'm all for bikeshedding a name - how about MAYBE_ERROR? I realise that the current definition is slightly ambiguous as to whether the `Close Details" field would be populated or not.
Sure! I prefer UNKNOWNERROR to MAYBEERROR, but I don't care too much. Agreed. Perhaps something like: NOERROR: This indicates that the registration was closed without any action specified for the receiver. I'm not loving that sentence, but my intent was to convey that close codes exist to carry some action or requirement of the receiver, and NOERROR carries no such action or requirement.
I think can handle the ethos stuff, I don't think we need to bother with an open and shut issue but if you do that's ok. That leaves the remaining question about name. I think with the new text it becomes clearer that the "NOERROR" is really just "CLOSEDWITHNOACTION"
I like . Beyond that, I don't much care about the name. Slight preference for NOERROR but I'm OK with CLOSEDWITHNOACTION
I'm happy without another error code right now. So how about we close this ticket and spin off just a naming bikeshed issue?
Sounds good, closing this one. I'll let you open the naming issue :)
Approved modulo a typo

The context ID to close. The close code allows an endpoint to provide additional  <ins> information as to why a datagram context was closed. close-codes defines a set of codes, the circumstances under which an implementation sends them, and how receivers react. </ins> This is meant for debugging purposes.  It consists of a human- readable string encoded in UTF-8. 4.4.3.1. <ins> Close codes are intended to allow implementations to react differently when they receive them - for example, some close codes require the receiver to not open another context under certain conditions. </ins> This specification defines the close codes below.  Their numeric  <ins> values are in iana-close-codes.  Extensions to this mechanism MAY define new close codes and they SHOULD state how receivers react to them. </ins>  <ins> This indicates that a context was closed without any action specified for the receiver. </ins> This indicates that the sender does not know how to interpret the datagram format type associated with this context.  The endpoint


6.  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

Most likely just need a sentence saying that the data stream is treated the same regardless if capsules are used or not.
Adding that sentence sounds fine by me.

6. <ins> Data streams (see capsule-protocol) can be prioritized using any means suited to stream or request prioritization.  For example, Section 11 of PRIORITY. </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


-1, so the largest legal value of Quarter Stream ID is 2 -1.  Receipt of a frame that includes a larger value MUST be <del> treated as a connection error of type FRAME_ENCODING_ERROR. </del>  The payload of the datagram, whose semantics are defined by individual applications.  Note that this field can be empty. Receipt of a QUIC DATAGRAM frame whose payload is too short to allow parsing the Quarter Stream ID field MUST be treated as an HTTP/3 <del> connection error of type H3_GENERAL_PROTOCOL_ERROR. </del>  Endpoints MUST NOT send HTTP/3 datagrams unless the corresponding stream's send side is open.  On a given endpoint, once the receive 4.2.  Definitions of new HTTP Upgrade Tokens that use the Capsule Protocol MAY use the Capsule-Protocol header field to simplify intermediary processing. Protocol header field value, but future documents MAY define parameters.  Receivers MUST ignore unknown parameters. <del> 4.3. </del>  This document defines the DATAGRAM capsule type (see iana-types for the value of the capsule type).  This capsule allows an endpoint to 8.2. This document will request IANA to register the following entry in  the "HTTP Field Name" registry: Capsule-Protocol None <del> 8.3. </del>  This document establishes a registry for HTTP capsule type codes. The "HTTP Capsule Types" registry governs a 62-bit space.

Borrowing text from H3. Also I don't think there is a 'FRAMEENCODINGERROR' defined anywhere.
Thanks! Approved pending some minor tweaks

-1, so the largest legal value of Quarter Stream ID is 2 -1.  Receipt of a frame that includes a larger value MUST be  <ins> treated as a connection error of type H3_DATAGRAM_ERROR. </ins> The payload of the datagram, whose semantics are defined by individual applications.  Note that this field can be empty. Receipt of a QUIC DATAGRAM frame whose payload is too short to allow parsing the Quarter Stream ID field MUST be treated as an HTTP/3  <ins> connection error of type H3_DATAGRAM_ERROR. </ins> Endpoints MUST NOT send HTTP/3 datagrams unless the corresponding stream's send side is open.  On a given endpoint, once the receive 4.2. <ins> When an error occurs 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 messages is described in section 4.1.3 of H3.  For HTTP/2, the handling of malformed messages is described in section 8.1.2.6 of H2. For HTTP/1.1, the handling of incomplete messages is described in section 8 of CORE-MESSAGING. 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 before the end of the identified fields MUST be treated as a malformed or incomplete message.  In particular, redundant length encodings MUST be verified to be self-consistent. When a stream carrying capsules terminates cleanly, if the last capsule on the stream was truncated, this MUST be treated as a malformed or incomplete message. 4.3. </ins> Definitions of new HTTP Upgrade Tokens that use the Capsule Protocol MAY use the Capsule-Protocol header field to simplify intermediary processing. Protocol header field value, but future documents MAY define parameters.  Receivers MUST ignore unknown parameters.  <ins> 4.4. </ins> This document defines the DATAGRAM capsule type (see iana-types for the value of the capsule type).  This capsule allows an endpoint to 8.2. This document will request IANA to register the following entry in <ins> the "HTTP/3 Error Code" registry: 8.3. This document will request IANA to register the following entry in </ins> the "HTTP Field Name" registry: Capsule-Protocol None  <ins> 8.4. </ins> This document establishes a registry for HTTP capsule type codes. The "HTTP Capsule Types" registry governs a 62-bit space.


streams, and those have stream IDs that are divisible by four). The largest legal QUIC stream ID value is 2 <del> -1, so the largest legal value of Quarter Stream ID is 2 </del>  <del> -1 / 4.  Receipt of a frame that includes a larger value MUST be </del>  treated as a connection error of type FRAME_ENCODING_ERROR. A variable-length integer indicating the context ID of the

Why would parentheses be required? Exponent has higher precedence than subtraction.
I think this proposal resolves the misinterpretation of 2^62 - (1/4)
Oh my bad, I had misread.

streams, and those have stream IDs that are divisible by four). The largest legal QUIC stream ID value is 2  <ins> -1, so the largest legal value of Quarter Stream ID is (2 </ins>  <ins> -1) / 4.  Receipt of a frame that includes a larger value MUST be </ins> treated as a connection error of type FRAME_ENCODING_ERROR. A variable-length integer indicating the context ID of the


Capsules MUST be forwarded unmodified by intermediaries, with the exception of the DATAGRAM capsule; see datagram-capsule.  An <del> intermediary that understands the request semantics enough to know that capsules are in use MAY convert between QUIC DATAGRAM frames and DATAGRAM capsules.  Definitions of new Capsule Types MAY specify optional custom intermediary processing. </del>  Endpoints which receive a Capsule with an unknown Capsule Type MUST silently drop that Capsule.

cc NAME
I think that this is right, but we should be more precise about what this means. That is, if the method is CONNECT and either: the intermediary understands the :protocol selection, or the request includes Capsule-Protocol Then the intermediary can forward DATAGRAM capsules as QUIC DATAGRAM frames or forward QUIC DATAGRAM frames as DATAGRAM capsules. Those conditions could be spelled out more clearly.
I agree. I'll add this to the . Note that this was filed on the wrong repository, is the droid you're looking for.
Oops. You should be able to move the issue.
Ah right, thanks! I've moved the issue.

Capsules MUST be forwarded unmodified by intermediaries, with the exception of the DATAGRAM capsule; see datagram-capsule.  An  <ins> intermediary can identify the use of the capsule protocol either through the presence of the Capsule-Protocol header field (hdr) or by understanding the chosen HTTP Upgrade token.  An intermediary that identifies the use of the capsule protocol MAY convert between DATAGRAM capsules and QUIC DATAGRAM frames when forwarding. Definitions of new Capsule Types MAY specify optional custom intermediary processing. </ins> Endpoints which receive a Capsule with an unknown Capsule Type MUST silently drop that Capsule.


the connection with error H3_SETTINGS_ERROR.  In all cases, the maximum permitted value of the H3_DATAGRAM SETTINGS parameter is 1.  5.1. [[RFC editor: please remove this section before publication.]] 7. <del> Since this feature requires sending an HTTP/3 Settings parameter, it "sticks out".  In other words, probing clients can learn whether a server supports this feature.  Implementations that support this feature SHOULD always send this Settings parameter to avoid leaking the fact that there are applications using HTTP/3 datagrams enabled on this endpoint. </del>  8.

The doc has evolved from just HTTP/3 Datagram, to define Capsule protocol and HTTP datagrams over capsule. In Security Considerations, we say It's a little ambiguous what "this feature" on face value. Arguably, the recommendation to always send the setting could be done in the section that defines the setting. Some editorial work would address these concerns.
Agreed
The intent is much clearer to me now, thanks!

the connection with error H3_SETTINGS_ERROR.  In all cases, the maximum permitted value of the H3_DATAGRAM SETTINGS parameter is 1. <ins> It is RECOMMENDED that implementations that support receiving HTTP Datagrams using QUIC always send the H3_DATAGRAM SETTINGS parameter with a value of 1, even if the application does not intend to use HTTP Datagrams.  This helps to avoid "sticking out"; see security. </ins> 5.1. [[RFC editor: please remove this section before publication.]] 7.  <ins> Since transmitting HTTP Datagrams using QUIC DATAGRAM frames requires sending an HTTP/3 Settings parameter, it "sticks out".  In other words, probing clients can learn whether a server supports HTTP Datagrams over QUIC DATAGRAM frames.  As some servers might wish to obfuscate the fact that they offer application services that use HTTP datagrams, it's best for all implementations that support this feature to always send this Settings parameter, see setting. </ins> 8.


This document will request IANA to register the following entry in the "HTTP/3 Settings" registry:  8.2. This document will request IANA to register the following entry in

The HTTP/3 spec was "contracted out to the QUIC WG", but the registries it establishes are given back to the the HTTP WG are all assigned permanent status and list a change controller of the IETF and a contact of the HTTP working group (EMAIL). This spec defines some new registries, it isn't clear to me which WG would "own" the registry after we are done with this spec.
Technically, IANA registries aren't owned by Working Groups. But adding the HTTP working group as a contact for the initial entries sounds fine by me. But I'd prefer to put this on hold until we're closer to publication.
WFM!

This document will request IANA to register the following entry in the "HTTP/3 Settings" registry: <ins> 0xffd277 (note that this will switch to a lower value before publication) H3_DATAGRAM 0 provisional (permanent if this document is approved) This Document IETF HTTP_WG; HTTP working group; ietf-http-wg@w3.org </ins> 8.2. This document will request IANA to register the following entry in


large without suffering any loss; this can misrepresent the true path properties, defeating methods such as DPLPMTUD.  5. Implementations of HTTP/3 that support HTTP Datagrams can indicate

In we discussed the risk presented by buffering extremely large datagram capsules. We should add some text to warn about this.
lgtm modulo nit

large without suffering any loss; this can misrepresent the true path properties, defeating methods such as DPLPMTUD. <ins> While DATAGRAM capsules can theoretically carry a payload of length 2 -1, most applications will have their own limits on what datagran payload sizes are practical.  Implementations SHOULD take those limits into account when parsing DATAGRAM capsules: if an incoming DATAGRAM capsule has a length that is known to be so large as to not be usable, the implementation SHOULD discard the capsule without buffering its contents into memory. </ins> 5. Implementations of HTTP/3 that support HTTP Datagrams can indicate


that datagram silently or buffer it temporarily while awaiting the creation of the corresponding stream.  HTTP/3 datagrams MUST only be sent with an association to a stream that supports semantics for HTTP Datagrams.  For example, existing HTTP methods GET and POST do not define semantics for associated HTTP

We say: This has some parallels to Extensible Priorities where we are expected to handling an H3 frame that might reference a stream that has not yet been created (most likely due to reordering). We can't avoid reordering but we can be more conservative on the frames that do get buffered. URL says: We can probably recommend something similar here.
This makes sense, sending an HTTP Datagram for a stream that you're not yet allowed to create violates a MUST in a detectable way so we can recommend punishment. Though I doubt that we'd implement this check.

that datagram silently or buffer it temporarily while awaiting the creation of the corresponding stream. <ins> 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 a connection error of 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. </ins> HTTP/3 datagrams MUST only be sent with an association to a stream that supports semantics for HTTP Datagrams.  For example, existing HTTP methods GET and POST do not define semantics for associated HTTP


4.3. <del> Definitions of new HTTP Upgrade Tokens that use the Capsule Protocol MAY use the Capsule-Protocol header field to simplify intermediary processing. "Capsule-Protocol" is an Item Structured Header (see STRUCTURED- FIELDS.  Its value MUST be a Boolean.  Its ABNF is: </del>  Endpoints indicate that the Capsule Protocol is in use on the data stream by sending the Capsule-Protocol header field with a value of Protocol header field value, but future documents MAY define parameters.  Receivers MUST ignore unknown parameters.  4.4. This document defines the DATAGRAM capsule type (see iana-types for

The HTTP WG is working on a style guide, see URL In line with the style, the reference to structured fields is updated in because it's less contentious. What remains here is probably more so. First, move the consideration for intermediaries to the bottom of the section. It doesn't seem a leading item to me. Then we start the section with a focus on defining the field itself. The ABNF is probably the bit we'll disagree with. It seems in trying to be specific on the Item type, you've written out the the subcomponents of the ABNF. This is something that is being discussed in the HTTP WG list. Personally I don't like being overly specific in the ABNF because it could be misconstrued as something that is SF-like but not really SF. As far as a generic SF parser goes, it will only validate that the thing is an Item and it will be up to higher layers to apply additional constraints on that. Parameters can always appear with an Item on the wire, whether an application allows that or not is a different matter. Restating ABNF makes this topic more thorny.

4.3.  <ins> This document defines the "Capsule-Protocol" header field.  It is an Item Structured Header RFC8941; its value MUST be a Boolean.  Its ABNF is: </ins> Endpoints indicate that the Capsule Protocol is in use on the data stream by sending the Capsule-Protocol header field with a value of Protocol header field value, but future documents MAY define parameters.  Receivers MUST ignore unknown parameters. <ins> Definitions of new HTTP Upgrade Tokens that use the Capsule Protocol MAY use the Capsule-Protocol header field to simplify intermediary processing. </ins> 4.4. This document defines the DATAGRAM capsule type (see iana-types for