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/17 15:50:32 UTC
(tomcat) 13/17: Reject @OnMessage methods with a primitive payload and boolean last flag
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 6e6f2fbd8dfbe5f7243a1fcf9415d3854196b902
Author: opencode <re...@apache.org>
AuthorDate: Sat Oct 17 13:50:48 2026 +0200
Reject @OnMessage methods with a primitive payload and boolean last flag
Partial message delivery is only defined for String, byte[] and
ByteBuffer payloads, optionally with a boolean last flag. Tomcat
already rejects Reader, InputStream, PongMessage and decoded object
payloads combined with a boolean last flag at deployment time but did
not reject the same combination for a primitive (or boxed primitive)
payload parameter.
For a method like void onMessage(int payload, boolean last) the method
mapping was accepted, handler creation then fell through to the partial
ByteBuffer branch and constructed PojoMessageHandlerPartialBinary with
an index of -1. The first fragmented binary message caused
parameters[indexPayload] = message in
PojoMessageHandlerPartialBase.onMessage() to throw an
ArrayIndexOutOfBoundsException outside the try/catch, which WsFrameBase
handled as an unexpected error, invoking onError() and closing the
session abnormally (1006). Any client connecting to such an endpoint
could trigger this with a single fragmented binary message.
Reject the parameter combination at deployment time instead, matching
the existing partial parameter validation, with a new
pojoMethodMapping.partialPrimitive message. This also removes the last
route by which the partial message handler creation could be reached
without a valid payload index.
Add a regression test asserting the DeploymentException is raised for
this signature.
---
.../tomcat/websocket/pojo/LocalStrings.properties | 1 +
.../tomcat/websocket/pojo/PojoMethodMapping.java | 5 ++++
.../websocket/pojo/TestPojoMethodMapping.java | 27 ++++++++++++++++++++++
3 files changed, 33 insertions(+)
diff --git a/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties b/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties
index bca0d92d52..ff644045cc 100644
--- a/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties
+++ b/java/org/apache/tomcat/websocket/pojo/LocalStrings.properties
@@ -42,6 +42,7 @@ pojoMethodMapping.paramWithoutAnnotation=A parameter of type [{0}] was found on
pojoMethodMapping.partialInputStream=Invalid InputStream and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage
pojoMethodMapping.partialObject=Invalid Object and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage
pojoMethodMapping.partialPong=Invalid PongMessage and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage
+pojoMethodMapping.partialPrimitive=Invalid primitive type and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage
pojoMethodMapping.partialReader=Invalid Reader and boolean parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage
pojoMethodMapping.pongWithPayload=Invalid PongMessage and Message parameters present on the method [{0}] of class [{1}] that was annotated with OnMessage
diff --git a/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java b/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java
index 9f4defaed3..cb33282475 100644
--- a/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java
+++ b/java/org/apache/tomcat/websocket/pojo/PojoMethodMapping.java
@@ -607,6 +607,11 @@ public class PojoMethodMapping {
throw new DeploymentException(sm.getString("pojoMethodMapping.partialInputStream", m.getName(),
m.getDeclaringClass().getName()));
}
+ if (indexPrimitive != -1 && indexBoolean != -1) {
+ throw new DeploymentException(
+ sm.getString("pojoMethodMapping.partialPrimitive", m.getName(),
+ m.getDeclaringClass().getName()));
+ }
if (decoderMatch != null && decoderMatch.hasMatches() && indexBoolean != -1) {
throw new DeploymentException(
sm.getString("pojoMethodMapping.partialObject", m.getName(), m.getDeclaringClass().getName()));
diff --git a/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java b/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java
index 623da81eb1..b188597d8b 100644
--- a/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java
+++ b/test/org/apache/tomcat/websocket/pojo/TestPojoMethodMapping.java
@@ -21,6 +21,7 @@ import java.util.ArrayList;
import java.util.List;
import jakarta.websocket.ContainerProvider;
+import jakarta.websocket.DeploymentException;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
@@ -96,6 +97,32 @@ public class TestPojoMethodMapping extends TomcatBaseTest {
}
+ /*
+ * Only String, byte[] and ByteBuffer payloads (plus the boolean last flag) are permitted for partial messages. A
+ * primitive payload combined with a boolean last flag must be rejected at deployment time rather than resulting in
+ * a partial message handler that fails when the first fragmented message arrives.
+ */
+ @Test
+ public void testPrimitiveAndBooleanParameters() throws Exception {
+ try {
+ new PojoMethodMapping(PrimitiveAndBooleanServer.class, new ArrayList<>(), "/primitiveAndBoolean", null);
+ Assert.fail("Expected a DeploymentException");
+ } catch (DeploymentException de) {
+ Assert.assertTrue("Unexpected message: " + de.getMessage(), de.getMessage().contains("primitive type"));
+ }
+ }
+
+
+ @ServerEndpoint("/primitiveAndBoolean")
+ public static final class PrimitiveAndBooleanServer {
+
+ @OnMessage
+ public void onMessage(@SuppressWarnings("unused") int payload, @SuppressWarnings("unused") boolean last) {
+ // No-Op
+ }
+ }
+
+
@ServerEndpoint(value = "/{one}/{two}/{three}", configurator = SingletonConfigurator.class)
public static final class Server {
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org