io.undertow.websockets.core.BufferedTextMessage Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* 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 io.undertow.websockets.core;
import org.xnio.ChannelListener;
import io.undertow.connector.PooledByteBuffer;
import java.io.IOException;
import java.nio.ByteBuffer;
/**
* A buffered text message.
*
* @author Stuart Douglas
*/
public class BufferedTextMessage {
private final UTF8Output data = new UTF8Output();
private final boolean bufferFullMessage;
private final long maxMessageSize;
private boolean complete;
long currentSize;
/**
* @param maxMessageSize The maximum message size
* @param bufferFullMessage If the complete message should be buffered
*/
public BufferedTextMessage(long maxMessageSize, boolean bufferFullMessage) {
this.maxMessageSize = maxMessageSize;
this.bufferFullMessage = bufferFullMessage;
}
public BufferedTextMessage(boolean bufferFullMessage) {
this(-1, bufferFullMessage);
}
private void checkMaxSize(StreamSourceFrameChannel channel, int res) throws IOException {
if(res > 0) {
currentSize += res;
}
if (maxMessageSize > 0 && currentSize > maxMessageSize) {
WebSockets.sendClose(new CloseMessage(CloseMessage.MSG_TOO_BIG, WebSocketMessages.MESSAGES.messageToBig(maxMessageSize)), channel.getWebSocketChannel(), null);
throw new IOException(WebSocketMessages.MESSAGES.messageToBig(maxMessageSize));
}
}
public void readBlocking(StreamSourceFrameChannel channel) throws IOException {
PooledByteBuffer pooled = channel.getWebSocketChannel().getBufferPool().allocate();
final ByteBuffer buffer = pooled.getBuffer();
try {
for (; ; ) {
int res = channel.read(buffer);
if (res == -1) {
buffer.flip();
data.write(buffer);
this.complete = true;
return;
} else if (res == 0) {
channel.awaitReadable();
}
checkMaxSize(channel, res);
if (!buffer.hasRemaining()) {
buffer.flip();
data.write(buffer);
buffer.compact();
if (!bufferFullMessage) {
//if we are not reading the full message we return
return;
}
}
}
} finally {
pooled.close();
}
}
public void read(final StreamSourceFrameChannel channel, final WebSocketCallback callback) {
PooledByteBuffer pooled = channel.getWebSocketChannel().getBufferPool().allocate();
final ByteBuffer buffer = pooled.getBuffer();
try {
try {
for (; ; ) {
int res = channel.read(buffer);
if (res == -1) {
this.complete = true;
buffer.flip();
data.write(buffer);
callback.complete(channel.getWebSocketChannel(), this);
return;
} else if (res == 0) {
buffer.flip();
if (buffer.hasRemaining()) {
data.write(buffer);
if (!bufferFullMessage) {
callback.complete(channel.getWebSocketChannel(), this);
}
}
channel.getReadSetter().set(new ChannelListener() {
@Override
public void handleEvent(StreamSourceFrameChannel channel) {
if(complete ) {
return;
}
PooledByteBuffer pooled = channel.getWebSocketChannel().getBufferPool().allocate();
final ByteBuffer buffer = pooled.getBuffer();
try {
try {
for (; ; ) {
int res = channel.read(buffer);
if (res == -1) {
checkMaxSize(channel, res);
buffer.flip();
data.write(buffer);
complete = true;
callback.complete(channel.getWebSocketChannel(), BufferedTextMessage.this);
return;
} else if (res == 0) {
buffer.flip();
if (buffer.hasRemaining()) {
data.write(buffer);
if (!bufferFullMessage) {
callback.complete(channel.getWebSocketChannel(), BufferedTextMessage.this);
}
}
return;
}
if (!buffer.hasRemaining()) {
buffer.flip();
data.write(buffer);
buffer.clear();
if (!bufferFullMessage) {
callback.complete(channel.getWebSocketChannel(), BufferedTextMessage.this);
}
}
}
} catch (IOException e) {
callback.onError(channel.getWebSocketChannel(), BufferedTextMessage.this, e);
}
} finally {
pooled.close();
}
}
});
channel.resumeReads();
return;
}
checkMaxSize(channel, res);
if (!buffer.hasRemaining()) {
buffer.flip();
data.write(buffer);
buffer.clear();
if (!bufferFullMessage) {
callback.complete(channel.getWebSocketChannel(), this);
}
}
}
} catch (IOException e) {
callback.onError(channel.getWebSocketChannel(), this, e);
}
} finally {
pooled.close();
}
}
/**
* Gets the buffered data and clears the buffered text message. If this is not called on a UTF8
* character boundary there may be partial code point data that is still buffered.
*
* @return The data
*/
public String getData() {
return data.extract();
}
public boolean isComplete() {
return complete;
}
}