Thoughts on back-porting this? From a consistency point of view we
probably should. If someone calls setHeader("Content-Type","something")
they'd expect a call to getHeader("Content-Type") to return the value
they just set.
Mark
On 03/03/2026 23:15, [email protected] wrote:
This is an automated email from the ASF dual-hosted git repository.
remm 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 5f9bd1d87d Fix inconsistencies with special headers and getHeader
5f9bd1d87d is described below
commit 5f9bd1d87d18b3898ebcc5a103a8266f5f98ce9a
Author: remm <[email protected]>
AuthorDate: Wed Mar 4 00:15:20 2026 +0100
Fix inconsistencies with special headers and getHeader
Handling of Content-Type and Content-Length with getHeader,
getHeaderNames and getHeaders.
BZ69967
---
java/org/apache/catalina/connector/Response.java | 46 +++++++++++++++++++++-
.../apache/catalina/connector/TestResponse.java | 18 +++++++++
webapps/docs/changelog.xml | 5 +++
3 files changed, 68 insertions(+), 1 deletion(-)
diff --git a/java/org/apache/catalina/connector/Response.java
b/java/org/apache/catalina/connector/Response.java
index 3741673014..55aa8b826d 100644
--- a/java/org/apache/catalina/connector/Response.java
+++ b/java/org/apache/catalina/connector/Response.java
@@ -747,6 +747,23 @@ public class Response implements HttpServletResponse {
@Override
public String getHeader(String name) {
+ // Need special handling for Content-Type and Content-Length due to
+ // special handling of these in coyoteResponse
+ char cc = name.charAt(0);
+ if (cc == 'C' || cc == 'c') {
+ if (name.equalsIgnoreCase("Content-Type")) {
+ // Will return null if this has not been set
+ return getCoyoteResponse().getContentType();
+ }
+ if (name.equalsIgnoreCase("Content-Length")) {
+ // -1 means not known and is not sent to client
+ if (getCoyoteResponse().getContentLengthLong() != -1) {
+ return
String.valueOf(getCoyoteResponse().getContentLengthLong());
+ } else {
+ return null;
+ }
+ }
+ }
return getCoyoteResponse().getMimeHeaders().getHeader(name);
}
@@ -759,13 +776,40 @@ public class Response implements HttpServletResponse {
for (int i = 0; i < n; i++) {
result.add(headers.getName(i).toString());
}
+ if (getCoyoteResponse().getContentType() != null) {
+ result.add("Content-Type");
+ }
+ if (getCoyoteResponse().getContentLengthLong() != -1) {
+ result.add("Content-Length");
+ }
return result;
-
}
@Override
public Collection<String> getHeaders(String name) {
+ // Need special handling for Content-Type and Content-Length due to
+ // special handling of these in coyoteResponse
+ char cc = name.charAt(0);
+ if (cc == 'C' || cc == 'c') {
+ if (name.equalsIgnoreCase("Content-Type")) {
+ // Will return null if this has not been set
+ String contentType = getCoyoteResponse().getContentType();
+ if (contentType != null) {
+ return Set.of(contentType);
+ } else {
+ return Set.of();
+ }
+ }
+ if (name.equalsIgnoreCase("Content-Length")) {
+ // -1 means not known and is not sent to client
+ if (getCoyoteResponse().getContentLengthLong() != -1) {
+ return
Set.of(String.valueOf(getCoyoteResponse().getContentLengthLong()));
+ } else {
+ return Set.of();
+ }
+ }
+ }
Enumeration<String> enumeration =
getCoyoteResponse().getMimeHeaders().values(name);
Set<String> result = new LinkedHashSet<>();
while (enumeration.hasMoreElements()) {
diff --git a/test/org/apache/catalina/connector/TestResponse.java
b/test/org/apache/catalina/connector/TestResponse.java
index f79a3cebf8..9f0eb25a6b 100644
--- a/test/org/apache/catalina/connector/TestResponse.java
+++ b/test/org/apache/catalina/connector/TestResponse.java
@@ -736,6 +736,24 @@ public class TestResponse extends TomcatBaseTest {
}
+ @Test
+ public void testSetContentLengthHeader() {
+ Response response = setupResponse();
+
+ response.setContentLength(10);
+ Assert.assertEquals("10", response.getHeader("Content-Length"));
+ }
+
+
+ @Test
+ public void testSetContentTypeHeader() {
+ Response response = setupResponse();
+
+ response.setContentType(TEXT_UTF_8);
+ Assert.assertEquals(TEXT_UTF_8, response.getHeader("Content-Type"));
+ }
+
+
@Test
public void testSetContentType01() {
Response response = setupResponse();
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 20d0219006..4851a94056 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -191,6 +191,11 @@
to <code>true</code>. (markt)
</update>
<!-- Entries for backport and removal before 12.0.0-M1 below this line
-->
+ <fix>
+ <bug>69967</bug>: Fix inconsistencies related to
+ <code>Content-Length</code> and <code>Content-Type</code> headers when
+ accessed using the <code>getHeader</code> method and similar. (remm)
+ </fix>
</changelog>
</subsection>
<subsection name="Coyote">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]