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

Quarkus’s applyCompression Method Disables Vert.x Compression Logic #44637

Open
aruis opened this issue Nov 22, 2024 · 0 comments
Open

Quarkus’s applyCompression Method Disables Vert.x Compression Logic #44637

aruis opened this issue Nov 22, 2024 · 0 comments
Labels
area/vertx kind/bug Something isn't working

Comments

@aruis
Copy link

aruis commented Nov 22, 2024

Describe the bug

In the VertxHttpRecorder class, the applyCompression method forcibly adds a Content-Encoding: identity header when compression (enableCompression=true) is enabled. This behavior directly disables Vert.x’s built-in compression logic (HttpContentCompressor). As a result, even when HTTP compression is enabled in the Quarkus configuration, responses are not compressed.

Expected behavior

When quarkus.http.enable-compression=true is set, the compression logic should be delegated to Vert.x. Vert.x should dynamically decide whether to apply compression based on the client’s Accept-Encoding header and response content size.

Actual behavior

The applyCompression method explicitly sets the Content-Encoding: identity header:

private void applyCompression(boolean enableCompression, Router httpRouteRouter) {
if (enableCompression) {
httpRouteRouter.route().order(RouteConstants.ROUTE_ORDER_COMPRESSION).handler(new Handler<RoutingContext>() {
@Override
public void handle(RoutingContext ctx) {
// Add "Content-Encoding: identity" header that disables the compression
// This header can be removed to enable the compression
ctx.response().putHeader(HttpHeaders.CONTENT_ENCODING, HttpHeaders.IDENTITY);
ctx.next();
}
});
}
}

This leads to:
1. Disabling Vert.x Compression: Vert.x’s HttpContentCompressor detects that Content-Encoding is already set and skips the compression logic.
2. Additional Developer Effort: Developers must manually remove the Content-Encoding header in their custom handlers to allow compression to work properly, especially when using Vert.x features like StaticHandler.

How to Reproduce?

Reproduction Steps

  1. Enable HTTP compression in Quarkus:

quarkus.http.enable-compression=true

  1. Create a custom route using Vert.x’s StaticHandler:
Router router = Router.router(vertx);
router.route("/static/*").handler(routingContext -> {
    // Without this line, compression won't work
    routingContext.response().headers().remove(HttpHeaders.CONTENT_ENCODING);
    StaticHandler.create().handle(routingContext);
});
  1. Request a static file with Accept-Encoding: gzip: curl -H "Accept-Encoding: gzip" http://localhost:8080/static/index.html

  2. Observe that the response is not compressed unless the Content-Encoding header is explicitly removed in the handler.

Output of uname -a or ver

Darwin mini2024.local 24.1.0 Darwin Kernel Version 24.1.0: Thu Nov 14 18:15:21 PST 2024; root:xnu-11215.41.3~13/RELEASE_ARM64_T6041 arm64

Output of java -version

openjdk version "21.0.5" 2024-10-15 LTS OpenJDK Runtime Environment Zulu21.38+21-CA (build 21.0.5+11-LTS) OpenJDK 64-Bit Server VM Zulu21.38+21-CA (build 21.0.5+11-LTS, mixed mode, sharing)

Quarkus version or git rev

3.16.4

Build tool (ie. output of mvnw --version or gradlew --version)

Gradle 8.8

Additional information

Analysis

Netty Source Code Behavior

Vert.x’s compression logic relies on Netty’s HttpContentCompressor, which dynamically applies compression based on the Accept-Encoding header and response content. The critical part of HttpContentCompressor’s logic is as follows:

https://github.com/netty/netty/blob/a0e67671651a99977391c5552dd90e7bc147308a/codec-http/src/main/java/io/netty/handler/codec/http/HttpContentCompressor.java#L246-L259

protected Result beginEncode(HttpResponse httpResponse, String acceptEncoding) throws Exception {
    // Skip compression if the content is too small
    if (this.contentSizeThreshold > 0) {
        if (httpResponse instanceof HttpContent &&
                ((HttpContent) httpResponse).content().readableBytes() < contentSizeThreshold) {
            return null;
        }
    }

    // Skip compression if Content-Encoding is already set
    String contentEncoding = httpResponse.headers().get(HttpHeaderNames.CONTENT_ENCODING);
    if (contentEncoding != null) {
        return null;
    }

    // Dynamically choose compression encoding based on Accept-Encoding
    String targetContentEncoding = determineEncoding(acceptEncoding);
    if (targetContentEncoding == null) {
        return null;
    }

    return new Result(targetContentEncoding,
            new EmbeddedChannel(ctx.channel().id(), ctx.channel().metadata().hasDisconnect(),
                    ctx.channel().config(), encoderFactory.createEncoder()));
}
•	Key Point 1: If Content-Encoding is set (even as identity), compression is skipped entirely.
•	Key Point 2: If Quarkus sets Content-Encoding: identity, the compression logic is bypassed, even when the client requests gzip encoding.

Issues with Current Quarkus Implementation

•	The applyCompression method’s forced header setting disrupts Vert.x’s native behavior.
•	Developers are forced to manually adjust response headers to bypass this interference, adding unnecessary complexity.

Suggested Fix

Remove the forced addition of the Content-Encoding: identity header in the applyCompression method. Allow Vert.x to manage compression independently.

The updated code could be:

private void applyCompression(boolean enableCompression, Router httpRouteRouter) {
    // Do nothing here and delegate compression logic to Vert.x.
}

Summary

The current implementation of applyCompression conflicts with Vert.x’s dynamic compression capabilities and imposes unnecessary maintenance overhead on developers. By removing this logic, Quarkus can fully leverage Vert.x’s built-in features, streamline code behavior, and better align with user expectations.

@aruis aruis added the kind/bug Something isn't working label Nov 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/vertx kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant