The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and <del> "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  This document defines requirements on future QUIC versions, even where normative language is not used. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and <del> "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  This document uses the terminology established in QUIC-TRANSPORT. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and <del> "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  Commonly used terms in the document are described below. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and <del> "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  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 <del> "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  Definitions of terms that are used in this document:

kramdown-rfc2629 inserts a non-breaking space when expanding , which xml2rfc subsequently mangles to produce invalid XML. Rather than deal with that, insert the boilerplate with regular spaces instead. Note that this is necessary to make work properly, as that tool drops the non-breaking whitespace character between "BCP" and "14".
URL (I need to follow up regarding the use of non-breaking whitespace generally).
This seems fine, but I assume you've separately filed the appropriate bugs to fix the regular tools?

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and  <ins> "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </ins> This document defines requirements on future QUIC versions, even where normative language is not used. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and  <ins> "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </ins> This document uses the terminology established in QUIC-TRANSPORT. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and  <ins> "OPTIONAL" in this document are to be interpreted as described in BCP 14 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </ins> Commonly used terms in the document are described below. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and  <ins> "OPTIONAL" in this document are to be interpreted as described in BCP 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  <ins> "OPTIONAL" in this document are to be interpreted as described in BCP 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:


Indicates that x is A bits long Indicates that x can be any length from A to B; A can be omitted <del> to indicate a minimum of zero bits and B can be omitted to </del>  indicate no set upper limit; values in this format always end on a byte boundary <del> Indicates that x, with a length described by L, has a fixed value of C </del>  <del> Indicates that x is repeated zero or more times (and that each instance is length L) </del>  This document uses network byte order (that is, big endian) values. Fields are placed starting from the high-order bits of each byte. Indicates that x is A bits long Indicates that x holds an integer value using the variable-length <del> encoding in </del>  Indicates that x can be any length from A to B; A can be omitted <del> to indicate a minimum of zero bits and B can be omitted to </del>  indicate no set upper limit; values in this format always end on a byte boundary <del> Indicates that x has a fixed value of C with the length described by L, which can use any of the three length forms above </del>  Indicates that x has a value in the range from C to D, inclusive, with the length described by L, as above <del> Indicates that x is optional (and has length of L) </del>  <del> Indicates that zero or more instances of x are present (and that each instance is length L) </del>  This document uses network byte order (that is, big endian) values. Fields are placed starting from the high-order bits of each byte.

These were not the same, even for the same items, so I fixed that. Checked with: Which shows the three items that are only present in -transport (-invariants doesn't use these).

Indicates that x is A bits long Indicates that x can be any length from A to B; A can be omitted  <ins> to indicate a minimum of zero bits, and B can be omitted to </ins> indicate no set upper limit; values in this format always end on a byte boundary  <ins> Indicates that x has a fixed value of C; the length of x is described by L, which can use any of the length forms above </ins>  <ins> Indicates that x is repeated zero or more times and that each instance has a length of L </ins> This document uses network byte order (that is, big endian) values. Fields are placed starting from the high-order bits of each byte. Indicates that x is A bits long Indicates that x holds an integer value using the variable-length  <ins> encoding described in </ins> Indicates that x can be any length from A to B; A can be omitted  <ins> to indicate a minimum of zero bits, and B can be omitted to </ins> indicate no set upper limit; values in this format always end on a byte boundary  <ins> Indicates that x has a fixed value of C; the length of x is described by L, which can use any of the length forms above </ins> Indicates that x has a value in the range from C to D, inclusive, with the length described by L, as above  <ins> Indicates that x is optional and has a length of L </ins>  <ins> Indicates that x is repeated zero or more times and that each instance has a length of L </ins> This document uses network byte order (that is, big endian) values. Fields are placed starting from the high-order bits of each byte.


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 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  This document defines requirements on future QUIC versions, even where normative language is not used. 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 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  Commonly used terms in this document are described below. current maximum datagram size, referred to as PMTU probes.  All QUIC packets that are not sent in a PMTU probe SHOULD be sized to fit within the maximum datagram size to avoid the datagram being <del> fragmented or dropped RFC8085. </del>  If a QUIC endpoint determines that the PMTU between any pair of local and remote IP addresses cannot support the smallest allowed maximum the payload of an ICMP message to associate the message with a corresponding transport connection (see Section 4.6.1 of DPLPMTUD). ICMP message validation MUST include matching IP addresses and UDP <del> ports RFC8085 and, when possible, connection IDs to an active QUIC </del>  session.  The endpoint SHOULD ignore all ICMP messages that fail validation. 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 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  This document uses the terminology established in 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 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  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 RFC2119 RFC8174 when, and only when, they appear in all capitals, as shown here. </del>  Definitions of terms that are used in this document:

This includes all the updates to references in transport. This includes new code again. See URL It would be possible to cite BCP38 as an RFC and avoid this, but I think that the BCP reference is correct. Not as sure about the BCP145 reference, as we need to point to the RFC directly to get the section reference, but I think that is OK on balance.

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 BCP14 when, and only when, they appear in all capitals, as shown here. </ins> This document defines requirements on future QUIC versions, even where normative language is not used. 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 BCP14 when, and only when, they appear in all capitals, as shown here. </ins> Commonly used terms in this document are described below. current maximum datagram size, referred to as PMTU probes.  All QUIC packets that are not sent in a PMTU probe SHOULD be sized to fit within the maximum datagram size to avoid the datagram being  <ins> fragmented or dropped BCP145. </ins> If a QUIC endpoint determines that the PMTU between any pair of local and remote IP addresses cannot support the smallest allowed maximum the payload of an ICMP message to associate the message with a corresponding transport connection (see Section 4.6.1 of DPLPMTUD). ICMP message validation MUST include matching IP addresses and UDP  <ins> ports BCP145 and, when possible, connection IDs to an active QUIC </ins> session.  The endpoint SHOULD ignore all ICMP messages that fail validation. 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 BCP14 when, and only when, they appear in all capitals, as shown here. </ins> This document uses the terminology established in 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  <ins> 14 BCP14 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  <ins> 14 BCP14 when, and only when, they appear in all capitals, as shown here. </ins> Definitions of terms that are used in this document:


the new RTT to be included in smoothed_rtt. Endpoints SHOULD set the min_rtt to the newest RTT sample after <del> persistent congestion is established.  This is to allow a connection to reset its estimate of min_rtt and smoothed_rtt (smoothed-rtt) after a disruptive network event, and because it is possible that an increase in path delay resulted in persistent congestion being incorrectly declared. </del>  Endpoints MAY re-establish the min_rtt at other times in the connection, such as when traffic volume is low and an acknowledgment

3) [rfced] Does the following improve the readability of the paragraph? Current: Endpoints SHOULD set the minrtt to the newest RTT sample after persistent congestion is established. This is to allow a connection to reset its estimate of minrtt and smoothedrtt after a disruptive network event (Section 5.3), and because it is possible that an increase in path delay resulted in persistent congestion being incorrectly declared. Perhaps: Endpoints SHOULD set the minrtt to the newest RTT sample after persistent congestion is established because it is possible that an increase in path delay resulted in persistent congestion being incorrectly declared. This also allows a connection to reset its estimate of minrtt and smoothedrtt after a disruptive network event (Section 5.3).
I find this easier to read, but I think it may be subtly different, so I put it into a separate PR.
It doesn't change the meaning, but it does feel like the first sentence is trying to span too many topics. I like the reordering, but I'd split it out.This is good, thank you !

the new RTT to be included in smoothed_rtt. Endpoints SHOULD set the min_rtt to the newest RTT sample after  <ins> persistent congestion is established.  This avoids repeatedly declaring persistent congestion when the RTT increases.  This also allows a connection to reset its estimate of min_rtt and smoothed_rtt after a disruptive network event; see smoothed-rtt. </ins> Endpoints MAY re-establish the min_rtt at other times in the connection, such as when traffic volume is low and an acknowledgment


4.7. QUIC uses a probe timeout (PTO; see pto), with a timer based on TCP's <del> RTO computation; see RFC6297.  QUIC's PTO includes the peer's maximum expected acknowledgment delay instead of using a fixed minimum timeout. </del>  Similar to the RACK-TLP loss detection algorithm for TCP (RACK), QUIC does not collapse the congestion window when the PTO expires, since a retransmissions and may result in degraded performance due to the actions of the congestion controller upon detecting loss. Implementations can detect spurious retransmissions and increase the <del> reordering threshold in packets or time to reduce future spurious </del>  retransmissions and loss events.  Implementations with adaptive time thresholds MAY choose to start with smaller initial reordering thresholds to minimize recovery latency. constants-of-interest) for a new path, but the delay SHOULD NOT be considered an RTT sample. <del> Initial packets and Handshake packets could be never acknowledged, but they are removed from bytes in flight when the Initial and Handshake keys are discarded, as described below in discarding- packets.  When Initial or Handshake keys are discarded, the PTO and loss detection timers MUST be reset, because discarding keys indicates forward progress and the loss detection timer might have been set for a now discarded packet number space. </del>  6.2.2.1. from the client, it is the client's responsibility to send packets to unblock the server until it is certain that the server has finished its address validation (see Section 8 of QUIC-TRANSPORT).  That is, <del> the client MUST set the probe timer if the client has not received an </del>  acknowledgment for any of its Handshake packets and the handshake is not confirmed (see Section 4.1.2 of QUIC-TLS), even if there are no packets in flight.  When the PTO fires, the client MUST send a arrive before Initial packets, early 0-RTT packets will be declared lost, but that is expected to be infrequent. <del> It is expected that keys are discarded after packets encrypted with them would be acknowledged or declared lost.  However, Initial and Handshake secrets are discarded as soon as handshake and 1-RTT keys are proven to be available to both client and server; see Section 4.9.1 of QUIC-TLS. </del>  7. When bytes in flight is smaller than the congestion window and sending is not pacing limited, the congestion window is under- <del> utilized.  When this occurs, the congestion window SHOULD NOT be increased in either slow start or congestion avoidance.  This can happen due to insufficient application data or flow control limits. </del>  A sender that paces packets (see pacing) might delay sending packets and not fully utilize the congestion window due to this delay.  A

Addresses comments 2, 4, 7, 8, 9, and 11.
one tiny suggestion, but lgtm -- thanks for doing this!

4.7. QUIC uses a probe timeout (PTO; see pto), with a timer based on TCP's  <ins> retransmission timeout (RTO) computation; see RFC6298.  QUIC's PTO includes the peer's maximum expected acknowledgment delay instead of using a fixed minimum timeout. </ins> Similar to the RACK-TLP loss detection algorithm for TCP (RACK), QUIC does not collapse the congestion window when the PTO expires, since a retransmissions and may result in degraded performance due to the actions of the congestion controller upon detecting loss. Implementations can detect spurious retransmissions and increase the  <ins> packet or time reordering threshold to reduce future spurious </ins> retransmissions and loss events.  Implementations with adaptive time thresholds MAY choose to start with smaller initial reordering thresholds to minimize recovery latency. constants-of-interest) for a new path, but the delay SHOULD NOT be considered an RTT sample.  <ins> When the Initial keys and Handshake keys are discarded (discarding- packets), any Initial packets and Handshake packets can no longer be acknowledged, so they are removed from bytes in flight.  When Initial or Handshake keys are discarded, the PTO and loss detection timers MUST be reset, because discarding keys indicates forward progress and the loss detection timer might have been set for a now discarded packet number space. </ins> 6.2.2.1. from the client, it is the client's responsibility to send packets to unblock the server until it is certain that the server has finished its address validation (see Section 8 of QUIC-TRANSPORT).  That is,  <ins> the client MUST set the PTO timer if the client has not received an </ins> acknowledgment for any of its Handshake packets and the handshake is not confirmed (see Section 4.1.2 of QUIC-TLS), even if there are no packets in flight.  When the PTO fires, the client MUST send a arrive before Initial packets, early 0-RTT packets will be declared lost, but that is expected to be infrequent.  <ins> It is expected that keys are discarded at some time after the packets encrypted with them are either acknowledged or declared lost. However, Initial and Handshake secrets are discarded as soon as handshake and 1-RTT keys are proven to be available to both client and server; see Section 4.9.1 of QUIC-TLS. </ins> 7. When bytes in flight is smaller than the congestion window and sending is not pacing limited, the congestion window is under-  <ins> utilized.  This can happen due to insufficient application data or flow control limits.  When this occurs, the congestion window SHOULD NOT be increased in either slow start or congestion avoidance. </ins> A sender that paces packets (see pacing) might delay sending packets and not fully utilize the congestion window due to this delay.  A


flight, the timer MUST be set to the earlier value of the Initial and Handshake packet number spaces. <del> An endpoint MUST NOT set its PTO timer for the application data </del>  packet number space until the handshake is confirmed.  Doing so prevents the endpoint from retransmitting information in packets when either the peer does not yet have the keys to process them or the

For this document, I believe the best option is to use "Application Data" when referring to the packet number space, and "application data" when referring to generic application data, such as when discussing being app-limited due to lack of application data. 6) [rfced] Throughout the text, the following term appears to be used inconsistently. Please review these occurrences and let us know if/how they may be made consistent. application data / Application Data Note that RFC-to-be 9000 uses the lowercase form consistently. We raised a similar question for RFC-to-be 9001; the authors decided on the following: (see URL)

flight, the timer MUST be set to the earlier value of the Initial and Handshake packet number spaces.  <ins> An endpoint MUST NOT set its PTO timer for the Application Data </ins> packet number space until the handshake is confirmed.  Doing so prevents the endpoint from retransmitting information in packets when either the peer does not yet have the keys to process them or the


QUIC aims to constrain the capabilities of an on-path attacker as follows: <del> An on-path attacker can prevent use of a path for a connection, causing the connection to fail if it cannot use a different path that does not contain the attacker.  This can be achieved by dropping all packets, modifying them so that they fail to decrypt, or other methods. </del>  An on-path attacker can prevent migration to a new path for which the attacker is also on-path by causing path validation to fail on

Do you need to rebase? There's a change that seems to have been repeated in a previously merged PR.

QUIC aims to constrain the capabilities of an on-path attacker as follows:  <ins> An on-path attacker can prevent the use of a path for a connection, causing the connection to fail if it cannot use a different path that does not contain the attacker.  This can be achieved by dropping all packets, modifying them so that they fail to decrypt, or other methods. </ins> An on-path attacker can prevent migration to a new path for which the attacker is also on-path by causing path validation to fail on


as sending a Stateless Reset. An endpoint cannot determine the Source Connection ID from a packet <del> with a short header, therefore it cannot set the Destination </del>  Connection ID in the Stateless Reset.  The Destination Connection ID will therefore differ from the value used in previous packets.  A random Destination Connection ID makes the connection ID appear to be against all previous values, but a duplicate value MAY be treated as a connection error of type PROTOCOL_VIOLATION. <del> Note that Stateless Reset packets do not have any cryptographic protection. </del>  10.3.3. sufficient to prevent looping.  In the event of a loop, this results in packets eventually being too small to trigger a response. <del> An endpoint can remember the number of Stateless Reset packets that it has sent and stop generating new Stateless Reset packets once a limit is reached.  Using separate limits for different remote addresses will ensure that Stateless Reset packets can be used to close connections when other peers or connections have exhausted limits. A Stateless Reset packet that is smaller than 41 bytes might be identifiable as a Stateless Reset packet by an observer, depending upon the length of the peer's connection IDs.  Conversely, not sending a Stateless Reset packet in response to a small packet might result in Stateless Reset packets not being useful in detecting cases of broken connections where only very small packets are sent; such failures might only be detected by other means, such as timers. </del>  11. current maximum datagram size, referred to as PMTU probes.  All QUIC packets that are not sent in a PMTU probe SHOULD be sized to fit within the maximum datagram size to avoid the datagram being <del> fragmented or dropped BCP145. </del>  If a QUIC endpoint determines that the PMTU between any pair of local and remote IP addresses cannot support the smallest allowed maximum the payload of an ICMP message to associate the message with a corresponding transport connection (see Section 4.6.1 of DPLPMTUD). ICMP message validation MUST include matching IP addresses and UDP <del> ports BCP145 and, when possible, connection IDs to an active QUIC </del>  session.  The endpoint SHOULD ignore all ICMP messages that fail validation. In packet types that contain a Packet Number field, the least significant two bits (those with a mask of 0x03) of byte 0 contain <del> the length of the packet number, encoded as an unsigned two-bit integer that is one less than the length of the Packet Number </del>  field in bytes.  That is, the length of the Packet Number field is the value of this field plus one.  These bits are protected using header protection; see Section 5.4 of QUIC-TLS. This field is 1 to 4 bytes long.  The packet number is protected using header protection; see Section 5.4 of QUIC-TLS.  The length <del> of the packet number field is encoded in the Packet Number Length </del>  bits of byte 0; see above. This is the payload of the packet - containing a sequence of If an endpoint receives a NEW_CONNECTION_ID frame that repeats a previously issued connection ID with a different Stateless Reset <del> Token or a different sequence number, or if a sequence number is used for different connection IDs, the endpoint MAY treat that receipt as a connection error of type PROTOCOL_VIOLATION. </del>  The Retire Prior To field applies to connection IDs established during connection setup and the preferred_address transport The Source and Destination Connection ID fields are the primary means of protection against an off-path attack during the handshake; see validate-handshake.  These are required to match those set by a peer. <del> Except for Initial and Stateless Reset packets, an endpoint only </del>  accepts packets that include a Destination Connection ID field that matches a value the endpoint previously chose.  This is the only protection offered for Version Negotiation packets.

Individual commits break this down, but this is all fairly prosaic stuff..
Thanks for clarifying and for fixing the one awkward case.

as sending a Stateless Reset. An endpoint cannot determine the Source Connection ID from a packet  <ins> with a short header; therefore, it cannot set the Destination </ins> Connection ID in the Stateless Reset.  The Destination Connection ID will therefore differ from the value used in previous packets.  A random Destination Connection ID makes the connection ID appear to be against all previous values, but a duplicate value MAY be treated as a connection error of type PROTOCOL_VIOLATION.  <ins> Note that Stateless Resets do not have any cryptographic protection. </ins> 10.3.3. sufficient to prevent looping.  In the event of a loop, this results in packets eventually being too small to trigger a response.  <ins> An endpoint can remember the number of Stateless Resets that it has sent and stop generating new Stateless Resets once a limit is reached.  Using separate limits for different remote addresses will ensure that Stateless Resets can be used to close connections when other peers or connections have exhausted limits. A Stateless Reset that is smaller than 41 bytes might be identifiable as a Stateless Reset by an observer, depending upon the length of the peer's connection IDs.  Conversely, not sending a Stateless Reset in response to a small packet might result in Stateless Resets not being useful in detecting cases of broken connections where only very small packets are sent; such failures might only be detected by other means, such as timers. </ins> 11. current maximum datagram size, referred to as PMTU probes.  All QUIC packets that are not sent in a PMTU probe SHOULD be sized to fit within the maximum datagram size to avoid the datagram being  <ins> fragmented or dropped RFC8085. </ins> If a QUIC endpoint determines that the PMTU between any pair of local and remote IP addresses cannot support the smallest allowed maximum the payload of an ICMP message to associate the message with a corresponding transport connection (see Section 4.6.1 of DPLPMTUD). ICMP message validation MUST include matching IP addresses and UDP  <ins> ports RFC8085 and, when possible, connection IDs to an active QUIC </ins> session.  The endpoint SHOULD ignore all ICMP messages that fail validation. In packet types that contain a Packet Number field, the least significant two bits (those with a mask of 0x03) of byte 0 contain  <ins> the length of the Packet Number field, encoded as an unsigned two- bit integer that is one less than the length of the Packet Number </ins> field in bytes.  That is, the length of the Packet Number field is the value of this field plus one.  These bits are protected using header protection; see Section 5.4 of QUIC-TLS. This field is 1 to 4 bytes long.  The packet number is protected using header protection; see Section 5.4 of QUIC-TLS.  The length  <ins> of the Packet Number field is encoded in the Packet Number Length </ins> bits of byte 0; see above. This is the payload of the packet - containing a sequence of If an endpoint receives a NEW_CONNECTION_ID frame that repeats a previously issued connection ID with a different Stateless Reset  <ins> Token field value or a different Sequence Number field value, or if a sequence number is used for different connection IDs, the endpoint MAY treat that receipt as a connection error of type PROTOCOL_VIOLATION. </ins> The Retire Prior To field applies to connection IDs established during connection setup and the preferred_address transport The Source and Destination Connection ID fields are the primary means of protection against an off-path attack during the handshake; see validate-handshake.  These are required to match those set by a peer.  <ins> Except for Initial packets and Stateless Resets, an endpoint only </ins> accepts packets that include a Destination Connection ID field that matches a value the endpoint previously chose.  This is the only protection offered for Version Negotiation packets.


the stream becomes unblocked, and releasing the flow control prematurely makes the decoder vulnerable to memory exhaustion attacks.  A stream becomes unblocked when the Insert Count becomes <del> unblocked when the Insert Count becomes greater than or equal to the Required Insert Count for all encoded field sections the decoder has started reading from the stream. </del>  When processing encoded field sections, the decoder expects the Required Insert Count to equal the lowest possible value for the

The repeated "when" clauses in this sentence make it difficult to parse. If our suggestion does not correctly capture your intent, could you please rephrase? Original: A stream becomes unblocked when the Insert Count becomes unblocked when the Insert Count becomes greater than or equal to the Required Insert Count for all encoded field sections the decoder has started reading from the stream. Perhaps: A stream becomes unblocked when the Insert Count becomes unblocked. When the Insert Count becomes greater than or equal to the Required Insert Count for all encoded field sections, the decoder has started reading from the stream.
It actually looks as though the words "becomes unblocked when the Insert Count" are duplicated, which would make the corrected text: That might still be confusing, but the proposed text certainly isn't the right change. The key point to capture is: The decoder has started reading at least one encoded field section from the stream and encountered a Required Insert Count value in some or all of them which exceeds its current Insert Count. This caused the stream to be considered blocked. When the Insert Count is greater than or equal to the RIC value from all of the encoded field sections the decoder has attempted to process, the stream becomes unblocked.
Fixed in .
Good catch.

the stream becomes unblocked, and releasing the flow control prematurely makes the decoder vulnerable to memory exhaustion attacks.  A stream becomes unblocked when the Insert Count becomes  <ins> greater than or equal to the Required Insert Count for all encoded field sections the decoder has started reading from the stream. </ins> When processing encoded field sections, the decoder expects the Required Insert Count to equal the lowest possible value for the


the message exchange, they must be received and processed before the message can be consumed.  See header-formatting for more details. <del> Transfer codings (see Section 6.1 of HTTP11) are not defined for </del>  HTTP/3; the Transfer-Encoding header field MUST NOT be used. A response MAY consist of multiple messages when and only when one or

Noticed in URL that we're pointing to different sections: 6.1 is the Transfer-Encoding header 7.1 is specifically 7 is transfer codings in general Since this passage is referring to the concept in general not being present in HTTP/3, Section 7 is the correct reference.

the message exchange, they must be received and processed before the message can be consumed.  See header-formatting for more details.  <ins> Transfer codings (see Section 7 of HTTP11) are not defined for </ins> HTTP/3; the Transfer-Encoding header field MUST NOT be used. A response MAY consist of multiple messages when and only when one or


A TCP connection error is signaled by abruptly terminating the stream.  A proxy treats any error in the TCP connection, which includes receiving a TCP segment with the RST bit set, as a stream <del> error of type H3_CONNECT_ERROR; see errors.  Correspondingly, if a proxy detects an error with the stream or the QUIC connection, it MUST close the TCP connection.  If the underlying TCP implementation permits it, the proxy SHOULD send a TCP segment with the RST bit set. </del>  Since CONNECT creates a tunnel to an arbitrary server, proxies that support CONNECT SHOULD restrict its use to a set of known ports or a

This looks great to me.
NAME that's a good point. Let me reword it to use the operation terms rather than the v1 frame names.
From ... : URL be improved in h3. Not the TCP RST part, but the bit that leads up to it. Otherwise, we might not get the right behaviour. If the proxy just closes the connection in response to RESET_STREAM, it might then just end the stream (with a FIN bit), which would be wrong. Perhaps instead: Somewhat substantive, unfortunately, and very, very, very late. I'm happy to wait and file an erratum.
This seems like a solid improvement, but it's definitely not editorial. NAME and NAME will need to decide whether this is a change they're willing to accept post-IESG.
Endpoints that overlook the proposed behaviour risk zombie streams. This seems like something worth addressing while we have the opportunity. Can one of you please file create a PR and we'll take it to the AD.
Closed in .
Better than my text :)This looks ready to go, are we merging it soon?

A TCP connection error is signaled by abruptly terminating the stream.  A proxy treats any error in the TCP connection, which includes receiving a TCP segment with the RST bit set, as a stream  <ins> error of type H3_CONNECT_ERROR; see errors. Correspondingly, if a proxy detects an error with the stream or the QUIC connection, it MUST close the TCP connection.  If the proxy detects that the client has reset the stream or aborted reading from the stream, it MUST close the TCP connection.  If the stream is reset or reading is aborted by the client, a proxy SHOULD perform the same operation on the other direction in order to ensure that both directions of the stream are cancelled.  In all these cases, if the underlying TCP implementation permits it, the proxy SHOULD send a TCP segment with the RST bit set. </ins> Since CONNECT creates a tunnel to an arbitrary server, proxies that support CONNECT SHOULD restrict its use to a set of known ports or a


If the stream header indicates a stream type that is not supported by the recipient, the remainder of the stream cannot be consumed as the <del> semantics are unknown.  Recipients of unknown stream types MAY abort reading of the stream with an error code of H3_STREAM_CREATION_ERROR or a reserved error code (http-error-codes), but the recipients MUST NOT consider such streams to be a connection error of any kind. </del>  As certain stream types can affect connection state, a recipient SHOULD NOT discard data from incoming unidirectional streams prior to and stream types (iana-stream-types). Implementations MUST ignore unknown or unsupported values in all <del> extensible protocol elements.  Implementations MUST discard frames and abort reading on unidirectional streams that have unknown or </del>  unsupported types.  This means that any of these extension points can be safely used by extensions without prior arrangement or negotiation.  However, where a known frame type is required to be in

NAME observed a seeming conflict in the requirements around unknown unidirectional stream types. Section 9 says: This has two problems. First and editorial, if the type is unknown/unsupported, the presence of frames can't be determined. This should refer to discarding any data, not frames specifically. Second, it appears to disagree with Section 6.2: I think the intent was MUST abort, but MAY pick an error code. Looking at the history of the commits in Section 6.2, it was first MUST abort, then SHOULD use a particular code, then became MAY use the specific code with the prohibition on blowing up the whole connection. The text should clarify the scope of the MAY.
Agree. This change would meet the intent of the text and is editorial. So it the proposal here something like:
I think I'd say "MUST either abort reading of the stream or discard incoming data without further processing. If reading is aborted, the recipient SHOULD use...."
That would work for me too, care to make a PR?
Closed in .
LGTM thank you

If the stream header indicates a stream type that is not supported by the recipient, the remainder of the stream cannot be consumed as the  <ins> semantics are unknown.  Recipients of unknown stream types MUST either abort reading of the stream or discard incoming data without further processing.  If reading is aborted, the recipient SHOULD use the H3_STREAM_CREATION_ERROR error code or a reserved error code (http-error-codes).  The recipient MUST NOT consider unknown stream types to be a connection error of any kind. </ins> As certain stream types can affect connection state, a recipient SHOULD NOT discard data from incoming unidirectional streams prior to and stream types (iana-stream-types). Implementations MUST ignore unknown or unsupported values in all  <ins> extensible protocol elements.  Implementations MUST discard data or abort reading on unidirectional streams that have unknown or </ins> unsupported types.  This means that any of these extension points can be safely used by extensions without prior arrangement or negotiation.  However, where a known frame type is required to be in


<del> Hypertext Transfer Protocol Version 3 (HTTP/3) </del>  Abstract with a value of '*'; see Section 7.1 of SEMANTICS. All HTTP/3 requests MUST include exactly one value for the ":method", <del> ":scheme", and ":path" pseudo-header fields, unless it is a CONNECT request; see connect. </del>  If the ":scheme" pseudo-header field identifies a scheme that has a mandatory authority component (including "http" and "https"), the cancelling a request it has already begun processing. Implementations SHOULD cancel requests by abruptly terminating any <del> directions of a stream that are still open.  This means resetting the sending parts of streams and aborting reading on receiving parts of streams; see Section 2.4 of QUIC-TRANSPORT. </del>  When the server cancels a request without performing any application processing, the request is considered "rejected".  The server SHOULD stream, HTTP/3 does not make use of this feature. QUIC streams can be either unidirectional, carrying data only from <del> initiator to receiver, or bidirectional.  Streams can be initiated by either the client or the server.  For more detail on QUIC streams, see Section 2 of QUIC-TRANSPORT. </del>  When HTTP fields and data are sent over QUIC, the QUIC layer handles most of the stream management.  HTTP does not need to do any separate becomes blocked.  In particular, implementations should consider that remote peers may wish to exercise reserved stream behavior (stream- grease) with some of the unidirectional streams they are permitted to <del> use.  To avoid blocking, the transport parameters sent by both clients and servers MUST allow the peer to create at least one unidirectional stream for the HTTP control stream plus the number of unidirectional streams required by mandatory extensions (three being the minimum number required for the base HTTP/3 protocol and QPACK), and SHOULD provide at least 1,024 bytes of flow-control credit to each stream. </del>  Note that an endpoint is not required to grant additional credits to create more unidirectional streams if its peer consumes all the The entries in iana-setting-table are registered by this document.  Each code of the format 0x1f * N + 0x21 for non-negative integer values of N (that is, 0x21, 0x40, ..., through 0x3ffffffffffffffe) MUST NOT be assigned by IANA and MUST NOT appear in the listing of

This PR covers questions asked during Auth48 which aren't pure copyediting, but seem to have a straightforward single-location fix. Individual commits, so it's easy to pull one out if someone disagrees.
In , the RFC Editor asks:
Either A or B is better, but I have no preference.
Fixed in , but GitHub won't automatically close until it hits .

<ins> HTTP/3 </ins> Abstract with a value of '*'; see Section 7.1 of SEMANTICS. All HTTP/3 requests MUST include exactly one value for the ":method",  <ins> ":scheme", and ":path" pseudo-header fields, unless the request is a CONNECT request; see connect. </ins> If the ":scheme" pseudo-header field identifies a scheme that has a mandatory authority component (including "http" and "https"), the cancelling a request it has already begun processing. Implementations SHOULD cancel requests by abruptly terminating any  <ins> directions of a stream that are still open.  To do so, an implementation resets the sending parts of streams and aborts reading on the receiving parts of streams; see Section 2.4 of QUIC-TRANSPORT. </ins> When the server cancels a request without performing any application processing, the request is considered "rejected".  The server SHOULD stream, HTTP/3 does not make use of this feature. QUIC streams can be either unidirectional, carrying data only from  <ins> initiator to receiver, or bidirectional, carrying data in both directions.  Streams can be initiated by either the client or the server.  For more detail on QUIC streams, see Section 2 of QUIC- TRANSPORT. </ins> When HTTP fields and data are sent over QUIC, the QUIC layer handles most of the stream management.  HTTP does not need to do any separate becomes blocked.  In particular, implementations should consider that remote peers may wish to exercise reserved stream behavior (stream- grease) with some of the unidirectional streams they are permitted to  <ins> use. Each endpoint needs to create at least one unidirectional stream for the HTTP control stream.  QPACK requires two additional unidirectional streams, and other extensions might require further streams.  Therefore, the transport parameters sent by both clients and servers MUST allow the peer to create at least three unidirectional streams.  These transport parameters SHOULD also provide at least 1,024 bytes of flow-control credit to each unidirectional stream. </ins> Note that an endpoint is not required to grant additional credits to create more unidirectional streams if its peer consumes all the The entries in iana-setting-table are registered by this document. <ins> For fomatting reasons, setting names can be abbreviated by removing the 'SETTING_' prefix. </ins> Each code of the format 0x1f * N + 0x21 for non-negative integer values of N (that is, 0x21, 0x40, ..., through 0x3ffffffffffffffe) MUST NOT be assigned by IANA and MUST NOT appear in the listing of


An HTTP message (request or response) consists of: <del> the header section, sent as a single HEADERS frame (see frame- headers), </del>  optionally, the content, if present, sent as a series of DATA frames (see frame-data), and 4.1.1. <del> HTTP messages carry metadata as a series of key-value pairs called "HTTP fields"; see Sections HTTP and HTTP of HTTP.  For a listing of registered HTTP fields, see the "Hypertext Transfer Protocol (HTTP) Field Name Registry" maintained at <https://www.iana.org/assignments/ http-fields/>. Field names are strings containing a subset of ASCII characters. Properties of HTTP field names and values are discussed in more detail in HTTP.  As in HTTP/2, characters in field names MUST be converted to lowercase prior to their encoding.  A request or response containing uppercase characters in field names MUST be treated as malformed (malformed). Like HTTP/2, HTTP/3 does not use the Connection header field to indicate connection-specific fields; in this protocol, connection- specific metadata is conveyed by other means.  An endpoint MUST NOT generate an HTTP/3 field section containing connection-specific fields; any message containing connection-specific fields MUST be treated as malformed (malformed). The only exception to this is the TE header field, which MAY be present in an HTTP/3 request header; when it is, it MUST NOT contain any value other than "trailers". An intermediary transforming an HTTP/1.x message to HTTP/3 MUST remove connection-specific header fields as discussed in HTTP, or their messages will be treated by other HTTP/3 endpoints as malformed (malformed). 4.1.1.1. Like HTTP/2, HTTP/3 employs a series of pseudo-header fields, where the field name begins with the ':' character (ASCII 0x3a).  These pseudo-header fields convey the target URI, the method of the request, and the status code for the response. Pseudo-header fields are not HTTP fields.  Endpoints MUST NOT generate pseudo-header fields other than those defined in this document; however, an extension could negotiate a modification of this restriction; see extensions. Pseudo-header fields are only valid in the context in which they are defined.  Pseudo-header fields defined for requests MUST NOT appear in responses; pseudo-header fields defined for responses MUST NOT appear in requests.  Pseudo-header fields MUST NOT appear in trailer sections.  Endpoints MUST treat a request or response that contains undefined or invalid pseudo-header fields as malformed (malformed). All pseudo-header fields MUST appear in the header section before regular header fields.  Any request or response that contains a pseudo-header field that appears in a header section after a regular header field MUST be treated as malformed (malformed). The following pseudo-header fields are defined for requests: All HTTP/3 requests MUST include exactly one value for the ":method", ":scheme", and ":path" pseudo-header fields, unless the request is a CONNECT request; see connect. If the ":scheme" pseudo-header field identifies a scheme that has a mandatory authority component (including "http" and "https"), the request MUST contain either an ":authority" pseudo-header field or a "Host" header field.  If these fields are present, they MUST NOT be empty.  If both fields are present, they MUST contain the same value. If the scheme does not have a mandatory authority component and none is provided in the request target, the request MUST NOT contain the ":authority" pseudo-header or "Host" header fields. An HTTP request that omits mandatory pseudo-header fields or contains invalid values for those pseudo-header fields is malformed (malformed). HTTP/3 does not define a way to carry the version identifier that is included in the HTTP/1.1 request line. For responses, a single ":status" pseudo-header field is defined that carries the HTTP status code; see HTTP.  This pseudo-header field MUST be included in all responses; otherwise, the response is malformed (see malformed). HTTP/3 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line. 4.1.1.2. QPACK describes a variation of HPACK that gives an encoder some control over how much head-of-line blocking can be caused by compression.  This allows an encoder to balance compression efficiency with latency.  HTTP/3 uses QPACK to compress header and trailer sections, including the pseudo-header fields present in the header section. To allow for better compression efficiency, the "Cookie" field (RFC6265) MAY be split into separate field lines, each with one or more cookie-pairs, before compression.  If a decompressed field section contains multiple cookie field lines, these MUST be concatenated into a single byte string using the two-byte delimiter of 0x3b, 0x20 (the ASCII string "; ") before being passed into a context other than HTTP/2 or HTTP/3, such as an HTTP/1.1 connection, or a generic HTTP server application. 4.1.1.3. An HTTP/3 implementation MAY impose a limit on the maximum size of the message header it will accept on an individual HTTP message.  A server that receives a larger header section than it is willing to handle can send an HTTP 431 (Request Header Fields Too Large) status code (RFC6585).  A client can discard responses that it cannot process.  The size of a field list is calculated based on the uncompressed size of fields, including the length of the name and value in bytes plus an overhead of 32 bytes for each field. If an implementation wishes to advise its peer of this limit, it can be conveyed as a number of bytes in the SETTINGS_MAX_FIELD_SECTION_SIZE parameter.  An implementation that has received this parameter SHOULD NOT send an HTTP message header that exceeds the indicated size, as the peer will likely refuse to process it.  However, an HTTP message can traverse one or more intermediaries before reaching the origin server; see HTTP.  Because this limit is applied separately by each implementation that processes the message, messages below this limit are not guaranteed to be accepted. 4.1.2. </del> Once a request stream has been opened, the request MAY be cancelled by either endpoint.  Clients cancel requests if the response is no longer of interest; servers cancel requests if they are unable to or independent of the method or some means to detect that the original request was never applied.  See HTTP for more details. <del> 4.1.3. </del>  A malformed request or response is one that is an otherwise valid sequence of frames but is invalid due to: 4.2.  The CONNECT method requests that the recipient establish a tunnel to the destination origin server identified by the request-target; see HTTP.  It is primarily used with HTTP proxies to establish a TLS support CONNECT SHOULD restrict its use to a set of known ports or a list of safe request targets; see HTTP for more details. <del> 4.3. </del>  HTTP/3 does not support the HTTP Upgrade mechanism (HTTP) or the 101 (Switching Protocols) informational status code (HTTP). <del> 4.4. </del>  Server push is an interaction mode that permits a server to push a request-response exchange to a client in anticipation of the client Push ID that is greater than the maximum Push ID. The Push ID is used in one or more PUSH_PROMISE frames (frame-push- <del> promise) that carry the header section of the request message.  These frames are sent on the request stream that generated the push.  This allows the server push to be associated with a client request.  When the same Push ID is promised on multiple request streams, the decompressed request field sections MUST contain the same fields in the same order, and both the name and the value in each field MUST be identical. </del>  The Push ID is then included with the push stream that ultimately fulfills those promises; see push-streams.  The push stream

The diff looks larger than it is; I moved some sections around to more closely resemble the TOC of the HTTP/2 spec, and changed a section title that seemed a bit odd a year later. The relocated sections haven't changed. Old TOC: HTTP Request Lifecycle HTTP Message Exchanges Field Formatting and Compression Request Cancellation and Rejection Malformed Requests and Responses The CONNECT Method HTTP Upgrade Server Push New TOC: Expressing HTTP Semantics in HTTP/3 HTTP Message Framing Request Cancellation and Rejection Malformed Requests and Responses HTTP Fields HTTP Control Data Request Pseudo-Header Fields Response Pseudo-Header Fields The CONNECT Method HTTP Upgrade Server Push Comparison H2 TOC: Expressing HTTP Semantics in HTTP/2 HTTP Message Framing Malformed Messages HTTP Fields Field Validity Connection-Specific Header Fields Compressing the Cookie Header Field HTTP Control Data Request Pseudo-Header Fields Response Pseudo-Header Fields Server Push Push Requests Push Responses The CONNECT Method The Upgrade Header Field URL then some further sections as well.
Http-core introduces a new term, "control data," and HTTP/2 has been updated to use this term. HTTP/3 has not. While it was not raised in Auth48, it might be appropriate to align this terminology before we publish these documents together.
This seems like a good change for consistency, even if it might cause the document editor some short term pain.
Closed in .

An HTTP message (request or response) consists of:  <ins> the header section, including message control data, sent as a single HEADERS frame (see frame-headers), </ins> optionally, the content, if present, sent as a series of DATA frames (see frame-data), and 4.1.1.  Once a request stream has been opened, the request MAY be cancelled by either endpoint.  Clients cancel requests if the response is no longer of interest; servers cancel requests if they are unable to or independent of the method or some means to detect that the original request was never applied.  See HTTP for more details.  <ins> 4.1.2. </ins> A malformed request or response is one that is an otherwise valid sequence of frames but is invalid due to: 4.2. <ins> HTTP messages carry metadata as a series of key-value pairs called "HTTP fields"; see Sections HTTP and HTTP of HTTP.  For a listing of registered HTTP fields, see the "Hypertext Transfer Protocol (HTTP) Field Name Registry" maintained at <https://www.iana.org/assignments/ http-fields/>. Field names are strings containing a subset of ASCII characters. Properties of HTTP field names and values are discussed in more detail in HTTP.  As in HTTP/2, characters in field names MUST be converted to lowercase prior to their encoding.  A request or response containing uppercase characters in field names MUST be treated as malformed (malformed). Like HTTP/2, HTTP/3 does not use the Connection header field to indicate connection-specific fields; in this protocol, connection- specific metadata is conveyed by other means.  An endpoint MUST NOT generate an HTTP/3 field section containing connection-specific fields; any message containing connection-specific fields MUST be treated as malformed (malformed). The only exception to this is the TE header field, which MAY be present in an HTTP/3 request header; when it is, it MUST NOT contain any value other than "trailers". An intermediary transforming an HTTP/1.x message to HTTP/3 MUST remove connection-specific header fields as discussed in HTTP, or their messages will be treated by other HTTP/3 endpoints as malformed (malformed). 4.2.1. QPACK describes a variation of HPACK that gives an encoder some control over how much head-of-line blocking can be caused by compression.  This allows an encoder to balance compression efficiency with latency.  HTTP/3 uses QPACK to compress header and trailer sections, including the control data present in the header section. To allow for better compression efficiency, the "Cookie" field (RFC6265) MAY be split into separate field lines, each with one or more cookie-pairs, before compression.  If a decompressed field section contains multiple cookie field lines, these MUST be concatenated into a single byte string using the two-byte delimiter of 0x3b, 0x20 (the ASCII string "; ") before being passed into a context other than HTTP/2 or HTTP/3, such as an HTTP/1.1 connection, or a generic HTTP server application. 4.2.2. An HTTP/3 implementation MAY impose a limit on the maximum size of the message header it will accept on an individual HTTP message.  A server that receives a larger header section than it is willing to handle can send an HTTP 431 (Request Header Fields Too Large) status code (RFC6585).  A client can discard responses that it cannot process.  The size of a field list is calculated based on the uncompressed size of fields, including the length of the name and value in bytes plus an overhead of 32 bytes for each field. If an implementation wishes to advise its peer of this limit, it can be conveyed as a number of bytes in the SETTINGS_MAX_FIELD_SECTION_SIZE parameter.  An implementation that has received this parameter SHOULD NOT send an HTTP message header that exceeds the indicated size, as the peer will likely refuse to process it.  However, an HTTP message can traverse one or more intermediaries before reaching the origin server; see HTTP.  Because this limit is applied separately by each implementation that processes the message, messages below this limit are not guaranteed to be accepted. 4.3. Like HTTP/2, HTTP/3 employs a series of pseudo-header fields, where the field name begins with the ':' character (ASCII 0x3a).  These pseudo-header fields convey message control data; see HTTP. Pseudo-header fields are not HTTP fields.  Endpoints MUST NOT generate pseudo-header fields other than those defined in this document.  However, an extension could negotiate a modification of this restriction; see extensions. Pseudo-header fields are only valid in the context in which they are defined.  Pseudo-header fields defined for requests MUST NOT appear in responses; pseudo-header fields defined for responses MUST NOT appear in requests.  Pseudo-header fields MUST NOT appear in trailer sections.  Endpoints MUST treat a request or response that contains undefined or invalid pseudo-header fields as malformed (malformed). All pseudo-header fields MUST appear in the header section before regular header fields.  Any request or response that contains a pseudo-header field that appears in a header section after a regular header field MUST be treated as malformed (malformed). 4.3.1. The following pseudo-header fields are defined for requests: All HTTP/3 requests MUST include exactly one value for the ":method", ":scheme", and ":path" pseudo-header fields, unless the request is a CONNECT request; see connect. If the ":scheme" pseudo-header field identifies a scheme that has a mandatory authority component (including "http" and "https"), the request MUST contain either an ":authority" pseudo-header field or a "Host" header field.  If these fields are present, they MUST NOT be empty.  If both fields are present, they MUST contain the same value. If the scheme does not have a mandatory authority component and none is provided in the request target, the request MUST NOT contain the ":authority" pseudo-header or "Host" header fields. An HTTP request that omits mandatory pseudo-header fields or contains invalid values for those pseudo-header fields is malformed (malformed). HTTP/3 does not define a way to carry the version identifier that is included in the HTTP/1.1 request line.  HTTP/3 requests implicitly have a protocol version of "3.0". 4.3.2. For responses, a single ":status" pseudo-header field is defined that carries the HTTP status code; see HTTP.  This pseudo-header field MUST be included in all responses; otherwise, the response is malformed (see malformed). HTTP/3 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line.  HTTP/3 responses implicitly have a protocol version of "3.0". 4.4. </ins> The CONNECT method requests that the recipient establish a tunnel to the destination origin server identified by the request-target; see HTTP.  It is primarily used with HTTP proxies to establish a TLS support CONNECT SHOULD restrict its use to a set of known ports or a list of safe request targets; see HTTP for more details.  <ins> 4.5. </ins> HTTP/3 does not support the HTTP Upgrade mechanism (HTTP) or the 101 (Switching Protocols) informational status code (HTTP).  <ins> 4.6. </ins> Server push is an interaction mode that permits a server to push a request-response exchange to a client in anticipation of the client Push ID that is greater than the maximum Push ID. The Push ID is used in one or more PUSH_PROMISE frames (frame-push-  <ins> promise) that carry the control data and header fields of the request message.  These frames are sent on the request stream that generated the push.  This allows the server push to be associated with a client request.  When the same Push ID is promised on multiple request streams, the decompressed request field sections MUST contain the same fields in the same order, and both the name and the value in each field MUST be identical. </ins> The Push ID is then included with the push stream that ultimately fulfills those promises; see push-streams.  The push stream


more cookie-pairs, before compression.  If a decompressed field section contains multiple cookie field lines, these MUST be concatenated into a single byte string using the two-byte delimiter <del> of 0x3b, 0x20 (the ASCII string "; ") before being passed into a context other than HTTP/2 or HTTP/3, such as an HTTP/1.1 connection, or a generic HTTP server application. </del>  4.2.2. 4.3. Like HTTP/2, HTTP/3 employs a series of pseudo-header fields, where <del> the field name begins with the ':' character (ASCII 0x3a).  These </del>  pseudo-header fields convey message control data; see HTTP. Pseudo-header fields are not HTTP fields.  Endpoints MUST NOT Similarly, HTTP/3 can transport field values that are not valid. While most values that can be encoded will not alter field parsing, <del> carriage return (CR, ASCII 0x0d), line feed (LF, ASCII 0x0a), and the zero character (NUL, ASCII 0x00) might be exploited by an attacker if they are translated verbatim.  Any request or response that contains a character not permitted in a field value MUST be treated as malformed (malformed).  Valid characters are defined by the "field- content" ABNF rule in HTTP. </del>  10.4.

The RFC Editor asks:
Along the way, there are two equivalent statements that need to be deduplicated that this change touches: I would suggest collapsing these two into the first statement, but using OPTIONS as an example and keeping the reference into http-core. Or perhaps that should be a question -- is there a difference between asterisk-form and OPTIONS-without-path?
Resolved in .

more cookie-pairs, before compression.  If a decompressed field section contains multiple cookie field lines, these MUST be concatenated into a single byte string using the two-byte delimiter  <ins> of "; " (ASCII 0x3b, 0x20) before being passed into a context other than HTTP/2 or HTTP/3, such as an HTTP/1.1 connection, or a generic HTTP server application. </ins> 4.2.2. 4.3. Like HTTP/2, HTTP/3 employs a series of pseudo-header fields, where  <ins> the field name begins with the ":" character (ASCII 0x3a).  These </ins> pseudo-header fields convey message control data; see HTTP. Pseudo-header fields are not HTTP fields.  Endpoints MUST NOT Similarly, HTTP/3 can transport field values that are not valid. While most values that can be encoded will not alter field parsing,  <ins> carriage return (ASCII 0x0d), line feed (ASCII 0x0a), and the null character (ASCII 0x00) might be exploited by an attacker if they are translated verbatim.  Any request or response that contains a character not permitted in a field value MUST be treated as malformed (malformed).  Valid characters are defined by the "field-content" ABNF rule in HTTP. </ins> 10.4.


and structure of data that follows this integer is determined by the stream type. <del> Two stream types are defined in this document: control streams (control-streams) and (push-streams).  RFC9204 defines two additional stream types.  Other stream types can be defined by extensions to HTTP/3; see extensions for more details.  Some stream types are reserved (stream-grease). </del>  The performance of HTTP/3 connections in the early phase of their lifetime is sensitive to the creation and exchange of data on If an entire connection needs to be terminated, QUIC similarly provides mechanisms to communicate a reason; see QUIC-TRANSPORT. <del> This is referred to as a "".  Similar to stream errors, an HTTP/3 implementation can terminate a QUIC connection and communicate the reason using an error code from http-error-codes. </del>  Although the reasons for closing streams and connections are called "errors", these actions do not necessarily indicate a problem with CANCEL_PUSH connection error control stream <del> control streams control streams </del> D DATA

NAME was helpful enough to show me how to do this in URL, so now singular and plural versions of the same term are a single index entry.

and structure of data that follows this integer is determined by the stream type.  <ins> Two stream types are defined in this document: (control-streams) and (push-streams).  RFC9204 defines two additional stream types.  Other stream types can be defined by extensions to HTTP/3; see extensions for more details.  Some stream types are reserved (stream-grease). </ins> The performance of HTTP/3 connections in the early phase of their lifetime is sensitive to the creation and exchange of data on If an entire connection needs to be terminated, QUIC similarly provides mechanisms to communicate a reason; see QUIC-TRANSPORT.  <ins> This is referred to as a "".  Similar to , an HTTP/3 implementation can terminate a QUIC connection and communicate the reason using an error code from http-error-codes. </ins> Although the reasons for closing streams and connections are called "errors", these actions do not necessarily indicate a problem with CANCEL_PUSH connection error control stream  D DATA


stream.  Receipt of a second instance of either stream type MUST be treated as a connection error of type H3_STREAM_CREATION_ERROR. <del> These streams MUST NOT be closed.  Closure of either unidirectional stream type MUST be treated as a connection error of type H3_CLOSED_CRITICAL_STREAM. </del>  An endpoint MAY avoid creating an encoder stream if it will not be used (for example, if its encoder does not wish to use the dynamic

builds on .
URL stream type MUST be treated as a connection error of type H3CLOSEDCRITICALSTREAM. I'd like to clarify that whether this effectively says that receiver is not allowed to send STOPSENDING. STOPSENDING is elicit RESETSTREAM that closes a stream. MUST send a RESETSTREAM frame if the stream is in the "Ready" or "Send" state. STOPSENDING itself does not close a stream, but it is an action to request a closure. I found in interop runner test, one implementation sends STOPSENDING to QPACK streams. My implementation sends RESETSTREAM when it is received as mandated by spec, and upon stream closure, the connection is closed because QPACK streams are closed, then the test fails. HTTP draft explicitly says that requesting closure for the control stream is prohibited: request that the sender close the control stream. It would be nice to add the similar statement to QPACK streams.
It's super-late in the process, but maybe the editors can see a way to squeeze an editorial change in.
Thanks Tatsuhiro. I agree, IMO the intention was always for consistent treatment of open control streams and open qpack streams when it comes to not closing them. Finding a way to address this during AUTH48 would be nice.
I agree, this was the intention -- closing the stream is treated as an error, and being asked to commit an error is itself an error. One could squint and say it's covered by the existing text -- upon receipt of the STOP_SENDING, the send is required to close the stream; closure of the stream is already required to be treated as an error. It's technically a normative change, but there's no effective change in behavior.
If it's a normative change, is it still OK to change in auth48 just with a WG consensus call or is more process required?
The AD has to decide what to do and approve this change to the RFC editor.
Since the fix includes a gentle normative change, marking this as a design issue and we'll put out a consensus call to the list.
Consensus was declared, so was merged.

stream.  Receipt of a second instance of either stream type MUST be treated as a connection error of type H3_STREAM_CREATION_ERROR.  <ins> The sender MUST NOT close either of these streams, and the receiver MUST NOT request that the sender close either of these streams. Closure of either unidirectional stream type MUST be treated as a connection error of type H3_CLOSED_CRITICAL_STREAM. </ins> An endpoint MAY avoid creating an encoder stream if it will not be used (for example, if its encoder does not wish to use the dynamic


SETTINGS, the encoder must treat this as a connection error of type QPACK_DECODER_STREAM_ERROR. <del> For HTTP/3 servers and HTTP/3 clients when 0-RTT is not attempted or is rejected, the maximum table capacity is 0 until the encoder processes a SETTINGS frame with a non-zero value of SETTINGS_QPACK_MAX_TABLE_CAPACITY. </del>  When the maximum table capacity is zero, the encoder MUST NOT insert entries into the dynamic table and MUST NOT send any encoder HPACK defines string literals to begin on a byte boundary.  They begin with a single bit flag, denoted as 'H' in this document <del> (indicating whether the string is Huffman-coded), followed by the </del>  Length encoded as a 7-bit prefix integer, and finally Length bytes of data.  When Huffman encoding is enabled, the Huffman table from Section B of RFC7541 is used without modification and Length only provide a limited amount of protection for the length of that content. <del> Padding schemes only provide limited protection against an </del>  attacker with these capabilities, potentially only forcing an increased number of guesses to learn the length associated with a given guess.  Padding schemes also work directly against merge compression contexts that the original encoder had specifically kept separate. <del> Simply removing entries corresponding to the field from the dynamic table can be ineffectual if the attacker has a reliable way of causing values to be reinstalled.  For example, a request to load an image in a web browser typically includes the Cookie header field (a potentially highly valued target for this sort of attack), and websites can easily force an image to be loaded, thereby refreshing the entry in the dynamic table. </del> 7.1.3. Implementations can also choose to protect sensitive fields by not

Addresses most of the open RFC Editor questions.
Need to update Buck's contact information to .
Fixed in .
This is a change in the RFC Editor diff that I don't think works; pulling out for separate discussion. Original: Proposed but incorrect: The intended reading is: For... HTTP/3 servers (always, regardless of 0-RTT) and HTTP/3 clients when 0-RTT is not attempted or is rejected URL maximum table capacity is 0.
Fixed in .
Should the following text be formatted using ? See the definition at . Original: Note: Padding schemes only provide limited protection against an attacker with these capabilities, potentially only forcing an increased number of guesses to learn the length associated with a given guess. Padding schemes also work directly against compression by increasing the number of bits that are transmitted. Original: Note: Simply removing entries corresponding to the field from the dynamic table can be ineffectual if the attacker has a reliable way of causing values to be reinstalled. For example, a request to load an image in a web browser typically includes the Cookie header field (a potentially highly valued target for this sort of attack), and websites can easily force an image to be loaded, thereby refreshing the entry in the dynamic table.
Probably yes.
Fixed in .
May we update "Huffman-coded" with "Huffman encoded" in this text to match other uses? Original: They begin with a single bit flag, denoted as 'H' in this document (indicating whether the string is Huffman-coded), followed by the Length encoded as a 7-bit prefix integer, and finally Length bytes of data.
Fixed in .

SETTINGS, the encoder must treat this as a connection error of type QPACK_DECODER_STREAM_ERROR.  <ins> For clients not using 0-RTT data (whether 0-RTT is not attempted or is rejected) and for all HTTP/3 servers, the maximum table capacity is 0 until the encoder processes a SETTINGS frame with a non-zero value of SETTINGS_QPACK_MAX_TABLE_CAPACITY. </ins> When the maximum table capacity is zero, the encoder MUST NOT insert entries into the dynamic table and MUST NOT send any encoder HPACK defines string literals to begin on a byte boundary.  They begin with a single bit flag, denoted as 'H' in this document  <ins> (indicating whether the string is Huffman encoded), followed by the </ins> Length encoded as a 7-bit prefix integer, and finally Length bytes of data.  When Huffman encoding is enabled, the Huffman table from Section B of RFC7541 is used without modification and Length only provide a limited amount of protection for the length of that content.  <ins> Note: Padding schemes only provide limited protection against an </ins> attacker with these capabilities, potentially only forcing an increased number of guesses to learn the length associated with a given guess.  Padding schemes also work directly against merge compression contexts that the original encoder had specifically kept separate.  7.1.3. Implementations can also choose to protect sensitive fields by not


section.  An encoder MUST emit field representations in the order they appear in the input field section. <del> QPACK is designed to contain the more complex state tracking to the encoder, while the decoder is relatively simple. </del>  2.1.1.

Inspired by NAME suggestion;
Is "to the encoder" intended? Should this be "within the encoder" or might "contain" be made "limit" or something else? Original: QPACK is designed to contain the more complex state tracking to the encoder, while the decoder is relatively simple.
"Limit" is probably the closest if we want to keep the phrase as-is. Writing something de novo might be better, but I'm having trouble coming up with anything pithy.
Some alternatives (aka throwing mud at the wall) "The design of QPACK requires an encoder to implement relatively more-complex state tracking than a decoder." "QPACK's design requires state tracking in various degrees of complexity. In relative terms, encoders have complex requirements, while decoders are more simple. "QPACK is designed to put the state tracking complexity onus on encoders, resulting in relatively simple decoders."
I like the third one.
Fixed in with a variant of the third option.
LGTM

section.  An encoder MUST emit field representations in the order they appear in the input field section.  <ins> QPACK is designed to place the burden of optional state tracking on the encoder, resulting in relatively simple decoders. </ins> 2.1.1.


A unique index for each entry in the dynamic table. <del> A reference point for relative and post-base indices. </del>  Representations that reference dynamic table entries are relative to a Base. HPACK defines string literals to begin on a byte boundary.  They begin with a single bit flag, denoted as 'H' in this document (indicating whether the string is Huffman encoded), followed by the <del> Length encoded as a 7-bit prefix integer, and finally Length bytes of data.  When Huffman encoding is enabled, the Huffman table from Section B of RFC7541 is used without modification and Length indicates the size of the string after encoding. </del>  This document expands the definition of string literals by permitting them to begin other than on a byte boundary.  An "N-bit prefix string literal" begins mid-byte, with the first (8-N) bits allocated to a previous field.  The string uses one bit for the Huffman flag, <del> followed by the Length encoded as a (N-1)-bit prefix integer.  The prefix size, N, can have a value between 2 and 8, inclusive.  The remainder of the string literal is unmodified. </del>  A string literal without a prefix length noted is an 8-bit prefix string literal and follows the definitions in RFC7541 without Each encoded field section is prefixed with two integers.  The Required Insert Count is encoded as an integer with an 8-bit prefix <del> using the encoding described in ric.  The Base is encoded as a sign </del>  bit ('S') and a Delta Base value with a 7-bit prefix; see base. 4.5.1.1. described in relative-indexing. To save space, the Base is encoded relative to the Required Insert <del> Count using a one-bit sign ('S') and the Delta Base value.  A sign bit of 0 indicates that the Base is greater than or equal to the value of the Required Insert Count; the decoder adds the value of Delta Base to the Required Insert Count to determine the value of the Base.  A sign bit of 1 indicates that the Base is less than the Required Insert Count; the decoder subtracts the value of Delta Base from the Required Insert Count and also subtracts one to determine the value of the Base.  That is: </del>  A single-pass encoder determines the Base before encoding a field section.  If the encoder inserted entries in the dynamic table while encoding the field section and is referencing them, Required Insert Count will be greater than the Base, so the encoded difference is <del> negative and the sign bit is set to 1.  If the field section was not </del>  encoded using representations that reference the most recent entry in the table and did not insert any new entries, the Base will be <del> greater than the Required Insert Count, so the delta will be positive and the sign bit is set to 0. </del>  The value of Base MUST NOT be negative.  Though the protocol might <del> operate correctly with a negative base using post-base indexing, it </del>  is unnecessary and inefficient.  An endpoint MUST treat a field block <del> with an S bit of 1 as invalid if the value of Required Insert Count </del>  is less than or equal to the value of Delta Base. An encoder that produces table updates before encoding a field section might set Base to the value of Required Insert Count.  In <del> such a case, both the sign bit and the Delta Base will be set to </del>  zero. A field section that was encoded without references to the dynamic table can use any value for the Base; setting Delta Base to zero is one of the most efficient encodings. <del> For example, with a Required Insert Count of 9, a decoder receives an S bit of 1 and a Delta Base of 2.  This sets the Base to 6 and enables post-base indexing for three entries.  In this example, a </del>  relative index of 1 refers to the fifth entry that was added to the <del> table; a post-base index of 1 refers to the eighth entry. </del>  4.5.2. 4.5.3. <del> An indexed field line with post-base index representation identifies </del>  an entry in the dynamic table with an absolute index greater than or equal to the value of the Base. This representation starts with the '0001' 4-bit pattern.  This is <del> followed by the post-base index (post-base) of the matching field </del>  line, represented as an integer with a 4-bit prefix; see prefixed- integers. 4.5.5. <del> A literal field line with post-base name reference representation </del>  encodes a field line where the field name matches the field name of a dynamic table entry with an absolute index greater than or equal to the value of the Base. This representation starts with the '0000' 4-bit pattern.  The fifth bit is the 'N' bit as described in literal-name-reference.  This is <del> followed by a post-base index of the dynamic table entry (post-base) </del>  encoded as an integer with a 3-bit prefix; see prefixed-integers. Only the field name is taken from the dynamic table entry; the field

While there are legitimate arguments for both capitalizing and not capitalizing Base, this is a smaller change and easier to be sure we got them all. That gets my vote at this point in the process. Each capitalization decision discussed in the issue is in a separate commit, in case we need to lift out and revisit one.
We had the following questions related to the terminology used in this document. a) Throughout the text, the following terminology appears to be used inconsistently. Please review these occurrences and let us know if/how they may be made consistent. base vs. Base post-base vs. Post Base length vs. Length delta vs. Delta Base b) We have updated the following terminology to use the form on the right consistently to match what we feel was the intended use. Please review and let us know any objections. Instruction / instruction (e.g., Insert Count Increment instructions) c) We see the use of both "single pass" and "one pass" in this document. Please review if these should be made uniform.
60 occurrences of "Base" vs. 31 occurrences of "base". Of those 31 lowercase instances, 22 of them are not part of the normal prose (e.g. pseudocode, section anchors, etc.) or aren't referring to this concept (e.g. "length-based", "based on"). Of the remaining nine, eight are occurrences of "post-base." Pretty clearly, our convention (deliberate or not) has been to capitalize this term. That doesn't mesh with the rest of the QUIC documents, where the convention has been to capitalize field names, not terminology. One could argue that Base is effectively a field, albeit one encoded on the wire as the sum/difference of two other values; of course, one could say the same of the QUIC packet number and we didn't capitalize that. The term "post-base" is uniformly not capitalized, except that "Post-Base" is used in the following two situations: When title-casing (probably correct) At the beginning of a sentence (probably incorrect) These two conventions don't align with each other. We should align on either "Base"/"post-Base" or "base"/"post-base".
"Length" is capitalized in several difference situations in the prose: In 4.1.2, defining string literals, "Length" is used interchangeably to refer to the length of the string and the field which contains that value. In field names ("Value Length", "Name Length") when representing the length-part of string literals In field diagrams, indicating the length of a field whose length was indicated by the previous field ("Length bytes") It seems to me that the first should be fixed while the second is fine. The third might benefit from a different means of indicating the size of the field, but it's not as obvious.
"delta" vs. "Delta Base" is used correctly, since "Delta Base" uniformly refers to the field. Lowercase "delta" is used in one instance to refer to the difference being encoded here; we could improve clarity by not using this term or by referring to the field.
I don't see any instances of (capitalized) "Instruction" in the document which aren't title-cased or the first word of a sentence. That's fine. The one instance of "One Pass" could be normalized to "Single Pass" without issue.
Fixed in .
Two small URL

A unique index for each entry in the dynamic table.  <ins> A reference point for relative and post-Base indices. </ins> Representations that reference dynamic table entries are relative to a Base. HPACK defines string literals to begin on a byte boundary.  They begin with a single bit flag, denoted as 'H' in this document (indicating whether the string is Huffman encoded), followed by the  <ins> string length encoded as a 7-bit prefix integer, and finally the indicated number of bytes of data.  When Huffman encoding is enabled, the Huffman table from Section B of RFC7541 is used without modification and the indicated length is the size of the string after encoding. </ins> This document expands the definition of string literals by permitting them to begin other than on a byte boundary.  An "N-bit prefix string literal" begins mid-byte, with the first (8-N) bits allocated to a previous field.  The string uses one bit for the Huffman flag,  <ins> followed by the length of the encoded string as a (N-1)-bit prefix integer.  The prefix size, N, can have a value between 2 and 8, inclusive.  The remainder of the string literal is unmodified. </ins> A string literal without a prefix length noted is an 8-bit prefix string literal and follows the definitions in RFC7541 without Each encoded field section is prefixed with two integers.  The Required Insert Count is encoded as an integer with an 8-bit prefix  <ins> using the encoding described in ric.  The Base is encoded as a Sign </ins> bit ('S') and a Delta Base value with a 7-bit prefix; see base. 4.5.1.1. described in relative-indexing. To save space, the Base is encoded relative to the Required Insert  <ins> Count using a one-bit Sign ('S' in fig-base-index) and the Delta Base value.  A Sign bit of 0 indicates that the Base is greater than or equal to the value of the Required Insert Count; the decoder adds the value of Delta Base to the Required Insert Count to determine the value of the Base.  A Sign bit of 1 indicates that the Base is less than the Required Insert Count; the decoder subtracts the value of Delta Base from the Required Insert Count and also subtracts one to determine the value of the Base.  That is: </ins> A single-pass encoder determines the Base before encoding a field section.  If the encoder inserted entries in the dynamic table while encoding the field section and is referencing them, Required Insert Count will be greater than the Base, so the encoded difference is  <ins> negative and the Sign bit is set to 1.  If the field section was not </ins> encoded using representations that reference the most recent entry in the table and did not insert any new entries, the Base will be  <ins> greater than the Required Insert Count, so the encoded difference will be positive and the Sign bit is set to 0. </ins> The value of Base MUST NOT be negative.  Though the protocol might  <ins> operate correctly with a negative Base using post-Base indexing, it </ins> is unnecessary and inefficient.  An endpoint MUST treat a field block  <ins> with a Sign bit of 1 as invalid if the value of Required Insert Count </ins> is less than or equal to the value of Delta Base. An encoder that produces table updates before encoding a field section might set Base to the value of Required Insert Count.  In  <ins> such a case, both the Sign bit and the Delta Base will be set to </ins> zero. A field section that was encoded without references to the dynamic table can use any value for the Base; setting Delta Base to zero is one of the most efficient encodings.  <ins> For example, with a Required Insert Count of 9, a decoder receives a Sign bit of 1 and a Delta Base of 2.  This sets the Base to 6 and enables post-Base indexing for three entries.  In this example, a </ins> relative index of 1 refers to the fifth entry that was added to the  <ins> table; a post-Base index of 1 refers to the eighth entry. </ins> 4.5.2. 4.5.3.  <ins> An indexed field line with post-Base index representation identifies </ins> an entry in the dynamic table with an absolute index greater than or equal to the value of the Base. This representation starts with the '0001' 4-bit pattern.  This is  <ins> followed by the post-Base index (post-base) of the matching field </ins> line, represented as an integer with a 4-bit prefix; see prefixed- integers. 4.5.5.  <ins> A literal field line with post-Base name reference representation </ins> encodes a field line where the field name matches the field name of a dynamic table entry with an absolute index greater than or equal to the value of the Base. This representation starts with the '0000' 4-bit pattern.  The fifth bit is the 'N' bit as described in literal-name-reference.  This is  <ins> followed by a post-Base index of the dynamic table entry (post-base) </ins> encoded as an integer with a 3-bit prefix; see prefixed-integers. Only the field name is taken from the dynamic table entry; the field


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 <del> to send the value 65536 in the max_datagram_frame_size transport </del>  parameter as that indicates to the peer that this endpoint will accept any DATAGRAM frame that fits inside a QUIC packet.

Current text says: This is nice, but I'm wondering if it should be 65535. The max UDP payload for a QUIC packet is 65527, which is lower than both. It's nice for an implementation to only need to store 16-bit integers for max datagram size to avoid excess memory, and it's of course easy to round down from 65536 to 65535, but it just seems arbitrary to have it be 1 more than the max value for a 16-bit integer...
NAME thoughts?
That sounds reasonable, 65535 is fine by me. (as long as the 1s don't take longer to travel than the 0s )

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  <ins> to send the value 65535 in the max_datagram_frame_size transport </ins> parameter as that indicates to the peer that this endpoint will accept any DATAGRAM frame that fits inside a QUIC packet.


QUIC uses a more nuanced loss recovery mechanism than the DTLS handshake, which has a basic packet loss retransmission timer. <del> This may allow loss recovery to occur more quickly for QUIC data. </del>  QUIC datagrams, while unreliable, can support acknowledgements, allowing applications to be aware of whether a datagram was Application protocols using datagrams are responsible for defining the semantics of the Datagram Data field, and how it is parsed.  If the application protocol supports the coexistence of multiple <del> entities using datagrams inside a single QUIC connection, it may need </del>  a mechanism to allow demultiplexing between them.  For example, using datagrams with HTTP/3 involves prepending a flow identifier to all datagrams, see I-D.schinazi-quic-h3-datagram. and do not contribute to any per-flow or connection-wide data limit. The risk associated with not providing flow control for DATAGRAM <del> frames is that a receiver may not be able to commit the necessary resources to process the frames.  For example, it may not be able to store the frame contents in memory.  However, since DATAGRAM frames are inherently unreliable, they MAY be dropped by the receiver if the receiver cannot process them. </del>  5.3. DATAGRAM frames employ the QUIC connection's congestion controller. <del> As a result, a connection may be unable to send a DATAGRAM frame </del>  generated by the application until the congestion controller allows it I-D.ietf-quic-recovery.  The sender implementation MUST either delay sending the frame until the controller allows it or drop

There are several instances of lowercase "may" in this document. It is ambiguous if these are normative requirements or not.
Could you elaborate on why it's ambiguous? We have a reference to RFC 8174.
I sometimes assume typos :) If you're happy the present document is correct, I will close this issue
I'm not aware of errors like this, do you have any specific ones in mind?
Gah, fat fingered accidental close. The example that triggered opening this issue is below, I had to read this several times. Perhaps that's just a sign that editorial tweaks would help, regardless of the exact words in use
I can fix this
Thanks!

QUIC uses a more nuanced loss recovery mechanism than the DTLS handshake, which has a basic packet loss retransmission timer.  <ins> This can allow loss recovery to occur more quickly for QUIC data. </ins> QUIC datagrams, while unreliable, can support acknowledgements, allowing applications to be aware of whether a datagram was Application protocols using datagrams are responsible for defining the semantics of the Datagram Data field, and how it is parsed.  If the application protocol supports the coexistence of multiple  <ins> entities using datagrams inside a single QUIC connection, it can use </ins> a mechanism to allow demultiplexing between them.  For example, using datagrams with HTTP/3 involves prepending a flow identifier to all datagrams, see I-D.schinazi-quic-h3-datagram. and do not contribute to any per-flow or connection-wide data limit. The risk associated with not providing flow control for DATAGRAM  <ins> frames is that a receiver might not be able to commit the necessary resources to process the frames.  For example, it might not be able to store the frame contents in memory.  However, since DATAGRAM frames are inherently unreliable, they MAY be dropped by the receiver if the receiver cannot process them. </ins> 5.3. DATAGRAM frames employ the QUIC connection's congestion controller.  <ins> As a result, a connection might be unable to send a DATAGRAM frame </ins> generated by the application until the congestion controller allows it I-D.ietf-quic-recovery.  The sender implementation MUST either delay sending the frame until the controller allows it or drop


it I-D.ietf-quic-recovery.  The sender implementation MUST either delay sending the frame until the controller allows it or drop the frame without sending it (at which point it MAY notify the <del> application). </del>  Implementations can optionally support allowing the application to specify a sending expiration time, beyond which a congestion-

Warn against the pathological case of dropping packets due to pacing.
Early in our VPN implementation, we sent QUIC datagrams without any queueing, assuming that if a datagram gets dropped, then we exceeded the cwnd (and thus the estimated channel capacity), so it would likely not reach the peer anyways. In practice, this turned out to be a terrible idea that lead to underutilization of the channel; our implementation always does pacing, so if you don't queue the datagram, it will get dropped unless it just happens to fit into the current pacing quantum. Because pacing is RECOMMENDED for QUIC, I believe some form of queueing should be RECOMMENDED for datagrams, otherwise the users risk running into the same hard-to-debug problem that we had.
I think adding a note about pacing to the "Congestion Control" subsection makes sense to me.
+1, if you're in the bucket of implementations that have insight into their pacing algorithm, it should be reasonable to expect that you'd avoid dropping your own datagrams unless you make a queue and then build up too much in that queue.
Thanks!

it I-D.ietf-quic-recovery.  The sender implementation MUST either delay sending the frame until the controller allows it or drop the frame without sending it (at which point it MAY notify the  <ins> application).  Implementations that use packet pacing SHOULD support delaying the transmission of DATAGRAM frames for at least the time it takes to send the paced packets allowed by the congestion controller to avoid dropping frames excessively. </ins> Implementations can optionally support allowing the application to specify a sending expiration time, beyond which a congestion-