Making WebSocketFrame use builder pattern

This commit is contained in:
Joakim Erdfelt 2012-07-10 11:12:10 -07:00
parent 20876011e0
commit c2f1d23f2b
6 changed files with 191 additions and 32 deletions

View File

@ -199,4 +199,5 @@ public class WebSocketPolicy
{ {
this.maxTextMessageSize = maxTextMessageSize; this.maxTextMessageSize = maxTextMessageSize;
} }
} }

View File

@ -46,26 +46,57 @@ public class Generator
public static final int OVERHEAD = 28; public static final int OVERHEAD = 28;
private final WebSocketPolicy policy; private final WebSocketPolicy policy;
private static ByteBufferPool bufferPool; private final ByteBufferPool bufferPool;
private boolean validating;
/**
*
* @param policy
* @deprecated discouraged usage form
*/
@Deprecated
public Generator(WebSocketPolicy policy) public Generator(WebSocketPolicy policy)
{ {
this.policy = policy; this(policy,new StandardByteBufferPool());
if (this.bufferPool == null)
{
this.bufferPool = new StandardByteBufferPool();
}
} }
/**
* Construct Generator with provided policy and bufferPool
*
* @param policy
* the policy to use
* @param bufferPool
* the buffer pool to use
*/
public Generator(WebSocketPolicy policy, ByteBufferPool bufferPool) public Generator(WebSocketPolicy policy, ByteBufferPool bufferPool)
{
this(policy,bufferPool,true);
}
/**
* Construct Generator with provided policy and bufferPool
*
* @param policy
* the policy to use
* @param bufferPool
* the buffer pool to use
* @param validating
* true to enable RFC frame validation
*/
public Generator(WebSocketPolicy policy, ByteBufferPool bufferPool, boolean validating)
{ {
this.policy = policy; this.policy = policy;
this.bufferPool = bufferPool; this.bufferPool = bufferPool;
this.validating = validating;
} }
public void assertFrameValid(WebSocketFrame frame) public void assertFrameValid(WebSocketFrame frame)
{ {
if (!validating)
{
return;
}
/* /*
* RFC 6455 Section 5.2 * RFC 6455 Section 5.2
* *
@ -262,11 +293,6 @@ public class Generator
return generate(bufferSize,frame); return generate(bufferSize,frame);
} }
public void init(ByteBufferPool pool)
{
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -3,6 +3,7 @@ package org.eclipse.jetty.websocket.protocol;
import java.nio.ByteBuffer; 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.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.api.ProtocolException; import org.eclipse.jetty.websocket.api.ProtocolException;
@ -66,11 +67,42 @@ public class CloseInfo
} }
} }
public CloseInfo(int statusCode, String reason)
{
this.statusCode = statusCode;
this.reason = reason;
}
public CloseInfo(WebSocketFrame frame) public CloseInfo(WebSocketFrame frame)
{ {
this(frame.getPayload(),false); this(frame.getPayload(),false);
} }
public ByteBuffer asByteBuffer()
{
if (statusCode != (-1))
{
ByteBuffer buf = ByteBuffer.allocate(WebSocketFrame.MAX_CONTROL_PAYLOAD);
buf.putChar((char)statusCode);
if (StringUtil.isNotBlank(reason))
{
byte utf[] = StringUtil.getUtf8Bytes(reason);
buf.put(utf,0,utf.length);
}
BufferUtil.flipToFlush(buf,0);
return buf;
}
return null;
}
public WebSocketFrame asFrame()
{
WebSocketFrame frame = new WebSocketFrame(OpCode.CLOSE);
frame.setFin(true);
frame.setPayload(asByteBuffer());
return frame;
}
public String getReason() public String getReason()
{ {
return reason; return reason;

View File

@ -18,9 +18,11 @@ import org.eclipse.jetty.websocket.generator.Generator;
*/ */
public class FrameBuilder public class FrameBuilder
{ {
/**
* A Generator that doesn't
*/
public class DirtyGenerator extends Generator public class DirtyGenerator extends Generator
{ {
public DirtyGenerator() public DirtyGenerator()
{ {
super(WebSocketPolicy.newServerPolicy(),bufferPool); super(WebSocketPolicy.newServerPolicy(),bufferPool);
@ -30,10 +32,9 @@ public class FrameBuilder
public void assertFrameValid(WebSocketFrame frame) public void assertFrameValid(WebSocketFrame frame)
{ {
/* /*
* we desire the ability to craft bad frames so ignore frame validation * Do no validation of the frame validity. <p> we desire the ability to craft bad frames so we'll ignore frame validation
*/ */
} }
} }
private static ByteBufferPool bufferPool = new StandardByteBufferPool(); private static ByteBufferPool bufferPool = new StandardByteBufferPool();

View File

@ -34,7 +34,7 @@ public class WebSocketFrame implements Frame
/** Maximum size of Control frame, per RFC 6455 */ /** Maximum size of Control frame, per RFC 6455 */
public static final int MAX_CONTROL_PAYLOAD = 125; public static final int MAX_CONTROL_PAYLOAD = 125;
private boolean fin = false; private boolean fin = true;
private boolean rsv1 = false; private boolean rsv1 = false;
private boolean rsv2 = false; private boolean rsv2 = false;
private boolean rsv3 = false; private boolean rsv3 = false;
@ -215,7 +215,7 @@ public class WebSocketFrame implements Frame
public void reset() public void reset()
{ {
fin = false; fin = true;
rsv1 = false; rsv1 = false;
rsv2 = false; rsv2 = false;
rsv3 = false; rsv3 = false;
@ -227,35 +227,41 @@ public class WebSocketFrame implements Frame
continuation = false; continuation = false;
} }
public void setContinuation(boolean continuation) public WebSocketFrame setContinuation(boolean continuation)
{ {
this.continuation = continuation; this.continuation = continuation;
return this;
} }
public void setContinuationIndex(int continuationIndex) public WebSocketFrame setContinuationIndex(int continuationIndex)
{ {
this.continuationIndex = continuationIndex; this.continuationIndex = continuationIndex;
return this;
} }
public void setFin(boolean fin) public WebSocketFrame setFin(boolean fin)
{ {
this.fin = fin; this.fin = fin;
return this;
} }
public void setMask(byte[] maskingKey) public WebSocketFrame setMask(byte[] maskingKey)
{ {
this.mask = maskingKey; this.mask = maskingKey;
this.masked = (mask != null); this.masked = (mask != null);
return this;
} }
public void setMasked(boolean mask) public WebSocketFrame setMasked(boolean mask)
{ {
this.masked = mask; this.masked = mask;
return this;
} }
public void setOpCode(OpCode opCode) public WebSocketFrame setOpCode(OpCode opCode)
{ {
this.opcode = opCode; this.opcode = opCode;
return this;
} }
/** /**
@ -264,12 +270,12 @@ public class WebSocketFrame implements Frame
* @param buf * @param buf
* the bytebuffer to set * the bytebuffer to set
*/ */
public void setPayload(byte buf[]) public WebSocketFrame setPayload(byte buf[])
{ {
if (buf == null) if (buf == null)
{ {
data = null; data = null;
return; return this;
} }
if (opcode.isControlFrame()) if (opcode.isControlFrame())
@ -284,6 +290,7 @@ public class WebSocketFrame implements Frame
data = ByteBuffer.allocate(len); data = ByteBuffer.allocate(len);
BufferUtil.clearToFill(data); BufferUtil.clearToFill(data);
data.put(buf,0,len); data.put(buf,0,len);
return this;
} }
/** /**
@ -292,12 +299,12 @@ public class WebSocketFrame implements Frame
* @param buf * @param buf
* the bytebuffer to set * the bytebuffer to set
*/ */
public void setPayload(byte buf[], int offset, int len) public WebSocketFrame setPayload(byte buf[], int offset, int len)
{ {
if (buf == null) if (buf == null)
{ {
data = null; data = null;
return; return this;
} }
if (opcode.isControlFrame()) if (opcode.isControlFrame())
@ -311,6 +318,7 @@ public class WebSocketFrame implements Frame
data = ByteBuffer.allocate(len); data = ByteBuffer.allocate(len);
BufferUtil.clearToFill(data); BufferUtil.clearToFill(data);
data.put(buf,0,len); data.put(buf,0,len);
return this;
} }
/** /**
@ -323,12 +331,12 @@ public class WebSocketFrame implements Frame
* @param buf * @param buf
* the bytebuffer to set * the bytebuffer to set
*/ */
public void setPayload(ByteBuffer buf) public WebSocketFrame setPayload(ByteBuffer buf)
{ {
if (buf == null) if (buf == null)
{ {
data = null; data = null;
return; return this;
} }
if (opcode.isControlFrame()) if (opcode.isControlFrame())
@ -340,21 +348,25 @@ public class WebSocketFrame implements Frame
} }
data = buf.slice(); data = buf.slice();
return this;
} }
public void setRsv1(boolean rsv1) public WebSocketFrame setRsv1(boolean rsv1)
{ {
this.rsv1 = rsv1; this.rsv1 = rsv1;
return this;
} }
public void setRsv2(boolean rsv2) public WebSocketFrame setRsv2(boolean rsv2)
{ {
this.rsv2 = rsv2; this.rsv2 = rsv2;
return this;
} }
public void setRsv3(boolean rsv3) public WebSocketFrame setRsv3(boolean rsv3)
{ {
this.rsv3 = rsv3; this.rsv3 = rsv3;
return this;
} }
@Override @Override

View File

@ -0,0 +1,87 @@
package org.eclipse.jetty.websocket.protocol;
import java.nio.ByteBuffer;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.io.StandardByteBufferPool;
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.websocket.ByteBufferAssert;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.generator.Generator;
import org.junit.BeforeClass;
import org.junit.Test;
public class WebSocketFrameTest
{
private static Generator strictGenerator;
private static Generator laxGenerator;
@BeforeClass
public static void initGenerator()
{
WebSocketPolicy policy = WebSocketPolicy.newServerPolicy();
ByteBufferPool bufferPool = new StandardByteBufferPool();
strictGenerator = new Generator(policy,bufferPool);
laxGenerator = new Generator(policy,bufferPool,false);
}
private void assertEqual(String message, ByteBuffer expected, ByteBuffer actual)
{
BufferUtil.flipToFlush(actual,0);
BufferUtil.flipToFlush(expected,0);
ByteBufferAssert.assertEquals(message,expected,actual);
}
@Test
public void testLaxInvalidClose()
{
WebSocketFrame frame = new WebSocketFrame(OpCode.CLOSE).setFin(false);
ByteBuffer actual = laxGenerator.generate(frame);
ByteBuffer expected = ByteBuffer.allocate(2);
expected.put((byte)0x08);
expected.put((byte)0x00);
assertEqual("Lax Invalid Close Frame",expected,actual);
}
@Test
public void testLaxInvalidPing()
{
WebSocketFrame frame = new WebSocketFrame(OpCode.PING).setFin(false);
ByteBuffer actual = laxGenerator.generate(frame);
ByteBuffer expected = ByteBuffer.allocate(2);
expected.put((byte)0x09);
expected.put((byte)0x00);
assertEqual("Lax Invalid Ping Frame",expected,actual);
}
@Test
public void testStrictValidClose()
{
CloseInfo close = new CloseInfo(StatusCode.NORMAL,null);
ByteBuffer actual = strictGenerator.generate(close.asFrame());
ByteBuffer expected = ByteBuffer.allocate(4);
expected.put((byte)0x88);
expected.put((byte)0x02);
expected.put((byte)0x03);
expected.put((byte)0xE8);
assertEqual("Strict Valid Close Frame",expected,actual);
}
@Test
public void testStrictValidPing()
{
WebSocketFrame frame = new WebSocketFrame(OpCode.PING);
ByteBuffer actual = strictGenerator.generate(frame);
ByteBuffer expected = ByteBuffer.allocate(2);
expected.put((byte)0x89);
expected.put((byte)0x00);
assertEqual("Strict Valid Ping Frame",expected,actual);
}
}