From df22356a3a4d960834564c7ac4e5a97fe1959b08 Mon Sep 17 00:00:00 2001 From: skyguard1 Date: Tue, 13 Jul 2021 18:25:30 +0800 Subject: [PATCH] Refactor HttpContentCompressor using CompressionEncoderFactory (#11480) Motivation: The `HttpContentCompressor.beginEncode()` method has too many if else, so consider refactoring Modification: Create the corresponding `CompressionEncoderFactory` according to the compression algorithm, remove the if else Result: The code of `HttpContentCompressor` is cleaner than the previous implementation Signed-off-by: xingrufei Co-authored-by: Norman Maurer --- .../codec/http/CompressionEncoderFactory.java | 27 +++++ .../codec/http/HttpContentCompressor.java | 102 +++++++++++++----- 2 files changed, 104 insertions(+), 25 deletions(-) create mode 100644 codec-http/src/main/java/io/netty/handler/codec/http/CompressionEncoderFactory.java diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/CompressionEncoderFactory.java b/codec-http/src/main/java/io/netty/handler/codec/http/CompressionEncoderFactory.java new file mode 100644 index 0000000000..f3d361d9e7 --- /dev/null +++ b/codec-http/src/main/java/io/netty/handler/codec/http/CompressionEncoderFactory.java @@ -0,0 +1,27 @@ +/* + * Copyright 2021 The Netty Project + * + * The Netty Project licenses this file to you 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: + * + * https://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. + */ +package io.netty.handler.codec.http; + +import io.netty.buffer.ByteBuf; +import io.netty.handler.codec.MessageToByteEncoder; + +/** + * Compression Encoder Factory for create {@link MessageToByteEncoder} + * used to compress http content + */ +interface CompressionEncoderFactory { + MessageToByteEncoder createEncoder(); +} diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java index 903899fffc..dbfc03c496 100644 --- a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java +++ b/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java @@ -15,8 +15,11 @@ */ package io.netty.handler.codec.http; +import io.netty.buffer.ByteBuf; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.embedded.EmbeddedChannel; +import io.netty.handler.codec.MessageToByteEncoder; +import io.netty.handler.codec.compression.ZlibEncoder; import io.netty.handler.codec.compression.Brotli; import io.netty.handler.codec.compression.BrotliEncoder; import io.netty.handler.codec.compression.ZlibCodecFactory; @@ -30,6 +33,9 @@ import io.netty.handler.codec.compression.ZstdEncoder; import io.netty.handler.codec.compression.ZstdOptions; import io.netty.util.internal.ObjectUtil; +import java.util.HashMap; +import java.util.Map; + /** * Compresses an {@link HttpMessage} and an {@link HttpContent} in {@code gzip} or * {@code deflate} encoding while respecting the {@code "Accept-Encoding"} header. @@ -50,6 +56,7 @@ public class HttpContentCompressor extends HttpContentEncoder { private final int memLevel; private final int contentSizeThreshold; private ChannelHandlerContext ctx; + private final Map factories; /** * Creates a new handler with the default compression level (6), @@ -130,6 +137,7 @@ public class HttpContentCompressor extends HttpContentEncoder { this.gzipOptions = null; this.deflateOptions = null; this.zstdOptions = null; + this.factories = null; supportsCompressionOptions = false; } @@ -199,6 +207,14 @@ public class HttpContentCompressor extends HttpContentEncoder { this.gzipOptions = gzipOptions; this.deflateOptions = deflateOptions; this.zstdOptions = zstdOptions; + this.factories = new HashMap() { + { + put("gzip", new GzipEncoderFactory()); + put("deflate", new DeflateEncoderFactory()); + put("br", new BrEncoderFactory()); + put("zstd", new ZstdEncoderFactory()); + } + }; this.compressionLevel = -1; this.windowBits = -1; this.memLevel = -1; @@ -232,32 +248,15 @@ public class HttpContentCompressor extends HttpContentEncoder { return null; } - if (targetContentEncoding.equals("gzip")) { - return new Result(targetContentEncoding, - new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), - ctx.channel().config(), ZlibCodecFactory.newZlibEncoder( - ZlibWrapper.GZIP, gzipOptions.compressionLevel() - , gzipOptions.windowBits(), gzipOptions.memLevel()))); + CompressionEncoderFactory encoderFactory = factories.get(targetContentEncoding); + + if (encoderFactory == null) { + throw new Error(); } - if (targetContentEncoding.equals("deflate")) { - return new Result(targetContentEncoding, - new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), - ctx.channel().config(), ZlibCodecFactory.newZlibEncoder( - ZlibWrapper.ZLIB, deflateOptions.compressionLevel(), - deflateOptions.windowBits(), deflateOptions.memLevel()))); - } - if (targetContentEncoding.equals("br")) { - return new Result(targetContentEncoding, - new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), - ctx.channel().config(), new BrotliEncoder(brotliOptions.parameters()))); - } - if (targetContentEncoding.equals("zstd")) { - return new Result(targetContentEncoding, - new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), - ctx.channel().config(), new ZstdEncoder(zstdOptions.compressionLevel(), - zstdOptions.blockSize(), zstdOptions.maxEncodeSize()))); - } - throw new Error(); + + return new Result(targetContentEncoding, + new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), + ctx.channel().config(), encoderFactory.createEncoder())); } else { ZlibWrapper wrapper = determineWrapper(acceptEncoding); if (wrapper == null) { @@ -384,4 +383,57 @@ public class HttpContentCompressor extends HttpContentEncoder { } return null; } + + /** + * Compression Encoder Factory that creates {@link ZlibEncoder}s + * used to compress http content for gzip content encoding + */ + private final class GzipEncoderFactory implements CompressionEncoderFactory { + + @Override + public MessageToByteEncoder createEncoder() { + return ZlibCodecFactory.newZlibEncoder( + ZlibWrapper.GZIP, gzipOptions.compressionLevel(), + gzipOptions.windowBits(), gzipOptions.memLevel()); + } + } + + /** + * Compression Encoder Factory that creates {@link ZlibEncoder}s + * used to compress http content for deflate content encoding + */ + private final class DeflateEncoderFactory implements CompressionEncoderFactory { + + @Override + public MessageToByteEncoder createEncoder() { + return ZlibCodecFactory.newZlibEncoder( + ZlibWrapper.ZLIB, deflateOptions.compressionLevel(), + deflateOptions.windowBits(), deflateOptions.memLevel()); + } + } + + /** + * Compression Encoder Factory that creates {@link BrotliEncoder}s + * used to compress http content for br content encoding + */ + private final class BrEncoderFactory implements CompressionEncoderFactory { + + @Override + public MessageToByteEncoder createEncoder() { + return new BrotliEncoder(brotliOptions.parameters()); + } + } + + /** + * Compression Encoder Factory for create {@link ZstdEncoder} + * used to compress http content for zstd content encoding + */ + private final class ZstdEncoderFactory implements CompressionEncoderFactory { + + @Override + public MessageToByteEncoder createEncoder() { + return new ZstdEncoder(zstdOptions.compressionLevel(), + zstdOptions.blockSize(), zstdOptions.maxEncodeSize()); + } + } }