You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2026/02/06 18:55:41 UTC
(tomcat) branch main updated (07a68e963a -> 638759b26e)
This is an automated email from the ASF dual-hosted git repository.
markt pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
from 07a68e963a Improve formatting
new 93f5c419ee Update baseline to 11.0.18
new 638759b26e Add an HTTP configuration setting, noCompressionEncodings
The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
java/org/apache/coyote/CompressionConfig.java | 34 ++++++++++++--
.../coyote/http11/AbstractHttp11Protocol.java | 9 ++++
test/org/apache/coyote/TestCompressionConfig.java | 54 ++++++++++++++--------
.../apache/coyote/http11/TestHttp11Processor.java | 30 +++++++++---
webapps/docs/changelog.xml | 13 +++---
webapps/docs/config/http.xml | 12 +++++
6 files changed, 117 insertions(+), 35 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
(tomcat) 02/02: Add an HTTP configuration setting, noCompressionEncodings
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 638759b26eb2ae7b5760232ced65b1147ec585ef
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Feb 6 18:55:30 2026 +0000
Add an HTTP configuration setting, noCompressionEncodings
This can be used to control which content encodings will not be
compressed when compression is enabled.
Based on pull request #914 by Long9725.
---
java/org/apache/coyote/CompressionConfig.java | 34 ++++++++++++--
.../coyote/http11/AbstractHttp11Protocol.java | 9 ++++
test/org/apache/coyote/TestCompressionConfig.java | 54 ++++++++++++++--------
.../apache/coyote/http11/TestHttp11Processor.java | 30 +++++++++---
webapps/docs/changelog.xml | 6 +++
webapps/docs/config/http.xml | 12 +++++
6 files changed, 116 insertions(+), 29 deletions(-)
diff --git a/java/org/apache/coyote/CompressionConfig.java b/java/org/apache/coyote/CompressionConfig.java
index c48dee1b13..2cf718936b 100644
--- a/java/org/apache/coyote/CompressionConfig.java
+++ b/java/org/apache/coyote/CompressionConfig.java
@@ -19,6 +19,7 @@ package org.apache.coyote;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.List;
@@ -47,6 +48,35 @@ public class CompressionConfig {
"text/javascript,application/javascript,application/json,application/xml";
private String[] compressibleMimeTypes = null;
private int compressionMinSize = 2048;
+ private Set<String> noCompressionEncodings =
+ new HashSet<>(Arrays.asList("br", "compress", "dcb", "dcz", "deflate", "gzip", "pack200-gzip", "zstd"));
+
+
+ public String getNoCompressionEncodings() {
+ return String.join(",", noCompressionEncodings);
+ }
+
+
+ /**
+ * Set the list of content encodings that indicate already-compressed content.
+ * When content is already encoded with one of these encodings, compression will not be applied
+ * to prevent double compression.
+ *
+ * @param encodings Comma-separated list of encoding names (e.g., "gzip,br.dflate")
+ */
+ public void setNoCompressionEncodings(String encodings) {
+ Set<String> newEncodings = new HashSet<>();
+ if (encodings != null && !encodings.isEmpty()) {
+ StringTokenizer tokens = new StringTokenizer(encodings, ",");
+ while (tokens.hasMoreTokens()) {
+ String token = tokens.nextToken().trim();
+ if(!token.isEmpty()) {
+ newEncodings.add(token);
+ }
+ }
+ }
+ this.noCompressionEncodings = newEncodings;
+ }
/**
@@ -210,9 +240,7 @@ public class CompressionConfig {
if (tokens.contains("identity")) {
// If identity, do not do content modifications
useContentEncoding = false;
- } else if (tokens.contains("br") || tokens.contains("compress") || tokens.contains("dcb") ||
- tokens.contains("dcz") || tokens.contains("deflate") || tokens.contains("gzip") ||
- tokens.contains("pack200-gzip") || tokens.contains("zstd")) {
+ } else if (noCompressionEncodings.stream().anyMatch(tokens::contains)) {
// Content should not be compressed twice
return false;
}
diff --git a/java/org/apache/coyote/http11/AbstractHttp11Protocol.java b/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
index 3b778a5057..f5ee4821d3 100644
--- a/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
+++ b/java/org/apache/coyote/http11/AbstractHttp11Protocol.java
@@ -340,6 +340,15 @@ public abstract class AbstractHttp11Protocol<S> extends AbstractProtocol<S> {
}
+ public String getNoCompressionEncodings() {
+ return compressionConfig.getNoCompressionEncodings();
+ }
+
+ public void setNoCompressionEncodings(String encodings) {
+ compressionConfig.setNoCompressionEncodings(encodings);
+ }
+
+
public boolean useCompression(Request request, Response response) {
return compressionConfig.useCompression(request, response);
}
diff --git a/test/org/apache/coyote/TestCompressionConfig.java b/test/org/apache/coyote/TestCompressionConfig.java
index ae16c02f8f..be336ec7e6 100644
--- a/test/org/apache/coyote/TestCompressionConfig.java
+++ b/test/org/apache/coyote/TestCompressionConfig.java
@@ -17,6 +17,7 @@
package org.apache.coyote;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@@ -33,29 +34,30 @@ public class TestCompressionConfig {
public static Collection<Object[]> parameters() {
List<Object[]> parameterSets = new ArrayList<>();
- parameterSets.add(new Object[] { new String[] { }, null, Boolean.FALSE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { "gzip" }, null, Boolean.TRUE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { "xgzip" }, null, Boolean.FALSE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { "<>gzip" }, null, Boolean.FALSE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { "foo", "gzip" }, null, Boolean.TRUE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { "<>", "gzip" }, null, Boolean.TRUE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] {}, null, Boolean.FALSE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] { "gzip" }, null, Boolean.TRUE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] { "xgzip" }, null, Boolean.FALSE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] { "<>gzip" }, null, Boolean.FALSE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] { "foo", "gzip" }, null, Boolean.TRUE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] { "<>", "gzip" }, null, Boolean.TRUE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { "gzip" }, null, Boolean.TRUE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { "gzip" }, "W/", Boolean.TRUE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { "gzip" }, "XX", Boolean.FALSE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] { "gzip" }, null, Boolean.TRUE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] { "gzip" }, "W/", Boolean.TRUE, Boolean.FALSE });
+ parameterSets.add(new Object[] { new String[] { "gzip" }, "XX", Boolean.FALSE, Boolean.FALSE });
- parameterSets.add(new Object[] { new String[] { }, null, Boolean.FALSE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "gzip" }, null, Boolean.TRUE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "xgzip" }, null, Boolean.FALSE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "<>gzip" }, null, Boolean.FALSE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "foo", "gzip" }, null, Boolean.TRUE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "<>", "gzip" }, null, Boolean.TRUE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] {}, null, Boolean.FALSE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "gzip" }, null, Boolean.TRUE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "xgzip" }, null, Boolean.FALSE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "<>gzip" }, null, Boolean.FALSE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "foo", "gzip" }, null, Boolean.TRUE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "<>", "gzip" }, null, Boolean.TRUE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "gzip" }, null, Boolean.TRUE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "gzip" }, "W/", Boolean.TRUE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "gzip" }, "XX", Boolean.TRUE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "gzip" }, null, Boolean.TRUE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "gzip" }, "W/", Boolean.TRUE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "gzip" }, "XX", Boolean.TRUE, Boolean.TRUE });
- parameterSets.add(new Object[] { new String[] { "foobar;foo=bar, gzip;bla=\"quoted\"" }, "XX", Boolean.TRUE, Boolean.TRUE });
+ parameterSets.add(new Object[] { new String[] { "foobar;foo=bar, gzip;bla=\"quoted\"" }, "XX", Boolean.TRUE,
+ Boolean.TRUE });
return parameterSets;
}
@@ -110,4 +112,18 @@ public class TestCompressionConfig {
}
}
}
+
+
+ @Test
+ public void testNoCompressionEncodings() {
+ CompressionConfig config = new CompressionConfig();
+ String encodings = config.getNoCompressionEncodings();
+ Assert.assertTrue(Arrays.asList("br", "compress", "dcb", "dcz", "deflate", "gzip", "pack200-gzip", "zstd")
+ .stream().anyMatch(encodings::contains));
+
+ config.setNoCompressionEncodings("br");
+ String newEncodings = config.getNoCompressionEncodings();
+ Assert.assertTrue(newEncodings.contains("br"));
+ Assert.assertFalse(newEncodings.contains("gzip"));
+ }
}
diff --git a/test/org/apache/coyote/http11/TestHttp11Processor.java b/test/org/apache/coyote/http11/TestHttp11Processor.java
index cc00ac4d84..fd77108f0d 100644
--- a/test/org/apache/coyote/http11/TestHttp11Processor.java
+++ b/test/org/apache/coyote/http11/TestHttp11Processor.java
@@ -32,6 +32,7 @@ import java.net.SocketAddress;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -421,7 +422,7 @@ public class TestHttp11Processor extends TomcatBaseTest {
tomcat.start();
ByteChunk responseBody = new ByteChunk();
- Map<String, List<String>> responseHeaders = new HashMap<>();
+ Map<String,List<String>> responseHeaders = new HashMap<>();
int rc = getUrl("http://localhost:" + getPort() + "/test", responseBody, responseHeaders);
Assert.assertEquals(HttpServletResponse.SC_OK, rc);
@@ -445,7 +446,7 @@ public class TestHttp11Processor extends TomcatBaseTest {
tomcat.start();
ByteChunk responseBody = new ByteChunk();
- Map<String, List<String>> responseHeaders = new HashMap<>();
+ Map<String,List<String>> responseHeaders = new HashMap<>();
int rc = getUrl("http://localhost:" + getPort() + "/test", responseBody, responseHeaders);
Assert.assertEquals(HttpServletResponse.SC_OK, rc);
@@ -854,11 +855,11 @@ public class TestHttp11Processor extends TomcatBaseTest {
tomcat.start();
ByteChunk getBody = new ByteChunk();
- Map<String, List<String>> getHeaders = new HashMap<>();
+ Map<String,List<String>> getHeaders = new HashMap<>();
int getStatus = getUrl("http://localhost:" + getPort() + "/test", getBody, getHeaders);
ByteChunk headBody = new ByteChunk();
- Map<String, List<String>> headHeaders = new HashMap<>();
+ Map<String,List<String>> headHeaders = new HashMap<>();
int headStatus = getUrl("http://localhost:" + getPort() + "/test", headBody, headHeaders);
Assert.assertEquals(HttpServletResponse.SC_OK, getStatus);
@@ -997,7 +998,7 @@ public class TestHttp11Processor extends TomcatBaseTest {
tomcat.start();
ByteChunk responseBody = new ByteChunk();
- Map<String, List<String>> responseHeaders = new HashMap<>();
+ Map<String,List<String>> responseHeaders = new HashMap<>();
int rc = getUrl("http://localhost:" + getPort() + "/test", responseBody, responseHeaders);
Assert.assertEquals(HttpServletResponse.SC_RESET_CONTENT, rc);
@@ -2149,7 +2150,6 @@ public class TestHttp11Processor extends TomcatBaseTest {
}
-
private static class EarlyHintsServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@@ -2165,6 +2165,7 @@ public class TestHttp11Processor extends TomcatBaseTest {
this.useSendError = useSendError;
this.errorString = errorString;
}
+
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.addHeader("Link", "</style.css>; rel=preload; as=style");
@@ -2185,4 +2186,19 @@ public class TestHttp11Processor extends TomcatBaseTest {
resp.getWriter().write("OK");
}
}
-}
+
+
+ @Test
+ public void testNoCompressionEncodings() {
+ Http11NioProtocol protocol = new Http11NioProtocol();
+ String encodings = protocol.getNoCompressionEncodings();
+ Assert.assertTrue(Arrays.asList("br", "compress", "dcb", "dcz", "deflate", "gzip", "pack200-gzip", "zstd")
+ .stream().anyMatch(encodings::contains));
+
+ protocol.setNoCompressionEncodings("br");
+
+ String newEncodings = protocol.getNoCompressionEncodings();
+ Assert.assertTrue(newEncodings.contains("br"));
+ Assert.assertFalse(newEncodings.contains("gzip"));
+ }
+}
\ No newline at end of file
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 83d23edd62..a470fac154 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -227,6 +227,12 @@
<bug>69938</bug>: Avoid changing the closed state of TLS channel when
resetting it after close. (remm)
</fix>
+ <add>
+ Add an HTTP configuration setting, <code>noCompressionEncodings</code>,
+ that can be used to control which content encodings will not be
+ compressed when compression is enabled. Based on pull request
+ <pr>914</pr> by Long9725. (markt)
+ </add>
</changelog>
</subsection>
<subsection name="Jasper">
diff --git a/webapps/docs/config/http.xml b/webapps/docs/config/http.xml
index deb1ed5c3c..443183508f 100644
--- a/webapps/docs/config/http.xml
+++ b/webapps/docs/config/http.xml
@@ -651,6 +651,18 @@
used.</p>
</attribute>
+ <attribute name="noCompressionEncodings" requried="false">
+ <p>A comma-separated list of content encodings that indicate
+ already-compressed content. When the response already has a
+ <code>Content-Encoding</code> header with one of these values, compression
+ will not be applied to prevent double compression. This attribute is only
+ used if <strong>compression</strong> is set to <code>on</code> or
+ <code>force</code>.</p>
+ <p>If not specified, the default values is
+ <code>br,compress,dcb,dcz,deflate,gzip,pack2000-gzip,zstd</code>, which
+ includes all commonly used compression algorithms.</p>
+ </attribute>
+
<attribute name="noCompressionUserAgents" required="false">
<p>The value is a regular expression (using <code>java.util.regex</code>)
matching the <code>user-agent</code> header of HTTP clients for which
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org
(tomcat) 01/02: Update baseline to 11.0.18
Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
markt pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 93f5c419eec96142dcba1366527e2e3cdf5293bb
Author: Mark Thomas <ma...@apache.org>
AuthorDate: Fri Feb 6 18:20:53 2026 +0000
Update baseline to 11.0.18
---
webapps/docs/changelog.xml | 7 +------
1 file changed, 1 insertion(+), 6 deletions(-)
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index b9fa6fcee6..83d23edd62 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -109,7 +109,7 @@
<changelog>
<scode>
This release contains all of the changes up to and including those in
- Apache Tomcat 11.0.17 plus the additional changes listed below. (markt)
+ Apache Tomcat 11.0.18 plus the additional changes listed below. (markt)
</scode>
<update>
The minimum Java version has been updated to Java 21. (markt)
@@ -223,11 +223,6 @@
Remove support for HTTP 0.9. (markt)
</update>
<!-- Entries for backport and removal before 12.0.0-M1 below this line -->
- <fix>
- <bug>69936</bug>: Fix bug in previous fix for Tomcat Native crashes on
- shutdown that triggered a significant memory leak. Patch provided by
- Wes. (markt)
- </fix>
<fix>
<bug>69938</bug>: Avoid changing the closed state of TLS channel when
resetting it after close. (remm)
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org