jiebi/TextFlow huggingface dataset:
Original text:
3. This document defines the "connect-udp" HTTP Upgrade Token. "connect- <del> udp" uses the Capsule Protocol as defined in HTTP-DGRAM. </del>  Clients issue requests containing a "connect-udp" upgrade token to initiate a UDP tunnel associated with a single HTTP stream.  Tunnels

Reviewer comments:
Section 3 "connect-udp" uses the Capsule Protocol as defined in [HTTP-DGRAM]. What does "uses" here mean? As there are situations where the Capsule Protocol and the Datagram Capsule defined in HTTP-DGRAM is not required to be used, it is not clear if it MUST be implemented and MAY be used?
It would be better to link specifically to URL associated request's data stream uses the Capsule Protocol. If they do so, that means that the contents of the associated request's data stream uses the following format ...
and possibly forward ref to https://ietf-wg-URL
And that might be clearer, assuming that the implementation requirement is clear in those section of the HTTP datagram spec.

Revised text:
3. This document defines the "connect-udp" HTTP Upgrade Token. "connect-  <ins> udp" uses the Capsule Protocol as defined in HTTP-DGRAM.  The format of HTTP Datagrams is defined in format. </ins> Clients issue requests containing a "connect-udp" upgrade token to initiate a UDP tunnel associated with a single HTTP stream.  Tunnels
Original text:
the request SHALL include a single Host header field containing the origin of the UDP proxy. <del> the request SHALL include a single "Connection" header field with value "Upgrade" (note that this requirement is case-insensitive as per HTTP). </del>  the request SHALL include a single "Upgrade" header field with value "connect-udp".

Reviewer comments:
"Upgrade" (note that this requirement is case-insensitive as per {{Section 7.6.1 of HTTP}}). "Single" implies that there can't be other values (at least in other header lines, and possibly this one). That's an inappropriate constraint.
Thanks for catching this oversight, fixing via .

Revised text:
the request SHALL include a single Host header field containing the origin of the UDP proxy.  <ins> the request SHALL include a "Connection" header field with value "Upgrade" (note that this requirement is case-insensitive as per HTTP). </ins> the request SHALL include a single "Upgrade" header field with value "connect-udp".
Original text:
"Upgrade" (note that this requirement is case-insensitive as per HTTP). <del> the request SHALL include a single "Upgrade" header field with value "connect-udp". </del>  For example, if the client is configured with URI Template "https://proxy.example.org/.well-known/masque/

Reviewer comments:
"connect-udp". "Single" implies that this mechanism is incompatible with any other upgrade mechanisms. If that's actually the case, it might be good to state so explicitly, rather than rely on this single word.
Thanks for catching this oversight. Similar to , this was not the intent. Fixing via .

Revised text:
"Upgrade" (note that this requirement is case-insensitive as per HTTP).  <ins> the request SHALL include an "Upgrade" header field with value "connect-udp". </ins> For example, if the client is configured with URI Template "https://proxy.example.org/.well-known/masque/
Original text:
successful UDP proxying responses also do not carry any message content. <del> Responses to UDP proxying requests are not cacheable. </del> 3.1. Upon receiving a UDP proxying request, the recipient UDP proxy

Reviewer comments:
Try as we might, we can't retroactively place this requirement on the countless deployed caches on the Internet. Given that at least over HTTP/1.1 this mechanism uses GET, it might be better to specify that the GET response needs the appropriate caching metadata.
Good catch. That particular text came from back when we only used CONNECT, as that's defined as non-cacheable. Since defining how to cache Upgrade sounds like dragons holding footguns, I'm just going to remove this text via . That way we rely on existing HTTP documents to properly define how caching works.

Revised text:
successful UDP proxying responses also do not carry any message content.  3.1. Upon receiving a UDP proxying request, the recipient UDP proxy
Original text:
3.1. <del> Upon receiving a UDP proxying request, the recipient UDP 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. </del>  Unlike TCP, UDP is connection-less.  The UDP proxy that opens the UDP socket has no way of knowing whether the destination is reachable.

Reviewer comments:
Looking at the changes in the document I think I have picked up on another potential issue. Due to the discussion in URL I have to ask what happens if the client issues an Connect request over HTTP/2 that is then changed into an HTTP/1.1 request by an intermediate HTTP proxy in front of the actual MASQUE server. I don’t think this issue is discussed and what a MASQUE server does if it gets a CONNECT request with an Connect-UDP upgrade header.
In that scenario, the client will send: and the intermediary converting from HTTP/2 to HTTP/1.1 will convert that to: That works as expected. Are you saying there's a problem here?
Probably worth a mention in this spec, like CONNECT already does, that a proxy can forward CONNECT-UDP requests to a proxy it has configured. I don't think much more detail is required than that. Such a proxy needs to follow the normative requirements set out else where. Concerns about converting requests between HTTP versions are common and not terribly unique here.
That sounds like a worthwhile clarification. Tagging as editorial.
LGTM, parity with HTTP without compromising existing tone / style

Revised text:
3.1.  <ins> Upon receiving a UDP proxying request: if the recipient is configured to use another HTTP proxy, it will act as an intermediary: it forwards the request to another HTTP server.  Note that such intermediaries may need to reencode the request if they forward it using a version of HTTP that is different from the one used to receive it, as the request encoding differs by version (see below). otherwise, the recipient will act as a UDP proxy: it 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> Unlike TCP, UDP is connection-less.  The UDP proxy that opens the UDP socket has no way of knowing whether the destination is reachable.
Original text:
certainty that the inner traffic is congestion-controlled. If a client or UDP proxy with a connection containing a UDP proxying <del> 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. </del>  When the protocol running over UDP that is being proxied uses loss recovery (e.g., QUIC), and the underlying HTTP connection runs over

Reviewer comments:
From AD Review: Expand the acronym and add a (normative!) reference.
I'm going to mark this editorial since it's just clarifying what ECN is, and I don't believe we've had any confusion on that point among working group members.
The second commit explicitly mentions the TCP ECN feedback mechanism, for completeness. And yes, this is editorial.

Revised text:
certainty that the inner traffic is congestion-controlled. If a client or UDP proxy with a connection containing a UDP proxying  <ins> request stream disables congestion control, it MUST NOT signal Explicit Congestion Notification (ECN) 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 QUIC ACK_ECN frames or the TCP "ECE" bit, 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
Original text:
Since the original HTTP CONNECT method allowed conveying the target host and port but not the scheme, proxy authority, path, nor query, <del> 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 MAY attempt to access UDP proxying capabilities using the default template, which is defined as: </del>  "https://$PROXY_HOST:$PROXY_PORT/.well-known/masque/ udp/{target_host}/{target_port}/" where $PROXY_HOST and $PROXY_PORT are the configured host and port of the UDP proxy respectively.  UDP

Reviewer comments:
Nit from the AD review. Reading this sentence, it took me a moment to figure out if we were talking about config on the client or the on the proxy.

Revised text:
Since the original HTTP CONNECT method allowed conveying the target host and port but not the scheme, proxy authority, path, nor query,  <ins> there exist clients with 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 MAY attempt to access UDP proxying capabilities using the default template, which is defined as: </ins> "https://$PROXY_HOST:$PROXY_PORT/.well-known/masque/ udp/{target_host}/{target_port}/" where $PROXY_HOST and $PROXY_PORT are the configured host and port of the UDP proxy respectively.  UDP
Original text:
8.2. <del> This document will request IANA to register "masque/udp" in the "Well-Known URIs" registry maintained at </del>  <<https://www.iana.org/assignments/well-known-uris>>.

Reviewer comments:
As per registrations cannot contain a character so we register instead of
L602 still includes /udp, Is that intended?
Yeah my thinking was that we register and for now only define semantics for . A future document can tweak the related info line to also assign semantics to
I'm not a .well-known expert. My interpretation from mnot's suggestion was the prefix ends up as ".well-known/masque" and that the remainder is defined here as "/udp/{targethost}/{targetport}". Yes something else might come along and define other things to follow the prefix .well-known/masque but that can be deferred for later, and that spec needs to state all of its own rules. An alternative is that we expect everything after the prefix to behave in a similar way, I.e. .well-known/masque/{masquetype}/{targethost}/{target_port}. I don't know if that holds true.
From reading it appears that there is a lot of flexibility on how to organize additional path components so this appears OK to me, but I'll let NAME provide insights here
Yep, how you deal with what's "under" your registration is up to you. One option is to create a separate registry; another is to require additional values to update the registering RFC.

Revised text:
8.2.  <ins> This document will request IANA to register "masque" in the "Well- Known URIs" registry maintained at </ins> <<https://www.iana.org/assignments/well-known-uris>>.
Original text:
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 <del> they have established support on a given connection.  If negotiation of HTTP Datagrams fails (for example if an HTTP/3 SETTINGS frame was received without the H3_DATAGRAM SETTINGS Parameter), the client MUST consider its CONNECT-UDP request as failed. </del>  The proxy that is creating the UDP socket to the destination responds to the CONNECT-UDP request with a 2xx (Successful) response.

Reviewer comments:
In Sec. 4 it says: If negotiation of HTTP Datagrams fails (for example if an HTTP/3 SETTINGS frame was received without the H3_DATAGRAM SETTINGS Parameter), the client MUST consider its CONNECT-UDP request as failed. IIUC it is entirely possible to do CONNECT-UDP entirely with CAPSULE frames, so I don't see why a client should fail the attempt because the first hop is H/2 only, or whatever.
Thanks for writing this up. I think this is the right solution. I'll leave this open for some time to see if anyone else would like to comment. To add context: this text predates the creation of capsules, and now CONNECT-UDP works even if QUIC datagram frames aren't available. We'll want to pick a solution for URL though. If the H3_DATAGRAM setting also covers capsules we might still need this text. But for now we can remove it.

Revised text:
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  <ins> they have established support on a given connection. </ins> The proxy that is creating the UDP socket to the destination responds to the CONNECT-UDP request with a 2xx (Successful) response.
Original text:
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.  6.

Reviewer comments:
This is partly related to URL but seems to fit its own issue. Let's assume a CONNECT-UDP request succeeds with a 2xx and a flow of datagrams is merrily exchanged. How do endpoints indicate they are done with the stream and associated flows? The spec doesn't really say anything. The main example I can think of is where a server decides to perform housekeeping on UDP connections (maybe as part of runtime garbage collection, or in reaction to the network stack throwing errors) after a 2xx was been sent. H3 CONNECT says ends the request stream (that is, the receive stream at the proxy enters the "Data Recvd" state), the proxy will set the FIN bit on its connection to the TCP server. When the proxy receives a packet with the FIN bit set, it will close the send stream that it sends to the client. TCP connections that remain half-closed in a single direction are not invalid, but are often handled poorly by servers, so clients SHOULD NOT close a stream for sending while they still expect to receive data from the target of the CONNECT. stream. A proxy treats any error in the TCP connection, which includes receiving a TCP segment with the RST bit set, as a stream error of type H3CONNECTERROR; see Section 8. Correspondingly, if a proxy detects an error with the stream or the QUIC connection, it MUST close the TCP connection. If the underlying TCP implementation permits it, the proxy SHOULD send a TCP segment with the RST bit set. Not all of that guidance directly translates but I think it would be helpful to set some expectations for endpoints wrt how stream read or write states might change during the lifetime of a CONNECT-UDP request - especially in the cases where no stream data is being exchanged.
I took "FIN or RESET = done" as a given, but it's worth stating. Proxy behavior will likely be identical in both the graceful and abrupt closure cases.

Revised text:
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. <ins> If a proxy is notified by its operating system that its socket is no longer usable, it MUST close the CONNECT-UDP stream. </ins> 6.
Original text:
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

Reviewer comments:
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.

Revised text:
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
Original text:
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.

Reviewer comments:
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.

Revised text:
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.
Original text:
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.

Reviewer comments:
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?

Revised text:
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.
Original text:
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.

Reviewer comments:
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.

Revised text:
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.
Original text:
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:

Reviewer comments:
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

Revised text:
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: