From f706ecbc90fc047bb62d7995113e2f8530505ff8 Mon Sep 17 00:00:00 2001 From: jake champion Date: Fri, 27 Feb 2026 08:34:54 +0000 Subject: [PATCH] Use configured compression levels for gzip and brotli Previously, gzip and brotli compression used hardcoded levels even when custom levels were configured via `HostConfiguration` Split initialization into `data_alloc()` and `transform_init()` so that gzip uses `hc->zlib_compression_level()`, and brotli uses `hc->brotli_compression_level()` and `hc->brotli_lgw_size()` Also adds proper error handling if encoder initialization fails --- plugins/compress/brotli_compress.cc | 47 ++++++++++++++++++++++------- plugins/compress/brotli_compress.h | 3 ++ plugins/compress/compress.cc | 21 +++++++++++++ plugins/compress/gzip_compress.cc | 29 ++++++++++++------ plugins/compress/gzip_compress.h | 3 ++ 5 files changed, 83 insertions(+), 20 deletions(-) diff --git a/plugins/compress/brotli_compress.cc b/plugins/compress/brotli_compress.cc index da0eb299971..880e13b9225 100644 --- a/plugins/compress/brotli_compress.cc +++ b/plugins/compress/brotli_compress.cc @@ -32,9 +32,6 @@ namespace Brotli { -const int BROTLI_COMPRESSION_LEVEL = 6; -const int BROTLI_LGW = 16; - static bool compress_operation(Data *data, const char *upstream_buffer, int64_t upstream_length, BrotliEncoderOperation op) { @@ -77,13 +74,7 @@ compress_operation(Data *data, const char *upstream_buffer, int64_t upstream_len void data_alloc(Data *data) { - debug("brotli compression. Create Brotli Encoder Instance."); - data->bstrm.br = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr); - if (!data->bstrm.br) { - fatal("Brotli Encoder Instance Failed"); - } - BrotliEncoderSetParameter(data->bstrm.br, BROTLI_PARAM_QUALITY, BROTLI_COMPRESSION_LEVEL); - BrotliEncoderSetParameter(data->bstrm.br, BROTLI_PARAM_LGWIN, BROTLI_LGW); + data->bstrm.br = nullptr; data->bstrm.next_in = nullptr; data->bstrm.avail_in = 0; data->bstrm.total_in = 0; @@ -92,10 +83,44 @@ data_alloc(Data *data) data->bstrm.total_out = 0; } +bool +transform_init(Data *data) +{ + debug("brotli compression: creating Brotli Encoder Instance"); + data->bstrm.br = BrotliEncoderCreateInstance(nullptr, nullptr, nullptr); + if (!data->bstrm.br) { + error("brotli-transform: failed to create Brotli Encoder Instance"); + return false; + } + + int compression_level = data->hc->brotli_compression_level(); + int lgwin = data->hc->brotli_lgw_size(); + + if (!BrotliEncoderSetParameter(data->bstrm.br, BROTLI_PARAM_QUALITY, compression_level)) { + error("brotli-transform: failed to set compression level %d", compression_level); + BrotliEncoderDestroyInstance(data->bstrm.br); + data->bstrm.br = nullptr; + return false; + } + + if (!BrotliEncoderSetParameter(data->bstrm.br, BROTLI_PARAM_LGWIN, lgwin)) { + error("brotli-transform: failed to set window size %d", lgwin); + BrotliEncoderDestroyInstance(data->bstrm.br); + data->bstrm.br = nullptr; + return false; + } + + debug("brotli compression context initialized with level %d, lgwin %d", compression_level, lgwin); + return true; +} + void data_destroy(Data *data) { - BrotliEncoderDestroyInstance(data->bstrm.br); + if (data->bstrm.br) { + BrotliEncoderDestroyInstance(data->bstrm.br); + data->bstrm.br = nullptr; + } } void diff --git a/plugins/compress/brotli_compress.h b/plugins/compress/brotli_compress.h index 40be1b90363..d799a0fd1fc 100644 --- a/plugins/compress/brotli_compress.h +++ b/plugins/compress/brotli_compress.h @@ -35,6 +35,9 @@ void data_alloc(Data *data); // Destroy brotli compression context void data_destroy(Data *data); +// Configure the context with compression level. Returns true when ready. +bool transform_init(Data *data); + // Compress one chunk of data void transform_one(Data *data, const char *upstream_buffer, int64_t upstream_length); diff --git a/plugins/compress/compress.cc b/plugins/compress/compress.cc index 30cb749d7bc..cd3c7003933 100644 --- a/plugins/compress/compress.cc +++ b/plugins/compress/compress.cc @@ -337,10 +337,31 @@ compress_transform_init(TSCont contp, Data *data) data->downstream_vio = TSVConnWrite(downstream_conn, contp, data->downstream_reader, INT64_MAX); } + // Initialize algorithm-specific compression encoders with configured levels + if ((data->compression_type & (COMPRESSION_TYPE_GZIP | COMPRESSION_TYPE_DEFLATE)) && + (data->compression_algorithms & (ALGORITHM_GZIP | ALGORITHM_DEFLATE))) { + if (!Gzip::transform_init(data)) { + error("Failed to configure gzip/deflate compression context"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + return; + } + } + +#if HAVE_BROTLI_ENCODE_H + if (data->compression_type & COMPRESSION_TYPE_BROTLI && (data->compression_algorithms & ALGORITHM_BROTLI)) { + if (!Brotli::transform_init(data)) { + error("Failed to configure brotli compression context"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); + return; + } + } +#endif + #if HAVE_ZSTD_H if (data->compression_type & COMPRESSION_TYPE_ZSTD && (data->compression_algorithms & ALGORITHM_ZSTD)) { if (!Zstd::transform_init(data)) { error("Failed to configure Zstandard compression context"); + TSHandleMLocRelease(bufp, TS_NULL_MLOC, hdr_loc); return; } } diff --git a/plugins/compress/gzip_compress.cc b/plugins/compress/gzip_compress.cc index 04111a47489..f521e54a7cb 100644 --- a/plugins/compress/gzip_compress.cc +++ b/plugins/compress/gzip_compress.cc @@ -35,7 +35,6 @@ extern const char *dictionary; namespace Gzip { -const int ZLIB_COMPRESSION_LEVEL = 6; voidpf gzip_alloc(voidpf /* opaque ATS_UNUSED */, uInt items, uInt size) { @@ -51,11 +50,6 @@ gzip_free(voidpf /* opaque ATS_UNUSED */, voidpf address) void data_alloc(Data *data) { - int window_bits = WINDOW_BITS_GZIP; - if (data->compression_type & COMPRESSION_TYPE_DEFLATE) { - window_bits = WINDOW_BITS_DEFLATE; - } - data->zstrm.next_in = Z_NULL; data->zstrm.avail_in = 0; data->zstrm.total_in = 0; @@ -66,19 +60,36 @@ data_alloc(Data *data) data->zstrm.zfree = Gzip::gzip_free; data->zstrm.opaque = (voidpf) nullptr; data->zstrm.data_type = Z_ASCII; +} + +bool +transform_init(Data *data) +{ + int window_bits = WINDOW_BITS_GZIP; + if (data->compression_type & COMPRESSION_TYPE_DEFLATE) { + window_bits = WINDOW_BITS_DEFLATE; + } + + int compression_level = data->hc->zlib_compression_level(); + debug("gzip compression context initialized with level %d", compression_level); - int err = deflateInit2(&data->zstrm, ZLIB_COMPRESSION_LEVEL, Z_DEFLATED, window_bits, ZLIB_MEMLEVEL, Z_DEFAULT_STRATEGY); + int err = deflateInit2(&data->zstrm, compression_level, Z_DEFLATED, window_bits, ZLIB_MEMLEVEL, Z_DEFAULT_STRATEGY); if (err != Z_OK) { - fatal("gzip-transform: ERROR: deflateInit (%d)!", err); + error("gzip-transform: deflateInit2 failed (%d)", err); + return false; } if (Compress::dictionary) { err = deflateSetDictionary(&data->zstrm, reinterpret_cast(Compress::dictionary), strlen(Compress::dictionary)); if (err != Z_OK) { - fatal("gzip-transform: ERROR: deflateSetDictionary (%d)!", err); + error("gzip-transform: deflateSetDictionary failed (%d)", err); + deflateEnd(&data->zstrm); + return false; } } + + return true; } void diff --git a/plugins/compress/gzip_compress.h b/plugins/compress/gzip_compress.h index 5257bb4bb49..35078f0994e 100644 --- a/plugins/compress/gzip_compress.h +++ b/plugins/compress/gzip_compress.h @@ -39,6 +39,9 @@ void data_alloc(Data *data); // Destroy gzip/deflate compression context void data_destroy(Data *data); +// Configure the context with compression level. Returns true when ready. +bool transform_init(Data *data); + // Compress one chunk of data void transform_one(Data *data, const char *upstream_buffer, int64_t upstream_length);