/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.transport.stomp; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Socket; import java.util.Arrays; import java.util.Collection; import javax.net.SocketFactory; import javax.net.ssl.SSLSocketFactory; import org.junit.Assume; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @RunWith(Parameterized.class) public class StompMaxFrameSizeTest extends StompTestSupport { enum TestType {FRAME_MAX_GREATER_THAN_HEADER_MAX, FRAME_MAX_LESS_THAN_HEADER_MAX, FRAME_MAX_LESS_THAN_ACTION_MAX}; // set max data size higher than max frame size so that max frame size gets tested private static final int MAX_DATA_SIZE = 100 * 1024; private final TestType testType; private final int maxFrameSize; /** * This defines the different possible max header sizes for this test. */ @Parameters public static Collection<Object[]> data() { return Arrays.asList(new Object[][] { // The maximum size exceeds the default max header size of 10 * 1024 {TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX, 64 * 1024}, // The maximum size is less than the default max header size of 10 * 1024 {TestType.FRAME_MAX_LESS_THAN_HEADER_MAX, 5 * 1024}, // The maximum size is less than the default max action size of 1024 {TestType.FRAME_MAX_LESS_THAN_ACTION_MAX, 512} }); } public StompMaxFrameSizeTest(TestType testType, int maxFrameSize) { this.testType = testType; this.maxFrameSize = maxFrameSize; } @Override protected boolean isUseSslConnector() { return true; } @Override protected boolean isUseNioConnector() { return true; } @Override protected boolean isUseNioPlusSslConnector() { return true; } @Override protected String getAdditionalConfig() { return "?wireFormat.maxDataLength=" + MAX_DATA_SIZE + "&wireFormat.maxFrameSize=" + maxFrameSize; } /** * These tests should cause a Stomp error because the body size is greater than the * max allowed frame size */ @Test(timeout = 60000) public void testOversizedBodyOnPlainSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doOversizedTestMessage(port, false, maxFrameSize + 100); } @Test(timeout = 60000) public void testOversizedBodyOnNioSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doOversizedTestMessage(nioPort, false, maxFrameSize + 100); } @Test(timeout = 60000) public void testOversizedBodyOnSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doOversizedTestMessage(sslPort, true, maxFrameSize + 100); } @Test(timeout = 60000) public void testOversizedBodyOnNioSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doOversizedTestMessage(nioSslPort, true, maxFrameSize + 100); } /** * These tests should cause a Stomp error because even though the body size is less than max frame size, * the action and headers plus data size should cause a max frame size failure */ @Test(timeout = 60000) public void testOversizedTotalFrameOnPlainSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doOversizedTestMessage(port, false, maxFrameSize - 50); } @Test(timeout = 60000) public void testOversizedTotalFrameOnNioSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doOversizedTestMessage(nioPort, false, maxFrameSize - 50); } @Test(timeout = 60000) public void testOversizedTotalFrameOnSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doOversizedTestMessage(sslPort, true, maxFrameSize - 50); } @Test(timeout = 60000) public void testOversizedTotalFrameOnNioSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doOversizedTestMessage(nioSslPort, true, maxFrameSize - 50); } /** * These tests will test a successful Stomp message when the total size is than max frame size */ @Test(timeout = 60000) public void testUndersizedTotalFrameOnPlainSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doUndersizedTestMessage(port, false); } @Test(timeout = 60000) public void testUndersizedTotalFrameOnNioSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doUndersizedTestMessage(nioPort, false); } @Test(timeout = 60000) public void testUndersizedTotalFrameOnSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doUndersizedTestMessage(sslPort, true); } @Test(timeout = 60000) public void testUndersizedTotalFrameOnNioSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_GREATER_THAN_HEADER_MAX); doUndersizedTestMessage(nioSslPort, true); } /** * These tests test that a Stomp error occurs if the action size exceeds maxFrameSize * when the maxFrameSize length is less than the default max action length */ @Test(timeout = 60000) public void testOversizedActionOnPlainSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_LESS_THAN_ACTION_MAX); doTestOversizedAction(port, false); } @Test(timeout = 60000) public void testOversizedActionOnNioSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_LESS_THAN_ACTION_MAX); doTestOversizedAction(nioPort, false); } @Test(timeout = 60000) public void testOversizedActionOnSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_LESS_THAN_ACTION_MAX); doTestOversizedAction(sslPort, true); } @Test(timeout = 60000) public void testOversizedActionOnNioSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_LESS_THAN_ACTION_MAX); doTestOversizedAction(nioSslPort, true); } /** * These tests will test that a Stomp error occurs if the header size exceeds maxFrameSize * when the maxFrameSize length is less than the default max header length */ @Test(timeout = 60000) public void testOversizedHeadersOnPlainSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_LESS_THAN_HEADER_MAX); doTestOversizedHeaders(port, false); } @Test(timeout = 60000) public void testOversizedHeadersOnNioSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_LESS_THAN_HEADER_MAX); doTestOversizedHeaders(nioPort, false); } @Test(timeout = 60000) public void testOversizedHeadersOnSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_LESS_THAN_HEADER_MAX); doTestOversizedHeaders(sslPort, true); } @Test(timeout = 60000) public void testOversizedHeadersOnNioSslSocket() throws Exception { Assume.assumeTrue(testType == TestType.FRAME_MAX_LESS_THAN_HEADER_MAX); doTestOversizedHeaders(nioSslPort, true); } protected void doTestOversizedAction(int port, boolean useSsl) throws Exception { initializeStomp(port, useSsl); char[] actionArray = new char[maxFrameSize + 100]; Arrays.fill(actionArray, 'A'); String action = new String(actionArray); String frame = action + "\n" + "destination:/queue/" + getQueueName() + "\n\n" + "body" + Stomp.NULL; stompConnection.sendFrame(frame); StompFrame received = stompConnection.receive(500000); assertNotNull(received); assertEquals("ERROR", received.getAction()); assertTrue(received.getBody().contains("maximum frame size")); } protected void doTestOversizedHeaders(int port, boolean useSsl) throws Exception { initializeStomp(port, useSsl); StringBuilder headers = new StringBuilder(maxFrameSize + 100); int i = 0; while (headers.length() < maxFrameSize + 1) { headers.append("key" + i++ + ":value\n"); } String frame = "SEND\n" + headers.toString() + "\n" + "destination:/queue/" + getQueueName() + headers.toString() + "\n\n" + "body" + Stomp.NULL; stompConnection.sendFrame(frame); StompFrame received = stompConnection.receive(5000); assertNotNull(received); assertEquals("ERROR", received.getAction()); assertTrue(received.getBody().contains("maximum frame size")); } protected void doOversizedTestMessage(int port, boolean useSsl, int dataSize) throws Exception { initializeStomp(port, useSsl); int size = dataSize + 100; char[] bigBodyArray = new char[size]; Arrays.fill(bigBodyArray, 'a'); String bigBody = new String(bigBodyArray); String frame = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + bigBody + Stomp.NULL; stompConnection.sendFrame(frame); StompFrame received = stompConnection.receive(5000); assertNotNull(received); assertEquals("ERROR", received.getAction()); assertTrue(received.getBody().contains("maximum frame size")); } protected void doUndersizedTestMessage(int port, boolean useSsl) throws Exception { initializeStomp(port, useSsl); int size = 100; char[] bigBodyArray = new char[size]; Arrays.fill(bigBodyArray, 'a'); String bigBody = new String(bigBodyArray); String frame = "SEND\n" + "destination:/queue/" + getQueueName() + "\n\n" + bigBody + Stomp.NULL; stompConnection.sendFrame(frame); StompFrame received = stompConnection.receive(); assertNotNull(received); assertEquals("MESSAGE", received.getAction()); assertEquals(bigBody, received.getBody()); } protected StompConnection stompConnect(int port, boolean ssl) throws Exception { if (stompConnection == null) { stompConnection = new StompConnection(); } Socket socket = null; if (ssl) { socket = createSslSocket(port); } else { socket = createSocket(port); } stompConnection.open(socket); return stompConnection; } protected void initializeStomp(int port, boolean useSsl) throws Exception{ stompConnect(port, useSsl); String frame = "CONNECT\n" + "login:system\n" + "passcode:manager\n\n" + Stomp.NULL; stompConnection.sendFrame(frame); frame = stompConnection.receiveFrame(); assertTrue(frame.startsWith("CONNECTED")); frame = "SUBSCRIBE\n" + "destination:/queue/" + getQueueName() + "\n" + "ack:auto\n\n" + Stomp.NULL; stompConnection.sendFrame(frame); } protected Socket createSocket(int port) throws IOException { return new Socket("127.0.0.1", port); } protected Socket createSslSocket(int port) throws IOException { SocketFactory factory = SSLSocketFactory.getDefault(); return factory.createSocket("127.0.0.1", port); } }