From da14aeea7adf85485d5586d0d5bc08196a31231a Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 7 Oct 2014 13:35:38 +0200 Subject: [PATCH] TextMessage.toString() does not throw StringIndexOutOfBoundsException for payload with multibyte characters Issue: SPR-12307 --- .../web/socket/AbstractWebSocketMessage.java | 13 ++--- .../web/socket/BinaryMessage.java | 3 +- .../web/socket/PingMessage.java | 5 +- .../web/socket/PongMessage.java | 5 +- .../web/socket/TextMessage.java | 10 ++-- .../web/socket/TextMessageTests.java | 48 +++++++++++++++++++ 6 files changed, 65 insertions(+), 19 deletions(-) create mode 100644 spring-websocket/src/test/java/org/springframework/web/socket/TextMessageTests.java diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/AbstractWebSocketMessage.java b/spring-websocket/src/main/java/org/springframework/web/socket/AbstractWebSocketMessage.java index 23727cd20f1..c4c272b2667 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/AbstractWebSocketMessage.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/AbstractWebSocketMessage.java @@ -69,10 +69,6 @@ public abstract class AbstractWebSocketMessage implements WebSocketMessage return this.last; } - @Override - public int hashCode() { - return AbstractWebSocketMessage.class.hashCode() * 13 + ObjectUtils.nullSafeHashCode(this.payload); - } @Override public boolean equals(Object other) { @@ -86,10 +82,15 @@ public abstract class AbstractWebSocketMessage implements WebSocketMessage return ObjectUtils.nullSafeEquals(this.payload, otherMessage.payload); } + @Override + public int hashCode() { + return ObjectUtils.nullSafeHashCode(this.payload); + } + @Override public String toString() { - return getClass().getSimpleName() + " payload= " + toStringPayload() - + ", byteCount=" + getPayloadLength() + ", last=" + isLast() + "]"; + return getClass().getSimpleName() + " payload=[" + toStringPayload() + + "], byteCount=" + getPayloadLength() + ", last=" + isLast() + "]"; } protected abstract String toStringPayload(); diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/BinaryMessage.java b/spring-websocket/src/main/java/org/springframework/web/socket/BinaryMessage.java index ab7137f8479..b6023503c83 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/BinaryMessage.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/BinaryMessage.java @@ -26,7 +26,6 @@ import java.nio.ByteBuffer; */ public final class BinaryMessage extends AbstractWebSocketMessage { - /** * Create a new binary WebSocket message with the given ByteBuffer payload. * @param payload the non-null payload @@ -78,7 +77,7 @@ public final class BinaryMessage extends AbstractWebSocketMessage { * @param isLast if the message is the last of a series of partial messages */ public BinaryMessage(byte[] payload, int offset, int length, boolean isLast) { - super((payload != null) ? ByteBuffer.wrap(payload, offset, length) : null, isLast); + super(payload != null ? ByteBuffer.wrap(payload, offset, length) : null, isLast); } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/PingMessage.java b/spring-websocket/src/main/java/org/springframework/web/socket/PingMessage.java index a2c9c0bd777..32b57c6b79a 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/PingMessage.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/PingMessage.java @@ -26,7 +26,6 @@ import java.nio.ByteBuffer; */ public final class PingMessage extends AbstractWebSocketMessage { - /** * Create a new ping message with an empty payload. */ @@ -45,12 +44,12 @@ public final class PingMessage extends AbstractWebSocketMessage { @Override public int getPayloadLength() { - return (getPayload() != null) ? getPayload().remaining() : 0; + return (getPayload() != null ? getPayload().remaining() : 0); } @Override protected String toStringPayload() { - return (getPayload() != null) ? getPayload().toString() : null; + return (getPayload() != null ? getPayload().toString() : null); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/PongMessage.java b/spring-websocket/src/main/java/org/springframework/web/socket/PongMessage.java index 5ede3a3cf10..271aafa3dd9 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/PongMessage.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/PongMessage.java @@ -26,7 +26,6 @@ import java.nio.ByteBuffer; */ public final class PongMessage extends AbstractWebSocketMessage { - /** * Create a new pong message with an empty payload. */ @@ -45,12 +44,12 @@ public final class PongMessage extends AbstractWebSocketMessage { @Override public int getPayloadLength() { - return (getPayload() != null) ? getPayload().remaining() : 0; + return (getPayload() != null ? getPayload().remaining() : 0); } @Override protected String toStringPayload() { - return (getPayload() != null) ? getPayload().toString() : null; + return (getPayload() != null ? getPayload().toString() : null); } } diff --git a/spring-websocket/src/main/java/org/springframework/web/socket/TextMessage.java b/spring-websocket/src/main/java/org/springframework/web/socket/TextMessage.java index 7d482a3766b..7586d838515 100644 --- a/spring-websocket/src/main/java/org/springframework/web/socket/TextMessage.java +++ b/spring-websocket/src/main/java/org/springframework/web/socket/TextMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,9 +41,8 @@ public final class TextMessage extends AbstractWebSocketMessage { } /** - * Create a new text WebSocket message from the given byte[]. It is assumed the - * byte array can be encoded into an UTF-8 String. - * + * Create a new text WebSocket message from the given byte[]. It is assumed + * the byte array can be encoded into an UTF-8 String. * @param payload the non-null payload */ public TextMessage(byte[] payload) { @@ -76,7 +75,8 @@ public final class TextMessage extends AbstractWebSocketMessage { @Override protected String toStringPayload() { - return (getPayloadLength() > 10) ? getPayload().substring(0, 10) + ".." : getPayload(); + String payload = getPayload(); + return (payload.length() > 10 ? payload.substring(0, 10) + ".." : payload); } } diff --git a/spring-websocket/src/test/java/org/springframework/web/socket/TextMessageTests.java b/spring-websocket/src/test/java/org/springframework/web/socket/TextMessageTests.java new file mode 100644 index 00000000000..650a2599742 --- /dev/null +++ b/spring-websocket/src/test/java/org/springframework/web/socket/TextMessageTests.java @@ -0,0 +1,48 @@ +/* + * Copyright 2002-2014 the original author or authors. + * + * Licensed 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.springframework.web.socket; + +import org.hamcrest.Matchers; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Test fixture for {@link TextMessage}. + * + * @author Shinobu Aoki + * @author Juergen Hoeller + */ +public class TextMessageTests { + + @Test + public void toStringWithAscii() { + String expected = "foo,bar"; + TextMessage actual = new TextMessage(expected); + assertThat(actual.getPayload(), Matchers.is(expected)); + assertThat(actual.toString(), Matchers.containsString(expected)); + } + + @Test + public void toStringWithMultibyteString() { + String expected = "\u3042\u3044\u3046\u3048\u304a"; + TextMessage actual = new TextMessage(expected); + assertThat(actual.getPayload(), Matchers.is(expected)); + assertThat(actual.toString(), Matchers.containsString(expected)); + } + +}