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

Reply via email to