diff --git a/src/main/java/org/jboss/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java b/src/main/java/org/jboss/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java index e79c40b815..9e904ddd00 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java @@ -15,13 +15,14 @@ */ package org.jboss.netty.handler.codec.http.websocketx; +import org.jboss.netty.buffer.ChannelBuffer; import org.jboss.netty.buffer.ChannelBuffers; +import org.jboss.netty.util.CharsetUtil; /** * Web Socket Frame for closing the connection */ public class CloseWebSocketFrame extends WebSocketFrame { - /** * Creates a new empty close frame. */ @@ -29,6 +30,63 @@ public class CloseWebSocketFrame extends WebSocketFrame { setBinaryData(ChannelBuffers.EMPTY_BUFFER); } + /** + * Creates a new empty close frame with closing status code and reason text + * + * @param statusCode + * Integer status code as per RFC 6455. For + * example, 1000 indicates normal closure. + * @param reasonText + * Reason text. Set to null if no text. + */ + public CloseWebSocketFrame(int statusCode, String reasonText) { + this(true, 0, statusCode, reasonText); + } + + /** + * Creates a new close frame with no losing status code and no reason text + * + * @param finalFragment + * flag indicating if this frame is the final fragment + * @param rsv + * reserved bits used for protocol extensions + */ + public CloseWebSocketFrame(boolean finalFragment, int rsv) { + this(finalFragment, rsv, null); + } + + /** + * Creates a new close frame with closing status code and reason text + * + * @param finalFragment + * flag indicating if this frame is the final fragment + * @param rsv + * reserved bits used for protocol extensions + * @param statusCode + * Integer status code as per RFC 6455. For + * example, 1000 indicates normal closure. + * @param reasonText + * Reason text. Set to null if no text. + */ + public CloseWebSocketFrame(boolean finalFragment, int rsv, int statusCode, String reasonText) { + setFinalFragment(finalFragment); + setRsv(rsv); + + byte[] reasonBytes = new byte[0]; + if (reasonText != null) { + reasonBytes = reasonText.getBytes(CharsetUtil.UTF_8); + } + + ChannelBuffer binaryData = ChannelBuffers.buffer(2 + reasonBytes.length); + binaryData.writeShort(statusCode); + if (reasonBytes.length > 0) { + binaryData.writeBytes(reasonBytes); + } + + binaryData.readerIndex(0); + setBinaryData(binaryData); + } + /** * Creates a new close frame * @@ -36,10 +94,51 @@ public class CloseWebSocketFrame extends WebSocketFrame { * flag indicating if this frame is the final fragment * @param rsv * reserved bits used for protocol extensions + * @param binaryData + * the content of the frame. Must be 2 byte integer followed by optional UTF-8 encoded string. */ - public CloseWebSocketFrame(boolean finalFragment, int rsv) { + public CloseWebSocketFrame(boolean finalFragment, int rsv, ChannelBuffer binaryData) { setFinalFragment(finalFragment); setRsv(rsv); + if (binaryData == null) { + setBinaryData(ChannelBuffers.EMPTY_BUFFER); + } else { + setBinaryData(binaryData); + } + } + + /** + * Returns the closing status code as per RFC 6455. If + * a status code is set, -1 is returned. + */ + public int getStatusCode() { + ChannelBuffer binaryData = this.getBinaryData(); + if (binaryData == null || binaryData.capacity() == 0) { + return -1; + } + + binaryData.readerIndex(0); + int statusCode = binaryData.readShort(); + binaryData.readerIndex(0); + + return statusCode; + } + + /** + * Returns the reason text as per RFC 6455 If a reason + * text is not supplied, an empty string is returned. + */ + public String getReasonText() { + ChannelBuffer binaryData = this.getBinaryData(); + if (binaryData == null || binaryData.capacity() <= 2) { + return ""; + } + + binaryData.readerIndex(2); + String reasonText = binaryData.toString(CharsetUtil.UTF_8); + binaryData.readerIndex(0); + + return reasonText; } @Override diff --git a/src/main/java/org/jboss/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java b/src/main/java/org/jboss/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java index 9d2cf1b2dc..cd9cf5c9d7 100644 --- a/src/main/java/org/jboss/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java +++ b/src/main/java/org/jboss/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java @@ -284,8 +284,9 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder= 0 && statusCode <= 999) || (statusCode >= 1004 && statusCode <= 1006) + || (statusCode >= 1012 && statusCode <= 2999)) { + protocolViolation(channel, "Invalid close frame status code: " + statusCode); + } + + // May have UTF-8 message + if (buffer.readableBytes() > 0) { + byte[] b = new byte[buffer.readableBytes()]; + buffer.readBytes(b); + try { + new UTF8Output(b); + } catch (UTF8Exception ex) { + protocolViolation(channel, "Invalid close frame reason text. Invalid UTF-8 bytes"); + } + } + + // Restore reader index + buffer.readerIndex(idx); + } }