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 3bcf5f2be743d030e08cdaa22155f9397865a252
Author: opencode <[email protected]>
AuthorDate: Sat Oct 17 11:38:36 2026 +0200

    Validate the WebSocket maximum message buffer size
    
    The session setters setMaxBinaryMessageBufferSize() /
    setMaxTextMessageBufferSize() and the container default setters
    setDefaultMaxBinaryMessageBufferSize() /
    setDefaultMaxTextMessageBufferSize() accepted any int without
    validation.
    
    With a zero size and a MessageHandler.Partial registered, the frame
    receiver enters an unbounded busy loop: the terminal transformation
    always reports OVERFLOW because the destination buffer has no room, so
    the application handler is invoked repeatedly with empty buffers and
    the frame payload is never consumed. A negative size results in a
    NegativeArraySizeException when the message buffer is allocated.
    
    Reject values below one with an IllegalArgumentException in the four
    setters. Since the session initializes its sizes from the container
    defaults and the server context init parameters are applied through the
    container setters, this covers all configuration paths. Add a
    regression test covering the container and session setters.
---
 .../tomcat/websocket/LocalStrings.properties       |  2 +
 java/org/apache/tomcat/websocket/WsSession.java    |  6 +++
 .../tomcat/websocket/WsWebSocketContainer.java     |  8 ++++
 .../tomcat/websocket/TestWsWebSocketContainer.java | 47 ++++++++++++++++++++++
 4 files changed, 63 insertions(+)

diff --git a/java/org/apache/tomcat/websocket/LocalStrings.properties 
b/java/org/apache/tomcat/websocket/LocalStrings.properties
index ca80062af0..5536b82290 100644
--- a/java/org/apache/tomcat/websocket/LocalStrings.properties
+++ b/java/org/apache/tomcat/websocket/LocalStrings.properties
@@ -132,6 +132,7 @@ wsSession.duplicateHandlerBinary=A binary message handler 
has already been confi
 wsSession.duplicateHandlerPong=A pong message handler has already been 
configured
 wsSession.duplicateHandlerText=A text message handler has already been 
configured
 wsSession.flushFailOnClose=Failed to flush batched messages on session close
+wsSession.illegalBufferSize=Invalid maximum message buffer size [{0}]. The 
value must be greater than zero.
 wsSession.instanceCreateFailed=Endpoint instance creation failed
 wsSession.instanceNew=Endpoint instance registration failed
 wsSession.invalidHandlerTypePong=A pong message handler must implement 
MessageHandler.Whole
@@ -155,6 +156,7 @@ wsWebSocketContainer.connect.write=Writing the HTTP upgrade 
request from buffer
 wsWebSocketContainer.defaultConfiguratorFail=Failed to create the default 
configurator
 wsWebSocketContainer.failedAuthentication=Failed to handle HTTP response code 
[{0}]. [{1}] header was not accepted by server.
 wsWebSocketContainer.httpRequestFailed=The HTTP request to initiate the 
WebSocket connection to [{0}] failed
+wsWebSocketContainer.illegalBufferSize=Invalid default maximum message buffer 
size [{0}]. The value must be greater than zero.
 wsWebSocketContainer.invalidExtensionsHeader=The server sent an invalid 
extension header
 wsWebSocketContainer.invalidExtensionParameters=The server responded with 
extension parameters the client is unable to support
 wsWebSocketContainer.invalidHeader=Unable to parse HTTP header as no colon is 
present to delimit header name and header value in [{0}]. The header has been 
skipped.
diff --git a/java/org/apache/tomcat/websocket/WsSession.java 
b/java/org/apache/tomcat/websocket/WsSession.java
index c8690ad44a..9f3ed1c01a 100644
--- a/java/org/apache/tomcat/websocket/WsSession.java
+++ b/java/org/apache/tomcat/websocket/WsSession.java
@@ -495,6 +495,9 @@ public class WsSession implements Session {
     @Override
     public void setMaxBinaryMessageBufferSize(int max) {
         checkState();
+        if (max < 1) {
+            throw new 
IllegalArgumentException(sm.getString("wsSession.illegalBufferSize", 
Integer.valueOf(max)));
+        }
         this.maxBinaryMessageBufferSize = max;
     }
 
@@ -509,6 +512,9 @@ public class WsSession implements Session {
     @Override
     public void setMaxTextMessageBufferSize(int max) {
         checkState();
+        if (max < 1) {
+            throw new 
IllegalArgumentException(sm.getString("wsSession.illegalBufferSize", 
Integer.valueOf(max)));
+        }
         this.maxTextMessageBufferSize = max;
     }
 
diff --git a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java 
b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
index 212451fe4e..cda0f24783 100644
--- a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
+++ b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java
@@ -1022,6 +1022,10 @@ public class WsWebSocketContainer implements 
WebSocketContainer, BackgroundProce
 
     @Override
     public void setDefaultMaxBinaryMessageBufferSize(int max) {
+        if (max < 1) {
+            throw new IllegalArgumentException(
+                    sm.getString("wsWebSocketContainer.illegalBufferSize", 
Integer.valueOf(max)));
+        }
         maxBinaryMessageBufferSize = max;
     }
 
@@ -1034,6 +1038,10 @@ public class WsWebSocketContainer implements 
WebSocketContainer, BackgroundProce
 
     @Override
     public void setDefaultMaxTextMessageBufferSize(int max) {
+        if (max < 1) {
+            throw new IllegalArgumentException(
+                    sm.getString("wsWebSocketContainer.illegalBufferSize", 
Integer.valueOf(max)));
+        }
         maxTextMessageBufferSize = max;
     }
 
diff --git a/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java 
b/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java
index 21e332596f..ce42d64a85 100644
--- a/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java
+++ b/test/org/apache/tomcat/websocket/TestWsWebSocketContainer.java
@@ -25,6 +25,7 @@ import java.util.Queue;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
+import java.util.function.IntConsumer;
 
 import jakarta.servlet.ServletContextEvent;
 import jakarta.websocket.ClientEndpointConfig;
@@ -106,6 +107,52 @@ public class TestWsWebSocketContainer extends 
WsWebSocketContainerBaseTest {
     }
 
 
+    @Test
+    public void testMaxMessageBufferSizeValidation() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        // No file system docBase required
+        Context ctx = getProgrammaticRootContext();
+        ctx.addApplicationListener(TesterEchoServer.Config.class.getName());
+        Tomcat.addServlet(ctx, "default", new DefaultServlet());
+        ctx.addServletMapping("/", "default");
+
+        tomcat.start();
+
+        WsWebSocketContainer wsContainer = new WsWebSocketContainer();
+
+        
doTestIllegalBufferSize(wsContainer::setDefaultMaxBinaryMessageBufferSize);
+        
doTestIllegalBufferSize(wsContainer::setDefaultMaxTextMessageBufferSize);
+
+        Session wsSession = 
wsContainer.connectToServer(TesterProgrammaticEndpoint.class,
+                ClientEndpointConfig.Builder.create().build(),
+                new URI("ws://" + getHostName() + ":" + getPort() + 
TesterEchoServer.Config.PATH_ASYNC));
+
+        doTestIllegalBufferSize(wsSession::setMaxBinaryMessageBufferSize);
+        doTestIllegalBufferSize(wsSession::setMaxTextMessageBufferSize);
+
+        // Positive values remain valid
+        wsSession.setMaxBinaryMessageBufferSize(1);
+        Assert.assertEquals(1, wsSession.getMaxBinaryMessageBufferSize());
+        wsSession.setMaxTextMessageBufferSize(1);
+        Assert.assertEquals(1, wsSession.getMaxTextMessageBufferSize());
+
+        wsSession.close();
+        wsContainer.destroy();
+    }
+
+
+    private static void doTestIllegalBufferSize(IntConsumer setter) {
+        for (int size : new int[] { 0, -1 }) {
+            try {
+                setter.accept(size);
+                Assert.fail("No exception thrown for buffer size [" + size + 
"]");
+            } catch (IllegalArgumentException iae) {
+                // Expected
+            }
+        }
+    }
+
+
     @Test(expected = DeploymentException.class)
     public void testConnectToServerEndpointInvalidScheme() throws Exception {
         Tomcat tomcat = getTomcatInstance();


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to