diff --git a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java
index 1f8ed46028..8ed9acb20b 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java
+++ b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/CloseWebSocketFrame.java
@@ -15,7 +15,9 @@
*/
package io.netty.handler.codec.http.websocketx;
+import io.netty.buffer.ChannelBuffer;
import io.netty.buffer.ChannelBuffers;
+import io.netty.util.CharsetUtil;
/**
* Web Socket Frame for closing the connection
@@ -30,7 +32,20 @@ public class CloseWebSocketFrame extends WebSocketFrame {
}
/**
- * Creates a new close frame
+ * 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
@@ -38,8 +53,93 @@ public class CloseWebSocketFrame extends WebSocketFrame {
* 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
+ *
+ * @param finalFragment
+ * 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, 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/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java b/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java
index 5bd7ea0038..b590c11d8a 100644
--- a/codec-http/src/main/java/io/netty/handler/codec/http/websocketx/WebSocket08FrameDecoder.java
+++ b/codec-http/src/main/java/io/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);
+ }
}
diff --git a/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java
index 0729d0b5ad..d04cb842c4 100644
--- a/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java
+++ b/example/src/main/java/io/netty/example/http/websocketx/autobahn/AutobahnServerHandler.java
@@ -82,11 +82,10 @@ public class AutobahnServerHandler extends SimpleChannelUpstreamHandler {
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {
if (logger.isDebugEnabled()) {
- logger.debug(String
- .format("Channel %s received %s", ctx.getChannel().getId(), frame.getClass().getSimpleName()));
+ logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), frame.getClass()
+ .getSimpleName()));
}
-
if (frame instanceof CloseWebSocketFrame) {
this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
} else if (frame instanceof PingWebSocketFrame) {