GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
GeezerVison is showing w3c.github.io — WebTransport 1. IntroductionThis section is non-normative. This specification uses [WEB-TRANSPORT-OVERVIEW] to send data to and receive data from servers. It can be used like WebSockets but with support for multiple streams, unidirectional streams, out-of-order delivery, and reliable as well as unreliable transport. Note: The API presented in this specification represents a preliminary proposal based on work-in-progress within the IETF WEBTRANS WG. Since the [WEB-TRANSPORT-HTTP3] and [WEB-TRANSPORT-HTTP2] specifications are a work-in-progress, both the protocol and API are likely to change significantly going forward. 2. ConformanceAs well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative. The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" are to be interpreted as described in [RFC2119] and [RFC8174] when, and only when, they appear in all capitals, as shown here. This specification defines conformance criteria that apply to a single product: the user agent that implements the interfaces that it contains. Conformance requirements phrased as algorithms or specific steps may be implemented in any manner, so long as the end result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.) Implementations that use ECMAScript to implement the APIs defined in this specification MUST implement them in a manner consistent with the ECMAScript Bindings defined in the Web IDL specification [WEBIDL], as this specification uses that specification and terminology. 3. Protocol conceptsThere are two main protocol concepts for WebTransport: sessions and streams. Each WebTransport session can contain multiple WebTransport streams. These should not be confused with protocol names which is an application-level API construct. 3.1. WebTransport sessionA WebTransport session is a session of WebTransport over an HTTP/3 or HTTP/2 underlying connection. There may be multiple WebTransport sessions on one connection, when pooling is enabled. A WebTransport session has the following capabilities defined in [WEB-TRANSPORT-OVERVIEW]:
A WebTransport session session is draining when the CONNECT stream is asked to gracefully close by the server, as described in [WEB-TRANSPORT-OVERVIEW] Section 4.1. To terminate a WebTransport session session with an optional integer code and an optional byte sequence reason, follow [WEB-TRANSPORT-OVERVIEW] Section 4.1. A WebTransport session session is terminated, with optionally an integer code and a byte sequence reason, when the CONNECT stream is closed by the server, as described at [WEB-TRANSPORT-OVERVIEW] Section 4.1. 3.2. WebTransport streamA WebTransport stream is a concept for a reliable in-order stream of bytes on a WebTransport session, as described in [WEB-TRANSPORT-OVERVIEW] Section 4.3. A WebTransport stream is one of incoming unidirectional, outgoing unidirectional or bidirectional.
Data sent on a stream is delivered
as an undifferentiated sequence of bytes.
The number of bytes in a single write operation on the sending side might not match
the number of bytes read in single operation at the receiving side.
Separate writes can be merged and delivered as a single byte sequence;
a single write might be delivered separately.
This includes Applications that depend on having a message-based protocol that preserves message boundaries between sender and receiver need to add a framing layer so that messages can be reconstructed. A WebTransport stream has the following capabilities:
A WebTransport stream has the following signals:
4.
|
| Internal Slot | Description (non-normative) |
|---|---|
[[OutgoingDatagramsQueue]]
| A queue of tuples of an outgoing datagram and a timestamp. |
[[BackpressurePromise]]
| A promise which is resolved once
[[OutgoingDatagramsQueue]] has room for another datagram.
|
[[Transport]]
| The WebTransport that owns this WebTransportDatagramsWritable.
|
[[SendGroup]]
| An optional WebTransportSendGroup, or null.
|
[[SendOrder]]
| An optional send order number, defaulting to 0. |
WebTransportDatagramsWritable, given a WebTransport transport, a sendGroup,
and a sendOrder, perform the following steps.
Let stream be a new WebTransportDatagramsWritable, with:
[[OutgoingDatagramsQueue]]
an empty queue
[[BackpressurePromise]]
a promise resolved with undefined
[[Transport]]
transport
[[SendGroup]]
sendGroup
[[SendOrder]]
sendOrder
Let writeDatagramsAlgorithm be an action that runs writeDatagrams with transport and stream.
Set up stream with writeAlgorithm set to writeDatagramsAlgorithm.
Append stream to
transport.[[Datagrams]].[[Writables]].
Return stream.
sendGroup, of type WebTransportSendGroup, nullable
The getter steps are:
Return this’s [[SendGroup]].
The setter steps, given value, are:
If value is non-null, and
value.[[Transport]] is not
this.[[Transport]], throw
an InvalidStateError.
Set this.[[SendGroup]] to value.
sendOrder, of type long long
The getter steps are:
Return this’s [[SendOrder]].
The setter steps, given value, are:
Set this.[[SendOrder]] to value.
The writeDatagrams algorithm is given a transport and writable as parameters and data as input. It is defined by running the following steps:
Let timestamp be a timestamp representing now.
If data is not a BufferSource object, then return a promise rejected with a TypeError.
Let duplex be transport.[[Datagrams]].
If duplex.[[OutgoingMaxDatagramSize]] is less than data’s [[ByteLength]], return
a promise resolved with undefined.
Let bytes be a copy of bytes which data represents.
Let chunk be (bytes, timestamp).
Enqueue chunk to writable.[[OutgoingDatagramsQueue]].
If writable’s send queue is full, then set
writable.[[BackpressurePromise]] to a new promise.
Return writable.[[BackpressurePromise]].
Note: The promise returned from the sink signals room in the send queue, not delivery.
It resolves as soon as [[OutgoingDatagramsQueue]] has room for another datagram,
which keeps that queue full.
Note: The associated WritableStream calls writeDatagrams again only when the promise
returned by the previous writeDatagrams for that stream has been resolved. Hence the
timestamp and the expiration duration work well only when the web developer pays attention to
WritableStreamDefaultWriter.ready.
To dequeue outgoing datagrams, given a WebTransport object transport, a
WebTransportDatagramsWritable object writable and a count, queue a network task
with transport to run these steps:
Let n be the minimum of count and the length of
writable.[[OutgoingDatagramsQueue]].
Repeat dequeuing writable.[[OutgoingDatagramsQueue]] n times.
If writable’s send queue is not full,
then resolve writable.[[BackpressurePromise]] with undefined.
A WebTransportDatagramsWritable writable’s
send queue is full if either of the following is
true:
The length of writable.[[OutgoingDatagramsQueue]] is not less than
writable.[[Transport]].[[Datagrams]].[[OutgoingMaxBufferedDatagrams]].
The total byte length of the datagrams in writable.[[OutgoingDatagramsQueue]] is greater
than an implementation-defined positive byte limit.
Note: The byte limit lets the user agent cap memory in the underlying sink, regardless of
outgoingMaxBufferedDatagrams. Datagrams beyond it wait in the
WritableStream’s queue instead. Tune the limit to keep throughput high.
To sendDatagrams, given a WebTransport object transport and a
WebTransportDatagramsWritable object writable, queue a network task
with transport to run the following steps:
Let datagrams be a copy of writable.[[OutgoingDatagramsQueue]].
Note: datagrams is a copy because the steps below run in parallel, whereas
writable.[[OutgoingDatagramsQueue]] is only ever touched by
dequeue outgoing datagrams, which queues a network task to do so. The copy, as well as
the queueing of a network task to run these steps, can be optimized.
Let maxSize be transport.[[Datagrams]].[[OutgoingMaxDatagramSize]].
Let duration be transport.[[Datagrams]].[[OutgoingDatagramsExpirationDuration]].
Let connected be true if transport.[[State]] is "connected", and false otherwise.
Run the following steps in parallel:
Let count be 0.
While datagrams is not empty:
If count is greater than 0, then the user agent MAY dequeue outgoing datagrams with transport, writable and count, and if it does, set count to 0.
While connected is true and datagrams is not empty:
Let bytes and timestamp be datagrams[0].
If bytes’s length ≤ maxSize and it is not possible to send bytes to the network immediately, then break this loop.
Dequeue datagrams.
Set count to count + 1.
The user agent MAY dequeue outgoing datagrams with transport, writable and count, and if it does, set count to 0.
If bytes’s length ≤ maxSize, then send a datagram, with
transport.[[Session]] and bytes.
If count is greater than 0, then dequeue outgoing datagrams with transport, writable and count.
Note: Dequeue outgoing datagrams is what makes room for more datagrams. The longer these calls
are batched, the more the send queue drains before the WritableStream is asked to refill it.
Batch only as much as tuning requires.
The user agent MUST, for any WebTransport object whose
[[State]] is "connecting" or "connected", run sendDatagrams on a
subset (determined by send-order rules) of its associated WebTransportDatagramsWritable
objects, and SHOULD do so as soon as reasonably possible whenever the
algorithm can make progress.
Note: Writing datagrams while the transport’s [[State]] is "connecting" is allowed. The
datagrams are stored in [[OutgoingDatagramsQueue]], and they can be discarded
in the same manner as when in the "connected" state. Once the transport’s [[State]] becomes
"connected", it will start sending the queued datagrams.
The send-order rules are that sending in general 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, except that sending MUST starve until
all bytes queued for sending on streams and datagrams with the same
[[SendGroup]] and a higher
[[SendOrder]], that are neither
errored nor blocked by flow control, have been sent.
Note: the default null sendGroup is a valid sendGroup.
WebTransportDatagramDuplexStream InterfaceA WebTransportDatagramDuplexStream is a generic duplex stream.
[Exposed =(Window ,Worker ),SecureContext ]interface WebTransportDatagramDuplexStream {WebTransportDatagramsWritable createWritable (optional WebTransportSendOptions = {});options readonly attribute ReadableStream readable ;readonly attribute unsigned long maxDatagramSize ;attribute unrestricted double ?incomingMaxAge ;attribute unrestricted double outgoingMaxAge ;attribute unsigned long incomingMaxBufferedDatagrams ;attribute unsigned long outgoingMaxBufferedDatagrams ; };
A WebTransportDatagramDuplexStream object has the following internal slots.
| Internal Slot | Description (non-normative) |
|---|---|
[[Transport]]
| The WebTransport that owns this WebTransportDatagramDuplexStream.
|
[[Readable]]
| A ReadableStream for incoming datagrams.
|
[[ReadableType]]
| The ReadableStreamType used for incoming datagrams.
|
[[Writables]]
| An ordered set of WebTransportDatagramsWritable streams,
initially empty.
|
[[IncomingDatagramsQueue]]
| A queue of tuples of an incoming datagram and a timestamp. |
[[IncomingDatagramsPullPromise]]
| A promise set by pullDatagrams, to wait for an incoming datagram. |
[[IncomingMaxBufferedDatagrams]]
| An unsigned long representing the
length of the incoming queue in number of datagrams, beyond which
datagrams are dropped from the head of the queue.
|
[[IncomingDatagramsExpirationDuration]]
| An unrestricted double representing the
expiration duration for incoming datagrams (in milliseconds), or null.
|
[[OutgoingMaxBufferedDatagrams]]
| An unsigned long representing the
maximum length of the underlying sink’s outgoing queue in number of datagrams,
beyond which backpressure is exerted. A byte limit can exert it sooner.
|
[[OutgoingDatagramsExpirationDuration]]
| An unrestricted double value representing the
expiration duration for outgoing datagrams (in milliseconds).
|
[[OutgoingMaxDatagramSize]]
|
An integer representing the maximum size for an outgoing datagram.
The maximum datagram size depends on the protocol that is in use.
In HTTP/3 [WEB-TRANSPORT-HTTP3], the value is related to the estimate of the
path MTU,
which is reduced by some implementation-defined amount to account for any overheads.
In HTTP/2 [WEB-TRANSPORT-HTTP2], there is no equivalent limit.
As the processing of datagrams generally involves holding the entire datagram in memory, implementations will have limits on size. A future protocol extension could enable the signaling of these size limits for all protocol variants. |
The user agent MAY update [[OutgoingMaxDatagramSize]] for any WebTransport object whose
[[State]] is either "connecting" or "connected".
WebTransportDatagramDuplexStream given a WebTransport transport, a
readable and readableType, perform the following steps.
Let stream be a new WebTransportDatagramDuplexStream, with:
[[Transport]]
transport
[[Readable]]
readable
[[ReadableType]]
readableType
[[Writables]]
an empty ordered set.
[[IncomingDatagramsQueue]]
an empty queue
[[IncomingDatagramsPullPromise]]
null
[[IncomingMaxBufferedDatagrams]]
an implementation-defined value
[[IncomingDatagramsExpirationDuration]]
null
[[OutgoingMaxBufferedDatagrams]]
an implementation-defined value
This implementation-defined value should be tuned to ensure decent throughput, without jeopardizing the timeliness of transmitted data.
[[OutgoingDatagramsExpirationDuration]]
Infinity
[[OutgoingMaxDatagramSize]]
an implementation-defined integer.
Return stream.
createWritable(options)
Creates a WebTransportDatagramsWritable. When called, the user agent MUST
run these steps:
Let transport be WebTransport object associated with this.
Let sendGroup be options’s sendGroup.
If sendGroup is not null, and
sendGroup.[[Transport]] is not
this.[[Transport]], throw
a TypeError.
If transport.[[State]] is "closed" or "failed",
throw an InvalidStateError.
Let sendOrder be options’s sendOrder.
Return the result of creating a WebTransportDatagramsWritable
with transport, sendGroup and sendOrder.
readable, of type ReadableStream, readonly
The getter steps are:
Return this.[[Readable]].
incomingMaxAge, of type unrestricted double, nullable
The getter steps are:
The setter steps, given value, are:
If value is negative or NaN, throw a RangeError.
If value is 0, set value to null.
Set this.[[IncomingDatagramsExpirationDuration]] to value.
maxDatagramSize, of type unsigned long, readonly
The maximum size data that may be passed to a WebTransportDatagramsWritable.
The getter steps are to return this.[[OutgoingMaxDatagramSize]].
outgoingMaxAge, of type unrestricted double
The getter steps are:
Return this’s [[OutgoingDatagramsExpirationDuration]].
The setter steps, given value, are:
If value is negative, 0, or NaN, throw a RangeError.
Set this.[[OutgoingDatagramsExpirationDuration]] to value.
incomingMaxBufferedDatagrams, of type unsigned long
The length of the incoming datagrams queue in number of datagrams, beyond which datagrams are dropped from the head of the queue.
Note: This differs from highWaterMark in that this queue, when full, causes datagrams to drop rather than back pressure being exerted.
The getter steps are:
Return this.[[IncomingMaxBufferedDatagrams]].
The setter steps, given value, are:
If value is < 1, set value to 1.
Set this.[[IncomingMaxBufferedDatagrams]] to value.
outgoingMaxBufferedDatagrams, of type unsigned long
The maximum length of the datagrams send queue in the underlying sink. The user agent can also limit this queue by byte length. See send queue is full.
Note: This differs from highWaterMark in that this queue resides in the underlying sink and can thus be optimized to be in another process for max throughput.
The getter steps are:
Return this.[[OutgoingMaxBufferedDatagrams]].
The setter steps, given value, are:
If value is < 1, set value to 1.
Set this.[[OutgoingMaxBufferedDatagrams]] to value.
For each writable in this.[[Writables]], if
writable’s send queue is not full,
then resolve
writable.[[BackpressurePromise]] with undefined.
WebTransport object transport, run these steps:
Let datagrams be transport.[[Datagrams]].
Assert: datagrams.[[IncomingDatagramsPullPromise]] is null.
Let queue be datagrams.[[IncomingDatagramsQueue]].
If queue is empty, then:
Set datagrams.[[IncomingDatagramsPullPromise]] to a new promise.
Return datagrams.[[IncomingDatagramsPullPromise]].
Let incoming be the result of dequeuing queue.
Let datagram be incoming[0].
If datagrams.[[ReadableType]] is "bytes", then:
If datagrams.[[Readable]]’s
current BYOB request view is not null, then:
If the size of datagram is 0, then return the result of running pullDatagrams with transport.
Let view be datagrams.[[Readable]]’s
current BYOB request view.
If view’s byte length is less than the size of datagram, return
a promise rejected with a RangeError.
Let elementSize be the element size specified in the typed array constructors table for
view.[[TypedArrayName]]. If view does not have a [[TypedArrayName]] internal slot
(i.e. it is a DataView), let elementSize be 0.
If elementSize is not 1, return a promise rejected with a TypeError.
Pull from bytes datagram into
datagrams.[[Readable]].
Otherwise:
Let chunk be a new Uint8Array object representing datagram.
Enqueue chunk to
transport.[[Datagrams]].[[Readable]].
Return a promise resolved with undefined.
WebTransport object transport, run these steps:
Let timestamp be a timestamp representing now.
Let queue be datagrams.[[IncomingDatagramsQueue]].
Let duration be datagrams.[[IncomingDatagramsExpirationDuration]].
If duration is null, then set duration to an implementation-defined value.
Let session be transport.[[Session]].
While there are available incoming datagrams on session:
Let datagram be the result of receiving a datagram with session in parallel.
Let timestamp be a timestamp representing now.
Let chunk be a (datagram, timestamp).
Enqueue chunk to queue.
Let toBeRemoved be the length of queue minus datagrams.[[IncomingMaxBufferedDatagrams]].
If toBeRemoved is positive, repeat dequeuing queue toBeRemoved (rounded down) times.
While queue is not empty:
If queue is not empty and datagrams.[[IncomingDatagramsPullPromise]] is non-null, then:
Let bytes and timestamp be the result of dequeuing queue.
Let promise be datagrams.[[IncomingDatagramsPullPromise]].
Set datagrams.[[IncomingDatagramsPullPromise]] to null.
Queue a network task with transport to run the following steps:
Let chunk be a new Uint8Array object representing bytes.
Enqueue chunk to datagrams.[[Readable]].
Resolve promise with undefined.
The user agent SHOULD run receiveDatagrams for any WebTransport object whose
[[State]] is "connected" as soon as reasonably possible whenever the algorithm can make
progress.
WebTransport InterfaceWebTransport provides an API to the underlying transport functionality
defined in [WEB-TRANSPORT-OVERVIEW].
[Exposed =(Window ,Worker ),SecureContext ]interface {WebTransport (constructor USVString ,url optional WebTransportOptions = {});options Promise <WebTransportConnectionStats >getStats (); [NewObject ]Promise <Uint8Array >exportKeyingMaterial (BufferSource ,label BufferSource ,context unsigned long );outputLength readonly attribute Promise <undefined >ready ;readonly attribute WebTransportReliabilityMode reliability ;readonly attribute WebTransportCongestionControl congestionControl ;attribute [EnforceRange ]unsigned short ?anticipatedConcurrentIncomingUnidirectionalStreams ;attribute [EnforceRange ]unsigned short ?anticipatedConcurrentIncomingBidirectionalStreams ;readonly attribute Headers ?responseHeaders ;readonly attribute DOMString protocol ;readonly attribute Promise <WebTransportCloseInfo >closed ;readonly attribute Promise <undefined >draining ;undefined close (optional WebTransportCloseInfo = {});closeInfo readonly attribute WebTransportDatagramDuplexStream datagrams ;Promise <WebTransportBidirectionalStream >createBidirectionalStream (optional WebTransportSendStreamOptions = {}); /* a ReadableStream of WebTransportBidirectionalStream objects */options readonly attribute ReadableStream incomingBidirectionalStreams ;Promise <WebTransportSendStream >createUnidirectionalStream (optional WebTransportSendStreamOptions = {}); /* a ReadableStream of WebTransportReceiveStream objects */options readonly attribute ReadableStream incomingUnidirectionalStreams ;WebTransportSendGroup createSendGroup ();static readonly attribute boolean supportsReliableOnly ; };enum {WebTransportReliabilityMode ,"pending" ,"reliable-only" , };"supports-unreliable"
A WebTransport object has the following internal slots.
| Internal Slot | Description (non-normative) |
|---|---|
[[SendStreams]]
| An ordered set of WebTransportSendStreams owned by this WebTransport.
|
[[ReceiveStreams]]
| An ordered set of WebTransportReceiveStreams owned by this
WebTransport.
|
[[IncomingBidirectionalStreams]]
| A ReadableStream consisting of WebTransportBidirectionalStream
objects.
|
[[IncomingUnidirectionalStreams]]
| A ReadableStream consisting of WebTransportReceiveStreams.
|
[[State]]
| An enum indicating the state of the transport. One of "connecting",
"connected", "draining", "closed", and "failed".
|
[[Ready]]
| A promise fulfilled when the associated WebTransport session gets established, or rejected if the establishment process failed. |
[[Reliability]]
| A WebTransportReliabilityMode indicating whether
the first hop supports unreliable (UDP) transport or whether only reliable
(TCP fallback) transport is available. Returns "pending" until a connection
has been established.
|
[[CongestionControl]]
| A WebTransportCongestionControl indicating
whether a preference for a congestion control algorithm optimized for
throughput or low latency was requested by the application and satisfied
by the user agent, or "default".
|
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]
| The number of concurrently open incoming unidirectional streams the application anticipates the server creating, or null. |
[[AnticipatedConcurrentIncomingBidirectionalStreams]]
| The number of concurrently open bidirectional streams the application anticipates the server creating, or null. |
[[ResponseHeaders]]
| A Headers object or null. Initially null.
|
[[Protocol]]
| A string indicating the application-level protocol selected by the server, if any. Initially an empty string. |
[[Closed]]
| A promise fulfilled when the associated WebTransport object is
closed gracefully, or rejected when it is closed abruptly or failed on initialization.
|
[[Draining]]
| A promise fulfilled when the associated WebTransport session starts draining. |
[[Datagrams]]
| A WebTransportDatagramDuplexStream.
|
[[Session]]
| A WebTransport session for this WebTransport object, or null.
|
[[NewConnection]]
| Either "no" or "yes-and-dedicated".
|
[[RequireUnreliable]]
| A boolean indicating whether UDP is required. |
WebTransport() constructor is invoked, the user
agent MUST run the following steps:
Let baseURL be this’s relevant settings object’s API base URL.
Let url be the URL record resulting from parsing
url with baseURL.
If url is failure, throw a SyntaxError exception.
If url’s scheme is not https, throw a SyntaxError exception.
If url’s fragment is not null, throw a SyntaxError exception.
Let newConnection be "no" if options’s
allowPooling is true; otherwise "yes-and-dedicated".
Let serverCertificateHashes be options’s
serverCertificateHashes.
If newConnection is "no" and serverCertificateHashes is not empty, then throw a
NotSupportedError exception.
Let requireUnreliable be options’s
requireUnreliable.
Let congestionControl be options’s
congestionControl.
If congestionControl is not "default", and the user agent does not support any
congestion control algorithms that optimize for congestionControl, as allowed by
[RFC9002] Section 7,
then set congestionControl to "default".
If any of the values in protocols occur more than once, fail to match
the requirements for elements that comprise the value of the negotiated
application protocol as defined by the WebTransport protocol, or have an isomorphic encoded
length of 0 or exceeding 512, throw a SyntaxError exception.
[WEB-TRANSPORT-OVERVIEW]
Section 3.1.
Let anticipatedConcurrentIncomingUnidirectionalStreams be options’s
anticipatedConcurrentIncomingUnidirectionalStreams.
Let anticipatedConcurrentIncomingBidirectionalStreams be options’s
anticipatedConcurrentIncomingBidirectionalStreams.
Let datagramsReadableType be options’s
datagramsReadableType.
Let incomingDatagrams be a new ReadableStream.
Let transport be a newly constructed WebTransport object, with:
[[SendStreams]]
an empty ordered set
[[ReceiveStreams]]
an empty ordered set
[[IncomingBidirectionalStreams]]
a new ReadableStream
[[IncomingUnidirectionalStreams]]
a new ReadableStream
[[State]]
"connecting"
[[Ready]]
a new promise
[[Reliability]]
"pending"
[[CongestionControl]]
congestionControl
[[AnticipatedConcurrentIncomingUnidirectionalStreams]]
anticipatedConcurrentIncomingUnidirectionalStreams
[[AnticipatedConcurrentIncomingBidirectionalStreams]]
anticipatedConcurrentIncomingBidirectionalStreams
[[ResponseHeaders]]
null
[[Protocol]]
an empty string
[[Closed]]
a new promise
[[Draining]]
a new promise
[[Datagrams]]
undefined
[[Session]]
null
[[NewConnection]]
newConnection
[[RequireUnreliable]]
requireUnreliable
Set transport.[[Datagrams]] to the result of creating
a WebTransportDatagramDuplexStream, with transport, incomingDatagrams and
datagramsReadableType.
Let pullDatagramsAlgorithm be an action that runs pullDatagrams with transport.
Note: Using 64 kibibytes buffers with datagrams is recommended because the effective maximum WebTransport datagram frame size has an upper bound of the QUIC maximum datagram frame size which is recommended to be 64 kibibytes (See [QUIC-DATAGRAM] Section 3). This will ensure the stream is not errored due to a datagram being larger than the buffer.
If datagramsReadableType is "bytes", set up with byte reading support
incomingDatagrams with pullAlgorithm set
to pullDatagramsAlgorithm, and highWaterMark
set to 0. Otherwise, set up incomingDatagrams with
pullAlgorithm set to pullDatagramsAlgorithm, and
highWaterMark set to 0.
Let pullBidirectionalStreamAlgorithm be an action that runs pullBidirectionalStream with transport.
Set up transport.[[IncomingBidirectionalStreams]] with
pullAlgorithm set to pullBidirectionalStreamAlgorithm, and
highWaterMark set to 0.
Let pullUnidirectionalStreamAlgorithm be an action that runs pullUnidirectionalStream with transport.
Set up transport.[[IncomingUnidirectionalStreams]] with
pullAlgorithm set to pullUnidirectionalStreamAlgorithm, and
highWaterMark set to 0.
Let client be transport’s relevant settings object.
Let origin be client’s origin.
Let request be a new request whose URL is url, client is
client, service-workers mode is "none",
referrer is "no-referrer", mode is "webtransport",
credentials mode is "omit", cache mode is "no-store",
policy container is client’s
policy container, destination is "",
origin is origin, WebTransport-hash list is
serverCertificateHashes and redirect mode is "error".
Note: Redirects are not followed. Network errors caused by redirection are intentionally indistinguishable from other network errors. In cross-origin contexts, this would reveal information that would normally be blocked by CORS. In same-origin contexts, it might encourage applications to abuse the handshake as a vector for passing information.
Set request’s method to "CONNECT", and set the method’s associated
:protocol pseudo-header to "webtransport".
Let headers be a new Headers object filled with
options["headers"].
Let requestHeaders be a new Headers object whose header list is
request’s header list and guard is "request".
For each header of headers’s header list:
If ascii lowercase header’s name is "wt-available-protocols",
then throw a TypeError.
append header to requestHeaders.
Note: Headers are subject to Fetch’s forbidden request-header restrictions.
If protocols is not empty, set a structured field value with
(WT-Available-Protocols, a
structured header list whose members are the
structured header string items in protocols in order) in request’s
header list.
Fetch request, with useParallelQueue set to true, and processResponse set to the following steps given a response:
Process a WebTransport fetch response with response and transport.
Return transport.
Let transport be the WebTransport object associated with request.
Let url be request’s current URL.
Let newConnection be transport.[[NewConnection]].
Assert: newConnection is not "no", or networkPartitionKey[1] is neither
null nor a fixed value.
Fetch currently allows networkPartitionKey[1] to be null. See whatwg/fetch#1926.
Let requireUnreliable be transport.[[RequireUnreliable]].
Let webTransportHashes be the values in request’s WebTransport-hash list.
Let connection be the result of obtaining a connection with networkPartitionKey, url, false, newConnection, requireUnreliable and webTransportHashes.
If connection is failure, return failure.
Wait for connection to receive the first SETTINGS frame, and let settings be a dictionary that represents the SETTINGS frame.
If settings doesn’t contain SETTINGS_ENABLE_CONNECT_PROTOCOL (0x08, see
Section 3 of [RFC8441] for
HTTP/2; 0x08, see Section 3 of
[RFC9220]) with a value of 1, then return failure.
If settings doesn’t indicate server support for WebTransport, then return failure. [WEB-TRANSPORT-OVERVIEW] Section 4.1.
Over HTTP/3, support requires SETTINGS_WT_ENABLED with a value above 0,
and SETTINGS_H3_DATAGRAM with a value of 1. [WEB-TRANSPORT-HTTP3]
Section 3.1.
Over HTTP/2, potential support is already indicated by SETTINGS_ENABLE_CONNECT_PROTOCOL above.
[WEB-TRANSPORT-HTTP2]
Section 3.1.
Return connection.
WebTransport
transport, run these steps:
If response is network error, then abort the remaining steps and queue a network task with transport to run these steps:
If transport.[[State]] is "closed" or "failed", then abort these steps.
Let error be a newly created WebTransportError whose
source is "session".
Cleanup transport with error.
Let connection be the underlying connection associated with response.
Follow any restrictions in [WEB-TRANSPORT-OVERVIEW] Section 4.1 to establish a WebTransport session on connection using the server’s response, and let session be the resulting WebTransport session. The resulting underlying transport stream is referred to as the session’s CONNECT stream.
Note: This step also concludes the transport parameter exchange specified in [QUIC-DATAGRAM].
If the previous step fails, abort the remaining steps and queue a network task with transport to run these steps:
If transport.[[State]] is "closed" or "failed", then abort these steps.
Let error be a newly created WebTransportError whose
source is "session".
Cleanup transport with error.
If the user agent supports more than one congestion control algorithm, choose one
appropriate for transport’s [[CongestionControl]] for sending of data on this connection.
Queue a network task with transport to run these steps:
Assert: this’s [[Datagrams]]’s [[OutgoingMaxDatagramSize]] is an integer.
If transport.[[State]] is not "connecting":
In parallel, terminate session.
Abort these steps.
Set transport.[[State]] to "connected".
Set transport.[[Session]] to session.
Let responseHeaders be a copy of response’s header list.
Delete "wt-protocol" from responseHeaders.
Set transport.[[ResponseHeaders]] to a new Headers object, whose
header list is responseHeaders and guard is "immutable".
Set transport.[[Protocol]] to either the string value of the negotiated application
protocol if present, following [WEB-TRANSPORT-OVERVIEW]
Section 3.1,
or "" if not present.
If the connection is an HTTP/3 connection, set transport.[[Reliability]] to "supports-unreliable".
If the connection is an HTTP/2 connection [WEB-TRANSPORT-HTTP2], set transport’s [[Reliability]] to "reliable-only".
WebTransport object transport, run
these steps.
If transport.[[State]] is "connecting", then return the result of performing the
following steps upon fulfillment of transport.[[Ready]]:
Return the result of pullBidirectionalStream with transport.
If transport.[[State]] is not "connected", then return a new rejected promise with
an InvalidStateError.
Let session be transport.[[Session]].
Let p be a new promise.
Run the following steps in parallel:
Wait until there is an available incoming bidirectional stream in session.
Let internalStream be the result of receiving a bidirectional stream from session.
Queue a network task with transport to run these steps:
Let stream be the result of creating a
WebTransportBidirectionalStream with internalStream and transport.
Enqueue stream to transport.[[IncomingBidirectionalStreams]].
Resolve p with undefined.
Return p.
WebTransport object transport, run
these steps.
If transport.[[State]] is "connecting", then return the result of performing the
following steps upon fulfillment of transport.[[Ready]]:
Return the result of pullUnidirectionalStream with transport.
If transport.[[State]] is not "connected", then return a new rejected promise with
an InvalidStateError.
Let session be transport.[[Session]].
Let p be a new promise.
Run the following steps in parallel:
Wait until there is an available incoming unidirectional stream in session.
Let internalStream be the result of receiving an incoming unidirectional stream from session.
Queue a network task with transport to run these steps:
Let stream be the result of creating a WebTransportReceiveStream with
internalStream and transport.
Enqueue stream to transport.[[IncomingUnidirectionalStreams]].
Resolve p with undefined.
Return p.
ready, of type Promise<undefined>, readonly
closed, of type Promise<WebTransportCloseInfo>, readonly
On getting, it MUST return this’s [[Closed]].
draining, of type Promise<undefined>, readonly
On getting, it MUST return this’s [[Draining]].
datagrams, of type WebTransportDatagramDuplexStream, readonly
A single duplex stream for sending and receiving datagrams over this session.
The getter steps for the datagrams attribute SHALL be:
Return this’s [[Datagrams]].
incomingBidirectionalStreams, of type ReadableStream, readonly
Returns a ReadableStream of WebTransportBidirectionalStreams that have been
received from the server.
Note: Whether the incoming streams already have data on them will depend on server behavior.
The getter steps for the incomingBidirectionalStreams attribute SHALL be:
Return this’s [[IncomingBidirectionalStreams]].
incomingUnidirectionalStreams, of type ReadableStream, readonly
A ReadableStream of unidirectional streams, each represented by a
WebTransportReceiveStream, that have been received from the server.
Note: Whether the incoming streams already have data on them will depend on server behavior.
The getter steps for incomingUnidirectionalStreams are:
reliability, of type WebTransportReliabilityMode, readonly
Whether connection supports unreliable (over UDP) transport or only reliable
(over TCP fallback) transport.
Returns "pending" until a connection has been established.
The getter steps are to return this’s [[Reliability]].
congestionControl, of type WebTransportCongestionControl, readonly
The application’s preference, if requested in the constructor, and satisfied
by the user agent, for a congestion control algorithm optimized for either
throughput or low latency for sending on this connection. If a preference was
requested but not satisfied, then the value is "default"
The getter steps are to return this’s [[CongestionControl]].
supportsReliableOnly, of type boolean, readonly
Returns true if the user agent supports WebTransport sessions over exclusively reliable connections, otherwise false.
anticipatedConcurrentIncomingUnidirectionalStreams, of type unsigned short, nullable
Optionally lets an application specify the number of concurrently open
incoming unidirectional streams it anticipates the server creating.
If not null, the user agent SHOULD attempt to reduce future round-trips by taking
[[AnticipatedConcurrentIncomingUnidirectionalStreams]] into consideration in its
negotiations with the server.
The getter steps are to return this’s [[AnticipatedConcurrentIncomingUnidirectionalStreams]].
The setter steps, given value, are to set this’s
[[AnticipatedConcurrentIncomingUnidirectionalStreams]] to value.
anticipatedConcurrentIncomingBidirectionalStreams, of type unsigned short, nullable
Optionally lets an application specify the number of concurrently open
bidirectional streams it anticipates the server creating.
If not null, the user agent SHOULD attempt to reduce future round-trips by taking
[[AnticipatedConcurrentIncomingBidirectionalStreams]] into consideration in its
negotiations with the server.
The getter steps are to return this’s [[AnticipatedConcurrentIncomingBidirectionalStreams]].
The setter steps, given value, are to set this’s
[[AnticipatedConcurrentIncomingBidirectionalStreams]] to value.
Note: Setting anticipatedConcurrentIncomingUnidirectionalStreams or
anticipatedConcurrentIncomingBidirectionalStreams does not guarantee
the application will receive the number of streams it anticipates.
responseHeaders, of type Headers, readonly, nullable
Once a WebTransport session has been established, holds the application-level
response headers set by the server, if any. Initially null.
The getter steps are to return this’s [[ResponseHeaders]].
protocol, of type DOMString, readonly
Once a WebTransport session has been established and the protocols
constructor option was used to provide a non-empty array, returns the application-level protocol
selected by the server, if any. Otherwise, an empty string.
The getter steps are to return this’s [[Protocol]].
close(closeInfo)
Terminates the WebTransport session associated with the WebTransport object. When called, the user agent MUST run these steps:
Let transport be this.
If transport.[[State]] is "closed" or "failed", then abort these steps.
If transport.[[State]] is "connecting":
Let error be a newly created WebTransportError whose
source is "session".
Cleanup transport with error.
Abort these steps.
Let session be transport.[[Session]].
Let code be closeInfo.closeCode.
Let reasonString be the maximal code unit prefix of
closeInfo.reason where the length of the
UTF-8 encoded prefix doesn’t exceed 1024.
Let reason be reasonString, UTF-8 encoded.
In parallel, terminate session with code and reason.
Note: This also aborts sending or aborts receiving on WebTransport streams contained in
transport.[[SendStreams]] and [[ReceiveStreams]].
Cleanup transport with AbortError and closeInfo.
getStats()
Gathers stats for this WebTransport’s underlying connection
and reports the result asynchronously.
When called, the user agent MUST run these steps:
Let transport be this.
Let p be a new promise.
If transport.[[State]] is "failed", reject p with an
InvalidStateError and abort these steps.
Run the following steps in parallel:
If transport.[[State]] is "connecting", wait until it changes.
If transport.[[State]] is "failed", abort these steps after
queueing a network task with transport to reject p with an
InvalidStateError.
If transport.[[State]] is "closed", abort these steps after
queueing a network task with transport to resolve p with
the most recent stats available for the connection. The exact point
at which those stats are collected is implementation-defined.
Let gatheredStats be the list of stats specific to the
underlying connection needed to populate the
dictionary members of WebTransportConnectionStats and
WebTransportDatagramStats accurately.
If transport.[[NewConnection]] is "no", then remove from
gatheredStats all stats not marked as pooled connection stats.
Queue a network task with transport to run the following steps:
Let stats be a new WebTransportConnectionStats object.
Let datagramStats be a new WebTransportDatagramStats object.
Set stats["datagrams"] to datagramStats.
For each member member of stats and datagramStats that the user agent chooses to expose, set member to the corresponding entry in gatheredStats.
Resolve p with stats.
Return p.
exportKeyingMaterial(BufferSource label, BufferSource context, unsigned long outputLength)
Exports keying material from a TLS Keying Material Exporter
that is derived from the TLS connection
and uniquely associated with this WebTransport session.
When called, the user agent MUST run these steps:
Let labelLength be label.byte length.
If labelLength is more than 255, return a promise rejected with a RangeError.
Let contextLength be context.byte length.
If contextLength is more than 255, return a promise rejected with a RangeError.
If outputLength is 0 or more than an implementation-defined value—which must be at least 4096—return a promise rejected with a RangeError.
If this.[[State]] is "closed" or "failed",
return a promise rejected with an InvalidStateError.
Let transport be this.
Let p be a new promise.
Run the following steps in parallel, but abort when transport’s
[[State]] becomes "closed" or "failed", and instead
queue a network task with transport to reject p with an InvalidStateError:
Let keyingMaterial be a Uint8Array that is produced by invoking a TLS key exporter,
following the process defined
in [WEB-TRANSPORT-OVERVIEW] Section 4.1
and the WebTransport protocol binding in use,
passing label, context, and outputLength.
Note: The process for generating the context that is passed to the TLS exporter interface could vary based on the HTTP version. HTTP/3 connections (Section 4.8 of [WEB-TRANSPORT-HTTP3]) and HTTP/2 connections (Section 5.3 of [WEB-TRANSPORT-HTTP2]) happen to use an identical construction, with only minor differences in how sessions are identified. Other WebTransport mappings could define a different process.
Queue a network task with transport to resolve p with keyingMaterial.
Return p.
createBidirectionalStream(options)
Creates a WebTransportBidirectionalStream object for an outgoing bidirectional
stream. Note that the mere creation of a stream is not immediately visible to the peer until
it is used to send data.
Note: There is no expectation that the server will be aware of the stream until data is sent on it.
When called, the user agent MUST run these steps:
Let sendGroup be options’s
sendGroup.
If sendGroup is not null, and sendGroup.[[Transport]]
is not this, return a promise rejected with a TypeError.
If this.[[State]] is "closed" or "failed",
return a promise rejected with an InvalidStateError.
Let sendOrder be options’s
sendOrder.
Let waitUntilAvailable be options’s
waitUntilAvailable.
Let p be a new promise.
Let transport be this.
Run the following steps in parallel, but abort when transport’s
[[State]] becomes "closed" or "failed", and instead
queue a network task with transport to reject p with an InvalidStateError:
Let streamId be a new stream ID that is valid and unique for
transport.[[Session]], as defined in [QUIC]
Section 19.11. If one is not
immediately available due to exhaustion, either wait for it to become
available if waitUntilAvailable is true, or if waitUntilAvailable is false,
abort these steps after queueing a network task with transport to reject p
with a QuotaExceededError whose requested and quota
are both null.
Let internalStream be the result of creating a bidirectional stream with
transport.[[Session]] and streamId.
Queue a network task with transport to run the following steps:
If transport.[[State]] is "closed" or "failed",
reject p with an InvalidStateError and abort these steps.
Let stream be the result of creating a
WebTransportBidirectionalStream with internalStream, transport, sendGroup, and sendOrder.
Resolve p with stream.
Return p.
createUnidirectionalStream(options)
Creates a WebTransportSendStream for an outgoing unidirectional stream. Note
that the mere creation of a stream is not immediately visible to the server until it is used
to send data.
Note: There is no expectation that the server will be aware of the stream until data is sent on it.
When called, the user agent MUST run these steps:
Let sendGroup be options’s
sendGroup.
If sendGroup is not null, and
sendGroup.[[Transport]] is not this,
return a promise rejected with a TypeError.
If this.[[State]] is "closed" or "failed",
return a promise rejected with an InvalidStateError.
Let sendOrder be options’s
sendOrder.
Let waitUntilAvailable be options’s
waitUntilAvailable.
Let p be a new promise.
Let transport be this.
Run the following steps in parallel, but abort when transport’s
[[State]] becomes "closed" or "failed", and instead
queue a network task with transport to reject p with an InvalidStateError:
Let streamId be a new stream ID that is valid and unique for
transport.[[Session]], as defined in [QUIC]
Section 19.11. If one is not
immediately available due to exhaustion, either wait for it to become
available if waitUntilAvailable is true, or if waitUntilAvailable is false,
abort these steps after queueing a network task with transport to reject p
with a QuotaExceededError.
Let internalStream be the result of creating an outgoing unidirectional stream with
transport.[[Session]] and streamId.
Queue a network task with transport to run the following steps:
If transport.[[State]] is "closed" or "failed",
reject p with an InvalidStateError and abort these steps.
Let stream be the result of creating a WebTransportSendStream with
internalStream, transport, sendGroup, and sendOrder.
Resolve p with stream.
return p.
createSendGroup()
Creates a WebTransportSendGroup.
createSendGroup() method is called, the user agent MUST
run the following steps:
If this.[[State]] is "closed" or "failed",
throw an InvalidStateError.
Return the result of creating a WebTransportSendGroup with this.
WebTransport transport with error and
optionally closeInfo, run these steps:
Let sendStreams be a copy of transport.[[SendStreams]].
Let receiveStreams be a copy of transport.[[ReceiveStreams]].
Let outgoingDatagramWritables be transport.[[Datagrams]].[[Writables]].
Let incomingDatagrams be transport.[[Datagrams]].[[Readable]].
Let ready be transport.[[Ready]].
Let closed be transport.[[Closed]].
Let incomingBidirectionalStreams be transport.[[IncomingBidirectionalStreams]].
Let incomingUnidirectionalStreams be transport.[[IncomingUnidirectionalStreams]].
Set transport.[[SendStreams]] to an empty set.
Set transport.[[ReceiveStreams]] to an empty set.
Set transport.[[Datagrams]].[[Writables]]
to an empty set.
For each writable in outgoingDatagramWritables:
Set writable.[[OutgoingDatagramsQueue]] to an
empty queue.
Resolve writable.[[BackpressurePromise]]
with undefined.
Set transport.[[Datagrams]].[[IncomingDatagramsQueue]]
to an empty queue.
If closeInfo is given, then set transport.[[State]] to "closed".
Otherwise, set transport.[[State]] to "failed".
For each stream in sendStreams, run the following steps:
If stream.[[PendingOperation]] is not null, reject stream.[[PendingOperation]]
with error.
Error stream with error.
For each writable in outgoingDatagramWritables, error writable with error.
Note: Script authors can inject code which runs in Promise resolution synchronously. Hence from here, do not touch transport as it may be mutated by scripts in an unpredictable way. This applies to logic calling this procedure, too.
If closeInfo is given, then:
Otherwise:
To queue a network task with a WebTransport transport and a
series of steps steps, run these steps:
Queue a global task on the network task source with transport’s relevant global object to run steps.
WebTransport transport is
terminated with optionally code and reasonBytes, run these steps:
Queue a network task with transport to run these steps:
If transport.[[State]] is "closed" or "failed", abort these steps.
Let error be a newly created WebTransportError whose
source is "session".
Let closeInfo be a new WebTransportCloseInfo.
If code is given, set closeInfo’s closeCode to code.
If reasonBytes is given, set closeInfo’s reason to reasonBytes,
UTF-8 decoded.
Note: No language or direction metadata is available with reasonBytes. First-strong heuristics can be used for direction when displaying the value.
Cleanup transport with error and closeInfo.
WebTransport transport’s underlying connection gets a connection error,
run these steps:
Queue a network task with transport to run these steps:
If transport.[[State]] is "closed" or "failed", abort these steps.
Let error be a newly created WebTransportError whose
source is "session".
Cleanup transport with error.
WebTransport transport:
If transport.[[State]] is "connected", then:
Set transport.[[State]] to "failed".
In parallel, terminate transport.[[Session]].
Queue a network task with transport to run the following steps:
Let error be a newly created WebTransportError whose
source is "session".
Cleanup transport with error.
If transport.[[State]] is "connecting", set transport.[[State]] to
"failed".
This needs to be done in workers too. See #127 and whatwg/html#6731.
A WebTransport object whose [[State]] is "connecting" must not be garbage collected if
[[IncomingBidirectionalStreams]], [[IncomingUnidirectionalStreams]], any
WebTransportReceiveStream, or [[Datagrams]].[[Readable]]
are locked, or if the ready, draining, or closed promise is being observed.
A WebTransport object whose [[State]] is "connected" must not be garbage collected if
[[IncomingBidirectionalStreams]], [[IncomingUnidirectionalStreams]], any
WebTransportReceiveStream, or [[Datagrams]].[[Readable]]
are locked, or if the draining or closed promise is being observed.
A WebTransport object whose [[State]] is "draining" must not be garbage collected if
[[IncomingBidirectionalStreams]], [[IncomingUnidirectionalStreams]], any
WebTransportReceiveStream, or [[Datagrams]].[[Readable]]
are locked, or if the closed promise is being observed.
A WebTransport object with an established WebTransport session
that has data queued to be transmitted to the network, must not be garbage collected.
If a WebTransport object is garbage collected while the underlying connection
is still open, the user agent must
terminate the WebTransport session
with an Application Error Code of 0 and Application Error Message of "".
dictionary {WebTransportHash required DOMString ;algorithm required BufferSource ; };value dictionary WebTransportOptions {boolean allowPooling =false ;boolean requireUnreliable =false ;HeadersInit headers = {};sequence <WebTransportHash >serverCertificateHashes = [];WebTransportCongestionControl congestionControl = "default"; [EnforceRange ]unsigned short ?anticipatedConcurrentIncomingUnidirectionalStreams =null ; [EnforceRange ]unsigned short ?anticipatedConcurrentIncomingBidirectionalStreams =null ;sequence <DOMString >protocols = [];ReadableStreamType datagramsReadableType ; };enum {WebTransportCongestionControl ,"default" ,"throughput" , };"low-latency"
WebTransportOptions is a dictionary of parameters
that determine how the WebTransport session is established and used.
allowPooling, of type boolean, defaulting to false
When set to true, the WebTransport session can be pooled, that is, its underlying connection can be shared with other WebTransport sessions.
requireUnreliable, of type boolean, defaulting to false
When set to true, the WebTransport session cannot be established over an HTTP/2 connection if an HTTP/3 connection is not possible.
headers, of type HeadersInit, defaulting to {}
Optionally, a Headers object, an object literal, or an array of two-item arrays
to set the request header list to use when establishing
a WebTransport session.
serverCertificateHashes, of type sequence<WebTransportHash>, defaulting to []
This option is only supported for transports using dedicated connections.
For transport protocols that do not support this feature, having this
field non-empty SHALL result in a NotSupportedError exception being thrown.
If supported and non-empty, the user agent SHALL deem a server certificate
trusted if and only if it can successfully verify a certificate hash against
serverCertificateHashes
and satisfies custom certificate requirements. The user agent SHALL
ignore any hash that uses an unknown algorithm.
If empty, the user agent SHALL use certificate verification
procedures it would use for normal fetch operations.
This cannot be used with allowPooling.
congestionControl, of type WebTransportCongestionControl, defaulting to "default"
Optionally specifies an application’s preference for a congestion control algorithm tuned for either throughput or low-latency to be used when sending data over this connection. This is a hint to the user agent.
anticipatedConcurrentIncomingUnidirectionalStreams, of type unsigned short, nullable, defaulting to null
Optionally lets an application specify the number of concurrently open
incoming unidirectional streams it anticipates the server creating.
The user agent MUST initially allow at least 100 incoming unidirectional
streams from the server.
If not null, the user agent SHOULD attempt to reduce round-trips by taking
[[AnticipatedConcurrentIncomingUnidirectionalStreams]] into consideration in its
negotiations with the server.
anticipatedConcurrentIncomingBidirectionalStreams, of type unsigned short, nullable, defaulting to null
Optionally lets an application specify the number of concurrently open
bidirectional streams it anticipates a server creating.
The user agent MUST initially allow the server to create at least 100
bidirectional streams.
If not null, the user agent SHOULD attempt to reduce round-trips by taking
[[AnticipatedConcurrentIncomingBidirectionalStreams]] into consideration in its
negotiations with the server.
protocols, of type sequence<DOMString>, defaulting to []
An optionally provided array of application-level protocol names. Selecting a preferred application-protocol and communicating it to the client is optional for the server. Servers might reject the request if a suitable protocol was not provided.
datagramsReadableType, of type ReadableStreamType
Optionally specifies an application’s preference for using a readable byte stream for incoming datagrams. Otherwise, a default readable stream is used.
Note: While readable stream is compatible with datagram semantics,
readable byte stream is not. Datagrams are differentiated messages
of zero or more bytes, that can arrive out of order, not an undifferentiated
byte sequence. A BYOB reader omits empty datagrams, and
min loses message delineation.
Let cert be certificate, represented as a DER encoding of Certificate message defined in [RFC5280].
Compute the SHA-256 hash of cert and return the computed value.
Let certificate be the first certificate in certificate chain (the leaf certificate).
Let referenceHash be the result of computing a certificate hash with certificate.
For every hash hash in hashes:
If hash.value is not null and hash.algorithm
is an ASCII case-insensitive match with "sha-256":
Let hashValue be the byte sequence which hash.value represents.
If hashValue is equal to referenceHash, return true.
Return false.
The custom certificate requirements are as follows: the certificate MUST be an X.509v3 certificate as defined in [RFC5280], the key used in the Subject Public Key field MUST be one of the allowed public key algorithms, the current time MUST be within the validity period of the certificate as defined in Section 4.1.2.5 of [RFC5280] and the total length of the validity period MUST NOT exceed two weeks. The user agent MAY impose additional implementation-defined requirements on the certificate.
The exact list of allowed public key algorithms used in the Subject Public Key Info field (and, as a consequence, in the TLS CertificateVerify message) is implementation-defined; however, it MUST include ECDSA with the secp256r1 (NIST P-256) named group ([RFC3279], Section 2.3.5; [RFC9846]) to provide an interoperable default. It MUST NOT contain RSA keys ([RFC3279], Section 2.3.1).
WebTransportCloseInfo DictionaryThe WebTransportCloseInfo dictionary includes information
used to set the error code and reason when terminating
a WebTransport session.
dictionary WebTransportCloseInfo {unsigned long closeCode = 0;USVString reason = ""; };
The dictionary SHALL have the following attributes:
closeCode, of type unsigned long, defaulting to 0
The error code communicated to the peer.
reason, of type USVString, defaulting to ""
The reason for closing the WebTransport.
WebTransportSendOptions DictionaryThe WebTransportSendOptions is a
base dictionary of parameters that affect how createUnidirectionalStream,
createBidirectionalStream, and the
createWritable methods behave.
dictionary WebTransportSendOptions {WebTransportSendGroup ?sendGroup =null ;long long sendOrder = 0; };
The dictionary SHALL have the following attributes:
sendGroup, of type WebTransportSendGroup, nullable, defaulting to null
An optional WebTransportSendGroup to group the
created stream under, or null.
sendOrder, of type long long, defaulting to 0
A send order number that, if provided, opts the created stream in to participating in strict ordering. Bytes currently queued on strictly ordered streams will be sent ahead of bytes currently queued on other strictly ordered streams created with lower send order numbers.
If no send order number is provided, then the order in which the user agent sends bytes from it relative to other streams is implementation-defined. User agents are strongly encouraged however to divide bandwidth fairly between all streams that aren’t starved by lower send order numbers.
Note: This is sender-side data prioritization which does not guarantee reception order.
WebTransportSendStreamOptions DictionaryThe WebTransportSendStreamOptions is a
dictionary of parameters that affect how WebTransportSendStreams created by
createUnidirectionalStream and
createBidirectionalStream behave.
dictionary WebTransportSendStreamOptions :WebTransportSendOptions {boolean waitUntilAvailable =false ; };
The dictionary SHALL have the following attributes:
waitUntilAvailable, of type boolean, defaulting to false
If true, the promise returned by the
createUnidirectionalStream or
createBidirectionalStream call will not be settled
until either the underlying connection has sufficient flow control
credit to create the stream, or the connection reaches a state in which no
further outgoing streams are possible. If false, the promise will be
rejected if no flow control window is available at the time of the call.
WebTransportConnectionStats DictionaryThe WebTransportConnectionStats dictionary includes information
about the WebTransport session’s underlying connection. Members of
WebTransportConnectionStats that are not marked as a
pooled connection stat are absent for
underlying connections that are subject to pooling.
A user agent can withhold stats members, e.g. for privacy. It
chooses to expose a stats dictionary member if it makes this
choice once per WebTransport session, not per call. So a member present in
one getStats() result won’t disappear from later results in the same session.
Note: When pooling is allowed, only pooled connection stats are revealed, and multiple WebTransport sessions pooled on the same connection all receive the same information, i.e. the information is disclosed across pooled sessions holding the same network partition key.
Note: Any unavailable stats will be absent from the WebTransportConnectionStats dictionary.
dictionary WebTransportConnectionStats {unsigned long long bytesSent ;unsigned long long bytesSentOverhead ;unsigned long long bytesAcknowledged ;unsigned long long packetsSent ;unsigned long long bytesLost ;unsigned long long packetsLost ;unsigned long long bytesReceived ;unsigned long long packetsReceived ;DOMHighResTimeStamp smoothedRtt ;DOMHighResTimeStamp rttVariation ;DOMHighResTimeStamp minRtt ;required WebTransportDatagramStats ;datagrams unsigned long long ?estimatedSendRate =null ;boolean atSendCapacity =false ; };
The dictionary SHALL have the following attributes:
bytesSent, of type unsigned long long
The number of payload bytes sent over the underlying connection, excluding any framing overhead or retransmissions.
bytesSentOverhead, of type unsigned long long
The framing and retransmission overhead in bytes of sending
bytesSent number of payload bytes on the
underlying connection.
bytesAcknowledged, of type unsigned long long
The number of payload bytes acknowledged as received by the server using QUIC’s ACK mechanism on the underlying connection. Excludes any framing.
Note: Typically trails bytesSent but can be permanently less due to packet loss.
bytesAcknowledged on WebTransportConnectionStats has been identified
by the Working Group as a feature at risk due to concerns over implementability.
packetsSent, of type unsigned long long
The number of packets sent on the underlying connection, including those that are determined to have been lost.
bytesLost, of type unsigned long long
The number of bytes lost on the underlying connection (does not monotonically increase, because packets that are declared lost can subsequently be received). Does not include UDP or any other outer framing.
packetsLost, of type unsigned long long
The number of packets lost on the underlying connection (does not monotonically increase, because packets that are declared lost can subsequently be received).
bytesReceived, of type unsigned long long
The number of total bytes received on the underlying connection, including duplicate data for streams. Does not include UDP or any other outer framing.
packetsReceived, of type unsigned long long
The number of total packets received on the underlying connection, including packets that were not processable.
smoothedRtt, of type DOMHighResTimeStamp
The smoothed round-trip time (RTT) currently observed on the connection, as defined in [RFC9002] Section 5.3. This is a pooled connection stat.
rttVariation, of type DOMHighResTimeStamp
The mean variation in round-trip time samples currently observed on the connection, as defined in [RFC9002] Section 5.3. This is a pooled connection stat.
minRtt, of type DOMHighResTimeStamp
The minimum round-trip time observed on the entire connection, as defined in [RFC9002] Section 5.2. This is a pooled connection stat.
estimatedSendRate, of type unsigned long long, nullable, defaulting to null
The estimated rate at which queued data will be sent by the user agent, in bits per second.
This rate applies to all streams and datagrams that share a WebTransport session
and is calculated by the congestion control algorithm (potentially chosen by
congestionControl). This estimate excludes any framing overhead and
represents the rate at which an application payload might be sent. If the user agent
does not currently have an estimate, the member MUST be the null value.
The member can be null even if it was not null in previous results.
This is a pooled connection stat.
atSendCapacity, of type boolean, defaulting to false
A value of false indicates the estimatedSendRate might be application limited,
meaning the application is sending significantly less data than the congestion
controller allows. A congestion controller might produce a poor estimate of the
available network capacity while it is application limited.
A value of true indicates the application is sending data at network
capacity, and the estimatedSendRate reflects the network capacity available
to the application.
atSendCapacity is true, the estimatedSendRate reflects a ceiling.
As long as the application send rate is sustained, the estimatedSendRate will adapt
to network conditions. However, estimatedSendRate is allowed to be null while
atSendCapacity is true.
WebTransportDatagramStats DictionaryThe WebTransportDatagramStats dictionary includes statistics
on datagram transmission over the underlying connection.
dictionary WebTransportDatagramStats {unsigned long long droppedIncoming ;unsigned long long expiredIncoming ;unsigned long long expiredOutgoing ;unsigned long long lostOutgoing ; };
The dictionary SHALL have the following attributes:
droppedIncoming, of type unsigned long long
The number of incoming datagrams that were dropped due to the application not reading
from datagrams' readable
before new datagrams overflow the receive queue.
expiredIncoming, of type unsigned long long
The number of incoming datagrams that were dropped due to being older than
incomingMaxAge before they were read from datagrams'
readable.
expiredOutgoing, of type unsigned long long
The number of datagrams queued for sending that were dropped due to being
older than outgoingMaxAge before they were able to be sent.
lostOutgoing, of type unsigned long long
The number of sent datagrams that were declared lost, as defined in [RFC9002] Section 6.1.
WebTransportSendStreamA WebTransportSendStream is a WritableStream providing outgoing streaming
features with an outgoing unidirectional or bidirectional
WebTransport stream.
It is a WritableStream of Uint8Array that can be written to, to send
data to the server.
[Exposed =(Window ,Worker ),SecureContext ,Transferable ]interface :WebTransportSendStream WritableStream {attribute WebTransportSendGroup ?sendGroup ;attribute long long sendOrder ;Promise <WebTransportSendStreamStats >getStats ();WebTransportWriter getWriter (); };
A WebTransportSendStream is always created by the
create procedure.
The WebTransportSendStream’s transfer steps and
transfer-receiving steps are
those of WritableStream.
sendGroup, of type WebTransportSendGroup, nullable
The getter steps are:
Return this’s [[SendGroup]].
The setter steps, given value, are:
If value is non-null, and
value.[[Transport]] is not
this.[[Transport]], throw
an InvalidStateError.
Set this.[[SendGroup]] to value.
sendOrder, of type long long
The getter steps are:
Return this’s [[SendOrder]].
The setter steps, given value, are:
Set this.[[SendOrder]] to value.
getStats()
Gathers stats specific to this WebTransportSendStream’s performance,
and reports the result asynchronously.
When called, the user agent MUST run these steps:
Let transport be this.[[Transport]].
Let p be a new promise.
Run the following steps in parallel:
Let gatheredStats be the list of stats specific to this
WebTransportSendStream needed to populate the
dictionary members of WebTransportSendStreamStats accurately.
Queue a network task with transport to run the following steps:
Let stats be a new WebTransportSendStreamStats object.
For each member member of stats that the user agent chooses to expose, set member to the corresponding entry in gatheredStats.
Resolve p with stats.
Return p.
getWriter()
Creates a WebTransportWriter for this stream.
When getWriter is called, return the result of
creating a WebTransportWriter with this.
A WebTransportSendStream has the following internal slots.
| Internal Slot | Description (non-normative) |
|---|---|
[[InternalStream]]
| An outgoing unidirectional or bidirectional WebTransport stream. |
[[PendingOperation]]
| A promise representing a pending write or close operation, or null. |
[[Transport]]
| The WebTransport that owns this WebTransportSendStream.
|
[[SendGroup]]
| An optional WebTransportSendGroup, or null.
|
[[SendOrder]]
| An optional send order number, defaulting to 0. |
[[AtomicWriteRequests]]
| An ordered set of promises, keeping track of the subset of write requests that are atomic among those queued to be processed by the underlying sink. |
[[InsideSynchronousAtomicWrite]]
| A boolean set to true only while inside the synchronous part of
the atomicWrite method.
|
[[BytesWritten]]
| The number of bytes that have been written to the stream. |
[[CommittedOffset]]
| An offset in the stream that records the number of bytes that will be delivered to a peer, even when the stream has aborted sending; see [RELIABLE-RESET]. |
To create a
WebTransportSendStream, with an outgoing unidirectional or bidirectional WebTransport stream
internalStream, a WebTransport transport, sendGroup, and a
sendOrder, run these steps:
Let stream be a new WebTransportSendStream, with:
[[InternalStream]]
internalStream
[[PendingOperation]]
null
[[Transport]]
transport
[[SendGroup]]
sendGroup
[[SendOrder]]
sendOrder
[[AtomicWriteRequests]]
An empty ordered set of promises
[[InsideSynchronousAtomicWrite]]
false
[[BytesWritten]]
0
[[CommittedOffset]]
0
Let writeAlgorithm be an action that writes chunk to stream, given chunk.
Let closeAlgorithm be an action that closes stream.
Let abortAlgorithm be an action that aborts stream with reason, given reason.
Set up stream with writeAlgorithm set to writeAlgorithm, closeAlgorithm set to closeAlgorithm, abortAlgorithm set to abortAlgorithm.
Let abortSignal be stream’s [[controller]].[[abortController]].[[signal]].
Add the following steps to abortSignal.
Let pendingOperation be stream.[[PendingOperation]].
If pendingOperation is null, then abort these steps.
Set stream.[[PendingOperation]] to null.
Let reason be abortSignal’s abort reason.
Let promise be the result of aborting stream with reason.
Upon fulfillment of promise, reject pendingOperation with reason.
Append stream to transport.[[SendStreams]].
Return stream.
WebTransportSendStream stream, run these steps:
Let transport be stream.[[Transport]].
If chunk is not a BufferSource, return a promise rejected with a TypeError.
Let promise be a new promise.
Let bytes be a copy of the byte sequence which chunk represents.
If bytes length is 0, resolve promise with undefined and return promise.
Set stream.[[PendingOperation]] to promise.
Let inFlightWriteRequest be stream.inFlightWriteRequest.
Let atomic be true if stream.[[AtomicWriteRequests]]
contains inFlightWriteRequest or
stream.[[InsideSynchronousAtomicWrite]] is true, otherwise false.
Run the following steps in parallel:
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:
Set stream.[[PendingOperation]] to null.
Abort all atomic write requests on stream.
Otherwise, send bytes on stream.[[InternalStream]]
and wait for the operation to complete.
This sending MUST follow the send-order rules.
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 the
WebTransportSendStream.
We access stream.[[SendOrder]] in parallel here.
User agents SHOULD respond to live updates of these values during sending, though
the details are implementation-defined.
Note: Ordering of retransmissions is implementation-defined,
but user agents are strongly encouraged to prioritize retransmissions of data with
higher [[SendOrder]] values.
This sending MUST NOT starve otherwise, except for flow control reasons or error.
The user agent SHOULD divide bandwidth fairly between all streams that aren’t starved.
Note: The definition of fairness here is implementation-defined.
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
reject stream.[[PendingOperation]].
Otherwise, queue a network task with transport to run these steps:
Set stream.[[PendingOperation]] to null.
Add the length of bytes to stream.[[BytesWritten]].
If stream.[[AtomicWriteRequests]] contains inFlightWriteRequest, remove inFlightWriteRequest.
Resolve promise with undefined.
Return promise.
Note: The fulfillment of the promise returned from this algorithm (or,
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 an application-level acknowledgment message.
WebTransportSendStream stream, run these steps:
Let transport be stream.[[Transport]].
Let promise be a new promise.
Remove stream from transport.[[SendStreams]].
Set stream.[[PendingOperation]] to promise.
Run the following steps in parallel:
Send FIN on stream.[[InternalStream]] and wait for the operation to
complete.
Wait for stream.[[InternalStream]] to enter the "all data committed" state. [QUIC]
Queue a network task with transport to run these steps:
Set stream.[[PendingOperation]] to null.
Resolve promise with undefined.
Return promise.
WebTransportSendStream stream with reason, run these steps:
Let transport be stream.[[Transport]].
Let promise be a new promise.
Let code be 0.
Remove stream from transport.[[SendStreams]].
If reason is a WebTransportError and reason.[[StreamErrorCode]] is not
null, then set code to reason.[[StreamErrorCode]].
If code < 0, then set code to 0.
If code > 4294967295, then set code to 4294967295.
Let committedOffset be stream.[[CommittedOffset]].
Note: Valid values of code are from 0 to 4294967295 inclusive. If the underlying connection is using HTTP/3, the code will be encoded to a number in [0x52e4a40fa8db, 0x52e5ac983162] as decribed in [WEB-TRANSPORT-HTTP3].
Run the following steps in parallel:
Abort sending on stream.[[InternalStream]] with code and committedOffset.
Queue a network task with transport to resolve promise with undefined.
Return promise.
WebTransportSendStream stream, run these steps:
Let writeRequests be stream.writeRequests.
Let requestsToAbort be stream.[[AtomicWriteRequests]].
If writeRequests contains a promise not in requestsToAbort, then
error stream with AbortError, and abort these steps.
For each promise in requestsToAbort, reject promise with AbortError.
In parallel, for each promise in requestsToAbort, abort the sending of bytes associated with promise.
WebTransportSendStream stream gets a
receiving aborted signal from the server, run these steps:
Let transport be stream.[[Transport]].
Let code be the application protocol error code attached to the receiving aborted signal.
Note: Valid values of code are from 0 to 4294967295 inclusive. If the underlying connection is using HTTP/3, the code will be encoded to a number in [0x52e4a40fa8db, 0x52e5ac983162] as decribed in [WEB-TRANSPORT-HTTP3].
Queue a network task with transport to run these steps:
If transport.[[State]] is "closed" or "failed", abort these steps.
Remove stream from transport.[[SendStreams]].
Let error be a newly created WebTransportError whose
source is "stream" and
streamErrorCode is code.
If stream.[[PendingOperation]] is not null, reject stream.[[PendingOperation]]
with error.
Error stream with error.
WebTransportSendStreamStats DictionaryThe WebTransportSendStreamStats dictionary includes information
on stats specific to one WebTransportSendStream.
dictionary WebTransportSendStreamStats {unsigned long long bytesWritten ;unsigned long long bytesSent ;unsigned long long bytesAcknowledged ; };
The dictionary SHALL have the following attributes:
bytesWritten, of type unsigned long long
The total number of bytes the application has successfully written to this
WebTransportSendStream. This number can only increase.
bytesSent, of type unsigned long long
An indicator of progress on how many of the application bytes written to this
WebTransportSendStream has been sent at least once. This
number can only increase, and is always less than or equal to
bytesWritten.
Note: this is progress of app data sent on a single stream only, and does not include any network overhead.
bytesAcknowledged, of type unsigned long long
An indicator of progress on how many of the application bytes written to this
WebTransportSendStream have been sent and acknowledged as received by
the server using QUIC’s ACK mechanism. Only sequential bytes up to, but not
including, the first non-acknowledged byte, are counted. This number can only
increase and is always less than or equal to bytesSent.
Note: This value will match bytesSent when
the connection is over HTTP/2.
WebTransportSendGroupA WebTransportSendGroup is an optional organizational object that tracks
transmission of data spread across many individual
(typically strictly ordered)
WebTransportSendStreams.
WebTransportSendStreams and WebTransportDatagramsWritables, at their
creation or through assignment of their sendGroup attribute, can be grouped
under at most one WebTransportSendGroup or the null sendGroup at any time.
By default, WebTransportSendStreams and WebTransportDatagramsWritables are assigned
to the null sendGroup.
The user agent considers WebTransportSendGroups as equals when allocating
bandwidth for sending WebTransportSendStreams. Each WebTransportSendGroup
also establishes a separate numberspace for evaluating
sendOrder numbers.
[Exposed =(Window ,Worker ),SecureContext ]interface {WebTransportSendGroup Promise <WebTransportSendStreamStats >getStats (); };
A WebTransportSendGroup is always created by the
create procedure.
getStats()
Aggregates stats from all WebTransportSendStreams
grouped under this sendGroup, and reports the result
asynchronously.
When called, the user agent MUST run these steps:
Let transport be this.[[Transport]].
Let p be a new promise.
Let streams be all WebTransportSendStreams whose
[[SendGroup]] is this.
Run the following steps in parallel:
Let gatheredStats be the list of aggregated stats from all
streams in streams needed to populate the
dictionary members of WebTransportSendStreamStats accurately.
Queue a network task with transport to run the following steps:
Let stats be a new WebTransportSendStreamStats object.
For each member member of stats that the user agent chooses to expose, set member to the corresponding entry in gatheredStats.
Resolve p with stats.
Return p.
A WebTransportSendGroup has the following internal slots.
| Internal Slot | Description (non-normative) |
|---|---|
[[Transport]]
| The WebTransport object owning this WebTransportSendGroup.
|
To create a
WebTransportSendGroup, with a WebTransport transport, run these steps:
Let sendGroup be a new WebTransportSendGroup, with:
[[Transport]]
transport
Return sendGroup.
WebTransportReceiveStreamA WebTransportReceiveStream is a ReadableStream providing incoming streaming
features with an incoming unidirectional or bidirectional
WebTransport stream.
It is a ReadableStream of Uint8Array that can be read from, to consume
data received from the server. WebTransportReceiveStream is a readable byte stream,
and hence it allows
its consumers to use a BYOB reader as well as a default reader.
[Exposed =(Window ,Worker ),SecureContext ,Transferable ]interface :WebTransportReceiveStream ReadableStream {Promise <WebTransportReceiveStreamStats >getStats (); };
A WebTransportReceiveStream is always created by the
create procedure.
The WebTransportReceiveStream’s transfer steps and
transfer-receiving steps are
those of ReadableStream.
getStats()
Gathers stats specific to this WebTransportReceiveStream’s performance,
and reports the result asynchronously.
When called, the user agent MUST run these steps:
Let transport be this.[[Transport]].
Let p be a new promise.
Run the following steps in parallel:
Let gatheredStats be the list of stats specific to this
WebTransportReceiveStream needed to populate the
dictionary members of WebTransportReceiveStreamStats accurately.
Queue a network task with transport to run the following steps:
Let stats be a new WebTransportReceiveStreamStats object.
For each member member of stats that the user agent chooses to expose, set member to the corresponding entry in gatheredStats.
Resolve p with stats.
Return p.
A WebTransportReceiveStream has the following internal slots.
| Internal Slot | Description (non-normative) |
|---|---|
[[InternalStream]]
| An incoming unidirectional or bidirectional WebTransport stream. |
[[Transport]]
| The WebTransport object owning this WebTransportReceiveStream.
|
To create a
WebTransportReceiveStream, with an incoming unidirectional or bidirectional WebTransport stream
internalStream and a WebTransport transport, run these steps:
Let stream be a new WebTransportReceiveStream, with:
[[InternalStream]]
internalStream
[[Transport]]
transport
Let pullAlgorithm be an action that pulls bytes from stream.
Let cancelAlgorithm be an action that cancels stream with reason, given reason.
Set up with byte reading support stream with pullAlgorithm set to pullAlgorithm and cancelAlgorithm set to cancelAlgorithm.
Append stream to transport.[[ReceiveStreams]].
Return stream.
To pull bytes from a WebTransportReceiveStream stream, run these steps.
Let transport be stream.[[Transport]].
Let internalStream be stream.[[InternalStream]].
Let promise be a new promise.
Let buffer, offset, and maxBytes be null.
If stream’s current BYOB request view for stream is not null:
Set offset to stream’s current BYOB request view.[[ByteOffset]].
Set maxBytes to stream’s current BYOB request view’s byte length.
Set buffer to stream’s current BYOB request view’s underlying buffer.
Otherwise:
Set offset to 0.
Set maxBytes to an implementation-defined size.
Set buffer be a new ArrayBuffer with maxBytes size. If allocating the
ArrayBuffer fails, return a promise rejected with a RangeError.
Run the following steps in parallel:
Write the bytes that area read from internalStream into buffer with offset offset, up to maxBytes bytes. Wait until either at least one byte is read or FIN is received. Let read be the number of read bytes, and let hasReceivedFIN be whether FIN was accompanied.
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 server.
Note: This operation may return before filling up all of buffer.
If the previous step failed, abort the remaining steps.
Note: We don’t reject promise here because we handle network errors elsewhere, and those steps error stream, which rejects any read requests awaiting this pull.
Queue a network task with transport to run these steps:
Note: If the buffer described above is available in the event loop where this procedure is running, the following steps may run immediately.
If read > 0:
Set view to a new Uint8Array with buffer, offset and read.
Enqueue view into stream.
If hasReceivedFIN is true:
Remove stream from transport.[[ReceiveStreams]].
Close stream.
Resolve promise with undefined.
Return promise.
To cancel a WebTransportReceiveStream stream with reason, run these
steps.
Let transport be stream.[[Transport]].
Let internalStream be stream.[[InternalStream]].
Let promise be a new promise.
Let code be 0.
If reason is a WebTransportError and reason.[[StreamErrorCode]] is not
null, then set code to reason.[[StreamErrorCode]].
If code < 0, then set code to 0.
If code > 4294967295, then set code to 4294967295.
Note: Valid values of code are from 0 to 4294967295 inclusive. If the underlying connection is using HTTP/3, the code will be encoded to a number in [0x52e4a40fa8db, 0x52e5ac983162] as decribed in [WEB-TRANSPORT-HTTP3].
Remove stream from transport.[[SendStreams]].
Run the following steps in parallel:
Abort receiving on internalStream with code.
Queue a network task with transport to run these steps:
Note: If the buffer described above is available in the event loop where this procedure is running, the following steps may run immediately.
Remove stream from transport.[[ReceiveStreams]].
Resolve promise with undefined.
Return promise.
WebTransportReceiveStream stream gets a
sending aborted signal from the server, run these steps:
Let transport be stream.[[Transport]].
Let code be the application protocol error code attached to the sending aborted signal.
Note: Valid values of code are from 0 to 4294967295 inclusive. If the underlying connection is using HTTP/3, the code will be encoded to a number in [0x52e4a40fa8db, 0x52e5ac983162] as decribed in [WEB-TRANSPORT-HTTP3].
Queue a network task with transport to run these steps:
If transport.[[State]] is "closed" or "failed", abort these steps.
Remove stream from transport.[[ReceiveStreams]].
Let error be a newly created WebTransportError whose
source is "stream" and
streamErrorCode is code.
Error stream with error.
WebTransportReceiveStreamStats DictionaryThe WebTransportReceiveStreamStats dictionary includes
information on stats specific to one WebTransportReceiveStream.
dictionary WebTransportReceiveStreamStats {unsigned long long bytesReceived ;unsigned long long bytesRead ; };
The dictionary SHALL have the following attributes:
bytesReceived, of type unsigned long long
An indicator of progress on how many of the server application’s bytes
intended for this WebTransportReceiveStream have been received so far.
Only sequential bytes up to, but not including, the first missing byte, are
counted. This number can only increase.
Note: this is progress of app data received on a single stream only, and does not include any network overhead.
bytesRead, of type unsigned long long
The total number of bytes the application has successfully read from this
WebTransportReceiveStream. This number can only increase, and is always
less than or equal to bytesReceived.
WebTransportBidirectionalStream[Exposed =(Window ,Worker ),SecureContext ]interface {WebTransportBidirectionalStream readonly attribute WebTransportReceiveStream readable ;readonly attribute WebTransportSendStream writable ; };
A WebTransportBidirectionalStream has the following internal slots.
| Internal Slot | Description (non-normative) |
|---|---|
[[Readable]]
| A WebTransportReceiveStream.
|
[[Writable]]
| A WebTransportSendStream.
|
[[Transport]]
| The WebTransport object owning this
WebTransportBidirectionalStream.
|
readable, of type WebTransportReceiveStream, readonly
The getter steps are to return this’s [[Readable]].
writable, of type WebTransportSendStream, readonly
The getter steps are to return this’s [[Writable]].
WebTransportBidirectionalStream with a
bidirectional WebTransport stream internalStream, a WebTransport
object transport, and a sendOrder, run these steps.
Let readable be the result of creating a WebTransportReceiveStream with
internalStream and transport.
Let writable be the result of creating a WebTransportSendStream with
internalStream, transport, and sendOrder.
Let stream be a new WebTransportBidirectionalStream, with:
[[Readable]]
readable
[[Writable]]
writable
[[Transport]]
transport
Return stream.
WebTransportWriter InterfaceWebTransportWriter is a subclass of WritableStreamDefaultWriter that
adds two methods.
A WebTransportWriter is always created by the
create procedure.
[Exposed=*,SecureContext ]interface :WebTransportWriter WritableStreamDefaultWriter {Promise <undefined >atomicWrite (optional any );chunk undefined commit (); };
atomicWrite(chunk)
The atomicWrite method will reject if the chunk given to it
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).
Note: atomicWrite can still reject after sending some data. Though it
provides atomicity with respect to flow control, other network errors could
cause the write to fail.
Furthermore, atomicWrite does not prevent data from being split between packets
or being interleaved with other data.
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 will be rejected as well. Any non-atomic writes rejected in this way will error the stream. Applications are therefore encouraged to always await an atomic write before attempting subsequent writes to the same stream.
When called, the user agent MUST run these steps:
If stream is undefined, return a promise rejected with a TypeError.
Set stream.[[InsideSynchronousAtomicWrite]] to true.
Set stream.[[InsideSynchronousAtomicWrite]] to false.
Append p to stream.[[AtomicWriteRequests]].
Return the result of reacting to p with the following steps:
If stream.[[AtomicWriteRequests]] contains p,
remove p.
If p was rejected with reason r, then return a promise rejected with r.
Return undefined.
commit()
The commit method will update the [[CommittedOffset]] of a stream
to match the number of bytes written to that stream ([[BytesWritten]]).
This ensures that those bytes will be delivered to a peer reliably,
even after writing is aborted, causing the stream to abort sending.
This uses the mechanism described in [RELIABLE-RESET].
Note: This does not guarantee delivery in the event that a connection fails, only when a stream has aborted sending.
When commit is called for stream, the user agent MUST run the following steps:
Set stream.[[CommittedOffset]]
to the value of stream.[[BytesWritten]].
To create a
WebTransportWriter, with a WebTransportSendStream stream, run these
steps:
Let writer be a new WebTransportWriter.
Set up writer for stream.
Return writer.
WebTransportError InterfaceWebTransportError is a subclass of DOMException that represents
An error coming from the server or the network, or
A reason for a client-initiated abort operation.
[Exposed =(Window ,Worker ),Serializable ,SecureContext ]interface WebTransportError :DOMException {constructor (optional DOMString = "",message optional WebTransportErrorOptions = {});options readonly attribute WebTransportErrorSource source ;readonly attribute unsigned long ?streamErrorCode ; };dictionary {WebTransportErrorOptions WebTransportErrorSource = "stream"; [source Clamp ]unsigned long ?=streamErrorCode null ; };enum {WebTransportErrorSource ,"stream" , };"session"
A WebTransportError has the following internal slots.
| Internal Slot | Description (non-normative) |
|---|---|
[[Source]]
| A WebTransportErrorSource indicating the source of this error.
|
[[StreamErrorCode]]
| The application protocol error code for this error, or null. |
The new WebTransportError(message, options)
constructor steps are:
Set this’s internal slots as follows:
[[Source]]
options.source
[[StreamErrorCode]]
options.streamErrorCode
Note: This name does not have a mapping to a legacy code, so this’s code
is 0.
source, of type WebTransportErrorSource, readonly
The getter steps are to return this’s [[Source]].
streamErrorCode, of type unsigned long, readonly, nullable
The getter steps are to return this’s [[StreamErrorCode]].
WebTransportError objects are serializable objects.
Run the DOMException serialization steps given value and serialized.
Set serialized.[[Source]] to value.[[Source]].
Set serialized.[[StreamErrorCode]] to value.[[StreamErrorCode]].
Run the DOMException deserialization steps given serialized and value.
Set value.[[Source]] to serialized.[[Source]].
Set value.[[StreamErrorCode]] serialized.[[StreamErrorCode]].
This section is non-normative.
This section describes the underlying protocol behavior of methods defined in this specification, utilizing [WEB-TRANSPORT-OVERVIEW]. Cause and effect may not be immediate due to buffering.
| WebTransport Protocol Action | API Effect |
|---|---|
| Session starts draining | await wt.draining
|
If the underlying connection is using HTTP/3, the following protocol behaviors from [WEB-TRANSPORT-HTTP3] apply.
The application streamErrorCode in the WebTransportError error is
converted to an httpErrorCode, and vice versa, as specified in [WEB-TRANSPORT-HTTP3]
Section 4.3.
| API Method | QUIC Protocol Action |
|---|---|
writable.abort(error)
| aborts sending on STREAM with httpErrorCode
and an offset that corresponds to the [[CommittedOffset]]
for the stream,
plus any stream header; see [RELIABLE-RESET]
|
writable.close()
| sends STREAM with FIN bit set |
writable.getWriter().write(chunk)()
| sends STREAM |
writable.getWriter().close()
| sends STREAM with FIN bit set |
writable.getWriter().abort(error)
| aborts sending on STREAM with httpErrorCode
and an offset that corresponds to the [[CommittedOffset]]
for the stream,
plus any stream header; see [RELIABLE-RESET]
|
readable.cancel(error)
| aborts receiving on STREAM with httpErrorCode |
readable.getReader().cancel(error)
| aborts receiving on STREAM with httpErrorCode |
wt.close(closeInfo)
| terminates session with closeInfo |
| QUIC Protocol Action | API Effect |
|---|---|
| received STOP_SENDING with httpErrorCode | errors writable
with streamErrorCode
|
| received STREAM | (await
readable.getReader().read()).value
|
| received STREAM with FIN bit set | (await
readable.getReader().read()).done
|
| received RESET_STREAM with httpErrorCode | errors readable
with streamErrorCode
|
| Session cleanly terminated with closeInfo | (await wt.closed).closeInfo, and
errors open streams
|
| Network error | (await wt.closed) rejects, and
errors open streams
|
Note: As discussed in Section 3.2 of [QUIC], receipt of a RESET_STREAM frame or RESET_STREAM_AT frame ([RELIABLE-RESET]) is not always indicated to the application. Receipt of the reset can be signaled immediately, interrupting delivery of stream data with any data not consumed being discarded. However, immediate signaling is not required. In particular, this signal might be delayed to allow delivery of the data indicated by the Reliable Size field in a RESET_STREAM_AT frame. If stream data has been completely received but has not yet been read by the application, the sending aborted signal can be suppressed. WebTransport always uses the RESET_STREAM_AT frame to ensure reliable delivery of the stream header; see Section 4.1 and Section 4.2 of [WEB-TRANSPORT-HTTP3].
| HTTP/3 Protocol Action | API Effect |
|---|---|
| Session starts draining | await wt.draining
|
If the underlying connection is using HTTP/2, the following protocol behaviors from [WEB-TRANSPORT-HTTP2] apply. Note that, unlike for HTTP/3, the stream error code does not need to be converted to an HTTP error code, and vice versa.
| API Method | HTTP/2 Protocol Action |
|---|---|
writable.abort(error)
| aborts sending on WT_STREAM with error |
writable.close()
| sends WT_STREAM with FIN bit set |
writable.getWriter().write()
| sends WT_STREAM |
writable.getWriter().close()
| sends WT_STREAM with FIN bit set |
writable.getWriter().abort(error)
| aborts sending on WT_STREAM with error |
readable.cancel(error)
| aborts receiving on WT_STREAM with error |
readable.getReader().cancel(error)
| aborts receiving on WT_STREAM with error |
wt.close(closeInfo)
| terminates session with closeInfo |
| HTTP/2 Protocol Action | API Effect |
|---|---|
| received WT_STOP_SENDING with error | errors writable
with streamErrorCode
|
| received WT_STREAM | (await
readable.getReader().read()).value
|
| received WT_STREAM with FIN bit set | (await
readable.getReader().read()).done
|
| received WT_RESET_STREAM with error | errors readable
with streamErrorCode
|
| Session cleanly terminated with closeInfo | (await wt.closed).closeInfo, and
errors open streams
|
| Network error | (await wt.closed) rejects, and
errors open streams
|
| Session starts draining | await wt.draining
|
This section is non-normative; it specifies no new behaviour, but instead summarizes information already present in other parts of the specification.
The fact that communication is taking place cannot be hidden from adversaries that can observe the network, so this has to be regarded as public information.
All of the transport protocols described in this document use either TLS [RFC9846] or a semantically equivalent protocol, thus providing all of the security properties of TLS, including confidentiality and integrity of the traffic. WebTransport over HTTP uses the same certificate verification mechanism as outbound HTTP requests, thus relying on the same public key infrastructure for authentication of the remote server. In WebTransport, certificate verification errors are fatal; no interstitial allowing bypassing certificate validation is available.
WebTransport does not by itself create any new unique identifiers or new ways to persistently store state, nor does it automatically expose any of the existing persistent state to the server. For instance, neither [WEB-TRANSPORT-HTTP3] nor [WEB-TRANSPORT-HTTP2] send cookies or support HTTP authentication or caching invalidation mechanisms. Since they do use TLS, they inherit TLS persistent state such as TLS session tickets, which while not visible to passive network observers, could be used by the server to correlate different connections from the same client.
WebTransport imposes a set of requirements as described in [WEB-TRANSPORT-OVERVIEW], including:
Ensuring that the remote server is aware that the WebTransport protocol is in
use and confirming that the remote server is willing to use the WebTransport
protocol. [WEB-TRANSPORT-HTTP3] uses a combination of ALPN [RFC7301], an
HTTP/3 setting, and a :protocol pseudo-header to identify the WebTransport
protocol. [WEB-TRANSPORT-HTTP2] uses a combination of ALPN, an HTTP/2 setting,
and a :protocol pseudo-header to identify the WebTransport protocol.
Allowing the server to filter connections based on the origin of the resource
originating the transport session. The Origin header
field on the session establishment request carries this information.
Protocol security related considerations are described in the Security Considerations sections of [WEB-TRANSPORT-OVERVIEW] Section 6, [WEB-TRANSPORT-HTTP3] Section 8, and [WEB-TRANSPORT-HTTP2] Section 9.
Networking APIs can be commonly used to scan the local network for available hosts, and thus be used for fingerprinting and other forms of attacks. WebTransport follows the WebSocket approach to this problem: the specific connection error is not returned until an endpoint is verified to be a WebTransport endpoint; thus, the Web application cannot distinguish between a non-existing endpoint and the endpoint that is not willing to accept connections from the Web.
Normally, a user agent authenticates a TLS connection between itself and a remote endpoint by verifying the validity of the TLS server certificate provided against the server name in the URL [RFC9525]. This is accomplished by chaining server certificates to one of the trust anchors maintained by the user agent; the trust anchors in question are responsible for authenticating the server names in the certificates. We will refer to this system as Web PKI.
This API provides web applications with a capability to connect to a remote network endpoint authenticated by a specific server certificate, rather than its server name. This mechanism enables connections to endpoints for which getting long-term certificates can be challenging, including hosts that are ephemeral in nature (e.g. short-lived virtual machines), or that are not publicly routable. Since this mechanism substitutes Web PKI-based authentication for an individual connection, we need to compare the security properties of both.
A remote server will be able to successfully perform a TLS handshake only if it posesses the private key corresponding to the public key of the certificate specified. The API identifies the certificates using their hashes. That is only secure as long as the cryptographic hash function used has second-preimage resistance. The only function defined in this document is SHA-256; the API provides a way to introduce new hash functions through allowing multiple algorithm-hash pairs to be specified.
It is important to note that Web PKI provides additional security mechanisms in addition to simply establishing a chain of trust for a server name. One of them is handling certificate revocation. In cases where the certificate used is ephemeral, such a mechanism is not necessary. In other cases, the Web application has to consider the mechanism by which the certificate hashes are provisioned; for instance, if the hash is provided as a cached HTTP resource, the cache needs to be invalidated if the corresponding certificate has been rotated due to compromise. Another security feature provided by the Web PKI are safeguards against certain issues with key generation, such as rejecting certificates with known weak keys; while this specification does not provide any specific guidance, browsers MAY reject those as a part of implementation-defined behavior.
Web PKI enforces an expiry period requirement on the certificates. This requirement limits the scope of potential key compromise; it also forces server operators to design systems that support and actively perform key rotation. For this reason, WebTransport imposes a similar expiry requirement; as the certificates are expected to be ephemeral or short-lived, the expiry period is limited to two weeks. The two weeks limit is a balance between setting the expiry limit as low as possible to minimize consequences of a key compromise, and maintaining it sufficiently high to accomodate for clock skew across devices, and to lower the costs of synchronizing certificates between the client and the server side.
The WebTransport API lets the application specify multiple certificate hashes at once, allowing the client to accept multiple certificates for a period in which a new certificate is being rolled out.
Unlike a similar mechanism in WebRTC, the server certificate hash API in WebTransport does not provide any means of authenticating the client; the fact that the client knows what the server certificate is or how to contact it is not sufficient. The application has to establish the identity of the client in-band if necessary.
This API provides sites with the ability to generate network activity and closely observe the effect of this activity. The information obtained in this way might be identifying.
It is important to recognize that very similar networking capabilities are
provided by other web platform APIs (such as
fetch() and WebSocket). The net
adverse effect on privacy due to adding WebTransport is therefore minimal. The
considerations in this section applies equally to other networking capabilities.
Measuring network characteristics requires that the network be used and that the effect of that usage be measured, both of which are enabled by this API. WebTransport provides sites with an ability to generate network activity toward a server of their choice and observe the effects. Observations of both the stable properties of a network path and dynamic effect of network usage are possible.
Information about the network is available to the server either directly through its own networking stack, indirectly through the rate at which data is consumed or transmitted by the client, or as part of the statistics provided by the API (see § 6.13 WebTransportConnectionStats Dictionary). Consequently, restrictions on information in user agents is not the only mechanism that might be needed to manage these privacy risks.
A site can observe available network capacity or round trip time (RTT) between a user agent and a chosen server. This information can be identifying when combined with other tracking vectors. RTT can also reveal something about the physical location of a user agent, especially if multiple measurements can be made from multiple vantage points.
Though networking is shared, network use is often sporadic, which means that sites are often able to observe the capacity and round trip times of an uncontested or lightly loaded network path. These properties are stable for many people as their network location does not change and the position of network bottlenecks--which determine available capacity--can be close to a user agent.
Contested links present sites with opportunities to enable cross-site recognition, which might be used to perform unsanctioned tracking [UNSANCTIONED-TRACKING]. Network capacity is a finite shared resource, so a user agent that concurrently accesses different sites might reveal a connection between the identity presented to each site.
The use of networking capabilities on one site reduces the capacity available to other sites, which can be observed using networking APIs. Network usage and metrics can change dynamically, so any change can be observed in real time. This might allow sites to increase confidence that activity on different sites originates from the same user.
A user agent could limit or degrade access to feedback mechanisms such as statistics (§ 6.13 WebTransportConnectionStats Dictionary) for sites that are inactive or do not have focus (HTML § 6.6 Focus). As noted, this does not prevent a server from making observations about changes in the network.
Similar to shared networking scenarios, when sessions are pooled on a single connection, information from one session is affected by the activity of another session. One session could infer information about the activity of another session, such as the rate at which another application is sending data.
The use of a shared connection already allows the server to correlate sessions. Use of a network partition key disables pooling where use of a shared session might enable unwanted cross-site recognition.
This section is non-normative.
Sending a buffer of datagrams can be achieved by using the
datagrams' createWritable
method and the resulting stream’s writer. In the
following example datagrams are only sent if the transport is ready to send.
async function sendDatagrams( url, datagrams) { const wt= new WebTransport( url); const writable= wt. datagrams. createWritable(); const writer= writable. getWriter(); for ( const bytesof datagrams) { await writer. ready; writer. write( bytes). catch (() => {}); } await writer. close(); }
This section is non-normative.
Sending datagrams at a fixed rate regardless if the transport is ready to send
can be achieved by simply using datagrams'
createWritable method and the resulting
stream’s writer without awaiting the ready attribute.
// Sends datagrams every 100 ms. async function sendFixedRate( url, createDatagram, ms= 100 ) { const wt= new WebTransport( url); const writable= wt. datagrams. createWritable(); const writer= writable. getWriter(); const bytes= createDatagram(); setInterval(() => writer. write( bytes). catch (() => {}), ms); }
This section is non-normative.
Datagrams can be received by reading from the
transport.datagrams.readable
attribute. Null values may indicate that packets are not being processed quickly
enough.
async function receiveDatagrams( url) { const wt= new WebTransport( url); for await ( const datagramof wt. datagrams. readable) { // Process the datagram } }
This section is non-normative.
As datagrams are readable byte streams, you can acquire a
BYOB reader for them, which allows more precise control over buffer allocation
in order to avoid copies. This example reads the datagram into a 64 kibibytes memory buffer.
const wt= new WebTransport( url); for await ( const datagramof wt. datagrams. readable) { const reader= datagram. getReader({ mode: "byob" }); let array_buffer= new ArrayBuffer( 65536 ); const buffer= await readInto( array_buffer); } async function readInto( buffer) { let offset= 0 ; while ( offset< buffer. byteLength) { const { value: view, done} = await reader. read( new Uint8Array( buffer, offset, buffer. byteLength- offset)); buffer= view. buffer; if ( done) { break ; } offset+= view. byteLength; } return buffer; }
This section is non-normative.
Sending data as a one-way stream can be achieved by using the
createUnidirectionalStream function and the resulting stream’s writer.
The written chunk boundaries aren’t preserved on reception, as the bytes might coalesce on the wire. Applications are therefore encouraged to provide their own framing.
async function sendData( url, ... data) { const wt= new WebTransport( url); const writable= await wt. createUnidirectionalStream(); const writer= writable. getWriter(); for ( const bytesof data) { await writer. ready; writer. write( bytes). catch (() => {}); } await writer. close(); }
The streams spec discourages awaiting the promise from write().
Encoding can also be done through pipes from a ReadableStream, for example using
TextEncoderStream.
async function sendText( url, readableStreamOfTextData) { const wt= new WebTransport( url); const writable= await wt. createUnidirectionalStream(); await readableStreamOfTextData. pipeThrough( new TextEncoderStream( "utf-8" )) . pipeTo( writable); }
This section is non-normative.
Reading incoming streams can be achieved by iterating over the
incomingUnidirectionalStreams attribute,
and then consuming each WebTransportReceiveStream by iterating over its chunks.
Chunking is determined by the user agent, not the sender.
async function receiveData( url, processTheData) { const wt= new WebTransport( url); for await ( const readableof wt. incomingUnidirectionalStreams) { // consume streams individually using IFFEs, reporting per-stream errors (( async () => { try { for await ( const bytesof readable) { processTheData( bytes); } } catch ( e) { console. error( e); } })()); } }
Decoding can also be done through pipes to new WritableStreams, for example using
TextDecoderStream. This example assumes text output should not be
interleaved, and therefore only reads one stream at a time.
async function receiveText( url, createWritableStreamForTextData) { const wt= new WebTransport( url); for await ( const readableof wt. incomingUnidirectionalStreams) { // consume sequentially to not interleave output, reporting per-stream errors try { await readable. pipeThrough( new TextDecoderStream( "utf-8" )) . pipeTo( createWritableStreamForTextData()); } catch ( e) { console. error( e); } } }
This section is non-normative.
As WebTransportReceiveStreams are readable byte streams, you can acquire a
BYOB reader for them, which allows more precise control over buffer allocation
in order to avoid copies. This example reads the first 1024 bytes from a
WebTransportReceiveStream into a single memory buffer.
const wt= new WebTransport( url); const reader= wt. incomingUnidirectionalStreams. getReader(); const { value: recv_stream, done} = await reader. read(); const byob_reader= recv_stream. getReader({ mode: "byob" }); let array_buffer= new ArrayBuffer( 1024 ); const buffer= await readInto( array_buffer); async function readInto( buffer) { let offset= 0 ; while ( offset< buffer. byteLength) { const { value: view, done} = await reader. read( new Uint8Array( buffer, offset, buffer. byteLength- offset)); buffer= view. buffer; if ( done) { break ; } offset+= view. byteLength; } return buffer; }
This section is non-normative.
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
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!= "AbortError" ) throw e; // rejected to avoid blocking on flow control // The writable remains un-errored provided no non-atomic writes are pending } finally { writer. releaseLock(); } }
This section is non-normative.
A WebTransport session can override the default trust evaluation performed by
the client with a check against the hash of the certificate provided to the
server. In the example below, hashValue is a BufferSource containing the
SHA-256 hash of a server certificate that the underlying connection should
consider to be valid.
const wt= new WebTransport( url, { serverCertificateHashes: [ { algorithm: "sha-256" , value: hashValue, } ] }); await wt. ready;
This section is non-normative.
This example illustrates use of the closed and ready promises, opening of uni-directional and bi-directional streams by either the client or the server, and sending and receiving datagrams.
writable attribute that used to exist on
a transport’s datagrams is easy to polyfill as follows:
wt.datagrams.writable ||= wt.datagrams.createWritable();
// Adds an entry to the event log on the page, optionally applying a specified // CSS class. let wt, streamNumber, datagramWriter; connect. onclick= async () => { try { const url= document. getElementById( 'url' ). value; wt= new WebTransport( url); wt. datagrams. writable||= wt. datagrams. createWritable(); addToEventLog( 'Initiating connection...' ); await wt. ready; addToEventLog( ` ${ ( wt. reliability== "reliable-only" ) ? "TCP" : "UDP" } ` + `connection ready.` ); wt. closed. then(() => addToEventLog( 'Connection closed normally.' )) . catch (() => addToEventLog( 'Connection closed abruptly.' , 'error' )); streamNumber= 1 ; datagramWriter= wt. datagrams. writable. getWriter(); readDatagrams(); acceptUnidirectionalStreams(); document. forms. sending. elements. send. disabled= false ; document. getElementById( 'connect' ). disabled= true ; } catch ( e) { addToEventLog( `Connection failed. ${ e} ` , 'error' ); } } sendData. onclick= async () => { const form= document. forms. sending. elements; const data= sending. data. value; const bytes= new TextEncoder( 'utf-8' ). encode( data); try { switch ( form. sendtype. value) { case 'datagram' : { await datagramWriter. ready; datagramWriter. write( bytes). catch (() => {}); addToEventLog( `Sent datagram: ${ data} ` ); break ; } case 'unidi' : { const writable= await wt. createUnidirectionalStream(); const writer= writable. getWriter(); writer. write( bytes). catch (() => {}); await writer. close(); addToEventLog( `Sent a unidirectional stream with data: ${ data} ` ); break ; } case 'bidi' : { const duplexStream= await wt. createBidirectionalStream(); const n= streamNumber++ ; readFromIncomingStream( duplexStream. readable, n); const writer= duplexStream. writable. getWriter(); writer. write( bytes). catch (() => {}); await writer. close(); addToEventLog( `Sent bidirectional stream # ${ n} with data: ${ data} ` ); break ; } } } catch ( e) { addToEventLog( `Error while sending data: ${ e} ` , 'error' ); } } // Reads datagrams into the event log until EOF is reached. async function readDatagrams() { try { const decoder= new TextDecoderStream( 'utf-8' ); for await ( const dataof wt. datagrams. readable. pipeThrough( decoder)) { addToEventLog( `Datagram received: ${ data} ` ); } addToEventLog( 'Done reading datagrams!' ); } catch ( e) { addToEventLog( `Error while reading datagrams: ${ e} ` , 'error' ); } } async function acceptUnidirectionalStreams() { try { for await ( const readableof wt. incomingUnidirectionalStreams) { const number= streamNumber++ ; addToEventLog( `New incoming unidirectional stream # ${ number} ` ); readFromIncomingStream( readable, number); } addToEventLog( 'Done accepting unidirectional streams!' ); } catch ( e) { addToEventLog( `Error while accepting streams ${ e} ` , 'error' ); } } async function readFromIncomingStream( readable, number) { try { const decoder= new TextDecoderStream( 'utf-8' ); for await ( const dataof readable. pipeThrough( decoder)) { addToEventLog( `Received data on stream # ${ number} : ${ data} ` ); } addToEventLog( `Stream # ${ number} closed` ); } catch ( e) { addToEventLog( `Error while reading from stream # ${ number} : ${ e} ` , 'error' ); addToEventLog( ` ${ e. message} ` ); } } function addToEventLog( text, severity= 'info' ) { const log= document. getElementById( 'event-log' ); const previous= log. lastElementChild; const entry= document. createElement( 'li' ); entry. innerText= text; entry. className= `log- ${ severity} ` ; log. appendChild( entry); // If the previous entry in the log was visible, scroll to the new element. if ( previous&& previous. getBoundingClientRect(). top< log. getBoundingClientRect(). bottom) { entry. scrollIntoView(); } }
The WebTransport interface is based on the QuicTransport interface
initially described in the W3C ORTC CG,
and has been adapted for use in this specification.