You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2026/10/14 20:27:00 UTC
(tomcat) 08/11: Replace obs-fold with a single SP when parsing headers
This is an automated email from the ASF dual-hosted git repository.
rmaucher pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit f301588994cf48bc1dcc32e137ca7ca21ca68ed4
Author: opencode <re...@apache.org>
AuthorDate: Wed Oct 14 19:15:09 2026 +0200
Replace obs-fold with a single SP when parsing headers
The header parser's line folding (obs-fold) handling peeked the first
byte of the continuation line and copied that raw byte into the
compacted header value. Since an obs-fold may start with HTAB, a TAB
could end up in the value, e.g. a header sent as "X: abcd CRLF TAB
efgh" was stored as "abcd\tefgh".
RFC 9112 section 5.2 requires a server that receives an obs-fold to
either reject the message or replace each obs-fold with one or more SP
octets. The parser now always inserts a single space at the fold point
instead of copying the peeked byte. Whitespace beyond the first byte of
the continuation line was and is skipped by the value-start state, so
the stored value for the HTAB case changes from a TAB to a space while
the SP case is unchanged. This also removes a divergence between what
Tomcat sees and what a spec-compliant intermediary would forward for
the same message.
The existing test for folded headers (bz 48839) asserted the legacy
behaviour with a tab in the value and was updated to expect the single
space mandated by the specification. A new test pins the SP
continuation case.
---
.../tomcat/util/http/parser/HttpHeaderParser.java | 7 ++-
.../coyote/http11/TestHttp11InputBuffer.java | 69 +++++++++++++++++++++-
2 files changed, 72 insertions(+), 4 deletions(-)
diff --git a/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java b/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java
index 2e7be33c3e..0eb653909b 100644
--- a/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java
+++ b/java/org/apache/tomcat/util/http/parser/HttpHeaderParser.java
@@ -255,9 +255,10 @@ public class HttpHeaderParser {
headerParsePos = HeaderParsePosition.HEADER_START;
break;
} else {
- // Copying one extra space in the buffer (since there must
- // be at least one space inserted between the lines)
- source.getHeaderByteBuffer().put(headerData.realPos, peek);
+ // Replace the line folding with a single space as required
+ // by RFC 9112 section 5.2. Any further whitespace at the
+ // start of the continuation line is skipped below.
+ source.getHeaderByteBuffer().put(headerData.realPos, SP);
headerData.realPos++;
headerParsePos = HeaderParsePosition.HEADER_VALUE_START;
}
diff --git a/test/org/apache/coyote/http11/TestHttp11InputBuffer.java b/test/org/apache/coyote/http11/TestHttp11InputBuffer.java
index 6533ba6c1c..0a376424cb 100644
--- a/test/org/apache/coyote/http11/TestHttp11InputBuffer.java
+++ b/test/org/apache/coyote/http11/TestHttp11InputBuffer.java
@@ -103,7 +103,9 @@ public class TestHttp11InputBuffer extends TomcatBaseTest {
if (getResponseBody() == null) {
return false;
}
- if (!getResponseBody().contains("abcd\tefgh")) {
+ // The line folding (CRLF + HTAB) is replaced with a single SP as
+ // required by RFC 9110 section 5.2
+ if (!getResponseBody().contains("abcd efgh")) {
return false;
}
return true;
@@ -133,6 +135,71 @@ public class TestHttp11InputBuffer extends TomcatBaseTest {
}
+ /**
+ * Test case for https://bz.apache.org/bugzilla/show_bug.cgi?id=48839 with a space rather than a tab starting the
+ * continuation line. Both fold forms must result in a single space in the parsed value (RFC 9112 section 5.2).
+ */
+ @Test
+ public void testObsFoldWithSpaceContinuation() {
+
+ ObsFoldClient client = new ObsFoldClient();
+
+ client.doRequest();
+ Assert.assertTrue(client.isResponse200());
+ Assert.assertTrue(client.getResponseBody(), client.getResponseBody().contains("abcd efgh"));
+ }
+
+
+ /**
+ * Obs-fold test client. Uses a SP continuation line.
+ */
+ private class ObsFoldClient extends SimpleHttpClient {
+
+ private Exception doRequest() {
+
+ Tomcat tomcat = getTomcatInstance();
+
+ Context root = tomcat.addContext("", TEMP_DIR);
+ Tomcat.addServlet(root, "ObsFold", new Bug48839Servlet());
+ root.addServletMapping("/test", "ObsFold");
+
+ try {
+ tomcat.start();
+ setPort(tomcat.getConnector().getLocalPort());
+
+ // Open connection
+ connect();
+
+ String[] request = new String[1];
+ // @formatter:off
+ request[0] =
+ "GET http://localhost:8080/test HTTP/1.1" + CRLF +
+ "Host: localhost:8080" + CRLF +
+ "X-Bug48839: abcd" + CRLF +
+ " efgh" + CRLF +
+ "Connection: close" + CRLF +
+ CRLF;
+ // @formatter:on
+
+ setRequest(request);
+ processRequest(); // blocks until response has been read
+
+ // Close the connection
+ disconnect();
+ } catch (Exception e) {
+ return e;
+ }
+ return null;
+ }
+
+ @Override
+ public boolean isResponseBodyOK() {
+ return getResponseBody() != null && getResponseBody().contains("abcd efgh");
+ }
+
+ }
+
+
@Test
public void testBug51557Valid() {
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org