Copyright © 2013 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved. W3C liability, trademark and document use rules apply.
This specification provides an API for representing binary and string data in web applications as a Stream
object,
as well as programmatically building and reading its contents. This includes:
Stream
interface, which represents a sequence of data which can be read only once and provides APIs for reading, writing, and piping the data.StreamConsumeResult
interface, which represents a chunk of content read from a stream.StreamReadType
interface, which represents how the Stream
is currently being read.Stream
object.Stream
.Stream
.
This API is designed to be used in conjunction with other APIs and elements on the web platform, notably:
File [FILE-API],
XMLHttpRequest
(e.g. with an overloaded send()
method
and response
object for Stream
objects) [XMLHTTPREQUEST2],
postMessage
, and
Web Workers [WEBWORKERS].
This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.
This document is not complete. It is subject to major changes and, while early experimentations are encouraged, it is therefore not intended for implementation.
This document was published by the W3C Web Applications (WebApps) as a Working Draft.
This document is intended to become a W3C Recommendation.
If you wish to make comments regarding this document, please send them to
public-webapps@w3.org
(subscribe,
archive)
with a Subject prefix of [streams-api]
.
If you wish to submit a bug, please use
Bugzilla.
All comments and bug reports are welcome.
Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.
This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.
This section is non-normative.
Web applications should have the ability to acquire and manipulate data in a wide variety of forms, including as a sequence of data made available over time. This specification defines the basic representation for Streams, errors raised by Streams, and programmatic ways to create, read, and write to Streams.
The Stream
interface represents binary data which can be obtained over time and read once. A Stream
can come from API producers such as XMLHttpRequest
, or can
be built using the Stream
constructor.
The Stream
interface provides a read
method for reading the data
from a Stream
as a StreamConsumeResult
, which provides the data as a Blob
, ArrayBuffer
, or as DOMString
,
and should happen asynchronously on the user agent’s main thread. Additionally, the stream can also be used in API consumers such as a media element.
The Stream
interface also provides a write
method for writing data
to a Stream
as a Blob
, ArrayBuffer
, or as DOMString
,
and should happen asynchronously on the user agent’s main thread.
An asynchronous API for reading Streams
prevents blocking and UI “freezing” on a user agent’s main thread.
This specification defines an asynchronous API to access a Stream
. Error conditions that may arise during reading of a Stream
will be handled by a reject callback set to the promise returned by the read() method. An example will be illustrative.
In the example below, different code blocks handle progress, error, and success conditions.
The example demonstrates how to read a chunk of data from a Stream
using read
. The Stream
may of come from a producer such as XMLHttpRequest
. Additionally, it demonstrates how to read a stream until an EOF is encountered.
// Read the first 1024 bytes of the stream as UTF-8 stream.readEncoding = "UTF-8"; stream.readType = "arraybuffer"; Promise readPromise = stream.read(1024); readPromise.then( function(result) { console.log("Loaded" + result.size + " bytes"); // Handle result.data }, function(error) { // Handle error } ); // Read data from the stream repeatedly function readUntilEof() { stream.read(1024).then( function(result) { // Handle read data someProcessFunction(result.data); // Print progress someReportFunction(result.size); if (!result.eof) { readUntilEof(); } }, function(error) { // Handle error } ); }
In the example below, different code blocks handle progress, error, and success conditions.
The example below demonstrates how to obtain a Stream
from XMLHttpRequest
to begin playing a large video in readystate
3. The example takes the Stream
from a producer, XMLHttpRequest
, and gives to a consumer, the video tag.
function handler() { if(this.readyState == this.LOADING) { var theStream = this.response; var streamURL = URL.createObjectURL(theStream); document.getElementById("myVideoTag").src = streamURL; } } var client = new XMLHttpRequest(); client.onreadystatechange = handler; client.setRequestHeader('customHeader', 'value'); client.setRequestHeader('customHeader2', 'value2'); client.open("GET", "myvideo.h264"); client.responseType = "stream"; client.send();
In addition to reading a Stream, this specification introduces a programatic way to write data to a Stream.
The Stream
interface provides a write()
method which allows applications to build the data to be read by a Stream consumer by appending the data to an internal buffer.
write()
supports appending data as a Blob
, ArrayBuffer
, or DOMString
to the buffer.
The example below demonstrates how to use write()
to load a Stream into the audio tag, whose data could be processed and built dynamically at read time.
var theStream = new Stream("audio/mp3"); function writeData(){ var moreData; // Do work to create more data to place into the stream // If we have no more data to process and place in the stream, we close if (moreData == null){ theStream.close(); } else{ theStream.write(moreData).then( function () { writeData(); }, function (error) { // Handle error } ); } } var streamURL = URL.createObjectURL(theStream); document.getElementById('audioTag').src = streamURL; writeData();
This section introduces the Stream
interface, as well as accompanying interfaces required as part of the Stream
implementation. This includes a constructor to build a Stream
, as well as methods to read
, write
, skip
, pipe
, and close
streams.
This interface represents a raw sequence of linear data which can be read only once over time. It provides a type attribute which represents the type of data in the Stream. It also provides the ability to read and write the contents of the Stream.
A Stream is an object that:
A Stream object has an associated write closed flag. It is set when the close() method is called. This flag is internal, so scripts cannot access it directly.
A Stream object has an associated write pending flag. It is set when the write() method is called and unset when it's completed. This flag is internal, so scripts cannot access it directly.
A Stream object has an associated read pending flag. It is set when read(), skip() or pipe() method is called and unset when it's completed. This flag is internal, so scripts cannot access it directly.
A Stream holds a sequence of bytes possibly terminated by a terminator. Writing bytes to a Stream means appending the bytes to the sequence. Terminating a Stream means appending a terminator to the sequence. Reading bytes from a Stream pops bytes from the head of the sequence. If a terminator is encountered while reading bytes from a Stream, it is said the EOF is reached. This sequence is internal, so scripts cannot access it directly.
[ Constructor (optional DOMString type)]
interface Stream {
readonly attribute DOMString type;
attribute StreamReadType
readType;
attribute DOMString readEncoding;
Promise write ((DOMString or ArrayBufferView or Blob) data);
void close ();
Promise read (optional [Clamp] unsigned long long size);
Promise skip (![Clamp] unsigned long long size);
Promise pipe (!(Stream or Stream[]) destination, optional [Clamp] unsigned long long size);
};
readEncoding
of type DOMString,
A DOMString
that represents the label of an encoding [EncodingDetermination]. If set, it will be used as part of the encoding determination used when processing a read
call. If not set, it will return the empty string.
readType
of type StreamReadType
,
Returns the type of the last read operation taken on the Stream
. On getting, conforming user agents must return the type of the last read operation. If no read operation has taken place and the readType
was not set, then return the empty string. This can be set to the empty string (default), "arraybuffer", "blob" and "text" to change the type of the read operation.
type
of type DOMString, readonly Stream
,
expressed as an RFC2046 MIME type [RFC2046].
Conforming user agents SHOULD return the MIME type of the Stream
, if it is known.
If conforming user agents cannot determine the media type of the Stream
, they MUST return the empty string.
A string is a valid MIME type if it matches the media-type token defined in section 3.7 "Media Types" of RFC 2616 [HTTP11].
close
This method closes the Stream
and does not allow any future writes. This is an irreversible operation; once a Stream
has been closed, it cannot be written to again.
When all data has been read from the Stream
on which close() has been called, i.e. EOF is reached, it resolves the Promise returned by read() with a StreamConsumeResult
with the eof attribute set to true.
The user agent must run the steps below:
Stream
has been neutered, throw an "InvalidStateError
" [DOM4] exception and terminate these steps.InvalidStateError
" [DOM4] exception and terminate these steps.InvalidStateError
" [DOM4] exception and terminate these steps.Stream
and terminate these steps.
pipe
This method transfers data from the Stream
to another Stream.
This method takes a destinations
and optionally a size
.
Another read(), skip() or pipe() call must not be made until the returned Promise is resolved or rejected.
Resolution of the returned Promise doesn't necessarily mean that the data transferred to the destination Stream has been successfully read from the Stream.
The user agent must run the steps below:
Stream
has been neutered, throw an "InvalidStateError
" [DOM4] exception and terminate these steps.InvalidStateError
" [DOM4] exception and terminate these steps.size
is specified but is 0, throw a "SyntaxError
" [DOM4] exception and terminate these steps.destinations
is a Stream
, let destinations
instead be an array consisting of just that Stream
.readPromise
be a new promise.readPromise
, but continue to process the steps in this algorithm.size
is specified, read data from the stream until size
bytes are read.destinations
.destinations
, neuter the Stream
, let exception
be an "InvalidStateError
" exception and run Reject(readPromise
, exception
)
as specified in the promises spec and terminate these steps.result
be a newly created StreamConsumeResult
object.result
to true.result
set to false.result
to the total size of the read data.Resolve(readPromise
, result
)
as specified in the promises spec.Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
destination |
| ✘ | ✘ | Destination Stream . |
size |
| ✘ | ✔ | Number of bytes to transfer. |
read
This method reads data from the Stream
.
This method takes an optional size
which represents the number of bytes to be read.
Another read(), skip() or pipe() call must not be made until the returned Promise is resolved or rejected.
The user agent must run the steps below (unless otherwise indicated):
Stream
has been neutered, throw an "InvalidStateError
" [DOM4] exception and terminate these steps.InvalidStateError
" [DOM4] exception and terminate these steps.size
is specified but is 0, throw a "SyntaxError
" [DOM4] exception and terminate these steps.readPromise
be a new promise.
readPromise
, but continue to process the steps in this algorithm.size
is specified, read data from the Stream until size
bytes are read.Stream
, let exception
be an "InvalidStateError
" [DOM4] exception and run Reject(readPromise
, exception
)
as specified in the promises spec and terminate these steps.result
be a newly created StreamConsumeResult
.result
to true.result
to false.result
to the result of executing the steps below.
text
"
readEncoding
.
result
be result of decoding the data read using fallback encoding charset.
blob
"
result
be a blob created from the read data
arraybuffer
"
result
be an array buffer created from the read data
Resolve(readPromise
, result
)
as specified in the promises spec.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
size |
| ✘ | ✔ | Number of bytes to read. |
skip
This method reads data from the Stream
and ignore them.
This method takes optionally a size
which represents the number of bytes to be read and ignored.
Another read(), skip() or pipe() call must not be made until the returned Promise is resolved or rejected.
The user agent must run the steps below:
Stream
has been neutered, throw an "InvalidStateError
" [DOM4] exception and terminate these steps.InvalidStateError
" [DOM4] exception and terminate these steps.size
is specified but is 0, throw a "SyntaxError
" [DOM4] exception and terminate these steps.readPromise
be a new promise.skip()
method with readPromise
, but continue to process the steps in this algorithm.size
is specified, read data from the Stream until size
bytes are read.Stream
, let exception
be an "InvalidStateError
" [DOM4] exception and run Reject(readPromise
, exception
)
as specified in the promises spec and terminate these steps.result
be a newly created StreamConsumeResult
object.result
to true.result
set to false.result
to the size of the read data in bytes.Resolve(readPromise, result)
as specified in the promises spec.Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
size |
| ✘ | ✘ | Number of bytes to read and ignore. |
write
This method writes data to the Stream
.
Another write() or close() call must not be made until the returned Promise is resolved or rejected.
Resolution of the returned Promise doesn't necessarily mean that the data written has been successfully read.
The user agent must run the steps below (unless otherwise indicated):
Stream
has been neutered, throw an "InvalidStateError
" [DOM4] exception and terminate these steps.InvalidStateError
" [DOM4] exception and terminate these steps.InvalidStateError
" [DOM4] exception and terminate these steps.writePromise
be a new promise.writePromise
, but continue to process the steps in this algorithm.data
:
ArrayBufferView
rawData
be the raw data represented by the Blob
object.Blob
rawData
be the data stored in the section of the buffer described by the ArrayBuffer
object that the ArrayBufferView
object references.DOMString
rawData
be the result of encoding data
to binary data using the encoding determined by the [EncodingDetermination] rawData
to the Stream.
Stream
, let exception
be an "InvalidStateError
" [DOM4] exception and run Reject(writePromise
, exception
)
as specified in the promises spec and terminate this algorithm.
Resolve(writePromise
, undefined
)
as specified in the promises spec. Implementations may delay this step if appropriate.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
data |
| ✘ | ✘ | Data to write. |
interface StreamConsumeResult {
readonly attribute boolean eof;
readonly attribute any data;
readonly attribute unsigned long long size;
};
data
of type any, readonly eof
of type boolean, readonly Stream
size
of type unsigned long long, readonly enum StreamReadType {
"blob",
"arraybuffer",
"text"
};
Enumeration description | |
---|---|
blob | Read operations should return data as a Blob |
arraybuffer | Read operations should return data as an ArrayBuffer |
text | Read operations should return data as a DOMString |
To reference a Stream
, the same URI used for Blobs
and Files
in
6.7. A URI for Blob and File reference of
the File API specification should be used. [FILE-API]
The definitions of Origin, Lifetime, Referencing, and Dereferencing of a Blob
should be applied to a Stream
.
A Stream URI is a Blob URI
that is referencing a Stream
.
These URIs are created and revoked using methods exposed on the URL object,
as defined in 6.7.5. Creating and Revoking a Blob URI
of the File API specification. [FILE-API]
URL.createObjectURL and URL.revokeObjectURL should both be extended as follows:
interface URL {
static DOMString? createObjectURL ((Blob or Stream
) object);
static DOMString? createFor ((Blob or Stream
) object);
static void revokeObjectURL (DOMString url);
};
createFor
, staticThe extension onto createFor
should have the following steps added.
Returns a unique Blob URL each time it is called on a valid object
argument, which is a non-null Stream
in scope of the global object's URL property from which this static method is called. Blob URLs created with this method are said to be auto-revoking since user-agents are responsible for the revocation of Blob URLs created with this method, subject to the lifetime stipulation for Blob URLs. This method must act as follows:
Stream
argument that is NOT valid, then user agents must return null.Stream
argument,
user agents must run the following sub-steps:
Stream
is set, return null.Stream
.Blob URI
that can be used to dereference the stream
argument.Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
object |
| ✘ | ✘ |
, nullablecreateObjectURL
, staticThe extension onto createObjectURL
should have the following steps added.
Returns a unique Blob URL each time it is called on a valid object
argument, which is a non-null Stream
in scope of the global object's URL property from which this static method is called. This method must act as follows:
Stream
argument that is NOT valid, then user agents must return null.Stream
argument,
user agents must run the following sub-steps:
Stream
is set, return null.Stream
.Blob URI
that can be used to dereference the stream
argument.Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
object |
| ✘ | ✘ |
, nullablerevokeObjectURL
, static
The extension onto revokeObjectURL
should have the following steps added.
Blob
or Stream
that is both
valid and in the same origin of the global object’s URL
property on which this static method was called,
user agents MUST return a 404 response code when the URL is dereferenced.Blob
or Stream
that is not valid
or if the value provided for the URL argument is not a Blob URI
or if the URL argument refers to a Blob
or Stream
that is not in the same origin
as the global object’s URL
property, this method call does nothing.
User agents MAY display a message on their error console.
Parameter | Type | Nullable | Optional | Description |
---|---|---|---|---|
url |
| ✘ | ✘ |
Streams can be both produced and consumed by various APIs. APIs which create streams are identified as producers, and ones which read and act on a stream are known as consumers. This section identifies some of the APIs where Streams may be produced and consumed.
This section outlines APIs which can consume a Stream object
This section outlines APIs which can produce a Stream object
A Stream
should have the same security considerations as a Blob
.
This is outlined in 6.8. Security Considerations
of the File API specification. [FILE-API]
Because a Stream
uses a Blob URI
, cross origin requests on a Stream
will not be supported.
This specification proposes an extension to XMLHttpRequest
[XMLHTTPREQUEST2] to add support for Stream
. This section is temporary and is meant to provide a recommendation for how Stream
should be incorporated into XMLHttpRequest
.
This will extend XMLHttpRequest
to allow for receiving and uploading of a Stream
.
One such scenario is providing access to data during readyState
3 (LOADING).
The sections below document in detail what extensions must be done to XMLHttpRequest
to support Stream
.
The section named "Response Entity Body" in XMLHttpRequest specification [XMLHTTPREQUEST2] should have the following additions:
The stream response entity body is either a Stream
representing the response entity body or null.
If the stream response entity body is null, let it be the return value of the following algorithm:
Stream
object.
Stream
object representing the response entity body.
stream
" responseType
A new value for the responseType
attribute "stream
" should be introduced.
In the IDL list in the section named "Interface XMLHttpRequest" in XMLHttpRequest specification [XMLHTTPREQUEST2], the definition of XMLHttpRequestResponseType
enum should now read:
enum XMLHttpRequestResponseType { "", "arraybuffer", "blob", "stream", "document", "json", "text" }
response
attribute
The algorithm of the response
attribute should be modified to handle the new responseType
value "stream
".
A Stream is binary data obtained sequentially over time.
Given this, a Stream
should be accessible in readyState
3 (LOADING).
The section named "The response attribute" in XMLHttpRequest specification [XMLHTTPREQUEST2] should now read:
The response
attribute must return the result of running these steps:
responseType
is the empty string or "text
"responseType
is "stream
"
The switch in otherwise case of step 4 of
The section named "The send()
method"
in XMLHttpRequest specification [XMLHTTPREQUEST2] should have the following additions:
Stream
If the object's type attribute is not the empty string let mime type be its value.
Set the read pending flag for the stream.
Let the request entity body be the raw data represented by data.
Once the read is completed for the request, call close() on the stream
The Stream
type allows for completion of several end-to-end experiences. This section covers what the requirements are for this API, and
illustrates some use cases.
XMLHttpRequest
in readyState
LOADING
Videos can typically be large files that may take a long time to download, and require authentication or certain headers to access. For certain video formats, an application can begin playing the video once the first chunks of data are available, and would not need to wait for the entire video to download.
Stream
as it is being read via XMLHttpRequest
If a file format is understood, then an application can make sense of the data as it being made available. For example, a given file may be very large and the application wants to begin processing the data immediately, rather than having to wait for full download of the file.
Stream
and XMLHttpRequest
There are situations where an application may have data to upload once the application is processing. This could involve processing of data an application wants to upload as it is being created. One such case is the upload of GPS coordinates within an application. The coordiantes may constantly change, and the application wants to upload the data as it being collected.
Stream
and XMLHttpRequest
Media streaming scenarios require the ability to quickly receive data over the network and connect it to a media element. An application can successfully accomplish this by receiving a Stream in readyState
LOADING and assign it to a media element. This helps avoid the application from having to buffer the data prior to assigning it to a media element.
Thanks to Eliot Graff for editorial assistance. Special thanks to the W3C. The editor would like to thank Anne van Kesteren, Austin William Wright, Aymeric Vitte, Domenic Denicola, Isaac Schlueter, Jonas Sicking, Kenneth Russell, Yusuke Suzuki, Adrian Bateman for their contributions to this specification.