diff --git a/Cargo.lock b/Cargo.lock
index 7f58e144b5..930a054ee8 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -316,9 +316,9 @@ checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
[[package]]
name = "brotli"
-version = "3.3.2"
+version = "3.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71cb90ade945043d3d53597b2fc359bb063db8ade2bcffe7997351d0756e9d50"
+checksum = "f838e47a451d5a8fa552371f80024dd6ace9b7acdf25c4c3d0f9bc6816fb1c39"
dependencies = [
"alloc-no-stdlib",
"alloc-stdlib",
@@ -870,9 +870,9 @@ dependencies = [
[[package]]
name = "deno_doc"
-version = "0.26.0"
+version = "0.26.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "73ff82ae22a4012a843799f5baadda95ddc67cc3bed21fe5ebcda2c5cff768a1"
+checksum = "e82f45d6513b789c04adf0915ca3c3c696f5f5f9379a82834ad4f783fbaa8b3a"
dependencies = [
"cfg-if 1.0.0",
"deno_ast",
@@ -1074,6 +1074,7 @@ dependencies = [
"base64 0.13.0",
"deno_core",
"encoding_rs",
+ "flate2",
"serde",
"tokio",
"uuid",
@@ -2150,9 +2151,9 @@ dependencies = [
[[package]]
name = "libloading"
-version = "0.7.2"
+version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afe203d669ec979b7128619bae5a63b7b42e9203c1b29146079ee05e2f604b52"
+checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
dependencies = [
"cfg-if 1.0.0",
"winapi 0.3.9",
@@ -3448,9 +3449,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.74"
+version = "1.0.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee2bb9cd061c5865d345bb02ca49fcef1391741b672b54a0bf7b679badec3142"
+checksum = "c059c05b48c5c0067d4b4b2b4f0732dd65feb52daf7e0ea09cd87e7dadc1af79"
dependencies = [
"indexmap",
"itoa 1.0.1",
@@ -3545,9 +3546,9 @@ dependencies = [
[[package]]
name = "siphasher"
-version = "0.3.7"
+version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b"
+checksum = "ba1eead9e94aa5a2e02de9e7839f96a007f686ae7a1d57c7797774810d24908a"
[[package]]
name = "slab"
@@ -3778,9 +3779,9 @@ dependencies = [
[[package]]
name = "swc_ecma_ast"
-version = "0.65.1"
+version = "0.65.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "279a4595711a9aaf02165398d5f317b89d718ab90d30b2c08f34abda6545aa3a"
+checksum = "3a82d26122365a721a7df46bd3e4240fbf19188d9ccf18c7faaa4d12dfc51488"
dependencies = [
"is-macro",
"num-bigint",
@@ -3850,9 +3851,9 @@ dependencies = [
[[package]]
name = "swc_ecma_parser"
-version = "0.87.0"
+version = "0.87.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3c454cbd95ab84fd9ffc5059cffad80b7711bd4b8732257a7c83f4b2c809dfa1"
+checksum = "f032c57793a287a8b374e92a2b606e5eb890539285e4723fe6acb9be1fadcec6"
dependencies = [
"either",
"enum_kind",
@@ -3870,9 +3871,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms"
-version = "0.111.1"
+version = "0.111.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae472031803e9fddb9f9141edc3ec0c3bff5904cd08e0509f2ad88689678ce7c"
+checksum = "8dd7878bd017ed942fdcd5a892fa4990c21b1fe49c4aca7be1ecba16403e7052"
dependencies = [
"swc_atoms",
"swc_common",
@@ -3889,9 +3890,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_base"
-version = "0.56.0"
+version = "0.56.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74824b2df0931ed3d84201e50138b68d1dc78a802aef9dbdec4ea0ffcea8a28b"
+checksum = "d62c460e81027cdda2325348c1e5c0233c59127ab3227a45aaeac80eac7c5df1"
dependencies = [
"once_cell",
"phf",
@@ -3909,9 +3910,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_classes"
-version = "0.43.0"
+version = "0.43.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a972a157b9104b7979a34556841f93e98d18d70b83c9e625b35dd390b57e59f"
+checksum = "5cd6d1fbe53dfa365827eddadbafec687c7afecd294c54a62fedcd92c4e44293"
dependencies = [
"swc_atoms",
"swc_common",
@@ -3936,9 +3937,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_optimization"
-version = "0.81.0"
+version = "0.81.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3af299ad73dc689a0516950613a9262203feff76adc3f2f14307a12bdd5835c9"
+checksum = "653395bad3ace0b3dcc99d9edf45bd08bbd97f48f8aec519d5b8ac336779ee00"
dependencies = [
"ahash",
"dashmap",
@@ -3958,9 +3959,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_proposal"
-version = "0.73.0"
+version = "0.73.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe1cf222cfe757700ffea622589990b1b0ef0a18c85ffe6e8442ba515257aa98"
+checksum = "da8cb3be65a35abfef0f4311d3f76dda381162a4920e526e3e7ac39d693df360"
dependencies = [
"either",
"serde",
@@ -3978,9 +3979,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_react"
-version = "0.75.0"
+version = "0.75.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cee01d3f5c0f424a199a4d13fc6fbe14cfd88ccff0b778558311075477e25310"
+checksum = "4d9e590632bfd9b958f7b68f408040a320a95920021a241f1a403e6670f004cb"
dependencies = [
"ahash",
"base64 0.13.0",
@@ -4003,9 +4004,9 @@ dependencies = [
[[package]]
name = "swc_ecma_transforms_typescript"
-version = "0.77.1"
+version = "0.77.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50560b92ecbd43ee4dea19ae763d0bde8d753c8401d76115c714cfb51f838e76"
+checksum = "29fe8ca3b3ad557407449fcc653acde3026aa6078fa4307ae6b318a35514fd8f"
dependencies = [
"serde",
"swc_atoms",
@@ -4048,9 +4049,9 @@ dependencies = [
[[package]]
name = "swc_ecmascript"
-version = "0.108.2"
+version = "0.108.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae93ca691a78c072b76045f70ffb9daf73e6e21530862c627c35a9a20bbd6d69"
+checksum = "5feaed38d2e24849c1b1bb725ea455855ebe4bff52332a491cabc07d107db322"
dependencies = [
"swc_ecma_ast",
"swc_ecma_codegen",
@@ -5109,9 +5110,9 @@ dependencies = [
[[package]]
name = "zeroize_derive"
-version = "1.2.2"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "65f1a51723ec88c66d5d1fe80c841f17f63587d6691901d66be9bec6c3b51f73"
+checksum = "81e8f13fef10b63c06356d65d416b070798ddabcadc10d3ece0c5be9b3c7eddb"
dependencies = [
"proc-macro2 1.0.36",
"quote 1.0.14",
diff --git a/ext/web/14_compression.js b/ext/web/14_compression.js
new file mode 100644
index 0000000000..1a0f77e665
--- /dev/null
+++ b/ext/web/14_compression.js
@@ -0,0 +1,123 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+// @ts-check
+///
+///
+///
+
+"use strict";
+
+((window) => {
+ const core = window.Deno.core;
+ const webidl = window.__bootstrap.webidl;
+ const { TransformStream } = window.__bootstrap.streams;
+
+ webidl.converters.CompressionFormat = webidl.createEnumConverter(
+ "CompressionFormat",
+ [
+ "deflate",
+ "gzip",
+ ],
+ );
+
+ class CompressionStream {
+ #transform;
+
+ constructor(format) {
+ const prefix = "Failed to construct 'CompressionStream'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ format = webidl.converters.CompressionFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ const rid = core.opSync("op_compression_new", format, false);
+
+ this.#transform = new TransformStream({
+ transform(chunk, controller) {
+ // TODO(lucacasonato): convert chunk to BufferSource
+ const output = core.opSync(
+ "op_compression_write",
+ rid,
+ chunk,
+ );
+ maybeEnqueue(controller, output);
+ },
+ flush(controller) {
+ const output = core.opSync("op_compression_finish", rid);
+ maybeEnqueue(controller, output);
+ },
+ });
+
+ this[webidl.brand] = webidl.brand;
+ }
+
+ get readable() {
+ webidl.assertBranded(this, CompressionStream);
+ return this.#transform.readable;
+ }
+
+ get writable() {
+ webidl.assertBranded(this, CompressionStream);
+ return this.#transform.writable;
+ }
+ }
+
+ webidl.configurePrototype(CompressionStream);
+
+ class DecompressionStream {
+ #transform;
+
+ constructor(format) {
+ const prefix = "Failed to construct 'DecompressionStream'";
+ webidl.requiredArguments(arguments.length, 1, { prefix });
+ format = webidl.converters.CompressionFormat(format, {
+ prefix,
+ context: "Argument 1",
+ });
+
+ const rid = core.opSync("op_compression_new", format, true);
+
+ this.#transform = new TransformStream({
+ transform(chunk, controller) {
+ // TODO(lucacasonato): convert chunk to BufferSource
+ const output = core.opSync(
+ "op_compression_write",
+ rid,
+ chunk,
+ );
+ maybeEnqueue(controller, output);
+ },
+ flush(controller) {
+ const output = core.opSync("op_compression_finish", rid);
+ maybeEnqueue(controller, output);
+ },
+ });
+
+ this[webidl.brand] = webidl.brand;
+ }
+
+ get readable() {
+ webidl.assertBranded(this, DecompressionStream);
+ return this.#transform.readable;
+ }
+
+ get writable() {
+ webidl.assertBranded(this, DecompressionStream);
+ return this.#transform.writable;
+ }
+ }
+
+ function maybeEnqueue(controller, output) {
+ if (output && output.byteLength > 0) {
+ controller.enqueue(output);
+ }
+ }
+
+ webidl.configurePrototype(DecompressionStream);
+
+ window.__bootstrap.compression = {
+ CompressionStream,
+ DecompressionStream,
+ };
+})(globalThis);
diff --git a/ext/web/Cargo.toml b/ext/web/Cargo.toml
index 31982d5901..14523e206f 100644
--- a/ext/web/Cargo.toml
+++ b/ext/web/Cargo.toml
@@ -18,6 +18,7 @@ async-trait = "0.1.51"
base64 = "0.13.0"
deno_core = { version = "0.116.0", path = "../../core" }
encoding_rs = "0.8.29"
+flate2 = "1"
serde = "1.0.129"
tokio = { version = "1.10.1", features = ["full"] }
uuid = { version = "0.8.2", features = ["v4", "serde"] }
diff --git a/ext/web/compression.rs b/ext/web/compression.rs
new file mode 100644
index 0000000000..c84db75506
--- /dev/null
+++ b/ext/web/compression.rs
@@ -0,0 +1,104 @@
+// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
+
+use deno_core::error::AnyError;
+use deno_core::OpState;
+use deno_core::Resource;
+use deno_core::ResourceId;
+use deno_core::ZeroCopyBuf;
+use flate2::write::GzDecoder;
+use flate2::write::GzEncoder;
+use flate2::write::ZlibDecoder;
+use flate2::write::ZlibEncoder;
+use flate2::Compression;
+use std::borrow::Cow;
+use std::cell::RefCell;
+use std::io::Write;
+use std::rc::Rc;
+
+#[derive(Debug)]
+struct CompressionResource(RefCell);
+
+#[derive(Debug)]
+enum Inner {
+ DeflateDecoder(ZlibDecoder>),
+ DeflateEncoder(ZlibEncoder>),
+ GzDecoder(GzDecoder>),
+ GzEncoder(GzEncoder>),
+}
+
+impl Resource for CompressionResource {
+ fn name(&self) -> Cow {
+ "compression".into()
+ }
+}
+
+pub fn op_compression_new(
+ state: &mut OpState,
+ format: String,
+ is_decoder: bool,
+) -> Result {
+ let w = Vec::new();
+ let inner = match (format.as_str(), is_decoder) {
+ ("deflate", true) => Inner::DeflateDecoder(ZlibDecoder::new(w)),
+ ("deflate", false) => {
+ Inner::DeflateEncoder(ZlibEncoder::new(w, Compression::default()))
+ }
+ ("gzip", true) => Inner::GzDecoder(GzDecoder::new(w)),
+ ("gzip", false) => {
+ Inner::GzEncoder(GzEncoder::new(w, Compression::default()))
+ }
+ _ => unreachable!(),
+ };
+ let resource = CompressionResource(RefCell::new(inner));
+ Ok(state.resource_table.add(resource))
+}
+
+pub fn op_compression_write(
+ state: &mut OpState,
+ rid: ResourceId,
+ input: ZeroCopyBuf,
+) -> Result {
+ let resource = state.resource_table.get::(rid)?;
+ let mut inner = resource.0.borrow_mut();
+ let out: Vec = match &mut *inner {
+ Inner::DeflateDecoder(d) => {
+ d.write_all(&input)?;
+ d.flush()?;
+ d.get_mut().drain(..)
+ }
+ Inner::DeflateEncoder(d) => {
+ d.write_all(&input)?;
+ d.flush()?;
+ d.get_mut().drain(..)
+ }
+ Inner::GzDecoder(d) => {
+ d.write_all(&input)?;
+ d.flush()?;
+ d.get_mut().drain(..)
+ }
+ Inner::GzEncoder(d) => {
+ d.write_all(&input)?;
+ d.flush()?;
+ d.get_mut().drain(..)
+ }
+ }
+ .collect();
+ Ok(out.into())
+}
+
+pub fn op_compression_finish(
+ state: &mut OpState,
+ rid: ResourceId,
+ _: (),
+) -> Result {
+ let resource = state.resource_table.take::(rid)?;
+ let resource = Rc::try_unwrap(resource).unwrap();
+ let inner = resource.0.into_inner();
+ let out: Vec = match inner {
+ Inner::DeflateDecoder(d) => d.finish()?,
+ Inner::DeflateEncoder(d) => d.finish()?,
+ Inner::GzDecoder(d) => d.finish()?,
+ Inner::GzEncoder(d) => d.finish()?,
+ };
+ Ok(out.into())
+}
diff --git a/ext/web/lib.deno_web.d.ts b/ext/web/lib.deno_web.d.ts
index ce20f08b10..1233b842f7 100644
--- a/ext/web/lib.deno_web.d.ts
+++ b/ext/web/lib.deno_web.d.ts
@@ -809,3 +809,17 @@ declare function structuredClone(
value: any,
options?: StructuredSerializeOptions,
): any;
+
+declare class CompressionStream {
+ constructor(format: string);
+
+ readonly readable: ReadableStream;
+ readonly writable: WritableStream;
+}
+
+declare class DecompressionStream {
+ constructor(format: string);
+
+ readonly readable: ReadableStream;
+ readonly writable: WritableStream;
+}
diff --git a/ext/web/lib.rs b/ext/web/lib.rs
index 281e55e06e..b32deeb972 100644
--- a/ext/web/lib.rs
+++ b/ext/web/lib.rs
@@ -1,6 +1,7 @@
// Copyright 2018-2022 the Deno authors. All rights reserved. MIT license.
mod blob;
+mod compression;
mod message_port;
use deno_core::error::range_error;
@@ -66,6 +67,7 @@ pub fn init(blob_store: BlobStore, maybe_location: Option) -> Extension {
"11_blob_url.js",
"12_location.js",
"13_message_port.js",
+ "14_compression.js",
))
.ops(vec![
("op_base64_decode", op_sync(op_base64_decode)),
@@ -102,6 +104,18 @@ pub fn init(blob_store: BlobStore, maybe_location: Option) -> Extension {
"op_message_port_recv_message",
op_async(op_message_port_recv_message),
),
+ (
+ "op_compression_new",
+ op_sync(compression::op_compression_new),
+ ),
+ (
+ "op_compression_write",
+ op_sync(compression::op_compression_write),
+ ),
+ (
+ "op_compression_finish",
+ op_sync(compression::op_compression_finish),
+ ),
])
.state(move |state| {
state.put(blob_store.clone());
diff --git a/runtime/js/99_main.js b/runtime/js/99_main.js
index 0c5555dd0f..ba2b367053 100644
--- a/runtime/js/99_main.js
+++ b/runtime/js/99_main.js
@@ -37,6 +37,7 @@ delete Object.prototype.__proto__;
const encoding = window.__bootstrap.encoding;
const colors = window.__bootstrap.colors;
const Console = window.__bootstrap.console.Console;
+ const compression = window.__bootstrap.compression;
const worker = window.__bootstrap.worker;
const internals = window.__bootstrap.internals;
const performance = window.__bootstrap.performance;
@@ -362,11 +363,13 @@ delete Object.prototype.__proto__;
streams.ByteLengthQueuingStrategy,
),
CloseEvent: util.nonEnumerable(CloseEvent),
+ CompressionStream: util.nonEnumerable(compression.CompressionStream),
CountQueuingStrategy: util.nonEnumerable(
streams.CountQueuingStrategy,
),
CryptoKey: util.nonEnumerable(crypto.CryptoKey),
CustomEvent: util.nonEnumerable(CustomEvent),
+ DecompressionStream: util.nonEnumerable(compression.DecompressionStream),
DOMException: util.nonEnumerable(domException.DOMException),
ErrorEvent: util.nonEnumerable(ErrorEvent),
Event: util.nonEnumerable(Event),
diff --git a/tools/wpt/expectation.json b/tools/wpt/expectation.json
index 6c8b2e4d07..f5cb0171d1 100644
--- a/tools/wpt/expectation.json
+++ b/tools/wpt/expectation.json
@@ -4030,5 +4030,37 @@
"Pattern: [{\"pathname\":\"*/{*}\"}] Inputs: [{\"pathname\":\"foo/bar\"}]",
"Pattern: [{\"pathname\":\"*//*\"}] Inputs: [{\"pathname\":\"foo/bar\"}]"
]
+ },
+ "compression": {
+ "compression-bad-chunks.tentative.any.html": true,
+ "compression-bad-chunks.tentative.any.worker.html": true,
+ "compression-including-empty-chunk.tentative.any.html": true,
+ "compression-including-empty-chunk.tentative.any.worker.html": true,
+ "compression-multiple-chunks.tentative.any.html": true,
+ "compression-multiple-chunks.tentative.any.worker.html": true,
+ "compression-output-length.tentative.any.html": true,
+ "compression-output-length.tentative.any.worker.html": true,
+ "compression-stream.tentative.any.html": true,
+ "compression-stream.tentative.any.worker.html": true,
+ "compression-with-detach.tentative.window.html": true,
+ "decompression-bad-chunks.tentative.any.html": true,
+ "decompression-bad-chunks.tentative.any.worker.html": true,
+ "decompression-buffersource.tentative.any.html": true,
+ "decompression-buffersource.tentative.any.worker.html": true,
+ "decompression-constructor-error.tentative.any.html": true,
+ "decompression-constructor-error.tentative.any.worker.html": true,
+ "decompression-correct-input.tentative.any.html": true,
+ "decompression-correct-input.tentative.any.worker.html": true,
+ "decompression-corrupt-input.tentative.any.html": true,
+ "decompression-corrupt-input.tentative.any.worker.html": true,
+ "decompression-empty-input.tentative.any.html": true,
+ "decompression-empty-input.tentative.any.worker.html": true,
+ "decompression-split-chunk.tentative.any.html": true,
+ "decompression-split-chunk.tentative.any.worker.html": true,
+ "decompression-uint8array-output.tentative.any.html": true,
+ "decompression-uint8array-output.tentative.any.worker.html": true,
+ "decompression-with-detach.tentative.window.html": true,
+ "idlharness.https.any.html": true,
+ "idlharness.https.any.worker.html": true
}
}
\ No newline at end of file