Subject: [quicwg/base-drafts] Define terms for application actions (#2857)

From: Mike Bishop <[email-masked]>
Date: Thu, 27 Jun 2019 16:14:15 -0700

This consists of two related commits:

- Defines the minimal set of operations which a QUIC implementation MUST expose to the application, introducing terms for them which don't rely on the specific wire formatting
- Changes HTTP/3 to use these terms instead of referring to specific QUIC frames

Note that this doesn't remove all references to QUIC frames, but the remaining references are explanatory -- they describe what will happen at the transport layer after taking a particular action, rather than being part of the normative text.  (But if you find one of these you think needs to go, please include that in this review.)

This is a design, because exposing this functionality is mandatory.  I'm not sure how you would previously have created a usable QUIC implementation without these operations, but you weren't previously required to have them all.

Fixes #2805, closes #2677.
You can view, comment on, or merge this pull request online at:

  https://github.com/quicwg/base-drafts/pull/2857

-- Commit Summary --

  * Required operations in Transport
  * HTTP rewords for newly-defined terms

-- File Changes --

    M draft-ietf-quic-http.md (105)
    M draft-ietf-quic-transport.md (52)

-- Patch Links --

https://github.com/quicwg/base-drafts/pull/2857.patch
https://github.com/quicwg/base-drafts/pull/2857.diff

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857

---

From: Mike Bishop <[email-masked]>
Date: Thu, 27 Jun 2019 16:15:35 -0700

@MikeBishop pushed 1 commit.

b4213afb9114f8d091433268878af33fcefcbb84  Verb tense

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857/files/337cb98ff728595527331ec085b1e3f2ba1d7be6..b4213afb9114f8d091433268878af33fcefcbb84

---

From: Mike Bishop <[email-masked]>
Date: Thu, 27 Jun 2019 16:18:56 -0700

6d4376f257923b10f7989b8f41ee07f24741030d  Correct top-level section

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857/files/b4213afb9114f8d091433268878af33fcefcbb84..6d4376f257923b10f7989b8f41ee07f24741030d

---

From: Mike Bishop <[email-masked]>
Date: Thu, 27 Jun 2019 16:33:23 -0700

34da6ec94b62f88ad923c3e357d17dd9202cd34c  Fix bulleted lists

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857/files/88d091a0444f3bdc863e76b82aa37a912b6b42ac..34da6ec94b62f88ad923c3e357d17dd9202cd34c

---

From: Martin Thomson <[email-masked]>
Date: Thu, 27 Jun 2019 17:31:35 -0700

martinthomson commented on this pull request.

Thanks for doing this Mike, I have quite a few comments.

> @@ -452,12 +452,12 @@ HTTP_INCOMPLETE_REQUEST.
 
 A server can send a complete response prior to the client sending an entire
 request if the response does not depend on any portion of the request that has
-not been sent and received. When this is true, a server MAY request that the
-client abort transmission of a request without error by triggering a QUIC
-STOP_SENDING frame with error code HTTP_EARLY_RESPONSE, sending a complete
-response, and cleanly closing its stream. Clients MUST NOT discard complete
-responses as a result of having their request terminated abruptly, though
-clients can always discard responses at their discretion for other reasons.
+not been sent and received. When this is true, a server MAY abort reading the
+receiving part of the request stream with error code HTTP_EARLY_RESPONSE, send a

Do you think that we can just say "abort reading the request stream" and drop the  "receiving part of" piece on the basis that "abort reading" can only apply to the receiving part?

> @@ -505,11 +505,11 @@ this limit are not guaranteed to be accepted.
 
 ### Request Cancellation and Rejection {#request-cancellation}
 
-Clients can cancel requests by aborting the stream (QUIC RESET_STREAM and/or
-STOP_SENDING frames, as appropriate) with an error code of
-HTTP_REQUEST_CANCELLED ({{http-error-codes}}).  When the client cancels a
-response, it indicates that this response is no longer of interest.
-Implementations SHOULD cancel requests by aborting both directions of a stream.
+Clients can cancel requests by abruptly terminating the sending part of the

"abruptly terminating" or just "resetting" ?

> @@ -1590,8 +1584,9 @@ the cause of a connection or stream error.
 
 ## HTTP/3 Error Codes {#http-error-codes}
 
-The following error codes are defined for use in QUIC RESET_STREAM frames,
-STOP_SENDING frames, and CONNECTION_CLOSE frames when using HTTP/3.
+The following error codes are defined for use when abruptly terminating the
+sending part of streams, aborting reading of the receiving part of streams, or

As above regarding reference to "parts".

> @@ -1718,8 +1713,8 @@ extension is disabled if the setting is omitted.
 The security considerations of HTTP/3 should be comparable to those of HTTP/2
 with TLS.  Note that where HTTP/2 employs PADDING frames and Padding fields in
 other frames to make a connection more resistant to traffic analysis, HTTP/3 can
-rely on QUIC PADDING frames or employ the reserved frame and stream types
-discussed in {{frame-grease}} and {{stream-grease}}.
+either rely on transport-layer padding or employ the reserved frame and stream
+types discussed in {{frame-grease}} and {{stream-grease}}.

Aside: we should probably have a conversation about the trade-offs with padding.  Transport-layer padding is in some ways superior, like in how it can be granular to a single byte, which reserved streams and frames cannot do.  But PADDING frames at the transport aren't retransmitted when lost, which could lead to some interesting attacks if packets can be suppressed by an attacker.  If retransmissions aren't padded, boom.

> @@ -345,6 +345,31 @@ the relative priority of streams.  When deciding which streams to dedicate
 resources to, the implementation SHOULD use the information provided by the
 application.
 
+## Required Operations on Streams
+
+There are certain operations which an application MUST be able to perform when
+interacting with QUIC streams.  This document does not specify an API, but
+any implementation of this version of QUIC MUST expose the ability to perform
+the operations described in this section on a QUIC stream.
+
+On the sending part of a stream:
+
+- Attempt to write data, understanding when stream flow control credit

List construction here implies continuation of a sentence, but the capital letter doesn't fit and there is no joiner.

I think that you want:

> On the sending part of a stream, application protocols need to be able to:
> * write data, understanding when .... ({{frame-stop-sending}});
> * end the stream, ....; and
> * reset the stream ... was already ended.

> @@ -345,6 +345,31 @@ the relative priority of streams.  When deciding which streams to dedicate
 resources to, the implementation SHOULD use the information provided by the
 application.
 
+## Required Operations on Streams
+
+There are certain operations which an application MUST be able to perform when
+interacting with QUIC streams.  This document does not specify an API, but
+any implementation of this version of QUIC MUST expose the ability to perform
+the operations described in this section on a QUIC stream.
+
+On the sending part of a stream:
+
+- Attempt to write data, understanding when stream flow control credit
+  ({{data-flow-control}}) has successfully been reserved to send the written
+  data or possibly discovering that the stream has been closed because the peer

I think that you might remove this "possibly discovering" clause.  Then add a new separate paragraph after the lists that says that application protocols will want to be informed about stream state changes and events, including when data is available, when the stream ends, is reset, or reading has been aborted by a peer, and when new streams are created by a peer.

As a general rule, I don't like having sections end on a list, so that would help with my little compulsion too.

> @@ -1101,6 +1126,38 @@ suggested structure:
 -->

+## Required Operations on Connections
+
+There are certain operations which an application MUST be able to perform when
+interacting with the QUIC transport.  This document does not specify an API, but
+any implementation of this version of QUIC MUST expose the ability to perform
+the operations described in this section on a QUIC connection.
+
+When implementing the client role:

Same list construction comment as above.

> @@ -1101,6 +1126,38 @@ suggested structure:
 -->

+## Required Operations on Connections
+
+There are certain operations which an application MUST be able to perform when
+interacting with the QUIC transport.  This document does not specify an API, but
+any implementation of this version of QUIC MUST expose the ability to perform
+the operations described in this section on a QUIC connection.
+
+When implementing the client role:
+
+- Open a connection, which begins the exchange described in {{handshake}}

Add: to enable 0-RTT, and to be informed when 0-RTT has been either accepted or rejected by a server.

> +interacting with the QUIC transport.  This document does not specify an API, but
+any implementation of this version of QUIC MUST expose the ability to perform
+the operations described in this section on a QUIC connection.
+
+When implementing the client role:
+
+- Open a connection, which begins the exchange described in {{handshake}}
+
+When implementing the server role:
+
+- Listen for incoming connections, which prepares for the exchange described in
+  {{handshake}}
+- If Early Data is supported, embed application-controlled data in the TLS
+  resumption ticket sent to the client
+- If Early Data is supported, retrieve application-controlled data from the
+  client's resumption ticket and approve/veto accepting Early Data

and enable rejection of 0-RTT based on that information

I don't like "veto" much here.  And we don't need to have an active acceptance involved.

> +
+- Open a connection, which begins the exchange described in {{handshake}}
+
+When implementing the server role:
+
+- Listen for incoming connections, which prepares for the exchange described in
+  {{handshake}}
+- If Early Data is supported, embed application-controlled data in the TLS
+  resumption ticket sent to the client
+- If Early Data is supported, retrieve application-controlled data from the
+  client's resumption ticket and approve/veto accepting Early Data
+
+In either role:
+
+- Configure minimum values for the initial number of permitted streams of each
+  type, as communicated in the transport parameters ({{transport-parameters}})

I think that there is a more general point, which basically means controlling resource allocation of all types, including streams and flow control.

The point you are looking at here - setting a minimum on the number of streams - is something HTTP needs, so I would add rather than replace.

> +
+- Listen for incoming connections, which prepares for the exchange described in
+  {{handshake}}
+- If Early Data is supported, embed application-controlled data in the TLS
+  resumption ticket sent to the client
+- If Early Data is supported, retrieve application-controlled data from the
+  client's resumption ticket and approve/veto accepting Early Data
+
+In either role:
+
+- Configure minimum values for the initial number of permitted streams of each
+  type, as communicated in the transport parameters ({{transport-parameters}})
+- Keep a connection from silently closing, either by generating PING frames
+  ({{frame-ping}}) or by requesting that the transport send additional frames
+  before the idle timeout expires ({{idle-timeout}})
+- Cease issuing credit for new streams via MAX_STREAMS frames

See the above point about controlling resource allocation.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857#pullrequestreview-255536084

---

From: MikkelFJ <[email-masked]>
Date: Thu, 27 Jun 2019 21:52:48 -0700

mikkelfj commented on this pull request.

+  ({{data-flow-control}}) has successfully been reserved to send the written
+  data or possibly discovering that the stream has been closed because the peer
+  sent a STOP_SENDING frame ({{frame-stop-sending}})
+- Cleanly terminate the stream, resulting in a STREAM frame ({{frame-stream}})
+  with the FIN bit set
+- Abruptly terminate the stream, resulting in a RESET_STREAM frame
+  ({{frame-reset-stream}}), even if the stream was cleanly terminated previously
+
+On the receiving part of a stream:
+
+- Attempt to read data, possibly discovering that the peer has terminated the
+  stream either cleanly or abruptly
+- Abort reading of the stream and request closure, resulting in a STOP_SENDING
+  frame ({{frame-stop-sending}})
+

This could be read as if aborting a stream should always result in a STOP_SENDING frame, but I don't think that that is necessarily true. I understand that the ability to do so is important though.

Cease and resume

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857#pullrequestreview-255583202

---

From: Mike Bishop <[email-masked]>
Date: Fri, 28 Jun 2019 08:21:17 -0700

MikeBishop commented on this pull request.

The only place where this is required by HTTP is to support GOAWAY; I'd argue that the ability to stop is required, and the ability to resume is something an implementation could choose to expose.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857#discussion_r298640014

---

From: Mike Bishop <[email-masked]>
Date: Fri, 28 Jun 2019 08:22:44 -0700

It's always true if the recipient hasn't already received through the end of the stream.  But yes, I'll try to expand on it.  It might be worth reframing some things in the transport doc to work in terms of acting on these requests from the application.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857#discussion_r298640589

---

From: Mike Bishop <[email-masked]>
Date: Fri, 28 Jun 2019 11:05:02 -0700

7656c7307df79f43eeffc9e23a0eeff7ac0de9f8  Review feedback

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857/files/34da6ec94b62f88ad923c3e357d17dd9202cd34c..7656c7307df79f43eeffc9e23a0eeff7ac0de9f8

---

From: Mike Bishop <[email-masked]>
Date: Fri, 28 Jun 2019 11:14:41 -0700

36ad00639195c13c7035cea167af5d84bdccdd35  Introduce STOP_SENDING description with 'abort reading'

-- 
You are receiving this because you are subscribed to this thread.
View it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857/files/7656c7307df79f43eeffc9e23a0eeff7ac0de9f8..36ad00639195c13c7035cea167af5d84bdccdd35

---

From: Lucas Pardue <[email-masked]>
Date: Sat, 29 Jun 2019 06:47:40 -0700

LPardue commented on this pull request.

> @@ -962,18 +960,16 @@ see {{extensions}} for more details.
 
 The performance of HTTP/3 connections in the early phase of their lifetime is
 sensitive to the creation and exchange of data on unidirectional streams.
-Endpoints that set low values for the QUIC transport parameters
-`initial_max_uni_streams` and `initial_max_stream_data_uni` will increase the
-chance that the remote peer reaches the limit early and becomes blocked. In
-particular, the value chosen for `initial_max_uni_streams` should consider that
-remote peers may wish to exercise reserved stream behavior ({{stream-grease}}).
-To avoid blocking, 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 (such as QPACK) by
-setting an appropriate value for the QUIC transport parameter
-`initial_max_uni_streams` (three being the minimum value required for the base
-HTTP/3 protocol and QPACK), and SHOULD use a value of 1,024 or greater for the
-QUIC transport parameter `initial_max_stream_data_uni`.
+Endpoints that excessively restrict the number or flow control window of these

This reads weird to me, my brain keeps thinking "or" is a typo for "of", which is untrue. I think it could read better to say

"Endpoints that excessively restrict the number of these streams or the size of each stream's flow control window will increase the chance that the remote peer reaches the limit early and becomes blocked." 

> -least one unidirectional stream for the HTTP control stream plus the number of
-unidirectional streams required by mandatory extensions (such as QPACK) by
-setting an appropriate value for the QUIC transport parameter
-`initial_max_uni_streams` (three being the minimum value required for the base
-HTTP/3 protocol and QPACK), and SHOULD use a value of 1,024 or greater for the
-QUIC transport parameter `initial_max_stream_data_uni`.
+Endpoints that excessively restrict the number or flow control window of these
+streams will increase the chance that the remote peer reaches the limit early
+and 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 use. To avoid blocking,
+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.

observation: the change to remove references to Transport Parameters in this paragraph could lead to some interesting unintended issues. Previously it was clear that the problems mentioned were related to small values of initial limits (imposed by TPs). One way to interpet the new text is that it is ok to advertise low values in TPs as long as you send MAX_STREAMS or MAX_STREAM_DATA.

Just wondering if that was the intent of this change, given some of the problems we've seen with these values during interop.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/pull/2857#pullrequestreview-256037561