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 <xingrufei@sogou-inc.com>
Co-authored-by: Norman Maurer <norman_maurer@apple.com>
This commit is contained in:
skyguard1 2021-07-13 18:25:30 +08:00 committed by GitHub
parent 6085cd7ab6
commit df22356a3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 104 additions and 25 deletions

View File

@ -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<ByteBuf> createEncoder();
}

View File

@ -15,8 +15,11 @@
*/ */
package io.netty.handler.codec.http; package io.netty.handler.codec.http;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedChannel; 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.Brotli;
import io.netty.handler.codec.compression.BrotliEncoder; import io.netty.handler.codec.compression.BrotliEncoder;
import io.netty.handler.codec.compression.ZlibCodecFactory; 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.handler.codec.compression.ZstdOptions;
import io.netty.util.internal.ObjectUtil; 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 * Compresses an {@link HttpMessage} and an {@link HttpContent} in {@code gzip} or
* {@code deflate} encoding while respecting the {@code "Accept-Encoding"} header. * {@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 memLevel;
private final int contentSizeThreshold; private final int contentSizeThreshold;
private ChannelHandlerContext ctx; private ChannelHandlerContext ctx;
private final Map<String, CompressionEncoderFactory> factories;
/** /**
* Creates a new handler with the default compression level (<tt>6</tt>), * Creates a new handler with the default compression level (<tt>6</tt>),
@ -130,6 +137,7 @@ public class HttpContentCompressor extends HttpContentEncoder {
this.gzipOptions = null; this.gzipOptions = null;
this.deflateOptions = null; this.deflateOptions = null;
this.zstdOptions = null; this.zstdOptions = null;
this.factories = null;
supportsCompressionOptions = false; supportsCompressionOptions = false;
} }
@ -199,6 +207,14 @@ public class HttpContentCompressor extends HttpContentEncoder {
this.gzipOptions = gzipOptions; this.gzipOptions = gzipOptions;
this.deflateOptions = deflateOptions; this.deflateOptions = deflateOptions;
this.zstdOptions = zstdOptions; this.zstdOptions = zstdOptions;
this.factories = new HashMap<String, CompressionEncoderFactory>() {
{
put("gzip", new GzipEncoderFactory());
put("deflate", new DeflateEncoderFactory());
put("br", new BrEncoderFactory());
put("zstd", new ZstdEncoderFactory());
}
};
this.compressionLevel = -1; this.compressionLevel = -1;
this.windowBits = -1; this.windowBits = -1;
this.memLevel = -1; this.memLevel = -1;
@ -232,32 +248,15 @@ public class HttpContentCompressor extends HttpContentEncoder {
return null; return null;
} }
if (targetContentEncoding.equals("gzip")) { CompressionEncoderFactory encoderFactory = factories.get(targetContentEncoding);
return new Result(targetContentEncoding,
new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), if (encoderFactory == null) {
ctx.channel().config(), ZlibCodecFactory.newZlibEncoder( throw new Error();
ZlibWrapper.GZIP, gzipOptions.compressionLevel()
, gzipOptions.windowBits(), gzipOptions.memLevel())));
} }
if (targetContentEncoding.equals("deflate")) {
return new Result(targetContentEncoding, return new Result(targetContentEncoding,
new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(), new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(),
ctx.channel().config(), ZlibCodecFactory.newZlibEncoder( ctx.channel().config(), encoderFactory.createEncoder()));
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();
} else { } else {
ZlibWrapper wrapper = determineWrapper(acceptEncoding); ZlibWrapper wrapper = determineWrapper(acceptEncoding);
if (wrapper == null) { if (wrapper == null) {
@ -384,4 +383,57 @@ public class HttpContentCompressor extends HttpContentEncoder {
} }
return null; 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<ByteBuf> 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<ByteBuf> 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<ByteBuf> 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<ByteBuf> createEncoder() {
return new ZstdEncoder(zstdOptions.compressionLevel(),
zstdOptions.blockSize(), zstdOptions.maxEncodeSize());
}
}
} }