From c411ff7d43617dea31d1a56e93d6ad3ff05f4685 Mon Sep 17 00:00:00 2001 From: arimu1 <19286898+arimu1@users.noreply.github.com> Date: Sat, 12 Sep 2026 20:21:30 +0700 Subject: [PATCH] fix(draft): cap default maxFrameSize and enforce in checkAlloc Use a 16 MiB default frame payload limit instead of Integer.MAX_VALUE so declared lengths cannot drive multi-gigabyte allocations. Draft_6455 checkAlloc now rejects sizes above maxFrameSize before buffering. Fixes #1507 --- .../org/java_websocket/drafts/Draft_6455.java | 18 +++++++- .../java_websocket/drafts/Draft_6455Test.java | 43 ++++++++++++++++--- 2 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/main/java/org/java_websocket/drafts/Draft_6455.java b/src/main/java/org/java_websocket/drafts/Draft_6455.java index eb4879976..cdacd6427 100644 --- a/src/main/java/org/java_websocket/drafts/Draft_6455.java +++ b/src/main/java/org/java_websocket/drafts/Draft_6455.java @@ -162,6 +162,13 @@ public class Draft_6455 extends Draft { */ private final SecureRandom reuseableRandom = new SecureRandom(); + /** + * Default maximum payload size for a single frame when not explicitly configured (16 MiB). + * + * @since 1.6.1 + */ + public static final int DEFAULT_MAX_FRAME_SIZE = 16 * 1024 * 1024; + /** * Attribute for the maximum allowed size of a frame * @@ -207,7 +214,7 @@ public Draft_6455(List inputExtensions) { * @since 1.3.7 */ public Draft_6455(List inputExtensions, List inputProtocols) { - this(inputExtensions, inputProtocols, Integer.MAX_VALUE); + this(inputExtensions, inputProtocols, DEFAULT_MAX_FRAME_SIZE); } /** @@ -381,6 +388,15 @@ public int getMaxFrameSize() { return maxFrameSize; } + @Override + public int checkAlloc(int bytecount) throws InvalidDataException { + int allowed = super.checkAlloc(bytecount); + if (allowed > maxFrameSize) { + throw new LimitExceededException("Payload limit reached.", maxFrameSize); + } + return allowed; + } + /** * Getter for all available protocols for this draft * diff --git a/src/test/java/org/java_websocket/drafts/Draft_6455Test.java b/src/test/java/org/java_websocket/drafts/Draft_6455Test.java index 41850b32e..e0b759edd 100644 --- a/src/test/java/org/java_websocket/drafts/Draft_6455Test.java +++ b/src/test/java/org/java_websocket/drafts/Draft_6455Test.java @@ -32,6 +32,7 @@ import org.java_websocket.enums.CloseHandshakeType; import org.java_websocket.enums.HandshakeState; import org.java_websocket.exceptions.InvalidHandshakeException; +import org.java_websocket.exceptions.LimitExceededException; import org.java_websocket.extensions.DefaultExtension; import org.java_websocket.extensions.IExtension; import org.java_websocket.framing.BinaryFrame; @@ -123,6 +124,24 @@ public void testGetExtension() throws Exception { assert (draft_6455.getExtension() instanceof DefaultExtension); } + @Test + public void testDefaultMaxFrameSize() { + Draft_6455 draft = new Draft_6455(); + assertEquals(Draft_6455.DEFAULT_MAX_FRAME_SIZE, draft.getMaxFrameSize()); + } + + @Test + public void testDeclaredPayloadLengthAboveDefaultMaxFrameSizeRejected() { + Draft_6455 draft = new Draft_6455(); + long declaredLength = (long) Draft_6455.DEFAULT_MAX_FRAME_SIZE + 1; + ByteBuffer frame = ByteBuffer.allocate(10); + frame.put((byte) 0x81); + frame.put((byte) 127); + frame.putLong(declaredLength); + frame.flip(); + assertThrows(LimitExceededException.class, () -> draft.translateFrame(frame)); + } + @Test public void testGetKnownExtensions() throws Exception { Draft_6455 draft_6455 = new Draft_6455(); @@ -202,24 +221,36 @@ public void testGetCloseHandshakeType() throws Exception { @Test public void testToString() throws Exception { Draft_6455 draft_6455 = new Draft_6455(); - assertEquals("Draft_6455 extension: DefaultExtension max frame size: 2147483647", + assertEquals( + "Draft_6455 extension: DefaultExtension max frame size: " + + Draft_6455.DEFAULT_MAX_FRAME_SIZE, draft_6455.toString()); draft_6455.acceptHandshakeAsServer(handshakedataProtocolExtension); - assertEquals("Draft_6455 extension: DefaultExtension protocol: max frame size: 2147483647", + assertEquals( + "Draft_6455 extension: DefaultExtension protocol: max frame size: " + + Draft_6455.DEFAULT_MAX_FRAME_SIZE, draft_6455.toString()); draft_6455 = new Draft_6455(Collections.emptyList(), Collections.singletonList(new Protocol("chat"))); - assertEquals("Draft_6455 extension: DefaultExtension max frame size: 2147483647", + assertEquals( + "Draft_6455 extension: DefaultExtension max frame size: " + + Draft_6455.DEFAULT_MAX_FRAME_SIZE, draft_6455.toString()); draft_6455.acceptHandshakeAsServer(handshakedataProtocolExtension); - assertEquals("Draft_6455 extension: DefaultExtension protocol: chat max frame size: 2147483647", + assertEquals( + "Draft_6455 extension: DefaultExtension protocol: chat max frame size: " + + Draft_6455.DEFAULT_MAX_FRAME_SIZE, draft_6455.toString()); draft_6455 = new Draft_6455(Collections.singletonList(new TestExtension()), Collections.singletonList(new Protocol("chat"))); - assertEquals("Draft_6455 extension: DefaultExtension max frame size: 2147483647", + assertEquals( + "Draft_6455 extension: DefaultExtension max frame size: " + + Draft_6455.DEFAULT_MAX_FRAME_SIZE, draft_6455.toString()); draft_6455.acceptHandshakeAsServer(handshakedataProtocolExtension); - assertEquals("Draft_6455 extension: TestExtension protocol: chat max frame size: 2147483647", + assertEquals( + "Draft_6455 extension: TestExtension protocol: chat max frame size: " + + Draft_6455.DEFAULT_MAX_FRAME_SIZE, draft_6455.toString()); draft_6455 = new Draft_6455(Collections.emptyList(), Collections.singletonList(new Protocol("chat")), 10);