tossing exceptions on a couple more edgecases and additional tests on close

This commit is contained in:
Jesse McConnell 2012-06-28 16:32:50 -05:00
parent 9cd2f887d1
commit 153daf4f3b
4 changed files with 279 additions and 95 deletions

View File

@ -2,7 +2,6 @@ package org.eclipse.jetty.websocket.frames;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.api.OpCode;
@ -17,8 +16,6 @@ public class CloseFrame extends ControlFrame
public CloseFrame()
{
super(OpCode.CLOSE);
// no status code, no reason
setPayload(BufferUtil.EMPTY_BUFFER);
}
/**
@ -46,6 +43,11 @@ public class CloseFrame extends ControlFrame
throw new IllegalArgumentException("Status Codes must be in the range 1000 - 65535");
}
if ((reason != null) && (reason.length() > 123))
{
throw new IllegalArgumentException("Reason must not exceed 123 characters.");
}
byte utf[] = null;
int len = 2; // status code
if (StringUtil.isNotBlank(reason))

View File

@ -20,10 +20,10 @@ public class CloseFrameGenerator extends FrameGenerator<CloseFrame>
if ( close.getStatusCode() != 0 )
{
buffer.putChar((char)close.getStatusCode()); // char is unsigned 16
// payload requires a status code in order to be written
if ( close.hasPayload() )
{
{
if (close.hasReason())
{
byte utf[] = close.getReason().getBytes(StringUtil.__UTF8_CHARSET);
@ -31,7 +31,7 @@ public class CloseFrameGenerator extends FrameGenerator<CloseFrame>
}
}
}
else if ( close.hasPayload() )
else if (close.hasPayload())
{
throw new WebSocketException("Close frames require setting a status code if using payload.");
}

View File

@ -47,9 +47,9 @@ public class ClosePayloadParser extends FrameParser<CloseFrame>
/*
* invalid payload length.
*/
if (payloadLength == 1)
if ((payloadLength == 1) || (payloadLength > 125))
{
throw new WebSocketException("Close: invalid payload length: 1");
throw new WebSocketException("Close: invalid payload length: " + payloadLength);
}
if (payload == null)

View File

@ -4,19 +4,15 @@ import static org.hamcrest.Matchers.is;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.websocket.ByteBufferAssert;
import org.eclipse.jetty.websocket.Debug;
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.CloseFrame;
import org.eclipse.jetty.websocket.frames.PingFrame;
import org.eclipse.jetty.websocket.frames.TextFrame;
import org.eclipse.jetty.websocket.generator.Generator;
import org.eclipse.jetty.websocket.parser.FrameParseCapture;
import org.eclipse.jetty.websocket.parser.Parser;
import org.eclipse.jetty.websocket.parser.PingPayloadParser;
import org.junit.Assert;
import org.junit.Test;
@ -24,90 +20,21 @@ public class TestABCase7_3
{
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
@Test
public void testGenerateEmptyCloseCase7_3_1()
{
CloseFrame closeFrame = new CloseFrame();
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(32);
generator.generate(actual, closeFrame);
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x88, (byte)0x00 });
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParseEmptyCloseCase7_3_1()
{
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x88, (byte)0x00 });
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(CloseFrame.class,1);
CloseFrame pActual = (CloseFrame)capture.getFrames().get(0);
Assert.assertThat("CloseFrame.payloadLength",pActual.getPayloadLength(),is(0));
ByteBufferAssert.assertSize("CloseFrame.payload",0,pActual.getPayload());
}
@Test (expected = WebSocketException.class)
public void testGenerate1BytePayloadCloseCase7_3_2()
{
CloseFrame pingFrame = new CloseFrame();
pingFrame.setPayload(new byte[] {0x00});
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(32);
generator.generate(actual, pingFrame);
}
@Test
public void testParse1BytePayloadCloseCase7_3_2()
{
Debug.enableDebugLogging(Parser.class);
ByteBuffer expected = ByteBuffer.allocate(32);
expected.put(new byte[]
{ (byte)0x88, 0x01, 0x00 });
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
Assert.assertEquals( "error on invalid close payload", 1, capture.getErrorCount(WebSocketException.class)) ;
WebSocketException known = capture.getErrors().get(0);
Assert.assertTrue("invalid payload should be in message",known.getMessage().contains("invalid payload length"));
}
@Test
public void testGenerateCloseWithStatusCase7_3_3()
{
CloseFrame closeFrame = new CloseFrame(1000);
CloseFrame closeFrame = new CloseFrame(1000);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(32);
@ -117,35 +44,290 @@ public class TestABCase7_3
expected.put(new byte[]
{ (byte)0x88, (byte)0x02, 0x03, (byte)0xe8 });
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParseCloseWithStatusCase7_3_3()
{
public void testGenerateCloseWithStatusMaxReasonCase7_3_5()
{
StringBuilder message = new StringBuilder();
for ( int i = 0 ; i < 123 ; ++i )
{
message.append("*");
}
byte[] messageBytes = message.toString().getBytes();
CloseFrame closeFrame = new CloseFrame(1000, message.toString());
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(132);
generator.generate(actual, closeFrame);
ByteBuffer expected = ByteBuffer.allocate(132);
expected.put(new byte[]
{ (byte)0x88 });
byte b = 0x00; // no masking
b |= (messageBytes.length + 2) & 0x7F;
expected.put(b);
expected.putShort((short)1000);
expected.put(messageBytes);
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test (expected = IllegalArgumentException.class )
public void testGenerateCloseWithStatusMaxReasonCase7_3_6()
{
StringBuilder message = new StringBuilder();
for ( int i = 0 ; i < 124 ; ++i )
{
message.append("*");
}
byte[] messageBytes = message.toString().getBytes();
CloseFrame closeFrame = new CloseFrame(1000, message.toString());
}
@Test
public void testGenerateCloseWithStatusReasonCase7_3_4()
{
String message = "bad cough";
byte[] messageBytes = message.getBytes();
CloseFrame closeFrame = new CloseFrame(1000, message);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(32);
generator.generate(actual, closeFrame);
ByteBuffer expected = ByteBuffer.allocate(32);
expected.put(new byte[]
{ (byte)0x88 });
byte b = 0x00; // no masking
b |= (message.length() + 2) & 0x7F;
expected.put(b);
expected.putShort((short)1000);
expected.put(messageBytes);
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testGenerateEmptyCloseCase7_3_1()
{
CloseFrame closeFrame = new CloseFrame();
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(32);
generator.generate(actual, closeFrame);
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x88, (byte)0x00 });
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParse1BytePayloadCloseCase7_3_2()
{
Debug.enableDebugLogging(Parser.class);
ByteBuffer expected = ByteBuffer.allocate(32);
expected.put(new byte[]
{ (byte)0x88, 0x01, 0x00 });
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
Assert.assertEquals( "error on invalid close payload", 1, capture.getErrorCount(WebSocketException.class)) ;
WebSocketException known = capture.getErrors().get(0);
Assert.assertTrue("invalid payload should be in message",known.getMessage().contains("invalid payload length"));
}
@Test
public void testParseCloseWithStatusCase7_3_3()
{
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x88, (byte)0x02, 0x03, (byte)0xe8 });
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(CloseFrame.class,1);
CloseFrame pActual = (CloseFrame)capture.getFrames().get(0);
Assert.assertThat("CloseFrame.payloadLength",pActual.getPayloadLength(),is(2));
ByteBufferAssert.assertSize("CloseFrame.payload",2,pActual.getPayload());
}
@Test
public void testParseCloseWithStatusMaxReasonCase7_3_5()
{
StringBuilder message = new StringBuilder();
for ( int i = 0 ; i < 123 ; ++i )
{
message.append("*");
}
byte[] messageBytes = message.toString().getBytes();
ByteBuffer expected = ByteBuffer.allocate(132);
expected.put(new byte[]
{ (byte)0x88 });
byte b = 0x00; // no masking
b |= (messageBytes.length + 2) & 0x7F;
expected.put(b);
expected.putShort((short)1000);
expected.put(messageBytes);
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(CloseFrame.class,1);
CloseFrame pActual = (CloseFrame)capture.getFrames().get(0);
Assert.assertThat("CloseFrame.payloadLength",pActual.getPayloadLength(),is(125));
ByteBufferAssert.assertSize("CloseFrame.payload", 125,pActual.getPayload());
}
@Test
public void testParseCloseWithStatusMaxReasonCase7_3_6()
{
StringBuilder message = new StringBuilder();
for ( int i = 0 ; i < 124 ; ++i )
{
message.append("*");
}
byte[] messageBytes = message.toString().getBytes();
ByteBuffer expected = ByteBuffer.allocate(132);
expected.put(new byte[]
{ (byte)0x88 });
byte b = 0x00; // no masking
b |= (messageBytes.length + 2) & 0x7F;
expected.put(b);
expected.putShort((short)1000);
expected.put(messageBytes);
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
Assert.assertEquals( "error on invalid close payload", 1, capture.getErrorCount(WebSocketException.class)) ;
WebSocketException known = capture.getErrors().get(0);
Assert.assertTrue("invalid payload should be in message",known.getMessage().contains("invalid payload length"));
}
@Test
public void testParseCloseWithStatusReasonCase7_3_4()
{
String message = "bad cough";
byte[] messageBytes = message.getBytes();
ByteBuffer expected = ByteBuffer.allocate(32);
expected.put(new byte[]
{ (byte)0x88 });
byte b = 0x00; // no masking
b |= (messageBytes.length + 2) & 0x7F;
expected.put(b);
expected.putShort((short)1000);
expected.put(messageBytes);
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(CloseFrame.class,1);
CloseFrame pActual = (CloseFrame)capture.getFrames().get(0);
Assert.assertThat("CloseFrame.payloadLength",pActual.getPayloadLength(),is(messageBytes.length + 2));
ByteBufferAssert.assertSize("CloseFrame.payload",messageBytes.length + 2,pActual.getPayload());
}
@Test
public void testParseEmptyCloseCase7_3_1()
{
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x88, (byte)0x00 });
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(CloseFrame.class,1);
CloseFrame pActual = (CloseFrame)capture.getFrames().get(0);
Assert.assertThat("CloseFrame.payloadLength",pActual.getPayloadLength(),is(0));
ByteBufferAssert.assertSize("CloseFrame.payload",0,pActual.getPayload());
ByteBufferAssert.assertSize("CloseFrame.payload",0,pActual.getPayload());
}
}