-
Notifications
You must be signed in to change notification settings - Fork 631
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
brotli support in HttpClient #2848
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -117,6 +117,7 @@ public String baseUrl() { | |||||
public int channelHash() { | ||||||
int result = super.channelHash(); | ||||||
result = 31 * result + Boolean.hashCode(acceptGzip); | ||||||
result = 31 * result + Boolean.hashCode(acceptBrotli); | ||||||
result = 31 * result + Objects.hashCode(decoder); | ||||||
result = 31 * result + _protocols; | ||||||
result = 31 * result + Objects.hashCode(sslProvider); | ||||||
|
@@ -202,6 +203,15 @@ public boolean isAcceptGzip() { | |||||
return acceptGzip; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Return whether Brotli compression is enabled. | ||||||
* | ||||||
* @return whether Brotli compression is enabled | ||||||
*/ | ||||||
public boolean isAcceptBrotli() { | ||||||
return acceptBrotli; | ||||||
} | ||||||
|
||||||
/** | ||||||
* Return true if {@code retry once} is disabled, false otherwise. | ||||||
* | ||||||
|
@@ -314,6 +324,7 @@ public WebsocketClientSpec websocketClientSpec() { | |||||
// Protected/Package private write API | ||||||
|
||||||
boolean acceptGzip; | ||||||
boolean acceptBrotli; | ||||||
String baseUrl; | ||||||
BiFunction<? super HttpClientRequest, ? super NettyOutbound, ? extends Publisher<Void>> body; | ||||||
Function<? super Mono<? extends Connection>, ? extends Mono<? extends Connection>> connector; | ||||||
|
@@ -349,6 +360,7 @@ public WebsocketClientSpec websocketClientSpec() { | |||||
Supplier<? extends SocketAddress> remoteAddress) { | ||||||
super(connectionProvider, options, remoteAddress); | ||||||
this.acceptGzip = false; | ||||||
this.acceptBrotli = false; | ||||||
this.cookieDecoder = ClientCookieDecoder.STRICT; | ||||||
this.cookieEncoder = ClientCookieEncoder.STRICT; | ||||||
this.decoder = new HttpResponseDecoderSpec(); | ||||||
|
@@ -363,6 +375,7 @@ public WebsocketClientSpec websocketClientSpec() { | |||||
HttpClientConfig(HttpClientConfig parent) { | ||||||
super(parent); | ||||||
this.acceptGzip = parent.acceptGzip; | ||||||
this.acceptBrotli = parent.acceptBrotli; | ||||||
this.baseUrl = parent.baseUrl; | ||||||
this.body = parent.body; | ||||||
this.connector = parent.connector; | ||||||
|
@@ -537,6 +550,7 @@ static void addStreamHandlers( | |||||
ConnectionObserver obs, | ||||||
ChannelOperations.OnSetup opsFactory, | ||||||
boolean acceptGzip, | ||||||
boolean acceptBrotli, | ||||||
@Nullable ChannelMetricsRecorder metricsRecorder, | ||||||
@Nullable SocketAddress proxyAddress, | ||||||
SocketAddress remoteAddress, | ||||||
|
@@ -551,7 +565,7 @@ static void addStreamHandlers( | |||||
pipeline.addLast(NettyPipeline.H2ToHttp11Codec, HTTP2_STREAM_FRAME_TO_HTTP_OBJECT) | ||||||
.addLast(NettyPipeline.HttpTrafficHandler, HTTP_2_STREAM_BRIDGE_CLIENT_HANDLER); | ||||||
|
||||||
if (acceptGzip) { | ||||||
if (acceptGzip || acceptBrotli) { | ||||||
pipeline.addLast(NettyPipeline.HttpDecompressor, new HttpContentDecompressor()); | ||||||
} | ||||||
|
||||||
|
@@ -617,7 +631,7 @@ else if (metricsRecorder instanceof ContextAwareHttpClientMetricsRecorder) { | |||||
} | ||||||
} | ||||||
|
||||||
static void configureHttp2Pipeline(ChannelPipeline p, boolean acceptGzip, HttpResponseDecoderSpec decoder, | ||||||
static void configureHttp2Pipeline(ChannelPipeline p, boolean acceptGzip, boolean acceptBrotli, HttpResponseDecoderSpec decoder, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is not needed:
Suggested change
|
||||||
Http2Settings http2Settings, ConnectionObserver observer) { | ||||||
Http2FrameCodecBuilder http2FrameCodecBuilder = | ||||||
Http2FrameCodecBuilder.forClient() | ||||||
|
@@ -639,6 +653,7 @@ static void configureHttp2Pipeline(ChannelPipeline p, boolean acceptGzip, HttpRe | |||||
static void configureHttp11OrH2CleartextPipeline( | ||||||
ChannelPipeline p, | ||||||
boolean acceptGzip, | ||||||
boolean acceptBrotli, | ||||||
HttpResponseDecoderSpec decoder, | ||||||
Http2Settings http2Settings, | ||||||
@Nullable ChannelMetricsRecorder metricsRecorder, | ||||||
|
@@ -670,7 +685,7 @@ static void configureHttp11OrH2CleartextPipeline( | |||||
Http2FrameCodec http2FrameCodec = http2FrameCodecBuilder.build(); | ||||||
|
||||||
Http2ClientUpgradeCodec upgradeCodec = new Http2ClientUpgradeCodec(http2FrameCodec, | ||||||
new H2CleartextCodec(http2FrameCodec, opsFactory, acceptGzip, metricsRecorder, proxyAddress, remoteAddress, uriTagValue)); | ||||||
new H2CleartextCodec(http2FrameCodec, opsFactory, acceptGzip, acceptBrotli, metricsRecorder, proxyAddress, remoteAddress, uriTagValue)); | ||||||
|
||||||
HttpClientUpgradeHandler upgradeHandler = | ||||||
new ReactorNettyHttpClientUpgradeHandler(httpClientCodec, upgradeCodec, decoder.h2cMaxContentLength()); | ||||||
|
@@ -679,7 +694,7 @@ static void configureHttp11OrH2CleartextPipeline( | |||||
.addBefore(NettyPipeline.ReactiveBridge, NettyPipeline.H2CUpgradeHandler, upgradeHandler) | ||||||
.addBefore(NettyPipeline.ReactiveBridge, NettyPipeline.HttpTrafficHandler, new HttpTrafficHandler(observer)); | ||||||
|
||||||
if (acceptGzip) { | ||||||
if (acceptGzip || acceptBrotli) { | ||||||
p.addBefore(NettyPipeline.ReactiveBridge, NettyPipeline.HttpDecompressor, new HttpContentDecompressor()); | ||||||
} | ||||||
|
||||||
|
@@ -704,6 +719,7 @@ else if (metricsRecorder instanceof ContextAwareHttpClientMetricsRecorder) { | |||||
@SuppressWarnings("deprecation") | ||||||
static void configureHttp11Pipeline(ChannelPipeline p, | ||||||
boolean acceptGzip, | ||||||
boolean acceptBrotli, | ||||||
HttpResponseDecoderSpec decoder, | ||||||
@Nullable ChannelMetricsRecorder metricsRecorder, | ||||||
@Nullable SocketAddress proxyAddress, | ||||||
|
@@ -720,7 +736,7 @@ static void configureHttp11Pipeline(ChannelPipeline p, | |||||
NettyPipeline.HttpCodec, | ||||||
new HttpClientCodec(decoderConfig, decoder.failOnMissingResponse, decoder.parseHttpAfterConnectRequest)); | ||||||
|
||||||
if (acceptGzip) { | ||||||
if (acceptGzip || acceptBrotli) { | ||||||
p.addAfter(NettyPipeline.HttpCodec, NettyPipeline.HttpDecompressor, new HttpContentDecompressor()); | ||||||
} | ||||||
|
||||||
|
@@ -779,6 +795,7 @@ else if (metricsRecorder instanceof ContextAwareHttpClientMetricsRecorder) { | |||||
static final class H2CleartextCodec extends ChannelHandlerAdapter { | ||||||
|
||||||
final boolean acceptGzip; | ||||||
final boolean acceptBrotli; | ||||||
final Http2FrameCodec http2FrameCodec; | ||||||
final ChannelMetricsRecorder metricsRecorder; | ||||||
final ChannelOperations.OnSetup opsFactory; | ||||||
|
@@ -790,11 +807,13 @@ static final class H2CleartextCodec extends ChannelHandlerAdapter { | |||||
Http2FrameCodec http2FrameCodec, | ||||||
ChannelOperations.OnSetup opsFactory, | ||||||
boolean acceptGzip, | ||||||
boolean acceptBrotli, | ||||||
@Nullable ChannelMetricsRecorder metricsRecorder, | ||||||
@Nullable SocketAddress proxyAddress, | ||||||
SocketAddress remoteAddress, | ||||||
@Nullable Function<String, String> uriTagValue) { | ||||||
this.acceptGzip = acceptGzip; | ||||||
this.acceptBrotli = acceptBrotli; | ||||||
this.http2FrameCodec = http2FrameCodec; | ||||||
this.metricsRecorder = metricsRecorder; | ||||||
this.opsFactory = opsFactory; | ||||||
|
@@ -819,12 +838,12 @@ public void handlerAdded(ChannelHandlerContext ctx) { | |||||
if (responseTimeoutHandler != null) { | ||||||
pipeline.remove(NettyPipeline.ResponseTimeoutHandler); | ||||||
http2MultiplexHandler = new Http2MultiplexHandler(H2InboundStreamHandler.INSTANCE, | ||||||
new H2Codec(owner, obs, opsFactory, acceptGzip, metricsRecorder, proxyAddress, | ||||||
new H2Codec(owner, obs, opsFactory, acceptGzip, acceptBrotli, metricsRecorder, proxyAddress, | ||||||
remoteAddress, responseTimeoutHandler.getReaderIdleTimeInMillis(), uriTagValue)); | ||||||
} | ||||||
else { | ||||||
http2MultiplexHandler = new Http2MultiplexHandler(H2InboundStreamHandler.INSTANCE, | ||||||
new H2Codec(owner, obs, opsFactory, acceptGzip, metricsRecorder, proxyAddress, remoteAddress, uriTagValue)); | ||||||
new H2Codec(owner, obs, opsFactory, acceptGzip, acceptBrotli, metricsRecorder, proxyAddress, remoteAddress, uriTagValue)); | ||||||
} | ||||||
pipeline.addAfter(ctx.name(), NettyPipeline.HttpCodec, http2FrameCodec) | ||||||
.addAfter(NettyPipeline.HttpCodec, NettyPipeline.H2MultiplexHandler, http2MultiplexHandler); | ||||||
|
@@ -839,6 +858,7 @@ public void handlerAdded(ChannelHandlerContext ctx) { | |||||
static final class H2Codec extends ChannelInitializer<Channel> { | ||||||
|
||||||
final boolean acceptGzip; | ||||||
final boolean acceptBrotli; | ||||||
final ChannelMetricsRecorder metricsRecorder; | ||||||
final ConnectionObserver observer; | ||||||
final ChannelOperations.OnSetup opsFactory; | ||||||
|
@@ -853,26 +873,29 @@ static final class H2Codec extends ChannelInitializer<Channel> { | |||||
@Nullable ConnectionObserver observer, | ||||||
ChannelOperations.OnSetup opsFactory, | ||||||
boolean acceptGzip, | ||||||
boolean acceptBrotli, | ||||||
@Nullable ChannelMetricsRecorder metricsRecorder, | ||||||
@Nullable SocketAddress proxyAddress, | ||||||
SocketAddress remoteAddress, | ||||||
@Nullable Function<String, String> uriTagValue) { | ||||||
// Handle outbound and upgrade streams | ||||||
this(owner, observer, opsFactory, acceptGzip, metricsRecorder, proxyAddress, remoteAddress, -1, uriTagValue); | ||||||
this(owner, observer, opsFactory, acceptGzip, acceptBrotli, metricsRecorder, proxyAddress, remoteAddress, -1, uriTagValue); | ||||||
} | ||||||
|
||||||
H2Codec( | ||||||
@Nullable Http2ConnectionProvider.DisposableAcquire owner, | ||||||
@Nullable ConnectionObserver observer, | ||||||
ChannelOperations.OnSetup opsFactory, | ||||||
boolean acceptGzip, | ||||||
boolean acceptBrotli, | ||||||
@Nullable ChannelMetricsRecorder metricsRecorder, | ||||||
@Nullable SocketAddress proxyAddress, | ||||||
SocketAddress remoteAddress, | ||||||
long responseTimeoutMillis, | ||||||
@Nullable Function<String, String> uriTagValue) { | ||||||
// Handle outbound and upgrade streams | ||||||
this.acceptGzip = acceptGzip; | ||||||
this.acceptBrotli = acceptBrotli; | ||||||
this.metricsRecorder = metricsRecorder; | ||||||
this.observer = observer; | ||||||
this.opsFactory = opsFactory; | ||||||
|
@@ -891,7 +914,7 @@ protected void initChannel(Channel ch) { | |||||
setChannelContext(ch, owner.currentContext()); | ||||||
} | ||||||
addStreamHandlers(ch, observer.then(new StreamConnectionObserver(owner.currentContext())), opsFactory, | ||||||
acceptGzip, metricsRecorder, proxyAddress, remoteAddress, responseTimeoutMillis, uriTagValue); | ||||||
acceptGzip, acceptBrotli, metricsRecorder, proxyAddress, remoteAddress, responseTimeoutMillis, uriTagValue); | ||||||
} | ||||||
else { | ||||||
// Handle server pushes (inbound streams) | ||||||
|
@@ -915,6 +938,7 @@ public boolean isSharable() { | |||||
|
||||||
static final class H2OrHttp11Codec extends ChannelInboundHandlerAdapter { | ||||||
final boolean acceptGzip; | ||||||
final boolean acceptBrotli; | ||||||
final HttpResponseDecoderSpec decoder; | ||||||
final Http2Settings http2Settings; | ||||||
final ChannelMetricsRecorder metricsRecorder; | ||||||
|
@@ -925,6 +949,7 @@ static final class H2OrHttp11Codec extends ChannelInboundHandlerAdapter { | |||||
|
||||||
H2OrHttp11Codec(HttpClientChannelInitializer initializer, ConnectionObserver observer, SocketAddress remoteAddress) { | ||||||
this.acceptGzip = initializer.acceptGzip; | ||||||
this.acceptBrotli = initializer.acceptBrotli; | ||||||
this.decoder = initializer.decoder; | ||||||
this.http2Settings = initializer.http2Settings; | ||||||
this.metricsRecorder = initializer.metricsRecorder; | ||||||
|
@@ -945,10 +970,10 @@ public void channelActive(ChannelHandlerContext ctx) { | |||||
log.debug(format(ctx.channel(), "Negotiated application-level protocol [" + protocol + "]")); | ||||||
} | ||||||
if (ApplicationProtocolNames.HTTP_2.equals(protocol)) { | ||||||
configureHttp2Pipeline(ctx.channel().pipeline(), acceptGzip, decoder, http2Settings, observer); | ||||||
configureHttp2Pipeline(ctx.channel().pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, observer); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is not needed:
Suggested change
|
||||||
} | ||||||
else if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) { | ||||||
configureHttp11Pipeline(ctx.channel().pipeline(), acceptGzip, decoder, metricsRecorder, proxyAddress, remoteAddress, uriTagValue); | ||||||
configureHttp11Pipeline(ctx.channel().pipeline(), acceptGzip, acceptBrotli, decoder, metricsRecorder, proxyAddress, remoteAddress, uriTagValue); | ||||||
} | ||||||
else { | ||||||
throw new IllegalStateException("unknown protocol: " + protocol); | ||||||
|
@@ -967,6 +992,7 @@ else if (ApplicationProtocolNames.HTTP_1_1.equals(protocol)) { | |||||
static final class HttpClientChannelInitializer implements ChannelPipelineConfigurer { | ||||||
|
||||||
final boolean acceptGzip; | ||||||
final boolean acceptBrotli; | ||||||
final HttpResponseDecoderSpec decoder; | ||||||
final Http2Settings http2Settings; | ||||||
final ChannelMetricsRecorder metricsRecorder; | ||||||
|
@@ -978,6 +1004,7 @@ static final class HttpClientChannelInitializer implements ChannelPipelineConfig | |||||
|
||||||
HttpClientChannelInitializer(HttpClientConfig config) { | ||||||
this.acceptGzip = config.acceptGzip; | ||||||
this.acceptBrotli = config.acceptBrotli; | ||||||
this.decoder = config.decoder; | ||||||
this.http2Settings = config.http2Settings(); | ||||||
this.metricsRecorder = config.metricsRecorderInternal(); | ||||||
|
@@ -999,21 +1026,21 @@ public void onChannelInit(ConnectionObserver observer, Channel channel, @Nullabl | |||||
new H2OrHttp11Codec(this, observer, remoteAddress)); | ||||||
} | ||||||
else if ((protocols & h11) == h11) { | ||||||
configureHttp11Pipeline(channel.pipeline(), acceptGzip, decoder, metricsRecorder, proxyAddress, remoteAddress, uriTagValue); | ||||||
configureHttp11Pipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, metricsRecorder, proxyAddress, remoteAddress, uriTagValue); | ||||||
} | ||||||
else if ((protocols & h2) == h2) { | ||||||
configureHttp2Pipeline(channel.pipeline(), acceptGzip, decoder, http2Settings, observer); | ||||||
configureHttp2Pipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, observer); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is not needed:
Suggested change
|
||||||
} | ||||||
} | ||||||
else { | ||||||
if ((protocols & h11orH2C) == h11orH2C) { | ||||||
configureHttp11OrH2CleartextPipeline(channel.pipeline(), acceptGzip, decoder, http2Settings, metricsRecorder, observer, opsFactory, proxyAddress, remoteAddress, uriTagValue); | ||||||
configureHttp11OrH2CleartextPipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, metricsRecorder, observer, opsFactory, proxyAddress, remoteAddress, uriTagValue); | ||||||
} | ||||||
else if ((protocols & h11) == h11) { | ||||||
configureHttp11Pipeline(channel.pipeline(), acceptGzip, decoder, metricsRecorder, proxyAddress, remoteAddress, uriTagValue); | ||||||
configureHttp11Pipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, metricsRecorder, proxyAddress, remoteAddress, uriTagValue); | ||||||
} | ||||||
else if ((protocols & h2c) == h2c) { | ||||||
configureHttp2Pipeline(channel.pipeline(), acceptGzip, decoder, http2Settings, observer); | ||||||
configureHttp2Pipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, observer); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This change is not needed:
Suggested change
|
||||||
} | ||||||
} | ||||||
} | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will remove any custom
Accept-Encoding
header that was set prior this invocation.Why do we need to do this? It will be better to preserve the custom headers.