Hi Tomcat developers,

As a follow-up to the proposal on configurable gzip compression parameters,
I would like to suggest an additional enhancement that enables pluggable
compression algorithms through an OutputFilterFactory pattern.

---

*Background*

While the gzip configuration work provides tunable compression settings,
users increasingly require support for alternative algorithms such as
Brotli, Zstandard, or even custom implementations. Currently, Tomcat’s
compression system is tightly coupled to gzip.

---

*Proposed Enhancement: OutputFilterFactory Pattern*

Objective: Enable pluggable compression algorithms while maintaining full
backward compatibility.


*1. OutputFilterFactory Interface*
```java
public interface OutputFilterFactory {
    OutputFilter createFilter(AbstractHttp11Protocol<?> protocol);
    String getEncodingName();  // e.g., "gzip", "br", "zstd"
}

2. Default Implementation: GzipOutputFilterFactory
```java
public class GzipOutputFilterFactory implements OutputFilterFactory {
    @Override
    public OutputFilter createFilter(AbstractHttp11Protocol<?> protocol) {
        GzipOutputFilter filter = new GzipOutputFilter();
        filter.setLevel(protocol.getGzipLevel());
        filter.setBufferSize(protocol.getGzipBufferSize());
        filter.setSyncFlush(protocol.getGzipSyncFlush());
        return filter;
    }

    @Override
    public String getEncodingName() {
        return "gzip";
    }
}
```


*3. Integration with AbstractHttp11Protocol*```java
private OutputFilterFactory outputFilterFactory = new
GzipOutputFilterFactory();

public void setOutputFilterFactory(OutputFilterFactory factory) {
    this.outputFilterFactory = factory;
}

public void setOutputFilterFactory(String className) throws Exception {
    Class<?> clazz = Class.forName(className);
    this.outputFilterFactory =
        (OutputFilterFactory) clazz.getDeclaredConstructor().newInstance();
}
```

4. noCompressionEncodings Configuration
```java
private Set<String> noCompressionEncodings =
    new HashSet<>(Arrays.asList("br","compress","gzip","deflate","zstd"));

if (tokens.contains("identity")) {

    // If identity, do not do content modifications

    useContentEncoding = false;

} else if (noCompressionEncodings.stream().anyMatch(tokens::contains)) {

    // Content should not be compressed twice

    return false;

}
```

---

Configuration Examples

*1. Default (Gzip)*
```xml
<Connector port="8080" protocol="HTTP/1.1" compression="on" />
```

2. Custom Algorithm (Brotli)
```java
public class BrotliOutputFilterFactory implements OutputFilterFactory {
    @Override
    public OutputFilter createFilter(AbstractHttp11Protocol<?> protocol) {
        return new BrotliOutputFilter(protocol.getCompressionLevel());
    }

    @Override
    public String getEncodingName() {
        return "br";
    }
}
```

```xml
<Connector port="8080" protocol="HTTP/1.1"
           compression="on"
           outputFilterFactory="com.example.BrotliOutputFilterFactory"
           noCompressionEncodings="gzip,br,deflate" />
```

3. Programmatic
```xml
Http11NioProtocol protocol = new Http11NioProtocol();
protocol.setCompression("on");
protocol.setOutputFilterFactory(new BrotliOutputFilterFactory());
```

---

*Benefits*


   1. Extensibility – Enables Brotli, Zstandard, or custom algorithms
   without modifying Tomcat source.
   2. Backward Compatibility – Default behavior unchanged (gzip remains
   default).
   3. Framework Integration – Easier to integrate with Spring Boot,
   Quarkus, etc.
   4. Future-Proof – New algorithms can be added through additional
   factories.

All changes are backward-compatible and can be cleanly backported to:


   -

   Tomcat 9.0.x
   -

   Tomcat 10.1.x
   -

   Tomcat 11.0.x (main)

An implementation is available and can be shared if the community is
interested.

Thanks for your consideration and feedback!


Best regards,

2025년 10월 31일 (금) 오전 11:34, 장성호 <[email protected]>님이 작성:

> Hi Tomcat developers,
>
> I would like to propose adding configurable gzip compression parameters to
>
> Tomcat's HTTP compression implementation. This enhancement would give users
>
> fine-grained control over compression behavior to optimize for their
> specific
>
> use cases.
>
> ---
>
> Problem Statement
>
> Currently, Tomcat's `GzipOutputFilter` uses hardcoded values for gzip
> compression:
>
> - Compression level: Always uses `Deflater.DEFAULT_COMPRESSION` (-1)
>
> - Buffer size: Fixed at 512 bytes
>
> - Sync flush: Hardcoded to `true`
>
>
> This limitation prevents users from:
>
> 1. Tuning compression level for speed vs. compression ratio trade-offs
>
> 2. Adjusting buffer sizes for different response patterns (streaming vs.
> bulk)
>
> 3. Controlling sync flush behavior for different latency requirements
>
>
> Users have raised this issue before (e.g., [Spring Boot issue #25748]),
>
> where the Spring Boot team noted that Tomcat doesn't expose these
> configuration options.
>
>
> ---
>
>
> Proposed Solution
>
> Add three new configurable properties to `AbstractHttp11Protocol`
>
> and HTTP/2’s compression logic:
>
>
> 1. gzipLevel (int, default: -1)
>
>    - Valid range: -1 (default), 0 (no compression), 1–9
>
>    - Maps directly to `java.util.zip.Deflater` compression levels
>
>
> 2. gzipBufferSize (int, default: 512)
>
>    - Internal buffer size for `GZIPOutputStream`
>
>    - Must be positive
>
>
> 3. gzipSyncFlush (boolean, default: true)
>
>    - Controls whether flush() calls invoke the deflater’s SYNC_FLUSH
>
>    - Important for streaming scenarios
>
>
> ---
>
> Implementation Details
>
> The implementation requires small changes in the following files:
>
>
> 1. GzipOutputFilter.java
>
>    - Add three private fields with getters/setters
>
>    - Use configurable values instead of hardcoded ones
>
>
> 2. CompressionConfig.java
>
>    - Add new fields and validation logic
>
>    - Validate compression level (-1 to 9) and buffer size (>0)
>
>
> 3. AbstractHttp11Protocol.java
>
>    - Expose new properties delegating to CompressionConfig
>
>    - Enables configuration via `server.xml` or programmatic API
>
>
> 4. Http11Processor.java and StreamProcessor.java - Pass configured
> values to `GzipOutputFilter` instances
>
>
> ---
>
>
> Configuration Examples
>
> server.xml
>
> ```xml
>
> <Connector port="8080" protocol="HTTP/1.1"
>
>            compression="on"
>
>            gzipLevel="6"
>
>            gzipBufferSize="8192"
>
>            gzipSyncFlush="true" />
>
> ```
>
> Benefits
>
> Performance tuning: Balance CPU vs. bandwidth by adjusting compression
> level
>
> Streaming optimization: Control buffer size and sync flush for
> real-time responses
>
> Framework integration: Enables frameworks (Spring Boot, Quarkus, etc.)
> to expose these settings
>
> Consistency: Aligns with configuration practices in Jetty and Undertow
>
>
> Target Versions
>
>
> This enhancement can be safely applied to:
>
> Tomcat 11.0.x (main)
>
> Tomcat 10.1.x
>
> Tomcat 9.0.x
>
>
> It is non-breaking and low-risk, as it only adds configuration hooks.
>
> Patch Availability
>
>
> A working implementation is available locally.
>
> If the community is interested, I can open a Bugzilla enhancement ticket
>
> and submit patches for Tomcat 9 → 11 along with test cases
>
> and documentation updates.
>
>
> Would the Tomcat community be interested in reviewing this enhancement?
>
>
> Best regards,
>
>
> --
> 장성호
> Server Platform Developer, Server Platform Team
> 010-3868-8634 | [email protected]
> 서울특별시 강남구 테헤란로 142, 4층, 10층, 11층, 12층, 13층, 22층, 23층(역삼동, 아크플레이스) (06236)
>


-- 
*장성호*
Server Platform Developer, Server Platform Team
010-3868-8634 | [email protected]
서울특별시 강남구 테헤란로 142, 4층, 10층, 11층, 12층, 13층, 22층, 23층(역삼동, 아크플레이스) (06236)
[image: Toss BI]

Reply via email to