diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/ActiveMQStompException.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/ActiveMQStompException.java index 118f7f8db5..f4f23e632f 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/ActiveMQStompException.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/ActiveMQStompException.java @@ -25,6 +25,7 @@ public class ActiveMQStompException extends Exception { public static final int NONE = 0; public static final int INVALID_EOL_V10 = 1; public static final int INVALID_COMMAND = 2; + public static final int UNDEFINED_ESCAPE = 3; private static final long serialVersionUID = -274452327574950068L; diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/ActiveMQStompProtocolMessageBundle.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/ActiveMQStompProtocolMessageBundle.java index e535725407..8108f32ad7 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/ActiveMQStompProtocolMessageBundle.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/ActiveMQStompProtocolMessageBundle.java @@ -150,4 +150,7 @@ public interface ActiveMQStompProtocolMessageBundle { @Message(id = 339039, value = "No id header in ACK/NACK frame.") ActiveMQStompException noIDInAck(); + + @Message(id = 339040, value = "Undefined escape sequence: {0}", format = Message.Format.MESSAGE_FORMAT) + ActiveMQStompException undefinedEscapeSequence(String sequence); } diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java index a6ddf68f0b..6dcff64e70 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/StompConnection.java @@ -121,6 +121,7 @@ public final class StompConnection implements RemotingConnection { frame = decode(buffer); break; case ActiveMQStompException.INVALID_COMMAND: + case ActiveMQStompException.UNDEFINED_ESCAPE: frameHandler.onError(e); break; default: diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java index c4a9a61dc7..867cdd8d97 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v11/StompFrameHandlerV11.java @@ -558,6 +558,12 @@ public class StompFrameHandlerV11 extends VersionedStompFrameHandler implements } } + protected void throwUndefinedEscape(byte b) throws ActiveMQStompException { + ActiveMQStompException error = BUNDLE.undefinedEscapeSequence(new String(new char[]{ESC_CHAR, (char) b})).setHandler(handler); + error.setCode(ActiveMQStompException.UNDEFINED_ESCAPE); + throw error; + } + @Override protected boolean parseHeaders() throws ActiveMQStompException { @@ -645,6 +651,9 @@ public class StompFrameHandlerV11 extends VersionedStompFrameHandler implements headerValueWhitespace = false; + if (isEscaping) { + throwUndefinedEscape(b); + } holder.append(b); } } diff --git a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v12/StompFrameHandlerV12.java b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v12/StompFrameHandlerV12.java index 2149721ee4..6b211d291c 100644 --- a/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v12/StompFrameHandlerV12.java +++ b/artemis-protocols/artemis-stomp-protocol/src/main/java/org/apache/activemq/artemis/core/protocol/stomp/v12/StompFrameHandlerV12.java @@ -230,6 +230,9 @@ public class StompFrameHandlerV12 extends StompFrameHandlerV11 { headerValueWhitespace = false; + if (isEscaping) { + throwUndefinedEscape(b); + } holder.append(b); } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/v11/StompV11Test.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/v11/StompV11Test.java index 4d42a34c8b..2bd15a1af4 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/v11/StompV11Test.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/v11/StompV11Test.java @@ -389,6 +389,39 @@ public class StompV11Test extends StompV11TestBase { newConn.disconnect(); } + /** + * In 1.1, undefined escapes must cause a fatal protocol error. + */ + @Test + public void testHeaderUndefinedEscape() throws Exception { + connV11.connect(defUser, defPass); + ClientStompFrame frame = connV11.createFrame("SEND"); + + String body = "Hello World 1!"; + String cLen = String.valueOf(body.getBytes(StandardCharsets.UTF_8).length); + + frame.addHeader("destination", getQueuePrefix() + getQueueName()); + frame.addHeader("content-type", "text/plain"); + frame.addHeader("content-length", cLen); + String hKey = "undefined-escape"; + String hVal = "is\\ttab"; + frame.addHeader(hKey, hVal); + + System.out.println("key: |" + hKey + "| val: |" + hVal + "|"); + + frame.setBody(body); + + connV11.sendFrame(frame); + + ClientStompFrame error = connV11.receiveFrame(); + + System.out.println("received " + error); + + String desc = "Should have received an ERROR for undefined escape sequence"; + Assert.assertNotNull(desc, error); + Assert.assertEquals(desc, "ERROR", error.getCommand()); + } + @Test public void testHeartBeat() throws Exception { //no heart beat at all if heat-beat absent diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/v12/StompV12Test.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/v12/StompV12Test.java index c075da5079..d3ef89ac02 100644 --- a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/v12/StompV12Test.java +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/stomp/v12/StompV12Test.java @@ -564,6 +564,42 @@ public class StompV12Test extends StompV11TestBase { newConn.disconnect(); } + /** + * In 1.2, undefined escapes must cause a fatal protocol error. + */ + @Test + public void testHeaderUndefinedEscape() throws Exception { + connV12.connect(defUser, defPass); + ClientStompFrame frame = connV12.createFrame("SEND"); + + String body = "Hello World 1!"; + String cLen = String.valueOf(body.getBytes(StandardCharsets.UTF_8).length); + + frame.addHeader("destination", getQueuePrefix() + getQueueName()); + frame.addHeader("content-type", "text/plain"); + frame.addHeader("content-length", cLen); + String hKey = "undefined-escape"; + String hVal = "is\\ttab"; + frame.addHeader(hKey, hVal); + + System.out.println("key: |" + hKey + "| val: |" + hVal + "|"); + + frame.setBody(body); + + connV12.sendFrame(frame); + + ClientStompFrame error = connV12.receiveFrame(); + + System.out.println("received " + error); + + String desc = "Should have received an ERROR for undefined escape sequence"; + Assert.assertNotNull(desc, error); + Assert.assertEquals(desc, "ERROR", error.getCommand()); + + waitDisconnect(connV12); + Assert.assertFalse("Should be disconnected in STOMP 1.2 after ERROR", connV12.isConnected()); + } + @Test public void testHeartBeat() throws Exception { StompClientConnection conn = StompClientConnectionFactory.createClientConnection("1.2", hostname, port);