Merge pull request #254 from veebs/3-wc-close
Issue #250. Implement web socket close frame status code and reason text
This commit is contained in:
commit
cf462e6d9d
@ -15,13 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package org.jboss.netty.handler.codec.http.websocketx;
|
package org.jboss.netty.handler.codec.http.websocketx;
|
||||||
|
|
||||||
|
import org.jboss.netty.buffer.ChannelBuffer;
|
||||||
import org.jboss.netty.buffer.ChannelBuffers;
|
import org.jboss.netty.buffer.ChannelBuffers;
|
||||||
|
import org.jboss.netty.util.CharsetUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Web Socket Frame for closing the connection
|
* Web Socket Frame for closing the connection
|
||||||
*/
|
*/
|
||||||
public class CloseWebSocketFrame extends WebSocketFrame {
|
public class CloseWebSocketFrame extends WebSocketFrame {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new empty close frame.
|
* Creates a new empty close frame.
|
||||||
*/
|
*/
|
||||||
@ -29,6 +30,63 @@ public class CloseWebSocketFrame extends WebSocketFrame {
|
|||||||
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
|
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new empty close frame with closing status code and reason text
|
||||||
|
*
|
||||||
|
* @param statusCode
|
||||||
|
* Integer status code as per <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a>. For
|
||||||
|
* example, <tt>1000</tt> 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 <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a>. For
|
||||||
|
* example, <tt>1000</tt> 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
|
* Creates a new close frame
|
||||||
*
|
*
|
||||||
@ -36,10 +94,51 @@ public class CloseWebSocketFrame extends WebSocketFrame {
|
|||||||
* flag indicating if this frame is the final fragment
|
* flag indicating if this frame is the final fragment
|
||||||
* @param rsv
|
* @param rsv
|
||||||
* reserved bits used for protocol extensions
|
* 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);
|
setFinalFragment(finalFragment);
|
||||||
setRsv(rsv);
|
setRsv(rsv);
|
||||||
|
if (binaryData == null) {
|
||||||
|
setBinaryData(ChannelBuffers.EMPTY_BUFFER);
|
||||||
|
} else {
|
||||||
|
setBinaryData(binaryData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the closing status code as per <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a>. 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 <a href="http://tools.ietf.org/html/rfc6455#section-7.4">RFC 6455</a> 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
|
@Override
|
||||||
|
@ -284,8 +284,9 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
|
|||||||
} else if (frameOpcode == OPCODE_PONG) {
|
} else if (frameOpcode == OPCODE_PONG) {
|
||||||
return new PongWebSocketFrame(frameFinalFlag, frameRsv, framePayload);
|
return new PongWebSocketFrame(frameFinalFlag, frameRsv, framePayload);
|
||||||
} else if (frameOpcode == OPCODE_CLOSE) {
|
} else if (frameOpcode == OPCODE_CLOSE) {
|
||||||
|
checkCloseFrameBody(channel, framePayload);
|
||||||
receivedClosingHandshake = true;
|
receivedClosingHandshake = true;
|
||||||
return new CloseWebSocketFrame(frameFinalFlag, frameRsv);
|
return new CloseWebSocketFrame(frameFinalFlag, frameRsv, framePayload);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Processing for possible fragmented messages for text and binary
|
// Processing for possible fragmented messages for text and binary
|
||||||
@ -391,4 +392,38 @@ public class WebSocket08FrameDecoder extends ReplayingDecoder<WebSocket08FrameDe
|
|||||||
protocolViolation(channel, "invalid UTF-8 bytes");
|
protocolViolation(channel, "invalid UTF-8 bytes");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void checkCloseFrameBody(Channel channel, ChannelBuffer buffer) throws CorruptedFrameException {
|
||||||
|
if (buffer == null || buffer.capacity() == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (buffer.capacity() == 1) {
|
||||||
|
protocolViolation(channel, "Invalid close frame body");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save reader index
|
||||||
|
int idx = buffer.readerIndex();
|
||||||
|
buffer.readerIndex(0);
|
||||||
|
|
||||||
|
// Must have 2 byte integer within the valid range
|
||||||
|
int statusCode = buffer.readShort();
|
||||||
|
if ((statusCode >= 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user