Author: markt Date: Fri Feb 17 23:17:57 2012 New Revision: 1245803 URL: http://svn.apache.org/viewvc?rev=1245803&view=rev Log: Move the frame header processing into the WsInputStream since the fragmented frame processing will required header processing at this level.
Added: tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java Modified: tomcat/trunk/java/org/apache/catalina/websocket/Constants.java tomcat/trunk/java/org/apache/catalina/websocket/StreamInbound.java tomcat/trunk/java/org/apache/catalina/websocket/WsInputStream.java Modified: tomcat/trunk/java/org/apache/catalina/websocket/Constants.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/websocket/Constants.java?rev=1245803&r1=1245802&r2=1245803&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/websocket/Constants.java (original) +++ tomcat/trunk/java/org/apache/catalina/websocket/Constants.java Fri Feb 17 23:17:57 2012 @@ -21,4 +21,12 @@ package org.apache.catalina.websocket; */ public class Constants { public static final String Package = "org.apache.catalina.websocket"; + + // OP Codes + public static final byte OPCODE_CONTINUATION = 0x00; + public static final byte OPCODE_TEXT = 0x01; + public static final byte OPCODE_BINARY = 0x02; + public static final byte OPCODE_CLOSE = 0x08; + public static final byte OPCODE_PING = 0x09; + public static final byte OPCODE_PONG = 0x0A; } Modified: tomcat/trunk/java/org/apache/catalina/websocket/StreamInbound.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/websocket/StreamInbound.java?rev=1245803&r1=1245802&r2=1245803&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/websocket/StreamInbound.java (original) +++ tomcat/trunk/java/org/apache/catalina/websocket/StreamInbound.java Fri Feb 17 23:17:57 2012 @@ -21,7 +21,6 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.io.Reader; -import org.apache.catalina.util.Conversions; import org.apache.coyote.http11.upgrade.UpgradeInbound; import org.apache.coyote.http11.upgrade.UpgradeOutbound; import org.apache.coyote.http11.upgrade.UpgradeProcessor; @@ -30,18 +29,6 @@ import org.apache.tomcat.util.net.Abstra public abstract class StreamInbound implements UpgradeInbound { - // These attributes apply to the current frame being processed - private boolean fin = true; - private boolean rsv1 = false; - private boolean rsv2 = false; - private boolean rsv3 = false; - private int opCode = -1; - private long payloadLength = -1; - - // These attributes apply to the message that may be spread over multiple - // frames - // TODO - private UpgradeProcessor<?> processor = null; private WsOutbound outbound; @@ -62,76 +49,30 @@ public abstract class StreamInbound impl @Override public SocketState onData() throws IOException { - // Must be start the start of a frame - - // Read the first byte - int i = processor.read(); - - fin = (i & 0x80) > 0; + // Must be start the start of a frame or series of frames + WsInputStream wsIs = new WsInputStream(processor); - rsv1 = (i & 0x40) > 0; - rsv2 = (i & 0x20) > 0; - rsv3 = (i & 0x10) > 0; - - if (rsv1 || rsv2 || rsv3) { - // TODO: Not supported. - } - - opCode = (i & 0x0F); + WsFrameHeader header = wsIs.getFrameHeader(); + byte opCode = header.getOpCode(); validateOpCode(opCode); - // Read the next byte - i = processor.read(); - - // Client data must be masked and this isn't - if ((i & 0x80) == 0) { - // TODO: Better message - throw new IOException(); - } - - payloadLength = i & 0x7F; - if (payloadLength == 126) { - byte[] extended = new byte[2]; - processor.read(extended); - payloadLength = Conversions.byteArrayToLong(extended); - } else if (payloadLength == 127) { - byte[] extended = new byte[8]; - processor.read(extended); - payloadLength = Conversions.byteArrayToLong(extended); + if (opCode == Constants.OPCODE_BINARY) { + onBinaryData(wsIs); + } else if (opCode == Constants.OPCODE_TEXT) { + InputStreamReader r = + new InputStreamReader(wsIs, B2CConverter.UTF_8); + onTextData(r); + } else { + // TODO i18n + throw new IOException("OpCode " + opCode + " not supported"); } - - byte[] mask = new byte[4]; - processor.read(mask); - - if (opCode == 1 || opCode == 2) { - WsInputStream wsIs = new WsInputStream(processor, mask, - payloadLength); - if (opCode == 2) { - onBinaryData(wsIs); - } else { - InputStreamReader r = - new InputStreamReader(wsIs, B2CConverter.UTF_8); - onTextData(r); - } - } - - // TODO: Doesn't currently handle multi-frame messages. That will need - // some refactoring. - - // TODO: Per frame extension handling is not currently supported. - - // TODO: Handle other control frames. - - // TODO: Handle control frames appearing in the middle of a multi-frame - // message - return SocketState.UPGRADED; } protected abstract void onBinaryData(InputStream is) throws IOException; protected abstract void onTextData(Reader r) throws IOException; - private void validateOpCode(int opCode) throws IOException { + private void validateOpCode(byte opCode) throws IOException { switch (opCode) { case 0: case 1: Added: tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java?rev=1245803&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java (added) +++ tomcat/trunk/java/org/apache/catalina/websocket/WsFrameHeader.java Fri Feb 17 23:17:57 2012 @@ -0,0 +1,62 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.catalina.websocket; + +/** + * This class does not represent the complete frame header, just those parts of + * it that need to be exposed more widely than the {@link WsInputStream}. + */ +public class WsFrameHeader { + + private final boolean fin; + private final boolean rsv1; + private final boolean rsv2; + private final boolean rsv3; + private final byte opCode; + + public WsFrameHeader(int b) { + fin = (b & 0x80) > 0; + + rsv1 = (b & 0x40) > 0; + rsv2 = (b & 0x20) > 0; + rsv3 = (b & 0x10) > 0; + + opCode = (byte) (b & 0x0F); + } + + public boolean getFin() { + return fin; + } + + public boolean getRsv1() { + return rsv1; + } + + public boolean getRsv2() { + return rsv2; + } + + public boolean getRsv3() { + return rsv3; + } + + public byte getOpCode() { + return opCode; + } + + +} Modified: tomcat/trunk/java/org/apache/catalina/websocket/WsInputStream.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/websocket/WsInputStream.java?rev=1245803&r1=1245802&r2=1245803&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/websocket/WsInputStream.java (original) +++ tomcat/trunk/java/org/apache/catalina/websocket/WsInputStream.java Fri Feb 17 23:17:57 2012 @@ -18,23 +18,66 @@ package org.apache.catalina.websocket; import java.io.IOException; +import org.apache.catalina.util.Conversions; import org.apache.coyote.http11.upgrade.UpgradeProcessor; public class WsInputStream extends java.io.InputStream { private UpgradeProcessor<?> processor; - private byte[] mask; + private final WsFrameHeader wsFrameHeader; + private long payloadLength = -1; + private byte[] mask = new byte[4]; + + private long remaining; private long read; - public WsInputStream(UpgradeProcessor<?> processor, byte[] mask, - long remaining) { + public WsInputStream(UpgradeProcessor<?> processor) throws IOException { this.processor = processor; - this.mask = mask; - this.remaining = remaining; - this.read = 0; + + int i = processor.read(); + this.wsFrameHeader = new WsFrameHeader(i); + + // Client data must be masked + i = processor.read(); + if ((i & 0x80) == 0) { + // TODO: StringManager / i18n + throw new IOException("Client frame not masked"); + } + + payloadLength = i & 0x7F; + if (payloadLength == 126) { + byte[] extended = new byte[2]; + processor.read(extended); + payloadLength = Conversions.byteArrayToLong(extended); + } else if (payloadLength == 127) { + byte[] extended = new byte[8]; + processor.read(extended); + payloadLength = Conversions.byteArrayToLong(extended); + } + remaining = payloadLength; + + processor.read(mask); + + + // TODO: Doesn't currently handle multi-frame messages. That will need + // some refactoring. + + // TODO: Per frame extension handling is not currently supported. + + // TODO: Handle other control frames. + + // TODO: Handle control frames appearing in the middle of a multi-frame + // message } + public WsFrameHeader getFrameHeader() { + return wsFrameHeader; + } + + + // ----------------------------------------------------- InputStream methods + @Override public int read() throws IOException { if (remaining == 0) { @@ -47,5 +90,4 @@ public class WsInputStream extends java. int masked = processor.read(); return masked ^ mask[(int) ((read - 1) % 4)]; } - } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org