This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit f31d971ad48de742f6a4876704f47f2c5e70756c 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 6cfbc6934d..91fea99600 100644 --- a/java/org/apache/tomcat/websocket/LocalStrings.properties +++ b/java/org/apache/tomcat/websocket/LocalStrings.properties @@ -123,6 +123,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 @@ -143,6 +144,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.invalidExtensionParameters=The server responded with extension parameters the client is unable to support wsWebSocketContainer.invalidExtensionsHeader=The server sent an invalid extension header 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 46150e19bf..badef72406 100644 --- a/java/org/apache/tomcat/websocket/WsSession.java +++ b/java/org/apache/tomcat/websocket/WsSession.java @@ -589,6 +589,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; } @@ -603,6 +606,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 eedc77a7d4..842c8aa1cc 100644 --- a/java/org/apache/tomcat/websocket/WsWebSocketContainer.java +++ b/java/org/apache/tomcat/websocket/WsWebSocketContainer.java @@ -1040,6 +1040,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; } @@ -1052,6 +1056,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 1b57ce8fb3..8593fa55b2 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 javax.servlet.ServletContextEvent; import javax.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]
