6161
6262import java .net .InetSocketAddress ;
6363import java .net .SocketOption ;
64+ import java .util .ArrayList ;
65+ import java .util .List ;
6466import java .util .concurrent .TimeUnit ;
6567
6668import io .netty .bootstrap .ServerBootstrap ;
7779import io .netty .channel .SimpleChannelInboundHandler ;
7880import io .netty .channel .socket .nio .NioChannelOption ;
7981import io .netty .handler .codec .ByteToMessageDecoder ;
82+ import io .netty .handler .codec .compression .Brotli ;
83+ import io .netty .handler .codec .compression .CompressionOptions ;
84+ import io .netty .handler .codec .compression .DeflateOptions ;
85+ import io .netty .handler .codec .compression .GzipOptions ;
86+ import io .netty .handler .codec .compression .StandardCompressionOptions ;
87+ import io .netty .handler .codec .compression .ZstdEncoder ;
8088import io .netty .handler .codec .http .HttpContentCompressor ;
8189import io .netty .handler .codec .http .HttpContentDecompressor ;
8290import io .netty .handler .codec .http .HttpMessage ;
@@ -440,7 +448,7 @@ protected void channelRead0(ChannelHandlerContext ctx, HttpMessage msg) throws E
440448 pipeline .addAfter (
441449 "aggregator" ,
442450 "encoder_compress" ,
443- new HttpContentCompressor (handlingSettings .getCompressionLevel ())
451+ new HttpContentCompressor (defaultCompressionOptions ( handlingSettings .getCompressionLevel () ))
444452 );
445453 }
446454 pipeline .addBefore ("handler" , "request_creator" , requestCreator );
@@ -467,7 +475,10 @@ protected void configureDefaultHttpPipeline(ChannelPipeline pipeline) {
467475 aggregator .setMaxCumulationBufferComponents (transport .maxCompositeBufferComponents );
468476 pipeline .addLast ("aggregator" , aggregator );
469477 if (handlingSettings .isCompression ()) {
470- pipeline .addLast ("encoder_compress" , new HttpContentCompressor (handlingSettings .getCompressionLevel ()));
478+ pipeline .addLast (
479+ "encoder_compress" ,
480+ new HttpContentCompressor (defaultCompressionOptions (handlingSettings .getCompressionLevel ()))
481+ );
471482 }
472483 pipeline .addLast ("request_creator" , requestCreator );
473484 pipeline .addLast ("response_creator" , responseCreator );
@@ -512,7 +523,10 @@ protected void initChannel(Channel childChannel) throws Exception {
512523
513524 if (handlingSettings .isCompression ()) {
514525 childChannel .pipeline ()
515- .addLast ("encoder_compress" , new HttpContentCompressor (handlingSettings .getCompressionLevel ()));
526+ .addLast (
527+ "encoder_compress" ,
528+ new HttpContentCompressor (defaultCompressionOptions (handlingSettings .getCompressionLevel ()))
529+ );
516530 }
517531
518532 childChannel .pipeline ()
@@ -563,4 +577,59 @@ protected ChannelInboundHandlerAdapter createHeaderVerifier() {
563577 protected ChannelInboundHandlerAdapter createDecompressor () {
564578 return new HttpContentDecompressor ();
565579 }
580+
581+ /**
582+ * Copy of {@link HttpContentCompressor} default compression options with ZSTD excluded:
583+ * although zstd-jni is on the classpath, {@link ZstdEncoder} requires direct buffers support
584+ * which by default {@link NettyAllocator} does not provide.
585+ *
586+ * @param compressionLevel
587+ * {@code 1} yields the fastest compression and {@code 9} yields the
588+ * best compression. {@code 0} means no compression. The default
589+ * compression level is {@code 6}.
590+ *
591+ * @return default compression options
592+ */
593+ private static CompressionOptions [] defaultCompressionOptions (int compressionLevel ) {
594+ return defaultCompressionOptions (compressionLevel , 15 , 8 );
595+ }
596+
597+ /**
598+ * Copy of {@link HttpContentCompressor} default compression options with ZSTD excluded:
599+ * although zstd-jni is on the classpath, {@link ZstdEncoder} requires direct buffers support
600+ * which by default {@link NettyAllocator} does not provide.
601+ *
602+ * @param compressionLevel
603+ * {@code 1} yields the fastest compression and {@code 9} yields the
604+ * best compression. {@code 0} means no compression. The default
605+ * compression level is {@code 6}.
606+ * @param windowBits
607+ * The base two logarithm of the size of the history buffer. The
608+ * value should be in the range {@code 9} to {@code 15} inclusive.
609+ * Larger values result in better compression at the expense of
610+ * memory usage. The default value is {@code 15}.
611+ * @param memLevel
612+ * How much memory should be allocated for the internal compression
613+ * state. {@code 1} uses minimum memory and {@code 9} uses maximum
614+ * memory. Larger values result in better and faster compression
615+ * at the expense of memory usage. The default value is {@code 8}
616+ *
617+ * @return default compression options
618+ */
619+ private static CompressionOptions [] defaultCompressionOptions (int compressionLevel , int windowBits , int memLevel ) {
620+ final List <CompressionOptions > options = new ArrayList <CompressionOptions >(4 );
621+ final GzipOptions gzipOptions = StandardCompressionOptions .gzip (compressionLevel , windowBits , memLevel );
622+ final DeflateOptions deflateOptions = StandardCompressionOptions .deflate (compressionLevel , windowBits , memLevel );
623+
624+ options .add (gzipOptions );
625+ options .add (deflateOptions );
626+ options .add (StandardCompressionOptions .snappy ());
627+
628+ if (Brotli .isAvailable ()) {
629+ options .add (StandardCompressionOptions .brotli ());
630+ }
631+
632+ return options .toArray (new CompressionOptions [0 ]);
633+ }
634+
566635}
0 commit comments