1. Introduction
This section is non-normative.
The APIs specified in this specification are used to compress and decompress streams of data. They support "deflate" and "gzip" as compression algorithms. They are widely used in web developers.
2. Conformance
As 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 and SHOULD are to be interpreted as described in [RFC2119] .
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-1] , as this specification uses that specification and terminology.
3. Terminology
A
chunk
is
a
piece
of
data.
In
the
case
of
CompressionStream
and
DecompressionStream,
the
output
chunk
type
is
Uint8Array.
They
accept
any
BufferSource
type
as
input.
A
stream
represents
an
ordered
sequence
of
chunks.
The
terms
ReadableStream
and
WritableStream
are
defined
in
[WHATWG-STREAMS]
.
Deflate is a compression format defined in [RFC1950] . It is referred to there as "ZLIB", but in this standard we call it "deflate" to match HTTP (see [RFC7230] section 4.2.2). Gzip is another compression format defined in [RFC1952] , also based on the deflate algorithm.
4.
Interface
Mixin
GenericTransformStream
The
GenericTransformStream
interface
mixin
represents
the
concept
of
a
transform
stream
in
IDL.
It
is
not
a
TransformStream,
though
it
has
the
same
interface
and
it
delegates
to
one.
interface mixin {
GenericTransformStream readonly attribute ReadableStream readable ;readonly attribute WritableStream writable ; };
An
object
that
includes
GenericTransformStream
has
an
associated
transform
of
type
TransformStream.
4.1. Attributes
-
readable
, of type ReadableStream , readonly -
The
readable
attribute’s getter, when invoked, must return this object’s transform[[readable]].[readable ]. -
writable
, of type WritableStream , readonly -
The
writable
attribute’s getter, when invoked, must return this object’s transform[[writable]].[writable ].
5.
Interface
CompressionStream
[Exposed =(Window ,Worker )]interface {
CompressionStream (
constructor DOMString ); };
format CompressionStream includes GenericTransformStream ;
The
CompressionStream
(format)
constructor,
when
invoked,
must
run
these
steps:
-
If format is unsupported in CompressionStream, then throw a
TypeError.TypeError . -
Let cs be a new CompressionStream object.
-
Set cs 's format to format .
-
Let startAlgorithm be an algorithm that takes no arguments and returns nothing.
-
Let transformAlgorithm be an algorithm which takes a chunk argument and runs the compress and enqueue a chunk algorithm with cs and chunk .
-
Let flushAlgorithm be an algorithm which takes no argument and runs the compress flush and enqueue algorithm with cs .
-
Let transform be the result of calling CreateTransformStream ( startAlgorithm , transformAlgorithm , flushAlgorithm ).
-
Set cs 's transform to transform .
-
Return cs .
The compress and enqueue a chunk algorithm, given a CompressionStream object cs and a chunk , runs these steps:
-
If chunk is not a
BufferSource
type, then throw a TypeError. -
Let buffer be the result of compressing chunk with cs 's format . If this throws an exception, then return a promise rejected with that exception.
-
Let controller be cs 's
transform.[[TransformStreamController]].transform. [TransformStreamController ]. -
If buffer is empty, return a new promise resolved with undefined.
-
Split buffer into one or more non-empty pieces and convert them into Uint8Arrays.
-
For each Uint8Array array , call TransformStreamDefaultControllerEnqueue ( controller , array ).
-
Return a new promise resolved with undefined.
The compress flush and enqueue algorithm, which handles the end of data from the input ReadableStream object, given a CompressionStream object cs , runs these steps:
-
Let buffer be the result of compressing an empty input with cs 's format , with the finish flag.
-
If buffer is empty, return a new promise resolved with undefined.
-
Split buffer into one or more non-empty pieces and convert them into Uint8Arrays.
-
For each Uint8Array array , call TransformStreamDefaultControllerEnqueue ( controller , array ).
-
Return a new promise resolved with undefined.
6.
Interface
DecompressionStream
[Exposed =(Window ,Worker )]interface {
DecompressionStream (
constructor DOMString ); };
format DecompressionStream includes GenericTransformStream ;
The
DecompressionStream
(format)
constructor,
when
invoked,
must
run
these
steps:
-
If format is unsupported in DecompressionStream, then throw a TypeError.
-
Let ds be a new DecompressionStream object.
-
Set ds 's format to format .
-
Let startAlgorithm be an algorithm that takes no arguments and returns nothing.
-
Let transformAlgorithm be an algorithm which takes a chunk argument and runs the decompress and enqueue a chunk algorithm with ds and chunk .
-
Let flushAlgorithm be an algorithm which takes no argument and runs the decompress flush and enqueue algorithm with ds .
-
Let transform be the result of calling CreateTransformStream ( startAlgorithm , transformAlgorithm , flushAlgorithm ).
-
Set ds 's transform to transform .
-
Return ds .
The decompress and enqueue a chunk algorithm, given a DecompressionStream object ds and a chunk , runs these steps:
-
If chunk is not a
BufferSource
type, then throw a TypeError. -
Let buffer be the result of decompressing chunk with ds 's format . If this throws an exception, then return a promise rejected with that exception.
-
Let controller be ds 's
transform.[[TransformStreamController]].transform. [TransformStreamController ]. -
If buffer is empty, return a new promise resolved with undefined.
-
Split buffer into one or more non-empty pieces and convert them into Uint8Arrays.
-
For each Uint8Array array , call TransformStreamDefaultControllerEnqueue ( controller , array ).
-
Return a new promise resolved with undefined.
The decompress flush and enqueue algorithm, which handles the end of data from the input ReadableStream object, given a DecompressionStream object ds , runs these steps:
-
Let buffer be the result of decompressing an empty input with ds 's format , with the finish flag.
-
If buffer is empty, return a new promise resolved with undefined.
-
Split buffer into one or more non-empty pieces and convert them into Uint8Arrays.
-
For each
Uint8Array
array , call TransformStreamDefaultControllerEnqueue ( controller , array ). -
Return a new promise resolved with undefined.
7. Privacy and Security Considerations
The API doesn’t add any new privileges to the web platform.
However, web developers have to pay attention to the situation when attackers can get the length of the data. If so, they may be able to guess the contents of the data.
8. Examples
8.1. Gzip-compress a stream
const compressedReadableStream= inputReadableStream. pipeThrough( new CompressionStream( 'gzip' ));
8.2. Deflate-compress an ArrayBuffer to a Uint8Array
async function compressArrayBuffer( in ) { const cs= new CompressionStream( 'deflate' ); const writer= cs. writable. getWriter(); writer. write( in ); writer. close(); const out= []; const reader= cs. readable. getReader(); let totalSize= 0 ; while ( true ) { const { value, done} = await reader. read(); if ( done) break ; out. push( value); totalSize+= value. byteLength; } const concatenated= new Uint8Array( totalSize); let offset= 0 ; for ( const arrayof out) { concatenated. set( array, offset); offset+= array. byteLength; } return concatenated; }
8.3. Gzip-decompress a Blob to Blob
async function DecompressBlob( blob) { const ds= new DecompressionStream( 'gzip' ); const decompressionStream= blob. stream(). pipeThrough( ds); return await new Response( decompressedStream). blob(); }