Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supports configurable compression level #3567

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions docs/modules/ROOT/pages/http-server.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,28 @@ You can configure the `HTTP` server to send a compressed response, depending on
* `compress(int)`: The compression is performed once the response size exceeds the given value (in bytes).
* `compress(BiPredicate<HttpServerRequest, HttpServerResponse>)`: The compression is performed if
the predicate returns `true`.
* `compressOptions(HttpCompressionOption... compressionOptions)`: Specifies the compression options for GZip, Deflate, and ZSTD.
+
[NOTE]
====
GZip Compression Options

* compression level : only the range 0 to 9 is allowed. (default: 6)
* window bits : only the range 0 to 9 is allowed. (default: 15)
* memory level : only the range 1 to 9 is allowed. (default: 8)

Deflate Compression Options

* compression level : only the range 0 to 9 is allowed. (default: 6)
* window bits : only the range 0 to 9 is allowed. (default: 15)
* memory level : only the range 1 to 9 is allowed. (default: 8)

ZSTD Compression Options

* compression level : only the range -131072 to 9 is allowed. (default: 3)
* block size : only the positive number is allowed. (default: 65536, that is 64KB)
* max encode size : only the positive number is allowed. (default: 33554432, that is 32MB)
====

The following example uses the `compress` method (set to `true`) to enable compression:

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018-2024 VMware, Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2018-2025 VMware, Inc. or its affiliates, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -47,6 +47,7 @@
import reactor.netty.ReactorNetty;
import reactor.netty.http.logging.HttpMessageArgProviderFactory;
import reactor.netty.http.logging.HttpMessageLogFactory;
import reactor.netty.http.server.compression.HttpCompressionOptionsSpec;
import reactor.util.annotation.Nullable;

import static io.netty.handler.codec.http.LastHttpContent.EMPTY_LAST_CONTENT;
Expand All @@ -62,6 +63,7 @@
final class Http2StreamBridgeServerHandler extends ChannelDuplexHandler {

final BiPredicate<HttpServerRequest, HttpServerResponse> compress;
final HttpCompressionOptionsSpec compressionOptions;
final ServerCookieDecoder cookieDecoder;
final ServerCookieEncoder cookieEncoder;
final HttpServerFormDecoderProvider formDecoderProvider;
Expand All @@ -84,6 +86,7 @@ final class Http2StreamBridgeServerHandler extends ChannelDuplexHandler {

Http2StreamBridgeServerHandler(
@Nullable BiPredicate<HttpServerRequest, HttpServerResponse> compress,
@Nullable HttpCompressionOptionsSpec compressionOptions,
ServerCookieDecoder decoder,
ServerCookieEncoder encoder,
HttpServerFormDecoderProvider formDecoderProvider,
Expand All @@ -94,6 +97,7 @@ final class Http2StreamBridgeServerHandler extends ChannelDuplexHandler {
@Nullable Duration readTimeout,
@Nullable Duration requestTimeout) {
this.compress = compress;
this.compressionOptions = compressionOptions;
this.cookieDecoder = decoder;
this.cookieEncoder = encoder;
this.formDecoderProvider = formDecoderProvider;
Expand Down Expand Up @@ -140,6 +144,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
listener,
request,
compress,
compressionOptions,
connectionInfo,
cookieDecoder,
cookieEncoder,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 VMware, Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2024-2025 VMware, Inc. or its affiliates, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -31,6 +31,7 @@
import reactor.netty.channel.ChannelMetricsRecorder;
import reactor.netty.channel.ChannelOperations;
import reactor.netty.http.logging.HttpMessageLogFactory;
import reactor.netty.http.server.compression.HttpCompressionOptionsSpec;
import reactor.netty.http.server.logging.AccessLog;
import reactor.netty.http.server.logging.AccessLogArgProvider;
import reactor.netty.http.server.logging.AccessLogHandlerFactory;
Expand Down Expand Up @@ -63,6 +64,7 @@ final class Http3Codec extends ChannelInitializer<QuicStreamChannel> {
final Function<String, String> methodTagValue;
final ChannelMetricsRecorder metricsRecorder;
final int minCompressionSize;
final HttpCompressionOptionsSpec compressionOptions;
final ChannelOperations.OnSetup opsFactory;
final Duration readTimeout;
final Duration requestTimeout;
Expand All @@ -83,6 +85,7 @@ final class Http3Codec extends ChannelInitializer<QuicStreamChannel> {
@Nullable Function<String, String> methodTagValue,
@Nullable ChannelMetricsRecorder metricsRecorder,
int minCompressionSize,
@Nullable HttpCompressionOptionsSpec compressionOptions,
ChannelOperations.OnSetup opsFactory,
@Nullable Duration readTimeout,
@Nullable Duration requestTimeout,
Expand All @@ -101,6 +104,7 @@ final class Http3Codec extends ChannelInitializer<QuicStreamChannel> {
this.methodTagValue = methodTagValue;
this.metricsRecorder = metricsRecorder;
this.minCompressionSize = minCompressionSize;
this.compressionOptions = compressionOptions;
this.opsFactory = opsFactory;
this.readTimeout = readTimeout;
this.requestTimeout = requestTimeout;
Expand All @@ -118,13 +122,13 @@ protected void initChannel(QuicStreamChannel channel) {

p.addLast(NettyPipeline.H3ToHttp11Codec, new Http3FrameToHttpObjectCodec(true, validate))
.addLast(NettyPipeline.HttpTrafficHandler,
new Http3StreamBridgeServerHandler(compressPredicate, cookieDecoder, cookieEncoder, formDecoderProvider,
new Http3StreamBridgeServerHandler(compressPredicate, compressionOptions, cookieDecoder, cookieEncoder, formDecoderProvider,
forwardedHeaderHandler, httpMessageLogFactory, listener, mapHandle, readTimeout, requestTimeout));

boolean alwaysCompress = compressPredicate == null && minCompressionSize == 0;

if (alwaysCompress) {
p.addLast(NettyPipeline.CompressionHandler, new SimpleCompressionHandler());
p.addLast(NettyPipeline.CompressionHandler, SimpleCompressionHandler.create(compressionOptions));
}

ChannelOperations.addReactiveBridge(channel, opsFactory, listener);
Expand Down Expand Up @@ -166,14 +170,15 @@ static ChannelHandler newHttp3ServerConnectionHandler(
@Nullable Function<String, String> methodTagValue,
@Nullable ChannelMetricsRecorder metricsRecorder,
int minCompressionSize,
@Nullable HttpCompressionOptionsSpec compressionOptions,
ChannelOperations.OnSetup opsFactory,
@Nullable Duration readTimeout,
@Nullable Duration requestTimeout,
@Nullable Function<String, String> uriTagValue,
boolean validate) {
return new Http3ServerConnectionHandler(
new Http3Codec(accessLogEnabled, accessLog, compressPredicate, decoder, encoder, formDecoderProvider, forwardedHeaderHandler,
httpMessageLogFactory, listener, mapHandle, methodTagValue, metricsRecorder, minCompressionSize,
httpMessageLogFactory, listener, mapHandle, methodTagValue, metricsRecorder, minCompressionSize, compressionOptions,
opsFactory, readTimeout, requestTimeout, uriTagValue, validate));
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 VMware, Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2024-2025 VMware, Inc. or its affiliates, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -24,6 +24,7 @@
import reactor.netty.Connection;
import reactor.netty.ConnectionObserver;
import reactor.netty.http.logging.HttpMessageLogFactory;
import reactor.netty.http.server.compression.HttpCompressionOptionsSpec;
import reactor.util.annotation.Nullable;

import java.net.SocketAddress;
Expand All @@ -43,6 +44,7 @@ final class Http3ServerOperations extends HttpServerOperations {
ConnectionObserver listener,
HttpRequest nettyRequest,
@Nullable BiPredicate<HttpServerRequest, HttpServerResponse> compressionPredicate,
@Nullable HttpCompressionOptionsSpec compressionOptions,
ConnectionInfo connectionInfo,
ServerCookieDecoder decoder,
ServerCookieEncoder encoder,
Expand All @@ -54,7 +56,7 @@ final class Http3ServerOperations extends HttpServerOperations {
@Nullable Duration requestTimeout,
boolean secured,
ZonedDateTime timestamp) {
super(c, listener, nettyRequest, compressionPredicate, connectionInfo, decoder, encoder, formDecoderProvider,
super(c, listener, nettyRequest, compressionPredicate, compressionOptions, connectionInfo, decoder, encoder, formDecoderProvider,
httpMessageLogFactory, isHttp2, mapHandle, readTimeout, requestTimeout, secured, timestamp, true);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2024 VMware, Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2024-2025 VMware, Inc. or its affiliates, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -41,6 +41,7 @@
import reactor.netty.ReactorNetty;
import reactor.netty.http.logging.HttpMessageArgProviderFactory;
import reactor.netty.http.logging.HttpMessageLogFactory;
import reactor.netty.http.server.compression.HttpCompressionOptionsSpec;
import reactor.util.annotation.Nullable;

import java.net.SocketAddress;
Expand All @@ -54,6 +55,7 @@

final class Http3StreamBridgeServerHandler extends ChannelDuplexHandler {
final BiPredicate<HttpServerRequest, HttpServerResponse> compress;
final HttpCompressionOptionsSpec compressionOptions;
final ServerCookieDecoder cookieDecoder;
final ServerCookieEncoder cookieEncoder;
final HttpServerFormDecoderProvider formDecoderProvider;
Expand All @@ -74,6 +76,7 @@ final class Http3StreamBridgeServerHandler extends ChannelDuplexHandler {

Http3StreamBridgeServerHandler(
@Nullable BiPredicate<HttpServerRequest, HttpServerResponse> compress,
@Nullable HttpCompressionOptionsSpec compressionOptions,
ServerCookieDecoder decoder,
ServerCookieEncoder encoder,
HttpServerFormDecoderProvider formDecoderProvider,
Expand All @@ -84,6 +87,7 @@ final class Http3StreamBridgeServerHandler extends ChannelDuplexHandler {
@Nullable Duration readTimeout,
@Nullable Duration requestTimeout) {
this.compress = compress;
this.compressionOptions = compressionOptions;
this.cookieDecoder = decoder;
this.cookieEncoder = encoder;
this.formDecoderProvider = formDecoderProvider;
Expand Down Expand Up @@ -131,6 +135,7 @@ public void channelRead(ChannelHandlerContext ctx, Object msg) {
listener,
request,
compress,
compressionOptions,
connectionInfo,
cookieDecoder,
cookieEncoder,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011-2024 VMware, Inc. or its affiliates, All Rights Reserved.
* Copyright (c) 2011-2025 VMware, Inc. or its affiliates, All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -45,6 +45,8 @@
import reactor.netty.http.HttpProtocol;
import reactor.netty.http.logging.HttpMessageLogFactory;
import reactor.netty.http.logging.ReactorNettyHttpMessageLogFactory;
import reactor.netty.http.server.compression.HttpCompressionOption;
import reactor.netty.http.server.compression.HttpCompressionOptionsSpec;
import reactor.netty.http.server.logging.AccessLog;
import reactor.netty.http.server.logging.AccessLogArgProvider;
import reactor.netty.http.server.logging.AccessLogFactory;
Expand Down Expand Up @@ -301,6 +303,7 @@ public final HttpServer compress(BiPredicate<HttpServerRequest, HttpServerRespon
/**
* Specifies whether GZip response compression is enabled if the client request
* presents accept encoding.
* default compression level is 6.
*
* @param compressionEnabled if true GZip response compression
* is enabled if the client request presents accept encoding, otherwise disabled.
Expand Down Expand Up @@ -336,6 +339,39 @@ public final HttpServer compress(int minResponseSize) {
return dup;
}

/**
* Specifies GZip, Deflate, ZSTD compression option
* with {@link reactor.netty.http.server.compression.GzipOption}, {@link reactor.netty.http.server.compression.DeflateOption}, , {@link reactor.netty.http.server.compression.ZstdOption}.
*
* @param compressionOptions configures {@link HttpCompressionOption} after enable compress.
*
* <pre>
* {@code
* HttpServer.create()
* .compress(true)
* .compressOptions(
* GzipOption.builder()
* .compressionLevel(6)
* .windowBits(15)
* .memoryLevel(8)
* .build(),
* ZstdOption.builder()
* .compressionLevel(3)
* .build()
* )
* .bindNow();
* }
* </pre>
* @return a new {@link HttpServer}
*/
public final HttpServer compressOptions(HttpCompressionOption... compressionOptions) {
Objects.requireNonNull(compressionOptions, "compressionOptions");

HttpServer dup = duplicate();
dup.configuration().compressionOptions = new HttpCompressionOptionsSpec(compressionOptions);
return dup;
}

/**
* Configure the
* {@link ServerCookieEncoder}; {@link ServerCookieDecoder} will be
Expand Down
Loading
Loading