Merge branch 'jetty-9' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project into jetty-9
This commit is contained in:
commit
a6bc9c1845
|
@ -9,18 +9,18 @@ import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
*/
|
*/
|
||||||
public class CloseFrame extends ControlFrame
|
public class CloseFrame extends ControlFrame
|
||||||
{
|
{
|
||||||
private short statusCode;
|
private int statusCode = 0;
|
||||||
private String reason;
|
private String reason;
|
||||||
|
|
||||||
public CloseFrame()
|
public CloseFrame()
|
||||||
{
|
{
|
||||||
this(StatusCode.NORMAL); // TODO: evaluate default (or unspecified status code)
|
super(OpCode.CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CloseFrame(short statusCode)
|
public CloseFrame(int statusCode)
|
||||||
{
|
{
|
||||||
super(OpCode.CLOSE);
|
super(OpCode.CLOSE);
|
||||||
this.statusCode = statusCode;
|
setStatusCode(statusCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getReason()
|
public String getReason()
|
||||||
|
@ -28,7 +28,7 @@ public class CloseFrame extends ControlFrame
|
||||||
return reason;
|
return reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
public short getStatusCode()
|
public int getStatusCode()
|
||||||
{
|
{
|
||||||
return statusCode;
|
return statusCode;
|
||||||
}
|
}
|
||||||
|
@ -43,8 +43,13 @@ public class CloseFrame extends ControlFrame
|
||||||
this.reason = reason;
|
this.reason = reason;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatusCode(short statusCode)
|
public void setStatusCode(int statusCode)
|
||||||
{
|
{
|
||||||
|
if ( ( statusCode <= 999) || ( statusCode > 65535 ) )
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException("Status Codes must be in the range 1000 - 65535");
|
||||||
|
}
|
||||||
|
|
||||||
this.statusCode = statusCode;
|
this.statusCode = statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,7 +64,7 @@ public abstract class ControlFrame extends BaseFrame
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void setPayload(byte[] buf)
|
public void setPayload(byte[] buf)
|
||||||
{
|
{
|
||||||
if ( buf.length > 125 )
|
if ( buf.length > 125 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.eclipse.jetty.websocket.generator;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||||
import org.eclipse.jetty.websocket.frames.CloseFrame;
|
import org.eclipse.jetty.websocket.frames.CloseFrame;
|
||||||
|
|
||||||
|
@ -16,11 +17,23 @@ public class CloseFrameGenerator extends FrameGenerator<CloseFrame>
|
||||||
@Override
|
@Override
|
||||||
public void fillPayload(ByteBuffer buffer, CloseFrame close)
|
public void fillPayload(ByteBuffer buffer, CloseFrame close)
|
||||||
{
|
{
|
||||||
buffer.putShort(close.getStatusCode());
|
if ( close.getStatusCode() != 0 )
|
||||||
if (close.hasReason())
|
|
||||||
{
|
{
|
||||||
byte utf[] = close.getReason().getBytes(StringUtil.__UTF8_CHARSET);
|
buffer.putChar((char)close.getStatusCode()); // char is unsigned 16
|
||||||
buffer.put(utf,0,utf.length);
|
|
||||||
|
// payload requires a status code in order to be written
|
||||||
|
if ( close.hasPayload() )
|
||||||
|
{
|
||||||
|
if (close.hasReason())
|
||||||
|
{
|
||||||
|
byte utf[] = close.getReason().getBytes(StringUtil.__UTF8_CHARSET);
|
||||||
|
buffer.put(utf,0,utf.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( close.hasPayload() )
|
||||||
|
{
|
||||||
|
throw new WebSocketException("Close frames require setting a status code if using payload.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||||
import org.eclipse.jetty.websocket.frames.CloseFrame;
|
import org.eclipse.jetty.websocket.frames.CloseFrame;
|
||||||
|
|
||||||
|
@ -45,6 +46,14 @@ public class ClosePayloadParser extends FrameParser<CloseFrame>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* invalid payload length and protects payload.getShort() call below from
|
||||||
|
* pulling too many bytes from buffer.
|
||||||
|
*/
|
||||||
|
if ( payloadLength == 1 )
|
||||||
|
{
|
||||||
|
throw new WebSocketException("Close: invalid payload length: 1");
|
||||||
|
}
|
||||||
|
|
||||||
while (buffer.hasRemaining())
|
while (buffer.hasRemaining())
|
||||||
{
|
{
|
||||||
if (payload == null)
|
if (payload == null)
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
package org.eclipse.jetty.websocket.ab;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
public class ABCase7_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);
|
||||||
|
|
||||||
|
String message = "*";
|
||||||
|
byte[] messageBytes = message.getBytes();
|
||||||
|
|
||||||
|
ByteBuffer expected = ByteBuffer.allocate(32);
|
||||||
|
|
||||||
|
expected.put(new byte[]
|
||||||
|
{ (byte)0x88 });
|
||||||
|
|
||||||
|
byte b = 0x00; // no masking
|
||||||
|
b |= messageBytes.length & 0x7F;
|
||||||
|
expected.put(b);
|
||||||
|
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("undefined option should be in message",known.getMessage().contains("invalid payload length"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ public class ClosePayloadParserTest
|
||||||
capture.assertNoErrors();
|
capture.assertNoErrors();
|
||||||
capture.assertHasFrame(CloseFrame.class,1);
|
capture.assertHasFrame(CloseFrame.class,1);
|
||||||
CloseFrame txt = (CloseFrame)capture.getFrames().get(0);
|
CloseFrame txt = (CloseFrame)capture.getFrames().get(0);
|
||||||
Assert.assertThat("CloseFrame.statusCode",txt.getStatusCode(),is(StatusCode.NORMAL));
|
Assert.assertThat("CloseFrame.statusCode",(short)txt.getStatusCode(),is(StatusCode.NORMAL));
|
||||||
Assert.assertThat("CloseFrame.data",txt.getReason(),is(expectedReason));
|
Assert.assertThat("CloseFrame.data",txt.getReason(),is(expectedReason));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue