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: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org