private ByteBuffer assembleChunksAndReset() { ByteBuffer result; if (this.chunks.size() == 1) { result = this.chunks.remove(); } else { result = ByteBuffer.allocate(getBufferSize()); for (ByteBuffer partial : this.chunks) { result.put(partial); } result.flip(); } this.chunks.clear(); this.expectedContentLength = null; return result; }
public List<Message<byte[]>> decode(WebSocketMessage<?> webSocketMessage) { List<Message<byte[]>> result = Collections.emptyList(); ByteBuffer byteBuffer; if (webSocketMessage instanceof TextMessage) { byteBuffer = ByteBuffer.wrap(((TextMessage) webSocketMessage).asBytes()); } else if (webSocketMessage instanceof BinaryMessage) { byteBuffer = ((BinaryMessage) webSocketMessage).getPayload(); } else { return result; } result = this.bufferingDecoder.decode(byteBuffer); if (result.isEmpty()) { if (logger.isTraceEnabled()) { logger.trace("Incomplete STOMP frame content received, bufferSize=" + this.bufferingDecoder.getBufferSize() + ", bufferSizeLimit=" + this.bufferingDecoder.getBufferSizeLimit() + "."); } } return result; }
private void checkBufferLimits() { Integer contentLength = this.expectedContentLength; if (contentLength != null && contentLength > this.bufferSizeLimit) { throw new StompConversionException( "STOMP 'content-length' header value " + this.expectedContentLength + " exceeds configured buffer size limit " + this.bufferSizeLimit); } if (getBufferSize() > this.bufferSizeLimit) { throw new StompConversionException("The configured STOMP buffer size limit of " + this.bufferSizeLimit + " bytes has been exceeded"); } }
if (logger.isTraceEnabled()) { logger.trace("Incomplete STOMP frame content received in session " + session + ", bufferSize=" + decoder.getBufferSize() + ", bufferSizeLimit=" + decoder.getBufferSizeLimit() + ".");
/** * Decodes one or more STOMP frames from the given {@code ByteBuffer} into a * list of {@link Message Messages}. * <p>If there was enough data to parse a "content-length" header, then the * value is used to determine how much more data is needed before a new * attempt to decode is made. * <p>If there was not enough data to parse the "content-length", or if there * is "content-length" header, every subsequent call to decode attempts to * parse again with all available data. Therefore the presence of a "content-length" * header helps to optimize the decoding of large messages. * @param newBuffer a buffer containing new data to decode * @return decoded messages or an empty list * @throws StompConversionException raised in case of decoding issues */ public List<Message<byte[]>> decode(ByteBuffer newBuffer) { this.chunks.add(newBuffer); checkBufferLimits(); Integer contentLength = this.expectedContentLength; if (contentLength != null && getBufferSize() < contentLength) { return Collections.emptyList(); } ByteBuffer bufferToDecode = assembleChunksAndReset(); MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); List<Message<byte[]>> messages = this.stompDecoder.decode(bufferToDecode, headers); if (bufferToDecode.hasRemaining()) { this.chunks.add(bufferToDecode); this.expectedContentLength = StompHeaderAccessor.getContentLength(headers); } return messages; }
public List<Message<byte[]>> decode(WebSocketMessage<?> webSocketMessage) { List<Message<byte[]>> result = Collections.emptyList(); ByteBuffer byteBuffer; if (webSocketMessage instanceof TextMessage) { byteBuffer = ByteBuffer.wrap(((TextMessage) webSocketMessage).asBytes()); } else if (webSocketMessage instanceof BinaryMessage) { byteBuffer = ((BinaryMessage) webSocketMessage).getPayload(); } else { return result; } result = this.bufferingDecoder.decode(byteBuffer); if (result.isEmpty()) { if (logger.isTraceEnabled()) { logger.trace("Incomplete STOMP frame content received, bufferSize=" + this.bufferingDecoder.getBufferSize() + ", bufferSizeLimit=" + this.bufferingDecoder.getBufferSizeLimit() + "."); } } return result; }
@Test public void twoMessagesInOneChunk() throws InterruptedException { BufferingStompDecoder stompDecoder = new BufferingStompDecoder(STOMP_DECODER, 128); String chunk = "SEND\na:alpha\n\nPayload1\0" + "SEND\na:alpha\n\nPayload2\0"; List<Message<byte[]>> messages = stompDecoder.decode(toByteBuffer(chunk)); assertEquals(2, messages.size()); assertEquals("Payload1", new String(messages.get(0).getPayload())); assertEquals("Payload2", new String(messages.get(1).getPayload())); assertEquals(0, stompDecoder.getBufferSize()); assertNull(stompDecoder.getExpectedContentLength()); }
public List<Message<byte[]>> decode(WebSocketMessage<?> webSocketMessage) { List<Message<byte[]>> result = Collections.emptyList(); ByteBuffer byteBuffer; if (webSocketMessage instanceof TextMessage) { byteBuffer = ByteBuffer.wrap(((TextMessage) webSocketMessage).asBytes()); } else if (webSocketMessage instanceof BinaryMessage) { byteBuffer = ((BinaryMessage) webSocketMessage).getPayload(); } else { return result; } result = this.bufferingDecoder.decode(byteBuffer); if (result.isEmpty()) { if (logger.isTraceEnabled()) { logger.trace("Incomplete STOMP frame content received, bufferSize=" + this.bufferingDecoder.getBufferSize() + ", bufferSizeLimit=" + this.bufferingDecoder.getBufferSizeLimit() + "."); } } return result; }
@Test public void basic() throws InterruptedException { BufferingStompDecoder stompDecoder = new BufferingStompDecoder(STOMP_DECODER, 128); String chunk = "SEND\na:alpha\n\nMessage body\0"; List<Message<byte[]>> messages = stompDecoder.decode(toByteBuffer(chunk)); assertEquals(1, messages.size()); assertEquals("Message body", new String(messages.get(0).getPayload())); assertEquals(0, stompDecoder.getBufferSize()); assertNull(stompDecoder.getExpectedContentLength()); }
@Test public void oneMessageInTwoChunks() throws InterruptedException { BufferingStompDecoder stompDecoder = new BufferingStompDecoder(STOMP_DECODER, 128); String chunk1 = "SEND\na:alpha\n\nMessage"; String chunk2 = " body\0"; List<Message<byte[]>> messages = stompDecoder.decode(toByteBuffer(chunk1)); assertEquals(Collections.<Message<byte[]>>emptyList(), messages); messages = stompDecoder.decode(toByteBuffer(chunk2)); assertEquals(1, messages.size()); assertEquals("Message body", new String(messages.get(0).getPayload())); assertEquals(0, stompDecoder.getBufferSize()); assertNull(stompDecoder.getExpectedContentLength()); }
@Test public void oneFullAndOneSplitMessageNoContentLength() throws InterruptedException { BufferingStompDecoder stompDecoder = new BufferingStompDecoder(STOMP_DECODER, 128); String chunk1 = "SEND\na:alpha\n\nPayload1\0SEND\na:alpha\n"; List<Message<byte[]>> messages = stompDecoder.decode(toByteBuffer(chunk1)); assertEquals(1, messages.size()); assertEquals("Payload1", new String(messages.get(0).getPayload())); assertEquals(13, stompDecoder.getBufferSize()); assertNull(stompDecoder.getExpectedContentLength()); String chunk2 = "\nPayload2a"; messages = stompDecoder.decode(toByteBuffer(chunk2)); assertEquals(0, messages.size()); assertEquals(23, stompDecoder.getBufferSize()); assertNull(stompDecoder.getExpectedContentLength()); String chunk3 = "-Payload2b\0"; messages = stompDecoder.decode(toByteBuffer(chunk3)); assertEquals(1, messages.size()); assertEquals("Payload2a-Payload2b", new String(messages.get(0).getPayload())); assertEquals(0, stompDecoder.getBufferSize()); assertNull(stompDecoder.getExpectedContentLength()); }
@Test public void oneFullAndOneSplitMessageContentLength() throws InterruptedException { BufferingStompDecoder stompDecoder = new BufferingStompDecoder(STOMP_DECODER, 128); int contentLength = "Payload2a-Payload2b".getBytes().length; String chunk1 = "SEND\na:alpha\n\nPayload1\0SEND\ncontent-length:" + contentLength + "\n"; List<Message<byte[]>> messages = stompDecoder.decode(toByteBuffer(chunk1)); assertEquals(1, messages.size()); assertEquals("Payload1", new String(messages.get(0).getPayload())); assertEquals(23, stompDecoder.getBufferSize()); assertEquals(contentLength, (int) stompDecoder.getExpectedContentLength()); String chunk2 = "\nPayload2a"; messages = stompDecoder.decode(toByteBuffer(chunk2)); assertEquals(0, messages.size()); assertEquals(33, stompDecoder.getBufferSize()); assertEquals(contentLength, (int) stompDecoder.getExpectedContentLength()); String chunk3 = "-Payload2b\0"; messages = stompDecoder.decode(toByteBuffer(chunk3)); assertEquals(1, messages.size()); assertEquals("Payload2a-Payload2b", new String(messages.get(0).getPayload())); assertEquals(0, stompDecoder.getBufferSize()); assertNull(stompDecoder.getExpectedContentLength()); }
@Test public void oneFullAndOneSplitWithContentLengthExceedingBufferSize() throws InterruptedException { BufferingStompDecoder stompDecoder = new BufferingStompDecoder(STOMP_DECODER, 128); String chunk1 = "SEND\na:alpha\n\nPayload1\0SEND\ncontent-length:129\n"; List<Message<byte[]>> messages = stompDecoder.decode(toByteBuffer(chunk1)); assertEquals("We should have gotten the 1st message", 1, messages.size()); assertEquals("Payload1", new String(messages.get(0).getPayload())); assertEquals(24, stompDecoder.getBufferSize()); assertEquals(129, (int) stompDecoder.getExpectedContentLength()); try { String chunk2 = "\nPayload2a"; stompDecoder.decode(toByteBuffer(chunk2)); fail("Expected exception"); } catch (StompConversionException ex) { // expected } }
private ByteBuffer assembleChunksAndReset() { ByteBuffer result; if (this.chunks.size() == 1) { result = this.chunks.remove(); } else { result = ByteBuffer.allocate(getBufferSize()); for (ByteBuffer partial : this.chunks) { result.put(partial); } result.flip(); } this.chunks.clear(); this.expectedContentLength = null; return result; }
private void checkBufferLimits() { Integer contentLength = this.expectedContentLength; if (contentLength != null && contentLength > this.bufferSizeLimit) { throw new StompConversionException( "STOMP 'content-length' header value " + this.expectedContentLength + " exceeds configured buffer size limit " + this.bufferSizeLimit); } if (getBufferSize() > this.bufferSizeLimit) { throw new StompConversionException("The configured STOMP buffer size limit of " + this.bufferSizeLimit + " bytes has been exceeded"); } }
/** * Decodes one or more STOMP frames from the given {@code ByteBuffer} into a * list of {@link Message Messages}. * <p>If there was enough data to parse a "content-length" header, then the * value is used to determine how much more data is needed before a new * attempt to decode is made. * <p>If there was not enough data to parse the "content-length", or if there * is "content-length" header, every subsequent call to decode attempts to * parse again with all available data. Therefore the presence of a "content-length" * header helps to optimize the decoding of large messages. * @param newBuffer a buffer containing new data to decode * @return decoded messages or an empty list * @throws StompConversionException raised in case of decoding issues */ public List<Message<byte[]>> decode(ByteBuffer newBuffer) { this.chunks.add(newBuffer); checkBufferLimits(); Integer contentLength = this.expectedContentLength; if (contentLength != null && getBufferSize() < contentLength) { return Collections.emptyList(); } ByteBuffer bufferToDecode = assembleChunksAndReset(); MultiValueMap<String, String> headers = new LinkedMultiValueMap<>(); List<Message<byte[]>> messages = this.stompDecoder.decode(bufferToDecode, headers); if (bufferToDecode.hasRemaining()) { this.chunks.add(bufferToDecode); this.expectedContentLength = StompHeaderAccessor.getContentLength(headers); } return messages; }
private ByteBuffer assembleChunksAndReset() { ByteBuffer result; if (this.chunks.size() == 1) { result = this.chunks.remove(); } else { result = ByteBuffer.allocate(getBufferSize()); for (ByteBuffer partial : this.chunks) { result.put(partial); } result.flip(); } this.chunks.clear(); this.expectedContentLength = null; return result; }
private ByteBuffer assembleChunksAndReset() { ByteBuffer result; if (this.chunks.size() == 1) { result = this.chunks.remove(); } else { result = ByteBuffer.allocate(getBufferSize()); for (ByteBuffer partial : this.chunks) { result.put(partial); } result.flip(); } this.chunks.clear(); this.expectedContentLength = null; return result; }
private void checkBufferLimits() { Integer contentLength = this.expectedContentLength; if (contentLength != null && contentLength > this.bufferSizeLimit) { throw new StompConversionException( "STOMP 'content-length' header value " + this.expectedContentLength + " exceeds configured buffer size limit " + this.bufferSizeLimit); } if (getBufferSize() > this.bufferSizeLimit) { throw new StompConversionException("The configured STOMP buffer size limit of " + this.bufferSizeLimit + " bytes has been exceeded"); } }
private void checkBufferLimits() { Integer contentLength = this.expectedContentLength; if (contentLength != null && contentLength > this.bufferSizeLimit) { throw new StompConversionException( "STOMP 'content-length' header value " + this.expectedContentLength + " exceeds configured buffer size limit " + this.bufferSizeLimit); } if (getBufferSize() > this.bufferSizeLimit) { throw new StompConversionException("The configured STOMP buffer size limit of " + this.bufferSizeLimit + " bytes has been exceeded"); } }