If a path has been validated to support ECN (RFC3168, RFC8311), QUIC treats a Congestion Experienced (CE) codepoint in the IP header as a signal of congestion.  This document specifies an endpoint's response <del> when its peer receives packets with the ECN-CE codepoint. </del>  7.2.

Also removes odd MAY when suggesting that a sender can use TCP's pipeACK method. Addresses .
In Recovery-31 there are several references that I judge as normative and not informative ones. Section 7.8: "A sender MAY use the pipeACK method described in Section 4.3 of [RFC7661] to determine if the congestion window is sufficiently utilized." A normative reference necessary to follow if one selects to use the optional method.Sectiom 7.3.2: "Implementations MAY reduce the congestion window immediately upon entering a recovery period or use other mechanisms, such as Proportional Rate Reduction ([PRR]), to reduce the congestion window more gradually." Another case of a suggested mechanism, which if one is to follow it requires one to read that PPR reference. Secondly, why the alternative reference style.Section 8.3: "Markings can be treated as equivalent to loss ([RFC3168]), but other responses can be specified, such as ([RFC8511]) or ([RFC8311])." So RFC3168 is the normative specification for the treat it equal to loss. RFC8511 is the TCP alternative back-off an experimental specification for the alternative. And RFC8311 is the process for performing other experiments with alternative responses. I judge all necessary depending on what one intendeds to do. So to my understanding this results in two downrefs to experimental specifications. I think that is acceptable in the context they are used in this document. But to be tried in IETF last call. However, I think I don't want to generally recommend them to be acceptable as downrefs so I have no intentions to promote them for the Downref registry.
Moving discussion from the PR to the issue. NAME : I'm not the expert on what should be normative, but these were intentionally marked as informative references since they're all TCP specific RFCs. The pipeACK reference in particular seems like an odd one. If this is what the chairs want, then I'm ok with it as an editor, but these choices were intentional. NAME : I see what NAME is saying, but I also see some wiggle room in RFC 3967, Section 1.1: When a reference to an example is made, such a reference need not be normative. For example, text such as "an algorithm such as the one specified in [RFCxxxx] would be acceptable" indicates an informative reference, since that cited algorithm is just one of several possible algorithms that could be used. I am also somewhat concerned that trying to get the downrefs into the registry is more likely to run into trouble (Sec 3) This procedure should not be used if the proper step is to move the document to which the reference is being made into the appropriate category. It is not intended as an easy way out of normal process. Rather, the procedure is intended for dealing with specific cases where putting particular documents into the required category is problematic and unlikely ever to happen.
Thanks for digging up the relevant text, NAME Based on that text from RFC 3967, it doesn't seem like we need to make these references normative. I agree that the pipeACK reference is odd, but I think that's probably because of the use of MAY there. I'm happy to replace the MAY with a can -- it is meant to present an option, not a permission -- and make that reference informative as well. NAME : thoughts?
I think at last RFC3168 should be referenced normatively somewhere (probably section 7.1 though) because you need to know what the ECN bits are in order to do anything with it. I guess because of section 7.1. RFC8311 should also be a normative reference.
NAME RFC3168 is already a normative reference in the transport doc, which in my view is appropriate.
Was wondering about this as well given the transport doc is of course a normative reference of this doc. However, as this doc uses terms like CE also directly itself I think the right practice is to also have it as a normative reference here, and as you have to read it no matter what, it definitely shouldn't hurt.
talks about ECN-CE markings, but really all of Section 7 talks about a response to an increase in ECN-CE count by the peer, which is defined in the transport doc. This does point to a small editorial issue. The text in Section 4.1 says: This really should be:
Good point on the editorial issue.
With that change, the only thing we're left with is . This does require an understanding of ECN, and it has RFC 2119 keywords, but it's really an optional mechanism that is suggested. We could remove the RFC 2119 words there, since they're really unnecessary.
My point is that RFC3168 should be normative because not matter what you need to understand what an ECN-CE mark is and that is defined/specified in RFC3168.
Mirja has a point, see URL
-transport is a normative reference. So 3168 is already (transitively) a normative reference. The question is whether this specific text requires anything from 3168 to understand. I don't see that it does, especially given the suggested change, which talks about a concept defined in -transport, not 3168.
has made these editorial changes; NAME can you see if anything else needs to be done here?
I will note that it was never my intention to let any of theses Experimental or informational TCP specs to be added into the downref registry by this last call. So, the pipeack reference needs to be reformulated to not be a normative one. As currently stated it is a clear normative reference per IESG Statement ([URL]) , and especially "Note 1: Even references that are relevant only for optional features must be classified as normative if they meet the above conditions for normative references. " You need to find a formulation that normative describes what the implementation MAY do, and then you can exemplify with the TCP version. Then one in Section 7.3.2 I can accept as still being informative as the MAY statement is related to the primary aspect of the sentence and the reference to PPR is exemplifying. Still this is very much on the border and may still generate a comment in IESG. For RFC 3168 I don't understand why not making it to a normative one. There are no issues with its status as it is proposed standard. And simply the security consideration section still implies that you need to know what a ECN-CE mark is to interpret this. So please make this one normative.
I'm ok with RFC 3168 being normative, particularly since it's already normative in transport, but would like to avoid making the others normative.
NAME if pipeack is not normative then a reformulation is necessary of that sentence in Section 7.8 to not state is as a mechanism that MAY be implemented.
The sentence currently has a can, not a MAY: "A sender can use the pipeACK method described in Section 4.3 of {{?RFC7661}} to determine if the congestion window is sufficiently utilized." But I sent out PR to make it clearer that pipeACK is an example, PTAL and see if that helps.
NAME what PR proposes removing that first sentence do resolve the pipeack to me. So merging , and moving RFC3168 to normative will resolve this issue to my understanding.
Thanks! I'll update PR to include moving RFC3168 to normative.
NAME NAME : I believe this is purely editorial, but I'd like to confirm.
We've meandered to a route that AFAICT makes reference types accurate to their existing intent, or avoids them becoming normative. I'm happy for this to be editorials.
I think that this is the most appropriate response.

If a path has been validated to support ECN (RFC3168, RFC8311), QUIC treats a Congestion Experienced (CE) codepoint in the IP header as a signal of congestion.  This document specifies an endpoint's response  <ins> when the peer-reported ECN-CE count increases; see Section 13.4.2 of QUIC-TRANSPORT. </ins> 7.2.


the congestion window. The minimum congestion window is the smallest value the congestion <del> window can decrease to as a response to loss, ECN-CE, or persistent congestion.  The RECOMMENDED value is 2 * max_datagram_size. </del>  7.3.

the congestion window. The minimum congestion window is the smallest value the congestion  <ins> window can decrease to as a response to loss, increase in the peer- reported ECN-CE count, or persistent congestion.  The RECOMMENDED value is 2 * max_datagram_size. </ins> 7.3.


increased in either slow start or congestion avoidance.  This can happen due to insufficient application data or flow control limits. <del> A sender MAY use the pipeACK method described in Section 4.3 of </del>  RFC7661 to determine if the congestion window is sufficiently utilized.

increased in either slow start or congestion avoidance.  This can happen due to insufficient application data or flow control limits.  <ins> A sender can use the pipeACK method described in Section 4.3 of </ins> RFC7661 to determine if the congestion window is sufficiently utilized.


cause a sender to increase their send rate.  This increase could result in congestion and loss. <del> A sender MAY attempt to detect suppression of reports by marking occasional packets that they send with ECN-CE.  If a packet sent with ECN-CE is not reported as having been CE marked when the packet is acknowledged, then the sender SHOULD disable ECN for that path. </del>  Reporting additional ECN-CE markings will cause a sender to reduce their sending rate, which is similar in effect to advertising reduced

cause a sender to increase their send rate.  This increase could result in congestion and loss.  <ins> A sender can detect suppression of reports by marking occasional packets that it sends with an ECN-CE marking.  If a packet sent with an ECN-CE marking is not reported as having been CE marked when the packet is acknowledged, then the sender can disable ECN for that path by not setting ECT codepoints in subsequent packets sent on that path RFC3168. </ins> Reporting additional ECN-CE markings will cause a sender to reduce their sending rate, which is similar in effect to advertising reduced


packetization defines models for the transmission, retransmission, and acknowledgement of data, and <del> packet-size specifies rules for managing the size of packets. </del>  Finally, encoding details of QUIC protocol elements are described in:

Addresses . NAME points out in that we use in the transport draft and in the recovery draft. In reading carefully, I realized that in the transport draft was actually historical, and is the more appropriate term. This is an entirely editorial PR, and it's largely simple changes, despite the fact that it looks a bit big. It is a bit subtle though. Sorry about that.
This issue will list a number of minor editorial things that should be checked and likely addressed with some editorial fixes: Section 5.3: "These delays are computed using the ACK Delay field of the ACK frame as described in Section 19.3 of [QUIC-TRANSPORT]." This text implies that the computation of the delay is described in Section 19.3 of QUIC-TRANSPORT. However, I don't think it is described the calculation, only the definition of the field. Please reformulate to imply only field definition not calculation. Section 5.3: "On the first RTT sample for the network path, that sample is used as rttsample. This ensures that the first measurement erases the history of any persisted or default values." I think this intended to cover cases where path changes are detected. But it is not well expressed. Does this need a reformulation and a reference into QUIC-TRANSPORT where it states when such a reset should occur? Section 6.1: "Either its packet number is kPacketThreshold smaller than an acknowledged packet" Nitpicking, assuming no PN gaps in transmission. Does that need a note? Section 6.2.4: "An endpoint MAY send up to two full-sized datagrams containing ack-eliciting packets, to avoid an expensive consecutive PTO expiration due to a single lost datagram or transmit data from multiple packet number spaces." This last part, I assume intended to generate additional datagrams to prevent single loss to impact. However, due to coalescing this is unclear in this context. Section 7: "Endpoints can unilaterally choose a different algorithm to use, such as Cubic ([RFC8312])." I think this sentence should be explicit that in needs to be sender-based algorithms. I think we need to have the requirement on performing congestion control on the sender unless there has been explicit agreement with the receiver that they will do it. Section 7.2: "Endpoints SHOULD use an initial congestion window of 10 times the maximum datagram size (maxdatagramsize), limited to the larger of 14720 bytes or twice the maximum datagram size." "maximum datagram size" is not used in Transport there need to be alignment here of what name to use. Transport has Maximum Packet Size, which appears to match the definition in the appendix of maxdatagram_size.
Thanks for your careful review, NAME -- these are good finds! I've addressed your comments below and in . I'll address point 6 in a separate PR. Section 19.3 has the following text, which does tell how to compute acknowledgement delay from the ACK Delay field: I've replaced "computed" with "decoded" in the recovery document to make it clearer. Coalescing applies to packets, not to datagrams. We've explicitly stated that a sender could send 2 datagrams to avoid any effects of coalescing. I think the text is pretty clear on this: "An endpoint MAY send up to two full-sized datagrams containing ack-eliciting packets". I've added "sender-side" to make the controller more explicit. To your point about making this a sender requirement, that is covered in the transport doc (end of ):
Based on and , labeling this as "editorial"
I think these issues are resolved once the two PRs are completely ready.
Except for the one erronous exchange of packet this looks good.

packetization defines models for the transmission, retransmission, and acknowledgement of data, and  <ins> datagram-size specifies rules for managing the size of datagrams carrying QUIC packets. </ins> Finally, encoding details of QUIC protocol elements are described in:


14. <del> The QUIC packet size includes the QUIC header and protected payload, but not the UDP or IP headers. </del>  QUIC depends upon a minimum IP packet size of at least 1280 bytes. This is the IPv6 minimum size (IPv6) and is also supported by most <del> modern IPv4 networks.  Assuming the minimum IP header size, this results in a QUIC maximum packet size of 1232 bytes for IPv6 and 1252 bytes for IPv4. </del>  <del> The QUIC maximum packet size is the largest size of QUIC packet that can be sent across a network path using a single packet.  Any maximum packet size larger than 1200 bytes can be discovered using Path Maximum Transmission Unit Discovery (PMTUD; see pmtud) or Datagram Packetization Layer PMTU Discovery (DPLPMTUD; see dplpmtud). </del>  Enforcement of the max_udp_payload_size transport parameter (transport-parameter-definitions) might act as an additional limit on <del> the maximum packet size.  A sender can avoid exceeding this limit, </del>  once the value is known.  However, prior to learning the value of the transport parameter, endpoints risk datagrams being lost if they send <del> packets larger than the smallest allowed maximum packet size of 1200 bytes. </del>  UDP datagrams MUST NOT be fragmented at the IP layer.  In IPv4 (IPv4), the DF bit MUST be set if possible, to prevent fragmentation

14.  <ins> A UDP datagram can include one or more QUIC packets.  The datagram size refers to the total UDP payload size of a single UDP datagram carrying QUIC packets.  The datagram size includes one or more QUIC packet headers and protected payloads, but not the UDP or IP headers. The maximum datagram size is defined as the largest size of UDP payload that can be sent across a network path using a single UDP datagram. </ins> QUIC depends upon a minimum IP packet size of at least 1280 bytes. This is the IPv6 minimum size (IPv6) and is also supported by most  <ins> modern IPv4 networks.  Assuming the minimum IP header size of 40 bytes for IPv6 and 20 bytes for IPv4 and a UDP header size of 8 bytes, this results in a maximum datagram size of 1232 bytes for IPv6 and 1252 bytes for IPv4. The maximum datagram size MUST be at least 1200 bytes. </ins>  <ins> Any maximum datagram size larger than 1200 bytes can be discovered using Path Maximum Transmission Unit Discovery (PMTUD; see pmtud) or Datagram Packetization Layer PMTU Discovery (DPLPMTUD; see dplpmtud). </ins> Enforcement of the max_udp_payload_size transport parameter (transport-parameter-definitions) might act as an additional limit on  <ins> the maximum datagram size.  A sender can avoid exceeding this limit, </ins> once the value is known.  However, prior to learning the value of the transport parameter, endpoints risk datagrams being lost if they send  <ins> datagrams larger than the smallest allowed maximum datagram size of 1200 bytes. </ins> UDP datagrams MUST NOT be fragmented at the IP layer.  In IPv4 (IPv4), the DF bit MUST be set if possible, to prevent fragmentation


14.1. A client MUST expand the payload of all UDP datagrams carrying <del> Initial packets to at least the smallest allowed maximum packet size (1200 bytes) by adding PADDING frames to the Initial packet or by coalescing the Initial packet; see packet-coalesce.  Sending a UDP </del>  datagram of this size ensures that the network path from the client to the server supports a reasonable Path Maximum Transmission Unit (PMTU).  This also helps reduce the amplitude of amplification

14.1. A client MUST expand the payload of all UDP datagrams carrying  <ins> Initial packets to at least the smallest allowed maximum datagram size (1200 bytes) by adding PADDING frames to the Initial packet or by coalescing the Initial packet; see packet-coalesce.  Sending a UDP </ins> datagram of this size ensures that the network path from the client to the server supports a reasonable Path Maximum Transmission Unit (PMTU).  This also helps reduce the amplitude of amplification


that it chooses. A server MUST discard an Initial packet that is carried in a UDP <del> datagram with a payload that is less than the smallest allowed maximum packet size of 1200 bytes.  A server MAY also immediately </del>  close the connection by sending a CONNECTION_CLOSE frame with an error code of PROTOCOL_VIOLATION; see immediate-close-hs.

that it chooses. A server MUST discard an Initial packet that is carried in a UDP  <ins> datagram with a payload that is smaller than the smallest allowed maximum datagram size of 1200 bytes.  A server MAY also immediately </ins> close the connection by sending a CONNECTION_CLOSE frame with an error code of PROTOCOL_VIOLATION; see immediate-close-hs.


The Path Maximum Transmission Unit (PMTU) is the maximum size of the entire IP packet including the IP header, UDP header, and UDP <del> payload.  The UDP payload includes the QUIC packet header, protected payload, and any authentication fields.  The PMTU can depend on path characteristics, and can therefore change over time.  The largest UDP payload an endpoint sends at any given time is referred to as the endpoint's maximum packet size. </del>  An endpoint SHOULD use DPLPMTUD (dplpmtud) or PMTUD (pmtud) to determine whether the path to a destination will support a desired <del> maximum packet size without fragmentation.  In the absence of these mechanisms, QUIC endpoints SHOULD NOT send IP packets larger than the smallest allowed maximum packet size. </del>  <del> Both DPLPMTUD and PMTUD send IP packets that are larger than the current maximum packet size, referred to as PMTU probes.  All QUIC </del>  packets that are not sent in a PMTU probe SHOULD be sized to fit <del> within the maximum packet size to avoid the packet being fragmented or dropped (RFC8085). </del>  If a QUIC endpoint determines that the PMTU between any pair of local and remote IP addresses has fallen below the smallest allowed maximum <del> packet size of 1200 bytes, it MUST immediately cease sending QUIC </del>  packets, except for those in PMTU probes or those containing CONNECTION_CLOSE frames, on the affected path.  An endpoint MAY terminate the connection if an alternative path cannot be found. Each pair of local and remote addresses could have a different PMTU. QUIC implementations that implement any kind of PMTU discovery <del> therefore SHOULD maintain a maximum packet size for each combination of local and remote IP addresses. </del>  A QUIC implementation MAY be more conservative in computing the <del> maximum packet size to allow for unknown tunnel overheads or IP </del>  header options/extensions. 14.2.1. Path Maximum Transmission Unit Discovery (PMTUD; RFC1191, RFC8201) relies on reception of ICMP messages (e.g., IPv6 Packet Too Big <del> messages) that indicate when a packet is dropped because it is larger than the local router MTU.  DPLPMTUD can also optionally use these messages.  This use of ICMP messages is potentially vulnerable to off-path attacks that successfully guess the addresses used on the </del>  path and reduce the PMTU to a bandwidth-inefficient value. An endpoint MUST ignore an ICMP message that claims the PMTU has <del> decreased below the minimum QUIC packet size. </del>  The requirements for generating ICMP (RFC1812, RFC4443) state that the quoted packet should contain as much of the original packet as

The Path Maximum Transmission Unit (PMTU) is the maximum size of the entire IP packet including the IP header, UDP header, and UDP  <ins> payload.  The UDP payload includes one or more QUIC packet headers and protected payloads.  The PMTU can depend on path characteristics, and can therefore change over time.  The largest UDP payload an endpoint sends at any given time is referred to as the endpoint's maximum datagram size. </ins> An endpoint SHOULD use DPLPMTUD (dplpmtud) or PMTUD (pmtud) to determine whether the path to a destination will support a desired  <ins> maximum datagram size without fragmentation.  In the absence of these mechanisms, QUIC endpoints SHOULD NOT send datagrams larger than the smallest allowed maximum datagram size. </ins>  <ins> Both DPLPMTUD and PMTUD send datagrams that are larger than the current maximum datagram size, referred to as PMTU probes.  All QUIC </ins> packets that are not sent in a PMTU probe SHOULD be sized to fit  <ins> within the maximum datagram size to avoid the datagram being fragmented or dropped (RFC8085). </ins> If a QUIC endpoint determines that the PMTU between any pair of local and remote IP addresses has fallen below the smallest allowed maximum  <ins> datagram size of 1200 bytes, it MUST immediately cease sending QUIC </ins> packets, except for those in PMTU probes or those containing CONNECTION_CLOSE frames, on the affected path.  An endpoint MAY terminate the connection if an alternative path cannot be found. Each pair of local and remote addresses could have a different PMTU. QUIC implementations that implement any kind of PMTU discovery  <ins> therefore SHOULD maintain a maximum datagram size for each combination of local and remote IP addresses. </ins> A QUIC implementation MAY be more conservative in computing the  <ins> maximum datagram size to allow for unknown tunnel overheads or IP </ins> header options/extensions. 14.2.1. Path Maximum Transmission Unit Discovery (PMTUD; RFC1191, RFC8201) relies on reception of ICMP messages (e.g., IPv6 Packet Too Big  <ins> messages) that indicate when an IP packet is dropped because it is larger than the local router MTU.  DPLPMTUD can also optionally use these messages.  This use of ICMP messages is potentially vulnerable to off-path attacks that successfully guess the addresses used on the </ins> path and reduce the PMTU to a bandwidth-inefficient value. An endpoint MUST ignore an ICMP message that claims the PMTU has  <ins> decreased below QUIC's smallest allowed maximum datagram size. </ins> The requirements for generating ICMP (RFC1812, RFC4443) state that the quoted packet should contain as much of the original packet as


validation. An endpoint MUST NOT increase PMTU based on ICMP messages; see <del> Section 3, clause 6 of DPLPMTUD.  Any reduction in the QUIC maximum packet size in response to ICMP messages MAY be provisional until </del>  QUIC's loss detection algorithm determines that the quoted packet has actually been lost.

validation. An endpoint MUST NOT increase PMTU based on ICMP messages; see  <ins> Section 3, clause 6 of DPLPMTUD.  Any reduction in QUIC's maximum datagram size in response to ICMP messages MAY be provisional until </ins> QUIC's loss detection algorithm determines that the quoted packet has actually been lost.


PADDING frame implement "Probing using padding data", as defined in Section 4.1 of DPLPMTUD. <del> Endpoints SHOULD set the initial value of BASE_PMTU (see Section 5.1 of DPLPMTUD) to be consistent with the minimum QUIC packet size.  The MIN_PLPMTU is the same as the BASE_PMTU. </del>  <del> QUIC endpoints implementing DPLPMTUD maintain a maximum packet size (DPLPMTUD MPS) for each combination of local and remote IP addresses. </del>  14.3.1. From the perspective of DPLPMTUD, QUIC is an acknowledged <del> packetization layer (PL).  A sender can therefore enter the DPLPMTUD BASE state when the QUIC connection handshake has been completed. </del>  14.3.2. <del> QUIC provides an acknowledged PL, therefore a sender does not implement the DPLPMTUD CONFIRMATION_TIMER while in the SEARCH_COMPLETE state; see Section 5.2 of DPLPMTUD. </del>  14.3.3.

PADDING frame implement "Probing using padding data", as defined in Section 4.1 of DPLPMTUD.  <ins> Endpoints SHOULD set the initial value of BASE_PLPMTU (Section 5.1 of DPLPMTUD) to be consistent with QUIC's smallest allowed maximum datagram size.  The MIN_PLPMTU is the same as the BASE_PLPMTU. </ins>  <ins> QUIC endpoints implementing DPLPMTUD maintain a DPLPMTUD Maximum Packet Size (MPS, Section 4.4 of DPLPMTUD) for each combination of local and remote IP addresses.  This corresponds to the maximum datagram size. </ins> 14.3.1. From the perspective of DPLPMTUD, QUIC is an acknowledged  <ins> Packetization Layer (PL).  A QUIC sender can therefore enter the DPLPMTUD BASE state (Section 5.2 of DPLPMTUD) when the QUIC connection handshake has been completed. </ins> 14.3.2.  <ins> QUIC is an acknowledged PL, therefore a QUIC sender does not implement a DPLPMTUD CONFIRMATION_TIMER while in the SEARCH_COMPLETE state; see Section 5.2 of DPLPMTUD. </ins> 14.3.3.


PMTU probes are ack-eliciting packets. Endpoints could limit the content of PMTU probes to PING and PADDING <del> frames as packets that are larger than the current maximum packet size are more likely to be dropped by the network.  Loss of a QUIC packet that is carried in a PMTU probe is therefore not a reliable indication of congestion and SHOULD NOT trigger a congestion control reaction; see Section 3, Bullet 7 of DPLPMTUD.  However, PMTU probes consume congestion window, which could delay subsequent transmission by an application. </del>  14.4.1.

PMTU probes are ack-eliciting packets. Endpoints could limit the content of PMTU probes to PING and PADDING  <ins> frames, since packets that are larger than the current maximum datagram size are more likely to be dropped by the network.  Loss of a QUIC packet that is carried in a PMTU probe is therefore not a reliable indication of congestion and SHOULD NOT trigger a congestion control reaction; see Section 3, Bullet 7 of DPLPMTUD.  However, PMTU probes consume congestion window, which could delay subsequent transmission by an application. </ins> 14.4.1.


This limit does act as an additional constraint on datagram size in the same way as the path MTU, but it is a property of the <del> endpoint and not the path; see packet-size.  It is expected that </del>  this is the space an endpoint dedicates to holding incoming packets.

This limit does act as an additional constraint on datagram size in the same way as the path MTU, but it is a property of the  <ins> endpoint and not the path; see datagram-size.  It is expected that </ins> this is the space an endpoint dedicates to holding incoming packets.


tuple, as shown in transport-parameter-encoding-fig: The Transport Parameter Length field contains the length of the <del> Transport Parameter Value field. </del>  QUIC encodes transport parameters into a sequence of bytes, which is then included in the cryptographic handshake.

Does this win the record for least amount of bytes touched in a PR?
Lars, I can't find it easily, but I believe that I pushed a 1 bit change at one point in this process.
Parameter Value field. Presumably the length in bytes.

tuple, as shown in transport-parameter-encoding-fig: The Transport Parameter Length field contains the length of the  <ins> Transport Parameter Value field in bytes. </ins> QUIC encodes transport parameters into a sequence of bytes, which is then included in the cryptographic handshake.


entity that receives an Initial packet from a client can recover the keys that will allow them to both read the contents of the packet and generate Initial packets that will be successfully authenticated at <del> either endpoint. </del>  All other packets are protected with keys derived from the cryptographic handshake.  The cryptographic handshake ensures that

The description neglected to mention this. Obviously, the confidentiality protection (specifically, the lack thereof) is the part that needs to be highlighted, but we shouldn't neglect the other purpose of using an AEAD here.

entity that receives an Initial packet from a client can recover the keys that will allow them to both read the contents of the packet and generate Initial packets that will be successfully authenticated at  <ins> either endpoint.  The AEAD also protects Initial packets against accidental modification. </ins> All other packets are protected with keys derived from the cryptographic handshake.  The cryptographic handshake ensures that


the inclusion of uppercase field names, or <del> the inclusion of invalid characters in field names or values </del>  A request or response that includes a payload body can include a Content-Length header field.  A request or response is also malformed

if we want to do that. There was a hole in the error code space, so I filled it with this. I haven't pulled Push out to its own error; it doesn't seem like it belongs with this one.
We might want to add a mention of this in A.4 where we talk about PROTOCOL_ERROR
(I couldn't find anything on this, but I'm prepared to be corrected. Also, it's late, so if this is closed, I'm totally OK with that.) We're just in the process of doing full validation of pseudo-header fields (I know, seems late, what are you gonna do about that). And we realized that there is no error code for indicating this sort of error. That is, if pseudo-fields are out of order, or a request contains , or there are uppercase characters. contains lots of MUSTs, but it seems to rely entirely on the definition of "malformed" which leads to H3GENERALPROTOCOL_ERROR. This is fine, but not especially helpful in isolating problems. Could we define an error code for this specific case?
H2 just says malformed is treated as PROTOCOL_ERROR. So H3 is providing parity. There might be an argument for more fidelity but I'm not convinced it would help much. It could require more contortions in the text - do you have different error for different types of malformed?
Internally, we use a different error code. Of course, all internal error codes map to the same code for sending in RESETSTREAM/CONNECTIONCLOSE.
I'm inclined not to do much, if anything, here. They all trace back to "malformed," as you note, which leads to GENERALPROTOCOLERROR. The instances in which we use GPE are: Malformed HTTP messages Push whose request headers change across multiple promises As a substitute for more specific codes I wouldn't be opposed to splitting the first two off into a new / two new codes, because that would be consistent with our principle of indicating the general area where the failure occurred. I would push back on having separate error codes for specific ways the message could be malformed, because that's pretty expansive rabbit hole.
OK, I'm satisfied with that response. I think that we'll just have to signal extra information in the text field. Happy to close this.
NAME do you think an error code for "malformed message" would be useful, if we don't go into the various types of malformed?
That might be useful, yes.
This is a design change, albeit a marginal one.
NAME let's merge the associated PR but keep this issue open and marked as "call-issued"
Keeping open, as requested.
Closing this now that the IESG review of draft 33 has concluded.
In fairness, I question whether the IESG review of the HTTP drafts has concluded. But as this is not an IESG comment, I'm content to close it. People have had time to object.
Yes I agree Mike. This was due to me being over eager with the close button. The issue may not have strictly been raised in the period that the IESG were directed to review the doc, and they have yet to ballot on draft 33. But either way there was no push back from the WG on this change since draft 33 was published.

the inclusion of uppercase field names, or  <ins> the inclusion of invalid characters in field names or values. </ins> A request or response that includes a payload body can include a Content-Length header field.  A request or response is also malformed


intermediary not acting as a tunnel) MUST NOT forward a malformed request or response.  Malformed requests or responses that are detected MUST be treated as a stream error (errors) of type <del> H3_GENERAL_PROTOCOL_ERROR. </del>  For malformed requests, a server MAY send an HTTP response indicating the error prior to closing or resetting the stream.  Clients MUST NOT

intermediary not acting as a tunnel) MUST NOT forward a malformed request or response.  Malformed requests or responses that are detected MUST be treated as a stream error (errors) of type  <ins> H3_MESSAGE_ERROR. </ins> For malformed requests, a server MAY send an HTTP response indicating the error prior to closing or resetting the stream.  Clients MUST NOT


The client's stream terminated without containing a fully-formed request.  The TCP connection established in response to a CONNECT request was reset or abnormally closed.

The client's stream terminated without containing a fully-formed request. <ins> An HTTP message was malformed and cannot be processed. </ins> The TCP connection established in response to a CONNECT request was reset or abnormally closed.


The payload of this packet contains CRYPTO frames and could contain PING, PADDING, or ACK frames.  Handshake packets MAY contain CONNECTION_CLOSE frames of type 0x1c.  Endpoints MUST treat receipt <del> of Handshake packets with other frames as a connection error. </del>  Like Initial packets (see discard-initial), data in CRYPTO frames for Handshake packets is discarded - and no longer retransmitted - when

Because it always is.
I'm checking "MUST treat" in the transport draft. Sec 17.2.4 says: This is only the place where the type of a connection error is NOT specified. This part should be modified as "a connection error of XXX".
This was deliberate, but you can now send CONNECTION_CLOSE in this case, so it makes sense to use a code here.

The payload of this packet contains CRYPTO frames and could contain PING, PADDING, or ACK frames.  Handshake packets MAY contain CONNECTION_CLOSE frames of type 0x1c.  Endpoints MUST treat receipt  <ins> of Handshake packets with other frames as a connection error of type PROTOCOL_VIOLATION. </ins> Like Initial packets (see discard-initial), data in CRYPTO frames for Handshake packets is discarded - and no longer retransmitted - when


control across the entire connection, QUIC has the capability to improve the performance of HTTP compared to a TCP mapping.  QUIC also incorporates TLS 1.3 (TLS13) at the transport layer, offering <del> comparable security to running TLS over TCP, with the improved connection setup latency of TCP Fast Open (TFO). </del>  This document defines a mapping of HTTP semantics over the QUIC transport protocol, drawing heavily on the design of HTTP/2.  While

Mostly because QUIC doesn't prevent all forms of request forgery. Thankfully, this is dealt with in detail in the transport draft.
NAME this looks good. Can you also change one sentence in Sec 1.2, from: to .
Hilarie Orman wrote: all this is assumed to be provided by QUIC. Section 10.2 says that all QUIC packets are encrypted; I'm not sure if that's true, or if QUIC has an option for "non-modifiable" without encryption.
Actually, we now know that this is not true, so this really needs to be fixed: -- from . The real solution here is to cite of the transport draft.
The version of QUIC required by this draft is always encrypted; that seems sufficient for the original issue. NAME issue is distinct, and worth fixing. I'll use this issue to track it.
... and we could add some text stating the integrity point in Section 1.2. NAME suggests: "comparable integrity and confidentiality to TLS over TCP"
Could we make some progress on this one?
Progress made; the PR now needs review.

control across the entire connection, QUIC has the capability to improve the performance of HTTP compared to a TCP mapping.  QUIC also incorporates TLS 1.3 (TLS13) at the transport layer, offering  <ins> comparable confidentiality and integrity to running TLS over TCP, with the improved connection setup latency of TCP Fast Open (TFO). </ins> This document defines a mapping of HTTP semantics over the QUIC transport protocol, drawing heavily on the design of HTTP/2.  While


The use of ALPN in the TLS and QUIC handshakes establishes the target application protocol before application-layer bytes are processed. <del> Because all QUIC packets are encrypted, it is difficult for an attacker to control the plaintext bytes of an HTTP/3 connection, which could be used in a cross-protocol attack on a plaintext protocol. </del>  10.3.

The use of ALPN in the TLS and QUIC handshakes establishes the target application protocol before application-layer bytes are processed.  <ins> This ensures that endpoints have strong assurances that peers are using the same protocol. This does not guarantee protection from all cross-protocol attacks. Section 21.5 of QUIC-TRANSPORT describes some ways in which the plaintext of QUIC packets can be used to perform request forgery against endpoints that don't use authenticated transports. </ins> 10.3.


A PATH_RESPONSE frame received on any network path validates the path on which the PATH_CHALLENGE was sent. <del> If the PATH_CHALLENGE frame that resulted in successful path validation was sent in a datagram that was not expanded to at least 1200 bytes, the endpoint can regard the address as valid.  The endpoint is then able to send more than three times the amount of </del>  data that has been received.  However, the endpoint MUST initiate another path validation with an expanded datagram to verify that the <del> path supports required MTU. </del>  Receipt of an acknowledgment for a packet containing a PATH_CHALLENGE frame is not adequate validation, since the acknowledgment can be

This was definitely odd. Let's take another tilt at making it comprehensible.
Erik Kline said:
Yep, when it's called out, it's distinctly odd. Hopefully it's an easy fix, but writing is hardd.

A PATH_RESPONSE frame received on any network path validates the path on which the PATH_CHALLENGE was sent.  <ins> If an endpoint sends a PATH_CHALLENGE frame in a datagram that is not expanded to at least 1200 bytes, and if the response to it validates the peer address, the path is validated but not the path MTU.  As a result, the endpoint can now send more than three times the amount of </ins> data that has been received.  However, the endpoint MUST initiate another path validation with an expanded datagram to verify that the  <ins> path supports the required MTU. </ins> Receipt of an acknowledgment for a packet containing a PATH_CHALLENGE frame is not adequate validation, since the acknowledgment can be


authenticated negotiation of an application protocol (TLS uses ALPN ALPN for this purpose) <del> Endpoints can use packets sent during the handshake to test for Explicit Congestion Notification (ECN) support; see ecn.  An endpoint verifies support for ECN by observing whether the ACK frames acknowledging the first packets it sends carry ECN counts, as described in ecn-validation. </del> The CRYPTO frame can be sent in different packet number spaces (packet-numbers).  The offsets used by CRYPTO frames to ensure ordered delivery of cryptographic handshake data start from zero in

This is my best stab at it.
Erik Kline said:
I thought that section reference was wrong, but Section 7 does indeed mention ECN twice. Once is almost too much for this section. I checked the history and the commits that affected this text likely are the result of a merge, and one that either git resolved incorrectly for us, or one that we messed up. Either way, this is worth fixing.
one nit

authenticated negotiation of an application protocol (TLS uses ALPN ALPN for this purpose)  The CRYPTO frame can be sent in different packet number spaces (packet-numbers).  The offsets used by CRYPTO frames to ensure ordered delivery of cryptographic handshake data start from zero in


shown with a '*'.  Once completed, endpoints are able to exchange application data. <del> An endpoint validates support for Explicit Congestion Notification (ECN) by observing whether the ACK frames acknowledging the first packets it sends carry ECN counts, as described in ecn-validation. </del>  Endpoints MUST explicitly negotiate an application protocol.  This avoids situations where there is a disagreement about the protocol

shown with a '*'.  Once completed, endpoints are able to exchange application data.  <ins> Endpoints can use packets sent during the handshake to test for Explicit Congestion Notification (ECN) support; see ecn.  An endpoint validates support for ECN by observing whether the ACK frames acknowledging the first packets it sends carry ECN counts, as described in ecn-validation. </ins> Endpoints MUST explicitly negotiate an application protocol.  This avoids situations where there is a disagreement about the protocol


A token allows a server to correlate activity between the connection where the token was issued and any connection where it is used. <del> Clients that want to break continuity of identity with a server MAY </del>  discard tokens provided using the NEW_TOKEN frame.  In comparison, a token obtained in a Retry packet MUST be used immediately during the connection attempt and cannot be used in subsequent connection

NAME said:
I think "can" works equally well, given the precondition. I'll make that change.

A token allows a server to correlate activity between the connection where the token was issued and any connection where it is used.  <ins> Clients that want to break continuity of identity with a server can </ins> discard tokens provided using the NEW_TOKEN frame.  In comparison, a token obtained in a Retry packet MUST be used immediately during the connection attempt and cannot be used in subsequent connection


The next bit (0x40) of byte 0 is set to 1.  Packets containing a zero value for this bit are not valid packets in this version and <del> MUST be discarded. </del>  The next two bits (those with a mask of 0x30) of byte 0 contain a packet type.  Packet types are listed in long-packet-types.

NAME said:
This particular choice has not a lot to do with QUIC and would therefore bring in a lot of non-sequitur references, but a single sentence won't hurt. It has to be repeated, which is gross, but I can live with that.

The next bit (0x40) of byte 0 is set to 1.  Packets containing a zero value for this bit are not valid packets in this version and  <ins> MUST be discarded.  A value of 1 for this bit allows QUIC to coexist with other protocols; see RFC7983. </ins> The next two bits (those with a mask of 0x30) of byte 0 contain a packet type.  Packet types are listed in long-packet-types.


The next bit (0x40) of byte 0 is set to 1.  Packets containing a zero value for this bit are not valid packets in this version and <del> MUST be discarded. </del>  The third most significant bit (0x20) of byte 0 is the latency spin bit, set as described in spin-bit.

The next bit (0x40) of byte 0 is set to 1.  Packets containing a zero value for this bit are not valid packets in this version and  <ins> MUST be discarded.  A value of 1 for this bit allows QUIC to coexist with other protocols; see RFC7983. </ins> The third most significant bit (0x20) of byte 0 is the latency spin bit, set as described in spin-bit.


newer encryption level are available. An endpoint cannot discard keys for a given encryption level unless <del> it has both received and acknowledged all CRYPTO frames for that encryption level and when all CRYPTO frames for that encryption level have been acknowledged by its peer.  However, this does not guarantee that no further packets will need to be received or sent at that </del>  encryption level because a peer might not have received all the <del> acknowledgments necessary to reach the same state. </del>  Though an endpoint might retain older keys, new data MUST be sent at the highest currently-available encryption level.  Only ACK frames

The three points are wordy enough it might be worth making this a bulleted list, however. Thoughts?
NAME said:
With NAME fixes, this is good.

newer encryption level are available. An endpoint cannot discard keys for a given encryption level unless  <ins> it has received all the cryptographic handshake messages from its peer at that encryption level and its peer has done the same. Different methods for determining this are provided for Initial keys (discard-initial) and Handshake keys (discard-handshake).  These methods do not prevent packets from being received or sent at that </ins> encryption level because a peer might not have received all the  <ins> acknowledgments necessary. </ins> Though an endpoint might retain older keys, new data MUST be sent at the highest currently-available encryption level.  Only ACK frames


21.13. Deployments should limit the ability of an attacker to target a new <del> connection to a particular server instance.  This means that client- controlled fields, such as the initial Destination Connection ID used on Initial and 0-RTT packets SHOULD NOT be used by themselves to make routing decisions.  Ideally, routing decisions are made independently of client-selected values; a Source Connection ID can be selected to route later packets to the same server. </del>  21.14.

This was just old and needed a little bit of a refresh. Removing the recommendation, which was counter to established views and unnecessary. I will let others determine whether this is editorial/design.
NAME said:
I think that the point of this section is to highlight the possibility that routing based on client-selected values exposes servers to load that is balanced under client - and therefore attacker - control. I don't think that it needs to include such a strong recommendation. If people deploying load balancers are not concerned about this, then that is good. That makes the recommendation less good. As this is very old text, it needs a bit of a cleanup anyway. I'm going to suggest something along the lines of my statement above in a pull request and we can polish the wording there. I don't think that we should remove the Retry SCID language. That remains an option for servers, even if they don't want to exercise the option (whether load balancers look at Retry tokens is very much down to how the various functions are distributed). What could happen is that the Retry SCID is chosen so that the next initial can be routed as though it were chosen by a client, but in such a way as it results in the connection being sent to a lightly-loaded server instance. That is, if the load balancer routes inchoate Initials based on connection ID, knowledge of that routing algorithm is used to direct traffic. That said, I understand that what is more likely here is that Initials with inauthentic Destination Connection ID fields will be routed using other information: round-robin, random, five-tuple, or whatever.
I think you're proposing that the text I quoted be deleted. That is satisfactory, and what I would recommend as well.
Returning to an open state as the chairs directed in their plan.
Closing this now that the IESG have approved the document(s).
To be safe, let's mark this design.

21.13. Deployments should limit the ability of an attacker to target a new  <ins> connection to a particular server instance.  Ideally, routing decisions are made independently of client-selected values, including addresses.  Once an instance is selected, a connection ID can be selected so that later packets are routed to the same instance. </ins> 21.14.


The endpoint uses RTT samples and peer-reported host delays (see Section 13.2 of QUIC-TRANSPORT) to generate a statistical description of the network path's RTT.  An endpoint computes the following three <del> values for each path: the minimum value observed over the lifetime of the path (min_rtt), an exponentially-weighted moving average (smoothed_rtt), and the mean deviation (referred to as "variation" in the rest of this document) in the observed RTT samples (rttvar). </del>  5.1.

This should be fixed. I've sent out .
The natural question that follows will be "which period of time", but I think that is already.Thanks, LG

The endpoint uses RTT samples and peer-reported host delays (see Section 13.2 of QUIC-TRANSPORT) to generate a statistical description of the network path's RTT.  An endpoint computes the following three  <ins> values for each path: the minimum value over a period of time (min_rtt), an exponentially-weighted moving average (smoothed_rtt), and the mean deviation (referred to as "variation" in the rest of this document) in the observed RTT samples (rttvar). </ins> 5.1.


5.2. min_rtt is the sender's estimate of the minimum RTT observed for a <del> given network path.  In this document, min_rtt is used by loss detection to reject implausibly small rtt samples. </del>  min_rtt MUST be set to the latest_rtt on the first RTT sample. min_rtt MUST be set to the lesser of min_rtt and latest_rtt (latest-

5.2. min_rtt is the sender's estimate of the minimum RTT observed for a  <ins> given network path over a period of time.  In this document, min_rtt is used by loss detection to reject implausibly small rtt samples. </ins> min_rtt MUST be set to the latest_rtt on the first RTT sample. min_rtt MUST be set to the lesser of min_rtt and latest_rtt (latest-


in compliance with RFC6437, unless the local API does not allow setting IPv6 flow labels. <del> The IPv6 flow label SHOULD be a pseudo-random function of the source and destination addresses, source and destination UDP ports, and the Destination Connection ID field.  The flow label generation MUST be designed to minimize the chances of linkability with a previously used flow label, as a stable flow label would enable correlating activity on multiple paths; see migration-linkability. A possible implementation is to compute the flow label as a cryptographic hash function of the source and destination addresses, source and destination UDP ports, Destination Connection ID field, and a local secret. </del>  10.

This was a little tricky as the current text already had what we wanted. But it wasn't quite clear on rationale, so I added some of that.
Éric Vyncke said:
I believe that the view was that a PRNG was inferior to a PRF because it required state, but yes, it should be fine. Should we have avoided repeating advice from 6437? (I forget who contributed this text, but I think that it was an RFC 6437 author.)
Text originates with Christian NAME in . A few people have touched it since for editorial purposes, but that doesn't change the point of what you're asking about.

in compliance with RFC6437, unless the local API does not allow setting IPv6 flow labels.  <ins> The flow label generation MUST be designed to minimize the chances of linkability with a previously used flow label, as a stable flow label would enable correlating activity on multiple paths; see migration- linkability. RFC6437 suggests deriving values using a pseudorandom function to generate flow labels.  Including the Destination Connection ID field in addition to source and destination addresses when generating flow labels ensures that changes are synchronized with changes in other observable identifiers.  A cryptographic hash function that combines these inputs with a local secret is one way this might be implemented. </ins> 10.


QUIC begins every connection in slow start with the congestion window set to an initial value.  Endpoints SHOULD use an initial congestion window of 10 times the maximum datagram size (max_datagram_size), <del> limited to the larger of 14720 bytes or twice the maximum datagram size.  This follows the analysis and recommendations in RFC6928, increasing the byte limit to account for the smaller 8-byte overhead of UDP compared to the 20-byte overhead for TCP. </del>  If the maximum datagram size changes during the connection, the initial congestion window SHOULD be recalculated with the new size.

Éric Vyncke said:
I think the ambiguity is whether the "limited to" is saying: the maximum datagram size is no more than twice the maximum datagram size (which is nonsensical) the initial congestion window is min(10maxdatagramsize, max(14720 bytes, 2maxdatagramsize)) Given that one of the possible interpretations is logically inconsistent, the other one must be correct. I'm not sure how to make this sentence clearer except through pseudo-code. Looking at the pseudo-code, there isn't any -- kInitialWindow is declared to be a constant, value defined by this text, but the definition of this constant is given in terms of a variable (maxdatagramsize). Maybe kInitialWindow should become a variable itself, and then have pseudo-code with the max/min relationship added to B.3?
This is clearer; thanks.

QUIC begins every connection in slow start with the congestion window set to an initial value.  Endpoints SHOULD use an initial congestion window of 10 times the maximum datagram size (max_datagram_size),  <ins> while limiting the window to the larger of 14720 bytes or twice the maximum datagram size.  This follows the analysis and recommendations in RFC6928, increasing the byte limit to account for the smaller 8-byte overhead of UDP compared to the 20-byte overhead for TCP. </ins> If the maximum datagram size changes during the connection, the initial congestion window SHOULD be recalculated with the new size.


If the recipient permits the migration, it MUST send subsequent packets to the new peer address and MUST initiate path validation (migrate-validate) to verify the peer's ownership of the address if <del> validation is not already underway. </del>  An endpoint only changes the address to which it sends packets in response to the highest-numbered non-probing packet.  This ensures

Section 9.3 of Transport(URL) says: "If the recipient permits the migration, it MUST send subsequent packets to the new peer address and MUST initiate path validation (Section 8.2) to verify the peer's ownership of the address if validation is not already underway." In section 9.5(URL) "Similarly, an endpoint MUST NOT reuse a connection ID when sending to more than one destination address. Due to network changes outside the control of its peer, an endpoint might receive packets from a new source address with the same destination connection ID, in which case it MAY continue to use the current connection ID with the new remote address while still sending from the same local address." So as long as it's an unintentional change, everything is clear. But if the destination address changes and the incoming CID changes, but the sender(ie: server) doesn't have any more CIDs, it's not clear what should be done, as the two MUSTs seem to contradict one another. Or maybe they imply the server can't send anything?
Later in 9.5, there's also this text that is relevant, but I don't think it clarifies how to resolve the MUSTs. " An endpoint that exhausts available connection IDs cannot probe new paths or initiate migration, nor can it respond to probes or attempts by its peer to migrate. To ensure that migration is possible and packets sent on different paths cannot be correlated, endpoints SHOULD provide new connection IDs before peers migrate; see Section 5.1.1. If a peer might have exhausted available connection IDs, a migrating endpoint could include a NEWCONNECTIONID frame in all packets sent on a new network path."
So the second quotation has that clarification (with emphasis): Isn't this all coherent?
Yes, that clarifies the issue when the CID does not change. But that does not clarify the case when the CID does change and the responder has no more CIDs.
Isn't that addressed by this: ?
So the answer is: 1) It can't send anything 2) It can send on the old path, but not the new one
It can probe the old path - but that is all it can do.
Why would it probe the old path that it's already validated?
I didn't say that it was useful, just possible :)
I don't see a pressing reason to do anything about this. That said, it's an unfortunate edge case, perhaps we could call it out explicitly, mentioning that this shouldn't arise if the other parts of the migration machinery are followed?
To be clear, I'm not looking for a fix as much as clarity on what is supposed to occur. I'll write a PR that I think will clarify it some and call out the edge case.
I'd argue this is really a MUST unless case, but people tend not to like those, so I tried to stick to the facts in my PR.
WFM

If the recipient permits the migration, it MUST send subsequent packets to the new peer address and MUST initiate path validation (migrate-validate) to verify the peer's ownership of the address if  <ins> validation is not already underway.  If the recipient has no unused connection IDs from the peer, it will not be able to send anything on the new path until the peer provides one; see migration-linkability. </ins> An endpoint only changes the address to which it sends packets in response to the highest-numbered non-probing packet.  This ensures


SHOULD begin processing partial HTTP messages once enough of the message has been received to make progress.  If a client-initiated stream terminates without enough of the HTTP message to provide a <del> complete response, the server SHOULD abort its response with the error code H3_REQUEST_INCOMPLETE; see errors. </del>  A server can send a complete response prior to the client sending an entire request if the response does not depend on any portion of the

to the extent I'm willing to do so.
Sec 4.1 and 4.1.2 do not explicitly define , , as stream errors. A.4.1 says that is a stream error. It would be nice if they are explicitly defined as stream errors in Sec 4.1 and 4.1.2. Also, it would be nice if each error code is categorized to either a connection error or a stream error in Table 4.
Commenting as an individual. The error code space is shared between connection and streams. The action associated with a stream error or connection error cause QUIC transport frames to be emitted, which can use a code. H3 inherits H2's design philosophy that endpoints can generate a connection error at will. So while there are specific cases that describe "treat X as stream error foo", endpoints are also allowed to "treat X as connection error foo". Constraining the error codes to different uses has a certain appeal. But then what do we say the the receiver of an error code of the wrong type should do? Generate its own error? I think this has come up a couple of times during H3 drafts but I'm satisfied that the flexibility we have today is about the best we can do.
I also think "stream error" and "abort a stream" are unique and consistent terms used through the document. But I'll let Mike spec to that point with his editor hat.
Even though categorization is not reasonable, Sec 4.1, for instance, should say like "the server SHOULD abort its response and treat as a stream error of type H3REQUESTINCOMPLETE".
"Abort" is a defined term in section 2.2. I personally don't see much clarity in the proposal, it threatens to add inconsistency to other places where streams are aborted due to application decisions rather than a protocol error.
My example proposal is to replace "the server SHOULD abort its response with the error code H3REQUESTINCOMPLETE" with "the server SHOULD abort its response and treat as a stream error of type H3REQUESTINCOMPLETE" in Sec 4.1. I don't understand why this would introduce inconsistency.
NAME For that particular instance, I think it is not unreasonable to change the text from "SHOULD abort its response with the error code ..." to "SHOULD abort its response stream with the error code ...", as the latter is the pattern that we use. Though I am not sure if such change is necessary; I tend to agree with NAME that the sentence is already clear; "abort" is a defined word and use of "response" implies a stream.
WRT inconsistency, the editor would need to sweep for all instances of abort and reason about whether they need additional text or not. And there's a risk that someone later on picks up on an inconsistency of usage because they didn't appreciate the nuance. Since adding more detail after an instance of seems duplicative, I would favour not adding any more.
I'm okay with NAME addition of "stream" since abort is defined as a stream operation. I don't think we need to separate out "abort" and "stream error" as separate statements, because abort already describes what needs to be done.
If I was worried too much, no change is necessary. One alternative approach is to add a sentence like "errors in this section are stream errors" in the beginning of Sec 4.

SHOULD begin processing partial HTTP messages once enough of the message has been received to make progress.  If a client-initiated stream terminates without enough of the HTTP message to provide a  <ins> complete response, the server SHOULD abort its response stream with the error code H3_REQUEST_INCOMPLETE; see errors. </ins> A server can send a complete response prior to the client sending an entire request if the response does not depend on any portion of the


data received, as specified in Section 8.1 of QUIC-TRANSPORT.  If no additional data can be sent, the server's PTO timer MUST NOT be armed until datagrams have been received from the client, because packets <del> sent on PTO count against the anti-amplification limit.  Note that the server could fail to validate the client's address even if 0-RTT is accepted. </del>  Since the server could be blocked until more datagrams are received from the client, it is the client's responsibility to send packets to

Text and pseudocode have been updated.
I just updated the pseudocode as well, since it's quite straightforward.
When the PTO is not armed due to the amplification limit and then a packet is received: URL, it's important to send data for the PN spaces the PTO is armed for(Initial or Handshake) prior to new application data. Typically PTO suggests writing new data instead of retransmitting data which may or may not be lost, but that's not true during the handshake. This is only an issue for the server, since it's caused by enforcing the amplification limits prior to address confirmation. This is most evident when 0-RTT is accepted, but address validation fails, since otherwise a server would not usually have enough data to write to create a problem.
I went and double checked the msquic code , and we always re-enable the loss detection timer when we become "unblocked" by amplification protection logic. I thought this logic was already driven by some statement in the spec. I just went back and found this: Do we need any more than this?
The potential issue is that if the PTO is armed, but should have already expired, it's important to execute it prior to sending any pending data. I'm working on a PR to make this clearer, and we can whether the extra clarification is necessary?
I wonder whether there is something else going on. Amplification or not, 0-RTT packets can only be acknowledged by ACK frames in 1-RTT packets. Those can only be received after the client gets the 1-rtt keys. So implementation should just start a short timer after the handshake completes.
This seems like an editorial change, please confirm. Either way, lets ensure NAME has an opportunity to comment before landing any changes.
ngtcp2 has dedicated code for this situation: URL I feel this is a kind of optimization or implementation techniques.
In response to NAME If the WG establish a consensus on the need for a change a particular fix then this PR can be applied in the AUTH48 with AD approval. I think we need to figure out if not merging the PR until AUTH48 is the best? It makes it simple to provide the changes to the RFC-editor, but maybe makes it harder for the rest of the community to keep track of the changes if there are no editors copy that contain all agreed things. However, considering the hopefully limited time that may make sense.
We can tag the versions that entered the RFC Editor queue, and then generate a diff against those at AUTH48.
That tag already exists, so we are good.
At the moment, states, quote: "Clients MUST ensure that UDP datagrams containing only Initial packets are sized to at least 1200 bytes, adding padding to packets in the datagram as necessary." I think this is incorrect and that "only" should be dropped, as it excludes a UDP datagram that contains an Initial and a 0-RTT packet. Pointed out by NAME in .
Technically a design change. I think that it should be any packets that contain Initial and don't contain Handshake or 1-RTT packets. At least, that's what I implemented.
I'll note that I think there are other requirements formulated in other sections. Perhaps define a term such a minimal initial datagram size and have the requirement in one place rather than sprinkling 1200 bytes in multiple places where it can be difficult to get the finer points (such as UDP vs QUIC packets and with or without header size). For example section 14 in transport:
NAME What you implemented should be fine. However, Initial + 0-RTT coalesced in a datagram should be padded I believe and I don't think we're clear on that today.
It might be simpler to require every UDP packet that contains an Initial be padded to at least 1200? I'm worried that only requiring that of Initial if there is no Handshake/1-RTT present might be tricky on the receiver: what do I do if I receive a non-padded Initial with Handshake but I can't decrypt the Handshake data?
NAME What we are talking here is a requirement specific to clients, and I am not sure if a client has a chance of sending Initial and Handshake packets at the same time. Quoting of the TLS draft, "a client MUST discard Initial keys when it first sends a Handshake packet." And even if there is a possibility of a client sending Initial and Handshake at the same moment, I do not think requiring the client to pad a packet that contains only an Initial is correct, as coalescing is an optional behavior to the send side. It would mean that clients coalescing the QUIC packets would send a non-padded datagram, while clients not coalescing would send a padded datagram. That seems like an odd behavior.
And yet another issue gets sucked into the wormhole that is the key discard mess. I guess that we will have to make a final determination based on the outcome of that stuff.
On consideration, I think that the requirement is simple and we don't have to stress about interactions with discarding keys. If the packet contains an Initial, it's possible that the Initial packet is the only packet that can be used by a server. Therefore, the datagram should be padded to 1200, regardless of whatever else is included. So we strike the "only" and we're good. See 6cfcbe26385f17072ccd330aea619f65bf3bdcb4.
I wonder - if 0-RTT does not have huge certificates, would it not make sense to permit small packets in this case, provided the auth token validates. But in other cases 1200 bytes must be provided. But since 0-RTT might fail, this could then require a retransmission. Resource constrained devices might be prefer the latter.
NAME Regardless of 0-RTT, for bandwidth constrained deployments, it makes sense for a client to always send a small packet and let the server validate the path. That said, the chartered goal of V1 is to reduce the connection establishment latency, and we have explicitly decided to require clients to send full-sized packets until the path is validated. I do not think we should revisit that design. Maybe we can in v2.
I do not believe that this is necessarily correct. The reason is that we have not yet nailed down Initial key discard and in at least one version, an Initial ACK would appear in the client's second flight, but that need not be padded.
I think the specification should mandate padding of server initial packets as well. When I was traveling a couple weeks ago, I was on a network where, when using IPv6, it allowed 1200-byte UDP packets through from client to server but blackholed them from server to client. Since our implementation pads initials in both directions, we were able to detect this failure during the handshake and fall back to TCP/TLS. If the server didn't pad its initials, we would have succeeded at the handshake but never gotten an HTTP response.
This definitely seems like a design issue. The purpose of the padding rule is solely to limit amplification, not to establish a minimum MTU. If you want some sort of MTU rule, that should be discussed separately.
This issue is marked as design. Are you suggesting I should open a separate one?
NAME I believe it is dual purpose: From the current transport draft: >The payload of a UDP datagram carrying the first Initial packet MUST be expanded to at least 1200 bytes, by adding PADDING frames to the Initial packet and/or by coalescing the Initial packet (see Section 12.2). Sending a UDP datagram of this size ensures that the network path supports a reasonable Maximum Transmission Unit (MTU), and helps reduce the amplitude of amplification attacks caused by server responses toward an unverified client address; see Section 8.
Yeah, that's dicta as far as I am concerned. I don't think we ever had consensus that we were going to enforce MTU here.
The insight I had here was this: If you are sending Initial, it is possible that this is the only packet in the datagram that can be processed by your peer. If that is the case, then a client needs to ensure that it pads the datagram as though no other packets were present. You can infer from the fact that you have Handshake keys that the server is able to process Handshake packets, and then extend that to say that if you include Handshake packets then the server won't need padding. But then you can extend that inference to saying that there is no need to send any Initial packets (as the current draft does; currently, you are not required to keep Initial keys once you are sending with Handshake keys). Either way, I figure that it is better to keep things simple and say "if Initial, pad". In those cases where padding ends up being excessive, it's only excessive for a short while.
I don't know where you get this from. It's total datagram size that matters, not the contents of the rest of the datagram (which is why the neqo padding strategy works). Anyway, the algorithm you propose seems fine, but it's not necessary, and therefore there's no need to specify it in the spec.
This was my thought too.
I'm not seeing a conflict between these statements. If the packet contains an Initial, the total datagram size must be at least 1200 bytes. You can achieve this by padding any packet in the payload; I don't think anyone is advocating for requiring the padding be in a particular spot.
I don't understand what "pads the datagram as though no other packets were present" is supposed to mean, then. The way neqo does this is that it puts the packets in the datagram and then pads the rest, without any regard to what keys the server might have.
Imprecise wording on my part. "pads the datagram as though no other packets were present" might be better as "as though no other packets can be processed by the server". Let's keep in mind that the proposed changes is just striking "only" in "Clients MUST ensure that UDP datagrams containing Initial packets have UDP payloads of at least 1200 bytes, [...]". I agree that this will result in larger packets than are ideal in a couple of cases. But the ACK-only Initial packets a client sent are most likely coalesced with other packets outside of cases where the padding is genuinely required.
I'm sorry, but I still don't see what benefit this change provides. Perhaps this would be easier next week.
The change makes it clear that if you send Initial+0-RTT then you should still pad to 1200. That's all. Previously, you would not have been required to pad, which would have been bad. Most of the debate and discussion is about the knock-on consequences of applying the broader rule, which I don't think are that important. And yes, the whole "when do you discard Initial keys" thing does confound things a little.
Discussed in Cupertino. The word "only" is to be removed from the respective sentence. Moving to Editorial.
Thanks Ian.

data received, as specified in Section 8.1 of QUIC-TRANSPORT.  If no additional data can be sent, the server's PTO timer MUST NOT be armed until datagrams have been received from the client, because packets  <ins> sent on PTO count against the anti-amplification limit. When the server receives a datagram from the client, the amplification limit is increased and the server resets the PTO timer. If the PTO timer is then set to a time in the past, it is executed immediately.  Doing so avoids sending new 1-RTT packets prior to packets critical to the completion of the handshake.  In particular, this can happen when 0-RTT is accepted but the server fails to validate the client's address. </ins> Since the server could be blocked until more datagrams are received from the client, it is the client's responsibility to send packets to


An endpoint MUST include the value from the Source Connection ID field of the packet it receives in the Destination Connection ID <del> field.  The value for Source Connection ID MUST be copied from the Destination Connection ID of the received packet, which is initially randomly selected by a client.  Echoing both connection IDs gives clients some assurance that the server received the packet and that the Version Negotiation packet was not generated by an attacker that is unable to observe packets. </del>  An endpoint that receives a Version Negotiation packet might change the version that it decides to use for subsequent packets.  The

The names are capitalized, but we don't say "the ... field." We probably should.

An endpoint MUST include the value from the Source Connection ID field of the packet it receives in the Destination Connection ID  <ins> field.  The value for the Source Connection ID field MUST be copied from the Destination Connection ID field of the received packet, which is initially randomly selected by a client.  Echoing both connection IDs gives clients some assurance that the server received the packet and that the Version Negotiation packet was not generated by an attacker that is unable to observe packets. </ins> An endpoint that receives a Version Negotiation packet might change the version that it decides to use for subsequent packets.  The


The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP <del> 14 BCP14 when, and only when, they appear in all capitals, as shown here. </del>  This document uses the variable-length integer encoding from QUIC- TRANSPORT.

I've had to make some changes in the template to deal with some odd regressions in CircleCI (see URL for details). This is the updated configuration.
Yeah, given how this breaks in Circle; that's probably wise.
NAME NAME do you think that you could stop following this project in CircleCI? Then we can merge this one.
Is there a reason not to simply move this repo over to GitHub Actions as well?

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP  <ins> 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </ins> This document uses the variable-length integer encoding from QUIC- TRANSPORT.


The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP <del> 14 BCP14 when, and only when, they appear in all capitals, as shown here. </del>  Definitions of terms that are used in this document:

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP  <ins> 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </ins> Definitions of terms that are used in this document:


The entries in iana-setting-table are registered by this document. <del> For fomatting reasons, setting names can be abbreviated by removing the 'SETTING_' prefix. </del>  Each code of the format "0x1f * N + 0x21" for non-negative integer values of "N" (that is, 0x21, 0x40, ..., through 0x3ffffffffffffffe)

which also occurs in H3 but apparently wasn't caught.
Throughout, the document uses "SETTINGS" as the first part of thte HTTP/3 setting names. We have updated this sentence for consistency. Please let us know if any corrections are needed. Original: For fomatting reasons, the setting names here are abbreviated by removing the 'SETTING' prefix. Current: For formatting reasons, the setting names here are abbreviated by removing the 'SETTINGS_' prefix.
Fixed in .

The entries in iana-setting-table are registered by this document.  <ins> For formatting reasons, setting names can be abbreviated by removing the 'SETTINGS_' prefix. </ins> Each code of the format "0x1f * N + 0x21" for non-negative integer values of "N" (that is, 0x21, 0x40, ..., through 0x3ffffffffffffffe)


bytes.  An endpoint that includes this parameter supports the DATAGRAM frame types and is willing to receive such frames on this connection.  Endpoints MUST NOT send DATAGRAM frames until they have <del> sent and received the max_datagram_frame_size transport parameter. Endpoints MUST NOT send DATAGRAM frames of size strictly larger than the value of max_datagram_frame_size the endpoint has received from its peer.  An endpoint that receives a DATAGRAM frame when it has not sent the max_datagram_frame_size transport parameter MUST terminate the connection with error PROTOCOL_VIOLATION.  An endpoint that receives a DATAGRAM frame that is strictly larger than the value it sent in its max_datagram_frame_size transport parameter MUST terminate the connection with error PROTOCOL_VIOLATION.  Endpoints that wish to use DATAGRAM frames need to ensure they send a max_datagram_frame_size value sufficient to allow their peer to use them.  It is RECOMMENDED to send the value 65536 in the max_datagram_frame_size transport parameter as that indicates to the peer that this endpoint will accept any DATAGRAM frame that fits inside a QUIC packet. </del>  When clients use 0-RTT, they MAY store the value of the server's max_datagram_frame_size transport parameter.  Doing so allows the

Defines the transport parameter as a unidirectional configuration.
The spec clearly states the following: But it's not completely clear what happens if both sides send different values. Is the value purely a unidirectional configuration? For instance, if the server advertises a value of 500, and the client advertises a value of 100, can the client still send 500 byte datagrams? Or does this essentially negotiate the max value either side can use to 100? If this is a unidirectional configuration, why require the peer to send the TP at all, if all they want to do is send datagrams, and not receive them? I'm loosely basing my thoughts on what the design could be on how we negotiate the number of streams an endpoint is willing to accept. Following that model, I'd recommend a design where, if an endpoint is willing to receive datagrams, it advertises a it's willing to accept. The TP has absolutely no meaning for the send direction. The protocol on top of QUIC decides how to interpret only a single direction allowing datagrams to be sent.
I agree with NAME principly due to this clause in the present draft: My read of the current text is that it is unidirectional. An endpoint tells it's peer that it is willing to receive a DATAGRAM up to size N by using . Having asymmetric values is fine because the paths can be asymmetric and other TPs also behave asymmetrically. The draft also says: For an application protocol like siduck, both ends need to support reception of DATAGRAM or else the application will fail. For something like an IoT sensor feed, it might be fine to support a send-only/receive-only model. The current text basically requires the application protocol to mandate that is 0 on the side that is send-only AND to describe what happens if the TP is missing - that seems like it will cause a duplication of effort.
I agree that we should make this purely unidirectional. I would resolve this by replacing with

bytes.  An endpoint that includes this parameter supports the DATAGRAM frame types and is willing to receive such frames on this connection.  Endpoints MUST NOT send DATAGRAM frames until they have  <ins> received the max_datagram_frame_size transport parameter.  Endpoints MUST NOT send DATAGRAM frames of size strictly larger than the value of max_datagram_frame_size the endpoint has received from its peer. An endpoint that receives a DATAGRAM frame when it has not sent the max_datagram_frame_size transport parameter MUST terminate the connection with error PROTOCOL_VIOLATION.  An endpoint that receives a DATAGRAM frame that is strictly larger than the value it sent in its max_datagram_frame_size transport parameter MUST terminate the connection with error PROTOCOL_VIOLATION.  Endpoints that wish to use DATAGRAM frames need to ensure they send a max_datagram_frame_size value sufficient to allow their peer to use them.  It is RECOMMENDED to send the value 65536 in the max_datagram_frame_size transport parameter as that indicates to the peer that this endpoint will accept any DATAGRAM frame that fits inside a QUIC packet. The max_datagram_frame_size transport parameter is a unidirectional limit and indication of support of DATAGRAM frames.  Application protocols that use DATAGRAM frames MAY choose to only negotiate and use them in a single direction. </ins> When clients use 0-RTT, they MAY store the value of the server's max_datagram_frame_size transport parameter.  Doing so allows the


to receiving packets that only contain DATAGRAM frames, since the timing of these acknowledgements is not used for loss recovery.  If a sender detects that a packet containing a specific DATAGRAM frame might have been lost, the implementation MAY notify the application that it believes the datagram was lost.

The draft has some good text in the "Acknowledgement Handling" and "Congestion Control" sections that essentially is stating that DATAGRAM is just like any other ACK-eliciting packet, but is not automatically retransmitted by the transport. That's all reasonable, but I think there needs to be more text on how the (suspected) loss of a packet with a DATAGRAM frame or a PTO with only an outstanding DATAGRAM packet should be handled. I can see two possible models: It's just like any other packet. The goal is to elicit some ACK from the peer to get accurate loss information about the outstanding packet as soon as possible. If there is nothing outstanding we could use to send in a new packet, just send a PING frame. It's special. Because we don't necessarily intend to retransmit the data in the packet if it is actually lost, we don't actually care about immediate loss information/feedback. Don't force anything to be sent immediately to elicit the ACK. So far as I have it coded up in MsQuic, I've assumed (1). This essentially results in an immediate PING frame/packet being sent out if I have nothing else to retransmit to try to elicit an ACK for the DATAGRAM frame/packet. This could result in a slightly noisier connection if the app doesn't care about all loss information about their datagrams, but, IMO makes for a cleaner design. I don't know what the general consequences to congestion control might be if we don't do this. Assuming folks are in agreement, we should have some text on this topic in the draft.
NAME NAME as authors of the recovery draft do you have an opinion here?
I support NAME choice of 1 and it aligns with the recovery draft. It also matches our implementation. Adding clarifying text around this SG and I'd be happy to review it.
I agree -- choice (1) is cleanest and I would argue that choice(2) is really not principled.
Late to the issue, but I think (1) is the right choice here. It's not simply that datagrams aren't retransmitted, but that they might be retransmitted by the application if they're declared lost. If you don't have prompt feedback, that scenario suffers.
Seems like we have good agreement on this, just need to write the text
NAME -- To NAME 's comment at the mic, you should cite .
This text sounds good, though I'd love a little bit more text mentioning the benefit of this probeThis text is fine with me. I am wondering if we should say something additional, like that packets with datagram frames shouldn't be treated special, with respect to loss recovery.

to receiving packets that only contain DATAGRAM frames, since the timing of these acknowledgements is not used for loss recovery. <ins> As with any ack-eliciting frame, when a sender suspects that a packet containing only DATAGRAM frames has been lost, it MAY send probe packets to elicit a faster acknowledgement as described in Section 6.2.4 of RFC9002. </ins> If a sender detects that a packet containing a specific DATAGRAM frame might have been lost, the implementation MAY notify the application that it believes the datagram was lost.


2.1. <del> A quota policy is described in terms of service-limit and a time- window.  It is an Item whose bare item is a service-limit, along with associated Parameters. </del>  <del> The following parameters are defined in this specification: </del>  <del> The REQUIRED "w" parameter value conveys a time window value as defined in time-window. Other parameters are allowed and can be regarded as comments.  They ought to be registered within the "Hypertext Transfer Protocol (HTTP) RateLimit Parameters Registry", as described in iana-ratelimit- </del>  parameters. <del> For example, a quota policy of 100 quota units per minute: The definition of a quota policy does not imply any specific distribution of quota units within the time window.  If applicable, these details can be conveyed as extension parameters. </del>  <del> For example, two quota policies containing further details via extension parameters: </del>  <del> To avoid clashes, implementers SHOULD prefix unregistered parameters with a vendor identifier, e.g. "acme-policy", "acme-burst".  While it is useful to define a clear syntax and semantics even for custom parameters, it is important to note that user agents are not required to process quota policy information. </del>  <del> 2.2. </del>  <del> Rate limit policies limit the number of acceptable requests within a given time interval, known as a time window. </del>  <del> The time window is a non-negative Integer value expressing that interval in seconds, similar to the "delay-seconds" rule defined in Section 10.2.3 of HTTP.  Subsecond precision is not supported. </del>  <del> 2.3. </del>  <del> The service limit is associated with the maximum number of requests that the server is willing to accept from one or more clients on a given basis (originating IP, authenticated user, geographical, ..) during a time-window. </del>  <del> The service limit is a non-negative Integer expressed in quota units. </del>  <del> The service limit SHOULD match the maximum number of acceptable requests.  However, the service limit MAY differ from the total number of acceptable requests when weight mechanisms, bursts, or other server policies are implemented. </del>  <del> If the service limit does not match the maximum number of acceptable requests the relation with that SHOULD be communicated out-of-band. </del>  <del> Example: A server could </del>  <del> count once requests like "/books/{id}" </del>  <del> count twice search requests like "/books?author=WuMing" </del>  <del> so that we have the following counters </del>  3.

Section 2.2: Section 2.3: This appears to be a circular definition -- what's actually being defined here?
(noting that 2.2 doesn't actually define quota-units)
Quota unit is now defined as the measurement unit for service limits.
PTAL - I tried to rearrange to address this a bit more holistically.
Looks good!LGTM

2.1.  <ins> A quota policy is maintained by a server to limit the activity (counted in quota units) of a given client over a period of time (known as the time-window) to a specified amount (known as the service-limit). </ins>  <ins> Quota policies can be advertised by servers (see ratelimit-policy- field), but they are not required to be, and more than one quota policy can affect a given request from a client to a server. </ins>  <ins> A quota policy is expressed in Structured Fields STRUCTURED-FIELDS as an Integer that indicates the service limit with associated </ins> parameters.  <ins> The following Parameters are defined in this specification: </ins>  <ins> The REQUIRED "w" parameter value conveys a time window (time- window). </ins>  <ins> For example, a quota policy of 100 quota units per minute is expressed as: </ins>  <ins> Other parameters are allowed and can be regarded as comments. Parameters for use by more than one implementation or service ought to be registered within the "Hypertext Transfer Protocol (HTTP) RateLimit Parameters Registry", as described in iana-ratelimit- parameters. </ins>  <ins> Implementation- or service-specific parameters SHOULD be prefixed parameters with a vendor identifier, e.g. "acme-policy", "acme- burst". </ins>  <ins> 2.2. </ins>  <ins> The service limit is a non-negative Integer indicating the maximum amount of activity that the server is willing to accept from what it identifies as the client (e.g., based upon originating IP or user authentication) during a time-window. </ins>  <ins> The activity being limited is usually the HTTP requests made by the client; for example "you can make 100 requests per minute".  However, a server might only rate limit some requests (based upon URI, method, user identity, etc.), and it might weigh requests differently. Therefore, quota policies are defined in terms of "quota units". Servers SHOULD document how they count quota units. </ins>  <ins> For example, a server could count requests like "/books/{id}" once, but count search requests like "/books?author=WuMing" twice.  This might result in the following counters: </ins>  <ins> Often, the service limit advertised will match the server's actual limit.  However, it MAY differ when weight mechanisms, bursts, or other server policies are implemented.  In that case the difference SHOULD be communicated using an extension or documented separately. </ins>  <ins> 2.3. </ins>  <ins> Quota policies limit the number of acceptable requests within a given time interval, known as a time window. </ins>  <ins> The time window is a non-negative Integer value expressing that interval in seconds, similar to the "delay-seconds" rule defined in Section 10.2.3 of HTTP.  Subsecond precision is not supported. </ins>  <ins> By default, a quota policy does not constrain the distribution of quota units within the time window.  If necessary, these details can be conveyed as extension parameters. </ins>  <ins> For example, two quota policies containing further details via extension parameters: </ins> 3.


header field names proliferates. <del> Client applications interfacing with different servers may thus need to process different headers, or the very same application interface </del>  that sits behind different reverse proxies may reply with different throttling headers.

Improves terminology
In other parts of the document we still use client as we are not sure whether to refer explicitly to a User Agent or not. Ideas welcome...
See RFC 7230 terminology definitions (, not changing in the new specs, FWIW).

header field names proliferates.  <ins> User Agents interfacing with different servers may thus need to process different headers, or the very same application interface </ins> that sits behind different reverse proxies may reply with different throttling headers.


"RateLimit-Reset": containing the time remaining in the current window, specified in seconds. <del> The behavior of "RateLimit-Reset" is compatible with the "delta- </del>  seconds" notation of "Retry-After". The fields definition allows to describe complex policies, including

uses http-core semantics fixes Sections refs cc: NAME
I'll wait for the new i-d-template image, but will do.
Please use either [RFCxxxx], Section yyy or Section yyy of [RFCxxxx]
Addressed by now.
If you start using the new kramdown-rcf2629 section ref syntax, you may want to do that consistently...

"RateLimit-Reset": containing the time remaining in the current window, specified in seconds.  <ins> The behavior of "RateLimit-Reset" is compatible with the "delay- </ins> seconds" notation of "Retry-After". The fields definition allows to describe complex policies, including


This specification does not cover the throttling scope, that may be the given resource-target, its parent path or the whole Origin <del> RFC6454 section 7. </del>  The rate-limit headers may be returned in both Successful and non Successful responses.  This specification does not cover whether

This specification does not cover the throttling scope, that may be the given resource-target, its parent path or the whole Origin  <ins> (see Section 7 of RFC6454). </ins> The rate-limit headers may be returned in both Successful and non Successful responses.  This specification does not cover whether


capitals, as shown here. This document uses the Augmented BNF defined in RFC5234 and updated <del> by RFC7405 along with the "#rule" extension defined in Section 7 of MESSAGING. </del>  <del> The term Origin is to be interpreted as described in RFC6454 section 7. </del>  <del> The "delta-seconds" rule is defined in CACHING section 1.2.1. </del>  2.

capitals, as shown here. This document uses the Augmented BNF defined in RFC5234 and updated  <ins> by RFC7405 along with the "#rule" extension defined in Section 5.6.1 of SEMANTICS. </ins>  <ins> The term Origin is to be interpreted as described in Section 7 of RFC6454. </ins>  <ins> The "delay-seconds" rule is defined in Section 10.2.4 of SEMANTICS. </ins> 2.


The header value is <del> The delta-seconds format is used because: </del>  it does not rely on clock synchronization and is resilient to clock adjustment and clock skew between client and server (see <del> SEMANTICS Section 4.1.1.1); </del>  it mitigates the risk related to thundering herd when too many clients are serviced with the same timestamp.

The header value is  <ins> The delay-seconds format is used because: </ins> it does not rely on clock synchronization and is resilient to clock adjustment and clock skew between client and server (see  <ins> Section 5.6.7 of SEMANTICS); </ins> it mitigates the risk related to thundering herd when too many clients are serviced with the same timestamp.


5. <del> This section documents the considerations advised in Section 15.3.3 </del>  of SEMANTICS. An intermediary that is not part of the originating service

5.  <ins> This section documents the considerations advised in Section 16.3.3 </ins> of SEMANTICS. An intermediary that is not part of the originating service


8.3.1. <del> The server does not expose "RateLimit-Remaining" values, but resets the limit counter every second. </del>  It communicates to the client the limit of 10 quota-units per second always returning the couple "RateLimit-Limit" and "RateLimit-Reset".

Improves example description
https://ietf-wg-URL The example with just RateLimit-Limit and RateLimit-Reset In it seems this is a case where the RateLimit-Reset value is not able to be used to determine how long one should wait, but is rather just a Limit definition ? Why not then just use RateLimit-Limit: 10;w=1 and omit the other two headers ? Is this to cater for the inevitable 429 to provide a RateLimit-Reset value at that point ? If that is the case I question the value of using the two headers in “successful” responses.
This example is related to an implementation that uses the "old" ratelimit field set, that do not support . We should improve the description.
:+1:

8.3.1.  <ins> The server does not expose "RateLimit-Remaining" values (for example, because the underlying counters are not available).  Instead, it resets the limit counter every second. </ins> It communicates to the client the limit of 10 quota-units per second always returning the couple "RateLimit-Limit" and "RateLimit-Reset".