blob: d9aa49807775df3f14826170a6969f810be434ab [file] [log] [blame]
// Copyright 2021-2023 Buf Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import * as zlib from "zlib";
import { promisify } from "util";
import type { Compression } from "@apachedubbo/dubbo/protocol";
import { Code, DubboError } from "@apachedubbo/dubbo";
import { getNodeErrorProps } from "./node-error.js";
const gzip = promisify(zlib.gzip);
const gunzip = promisify(zlib.gunzip);
const brotliCompress = promisify(zlib.brotliCompress);
const brotliDecompress = promisify(zlib.brotliDecompress);
/**
* The gzip compression algorithm, implemented with the Node.js built-in module
* zlib. This value can be used for the `sendCompression` and `acceptCompression`
* option of client transports, or for the `acceptCompression` option of server
* plugins like `fastifyDubboPlugin` from @apachedubbo/dubbo-fastify.
*/
export const compressionGzip: Compression = {
name: "gzip",
compress(bytes) {
return gzip(bytes, {});
},
decompress(bytes, readMaxBytes) {
return wrapZLibErrors(
gunzip(bytes, {
maxOutputLength: readMaxBytes,
}),
readMaxBytes
);
},
};
/**
* The brotli compression algorithm, implemented with the Node.js built-in module
* zlib. This value can be used for the `sendCompression` and `acceptCompression`
* option of client transports, or for the `acceptCompression` option of server
* plugins like `fastifyDubboPlugin` from @apachedubbo/dubbo-fastify.
*/
export const compressionBrotli: Compression = {
name: "br",
compress(bytes) {
return brotliCompress(bytes, {});
},
decompress(bytes, readMaxBytes) {
return wrapZLibErrors(
brotliDecompress(bytes, {
maxOutputLength: readMaxBytes,
}),
readMaxBytes
);
},
};
function wrapZLibErrors<T>(
promise: Promise<T>,
readMaxBytes: number
): Promise<T> {
return promise.catch((e) => {
const { code } = getNodeErrorProps(e);
// eslint-disable-next-line @typescript-eslint/switch-exhaustiveness-check
switch (code) {
case "ERR_BUFFER_TOO_LARGE":
e = new DubboError(
`message is larger than configured readMaxBytes ${readMaxBytes} after decompression`,
Code.ResourceExhausted
);
break;
case "Z_DATA_ERROR":
case "ERR_PADDING_2":
e = new DubboError(
"decompression failed",
Code.InvalidArgument,
undefined,
undefined,
e
);
break;
default:
e = new DubboError(
"decompression failed",
Code.Internal,
undefined,
undefined,
e
);
break;
}
return Promise.reject(e);
});
}