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

zlib one-shot methods #2533

Merged
merged 1 commit into from
Aug 26, 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
267 changes: 252 additions & 15 deletions src/node/internal/internal_zlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,14 @@
// https://opensource.org/licenses/Apache-2.0
// Copyright Joyent and Node contributors. All rights reserved. MIT license.

import { default as zlibUtil, type ZlibOptions } from 'node-internal:zlib';
import {
default as zlibUtil,
type ZlibOptions,
type CompressCallback,
} from 'node-internal:zlib';
import { Buffer } from 'node-internal:internal_buffer';
import { validateUint32 } from 'node-internal:validators';
import { ERR_INVALID_ARG_TYPE } from 'node-internal:internal_errors';
import { isArrayBufferView } from 'node-internal:internal_types';
import { Zlib } from 'node-internal:internal_zlib_base';

const {
Expand All @@ -20,6 +23,253 @@ const {
CONST_UNZIP,
} = zlibUtil;

export function crc32(
data: ArrayBufferView | string,
value: number = 0
): number {
validateUint32(value, 'value');
npaun marked this conversation as resolved.
Show resolved Hide resolved
return zlibUtil.crc32(data, value);
}

export function inflateSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_INFLATE));
}

export function deflateSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_DEFLATE));
}

export function gunzipSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_GUNZIP));
}

export function gzipSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(zlibUtil.zlibSync(data, options, zlibUtil.CONST_GZIP));
}

export function inflateRawSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(
zlibUtil.zlibSync(data, options, zlibUtil.CONST_INFLATERAW)
);
}

export function deflateRawSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(
zlibUtil.zlibSync(data, options, zlibUtil.CONST_DEFLATERAW)
);
}

export function unzipSync(
data: ArrayBufferView | string,
options: ZlibOptions = {}
): Buffer {
return Buffer.from(
zlibUtil.zlibSync(data, options, zlibUtil.CONST_DEFLATERAW)
);
}

function normalizeArgs(
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
): [ZlibOptions, CompressCallback<Error, Buffer>] {
if (typeof optionsOrCallback === 'function') {
return [{}, optionsOrCallback];
} else if (typeof callbackOrUndefined === 'function') {
return [optionsOrCallback, callbackOrUndefined];
}

throw new ERR_INVALID_ARG_TYPE('callback', 'Function', callbackOrUndefined);
}

function wrapCallback(
callback: CompressCallback<Error, Buffer>
): CompressCallback<string, ArrayBuffer> {
return (error: string | undefined, result: ArrayBuffer | undefined) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
queueMicrotask(() => {
npaun marked this conversation as resolved.
Show resolved Hide resolved
callback(
error ? new Error(error) : undefined,
result ? Buffer.from(result) : undefined
);
});
};
}

export function inflate(
data: ArrayBufferView | string,
callback: CompressCallback<Error, Buffer>
): void;
export function inflate(
data: ArrayBufferView | string,
options: ZlibOptions,
callback: CompressCallback<Error, Buffer>
): void;
export function inflate(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_INFLATE, wrapCallback(callback));
}

export function unzip(
data: ArrayBufferView | string,
callback: CompressCallback<Error, Buffer>
): void;
export function unzip(
data: ArrayBufferView | string,
options: ZlibOptions,
callback: CompressCallback<Error, Buffer>
): void;
export function unzip(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_UNZIP, wrapCallback(callback));
}

export function inflateRaw(
data: ArrayBufferView | string,
callback: CompressCallback<Error, Buffer>
): void;
export function inflateRaw(
data: ArrayBufferView | string,
options: ZlibOptions,
callback: CompressCallback<Error, Buffer>
): void;
export function inflateRaw(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(
data,
options,
zlibUtil.CONST_INFLATERAW,
wrapCallback(callback)
);
}

export function gunzip(
data: ArrayBufferView | string,
callback: CompressCallback<Error, Buffer>
): void;
export function gunzip(
data: ArrayBufferView | string,
options: ZlibOptions,
callback: CompressCallback<Error, Buffer>
): void;
export function gunzip(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_GUNZIP, wrapCallback(callback));
}

export function deflate(
data: ArrayBufferView | string,
callback: CompressCallback<Error, Buffer>
): void;
export function deflate(
data: ArrayBufferView | string,
options: ZlibOptions,
callback: CompressCallback<Error, Buffer>
): void;
export function deflate(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(data, options, zlibUtil.CONST_DEFLATE, wrapCallback(callback));
}

export function deflateRaw(
data: ArrayBufferView | string,
callback: CompressCallback<Error, Buffer>
): void;
export function deflateRaw(
data: ArrayBufferView | string,
options: ZlibOptions,
callback: CompressCallback<Error, Buffer>
): void;
export function deflateRaw(
data: ArrayBufferView | string,
optionsOrCallback: ZlibOptions | CompressCallback<Error, Buffer>,
callbackOrUndefined?: CompressCallback<Error, Buffer>
): void {
const [options, callback] = normalizeArgs(
optionsOrCallback,
callbackOrUndefined
);
zlibUtil.zlib(
data,
options,
zlibUtil.CONST_DEFLATERAW,
wrapCallback(callback)
);
}

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

const constPrefix = 'CONST_';
export const constants: Record<string, number> = {};

Expand All @@ -41,19 +291,6 @@ Object.defineProperties(
)
);

export function crc32(
Copy link
Member

Choose a reason for hiding this comment

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

I think we should move this function change to a different pull-request.

Copy link
Member Author

Choose a reason for hiding this comment

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

Normally I'm in favour of splitting PRs into small chunks, however, this time I think the changes are OK to go together, because I'm reusing the input source stuff between zlibsync and crc32sync

data: ArrayBufferView | string,
value: number = 0
): number {
if (typeof data === 'string') {
data = Buffer.from(data);
} else if (!isArrayBufferView(data)) {
throw new ERR_INVALID_ARG_TYPE('data', 'ArrayBufferView', typeof data);
}
validateUint32(value, 'value');
return zlibUtil.crc32(data, value);
}

export class Gzip extends Zlib {
public constructor(options: ZlibOptions) {
super(options, CONST_GZIP);
Expand Down
18 changes: 18 additions & 0 deletions src/node/internal/zlib.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,24 @@ 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,
result?: BufT
) => void;

export function crc32(data: ArrayBufferView | string, value: number): number;
export function zlibSync(
data: ArrayBufferView | string,
options: ZlibOptions,
mode: number
): ArrayBuffer;
export function zlib(
data: ArrayBufferView | string,
options: ZlibOptions,
mode: number,
cb: CompressCallback<string, ArrayBuffer>
): ArrayBuffer;
anonrig marked this conversation as resolved.
Show resolved Hide resolved

// zlib.constants (part of the API contract for node:zlib)
export const CONST_Z_NO_FLUSH: number;
export const CONST_Z_PARTIAL_FLUSH: number;
Expand Down
50 changes: 50 additions & 0 deletions src/node/zlib.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,24 @@ const createInflate = protectMethod(zlib.createInflate);
const createInflateRaw = protectMethod(zlib.createInflateRaw);
const createUnzip = protectMethod(zlib.createUnzip);

const inflate = protectMethod(zlib.inflate);
const inflateSync = protectMethod(zlib.inflateSync);
const deflate = protectMethod(zlib.deflate);
const deflateSync = protectMethod(zlib.deflateSync);

const inflateRaw = protectMethod(zlib.inflateRaw);
const inflateRawSync = protectMethod(zlib.inflateRawSync);
const deflateRaw = protectMethod(zlib.deflateRaw);
const deflateRawSync = protectMethod(zlib.deflateRawSync);

const gzip = protectMethod(zlib.gzip);
const gzipSync = protectMethod(zlib.gzipSync);
const gunzip = protectMethod(zlib.gunzip);
const gunzipSync = protectMethod(zlib.gunzipSync);

const unzip = protectMethod(zlib.unzip);
const unzipSync = protectMethod(zlib.unzipSync);

export {
crc32,
constants,
Expand All @@ -50,6 +68,22 @@ export {
createInflate,
createInflateRaw,
createUnzip,

// One-shot methods
inflate,
inflateSync,
deflate,
deflateSync,
inflateRaw,
inflateRawSync,
deflateRaw,
deflateRawSync,
gzip,
gzipSync,
gunzip,
gunzipSync,
unzip,
unzipSync,
};

export default {
Expand All @@ -73,4 +107,20 @@ export default {
createInflate,
createInflateRaw,
createUnzip,

// One-shot methods
inflate,
inflateSync,
deflate,
deflateSync,
inflateRaw,
inflateRawSync,
deflateRaw,
deflateRawSync,
gzip,
gzipSync,
gunzip,
gunzipSync,
unzip,
unzipSync,
};
Loading
Loading