Adding ClosePayloadParser & Tests

This commit is contained in:
Joakim Erdfelt 2012-06-20 14:43:16 -07:00
parent b61a58ad64
commit 1692b4f7c2
6 changed files with 145 additions and 36 deletions

View File

@ -8,7 +8,7 @@ import org.eclipse.jetty.websocket.api.WebSocket;
*/
public class CloseFrame extends ControlFrame
{
private final short statusCode;
private short statusCode;
private String reason;
public CloseFrame()
@ -43,6 +43,11 @@ public class CloseFrame extends ControlFrame
this.reason = reason;
}
public void setStatusCode(short statusCode)
{
this.statusCode = statusCode;
}
@Override
public String toString()
{

View File

@ -2,6 +2,8 @@ package org.eclipse.jetty.websocket.parser;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.CloseFrame;
@ -11,6 +13,8 @@ import org.eclipse.jetty.websocket.frames.CloseFrame;
public class ClosePayloadParser extends FrameParser<CloseFrame>
{
private CloseFrame frame;
private ByteBuffer payload;
private int payloadLength;
public ClosePayloadParser(WebSocketPolicy policy)
{
@ -34,7 +38,35 @@ public class ClosePayloadParser extends FrameParser<CloseFrame>
@Override
public boolean parsePayload(ByteBuffer buffer)
{
// TODO Auto-generated method stub
payloadLength = getFrame().getPayloadLength();
if (payloadLength == 0)
{
// no status code. no reason.
return true;
}
while (buffer.hasRemaining())
{
if (payload == null)
{
getPolicy().assertValidBinaryMessageSize(payloadLength);
payload = ByteBuffer.allocate(payloadLength);
}
copyBuffer(buffer,payload,payload.remaining());
if (payload.position() >= payloadLength)
{
payload.flip();
frame.setStatusCode(payload.getShort());
if (payload.remaining() > 0)
{
String reason = BufferUtil.toString(payload,StringUtil.__UTF8_CHARSET);
frame.setReason(reason);
}
return true;
}
}
return false;
}

View File

@ -109,7 +109,13 @@ public class Parser
boolean rsv1 = ((b & 0x40) != 0);
boolean rsv2 = ((b & 0x20) != 0);
boolean rsv3 = ((b & 0x10) != 0);
OpCode opcode = OpCode.from((byte)(b & 0x0F));
byte opc = (byte)(b & 0x0F);
OpCode opcode = OpCode.from(opc);
if (opcode == null)
{
throw new WebSocketException("Unknown opcode: " + opc);
}
if (opcode.isControlFrame() && !fin)
{

View File

@ -0,0 +1,50 @@
package org.eclipse.jetty.websocket.parser;
import static org.hamcrest.Matchers.*;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.Debug;
import org.eclipse.jetty.websocket.api.WebSocket;
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.CloseFrame;
import org.junit.Assert;
import org.junit.Test;
public class ClosePayloadParserTest
{
@Test
public void testGameOver()
{
Debug.enableDebugLogging(Parser.class);
Debug.enableDebugLogging(ClosePayloadParser.class);
String expectedReason = "Game Over";
byte utf[] = expectedReason.getBytes(StringUtil.__UTF8_CHARSET);
ByteBuffer payload = ByteBuffer.allocate(utf.length + 2);
payload.putShort(WebSocket.CLOSE_NORMAL);
payload.put(utf,0,utf.length);
payload.flip();
ByteBuffer buf = ByteBuffer.allocate(24);
buf.put((byte)(0x80 | 0x08)); // fin + close
buf.put((byte)(0x80 | payload.remaining()));
MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,payload);
buf.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(buf);
capture.assertNoErrors();
capture.assertHasFrame(CloseFrame.class,1);
CloseFrame txt = (CloseFrame)capture.getFrames().get(0);
Assert.assertThat("CloseFrame.statusCode",txt.getStatusCode(),is(WebSocket.CLOSE_NORMAL));
Assert.assertThat("CloseFrame.data",txt.getReason(),is(expectedReason));
}
}

View File

@ -0,0 +1,32 @@
package org.eclipse.jetty.websocket.parser;
import java.nio.ByteBuffer;
public class MaskedByteBuffer
{
private static byte[] mask = new byte[]
{ 0x00, (byte)0xF0, 0x0F, (byte)0xFF };
public static void putMask(ByteBuffer buffer)
{
buffer.put(mask,0,mask.length);
}
public static void putPayload(ByteBuffer buffer, byte[] payload)
{
int len = payload.length;
for (int i = 0; i < len; i++)
{
buffer.put((byte)(payload[i] ^ mask[i % 4]));
}
}
public static void putPayload(ByteBuffer buffer, ByteBuffer payload)
{
int len = payload.remaining();
for (int i = 0; i < len; i++)
{
buffer.put((byte)(payload.get() ^ mask[i % 4]));
}
}
}

View File

@ -16,11 +16,8 @@ import org.junit.Test;
public class TextPayloadParserTest
{
private final byte[] mask = new byte[]
{ 0x00, (byte)0xF0, 0x0F, (byte)0xFF };
@Test
public void testFrameTooLargeDueToPolicyText() throws Exception
public void testFrameTooLargeDueToPolicy() throws Exception
{
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setMaxTextMessageSize(1024); // set policy
@ -33,8 +30,8 @@ public class TextPayloadParserTest
buf.put((byte)0x81);
buf.put((byte)(0x80 | 0x7E)); // 0x7E == 126 (a 2 byte payload length)
buf.putShort((short)utf.length);
writeMask(buf);
writeMaskedPayload(buf,utf);
MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,utf);
buf.flip();
Parser parser = new Parser(policy);
@ -68,8 +65,8 @@ public class TextPayloadParserTest
buf.put((byte)0x81);
buf.put((byte)(0x80 | 0x7F)); // 0x7F == 127 (a 4 byte payload length)
buf.putInt(utf.length);
writeMask(buf);
writeMaskedPayload(buf,utf);
MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,utf);
buf.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
@ -103,8 +100,8 @@ public class TextPayloadParserTest
buf.put((byte)0x81);
buf.put((byte)(0x80 | 0x7E)); // 0x7E == 126 (a 2 byte payload length)
buf.putShort((short)utf.length);
writeMask(buf);
writeMaskedPayload(buf,utf);
MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,utf);
buf.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
@ -133,14 +130,14 @@ public class TextPayloadParserTest
// part 1
buf.put((byte)0x01); // no fin + text
buf.put((byte)(0x80 | b1.length));
writeMask(buf);
writeMaskedPayload(buf,b1);
MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,b1);
// part 2
buf.put((byte)0x80); // fin + continuation
buf.put((byte)(0x80 | b2.length));
writeMask(buf);
writeMaskedPayload(buf,b2);
MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,b2);
buf.flip();
@ -162,12 +159,13 @@ public class TextPayloadParserTest
public void testShortMaskedText() throws Exception
{
String expectedText = "Hello World";
byte utf[] = expectedText.getBytes(StringUtil.__UTF8_CHARSET);
ByteBuffer buf = ByteBuffer.allocate(24);
buf.put((byte)0x81);
buf.put((byte)(0x80 | expectedText.length()));
writeMask(buf);
writeMaskedPayload(buf,expectedText.getBytes(StringUtil.__UTF8));
buf.put((byte)(0x80 | utf.length));
MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,utf);
buf.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
@ -192,8 +190,8 @@ public class TextPayloadParserTest
ByteBuffer buf = ByteBuffer.allocate(24);
buf.put((byte)0x81);
buf.put((byte)(0x80 | utf.length));
writeMask(buf);
writeMaskedPayload(buf,utf);
MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,utf);
buf.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
@ -207,18 +205,4 @@ public class TextPayloadParserTest
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText));
}
private void writeMask(ByteBuffer buf)
{
buf.put(mask,0,mask.length);
}
private void writeMaskedPayload(ByteBuffer buf, byte[] bytes)
{
int len = bytes.length;
for (int i = 0; i < len; i++)
{
buf.put((byte)(bytes[i] ^ mask[i % 4]));
}
}
}