summaryrefslogtreecommitdiff
path: root/ext/node/polyfills
diff options
context:
space:
mode:
authorDivy Srivastava <dj.srivastava23@gmail.com>2023-06-24 16:12:08 +0200
committerGitHub <noreply@github.com>2023-06-24 19:42:08 +0530
commit4a18c761351dccb146973793cf22e6efffff18bf (patch)
tree35f23a7f6c64c0a9f28a5f0e21d6ecbd378a5c28 /ext/node/polyfills
parent7a8df8f00cce29605b2d74cb32b255d482f29dda (diff)
fix(ext/node): support brotli APIs (#19223)
Co-authored-by: Bartek IwaƄczuk <biwanczuk@gmail.com>
Diffstat (limited to 'ext/node/polyfills')
-rw-r--r--ext/node/polyfills/_brotli.js145
-rw-r--r--ext/node/polyfills/zlib.ts42
2 files changed, 169 insertions, 18 deletions
diff --git a/ext/node/polyfills/_brotli.js b/ext/node/polyfills/_brotli.js
new file mode 100644
index 000000000..d200d01b6
--- /dev/null
+++ b/ext/node/polyfills/_brotli.js
@@ -0,0 +1,145 @@
+// Copyright 2018-2023 the Deno authors. All rights reserved. MIT license.
+
+import { zlib as constants } from "ext:deno_node/internal_binding/constants.ts";
+import { TextEncoder } from "ext:deno_web/08_text_encoding.js";
+import { Transform } from "ext:deno_node/stream.ts";
+import { Buffer } from "ext:deno_node/buffer.ts";
+
+const { core } = globalThis.__bootstrap;
+const { ops } = core;
+
+const enc = new TextEncoder();
+const toU8 = (input) => {
+ if (typeof input === "string") {
+ return enc.encode(input);
+ }
+
+ return input;
+};
+
+export function createBrotliCompress(options) {
+ return new BrotliCompress(options);
+}
+
+export function createBrotliDecompress(options) {
+ return new BrotliDecompress(options);
+}
+
+export class BrotliDecompress extends Transform {
+ #context;
+
+ // TODO(littledivy): use `options` argument
+ constructor(_options = {}) {
+ super({
+ // TODO(littledivy): use `encoding` argument
+ transform(chunk, _encoding, callback) {
+ const input = toU8(chunk);
+ const output = new Uint8Array(1024);
+ const avail = ops.op_brotli_decompress_stream(context, input, output);
+ this.push(output.slice(0, avail));
+ callback();
+ },
+ flush(callback) {
+ core.close(context);
+ callback();
+ },
+ });
+
+ this.#context = ops.op_create_brotli_decompress();
+ const context = this.#context;
+ }
+}
+
+export class BrotliCompress extends Transform {
+ #context;
+
+ constructor(options = {}) {
+ super({
+ // TODO(littledivy): use `encoding` argument
+ transform(chunk, _encoding, callback) {
+ const input = toU8(chunk);
+ const output = new Uint8Array(brotliMaxCompressedSize(input.length));
+ const avail = ops.op_brotli_compress_stream(context, input, output);
+ this.push(output.slice(0, avail));
+ callback();
+ },
+ flush(callback) {
+ const output = new Uint8Array(1024);
+ const avail = ops.op_brotli_compress_stream_end(context, output);
+ this.push(output.slice(0, avail));
+ callback();
+ },
+ });
+
+ const params = Object.values(options?.params ?? {});
+ this.#context = ops.op_create_brotli_compress(params);
+ const context = this.#context;
+ }
+}
+
+function oneOffCompressOptions(options) {
+ const quality = options?.params?.[constants.BROTLI_PARAM_QUALITY] ??
+ constants.BROTLI_DEFAULT_QUALITY;
+ const lgwin = options?.params?.[constants.BROTLI_PARAM_LGWIN] ??
+ constants.BROTLI_DEFAULT_WINDOW;
+ const mode = options?.params?.[constants.BROTLI_PARAM_MODE] ??
+ constants.BROTLI_MODE_GENERIC;
+
+ return {
+ quality,
+ lgwin,
+ mode,
+ };
+}
+
+function brotliMaxCompressedSize(input) {
+ if (input == 0) return 2;
+
+ // [window bits / empty metadata] + N * [uncompressed] + [last empty]
+ const numLargeBlocks = input >> 24;
+ const overhead = 2 + (4 * numLargeBlocks) + 3 + 1;
+ const result = input + overhead;
+
+ return result < input ? 0 : result;
+}
+
+export function brotliCompress(
+ input,
+ options,
+ callback,
+) {
+ const buf = toU8(input);
+
+ if (typeof options === "function") {
+ callback = options;
+ options = {};
+ }
+
+ const { quality, lgwin, mode } = oneOffCompressOptions(options);
+ core.opAsync("op_brotli_compress_async", buf, quality, lgwin, mode)
+ .then((result) => callback(null, result))
+ .catch((err) => callback(err));
+}
+
+export function brotliCompressSync(
+ input,
+ options,
+) {
+ const buf = toU8(input);
+ const output = new Uint8Array(brotliMaxCompressedSize(buf.length));
+
+ const { quality, lgwin, mode } = oneOffCompressOptions(options);
+ const len = ops.op_brotli_compress(buf, output, quality, lgwin, mode);
+ return Buffer.from(output.subarray(0, len));
+}
+
+export function brotliDecompress(input) {
+ const buf = toU8(input);
+ return ops.op_brotli_decompress_async(buf)
+ .then((result) => callback(null, Buffer.from(result)))
+ .catch((err) => callback(err));
+}
+
+export function brotliDecompressSync(input) {
+ return Buffer.from(ops.op_brotli_decompress(toU8(input)));
+}
diff --git a/ext/node/polyfills/zlib.ts b/ext/node/polyfills/zlib.ts
index 07bc65c2d..33f17fc4e 100644
--- a/ext/node/polyfills/zlib.ts
+++ b/ext/node/polyfills/zlib.ts
@@ -32,11 +32,29 @@ import {
unzip,
unzipSync,
} from "ext:deno_node/_zlib.mjs";
+import {
+ brotliCompress,
+ brotliCompressSync,
+ brotliDecompress,
+ brotliDecompressSync,
+ createBrotliCompress,
+ createBrotliDecompress,
+} from "ext:deno_node/_brotli.js";
+
export class Options {
constructor() {
notImplemented("Options.prototype.constructor");
}
}
+
+interface IBrotliOptions {
+ flush?: number;
+ finishFlush?: number;
+ chunkSize?: number;
+ params?: Record<number, number>;
+ maxOutputLength?: number;
+}
+
export class BrotliOptions {
constructor() {
notImplemented("BrotliOptions.prototype.constructor");
@@ -58,24 +76,6 @@ export class ZlibBase {
}
}
export { constants };
-export function createBrotliCompress() {
- notImplemented("createBrotliCompress");
-}
-export function createBrotliDecompress() {
- notImplemented("createBrotliDecompress");
-}
-export function brotliCompress() {
- notImplemented("brotliCompress");
-}
-export function brotliCompressSync() {
- notImplemented("brotliCompressSync");
-}
-export function brotliDecompress() {
- notImplemented("brotliDecompress");
-}
-export function brotliDecompressSync() {
- notImplemented("brotliDecompressSync");
-}
export default {
Options,
@@ -122,7 +122,13 @@ export default {
};
export {
+ brotliCompress,
+ brotliCompressSync,
+ brotliDecompress,
+ brotliDecompressSync,
codes,
+ createBrotliCompress,
+ createBrotliDecompress,
createDeflate,
createDeflateRaw,
createGunzip,