Subject: Benjamin Kaduk's Discuss on draft-ietf-httpbis-http2bis-06: (with DISCUSS and COMMENT)

From: Benjamin Kaduk via Datatracker <[email-masked]>
Date: Wed, 05 Jan 2022 09:43:50 -0800

Benjamin Kaduk has entered the following ballot position for
draft-ietf-httpbis-http2bis-06: Discuss

When responding, please keep the subject line intact and reply to all
email addresses included in the To and CC lines. (Feel free to cut this
introductory paragraph, however.)

Please refer to https://www.ietf.org/blog/handling-iesg-ballot-positions/
for more information about how to handle DISCUSS and COMMENT positions.

The document, along with other ballot positions, can be found here:
https://datatracker.ietf.org/doc/draft-ietf-httpbis-http2bis/

----------------------------------------------------------------------
DISCUSS:
----------------------------------------------------------------------

I see that the list of "changes since RFC 7540" in Appendix B lists:

   *  The ranges of codepoints for settings and frame types that were
      reserved for "Experimental Use" are now available for general use.

But this doesn't seem to be reflected in either §11 (IANA Considerations)
or the live registry.
Should it be?  (Some backchannel discussion suggests that it's rather
this entry in the appendix is erroneous.)

----------------------------------------------------------------------
COMMENT:
----------------------------------------------------------------------

Thanks to Sean Turner for the secdir review, and the authors for preparing
PR #1001 in response.

Thanks as well for another high-quality and well-written document; it was a
pleasure to read.

I put most of my editorial suggestions in a PR on github:
https://github.com/httpwg/http2-spec/pull/1009

There are a number of places in the section-by-section comments where I
compare this document to the text in the quic-http spec; those comparisons
were made mostly in vacuum, and can safely be ignored if there are known
reasons for divergence between h/2 and h/3.

Section 4.1

I recall that quic-http has a note on the generic frame format that each
frame's payload must contain exactly the fields listed, with no additional
bytes and not terminating before the end of the listed fields, and that
redundant length-encodings must be verified for consistency.  While I don't
actually see any redundant length encodings in the frame types specified in
this document (but maybe there is some redundancy when HPACK is added into
the mix?), the other cautions from h/3 might be worth mentioning here as
well.

Section 4.3

   Field blocks carry the compressed bytes of a field section, with
   header sections also carrying control data associated with the
   message in the form of pseudo-header fields (Section 8.3) that use
   the same format as a field line.

The procedures described in the rest of the section give me the impression
that there is a 1:1 relationship between field section and field block, but
this text only gives me a clear impression that each field block corresponds
to a single field section, not the reverse.  Should we try to clarify that
it's definitely a 1:1 relationship (assuming it actually is, of course)?
Perhaps something like "a field block carries the compressed bytes of a
field section, with header sections also [...]".

Section 5.1

   half-closed (local):  A stream that is in the "half-closed (local)"
      [...]
      An endpoint can receive any type of frame in this state.
      [...]
      PRIORITY frames can be received in this state.

I'm not sure whether this redundancy is adding much.  In RFC 7540 the last
sentence was followed by a note about "used to reprioritize streams that
depend on the identified stream", but since PRIORITY is basically neutered
now it may not need a special mention.

   closed:  The "closed" state is the terminal state.
   [...]
      An endpoint that sends a frame with the END_STREAM flag set or a
      RST_STREAM frame might receive a WINDOW_UPDATE or RST_STREAM frame
      from its peer in the time before the peer receives and processes
      the frame that closes the stream.

Could such a client also receive PUSH_PROMISE frames in this situation?
The following paragraph (about the "open"->"closed" via sending RST_STREAM
transition) does mention receiving any frame (and PUSH_PROMISE specifically)
and the need to update compression state, but if I understand correctly
PUSH_PROMISE can happen after a "half-closed (local)"->"closed" transition
due to sending RST_STREAM as well, which does not seem covered by the
existing text.

Looking at the diff from RFC 7540, I see that this state's description was
substantially rewritten; in 7540 there was a dedicated paragraph about
PUSH_PROMISE that went on to note that RST_STREAM would be needed to close
an unwanted promised stream; I don't know if that is worth bringing back or
not.

Another item that comes up looking at the diff is receipt of DATA after
RST_STREAM.  That makes me wonder if the text I mentioned earlier, about
sending RST_STREAM specifically on a stream in the "open" state, is too
narrowly specified.  If that paragraph is not limited to the situation where
"closed" is entered by sending RST_STREAM from "open", then it looks like
most of what I'm worried about here would not be problematic anymore.  That
change might cause other issues, though.

Section 5.1.2

   An endpoint that wishes to reduce the value of
   SETTINGS_MAX_CONCURRENT_STREAMS to a value that is below the current
   number of open streams can either close streams that exceed the new
   value or allow streams to complete.

Is there a race condition here between the peer continuously creating new
connections and the endpoint closing connections to try to lower the value?
In particular, what happens if the SETTINGS that reduces the value crosses
on the wire with the frame creating a stream that would exceed the value?

Section 5.5

   An extension that changes existing elements MUST be negotiated before
   being used.  For example, an extension that changes the layout of the
   HEADERS frame cannot be used until the peer has given a positive
   signal that this is acceptable.  In this case, it could also be
   necessary to coordinate when the revised layout comes into effect.
   For example, treating frames other than DATA frames as flow
   controlled requires a change in semantics that both endpoints need to
   understand, so this can only be done through negotiation.

Do we want to call out use of frame types that alter (existing elements of)
connection state as another thing that needs negotiation before use?

Section 6.9.2

   The connection flow-control window is also 65,535 octets.  Both
   endpoints can adjust the initial window size for new streams by
   including a value for SETTINGS_INITIAL_WINDOW_SIZE in the SETTINGS
   frame that forms part of the connection preface.  [...]

This phrasing suggests that SETTINGS_INITIAL_WINDOW_SIZE can be sent only in
the connection preface, but the rest of the section does not seem consistent
with such a limitation.  Is it better to just end the sentence with "in a
SETTINGS frame"?

Section 8.4.1

   The header fields in PUSH_PROMISE and any subsequent CONTINUATION
   frames MUST be a valid and complete set of request header fields
   (Section 8.3.1).  The server MUST include a method in the :method
   pseudo-header field that is safe and cacheable.  If a client receives
   a PUSH_PROMISE that does not include a complete and valid set of
   header fields or the :method pseudo-header field identifies a method
   that is not safe, it MUST respond with a stream error (Section 5.4.2)
   of type PROTOCOL_ERROR.

Up in §8.4 we seemed to talk about the same (non-safe) scenario by saying
that the promised stream being reset with the PROTOCOL_ERROR.  But I read
this text ("respond with a stream error") as applying to the explicit
request to which the promised request is associated.  Is that the intent?
If not, perhaps we should say "respond on the promised stream ID".

Section 8.4.2

   Clients receiving a pushed response MUST validate that either the
   server is authoritative (see Section 10.1) or the proxy that provided
   the pushed response is configured for the corresponding request.  For
   example, a server that offers a certificate for only the example.com
   DNS-ID is not permitted to push a response for
   https://www.example.org/doc.

Should we reference RFC 6125 (or its bis) for "DNS-ID"?

Section 9.1

   Clients SHOULD NOT open more than one HTTP/2 connection to a given
   host and port pair, where the host is derived from a URI, a selected
   alternative service [ALT-SVC], or a configured proxy.

quic-http has similar text (in §3.3), but it refers to a given IP address
and port, rather than host and port.  Is the difference between host and IP
address significant when comparing h/2 and h/3?  (When using IP addresses,
we of course have to additionally talk about name resolution of the other
types of identifier.)

   A client MAY open multiple connections to the same IP address and TCP
   port using different Server Name Indication [TLS-EXT] values or to
   provide different TLS client certificates but SHOULD avoid creating
   multiple connections with the same configuration.

Similarly, comparing against the analogous h/3 text, h/3 talks about
"transport or TLS configurations" rather than SNI values or TLS client
certificates.  Do we want to follow h/3's lead on phrasing?

Section 9.2.2

   have non-intersecting sets of permitted cipher suites.  To avoid this
   problem causing TLS handshake failures, deployments of HTTP/2 that
   use TLS 1.2 MUST support TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
   [TLS-ECDHE] with the P-256 elliptic curve [FIPS186].

I think that RFC 8422 would be a fine reference for the use of the P-256
curve for TLS ECDHE.  In particular, FIPS186-4 only covers ECDSA, not ECDHE,
and for ECDSA it largely defers to the costs-money X9.62 standard, which
gives some reason to prefer more open references.

Section 10.5.2

   The CONNECT method can be used to create disproportionate load on a
   proxy, since stream creation is relatively inexpensive when compared
   to the creation and maintenance of a TCP connection.  A proxy might
   also maintain some resources for a TCP connection beyond the closing
   of the stream that carries the CONNECT request, since the outgoing
   TCP connection remains in the TIME_WAIT state.  Therefore, a proxy
   cannot rely on SETTINGS_MAX_CONCURRENT_STREAMS alone to limit the
   resources consumed by CONNECT requests.

Looking at the diff from this text to §10.5.2 of quic-http, I see the latter
has a new sentence about "a proxy that supports CONNECT might be more
conservative in the number of simultaneous requests it accepts", and also
has some different phrasing in the last sentences about "might delay
increasing the stream limit after a TCP connection terminates" vs "cannot
rely on SETTINGS_MAX_CONCURRENT_STREAMS alone".  I think that the overall
issues in this space remain pretty analogous between h/3 and h/2, so we
might want to pull in more of the updated h/3 text here.

Separately, do we want to mention [TALKING] again here and the issues it
raises?

Section 11.1

   This section marks the HTTP2-Settings header field registered by
   Section 11.5 of [RFC7540] in the Hypertext Transfer Protocol (HTTP)
   Field Name Registry as obsolete.  This capability has been removed:
   see Section 3.1.  [...]

I don't really see anything in §3.1 that speaks to HTTP2-Settings as being
obsolete.  "Settings" overall are mentioned under §3 only in §3.4, but only
in the context of the SETTINGS frame.

Is this perhaps something that should be mentioned in Appendix B (changes
from RFC 7540), and the reference changed to point to that?

Section 12.2

The link for [TALKING] doesn't resolve for me.
I guess it's probably the same content as
https://ptolemy.berkeley.edu/projects/truststc/pubs/840/websocket.pdf and
https://www.adambarth.com/papers/2011/huang-chen-barth-rescorla-jackson.pdf
though.

Appendix B

As part of resolving errata report 4666, we removed text from this
specification about the HTTP 421 status code, in particular, text saying
that it was cachable by default.  Is that change worth noting here?

EDITORIAL

Section 10.5

   *  An attacker can provide large amounts of flow control credit at
      the HTTP/2 layer, but withhold credit at the TCP layer, preventing
      frames from being sent.  An endpoint that constructs and remembers
      frames for sending without considering TCP limits might be subject
      to resource exhaustion.

This risk seems interrelated with the first one, about "insufficient
tracking of outstanding outbound frames"; is there a reason for the current
ordering of this list, or might we reorder to keep these related topics
together?

---

From: "Martin Thomson" <[email-masked]>
Date: Fri, 07 Jan 2022 15:13:46 +1100

For your comments, I have a few responses inline.  I've deleted those that I more or less directly accepted.  There were some good ones there, but I see no need to add to the size of this email.  See the pull request for details:

https://github.com/httpwg/http2-spec/pull/1012

>       reserved for "Experimental Use" are now available for general use.

Good catch.  That was lost in a refactoring of the IANA Considerations section.  That was in error.

https://github.com/httpwg/http2-spec/pull/1011

> the mix?), the other cautions from h/3 might be worth mentioning here as

HTTP/2 has no redundant lengths other than the length field itself which is often redundant.  We have adequate text but it is on a per-frame basis.

HTTP/3 is allowed to be better here.   I think we're OK without a change.

> now it may not need a special mention.

I would prefer to keep this as it is a common error.  It's easy to forget to allow this, especially now that PRIORITY is deprecated.

> due to sending RST_STREAM as well, which does not seem covered by the

The next paragraph covers that case, but neglected to mention "half-closed (local)" in that, which it should have.  I think that covers your other points about this.

> on the wire with the frame creating a stream that would exceed the value?

The new limit only applies after the peer acknowledges the change, so as long as they are within the limit that is currently acknowledged, they are not in violation of the protocol.  This is really talking about what to do about those that are nominally within the limit, but in excess of what the endpoint really wants.

> If not, perhaps we should say "respond on the promised stream ID".

Good question.  The error exists with the promise, not the request, so I think the latter.

> we of course have to additionally talk about name resolution of the other

I honestly don't know.  I think perhaps host is better in this case in the sense that clients aim to connect to hosts and connection coalescing is not a requirement, just permitted (as noted in the text that follows).  I'm not sure that it really matters ultimately, but it's worth checking.

Perhaps Mike Bishop can help us here.

> might want to pull in more of the updated h/3 text here.

The mitigations available in QUIC are not viable for HTTP/2, so I think we're OK with that difference.  (Again HTTP/3 is allowed to be better.)

> Separately, do we want to mention [TALKING] again here and the issues it

I don't think that those are specific to CONNECT or uniquely worse with CONNECT.

---

From: Benjamin Kaduk <[email-masked]>
Date: Fri, 7 Jan 2022 18:35:47 -0800

> For your comments, I have a few responses inline.  I've deleted those that I more or less directly accepted.  There were some good ones there, but I see no need to add to the size of this email.  S…

Understandable, and thanks.

I will also trim the bits about HTTP/2 vs HTTP/3; the common them of
"HTTP/3 is allowed to (and expected to!) be better than HTTP/2" is
well-taken, and "no change" seems reasonable as indicated.  Hopefully we
can hear from Mike where his input was requested.

> https://github.com/httpwg/http2-spec/pull/1011

Looks like an easy fix; excellent.

> I would prefer to keep this as it is a common error.  It's easy to forget to allow this, especially now that PRIORITY is deprecated.

Ok, that's a fine reason to have a special mention.

> The next paragraph covers that case, but neglected to mention "half-closed (local)" in that, which it should have.  I think that covers your other points about this.

I suspect you are right about that; the "half-closed (local)" state is very
similar to the "open" state in terms of what we would expect to receive.

The only part of my comment that this might not resolve is:

% in 7540 there was a dedicated paragraph about PUSH_PROMISE that went on
% to note that RST_STREAM would be needed to close an unwanted promised
% stream; I don't know if that is worth bringing back or not.

I would be willing to believe that we talk about this topic elsewhere and
it doesn't need to be covered here, though.

> The new limit only applies after the peer acknowledges the change, so as long as they are within the limit that is currently acknowledged, they are not in violation of the protocol.  This is really…

Okay, thanks for the explanation (and reminder that the acknowledgment is
needed before it takes effect).

> Good question.  The error exists with the promise, not the request, so I think the latter.

That was my thought as well, but I wasn't confident enough to just put it
in my PR and claim it to be "editorial" :)

Thanks again,

Ben

---

From: Mike Bishop <[email-masked]>
Date: Sun, 9 Jan 2022 06:44:13 +0000

I don't think I was mentioned three times, but I shall consider myself summoned nonetheless.

The H3 text is:

Clients SHOULD NOT open more than one HTTP/3 connection to a given IP address and UDP port, where the IP address and port might be derived from a URI, a selected alternative service ([ALTSVC]), a configured proxy, or name resolution of any of these. A client MAY open multiple HTTP/3 connections to the same IP address and UDP port using different transport or TLS configurations but SHOULD avoid creating multiple connections with the same configuration.

The HTTP/3 text does allow for differences of TLS configurations, which would encompass different certificates and/or SNI values, so I don’t think there’s necessarily a conflict here.

The H3 text was written in contemplation of Alt-Svc being the primary means of finding the endpoint and the Alt-Svc entries potentially covering a different set of hosts than the endpoint has certificates for.  By keying on IP address, it means that two Alt-Svc advertisements pointing to different hostnames which resolve to the same IP address would still enable connection reuse if the certificate covers both origins, while the HTTP/2 text would advise separate connections to that IP address for the two origins.

I think we could leave the text as-is in both documents and be fine.  I think we could normalize the documents to either version and be fine.  I tend to prefer more coalescing than less, FWIW.

-----Original Message-----
From: Martin Thomson <[email-masked]>
Sent: Friday, January 7, 2022 9:44 AM
To: Benjamin Kaduk <[email-masked]>; The IESG <[email-masked]>
Cc: [email-masked]; [email-masked]; [email-masked]; Mark Nottingham <[email-masked]>
Subject: Re: Benjamin Kaduk's Discuss on draft-ietf-httpbis-http2bis-06: (with DISCUSS and COMMENT)

> quic-http has similar text (in §3.3), but it refers to a given IP

> address and port, rather than host and port.  Is the difference

> between host and IP address significant when comparing h/2 and h/3?

> (When using IP addresses, we of course have to additionally talk about

> name resolution of the other types of identifier.)