Improve semantics writing currentData
Before this commit, the return value from write was interpreted as the data being fully written and ready to be released via releaseData(). This is not true for WebSocketSession implementations where a true return value simply means the message was sent with the full payload but releas is not appropriate until a send confirmation. Technically not an issue since WebSocketSession's extending this do not use pooled buffers. Nevertheless this commit refines the semantics of write, removes the releaseData() method, and makes sub-classes responsible for releasing the buffer when fully written (and they know best when that is). As a bonus currentData is now private. Issue: SPR-16207
This commit is contained in:
@@ -153,6 +153,9 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc
|
||||
|
||||
/**
|
||||
* Send the given WebSocket message.
|
||||
* <p><strong>Note:</strong> Sub-classes are responsible for releasing the
|
||||
* payload data buffer, once fully written, if pooled buffers apply to the
|
||||
* underlying container.
|
||||
*/
|
||||
protected abstract boolean sendMessage(WebSocketMessage message) throws IOException;
|
||||
|
||||
@@ -268,11 +271,6 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc
|
||||
return sendMessage(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void releaseData() {
|
||||
this.currentData = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isDataEmpty(WebSocketMessage message) {
|
||||
return (message.getPayload().readableByteCount() == 0);
|
||||
@@ -280,7 +278,7 @@ public abstract class AbstractListenerWebSocketSession<T> extends AbstractWebSoc
|
||||
|
||||
@Override
|
||||
protected boolean isWritePossible() {
|
||||
return (this.isReady && this.currentData != null);
|
||||
return (this.isReady);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,7 +27,9 @@ import io.undertow.websockets.core.WebSockets;
|
||||
import reactor.core.publisher.Mono;
|
||||
import reactor.core.publisher.MonoProcessor;
|
||||
|
||||
import org.springframework.core.io.buffer.DataBuffer;
|
||||
import org.springframework.core.io.buffer.DataBufferFactory;
|
||||
import org.springframework.core.io.buffer.DataBufferUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.reactive.socket.CloseStatus;
|
||||
@@ -78,19 +80,19 @@ public class UndertowWebSocketSession extends AbstractListenerWebSocketSession<W
|
||||
if (WebSocketMessage.Type.TEXT.equals(message.getType())) {
|
||||
getSendProcessor().setReadyToSend(false);
|
||||
String text = new String(buffer.array(), StandardCharsets.UTF_8);
|
||||
WebSockets.sendText(text, getDelegate(), new SendProcessorCallback());
|
||||
WebSockets.sendText(text, getDelegate(), new SendProcessorCallback(message.getPayload()));
|
||||
}
|
||||
else if (WebSocketMessage.Type.BINARY.equals(message.getType())) {
|
||||
getSendProcessor().setReadyToSend(false);
|
||||
WebSockets.sendBinary(buffer, getDelegate(), new SendProcessorCallback());
|
||||
WebSockets.sendBinary(buffer, getDelegate(), new SendProcessorCallback(message.getPayload()));
|
||||
}
|
||||
else if (WebSocketMessage.Type.PING.equals(message.getType())) {
|
||||
getSendProcessor().setReadyToSend(false);
|
||||
WebSockets.sendPing(buffer, getDelegate(), new SendProcessorCallback());
|
||||
WebSockets.sendPing(buffer, getDelegate(), new SendProcessorCallback(message.getPayload()));
|
||||
}
|
||||
else if (WebSocketMessage.Type.PONG.equals(message.getType())) {
|
||||
getSendProcessor().setReadyToSend(false);
|
||||
WebSockets.sendPong(buffer, getDelegate(), new SendProcessorCallback());
|
||||
WebSockets.sendPong(buffer, getDelegate(), new SendProcessorCallback(message.getPayload()));
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unexpected message type: " + message.getType());
|
||||
@@ -110,14 +112,22 @@ public class UndertowWebSocketSession extends AbstractListenerWebSocketSession<W
|
||||
|
||||
private final class SendProcessorCallback implements WebSocketCallback<Void> {
|
||||
|
||||
private final DataBuffer payload;
|
||||
|
||||
SendProcessorCallback(DataBuffer payload) {
|
||||
this.payload = payload;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete(WebSocketChannel channel, Void context) {
|
||||
DataBufferUtils.release(this.payload);
|
||||
getSendProcessor().setReadyToSend(true);
|
||||
getSendProcessor().onWritePossible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(WebSocketChannel channel, Void context, Throwable throwable) {
|
||||
DataBufferUtils.release(this.payload);
|
||||
getSendProcessor().cancel();
|
||||
getSendProcessor().onError(throwable);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user