You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Why gzip compression is not disabled for strong etag #13047
Compression adds the suffix of the compression on the ETag response for endpoints that generate the content and care about etags, maintaining the original non-weak etag, but with compression indicated (to satisfy http caching requirement)
Example:
If the original request is ...
GET /context/data HTTP/1.1
Host: localhost:8080
Connection: close
And that request passes through GzipHandler reaching a webapp DataServlet.
That DataServlet produces a response, and also adds the ETag: 2341olla response header.
Since that request didn't have an Accept-Encoding, there's no compression applied, and the response will be roughly ...
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 5123
ETag: 2341olla
<lots of response data here>
Now, if that same client makes a request, with that Etag ...
GET /context/data HTTP/1.1
Host: localhost:8080
If-None-Match: 2341olla
Connection: close
Then the response will again, go through GzipHandler, reach the webapp DataServlet.
That DataServlet checks the If-None-Match etag and decides, that it won't produce a response, but instead responds with a 304.
It goes back up through the response chain, past GzipHandler on the way out and the response seen by the client is ...
HTTP/1.1 304 Not Modified
Content-Type: application/octet-stream
ETag: 2341olla
However, if the client suddenly decides that it can support gzip, like this ...
GET /context/data HTTP/1.1
Host: localhost:8080
If-None-Match: 2341olla
Accept-Encoding: gzip
Connection: close
That will pass through the GzipHandler, it will see the support for Gzip in the request headers and prepare for Gzip response.
The request reaches the webapp DataServlet.
That DataServlet checks the If-None-Match etag and decides, that it won't produce a response, but instead responds with a 304.
The GzipHandler will see the 304 and not compress the response, and not mess with the ETag.
Producing a response like ...
HTTP/1.1 304 Not Modified
Content-Type: application/octet-stream
ETag: 2341olla
Nothing surprising yet, right?
Now, lets look at a new client, that has never asked for the resource, but supports ETag too.
Initial request ...
GET /context/data HTTP/1.1
Host: localhost:8080
Connection: close
And that request passes through GzipHandler reaching a webapp DataServlet.
That DataServlet produces a response, and also adds the ETag: 2341olla response header.
Since that request did have an Accept-Encoding, there is compression applied, and the ETag will have a --gzip suffix applied by the GzipHandler.
HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 413
Content-Encoding: gzip
ETag: 2341olla--gzip
<lots of compressed response data here>
The next request, by this new client will include the ETag in its full form, not being aware of the GzipHandler behavior.
GET /context/data HTTP/1.1
Host: localhost:8080
Accept-Encoding: gzip
If-None-Match: 2341olla--gzip
Connection: close
Then the response will again, go through GzipHandler, and it strips the --gzip suffix on the request If-None-Match header, sending the new modified request to the webapp DataServlet.
That DataServlet checks the If-None-Match etag (which it sees without the --gzip suffix) and decides, that it won't produce a response, but instead responds with a 304.
It goes back up through the response chain, past GzipHandler on the way out and the response seen by the client is ...
HTTP/1.1 304 Not Modified
Content-Type: application/octet-stream
ETag: 2341olla
@joakime, thank you for your reply. You are saying that the calculation/comparison of the ETag is done on the decompressed response, and I agree that compression will work properly in that case.
To give you a little bit of context, I recently migrated from Tomcat to Jetty, and compression is disabled by default for strong tags for Tomcat.
When I deployed the application after the migration, the production (iOS app that requests gzip compressed response) went down because we are heavily using ETags for caching, and Tomcat did not compress the response and did not send headers like 'Vary'.
I have overcome the issue, and I am just saying if disabling compression for strong etags is part of a standard, then Jetty should do the same as Tomcat, and other developers will not have the same issue when doing tomcat-jetty migration.
This issue has been automatically marked as stale because it has been a
full year without activity. It will be closed if no further activity occurs.
Thank you for your contributions.
Activity
joakime commentedon Apr 25, 2025
Compression adds the suffix of the compression on the ETag response for endpoints that generate the content and care about etags, maintaining the original non-weak etag, but with compression indicated (to satisfy http caching requirement)
Example:
If the original request is ...
And that request passes through GzipHandler reaching a webapp DataServlet.
That DataServlet produces a response, and also adds the
ETag: 2341ollaresponse header.Since that request didn't have an
Accept-Encoding, there's no compression applied, and the response will be roughly ...Now, if that same client makes a request, with that Etag ...
Then the response will again, go through GzipHandler, reach the webapp DataServlet.
That DataServlet checks the
If-None-Matchetag and decides, that it won't produce a response, but instead responds with a 304.It goes back up through the response chain, past GzipHandler on the way out and the response seen by the client is ...
However, if the client suddenly decides that it can support gzip, like this ...
That will pass through the GzipHandler, it will see the support for Gzip in the request headers and prepare for Gzip response.
The request reaches the webapp DataServlet.
That DataServlet checks the
If-None-Matchetag and decides, that it won't produce a response, but instead responds with a 304.The GzipHandler will see the 304 and not compress the response, and not mess with the ETag.
Producing a response like ...
Nothing surprising yet, right?
Now, lets look at a new client, that has never asked for the resource, but supports ETag too.
Initial request ...
And that request passes through GzipHandler reaching a webapp DataServlet.
That DataServlet produces a response, and also adds the
ETag: 2341ollaresponse header.Since that request did have an
Accept-Encoding, there is compression applied, and theETagwill have a--gzipsuffix applied by theGzipHandler.The next request, by this new client will include the ETag in its full form, not being aware of the GzipHandler behavior.
Then the response will again, go through GzipHandler, and it strips the
--gzipsuffix on the requestIf-None-Matchheader, sending the new modified request to the webapp DataServlet.That DataServlet checks the
If-None-Matchetag (which it sees without the--gzipsuffix) and decides, that it won't produce a response, but instead responds with a 304.It goes back up through the response chain, past GzipHandler on the way out and the response seen by the client is ...
sroui commentedon Apr 29, 2025
@joakime, thank you for your reply. You are saying that the calculation/comparison of the ETag is done on the decompressed response, and I agree that compression will work properly in that case.
To give you a little bit of context, I recently migrated from Tomcat to Jetty, and compression is disabled by default for strong tags for Tomcat.
When I deployed the application after the migration, the production (iOS app that requests gzip compressed response) went down because we are heavily using ETags for caching, and Tomcat did not compress the response and did not send headers like 'Vary'.
I have overcome the issue, and I am just saying if disabling compression for strong etags is part of a standard, then Jetty should do the same as Tomcat, and other developers will not have the same issue when doing tomcat-jetty migration.
github-actions commentedon Apr 30, 2026
This issue has been automatically marked as stale because it has been a
full year without activity. It will be closed if no further activity occurs.
Thank you for your contributions.
joakime commentedon May 2, 2026
We should add a configurable to 12.1.x CompressionHandler to support this behavior / use-case.