Croway commented on PR #26334:
URL: https://github.com/apache/camel/pull/26334#issuecomment-5635485555
Thanks for digging into this! I ran a reproducer against the PR and found a
regression on the default path.
**Problem:** `!BROTLI4J_AVAILABLE` is also true when brotli4j is not on the
classpath at all (plain Camel / Spring Boot), so the custom decoder map is
always installed. `buildDecodersWithoutBrotli()` drops the `x-gzip` alias that
HttpClient's default `ContentCompressionExec` registers: `Accept-Encoding`
becomes `gzip, deflate` and a `Content-Encoding: x-gzip` response fails with
`ClientProtocolException: Unsupported Content-Encoding: x-gzip`.
camel-http test with gzip / x-gzip / br / negotiated responses, across
classpaths:
| | brotli4j absent | brotli4j without native | brotli4j + native |
|---|---|---|---|
| main | ✅ | ❌ `UnsatisfiedLinkError` | ✅ |
| this PR | ❌ x-gzip | ❌ x-gzip | ✅ |
| suggested approach below | ✅ | ✅ | ✅ |
The new tests don't catch it: the test-scoped `brotli4j` pulls the native
jar on CI (Maven activates its OS profiles, also for transitive dependencies),
so the "unavailable" branch never runs.
For reference, HttpClient fixed this itself in
apache/httpcomponents-client@be07c77297576b08bc01bb93789eca6f5f9bf850 (not
released yet): `Brotli4jRuntime.available()` now loads `Brotli4jLoader` and
returns `isAvailable()` instead of only checking the class is present. The
Camel check can mirror that, and becomes redundant once we upgrade.
**Suggested approach: a narrow, self-disabling workaround in camel-http.**
Only replace the decoders when HttpClient registered brotli4j but its native
library can't load, keep `x-gzip`, and evaluate lazily (not in
`HttpComponent`'s static init). Once HttpClient ships the fix,
`Brotli4jRuntime.available()` returns false and this becomes a no-op.
```java
// HttpComponent#createHttpClientBuilder
} else if (BrotliContentDecoders.isBrotliDecoderUnusable()) { // lazy holder:
// Brotli4jRuntime.available() && !Brotli4jLoader.isAvailable()
(reflective)
clientBuilder.setContentDecoderRegistry(BrotliContentDecoders.decodersWithoutBrotli());
}
static LinkedHashMap<String, InputStreamFactory> decodersWithoutBrotli() {
LinkedHashMap<String, InputStreamFactory> decoders = new
LinkedHashMap<>();
for (ContentCoding coding : ContentCoding.values()) {
if (coding != ContentCoding.BROTLI &&
ContentCodecRegistry.decoder(coding) != null) {
decoders.put(coding.token(), decoder(coding));
}
}
// HttpClient's default content compression also accepts x-gzip as an
alias of gzip
if (decoders.containsKey(ContentCoding.GZIP.token())) {
decoders.put(ContentCoding.X_GZIP.token(),
decoder(ContentCoding.GZIP));
}
return decoders;
}
```
quarkusio/quarkus#56547 is still worth pursuing for the dev-mode case.
**Tests**, independent of the build machine:
- test-scoped `brotli4j` with a `*` exclusion plus an explicit `service`
dependency, so every CI platform runs with "classes but no native library" and
exercises the workaround;
- an HTTP test asserting `gzip`, `x-gzip` and a server-negotiated `br`
response all decode, and that `Accept-Encoding` equals HttpClient's default
minus `br`;
- the reflective availability check against an isolated `URLClassLoader`
holding only the brotli4j and service jars.
Minor: the JIRA says Maven doesn't activate brotli4j's profiles for
transitive dependencies, but `mvn dependency:tree` on `quarkus-vertx-http` does
pull `native-<os>`, and packaged Quarkus apps ship it. The missing native
library is specific to dev mode / `camel run --runtime=quarkus` (and to images
built on a different OS/arch), so it may be worth correcting the description.
_Claude Code on behalf of Croway_
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]