11/* * @file
22
3- Transforms content using gzip, deflate or brotli
3+ Transforms content using gzip, deflate, brotli or zstd
44
55 @section license License
66
2323
2424#include < cstring>
2525#include < zlib.h>
26+ #if HAVE_ZSTD_F
27+ #include < zstd.h>
28+ #endif
2629
2730#include " ts/apidefs.h"
2831#include " tscore/ink_config.h"
@@ -71,6 +74,10 @@ const int BROTLI_COMPRESSION_LEVEL = 6;
7174const int BROTLI_LGW = 16 ;
7275#endif
7376
77+ #if HAVE_ZSTD_H
78+ const int ZSTD_COMPRESSION_LEVEL = 6 ;
79+ #endif
80+
7481static const char *global_hidden_header_name = nullptr ;
7582
7683static TSMutex compress_config_mutex = nullptr ;
@@ -191,6 +198,16 @@ data_alloc(int compression_type, int compression_algorithms)
191198 data->bstrm .avail_out = 0 ;
192199 data->bstrm .total_out = 0 ;
193200 }
201+ #endif
202+ #if HAVE_ZSTD_H
203+ data->zstd_ctx = nullptr ;
204+ if (compression_type & COMPRESSION_TYPE_ZSTD) {
205+ debug (" zstd compression. Create Zstd Compression Context." );
206+ data->zstd_ctx = ZSTD_createCCtx ();
207+ if (!data->zstd_ctx ) {
208+ fatal (" Zstd Compression Context Creation Failed" );
209+ }
210+ }
194211#endif
195212 return data;
196213}
@@ -212,6 +229,11 @@ data_destroy(Data *data)
212229#if HAVE_BROTLI_ENCODE_H
213230 BrotliEncoderDestroyInstance (data->bstrm .br );
214231#endif
232+ #if HAVE_ZSTD_H
233+ if (data->zstd_ctx ) {
234+ ZSTD_freeCCtx (data->zstd_ctx );
235+ }
236+ #endif
215237
216238 TSfree (data);
217239}
@@ -233,6 +255,9 @@ content_encoding_header(TSMBuffer bufp, TSMLoc hdr_loc, const int compression_ty
233255 } else if (compression_type & COMPRESSION_TYPE_DEFLATE && (algorithm & ALGORITHM_DEFLATE)) {
234256 value = TS_HTTP_VALUE_DEFLATE;
235257 value_len = TS_HTTP_LEN_DEFLATE;
258+ } else if (compression_type & COMPRESSION_TYPE_ZSTD && (algorithm & ALGORITHM_ZSTD)) {
259+ value = " zstd" ;
260+ value_len = strlen (" zstd" );
236261 }
237262
238263 if (value_len == 0 ) {
@@ -357,6 +382,16 @@ compress_transform_init(TSCont contp, Data *data)
357382 data->downstream_vio = TSVConnWrite (downstream_conn, contp, data->downstream_reader , INT64_MAX);
358383 }
359384
385+ #if HAVE_ZSTD_H
386+ if (data->compression_type & COMPRESSION_TYPE_ZSTD) {
387+ zstd_compress_init (data);
388+ if (!data->zstd_cctx ) {
389+ TSError (" Failed to create Zstandard compression context" );
390+ return ;
391+ }
392+ }
393+ #endif
394+
360395 TSHandleMLocRelease (bufp, TS_NULL_MLOC, hdr_loc);
361396}
362397
@@ -462,6 +497,39 @@ brotli_transform_one(Data *data, const char *upstream_buffer, int64_t upstream_l
462497}
463498#endif
464499
500+ #if HAVE_ZSTD_H
501+ static void
502+ zstd_compress_init (Data *data)
503+ {
504+ data->zstd_cctx = ZSTD_createCCtx ();
505+ if (!data->zstd_cctx ) {
506+ error (" Failed to initialize Zstd compression context" );
507+ }
508+ }
509+
510+ static void
511+ zstd_compress_finish (Data *data)
512+ {
513+ if (data->zstd_cctx ) {
514+ ZSTD_freeCCtx (data->zstd_cctx );
515+ data->zstd_cctx = nullptr ;
516+ }
517+ }
518+
519+ static void
520+ zstd_compress_one (Data *data, const char *upstream_buffer, int64_t upstream_length)
521+ {
522+ char output_buffer[ZSTD_CStreamOutSize ()];
523+ size_t compressed_size = ZSTD_compressCCtx (data->zstd_cctx , output_buffer, sizeof (output_buffer), upstream_buffer, upstream_length, ZSTD_COMPRESSION_LEVEL);
524+ if (ZSTD_isError (compressed_size)) {
525+ error (" Zstd compression failed: %s" , ZSTD_getErrorName (compressed_size));
526+ return ;
527+ }
528+ TSIOBufferWrite (data->downstream_buffer , output_buffer, compressed_size);
529+ data->downstream_length += compressed_size;
530+ }
531+ #endif
532+
465533static void
466534compress_transform_one (Data *data, TSIOBufferReader upstream_reader, int amount)
467535{
@@ -488,6 +556,11 @@ compress_transform_one(Data *data, TSIOBufferReader upstream_reader, int amount)
488556 if (data->compression_type & COMPRESSION_TYPE_BROTLI && (data->compression_algorithms & ALGORITHM_BROTLI)) {
489557 brotli_transform_one (data, upstream_buffer, upstream_length);
490558 } else
559+ #endif
560+ #if HAVE_ZSTD_H
561+ if (data->compression_type & COMPRESSION_TYPE_ZSTD && (data->compression_algorithms & ALGORITHM_ZSTD)) {
562+ zstd_compress_one (data, upstream_buffer, upstream_length);
563+ } else
491564#endif
492565 if ((data->compression_type & (COMPRESSION_TYPE_GZIP | COMPRESSION_TYPE_DEFLATE)) &&
493566 (data->compression_algorithms & (ALGORITHM_GZIP | ALGORITHM_DEFLATE))) {
@@ -576,6 +649,12 @@ compress_transform_finish(Data *data)
576649 brotli_transform_finish (data);
577650 debug (" compress_transform_finish: brotli compression finish" );
578651 } else
652+ #endif
653+ #if HAVE_ZSTD_H
654+ if (data->compression_type & COMPRESSION_TYPE_ZSTD && data->compression_algorithms & ALGORITHM_ZSTD) {
655+ zstd_compress_finish (data);
656+ debug (" compress_transform_finish: zstd compression finish" );
657+ } else
579658#endif
580659 if ((data->compression_type & (COMPRESSION_TYPE_GZIP | COMPRESSION_TYPE_DEFLATE)) &&
581660 (data->compression_algorithms & (ALGORITHM_GZIP | ALGORITHM_DEFLATE))) {
@@ -771,6 +850,11 @@ transformable(TSHttpTxn txnp, bool server, HostConfiguration *host_configuration
771850 compression_acceptable = 1 ;
772851 }
773852 *compress_type |= COMPRESSION_TYPE_GZIP;
853+ } else if (strncasecmp (value, " zstd" , sizeof (" zstd" ) - 1 ) == 0 ) {
854+ if (*algorithms & ALGORITHM_ZSTD) {
855+ compression_acceptable = 1 ;
856+ }
857+ *compress_type |= COMPRESSION_TYPE_ZSTD;
774858 }
775859 }
776860
0 commit comments