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 d5cf2c9723 Decline permessage-deflate offers with invalid parameter
values (#1110)
d5cf2c9723 is described below
commit d5cf2c9723e48982b58868a6622ac37baef37e8d
Author: Arturo Bernal <[email protected]>
AuthorDate: Wed Nov 4 20:08:36 2026 +0100
Decline permessage-deflate offers with invalid parameter values (#1110)
RFC 7692, section 7.1 requires an offer that contains a parameter with
an invalid value to be declined. The no_context_takeover parameters have
no value, but a value was ignored, and the max_window_bits parameters
are integers without leading zeroes, but values such as "+15" or "015"
were accepted. Decline the offer in these cases.
---
.../tomcat/websocket/LocalStrings.properties | 1 +
.../apache/tomcat/websocket/PerMessageDeflate.java | 31 ++++++++++++++++--
.../tomcat/websocket/TestPerMessageDeflate.java | 38 ++++++++++++++++++++++
3 files changed, 68 insertions(+), 2 deletions(-)
diff --git a/java/org/apache/tomcat/websocket/LocalStrings.properties
b/java/org/apache/tomcat/websocket/LocalStrings.properties
index 3a862bdaa5..fd12229b4e 100644
--- a/java/org/apache/tomcat/websocket/LocalStrings.properties
+++ b/java/org/apache/tomcat/websocket/LocalStrings.properties
@@ -55,6 +55,7 @@ futureToSendHandler.timeout=Operation timed out after waiting
[{0}] [{1}] to com
perMessageDeflate.alreadyClosed=The transformer has been closed and may no
longer be used
perMessageDeflate.deflateFailed=Failed to decompress a compressed WebSocket
frame
perMessageDeflate.duplicateParameter=Duplicate definition of the [{0}]
extension parameter
+perMessageDeflate.invalidParameterValue=The [{0}] extension parameter has an
invalid value [{1}]
perMessageDeflate.invalidState=Invalid state
perMessageDeflate.invalidWindowSize=An invalid window size of [{1}] was
specified for [{0}]. Valid values are whole numbers from 8 to 15 inclusive.
perMessageDeflate.next.ise=The next transformation of type [{0}] returned
unexpected result
diff --git a/java/org/apache/tomcat/websocket/PerMessageDeflate.java
b/java/org/apache/tomcat/websocket/PerMessageDeflate.java
index 1c74e1919a..1d71f6860d 100644
--- a/java/org/apache/tomcat/websocket/PerMessageDeflate.java
+++ b/java/org/apache/tomcat/websocket/PerMessageDeflate.java
@@ -122,6 +122,7 @@ public class PerMessageDeflate implements Transformation {
try {
for (Parameter param : preference) {
if (SERVER_NO_CONTEXT_TAKEOVER.equals(param.getName())) {
+ checkNoValue(param);
if (serverContextTakeover) {
serverContextTakeover = false;
} else {
@@ -130,6 +131,7 @@ public class PerMessageDeflate implements Transformation {
sm.getString("perMessageDeflate.duplicateParameter",
SERVER_NO_CONTEXT_TAKEOVER));
}
} else if
(CLIENT_NO_CONTEXT_TAKEOVER.equals(param.getName())) {
+ checkNoValue(param);
if (clientContextTakeover) {
clientContextTakeover = false;
} else {
@@ -139,7 +141,7 @@ public class PerMessageDeflate implements Transformation {
}
} else if (SERVER_MAX_WINDOW_BITS.equals(param.getName()))
{
if (serverMaxWindowBits == -1) {
- serverMaxWindowBits =
Integer.parseInt(param.getValue());
+ serverMaxWindowBits = parseWindowBits(param);
if (serverMaxWindowBits < 8 || serverMaxWindowBits
> 15) {
throw new
IllegalArgumentException(sm.getString("perMessageDeflate.invalidWindowSize",
SERVER_MAX_WINDOW_BITS,
Integer.valueOf(serverMaxWindowBits)));
@@ -169,7 +171,7 @@ public class PerMessageDeflate implements Transformation {
// effectively hard-coded to 15
clientMaxWindowBits = 15;
} else {
- clientMaxWindowBits =
Integer.parseInt(param.getValue());
+ clientMaxWindowBits = parseWindowBits(param);
if (clientMaxWindowBits < 8 ||
clientMaxWindowBits > 15) {
throw new IllegalArgumentException(
sm.getString("perMessageDeflate.invalidWindowSize", CLIENT_MAX_WINDOW_BITS,
@@ -215,6 +217,31 @@ public class PerMessageDeflate implements Transformation {
}
+ /*
+ * RFC 7692, section 7.1.1: the no_context_takeover parameters have no
value.
+ */
+ private static void checkNoValue(Parameter param) {
+ if (param.getValue() != null) {
+ throw new IllegalArgumentException(
+ sm.getString("perMessageDeflate.invalidParameterValue",
param.getName(), param.getValue()));
+ }
+ }
+
+
+ /*
+ * RFC 7692, section 7.1.2: the value is a decimal integer without leading
zeroes (1*DIGIT).
+ */
+ private static int parseWindowBits(Parameter param) {
+ String value = param.getValue();
+ if (value == null || value.isEmpty() || value.charAt(0) == '0' ||
+ !value.chars().allMatch(c -> c >= '0' && c <= '9')) {
+ throw new IllegalArgumentException(
+ sm.getString("perMessageDeflate.invalidParameterValue",
param.getName(), value));
+ }
+ return Integer.parseInt(value);
+ }
+
+
private PerMessageDeflate(boolean serverContextTakeover, int
serverMaxWindowBits, boolean clientContextTakeover,
int clientMaxWindowBits, boolean isServer) {
this.serverContextTakeover = serverContextTakeover;
diff --git a/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
b/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
index 893905b760..16c440c6fe 100644
--- a/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
+++ b/test/org/apache/tomcat/websocket/TestPerMessageDeflate.java
@@ -781,6 +781,44 @@ public class TestPerMessageDeflate {
}
+ /*
+ * RFC 7692 section 7.1: the no_context_takeover parameters have no value
and the max_window_bits parameters have a
+ * decimal integer value without leading zeroes (1*DIGIT). Section 7.1
requires an offer that contains a parameter
+ * with an invalid value to be declined. The values used for the window
bits are all 15, which is accepted when it
+ * is written as specified, so the offer is only declined because of how
the value is written.
+ */
+ @Test
+ public void testInvalidParameterValueDeclinesOffer() {
+ assertDeclined("server_no_context_takeover", "1");
+ assertDeclined("client_no_context_takeover", "1");
+ assertDeclined("server_max_window_bits", "015");
+ assertDeclined("server_max_window_bits", "+15");
+ assertDeclined("client_max_window_bits", "015");
+ assertDeclined("client_max_window_bits", "+15");
+ assertDeclined("client_max_window_bits", "");
+ }
+
+
+ @Test
+ public void testValidParameterValueAcceptsOffer() {
+ assertAccepted("server_no_context_takeover", null);
+ assertAccepted("client_no_context_takeover", null);
+ assertAccepted("server_max_window_bits", "15");
+ assertAccepted("client_max_window_bits", "15");
+ assertAccepted("client_max_window_bits", null);
+ }
+
+
+ private static void assertAccepted(String name, String value) {
+ List<Parameter> parameters = new ArrayList<>();
+ parameters.add(new WsExtensionParameter(name, value));
+ List<List<Parameter>> preferences = new ArrayList<>();
+ preferences.add(parameters);
+
+ Assert.assertNotNull(name + "=" + value,
PerMessageDeflate.build(preferences, true));
+ }
+
+
private static void assertDeclined(String name, String value) {
List<Parameter> parameters = new ArrayList<>();
parameters.add(new WsExtensionParameter(name, value));
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]