Permalink
Browse files

Autobahn tests - still a lot to fix.

  • Loading branch information...
1 parent f27b8a6 commit b7b96247d3b2b66d57a3ceed1752ad4e29f46f9d @aslakhellesoy aslakhellesoy committed Oct 10, 2011
View
@@ -13,3 +13,4 @@ pom.xml.releaseBackup
pom.xml.asc
package.fig
+reports
View
@@ -62,9 +62,14 @@ build/.tests-pass: build/$(LIBRARY)-tests.jar
java -cp dist/$(LIBRARY).jar:build/$(LIBRARY)-tests.jar:$(CLASSPATH) org.junit.runner.JUnitCore $(call extracttests,build/$(LIBRARY)-tests.jar)
@touch $@
+# Run Autobahn tests
+autobahn:
+ PYTHONPATH=src/test/Autobahn/lib/python python src/test/Autobahn/testsuite/websockets/fuzzing_client.py
+
# Clean up
clean:
rm -rf build dist out
+
.PHONY: clean
again: clean all
View
@@ -94,10 +94,7 @@ We're using it to test Webbit.
Installing Autobahn
git submodule update --init
- pushd src/test/Autobahn/lib/python
easy_install twisted
- python setup.py install
- popd
Running Autobahn tests
@@ -107,8 +104,7 @@ In shell A:
In shell B:
- cd src/test/Autobahn/testsuite/websockets
- python fuzzing_client.py
+ make autobahn
More
-----------
@@ -0,0 +1,39 @@
+{
+ "servers": [{"agent": "AutobahnServer", "hostname": "localhost", "port": 9000, "version": 13}],
+ "cases": [
+ "1.1.1",
+ "1.1.2",
+ "1.1.3",
+ "1.1.4",
+ "1.1.5",
+ "1.1.6",
+ "1.1.7",
+ "1.1.8",
+ "1.2.1",
+ "1.2.2",
+ "1.2.3",
+ "1.2.4",
+ "1.2.5",
+ "1.2.6",
+ "1.2.7",
+ "1.2.8",
+ "2.1",
+ "2.2",
+ "2.3",
+ "2.4",
+ "2.5",
+ "2.6",
+ "2.7",
+ "2.8",
+ "2.9",
+ "2.10",
+ "2.11",
+ "3.1",
+ "3.2",
+ "3.3",
+ "3.4",
+ "3.5",
+ "3.6",
+ "3.7"
+ ]
+}
@@ -1,40 +1,32 @@
package org.webbitserver.netty;
import org.jboss.netty.buffer.ChannelBuffer;
+import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.handler.codec.frame.CorruptedFrameException;
import org.jboss.netty.handler.codec.frame.TooLongFrameException;
-import org.jboss.netty.handler.codec.http.websocket.DefaultWebSocketFrame;
import org.jboss.netty.handler.codec.replay.ReplayingDecoder;
import java.util.ArrayList;
import java.util.List;
-import static java.lang.Integer.toHexString;
-
public class Hybi10WebSocketFrameDecoder extends ReplayingDecoder<Hybi10WebSocketFrameDecoder.State> {
- private static final byte OPCODE_CONT = 0x0;
- private static final byte OPCODE_TEXT = 0x1;
- private static final byte OPCODE_BINARY = 0x2;
- private static final byte OPCODE_CLOSE = 0x8;
- private static final byte OPCODE_PING = 0x9;
- private static final byte OPCODE_PONG = 0xA;
-
- public static final int MAX_LENGTH = 16384;
-
- private Byte fragmentOpcode;
- private Byte opcode = null;
- private int currentFrameLength;
+ private long framePayloadLen;
private ChannelBuffer maskingKey;
private List<ChannelBuffer> frames = new ArrayList<ChannelBuffer>();
+ private boolean isServer = true;
+ private boolean requireMaskedClientFrames = true;
+ private boolean insideMessage;
+ private byte frameOpcode;
+ private Byte fragmentOpcode;
+ private boolean frameFin;
+ private int frameRsv;
+
public static enum State {
FRAME_START,
- PARSING_LENGTH,
MASKING_KEY,
- PARSING_LENGTH_2,
- PARSING_LENGTH_3,
PAYLOAD
}
@@ -46,75 +38,92 @@ public Hybi10WebSocketFrameDecoder() {
protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, State state) throws Exception {
switch (state) {
case FRAME_START:
+ // FIN, RSV, OPCODE
byte b = buffer.readByte();
- byte fin = (byte) (b & 0x80);
- byte reserved = (byte) (b & 0x70);
- byte opcode = (byte) (b & 0x0F);
+ frameFin = (b & 0x80) != 0;
+ frameRsv = (b & 0x70) >> 4;
+ frameOpcode = (byte) (b & 0x0F);
+
+ // MASK, PAYLOAD LEN 1
+ b = buffer.readByte();
+ boolean frameMasked = (b & 0x80) != 0;
+ int framePayloadLen1 = (b & 0x7F);
- if (reserved != 0) {
- throw new CorruptedFrameException("Reserved bits set: " + toZeroPaddedBinaryString(b));
+ if (frameRsv != 0) {
+ throw new CorruptedFrameException("RSV != 0 and no extension negotiated");
}
- if (!isOpcode(opcode)) {
- throw new CorruptedFrameException("Invalid opcode " + toHexString(b));
+
+ if (isServer && requireMaskedClientFrames && !frameMasked) {
+ throw new CorruptedFrameException("unmasked client to server frame");
}
- if (fin == 0) {
- if (fragmentOpcode == null) {
- if (!isDataOpcode(opcode)) {
- throw new CorruptedFrameException("Fragmented frame with invalid opcode " + toHexString(opcode));
- }
- fragmentOpcode = opcode;
- } else if (opcode != OPCODE_CONT) {
- throw new CorruptedFrameException("Continuation frame with invalid opcode " + toHexString(opcode));
+ if (frameOpcode > 7) { // control frame (have MSB in opcode set)
+
+ // control frames MUST NOT be fragmented
+ if (!frameFin) {
+ throw new CorruptedFrameException("fragmented control frame");
}
- } else {
- if (fragmentOpcode != null) {
- if (!isControlOpcode(opcode) && opcode != OPCODE_CONT) {
- throw new CorruptedFrameException("Final frame with invalid opcode " + toHexString(opcode));
- }
- } else if (opcode == OPCODE_CONT) {
- throw new CorruptedFrameException("Final frame with invalid opcode " + toHexString(opcode));
+
+ // control frames MUST have payload 125 octets or less
+ if (framePayloadLen1 > 125) {
+ throw new CorruptedFrameException("control frame with payload length > 125 octets");
}
- this.opcode = opcode;
- }
- checkpoint(State.PARSING_LENGTH);
- case PARSING_LENGTH:
- b = buffer.readByte();
- byte masked = (byte) (b & 0x80);
- if (masked == 0) {
- throw new CorruptedFrameException("Unmasked frame received");
+ // check for reserved control frame opcodes
+ if (!(frameOpcode == Opcodes.OPCODE_CLOSE || frameOpcode == Opcodes.OPCODE_PING || frameOpcode == Opcodes.OPCODE_PONG)) {
+ throw new CorruptedFrameException("control frame using reserved opcode " + frameOpcode);
+ }
+
+ // close frame : if there is a body, the first two bytes of the body MUST be a 2-byte
+ // unsigned integer (in network byte order) representing a status code
+ if (frameOpcode == 8 && framePayloadLen1 == 1) {
+ throw new CorruptedFrameException("received close control frame with payload len 1");
+ }
+ } else { // data frame
+ // check for reserved data frame opcodes
+ if (!(frameOpcode == Opcodes.OPCODE_CONT || frameOpcode == Opcodes.OPCODE_TEXT || frameOpcode == Opcodes.OPCODE_BINARY)) {
+ throw new CorruptedFrameException("data frame using reserved opcode " + frameOpcode);
+ }
+
+// // check opcode vs message fragmentation state 1/2
+// if (!insideMessage && frameOpcode == OPCODE_CONT) {
+// throw new CorruptedFrameException("received continuation data frame outside fragmented message");
+// }
+//
+// // check opcode vs message fragmentation state 2/2
+// if (insideMessage && frameOpcode != OPCODE_CONT) {
+// throw new CorruptedFrameException("received non-continuation data frame while inside fragmented message");
+// }
}
- int length = (byte) (b & 0x7F);
+ int maskLen = frameMasked ? 4 : 0;
+
+ if (framePayloadLen1 == 126) {
+ framePayloadLen = buffer.readUnsignedShort();
+ if (framePayloadLen < 126) {
+ throw new CorruptedFrameException("invalid data frame length (not using minimal length encoding)");
+ }
+ } else if (framePayloadLen1 == 127) {
+ framePayloadLen = buffer.readLong();
+ // TODO: check if it's bigger than 0x7FFFFFFFFFFFFFFF, Maybe just check if it's negative?
- if (length < 126) {
- currentFrameLength = length;
- checkpoint(State.MASKING_KEY);
- } else if (length == 126) {
- checkpoint(State.PARSING_LENGTH_2);
- } else if (length == 127) {
- checkpoint(State.PARSING_LENGTH_3);
+ if (framePayloadLen < 65536) {
+ throw new CorruptedFrameException("invalid data frame length (not using minimal length encoding)");
+ }
+ } else {
+ framePayloadLen = framePayloadLen1;
}
- return null;
- case PARSING_LENGTH_2:
- currentFrameLength = buffer.readShort() & 0xFFFF;
- checkpoint(State.MASKING_KEY);
- return null;
- case PARSING_LENGTH_3:
- currentFrameLength = buffer.readInt() & 0xFFFFFFFF;
checkpoint(State.MASKING_KEY);
return null;
case MASKING_KEY:
maskingKey = buffer.readBytes(4);
checkpoint(State.PAYLOAD);
case PAYLOAD:
- ChannelBuffer frame = buffer.readBytes(currentFrameLength);
- checkpoint(State.FRAME_START);
+ ChannelBuffer frame = buffer.readBytes(toFrameLength(framePayloadLen));
unmask(frame);
- if (this.opcode == OPCODE_CONT) {
- this.opcode = fragmentOpcode;
+ if (frameOpcode == Opcodes.OPCODE_CONT) {
+ frameOpcode = fragmentOpcode;
frames.add(frame);
frame = channel.getConfig().getBufferFactory().getBuffer(0);
@@ -125,57 +134,36 @@ protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffe
this.fragmentOpcode = null;
frames.clear();
- }
-
- if (this.opcode == OPCODE_TEXT) {
- if (frame.readableBytes() > MAX_LENGTH) {
- throw new TooLongFrameException();
+ } else {
+ checkpoint(State.FRAME_START);
+ if (frameOpcode == Opcodes.OPCODE_TEXT || frameOpcode == Opcodes.OPCODE_BINARY || frameOpcode == Opcodes.OPCODE_PONG) {
+ return new HybiFrame(frameOpcode, frameFin, frameRsv, frame);
+ } else if (frameOpcode == Opcodes.OPCODE_PING) {
+ channel.write(new HybiFrame(Opcodes.OPCODE_PONG, true, 0, frame));
+ return null;
+ } else if (frameOpcode == Opcodes.OPCODE_CLOSE) {
+ channel.write(new HybiFrame(Opcodes.OPCODE_CLOSE, true, 0, ChannelBuffers.buffer(0)));
+ channel.close();
+ return null;
}
- return new DefaultWebSocketFrame(0x00, frame);
- } else if (this.opcode == OPCODE_BINARY) {
- return new DefaultWebSocketFrame(0xFF, frame);
- } else if (this.opcode == OPCODE_PING) {
- channel.write(new Pong(0x00, frame));
- return null;
- } else if (this.opcode == OPCODE_PONG) {
- return new Pong(0x00, frame);
- } else if (this.opcode == OPCODE_CLOSE) {
- // TODO
- return null;
}
default:
throw new Error("Shouldn't reach here.");
}
}
+ private int toFrameLength(long l) throws TooLongFrameException {
+ if (l > Integer.MAX_VALUE) {
+ throw new TooLongFrameException("Length:" + l);
+ } else {
+ return (int) l;
+ }
+ }
+
private void unmask(ChannelBuffer frame) {
byte[] bytes = frame.array();
for (int i = 0; i < bytes.length; i++) {
frame.setByte(i, frame.getByte(i) ^ maskingKey.getByte(i % 4));
}
}
-
- private String toZeroPaddedBinaryString(byte b) {
- return String.format("%8s", Integer.toBinaryString(b)).replace(" ", "0");
- }
-
- private boolean isOpcode(int opcode) {
- return opcode == OPCODE_CONT ||
- opcode == OPCODE_TEXT ||
- opcode == OPCODE_BINARY ||
- opcode == OPCODE_CLOSE ||
- opcode == OPCODE_PING ||
- opcode == OPCODE_PONG;
- }
-
- private boolean isControlOpcode(int opcode) {
- return opcode == OPCODE_CLOSE ||
- opcode == OPCODE_PING ||
- opcode == OPCODE_PONG;
- }
-
- private boolean isDataOpcode(int opcode) {
- return opcode == OPCODE_TEXT ||
- opcode == OPCODE_BINARY;
- }
}
Oops, something went wrong. Retry.

0 comments on commit b7b9624

Please sign in to comment.