This is an automated email from the ASF dual-hosted git repository.
markt-asf pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git
The following commit(s) were added to refs/heads/11.0.x by this push:
new 8ba04b0f8a Ignore empty list elements when parsing the Upgrade header
(#1143)
8ba04b0f8a is described below
commit 8ba04b0f8a2d7e5a71ee32b54f336129813f8778
Author: Arturo Bernal <[email protected]>
AuthorDate: Thu Nov 12 18:27:41 2026 +0100
Ignore empty list elements when parsing the Upgrade header (#1143)
RFC 9110, section 5.6.1.2 requires a recipient to parse and ignore empty
list elements, and the Upgrade header is defined as a #protocol list. A
value such as "h2c,, websocket" or one with a leading or trailing comma
was rejected as a whole. Ignore the empty elements.
This also covers the case where the ignored elements are spread across
separate Upgrade header lines, e.g. "Upgrade: websocket" followed by
"Upgrade: ,,". A header line that reduces to nothing once its empty
elements are skipped no longer forces the whole parse to fail; it simply
contributes no protocol. Only when every header line does this, or there
are no Upgrade headers at all, does the existing contract apply: no
headers present yields an empty list, while one or more headers present
that contain no protocol is still invalid and yields null.
---
.../apache/tomcat/util/http/parser/Upgrade.java | 22 ++++++++++++++++++++++
.../tomcat/util/http/parser/TestUpgrade.java | 19 +++++++++++++++++++
webapps/docs/changelog.xml | 4 ++++
3 files changed, 45 insertions(+)
diff --git a/java/org/apache/tomcat/util/http/parser/Upgrade.java
b/java/org/apache/tomcat/util/http/parser/Upgrade.java
index 15d5dee633..65ea343b28 100644
--- a/java/org/apache/tomcat/util/http/parser/Upgrade.java
+++ b/java/org/apache/tomcat/util/http/parser/Upgrade.java
@@ -90,8 +90,10 @@ public class Upgrade {
public static List<Upgrade> parse(Enumeration<String> headerValues) {
try {
List<Upgrade> result = new ArrayList<>();
+ boolean sawHeader = false;
while (headerValues.hasMoreElements()) {
+ sawHeader = true;
String headerValue = headerValues.nextElement();
if (headerValue == null) {
// Invalid
@@ -101,6 +103,17 @@ public class Upgrade {
Reader r = new StringReader(headerValue);
SkipResult skipComma;
do {
+ // Empty list elements must be ignored (RFC 9110, section
5.6.1.2)
+ SkipResult skipEmpty = HttpParser.skipConstant(r, ",");
+ while (skipEmpty == SkipResult.FOUND) {
+ skipEmpty = HttpParser.skipConstant(r, ",");
+ }
+ if (skipEmpty == SkipResult.EOF) {
+ // Nothing left in this header value once any empty
+ // list elements are skipped. This header contributes
+ // no protocols, whether or not earlier headers did.
+ break;
+ }
// Skip any leading whitespace
HttpParser.skipWhitespace(r);
String protocolName = HttpParser.readToken(r);
@@ -129,6 +142,15 @@ public class Upgrade {
} while (skipComma == SkipResult.FOUND);
}
+ if (sawHeader && result.isEmpty()) {
+ // An Upgrade header must name at least one protocol (RFC
+ // 9110, section 7.8). One or more headers that reduce to an
+ // empty list once empty list elements are discarded is
+ // invalid. No Upgrade header at all is not an error; it
+ // yields the empty list below, as before this change.
+ return null;
+ }
+
return result;
} catch (IOException ioe) {
// Should never happen with Strings
diff --git a/test/org/apache/tomcat/util/http/parser/TestUpgrade.java
b/test/org/apache/tomcat/util/http/parser/TestUpgrade.java
index 3910b21a21..33dc24defd 100644
--- a/test/org/apache/tomcat/util/http/parser/TestUpgrade.java
+++ b/test/org/apache/tomcat/util/http/parser/TestUpgrade.java
@@ -31,6 +31,9 @@ import org.junit.runners.Parameterized.Parameter;
@RunWith(Parameterized.class)
public class TestUpgrade {
+ private static final Integer ZERO = Integer.valueOf(0);
+ private static final Integer ONE = Integer.valueOf(1);
+ private static final Integer TWO = Integer.valueOf(2);
private static final Integer FOUR = Integer.valueOf(4);
@Parameterized.Parameters(name = "{index}: headers[{0}]")
@@ -57,9 +60,25 @@ public class TestUpgrade {
// Make final version a non-token
parameterSets.add(new Object[] { Arrays.asList(new String[] {
"HTTP/2.0", "SHTTP/1.3", "IRC/6.9", "RTA/x}11" }), null} );
+ // Empty list elements must be ignored (RFC 9110, section 5.6.1.2)
+ parameterSets.add(new Object[] { Arrays.asList(new String[] {
"HTTP/2.0,, SHTTP/1.3" }), TWO } );
+ parameterSets.add(new Object[] { Arrays.asList(new String[] {
"HTTP/2.0, , SHTTP/1.3" }), TWO } );
+ parameterSets.add(new Object[] { Arrays.asList(new String[] { ",
HTTP/2.0, SHTTP/1.3" }), TWO } );
+ parameterSets.add(new Object[] { Arrays.asList(new String[] {
"HTTP/2.0, SHTTP/1.3," }), TWO } );
+ parameterSets.add(new Object[] { Arrays.asList(new String[] {
"HTTP/2.0, SHTTP/1.3, , " }), TWO } );
+
+ // A separate Upgrade header that reduces to an empty list once empty
+ // list elements are discarded must not invalidate a header that
+ // names a real protocol (RFC 9110, section 5.6.1.2)
+ parameterSets.add(new Object[] { Arrays.asList(new String[] {
"websocket", ",," }), ONE } );
+ parameterSets.add(new Object[] { Arrays.asList(new String[] { ",,",
"websocket" }), ONE } );
+
// Empty header isn't valid
parameterSets.add(new Object[] { Arrays.asList(new String[] { "" }),
null } );
+ // No Upgrade header at all is not an error; it is simply not present
+ parameterSets.add(new Object[] { Collections.<String>emptyList(), ZERO
} );
+
// Nulls shouldn't happen but check they are treated as invalid to be
safe
parameterSets.add(new Object[] { Arrays.asList(new String[] { null }),
null } );
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 3827c443d8..c3621a658d 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -134,6 +134,10 @@
connection error as required by RFC 9113, section 6.9.2. Pull request
<pr>1131</pr> provided by Arturo Bernal. (markt)
</fix>
+ <fix>
+ Ignore empty list elements when parsing the HTTP Upgrade header. Pull
+ request <pr>1143</pr> provided by Arturo Bernal. (markt)
+ </fix>
</changelog>
</subsection>
<subsection name="Jasper">
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]