From 672d62df11b53a202dc1020c4bf18f1b6d0adafe Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 25 Apr 2023 19:06:42 -0400 Subject: [PATCH 01/27] Add writer.atomicWrite() method. --- index.bs | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 533461d5..53f044f9 100644 --- a/index.bs +++ b/index.bs @@ -69,6 +69,8 @@ spec:fetch; type:dfn; for:/; text:fetch spec:url; type:dfn; text:scheme spec:url; type:dfn; text:fragment spec:infra; type:dfn; for:/; text:ASCII case-insensitive +spec:infra; type:dfn; text:list +spec:streams; type:dict-member; text:write
 url: https://html.spec.whatwg.org/multipage/origin.html#concept-origin; type: dfn; text: origin; for:/
@@ -1426,6 +1428,7 @@ data to the server.
 interface WebTransportSendStream : WritableStream {
   attribute long long? sendOrder;
   Promise<WebTransportSendStreamStats> getStats();
+  WebTransportWriter getWriter();
 };
 
@@ -1461,6 +1464,12 @@ The {{WebTransportSendStream}}'s [=transfer steps=] and 1. [=Resolve=] |p| with |stats|. 1. Return |p|. +: getWriter() +:: This method must be implemented the same as {{WritableStream/getWriter}} + inherited from {{WritableStream}}, except in place of creating a + {{WritableStreamDefaultWriter}}, it must instead + [=WebTransportWriter/create=] a {{WebTransportWriter}} with [=this=]. + ## Internal Slots ## {#send-stream-internal-slots} A {{WebTransportSendStream}} has the following internal slots. @@ -1490,6 +1499,11 @@ A {{WebTransportSendStream}} has the following internal slots. `[[SendOrder]]` An optional send order number, or null. + + `[[AtomicWriteRequests]]` + A [=list=] of promises, each representing an in-flight atomic + write request to be processed by the underlying sink. + @@ -1510,6 +1524,8 @@ To create a :: |transport| : {{WebTransportSendStream/[[SendOrder]]}} :: |sendOrder| + : {{WebTransportSendStream/[[AtomicWriteRequests]]}} + :: An empty [=list=] of promises. 1. Let |writeAlgorithm| be an action that [=writes=] |chunk| to |stream|, given |chunk|. 1. Let |closeAlgorithm| be an action that [=closes=] |stream|. 1. Let |abortAlgorithm| be an action that [=aborts=] |stream| with |reason|, given |reason|. @@ -1537,6 +1553,14 @@ To write |chunk| to a {{WebTransportSend 1. Let |promise| be a new promise. 1. Let |bytes| be a copy of the [=byte sequence=] which |chunk| represents. 1. Set |stream|.{{[[PendingOperation]]}} to |promise|. +1. Let |inFlightWriteRequest| be + |stream|.inFlightWriteRequest. + + Note: Find a [better way](https://streams.spec.whatwg.org/#other-specs) to integrate + with the streams spec to identify the write request in flight. + +1. Let |atomic| be true if |inFlightWriteRequest| [=list/exists=] + in [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}, otherwise false. 1. Run the following steps [=in parallel=]: 1. [=stream/Send=] |bytes| on |stream|.{{WebTransportSendStream/[[InternalStream]]}} and wait for the operation to complete. @@ -1552,6 +1576,12 @@ To write |chunk| to a {{WebTransportSend [=WritableStream/Error | errored=] nor blocked by [=flow control=], have been sent. + Whenever the sending of |bytes| becomes blocked by [=flow control=], + [=queue a network task=] with |transport| to [=abort all atomic write requests=] on |stream|. + + If the sending of |bytes| becomes blocked by [=flow control=] and |atomic| is true, + then give up on sending |bytes| and proceed immediately to the next step without failing. + The user agent SHOULD divide bandwidth fairly between all streams that aren't starved. Note: The definition of fairness here is [=implementation-defined=]. @@ -1567,13 +1597,15 @@ To write |chunk| to a {{WebTransportSend 1. [=Queue a network task=] with |transport| to run these steps: 1. Set |stream|.{{[[PendingOperation]]}} to null. + 1. If |atomic| is true, [=map/remove=] |inFlightWriteRequest| from + |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}}. 1. [=Resolve=] |promise| with undefined. 1. Return |promise|. Note: The user-agent MAY have a buffer to improve the transfer performance. Such a buffer SHOULD have a fixed upper limit, to carry the backpressure information to the user of {{WebTransportSendStream}}. This also means the [=fulfilled|fulfillment=] of the promise returned from this algorithm (or, -{{WritableStreamDefaultWriter/write|WritableStreamDefaultWriter.write}}) does **NOT** necessarily mean that the chunk is acked by +{{WritableStreamDefaultWriter/write(chunk)}}) does **NOT** necessarily mean that the chunk is acked by the server [[!QUIC]]. It may just mean that the chunk is appended to the buffer. To make sure that the chunk arrives at the server, use an application-level protocol. @@ -1619,6 +1651,16 @@ To abort a {{WebTransportSendStream}} |s +
+To abort all atomic write requests on a {{WebTransportSendStream}} |stream|, run these steps: + 1. Let |requestsToAbort| be [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. + 1. [=map/Clear=] [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. + 1. [=For each=] |promise| in |requestsToAbort|, [=reject=] |promise| with {{TransactionInactiveError}}. + 1. [=In parallel=], [=for each=] |promise| in |requestsToAbort|, abort the sending of data + associated with |promise|. + +
+ ## STOP_SENDING signal coming from the server ## {#send-stream-STOP_SENDING}
@@ -1970,6 +2012,72 @@ object |transport|, and a |sendOrder|, run these steps.
+# `WebTransportWriter` Interface # {#web-transport-writer-procedures-interface} + +{{WebTransportWriter}} is a subclass of {{WritableStreamDefaultWriter}} that +overloads one method and adds another. + +A {{WebTransportWriter}} is always created by the +[=WebTransportWriter/create=] procedure. + +
+[Exposed=*, SecureContext]
+interface WebTransportWriter : WritableStreamDefaultWriter {
+  Promise<undefined> write(optional any chunk);
+  Promise<undefined> atomicWrite(optional any chunk);
+};
+
+ +## Methods ## {#web-transport-writer-procedures-methods} + +: write(chunk) +:: The {{write}} method will not reject on [=flow control=] blockage + (unless queued behind one or more outstanding calls to {{atomicWrite}}). + This behavior is designed to satisfy most applications. + + When called, run the following steps: + 1. Let |stream| be the {{WebTransportSendStream}} associated with [=this=]. + 1. If |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} is not empty, + return the result of [=writing atomically=] on |stream| with |chunk|. + 1. Return the result of {{WritableStreamDefaultWriter/write(chunk)}} + on {{WritableStreamDefaultWriter}} with |chunk|. + +: atomicWrite(chunk) +:: The {{atomicWrite}} method will reject if the chunk given to it + cannot be sent in its entirety without blocking on [=flow control=]. + This behavior is designed to satisfy niche transactional applications + sensitive to [=flow control=] deadlocks ([[RFC9308]] + [Section 4.4](https://datatracker.ietf.org/doc/html/rfc9308#section-4.4)). + + When called, return the result of [=writing atomically=] on the + {{WebTransportSendStream}} associated with [=this=], with |chunk|. + +## Procedures ## {#web-transport-writer-procedures-procedures} + +
+ +To create a +{{WebTransportWriter}}, with a {{WebTransportSendStream}} |stream|, run these +steps: +1. Let |writer| be a [=new=] {{WebTransportWriter}}. +1. Run the [new WritableStreamDefaultWriter(stream)](https://streams.spec.whatwg.org/#default-writer-constructor) + constructor steps passing |writer| as this, and |stream| as the constructor argument. +1. Return |writer|. + +
+ +
+ +To write atomically +on a {{WebTransportSendStream}} |stream|, given |chunk|, run these steps: +1. Let |p| be the result of {{WritableStreamDefaultWriter/write(chunk)}} + on {{WritableStreamDefaultWriter}} with |chunk|. +1. Set |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} to |p|. +1. Return |p|. + +
+ + # `WebTransportError` Interface # {#web-transport-error-interface} WebTransportError is a subclass of {{DOMException}} that represents @@ -2093,7 +2201,7 @@ converted to an httpErrorCode, and vice versa, as specified in [[!WEB-TRANSPORT- [=stream/Send|sends=] STREAM with FIN bit set - {{WebTransportBidirectionalStream/writable}}.getWriter().{{WritableStreamDefaultWriter/write}}() + {{WebTransportBidirectionalStream/writable}}.getWriter().{{WritableStreamDefaultWriter/write(chunk)}}() [=stream/Send|sends=] STREAM @@ -2535,6 +2643,31 @@ async function receiveText(url, createWritableStreamForTextData) { } +## Sending a transactional chunk on a stream ## {#example-transactional-stream} + +*This section is non-normative.* + +Sending a transactional piece of data on a one-way stream only if it can be done +entirely without blocking on [=flow control=], can be achieved by using the +{{WebTransportSendStream/getWriter}} function and the resulting writer. + +
+async function sendTransactionalData(wt, bytes) {
+  const writable = await wt.createUnidirectionalStream();
+  const writer = writable.getWriter();
+  await writer.ready;
+  try {
+    await writer.atomicWrite(bytes);
+  } catch (e) {
+    if (e.name != "TransactionInactiveError") throw e;
+    // rejected to avoid blocking on flow control
+    // The writable remains un-errored unlike with regular writes
+  } finally {
+    writer.releaseLock();
+  }
+}
+
+ ## Complete example ## {#example-complete} *This section is non-normative.* From 86696ddfccf50863d30f5439d3709381bba4010f Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 10 Oct 2023 18:37:35 -0400 Subject: [PATCH 02/27] Clean up [[AtomicWriteRequests]] in case input validation failure. --- index.bs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 53f044f9..84b25e50 100644 --- a/index.bs +++ b/index.bs @@ -1598,7 +1598,7 @@ To write |chunk| to a {{WebTransportSend 1. [=Queue a network task=] with |transport| to run these steps: 1. Set |stream|.{{[[PendingOperation]]}} to null. 1. If |atomic| is true, [=map/remove=] |inFlightWriteRequest| from - |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}}. + |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} if it exists. 1. [=Resolve=] |promise| with undefined. 1. Return |promise|. @@ -2073,7 +2073,10 @@ on a {{WebTransportSendStream}} |stream|, given |chunk|, run these steps: 1. Let |p| be the result of {{WritableStreamDefaultWriter/write(chunk)}} on {{WritableStreamDefaultWriter}} with |chunk|. 1. Set |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} to |p|. -1. Return |p|. +1. Return the result of [=reacting=] to |p| with the following steps: + 1. [=map/Remove=] |p| from |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} if it exists. + 1. If |p| was rejected with reason |r|, then return [=a promise rejected with=] |r|. + 1. Return undefined. From 5e7b05bcfa38dfa15b30cdb7cc6a7dcb151f653d Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 10 Oct 2023 18:42:03 -0400 Subject: [PATCH 03/27] Use ordered set correctly. --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 84b25e50..e326fbdd 100644 --- a/index.bs +++ b/index.bs @@ -1501,7 +1501,7 @@ A {{WebTransportSendStream}} has the following internal slots. `[[AtomicWriteRequests]]` - A [=list=] of promises, each representing an in-flight atomic + An [=ordered set=] of promises, each representing an in-flight atomic write request to be processed by the underlying sink. @@ -2072,7 +2072,7 @@ To write atomically Date: Wed, 11 Oct 2023 15:08:30 -0400 Subject: [PATCH 04/27] Allow queueing atomic writes behind non-atomic ones, clarify prose and use AbortError. --- index.bs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/index.bs b/index.bs index e326fbdd..5c721a3c 100644 --- a/index.bs +++ b/index.bs @@ -1501,8 +1501,8 @@ A {{WebTransportSendStream}} has the following internal slots. `[[AtomicWriteRequests]]` - An [=ordered set=] of promises, each representing an in-flight atomic - write request to be processed by the underlying sink. + An [=ordered set=] of promises, keeping track of the subset of + write requests that are atomic among those queued be processed by the underlying sink. @@ -1525,7 +1525,7 @@ To create a : {{WebTransportSendStream/[[SendOrder]]}} :: |sendOrder| : {{WebTransportSendStream/[[AtomicWriteRequests]]}} - :: An empty [=list=] of promises. + :: An empty [=ordered set=] of promises. 1. Let |writeAlgorithm| be an action that [=writes=] |chunk| to |stream|, given |chunk|. 1. Let |closeAlgorithm| be an action that [=closes=] |stream|. 1. Let |abortAlgorithm| be an action that [=aborts=] |stream| with |reason|, given |reason|. @@ -1576,11 +1576,10 @@ To write |chunk| to a {{WebTransportSend [=WritableStream/Error | errored=] nor blocked by [=flow control=], have been sent. - Whenever the sending of |bytes| becomes blocked by [=flow control=], - [=queue a network task=] with |transport| to [=abort all atomic write requests=] on |stream|. - - If the sending of |bytes| becomes blocked by [=flow control=] and |atomic| is true, - then give up on sending |bytes| and proceed immediately to the next step without failing. + If the sending of |bytes| cannot be completed within the current [=flow control=] + window, and |atomic| is true, then give up on sending |bytes| and + [=queue a network task=] with |transport| to [=abort all atomic write requests=] + on |stream|, before proceeding immediately to the next step without failing. The user agent SHOULD divide bandwidth fairly between all streams that aren't starved. @@ -1655,7 +1654,7 @@ To abort a {{WebTransportSendStream}} |s To abort all atomic write requests on a {{WebTransportSendStream}} |stream|, run these steps: 1. Let |requestsToAbort| be [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. 1. [=map/Clear=] [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. - 1. [=For each=] |promise| in |requestsToAbort|, [=reject=] |promise| with {{TransactionInactiveError}}. + 1. [=For each=] |promise| in |requestsToAbort|, [=reject=] |promise| with {{AbortError}}. 1. [=In parallel=], [=for each=] |promise| in |requestsToAbort|, abort the sending of data associated with |promise|. From f70078932761cf0980f8421d9475b110a4673cbc Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 11 Oct 2023 15:26:48 -0400 Subject: [PATCH 05/27] Add a note on all or nothing --- index.bs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index 5c721a3c..0ab14c60 100644 --- a/index.bs +++ b/index.bs @@ -2037,17 +2037,23 @@ interface WebTransportWriter : WritableStreamDefaultWriter { When called, run the following steps: 1. Let |stream| be the {{WebTransportSendStream}} associated with [=this=]. 1. If |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} is not empty, - return the result of [=writing atomically=] on |stream| with |chunk|. + then return the result of [=writing atomically=] on |stream| with |chunk|. 1. Return the result of {{WritableStreamDefaultWriter/write(chunk)}} on {{WritableStreamDefaultWriter}} with |chunk|. : atomicWrite(chunk) -:: The {{atomicWrite}} method will reject if the chunk given to it - cannot be sent in its entirety without blocking on [=flow control=]. - This behavior is designed to satisfy niche transactional applications - sensitive to [=flow control=] deadlocks ([[RFC9308]] +:: The {{atomicWrite}} method will reject if the |chunk| given to it + cannot be sent in its entirety within the [=flow control=] window that + is current at the time of sending. In other words, the sending of |chunk| + is all or nothing. This behavior is designed to satisfy niche transactional + applications sensitive to [=flow control=] deadlocks ([[RFC9308]] [Section 4.4](https://datatracker.ietf.org/doc/html/rfc9308#section-4.4)). - + + Note: Atomic writes can still block if queued behind non-atomic writes. If + the write is rejected, everything queued behind it will be rejected as well, + including non-atomic writes. Applications are therefore encouraged to always + await atomic writes. + When called, return the result of [=writing atomically=] on the {{WebTransportSendStream}} associated with [=this=], with |chunk|. From a223f505354cf099bb7085189494d2572013b7aa Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 11 Oct 2023 15:29:56 -0400 Subject: [PATCH 06/27] Link to sending --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 0ab14c60..152fc821 100644 --- a/index.bs +++ b/index.bs @@ -1655,8 +1655,8 @@ To abort all atomic write requests on a 1. Let |requestsToAbort| be [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. 1. [=map/Clear=] [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. 1. [=For each=] |promise| in |requestsToAbort|, [=reject=] |promise| with {{AbortError}}. - 1. [=In parallel=], [=for each=] |promise| in |requestsToAbort|, abort the sending of data - associated with |promise|. + 1. [=In parallel=], [=for each=] |promise| in |requestsToAbort|, abort the + [=stream/send|sending=] of bytes associated with |promise|. From 806a880f9581825e7fdcabdde8dafd6b8df53c00 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 11 Oct 2023 20:38:54 -0400 Subject: [PATCH 07/27] Remove unnecessary parens Co-authored-by: Martin Thomson --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 71742a27..bbad2bac 100644 --- a/index.bs +++ b/index.bs @@ -2150,7 +2150,7 @@ interface WebTransportWriter : WritableStreamDefaultWriter { : write(chunk) :: The {{write}} method will not reject on [=flow control=] blockage - (unless queued behind one or more outstanding calls to {{atomicWrite}}). + unless queued behind one or more outstanding calls to {{atomicWrite}}. This behavior is designed to satisfy most applications. When called, run the following steps: From e82d1e0c0e097dfb0c0d4d8c7759d7c16671a387 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 11 Oct 2023 20:39:12 -0400 Subject: [PATCH 08/27] clarify prose Co-authored-by: Martin Thomson --- index.bs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/index.bs b/index.bs index bbad2bac..7dff6e1a 100644 --- a/index.bs +++ b/index.bs @@ -2170,7 +2170,8 @@ interface WebTransportWriter : WritableStreamDefaultWriter { Note: Atomic writes can still block if queued behind non-atomic writes. If the write is rejected, everything queued behind it will be rejected as well, - including non-atomic writes. Applications are therefore encouraged to always + including non-atomic writes, which are enqueued as atomic writes when an + atomic write is outstanding. Applications are therefore encouraged to always await atomic writes. When called, return the result of [=writing atomically=] on the From ba7609e20f55868eb70827059d8d6acc2748a472 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 11 Oct 2023 20:39:31 -0400 Subject: [PATCH 09/27] Use correct error in example Co-authored-by: Martin Thomson --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 7dff6e1a..6af33ee5 100644 --- a/index.bs +++ b/index.bs @@ -2787,7 +2787,7 @@ async function sendTransactionalData(wt, bytes) { try { await writer.atomicWrite(bytes); } catch (e) { - if (e.name != "TransactionInactiveError") throw e; + if (e.name != "AbortError") throw e; // rejected to avoid blocking on flow control // The writable remains un-errored unlike with regular writes } finally { From 892bb1bf8ff8cf5dde7399e5592758534276fcf1 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 11 Oct 2023 20:41:56 -0400 Subject: [PATCH 10/27] s/give up on/stop/ + remove note in favor of opening an issue --- index.bs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/index.bs b/index.bs index 6af33ee5..993fe4bf 100644 --- a/index.bs +++ b/index.bs @@ -1594,10 +1594,6 @@ To write |chunk| to a {{WebTransportSend 1. Set |stream|.{{[[PendingOperation]]}} to |promise|. 1. Let |inFlightWriteRequest| be |stream|.inFlightWriteRequest. - - Note: Find a [better way](https://streams.spec.whatwg.org/#other-specs) to integrate - with the streams spec to identify the write request in flight. - 1. Let |atomic| be true if |inFlightWriteRequest| [=list/exists=] in [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}, otherwise false. 1. Run the following steps [=in parallel=]: @@ -1616,7 +1612,7 @@ To write |chunk| to a {{WebTransportSend except for [=flow control=] reasons or [=WritableStream/Error | error=]. If the sending of |bytes| cannot be completed in its entirety within the current - [=flow control=] window, and |atomic| is true, then give up on sending |bytes| and + [=flow control=] window, and |atomic| is true, then stop sending |bytes| and [=queue a network task=] with |transport| to [=abort all atomic write requests=] on |stream|, before proceeding immediately to the next step without failing. From a6e7e275922e14aaf131909cb00a860b8a68fa7e Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 1 Nov 2023 16:58:17 -0400 Subject: [PATCH 11/27] typo --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 993fe4bf..c6e14e7e 100644 --- a/index.bs +++ b/index.bs @@ -1538,7 +1538,7 @@ A {{WebTransportSendStream}} has the following internal slots. `[[AtomicWriteRequests]]` An [=ordered set=] of promises, keeping track of the subset of - write requests that are atomic among those queued be processed by the underlying sink. + write requests that are atomic among those queued to be processed by the underlying sink. From 76622e10246fe3627ea1e181f957b41b4a1962f7 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Fri, 3 Nov 2023 16:49:21 -0400 Subject: [PATCH 12/27] Reorder send steps into three outcomes. --- index.bs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/index.bs b/index.bs index c6e14e7e..665c4ccf 100644 --- a/index.bs +++ b/index.bs @@ -1611,11 +1611,6 @@ To write |chunk| to a {{WebTransportSend This sending MUST NOT starve otherwise, except for [=flow control=] reasons or [=WritableStream/Error | error=]. - If the sending of |bytes| cannot be completed in its entirety within the current - [=flow control=] window, and |atomic| is true, then stop sending |bytes| and - [=queue a network task=] with |transport| to [=abort all atomic write requests=] - on |stream|, before proceeding immediately to the next step without failing. - The user agent SHOULD divide bandwidth fairly between all streams that aren't starved. Note: The definition of fairness here is [=implementation-defined=]. @@ -1624,14 +1619,22 @@ To write |chunk| to a {{WebTransportSend respond to live updates of these values during sending, though the details are [=implementation-defined=]. - 1. If the previous step failed, abort the remaining steps. + If the the current [=flow control=] window ends before |bytes| can be sent in + their entirety, and |atomic| is true, then stop sending |bytes|. + + 1. If the previous step failed due to a network error, abort the remaining steps. Note: We don't reject |promise| here because we handle network errors elsewhere, and those steps error |stream| and reject the result of this write operation. - 1. [=Queue a network task=] with |transport| to run these steps: + 1. If |bytes| were not sent in their entirety, [=queue a network task=] with |transport| + to run these steps: + 1. Set |stream|.{{[[PendingOperation]]}} to null. + 1. [=Abort all atomic write requests=] on |stream|. + 1. Otherwise, [=queue a network task=] with |transport| + to run these steps: 1. Set |stream|.{{[[PendingOperation]]}} to null. - 1. If |atomic| is true, [=map/remove=] |inFlightWriteRequest| from + 1. [=map/Remove=] |inFlightWriteRequest| from |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} if it exists. 1. [=Resolve=] |promise| with undefined. 1. Return |promise|. From 4e79fb4fc7c7b28ddda3c1b9dad622b38a542763 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 8 Nov 2023 12:59:52 -0500 Subject: [PATCH 13/27] Add note about limitations of atomicWrite. --- index.bs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 665c4ccf..4687fa55 100644 --- a/index.bs +++ b/index.bs @@ -1619,8 +1619,8 @@ To write |chunk| to a {{WebTransportSend respond to live updates of these values during sending, though the details are [=implementation-defined=]. - If the the current [=flow control=] window ends before |bytes| can be sent in - their entirety, and |atomic| is true, then stop sending |bytes|. + Stop sending |bytes| if |atomic| is true and the current [=flow control=] window + ends before |bytes| can be sent in their entirety. 1. If the previous step failed due to a network error, abort the remaining steps. @@ -2167,6 +2167,10 @@ interface WebTransportWriter : WritableStreamDefaultWriter { applications sensitive to [=flow control=] deadlocks ([[RFC9308]] [Section 4.4](https://datatracker.ietf.org/doc/html/rfc9308#section-4.4)). + Note: {{atomicWrite}} does not guarantee atomicity on the wire (e.g. MTU) or + at the receiver, nor does it prevent interleaving of data with other send + requests. Only the sender will know if it failed. + Note: Atomic writes can still block if queued behind non-atomic writes. If the write is rejected, everything queued behind it will be rejected as well, including non-atomic writes, which are enqueued as atomic writes when an From e450cccb513d4e372d7bc20955b2b07f85790a58 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 8 Nov 2023 13:24:31 -0500 Subject: [PATCH 14/27] Slight rephrase of use of list algorithms from infra. --- index.bs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/index.bs b/index.bs index 4687fa55..89dfb405 100644 --- a/index.bs +++ b/index.bs @@ -1594,8 +1594,8 @@ To write |chunk| to a {{WebTransportSend 1. Set |stream|.{{[[PendingOperation]]}} to |promise|. 1. Let |inFlightWriteRequest| be |stream|.inFlightWriteRequest. -1. Let |atomic| be true if |inFlightWriteRequest| [=list/exists=] - in [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}, otherwise false. +1. Let |atomic| be true if [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}} + [=list/contains=] |inFlightWriteRequest|, otherwise false. 1. Run the following steps [=in parallel=]: 1. [=stream/Send=] |bytes| on |stream|.{{WebTransportSendStream/[[InternalStream]]}} and wait for the operation to complete. @@ -1634,8 +1634,7 @@ To write |chunk| to a {{WebTransportSend 1. Otherwise, [=queue a network task=] with |transport| to run these steps: 1. Set |stream|.{{[[PendingOperation]]}} to null. - 1. [=map/Remove=] |inFlightWriteRequest| from - |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} if it exists. + 1. If |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} [=list/contains=] |inFlightWriteRequest|, [=list/remove=] |inFlightWriteRequest|. 1. [=Resolve=] |promise| with undefined. 1. Return |promise|. @@ -1691,7 +1690,7 @@ To abort a {{WebTransportSendStream}} |s
To abort all atomic write requests on a {{WebTransportSendStream}} |stream|, run these steps: 1. Let |requestsToAbort| be [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. - 1. [=map/Clear=] [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. + 1. [=list/Empty=] [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. 1. [=For each=] |promise| in |requestsToAbort|, [=reject=] |promise| with {{AbortError}}. 1. [=In parallel=], [=for each=] |promise| in |requestsToAbort|, abort the [=stream/send|sending=] of bytes associated with |promise|. @@ -2202,7 +2201,8 @@ on a {{WebTransportSendStream}} |stream|, given |chunk|, run these steps: on {{WritableStreamDefaultWriter}} with |chunk|. 1. [=set/Append=] |p| to |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}}. 1. Return the result of [=reacting=] to |p| with the following steps: - 1. [=map/Remove=] |p| from |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} if it exists. + 1. If |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} [=list/contains=] |p|, + [=list/remove=] |p|. 1. If |p| was rejected with reason |r|, then return [=a promise rejected with=] |r|. 1. Return undefined. From 166f9217d27cd2530bd0a157dcd3aed80fadd5bf Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Wed, 8 Nov 2023 13:53:53 -0500 Subject: [PATCH 15/27] s/receiver/server/ and s/sender/client/ --- index.bs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.bs b/index.bs index 89dfb405..3d59aa51 100644 --- a/index.bs +++ b/index.bs @@ -2167,8 +2167,8 @@ interface WebTransportWriter : WritableStreamDefaultWriter { [Section 4.4](https://datatracker.ietf.org/doc/html/rfc9308#section-4.4)). Note: {{atomicWrite}} does not guarantee atomicity on the wire (e.g. MTU) or - at the receiver, nor does it prevent interleaving of data with other send - requests. Only the sender will know if it failed. + at the server, nor does it prevent interleaving of data with other send + requests. Only the client will know if it failed. Note: Atomic writes can still block if queued behind non-atomic writes. If the write is rejected, everything queued behind it will be rejected as well, From 0aa25f66dedba36c0a88e683012d4cf65d9fa27b Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 16 Jan 2024 09:44:22 -0500 Subject: [PATCH 16/27] Error the stream with AbortError at the point where reordering would otherwise occur --- index.bs | 72 +++++++++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 45 deletions(-) diff --git a/index.bs b/index.bs index 9f3feab8..2ad3c090 100644 --- a/index.bs +++ b/index.bs @@ -1708,7 +1708,11 @@ To abort a {{WebTransportSendStream}} |s
To abort all atomic write requests on a {{WebTransportSendStream}} |stream|, run these steps: + 1. Let |writeRequests| be + |stream|.writeRequests. 1. Let |requestsToAbort| be [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. + 1. If |writeRequests| [=list/contains=] a promise not in |requestsToAbort|, then + [=WritableStream/error=] |stream| with {{AbortError}}, and abort these steps. 1. [=list/Empty=] [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}}. 1. [=For each=] |promise| in |requestsToAbort|, [=reject=] |promise| with {{AbortError}}. 1. [=In parallel=], [=for each=] |promise| in |requestsToAbort|, abort the @@ -2143,7 +2147,7 @@ object |transport|, and a |sendOrder|, run these steps. # `WebTransportWriter` Interface # {#web-transport-writer-procedures-interface} {{WebTransportWriter}} is a subclass of {{WritableStreamDefaultWriter}} that -overloads one method and adds another. +adds one method. A {{WebTransportWriter}} is always created by the [=WebTransportWriter/create=] procedure. @@ -2151,45 +2155,39 @@ A {{WebTransportWriter}} is always created by the
 [Exposed=*, SecureContext]
 interface WebTransportWriter : WritableStreamDefaultWriter {
-  Promise<undefined> write(optional any chunk);
   Promise<undefined> atomicWrite(optional any chunk);
 };
 
## Methods ## {#web-transport-writer-procedures-methods} -: write(chunk) -:: The {{write}} method will not reject on [=flow control=] blockage - unless queued behind one or more outstanding calls to {{atomicWrite}}. - This behavior is designed to satisfy most applications. - - When called, run the following steps: - 1. Let |stream| be the {{WebTransportSendStream}} associated with [=this=]. - 1. If |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} is not empty, - then return the result of [=writing atomically=] on |stream| with |chunk|. - 1. Return the result of {{WritableStreamDefaultWriter/write(chunk)}} - on {{WritableStreamDefaultWriter}} with |chunk|. - : atomicWrite(chunk) :: The {{atomicWrite}} method will reject if the |chunk| given to it - cannot be sent in its entirety within the [=flow control=] window that - is current at the time of sending. In other words, the sending of |chunk| - is all or nothing. This behavior is designed to satisfy niche transactional - applications sensitive to [=flow control=] deadlocks ([[RFC9308]] + could not be sent in its entirety within the [=flow control=] window that + is current at the time of sending. This behavior is designed to satisfy niche + transactional applications sensitive to [=flow control=] deadlocks ([[RFC9308]] [Section 4.4](https://datatracker.ietf.org/doc/html/rfc9308#section-4.4)). - Note: {{atomicWrite}} does not guarantee atomicity on the wire (e.g. MTU) or - at the server, nor does it prevent interleaving of data with other send - requests. Only the client will know if it failed. + Note: {{atomicWrite}} might have partially sent a chunk before rejecting. It + does not guarantee atomicity on the wire (e.g. MTU) or at the server, nor does + it prevent interleaving of data with other send requests. Only the client will + know if it failed. Note: Atomic writes can still block if queued behind non-atomic writes. If - the write is rejected, everything queued behind it will be rejected as well, - including non-atomic writes, which are enqueued as atomic writes when an - atomic write is outstanding. Applications are therefore encouraged to always - await atomic writes. - - When called, return the result of [=writing atomically=] on the - {{WebTransportSendStream}} associated with [=this=], with |chunk|. + the atomic write is rejected, everything queued behind it at that moment + will be rejected as well. Any non-atomic writes rejected in this way will + [=WritableStream/error=] the stream. Applications are therefore encouraged to + always await atomic writes. + + When atomicWrite is called, the user agent MUST run the following steps: + 1. Let |p| be the result of {{WritableStreamDefaultWriter/write(chunk)}} + on {{WritableStreamDefaultWriter}} with |chunk|. + 1. [=set/Append=] |p| to |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}}. + 1. Return the result of [=reacting=] to |p| with the following steps: + 1. If |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} [=list/contains=] |p|, + [=list/remove=] |p|. + 1. If |p| was rejected with reason |r|, then return [=a promise rejected with=] |r|. + 1. Return undefined. ## Procedures ## {#web-transport-writer-procedures-procedures} @@ -2205,22 +2203,6 @@ steps:
-
- -To write atomically -on a {{WebTransportSendStream}} |stream|, given |chunk|, run these steps: -1. Let |p| be the result of {{WritableStreamDefaultWriter/write(chunk)}} - on {{WritableStreamDefaultWriter}} with |chunk|. -1. [=set/Append=] |p| to |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}}. -1. Return the result of [=reacting=] to |p| with the following steps: - 1. If |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}} [=list/contains=] |p|, - [=list/remove=] |p|. - 1. If |p| was rejected with reason |r|, then return [=a promise rejected with=] |r|. - 1. Return undefined. - -
- - # `WebTransportError` Interface # {#web-transport-error-interface} WebTransportError is a subclass of {{DOMException}} that represents @@ -2804,7 +2786,7 @@ async function sendTransactionalData(wt, bytes) { } catch (e) { if (e.name != "AbortError") throw e; // rejected to avoid blocking on flow control - // The writable remains un-errored unlike with regular writes + // The writable remains un-errored provided no non-atomic writes are pending } finally { writer.releaseLock(); } From 9429dfda4fb4460b1502ca01a9fc5dc92b00f946 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 23 Jan 2024 16:37:01 -0500 Subject: [PATCH 17/27] Remove unnecessary link-default --- index.bs | 1 - 1 file changed, 1 deletion(-) diff --git a/index.bs b/index.bs index 2ad3c090..5d838b8f 100644 --- a/index.bs +++ b/index.bs @@ -70,7 +70,6 @@ spec:url; type:dfn; text:scheme spec:url; type:dfn; text:fragment spec:infra; type:dfn; for:/; text:ASCII case-insensitive spec:infra; type:dfn; text:list -spec:streams; type:dict-member; text:write
 url: https://html.spec.whatwg.org/multipage/origin.html#concept-origin; type: dfn; text: origin; for:/

From 4ea6bf8fc102ec92112e71330a741350da6e0e84 Mon Sep 17 00:00:00 2001
From: Jan-Ivar Bruaroey 
Date: Tue, 23 Jan 2024 16:38:24 -0500
Subject: [PATCH 18/27] "some form of acknowledgment message" rephrase

Co-authored-by: Martin Thomson 
---
 index.bs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/index.bs b/index.bs
index 5d838b8f..5fc58cfa 100644
--- a/index.bs
+++ b/index.bs
@@ -1661,7 +1661,7 @@ To write |chunk| to a {{WebTransportSend
 Note: The [=fulfilled|fulfillment=] of the promise returned from this algorithm (or,
 {{WritableStreamDefaultWriter/write(chunk)}}) does **NOT** necessarily mean that the chunk is acked by
 the server [[!QUIC]]. It may just mean that the chunk is appended to the buffer. To make sure that
-the chunk arrives at the server, use an application-level protocol.
+the chunk arrives at the server, the server needs to send some form of acknowledgment message.
 
 
From d82687ab4aae89919a3586bf34d4cb0bd46e128b Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 23 Jan 2024 16:53:03 -0500 Subject: [PATCH 19/27] Clarify partial send Co-authored-by: Martin Thomson --- index.bs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/index.bs b/index.bs index 5fc58cfa..52f8b8b0 100644 --- a/index.bs +++ b/index.bs @@ -2167,10 +2167,11 @@ interface WebTransportWriter : WritableStreamDefaultWriter { transactional applications sensitive to [=flow control=] deadlocks ([[RFC9308]] [Section 4.4](https://datatracker.ietf.org/doc/html/rfc9308#section-4.4)). - Note: {{atomicWrite}} might have partially sent a chunk before rejecting. It - does not guarantee atomicity on the wire (e.g. MTU) or at the server, nor does - it prevent interleaving of data with other send requests. Only the client will - know if it failed. + Note: {{atomicWrite}} can still reject after sending some data. Though it + provides atomicity with respect to flow control, other errors may occur. + {{atomicWrite}} does not prevent data from being split between packets + or being interleaved with other data. Only the sender learns if + {{atomicWrite}} fails due to lack of available flow control credit. Note: Atomic writes can still block if queued behind non-atomic writes. If the atomic write is rejected, everything queued behind it at that moment From 62c87a71b6af84a371480eca53a5f9b0ff6bfbd6 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 23 Jan 2024 17:18:23 -0500 Subject: [PATCH 20/27] Move atomic language ahead of sending. --- index.bs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/index.bs b/index.bs index 52f8b8b0..5c306253 100644 --- a/index.bs +++ b/index.bs @@ -1613,8 +1613,13 @@ To write |chunk| to a {{WebTransportSend 1. Let |atomic| be true if [=stream=].{{WebTransportSendStream/[[AtomicWriteRequests]]}} [=list/contains=] |inFlightWriteRequest|, otherwise false. 1. Run the following steps [=in parallel=]: - 1. [=stream/Send=] |bytes| on |stream|.{{WebTransportSendStream/[[InternalStream]]}} and wait for the - operation to complete. + 1. If |atomic| is true and the current [=flow control=] window is too small for |bytes| to be sent + in its entirety, then abort the remaining steps and [=queue a network task=] with |transport| + to run these sub-steps: + 1. Set |stream|.{{[[PendingOperation]]}} to null. + 1. [=Abort all atomic write requests=] on |stream|. + 1. Otherwise, [=stream/send=] |bytes| on |stream|.{{WebTransportSendStream/[[InternalStream]]}} + and wait for the operation to complete. This sending MAY be interleaved with sending of previously queued streams and datagrams, as well as streams and datagrams yet to be queued to be sent over this transport. @@ -1639,18 +1644,11 @@ To write |chunk| to a {{WebTransportSend Note: The definition of fairness here is [=implementation-defined=]. - Stop sending |bytes| if |atomic| is true and the current [=flow control=] window - ends before |bytes| can be sent in their entirety. - 1. If the previous step failed due to a network error, abort the remaining steps. Note: We don't reject |promise| here because we handle network errors elsewhere, and those steps error |stream| and reject the result of this write operation. - 1. If |bytes| were not sent in their entirety, [=queue a network task=] with |transport| - to run these steps: - 1. Set |stream|.{{[[PendingOperation]]}} to null. - 1. [=Abort all atomic write requests=] on |stream|. 1. Otherwise, [=queue a network task=] with |transport| to run these steps: 1. Set |stream|.{{[[PendingOperation]]}} to null. From 64c44f997be011a996fb5ab1cd5955b02aae7dc4 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 30 Jan 2024 18:53:23 -0500 Subject: [PATCH 21/27] ...in the same manner Co-authored-by: Nidhi Jaju <41948741+nidhijaju@users.noreply.github.com> --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 5c306253..6afc4e4b 100644 --- a/index.bs +++ b/index.bs @@ -1513,7 +1513,7 @@ The {{WebTransportSendStream}}'s [=transfer steps=] and 1. Return |p|. : getWriter() -:: This method must be implemented the same as {{WritableStream/getWriter}} +:: This method must be implemented in the same manner as {{WritableStream/getWriter}} inherited from {{WritableStream}}, except in place of creating a {{WritableStreamDefaultWriter}}, it must instead [=WebTransportWriter/create=] a {{WebTransportWriter}} with [=this=]. From 4f21656eeca2db20c943d2cbeddc94bb29b63db4 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 30 Jan 2024 18:53:59 -0500 Subject: [PATCH 22/27] ...application-level ack Co-authored-by: Nidhi Jaju <41948741+nidhijaju@users.noreply.github.com> --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 6afc4e4b..ec590b79 100644 --- a/index.bs +++ b/index.bs @@ -1659,7 +1659,7 @@ To write |chunk| to a {{WebTransportSend Note: The [=fulfilled|fulfillment=] of the promise returned from this algorithm (or, {{WritableStreamDefaultWriter/write(chunk)}}) does **NOT** necessarily mean that the chunk is acked by the server [[!QUIC]]. It may just mean that the chunk is appended to the buffer. To make sure that -the chunk arrives at the server, the server needs to send some form of acknowledgment message. +the chunk arrives at the server, the server needs to send an application-level acknowledgment message. From 7d8bb5eefd099022fc1a005cf4f68af88edc75de Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 30 Jan 2024 18:54:57 -0500 Subject: [PATCH 23/27] When {{atomicWrite}}... Co-authored-by: Martin Thomson --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index ec590b79..daed0637 100644 --- a/index.bs +++ b/index.bs @@ -2177,7 +2177,7 @@ interface WebTransportWriter : WritableStreamDefaultWriter { [=WritableStream/error=] the stream. Applications are therefore encouraged to always await atomic writes. - When atomicWrite is called, the user agent MUST run the following steps: + When {{atomicWrite}} is called, the user agent MUST run the following steps: 1. Let |p| be the result of {{WritableStreamDefaultWriter/write(chunk)}} on {{WritableStreamDefaultWriter}} with |chunk|. 1. [=set/Append=] |p| to |stream|.{{WebTransportSendStream/[[AtomicWriteRequests]]}}. From a4779259239dbc56a772560ad73508420b808e96 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 30 Jan 2024 18:56:15 -0500 Subject: [PATCH 24/27] fix typo in anchor Co-authored-by: Nidhi Jaju <41948741+nidhijaju@users.noreply.github.com> --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index daed0637..40e1dc89 100644 --- a/index.bs +++ b/index.bs @@ -2156,7 +2156,7 @@ interface WebTransportWriter : WritableStreamDefaultWriter { }; -## Methods ## {#web-transport-writer-procedures-methods} +## Methods ## {#web-transport-writer-methods} : atomicWrite(chunk) :: The {{atomicWrite}} method will reject if the |chunk| given to it From f791fe6eab8d0a97e264d7c08b7dde559a58fd27 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 30 Jan 2024 18:56:41 -0500 Subject: [PATCH 25/27] minus "procedures" Co-authored-by: Nidhi Jaju <41948741+nidhijaju@users.noreply.github.com> --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 40e1dc89..e21aa4a7 100644 --- a/index.bs +++ b/index.bs @@ -2141,7 +2141,7 @@ object |transport|, and a |sendOrder|, run these steps. -# `WebTransportWriter` Interface # {#web-transport-writer-procedures-interface} +# `WebTransportWriter` Interface # {#web-transport-writer-interface} {{WebTransportWriter}} is a subclass of {{WritableStreamDefaultWriter}} that adds one method. From 6099a3182a35da754355bb39cf3929bd22473c2f Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 30 Jan 2024 18:57:02 -0500 Subject: [PATCH 26/27] minus "procedures" again Co-authored-by: Nidhi Jaju <41948741+nidhijaju@users.noreply.github.com> --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index e21aa4a7..2fa4fe18 100644 --- a/index.bs +++ b/index.bs @@ -2187,7 +2187,7 @@ interface WebTransportWriter : WritableStreamDefaultWriter { 1. If |p| was rejected with reason |r|, then return [=a promise rejected with=] |r|. 1. Return undefined. -## Procedures ## {#web-transport-writer-procedures-procedures} +## Procedures ## {#web-transport-writer-procedures}
From fbc834be384bd439032907ca65fa0806842c3b93 Mon Sep 17 00:00:00 2001 From: Jan-Ivar Bruaroey Date: Tue, 30 Jan 2024 18:57:30 -0500 Subject: [PATCH 27/27] s/one-way/unidirectional/ Co-authored-by: Nidhi Jaju <41948741+nidhijaju@users.noreply.github.com> --- index.bs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.bs b/index.bs index 2fa4fe18..43003977 100644 --- a/index.bs +++ b/index.bs @@ -2770,7 +2770,7 @@ async function receiveText(url, createWritableStreamForTextData) { *This section is non-normative.* -Sending a transactional piece of data on a one-way stream only if it can be done +Sending a transactional piece of data on a unidirectional stream, only if it can be done entirely without blocking on [=flow control=], can be achieved by using the {{WebTransportSendStream/getWriter}} function and the resulting writer.