Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement brotli one shot methods #2660

Merged
merged 1 commit into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 61 additions & 25 deletions src/node/internal/internal_zlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
default as zlibUtil,
type ZlibOptions,
type CompressCallback,
type InternalCompressCallback,
type BrotliOptions,
} from 'node-internal:zlib';
import { Buffer } from 'node-internal:internal_buffer';
Expand Down Expand Up @@ -87,10 +88,24 @@ export function unzipSync(
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_UNZIP));
}

export function brotliDecompressSync(
data: ArrayBufferView | string,
options: BrotliOptions = {}
): Buffer {
return Buffer.from(zlibUtil.brotliDecompressSync(data, options));
}

export function brotliCompressSync(
data: ArrayBufferView | string,
options: BrotliOptions = {}
): Buffer {
return Buffer.from(zlibUtil.brotliCompressSync(data, options));
}

function normalizeArgs(
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
): [ZlibOptions, CompressCallback<Error, Buffer>] {
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): [ZlibOptions, CompressCallback] {
if (typeof optionsOrCallback === 'function') {
return [{}, optionsOrCallback];
} else if (typeof callbackOrUndefined === 'function') {
Expand All @@ -100,25 +115,22 @@ function normalizeArgs(
throw new ERR_INVALID_ARG_TYPE('callback', 'Function', callbackOrUndefined);
}

function wrapCallback(
callback: CompressCallback<Error, Buffer>
): CompressCallback<string, ArrayBuffer> {
return (error: string | null, result: ArrayBuffer | undefined) => {
function wrapCallback(callback: CompressCallback): InternalCompressCallback {
return (res: Error | ArrayBuffer) => {
queueMicrotask(() => {
if (error) {
callback(new Error(error));
if (res instanceof Error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Is there a way to avoid this check on the runtime. Checking for truthy value vs. instanceof checks have different characteristics and runtime performance costs.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll look into whether some template voodoo is possible

callback(res);
} else {
// To avoid having a runtime assertion, let's use type assertion.
callback(null, Buffer.from(result as ArrayBuffer));
callback(null, Buffer.from(res));
}
});
};
}

export function inflate(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
Expand All @@ -129,8 +141,8 @@ export function inflate(

export function unzip(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
Expand All @@ -141,8 +153,8 @@ export function unzip(

export function inflateRaw(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
Expand All @@ -158,8 +170,8 @@ export function inflateRaw(

export function gunzip(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
Expand All @@ -170,8 +182,8 @@ export function gunzip(

export function deflate(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
Expand All @@ -182,8 +194,8 @@ export function deflate(

export function deflateRaw(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
Expand All @@ -199,8 +211,8 @@ export function deflateRaw(

export function gzip(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
optionsOrCallback: ZlibOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
Expand All @@ -209,6 +221,30 @@ export function gzip(
zlibUtil.zlib(data, options, zlibUtil.CONST_GZIP, wrapCallback(callback));
}

export function brotliDecompress(
data: ArrayBufferView | string,
optionsOrCallback: BrotliOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.brotliDecompress(data, options, wrapCallback(callback));
}

export function brotliCompress(
data: ArrayBufferView | string,
optionsOrCallback: BrotliOptions | CompressCallback,
callbackOrUndefined?: CompressCallback
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.brotliCompress(data, options, wrapCallback(callback));
}

export class Gzip extends Zlib {
public constructor(options: ZlibOptions) {
super(options, CONST_GZIP);
Expand Down
29 changes: 25 additions & 4 deletions src/node/internal/zlib.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import { owner_symbol, type Zlib } from 'node-internal:internal_zlib_base';

export function crc32(data: ArrayBufferView, value: number): number;

export type CompressCallback<ErrT, BufT> = (
error: ErrT | null,
result?: BufT
export type CompressCallback = (
err: Error | null,
buffer?: ArrayBuffer
) => void;
export type InternalCompressCallback = (res: Error | ArrayBuffer) => void;

export function crc32(data: ArrayBufferView | string, value: number): number;
export function zlibSync(
Expand All @@ -17,8 +18,28 @@ export function zlib(
data: ArrayBufferView | string,
options: ZlibOptions,
mode: number,
cb: CompressCallback<string, ArrayBuffer>
cb: InternalCompressCallback
): void;

export function brotliDecompressSync(
data: ArrayBufferView | string,
options: BrotliOptions
): ArrayBuffer;
export function brotliDecompress(
data: ArrayBufferView | string,
options: BrotliOptions,
cb: InternalCompressCallback
): void;

export function brotliCompressSync(
data: ArrayBufferView | string,
options: BrotliOptions
): ArrayBuffer;
export function brotliCompress(
data: ArrayBufferView | string,
options: BrotliOptions,
cb: InternalCompressCallback
): void;

// zlib.constants (part of the API contract for node:zlib)
export const CONST_Z_NO_FLUSH: number;
Expand Down
12 changes: 12 additions & 0 deletions src/node/zlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ const gunzip = protectMethod(zlib.gunzip);
const gunzipSync = protectMethod(zlib.gunzipSync);
const unzip = protectMethod(zlib.unzip);
const unzipSync = protectMethod(zlib.unzipSync);
const brotliCompress = protectMethod(zlib.brotliCompress);
const brotliCompressSync = protectMethod(zlib.brotliCompressSync);
const brotliDecompress = protectMethod(zlib.brotliDecompress);
const brotliDecompressSync = protectMethod(zlib.brotliDecompressSync);

export {
crc32,
Expand Down Expand Up @@ -92,6 +96,10 @@ export {
gunzipSync,
unzip,
unzipSync,
brotliDecompress,
brotliDecompressSync,
brotliCompress,
brotliCompressSync,
};

export default {
Expand Down Expand Up @@ -136,4 +144,8 @@ export default {
gunzipSync,
unzip,
unzipSync,
brotliDecompress,
brotliDecompressSync,
brotliCompress,
brotliCompressSync,
};
Loading