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
The following commit(s) were added to refs/heads/main by this push:
new a0d8e68eee Avoid various edge cases when setting an invalid c-l via
[set|add]Header
a0d8e68eee is described below
commit a0d8e68eee9e97c0fd8f12bf540e86143228a994
Author: Mark Thomas <[email protected]>
AuthorDate: Wed Apr 1 16:17:29 2026 +0100
Avoid various edge cases when setting an invalid c-l via [set|add]Header
Any previous value is always cleared.
Any invalid new value is ignored.
---
java/org/apache/coyote/LocalStrings.properties | 1 +
java/org/apache/coyote/Response.java | 9 +++-----
.../apache/catalina/connector/TestResponse.java | 27 ++++++++++++++++++++++
webapps/docs/changelog.xml | 7 ++++++
4 files changed, 38 insertions(+), 6 deletions(-)
diff --git a/java/org/apache/coyote/LocalStrings.properties
b/java/org/apache/coyote/LocalStrings.properties
index bd4e432e64..b9740662c3 100644
--- a/java/org/apache/coyote/LocalStrings.properties
+++ b/java/org/apache/coyote/LocalStrings.properties
@@ -64,6 +64,7 @@ request.notAsync=It is only valid to switch to non-blocking
IO within async proc
request.nullReadListener=The listener passed to setReadListener() may not be
null
request.readListenerSet=The non-blocking read listener has already been set
+response.contentlength.invalid=The content-length [{0}] is not a valid Long
value and has been ignored. The content length is currently unset.
response.encoding.invalid=The encoding [{0}] is not recognised by the JRE
response.noTrailers.notSupported=A trailer fields supplier may not be set for
this response. Either the underlying protocol does not support trailer fields
or the protocol requires that the supplier is set before the response is
committed
response.notAsync=It is only valid to switch to non-blocking IO within async
processing or HTTP upgrade processing
diff --git a/java/org/apache/coyote/Response.java
b/java/org/apache/coyote/Response.java
index cafec421e0..cb316e1bb5 100644
--- a/java/org/apache/coyote/Response.java
+++ b/java/org/apache/coyote/Response.java
@@ -410,8 +410,6 @@ public final class Response {
* need to set the header.
*/
private boolean checkSpecialHeader(String name, String value) {
- // XXX Eliminate redundant fields !!!
- // ( both header and in special fields )
if (name.equalsIgnoreCase("Content-Type")) {
setContentType(value);
return true;
@@ -424,12 +422,11 @@ public final class Response {
}
long cL = Long.parseLong(value);
setContentLength(cL);
- return true;
} catch (NumberFormatException ex) {
- // Do nothing - the spec doesn't have any "throws"
- // and the user might know what they're doing
- return false;
+ setContentLength(-1);
+ log.warn(sm.getString("response.contentlength.invalid",
value), ex);
}
+ return true;
}
return false;
}
diff --git a/test/org/apache/catalina/connector/TestResponse.java
b/test/org/apache/catalina/connector/TestResponse.java
index 9f0eb25a6b..d8cf0f1da9 100644
--- a/test/org/apache/catalina/connector/TestResponse.java
+++ b/test/org/apache/catalina/connector/TestResponse.java
@@ -1032,4 +1032,31 @@ public class TestResponse extends TomcatBaseTest {
}
}
}
+
+
+ @Test
+ public void testSpecialHeaderContentLength() throws Exception {
+ Response response = setupResponse();
+
+ // Valid
+ response.setHeader("Content-Length", "10");
+ Assert.assertEquals(10, response.getContentLength());
+ Assert.assertEquals("10", response.getHeader("Content-Length"));
+ Assert.assertEquals(1, response.getHeaderNames().stream().filter(s ->
s.equalsIgnoreCase("Content-Length")).count());
+ Assert.assertEquals(1, response.getHeaders("Content-Length").size());
+
+ // Invalid
+ response.setHeader("Content-Length", "zzz");
+ Assert.assertEquals(-1, response.getContentLength());
+ Assert.assertNull(response.getHeader("Content-Length"));
+ Assert.assertEquals(0, response.getHeaderNames().stream().filter(s ->
s.equalsIgnoreCase("Content-Length")).count());
+ Assert.assertEquals(0, response.getHeaders("Content-Length").size());
+
+ // Valid
+ response.setHeader("Content-Length", "20");
+ Assert.assertEquals(20, response.getContentLength());
+ Assert.assertEquals("20", response.getHeader("Content-Length"));
+ Assert.assertEquals(1, response.getHeaderNames().stream().filter(s ->
s.equalsIgnoreCase("Content-Length")).count());
+ Assert.assertEquals(1, response.getHeaders("Content-Length").size());
+ }
}
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index d129d89f63..9dc2cdf04b 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -231,6 +231,13 @@
Remove support for HTTP 0.9. (markt)
</update>
<!-- Entries for backport and removal before 12.0.0-M1 below this line
-->
+ <fix>
+ Avoid various edge cases if <code>Content-Length</code> is set via
+ <code>setHeader(String,String)</code> or
+ <code>addHeader(String,String)</code> with an invalid value by always
+ clearing the previous value whether the new value is valid or not and
+ ignoring any invalid new value. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]