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

brotli support in HttpClient #2848

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

Conversation

sullis
Copy link
Contributor

@sullis sullis commented Jul 6, 2023

enable Brotli compression support in the Reactor http client.

@sullis
Copy link
Contributor Author

sullis commented Jul 7, 2023

@violetagg Please take a look :)

@violetagg
Copy link
Member

violetagg commented Jul 10, 2023

@sullis I can take a look at the end of the week. Can you verify that when we do not have Brotli in the class path the native-image functionality is still working OK? When we have native-image we need to be careful with reflection and Brotli.isAvailable does reflection.

@violetagg violetagg added the type/enhancement A general enhancement label Jul 10, 2023
@violetagg violetagg modified the milestones: 1.1.9, 1.1.x Backlog Jul 10, 2023
@violetagg
Copy link
Member

@sullis I can take a look at the end of the week. Can you verify that when we do not have Brotli in the class path the native-image functionality is still working OK? When we have native-image we need to be careful with reflection and Brotli.isAvailable does reflection.

I tested this one

When there is no Brotli in the class path the HttpClient works as expected when native-image

One can see

========================================================================================================================
GraalVM Native Image: Generating 'brotli-example' (executable)...
========================================================================================================================
...
Warning: Could not resolve com.aayushatharva.brotli4j.Brotli4jLoader for reflection configuration. Reason: java.lang.ClassNotFoundException: com.aayushatharva.brotli4j.Brotli4jLoader.
...
10:07:26.303 [main] DEBUG io.netty.handler.codec.compression.Brotli -- brotli4j not in the classpath; Brotli support will be unavailable.

I'm using GraalVM reachability metadata
https://github.com/oracle/graalvm-reachability-metadata/blob/f629b5468b723521023dd05c65f2af5d47de0a24/metadata/io.netty/netty-common/4.1.80.Final/reflect-config.json#L300-L305

When I have Brotli in the class path and I run on Linux the HttpClient works as expected when native-image. The arch is recognised and GraalVM reachability metadata has the proper configuration
https://github.com/oracle/graalvm-reachability-metadata/blob/f629b5468b723521023dd05c65f2af5d47de0a24/metadata/io.netty/netty-common/4.1.80.Final/resource-config.json#L15

When I have Brotli in the class path and I run on Mac OS, I'm seeing the log below and the brotli support is disabled when native-image.

11:19:56.915 [main] DEBUG io.netty.handler.codec.compression.Brotli -- Failed to load brotli4j; Brotli support will be unavailable.
java.lang.UnsupportedOperationException: Unsupported OS and Architecture: Mac OS X, amd64
        at com.aayushatharva.brotli4j.Brotli4jLoader.getPlatform(Brotli4jLoader.java:142)
        at com.aayushatharva.brotli4j.Brotli4jLoader.<clinit>(Brotli4jLoader.java:53)
        at io.netty.handler.codec.compression.Brotli.<clinit>(Brotli.java:46)
        at reactor.netty.http.client.HttpClient.compress(HttpClient.java:521)
        at org.example.Application.main(Application.java:10)

@violetagg
Copy link
Member

I'm seeing that com.aayushatharva.brotli4j.Brotli4jLoader#getPlatform checks the arch like this

        } else if (osName.startsWith("Mac")) {
            if (archName.equalsIgnoreCase("x86_64")) {
                return "osx-x86_64";
            }

While for example in Netty we do the following:
io.netty.util.internal.PlatformDependent#normalizeArch

        value = normalize(value);
        if (value.matches("^(x8664|amd64|ia32e|em64t|x64)$")) {
            return "x86_64";
        }

@sullis
Copy link
Contributor Author

sullis commented Jul 21, 2023

Interesting. I'll take a closer look this weekend.

@violetagg
Copy link
Member

@sullis it will be great if you can rebase so that you can pick up the GraalVM smoke tests change.

@sullis
Copy link
Contributor Author

sullis commented Sep 14, 2023

@sullis it will be great if you can rebase so that you can pick up the GraalVM smoke tests change.

Rebase done.

@violetagg
Copy link
Member

violetagg commented Sep 15, 2023

@sullis If you want we can proceed with this. We will state that Brotli supports native image only for linux-x86_64. For the rest it will be disabled.

08:05:21.382 [main] DEBUG io.netty.handler.codec.compression.Brotli - Failed to load brotli4j; Brotli support will be unavailable.
java.lang.UnsatisfiedLinkError: Failed to find Brotli native library in classpath: /lib/osx-aarch64/libbrotli.dylib
        at com.aayushatharva.brotli4j.Brotli4jLoader.<clinit>(Brotli4jLoader.java:77)
        at io.netty.handler.codec.compression.Brotli.<clinit>(Brotli.java:46)
        at reactor.netty.http.client.HttpClient.compress(HttpClient.java:521)
04:57:54.390 [main] DEBUG io.netty.handler.codec.compression.Brotli - Failed to load brotli4j; Brotli support will be unavailable.
java.lang.UnsatisfiedLinkError: Failed to find Brotli native library in classpath: /lib/linux-aarch64/libbrotli.so
        at com.aayushatharva.brotli4j.Brotli4jLoader.<clinit>(Brotli4jLoader.java:77)
        at io.netty.handler.codec.compression.Brotli.<clinit>(Brotli.java:46)
        at reactor.netty.http.client.HttpClient.compress(HttpClient.java:521)

@sullis
Copy link
Contributor Author

sullis commented Sep 15, 2023

@sullis If you want we can proceed with this. We will state that Brotli supports native image only for linux-x86_64. For the rest it will be disabled.

Sounds good to me!

@violetagg violetagg marked this pull request as ready for review September 15, 2023 06:20
@violetagg violetagg modified the milestones: 1.1.x Backlog, 1.1.12 Sep 15, 2023
@@ -598,7 +612,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,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not needed:

Suggested change
static void configureHttp2Pipeline(ChannelPipeline p, boolean acceptGzip, boolean acceptBrotli, HttpResponseDecoderSpec decoder,
static void configureHttp2Pipeline(ChannelPipeline p, boolean acceptGzip, HttpResponseDecoderSpec decoder,

@@ -905,10 +930,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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not needed:

Suggested change
configureHttp2Pipeline(ctx.channel().pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, observer);
configureHttp2Pipeline(ctx.channel().pipeline(), acceptGzip, decoder, http2Settings, observer);

}
else if ((protocols & h2) == h2) {
configureHttp2Pipeline(channel.pipeline(), acceptGzip, decoder, http2Settings, observer);
configureHttp2Pipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, observer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not needed:

Suggested change
configureHttp2Pipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, observer);
configureHttp2Pipeline(channel.pipeline(), acceptGzip, decoder, http2Settings, observer);

}
else if ((protocols & h2c) == h2c) {
configureHttp2Pipeline(channel.pipeline(), acceptGzip, decoder, http2Settings, observer);
configureHttp2Pipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, observer);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is not needed:

Suggested change
configureHttp2Pipeline(channel.pipeline(), acceptGzip, acceptBrotli, decoder, http2Settings, observer);
configureHttp2Pipeline(channel.pipeline(), acceptGzip, decoder, http2Settings, observer);

@@ -515,7 +516,13 @@ public final HttpClient baseUrl(String baseUrl) {
* @return a new {@link HttpClient}
*/
public final HttpClient compress(boolean compressionEnabled) {
configuration().headers.remove(HttpHeaderNames.ACCEPT_ENCODING);
Copy link
Member

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.

if (brotliEnabled) {
assertThat(Brotli.isAvailable()).isTrue();
client = client.compress(true);
client.configuration().headers = client.configuration().headers()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need this? The compress method should add the header.

Comment on lines +509 to +513
.response((r, buf) -> buf.asString()
.elementAt(0)
.zipWith(Mono.just(r))))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
.response((r, buf) -> buf.asString()
.elementAt(0)
.zipWith(Mono.just(r))))
.responseSingle((r, buf) -> buf.asString().zipWith(Mono.just(r))))

@violetagg violetagg modified the milestones: 1.1.12, 1.1.x Backlog Sep 29, 2023
@violetagg violetagg modified the milestones: 1.1.x Backlog, 1.2.x Backlog Dec 15, 2023
@sullis sullis force-pushed the httpclient-brotli branch 2 times, most recently from 56434f8 to b0b2878 Compare March 20, 2024 14:43
@sullis
Copy link
Contributor Author

sullis commented Mar 30, 2024

rebased

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type/enhancement A general enhancement
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants