Skip to content

Fix stale Content-Encoding header in ProxyServlet after HttpClient bump - #7937

Merged
labkey-tchad merged 6 commits into
release26.7-SNAPSHOTfrom
26.7_fb_httpClientUpgrade
Aug 17, 2026
Merged

Fix stale Content-Encoding header in ProxyServlet after HttpClient bump#7937
labkey-tchad merged 6 commits into
release26.7-SNAPSHOTfrom
26.7_fb_httpClientUpgrade

Conversation

@labkey-tchad

@labkey-tchad labkey-tchad commented Aug 15, 2026

Copy link
Copy Markdown
Member

Rationale

The bug, in ProxyServlet:

  proxyResponse = proxyClient.execute(getTargetHost(servletRequest), proxyRequest);
  copyResponseHeaders(proxyResponse, servletRequest, servletResponse);   // copies Content-Encoding verbatim
  copyResponseEntity(proxyResponse, servletResponse, proxyRequest, servletRequest);  // streams whatever entity HttpClient gave it
  copyResponseHeader only skips hop-by-hop headers (Connection, Keep-Alive, Transfer-Encoding, etc.) — Content-Encoding and Content-Length are copied through unconditionally.

Why 5.6.4 breaks this: Apache HttpClient5's internal ContentCompressionExec auto-decompresses gzip/deflate response bodies transparently. In 5.5.2 it also scrubbed the now-stale headers off the raw response:

  response.setEntity(new DecompressingEntity(response.getEntity(), decoderFactory));
  response.removeHeaders(HttpHeaders.CONTENT_LENGTH);
  response.removeHeaders(HttpHeaders.CONTENT_ENCODING);   // <- removed
  response.removeHeaders(HttpHeaders.CONTENT_MD5);

In 5.6.4 (part of a rewrite adding pluggable codecs — Brotli/Zstd/etc. — via a new ContentCodecRegistry), that cleanup was dropped:

  response.setEntity(decoder.apply(response.getEntity()));
  // no more removeHeaders() calls

The entity is still silently decompressed, but Content-Encoding: gzip (and the old compressed Content-Length) now survive on the response object and get forwarded verbatim by ProxyServlet.

Net effect: browser receives Content-Encoding: gzip header + already-decompressed plaintext body → Firefox refuses to render it → exactly the contentEncodingError you're seeing.

Related Pull Requests

Changes

  • Disable HttpClient's automatic content-decompression on the shared proxyClient in ProxyServlet.createHttpClient(), so ProxyServlet always streams the backend's original bytes and headers through unmodified.

HttpClient5 5.6+ stopped stripping Content-Encoding/Content-Length after auto-decompressing responses, so ProxyServlet forwarded a decompressed body under a stale compressed-encoding header. Disable auto-decompression so bytes and headers always stay consistent.
@labkey-tchad
labkey-tchad requested a review from XingY August 15, 2026 01:35
@labkey-tchad

Copy link
Copy Markdown
Member Author

Verifying with RStudio on TeamCity: https://teamcity.labkey.org/buildConfiguration/LabKey_267Release_Premium_ModulesSuites_RStudioPostgres/4134256
Not sure how this will interact with the doHandleCompression flag added for AWS.

@XingY XingY left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It seems our ProxyServlet diverged from the original implementation:
https://github.com/mitre/HTTP-Proxy-Servlet/blame/9a522c5c021e6941cd951941ed49d96ff996f1eb/src/main/java/org/mitre/dsmiley/httpproxy/ProxyServlet.java#L286

Based on the original code, if should check doHandleCompression to set the config.

@labkey-tchad
labkey-tchad requested a review from XingY August 17, 2026 20:25
if (doHandleCompression && headerName.equals(HttpHeaders.ACCEPT_ENCODING))
return;
// In Apache HttpClient <5.6.4, these headers were automatically removed. Now we need to remove them manually.
if (doHandleCompression && (headerName.equals(HttpHeaders.CONTENT_ENCODING) || headerName.equals(HttpHeaders.CONTENT_MD5)))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Can this be added in LabKeyProxyServlet as override instead? We try to keep ProxyServlet consistent with the original library to make the next sync easier.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

On, sure, that makes sense.
I suspect something similar will be added to the upstream if/when they update HttpClient. They haven't really made any significant changes since 2023.

@labkey-tchad
labkey-tchad requested a review from XingY August 17, 2026 20:50
@labkey-tchad

Copy link
Copy Markdown
Member Author

@labkey-tchad
labkey-tchad merged commit b032e26 into release26.7-SNAPSHOT Aug 17, 2026
8 of 11 checks passed
@labkey-tchad
labkey-tchad deleted the 26.7_fb_httpClientUpgrade branch August 17, 2026 23:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants