Author: markt
Date: Wed Dec 26 18:25:22 2012
New Revision: 1425980
URL: http://svn.apache.org/viewvc?rev=1425980&view=rev
Log:
Fix various failures when running the Autobahn close tests
- some close codes are not meant to be used on the wire
- properly decode UTF-8 close reasons
- single byte close codes are invalid
Modified:
tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties
tomcat/trunk/java/org/apache/tomcat/websocket/Util.java
tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java
Modified: tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties?rev=1425980&r1=1425979&r2=1425980&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties
(original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties Wed
Dec 26 18:25:22 2012
@@ -25,7 +25,9 @@ wsFrame.controlPayloadTooBig=A control f
wsFrame.controlNoFin=A control frame was sent that did not have the fin bit
set. Control frames are not permitted to use continuation frames.
wsFrame.invalidOpCode= A WebSocket frame was sent with an unrecognised opCode
of [{0}]
wsFrame.invalidUtf8=A WebSocket text frame was received that could not be
decoded to UTF-8 because it contained invalid byte sequences
+wsFrame.invalidUtf8Close=A WebSocket close frame was received with a close
reason that contained invalid UTF-8 byte sequences
wsFrame.noContinuation=A new message was started when a continuation frame was
expected
wsFrame.notMasked=The client frame was not masked but all client frames must
be masked
+wsFrame.oneByteCloseCode=The client sent a close frame with a single byte
payload which is not valid
wsFrame.textMessageTooBig=The decoded text message was too big to fit in the
output text message buffer and the endpoint does not support delivery of
partial messages
wsFrame.wrongRsv=The client frame set the reserved bits to [{0}] which was not
supported by this endpoint
\ No newline at end of file
Modified: tomcat/trunk/java/org/apache/tomcat/websocket/Util.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/Util.java?rev=1425980&r1=1425979&r2=1425980&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/Util.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/Util.java Wed Dec 26 18:25:22
2012
@@ -57,6 +57,9 @@ class Util {
static CloseCode getCloseCode(int code) {
+ if (code > 2999 && code < 5000) {
+ return CloseCodes.NORMAL_CLOSURE;
+ }
switch (code) {
case 1000:
return CloseCodes.NORMAL_CLOSURE;
@@ -67,11 +70,17 @@ class Util {
case 1003:
return CloseCodes.CANNOT_ACCEPT;
case 1004:
- return CloseCodes.RESERVED;
+ // Should not be used in a close frame
+ // return CloseCodes.RESERVED;
+ return CloseCodes.PROTOCOL_ERROR;
case 1005:
- return CloseCodes.NO_STATUS_CODE;
+ // Should not be used in a close frame
+ // return CloseCodes.NO_STATUS_CODE;
+ return CloseCodes.PROTOCOL_ERROR;
case 1006:
- return CloseCodes.CLOSED_ABNORMALLY;
+ // Should not be used in a close frame
+ // return CloseCodes.CLOSED_ABNORMALLY;
+ return CloseCodes.PROTOCOL_ERROR;
case 1007:
return CloseCodes.NOT_CONSISTENT;
case 1008:
@@ -83,11 +92,17 @@ class Util {
case 1011:
return CloseCodes.UNEXPECTED_CONDITION;
case 1012:
- return CloseCodes.SERVICE_RESTART;
+ // Not in RFC6455
+ // return CloseCodes.SERVICE_RESTART;
+ return CloseCodes.PROTOCOL_ERROR;
case 1013:
- return CloseCodes.TRY_AGAIN_LATER;
+ // Not in RFC6455
+ // return CloseCodes.TRY_AGAIN_LATER;
+ return CloseCodes.PROTOCOL_ERROR;
case 1015:
- return CloseCodes.TLS_HANDSHAKE_FAILURE;
+ // Should not be used in a close frame
+ // return CloseCodes.TLS_HANDSHAKE_FAILURE;
+ return CloseCodes.PROTOCOL_ERROR;
default:
return CloseCodes.PROTOCOL_ERROR;
}
Modified: tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java
URL:
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java?rev=1425980&r1=1425979&r2=1425980&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java (original)
+++ tomcat/trunk/java/org/apache/tomcat/websocket/WsFrame.java Wed Dec 26
18:25:22 2012
@@ -49,12 +49,16 @@ public class WsFrame {
// Attributes for control messages
// Control messages can appear in the middle of other messages so need
// separate attributes
- private final ByteBuffer controlBuffer = ByteBuffer.allocate(125);
+ private final ByteBuffer controlBufferBinary = ByteBuffer.allocate(125);
+ private final CharBuffer controlBufferText = CharBuffer.allocate(125);
// Attributes of the current message
private final ByteBuffer messageBufferBinary;
private final CharBuffer messageBufferText;
- private final CharsetDecoder utf8Decoder = new Utf8Decoder().
+ private final CharsetDecoder utf8DecoderControl = new Utf8Decoder().
+ onMalformedInput(CodingErrorAction.REPORT).
+ onUnmappableCharacter(CodingErrorAction.REPORT);
+ private final CharsetDecoder utf8DecoderMessage = new Utf8Decoder().
onMalformedInput(CodingErrorAction.REPORT).
onUnmappableCharacter(CodingErrorAction.REPORT);
private boolean continuationExpected = false;
@@ -246,7 +250,7 @@ public class WsFrame {
messageBufferBinary.flip();
boolean last = false;
while (true) {
- CoderResult cr = utf8Decoder.decode(
+ CoderResult cr = utf8DecoderMessage.decode(
messageBufferBinary, messageBufferText, last);
if (cr.isError()) {
throw new WsIOException(new CloseReason(
@@ -314,40 +318,58 @@ public class WsFrame {
private boolean processDataControl() throws IOException {
- appendPayloadToMessage(controlBuffer);
+ appendPayloadToMessage(controlBufferBinary);
if (writePos < frameStart + headerLength + payloadLength) {
return false;
}
- controlBuffer.flip();
+ controlBufferBinary.flip();
if (opCode == Constants.OPCODE_CLOSE) {
String reason = null;
int code = CloseCodes.NORMAL_CLOSURE.getCode();
- if (controlBuffer.remaining() > 1) {
- code = controlBuffer.getShort();
- if (controlBuffer.remaining() > 0) {
- reason = new String(controlBuffer.array(),
- controlBuffer.arrayOffset() +
controlBuffer.position(),
- controlBuffer.remaining(), "UTF8");
+ if (controlBufferBinary.remaining() == 1) {
+ controlBufferBinary.clear();
+ // Payload must be zero or greater than 2
+ throw new WsIOException(new CloseReason(
+ CloseCodes.PROTOCOL_ERROR,
+ sm.getString("wsFrame.oneByteCloseCode")));
+ }
+ if (controlBufferBinary.remaining() > 1) {
+ code = controlBufferBinary.getShort();
+ if (controlBufferBinary.remaining() > 0) {
+ CoderResult cr = utf8DecoderControl.decode(
+ controlBufferBinary, controlBufferText, true);
+ if (cr.isError()) {
+ controlBufferBinary.clear();
+ controlBufferText.clear();
+ throw new WsIOException(new CloseReason(
+ CloseCodes.PROTOCOL_ERROR,
+ sm.getString("wsFrame.invalidUtf8Close")));
+ }
+ reason = new String(controlBufferBinary.array(),
+ controlBufferBinary.arrayOffset() +
+ controlBufferBinary.position(),
+ controlBufferBinary.remaining(), "UTF8");
}
}
wsSession.onClose(
new CloseReason(Util.getCloseCode(code), reason));
} else if (opCode == Constants.OPCODE_PING) {
- wsSession.getRemote().sendPong(controlBuffer);
+ wsSession.getRemote().sendPong(controlBufferBinary);
} else if (opCode == Constants.OPCODE_PONG) {
MessageHandler.Basic<PongMessage> mhPong =
wsSession.getPongMessageHandler();
if (mhPong != null) {
- mhPong.onMessage(new WsPongMessage(controlBuffer));
+ mhPong.onMessage(new WsPongMessage(controlBufferBinary));
}
} else {
// Should have caught this earlier but just in case...
+ controlBufferBinary.clear();
throw new WsIOException(new CloseReason(
CloseCodes.PROTOCOL_ERROR,
sm.getString("wsFrame.invalidOpCode",
Integer.valueOf(opCode))));
}
- controlBuffer.clear();
+ controlBufferBinary.clear();
newFrame();
return true;
}
@@ -386,7 +408,7 @@ public class WsFrame {
private void newMessage() {
messageBufferBinary.clear();
messageBufferText.clear();
- utf8Decoder.reset();
+ utf8DecoderMessage.reset();
continuationExpected = false;
newFrame();
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]