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 8e786a8eda Update the default HEAD response to exclude payload headers
8e786a8eda is described below
commit 8e786a8eda188426dff97e9c997dfceb4eb469c2
Author: Mark Thomas <[email protected]>
AuthorDate: Thu Jan 19 20:40:10 2023 +0000
Update the default HEAD response to exclude payload headers
First explicitly allowed in RFC 7231 and also in the current RFC 9110
---
java/org/apache/coyote/http11/Http11Processor.java | 10 +++++++-
java/org/apache/coyote/http2/StreamProcessor.java | 6 +++++
.../servlet/http/HttpServletDoHeadBaseTest.java | 27 +++++++++++++++++-----
test/jakarta/servlet/http/TestHttpServlet.java | 20 ++++++++++++++--
webapps/docs/changelog.xml | 4 ++++
5 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/java/org/apache/coyote/http11/Http11Processor.java
b/java/org/apache/coyote/http11/Http11Processor.java
index c27ff911f4..951d276593 100644
--- a/java/org/apache/coyote/http11/Http11Processor.java
+++ b/java/org/apache/coyote/http11/Http11Processor.java
@@ -916,7 +916,8 @@ public class Http11Processor extends AbstractProcessor {
}
MessageBytes methodMB = request.method();
- if (methodMB.equals("HEAD")) {
+ boolean head = methodMB.equals("HEAD");
+ if (head) {
// No entity body
outputBuffer.addActiveFilter
(outputFilters[Constants.VOID_FILTER]);
@@ -1056,6 +1057,13 @@ public class Http11Processor extends AbstractProcessor {
headers.setValue("Server").setString(server);
}
+ if (head) {
+ headers.removeHeader("content-length");
+ headers.removeHeader("content-range");
+ headers.removeHeader("trailer");
+ headers.removeHeader("transfer-encoding");
+ }
+
// Build the response header
try {
outputBuffer.sendStatus();
diff --git a/java/org/apache/coyote/http2/StreamProcessor.java
b/java/org/apache/coyote/http2/StreamProcessor.java
index 3afda9037b..acd9dce237 100644
--- a/java/org/apache/coyote/http2/StreamProcessor.java
+++ b/java/org/apache/coyote/http2/StreamProcessor.java
@@ -220,6 +220,12 @@ class StreamProcessor extends AbstractProcessor {
if (statusCode >= 200 && headers.getValue("date") == null) {
headers.addValue("date").setString(FastHttpDateFormat.getCurrentDate());
}
+
+ // Remove payload headers for HEAD requests
+ if (coyoteRequest != null &&
"HEAD".equals(coyoteRequest.method().toString())) {
+ headers.removeHeader("content-length");
+ headers.removeHeader("content-range");
+ }
}
diff --git a/test/jakarta/servlet/http/HttpServletDoHeadBaseTest.java
b/test/jakarta/servlet/http/HttpServletDoHeadBaseTest.java
index 21a962d48d..e513be2430 100644
--- a/test/jakarta/servlet/http/HttpServletDoHeadBaseTest.java
+++ b/test/jakarta/servlet/http/HttpServletDoHeadBaseTest.java
@@ -95,7 +95,15 @@ public class HttpServletDoHeadBaseTest extends Http2TestBase
{
rc = headUrl(path, out, headHeaders);
Assert.assertEquals(HttpServletResponse.SC_OK, rc);
- // Headers should be the same (apart from Date)
+ // Headers should be the same part from:
+ // - Date header may be different
+ // - HEAD requests don't include payload headers
+ // (RFC 7231, section 4.3.2)
+ getHeaders.remove("content-length");
+ getHeaders.remove("content-range");
+ getHeaders.remove("trailer");
+ getHeaders.remove("transfer-encoding");
+
Assert.assertEquals(getHeaders.size(), headHeaders.size());
for (Map.Entry<String, List<String>> getHeader :
getHeaders.entrySet()) {
String headerName = getHeader.getKey();
@@ -158,15 +166,22 @@ public class HttpServletDoHeadBaseTest extends
Http2TestBase {
String[] headHeaders = traceHead.split("\n");
int i = 0;
+ int j = 0;
for (; i < getHeaders.length; i++) {
- // Headers should be the same, ignoring the first character
which is the steam ID
- Assert.assertEquals(getHeaders[i] + "\n" + traceGet +
traceHead, '3', getHeaders[i].charAt(0));
- Assert.assertEquals(headHeaders[i] + "\n" + traceGet +
traceHead, '5', headHeaders[i].charAt(0));
- Assert.assertEquals(traceGet + traceHead,
getHeaders[i].substring(1), headHeaders[i].substring(1));
+ // Ignore payload headers
+ if (getHeaders[i].contains("content-length") ||
getHeaders[i].contains("content-range") ) {
+ // Skip
+ } else {
+ // Headers should be the same, ignoring the first
character which is the steam ID
+ Assert.assertEquals(getHeaders[i] + "\n" + traceGet +
traceHead, '3', getHeaders[i].charAt(0));
+ Assert.assertEquals(headHeaders[j] + "\n" + traceGet +
traceHead, '5', headHeaders[j].charAt(0));
+ Assert.assertEquals(traceGet + traceHead,
getHeaders[i].substring(1), headHeaders[j].substring(1));
+ j++;
+ }
}
// Stream 5 should have one more trace entry
- Assert.assertEquals("5-EndOfStream", headHeaders[i]);
+ Assert.assertEquals("5-EndOfStream", headHeaders[j]);
} catch (Exception t) {
System.out.println(debug.toString());
throw t;
diff --git a/test/jakarta/servlet/http/TestHttpServlet.java
b/test/jakarta/servlet/http/TestHttpServlet.java
index e12bcd54be..077467454e 100644
--- a/test/jakarta/servlet/http/TestHttpServlet.java
+++ b/test/jakarta/servlet/http/TestHttpServlet.java
@@ -45,6 +45,10 @@ import
org.apache.tomcat.util.net.TesterSupport.SimpleServlet;
public class TestHttpServlet extends TomcatBaseTest {
+ /*
+ * Nature of test has changed from original bug report since content-length
+ * is no longer returned for HEAD requests as allowed by RFC 7231.
+ */
@Test
public void testBug53454() throws Exception {
Tomcat tomcat = getTomcatInstance();
@@ -64,8 +68,7 @@ public class TestHttpServlet extends TomcatBaseTest {
resHeaders);
Assert.assertEquals(HttpServletResponse.SC_OK, rc);
- Assert.assertEquals(LargeBodyServlet.RESPONSE_LENGTH,
- resHeaders.get("Content-Length").get(0));
+ Assert.assertNull(resHeaders.get("Content-Length"));
}
@@ -178,6 +181,7 @@ public class TestHttpServlet extends TomcatBaseTest {
int rc = getUrl(path, out, getHeaders);
Assert.assertEquals(HttpServletResponse.SC_OK, rc);
+ removePayloadHeaders(getHeaders);
out.recycle();
Map<String,List<String>> headHeaders = new HashMap<>();
@@ -204,6 +208,18 @@ public class TestHttpServlet extends TomcatBaseTest {
}
+ /*
+ * Removes headers that are not expected to appear in the response to the
+ * equivalent HEAD request.
+ */
+ private void removePayloadHeaders(Map<String,List<String>> headers) {
+ headers.remove("content-length");
+ headers.remove("content-range");
+ headers.remove("trailer");
+ headers.remove("transfer-encoding");
+ }
+
+
@Test
public void testDoOptions() throws Exception {
doTestDoOptions(new OptionsServlet(), "GET, HEAD, OPTIONS");
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 7570715faa..9fd2f679a3 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -125,6 +125,10 @@
Implement the new Servlet API methods for setting character encodings
that accept {@code Charset} objects. (markt)
</add>
+ <update>
+ The default HEAD response no longer includes the payload HTTP header
+ fields as per section 9.3.2 of RFC 9110. (markt)
+ </update>
</changelog>
</subsection>
<subsection name="Coyote">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]