some frame consolidation work in progress

This commit is contained in:
Jesse McConnell 2012-06-21 16:22:17 -05:00
parent aaf27d7e2a
commit f4a644347b
16 changed files with 158 additions and 142 deletions

View File

@ -5,7 +5,6 @@ import java.util.Map;
import org.eclipse.jetty.websocket.frames.BinaryFrame;
import org.eclipse.jetty.websocket.frames.CloseFrame;
import org.eclipse.jetty.websocket.frames.ContinuationFrame;
import org.eclipse.jetty.websocket.frames.PingFrame;
import org.eclipse.jetty.websocket.frames.PongFrame;
import org.eclipse.jetty.websocket.frames.TextFrame;

View File

@ -37,8 +37,6 @@ public class BaseFrame
private int payloadLength;
private byte mask[];
// internal tracking
private int continuationIndex = 0;
/**
* Default constructor
@ -55,19 +53,7 @@ public class BaseFrame
this.opcode = opcode;
}
/**
* The number of fragments this frame consists of.
* <p>
* For every {@link OpCode#CONTINUATION} opcode encountered, this increments by one.
* <p>
* Note: Not part of the Base Framing Protocol / header information.
*
* @return the number of continuation fragments encountered.
*/
public int getContinuationIndex()
{
return continuationIndex;
}
public byte[] getMask()
{
@ -128,13 +114,8 @@ public class BaseFrame
masked = false;
payloadLength = -1;
mask = null;
continuationIndex = 0;
}
public void setContinuationIndex(int continuationIndex)
{
this.continuationIndex = continuationIndex;
}
public void setFin(boolean fin)
{

View File

@ -10,7 +10,6 @@ import org.eclipse.jetty.websocket.api.OpCode;
*/
public class BinaryFrame extends DataFrame
{
private ByteBuffer data; // TODO: make this a standard byte buffer?
/**
* Default unspecified data
@ -20,45 +19,20 @@ public class BinaryFrame extends DataFrame
super(OpCode.BINARY);
}
/**
* Get the data
*
* @return the raw bytebuffer data (can be null)
*/
public ByteBuffer getData()
{
return data;
}
@Override
public OpCode getOpCode()
{
return OpCode.BINARY;
}
/**
* Set the data and payload length.
*
* @param buf
* the bytebuffer to set
*/
public void setData(byte buf[])
{
int len = buf.length;
this.data = ByteBuffer.allocate(len);
this.setPayloadLength(len);
}
/**
* Set the data and payload length.
*
* @param buf
* the byte array to set
*/
public void setData(ByteBuffer buffer)
@Override
public void setPayload(ByteBuffer buffer)
{
this.data = buffer;
this.setPayloadLength(buffer.capacity());
// TODO Auto-generated method stub
super.setPayload(buffer);
}
@Override
@ -67,7 +41,7 @@ public class BinaryFrame extends DataFrame
StringBuilder b = new StringBuilder();
b.append("BinaryFrame[");
b.append("len=").append(getPayloadLength());
b.append(",data=").append(BufferUtil.toDetailString(getData()));
b.append(",data=").append(BufferUtil.toDetailString(getPayload()));
b.append("]");
return b.toString();
}

View File

@ -1,11 +0,0 @@
package org.eclipse.jetty.websocket.frames;
import org.eclipse.jetty.websocket.api.OpCode;
public class ContinuationFrame extends BaseFrame
{
public ContinuationFrame()
{
super(OpCode.CONTINUATION);
}
}

View File

@ -1,9 +1,16 @@
package org.eclipse.jetty.websocket.frames;
import java.nio.ByteBuffer;
import org.eclipse.jetty.websocket.api.OpCode;
public abstract class DataFrame extends BaseFrame
{
// internal tracking
private int continuationIndex = 0;
private boolean continuation = false;
private ByteBuffer payload;
public DataFrame()
{
super();
@ -13,4 +20,78 @@ public abstract class DataFrame extends BaseFrame
{
super(opcode);
}
/**
* Get the data
*
* @return the raw bytebuffer data (can be null)
*/
public ByteBuffer getPayload()
{
return payload;
}
/**
* Set the data and payload length.
*
* @param buf
* the bytebuffer to set
*/
protected void setPayload(byte buf[])
{
int len = buf.length;
this.payload = ByteBuffer.allocate(len);
this.setPayloadLength(len);
}
/**
* Set the data and payload length.
*
* @param buf
* the byte array to set
*/
protected void setPayload(ByteBuffer buffer)
{
this.payload = buffer;
this.setPayloadLength(buffer.capacity());
}
/**
* The number of fragments this frame consists of.
* <p>
* For every {@link OpCode#CONTINUATION} opcode encountered, this increments by one.
* <p>
* Note: Not part of the Base Framing Protocol / header information.
*
* @return the number of continuation fragments encountered.
*/
public int getContinuationIndex()
{
return continuationIndex;
}
public void setContinuationIndex(int continuationIndex)
{
this.continuationIndex = continuationIndex;
}
@Override
public void reset()
{
super.reset();
continuationIndex = 0;
}
public boolean isContinuation()
{
return continuation;
}
public void setContinuation(boolean continuation)
{
this.continuation = continuation;
}
}

View File

@ -1,5 +1,7 @@
package org.eclipse.jetty.websocket.frames;
import java.nio.ByteBuffer;
import org.eclipse.jetty.websocket.api.OpCode;
/**
@ -7,8 +9,6 @@ import org.eclipse.jetty.websocket.api.OpCode;
*/
public class TextFrame extends DataFrame
{
private StringBuilder data = new StringBuilder();
/**
* Default constructor (unspecified data)
*/
@ -26,17 +26,7 @@ public class TextFrame extends DataFrame
public TextFrame(String message)
{
this();
setData(message);
}
/**
* Get the data
*
* @return the raw StringBuilder data (can be null)
*/
public StringBuilder getData()
{
return data;
setPayload(message);
}
/**
@ -45,24 +35,18 @@ public class TextFrame extends DataFrame
* @param str
* the String to set
*/
public void setData(String str)
public void setPayload(String str)
{
int len = str.length();
this.data = new StringBuilder(str);
ByteBuffer b = ByteBuffer.allocate(len);
b.put(str.getBytes()); // TODO validate utf-8
this.setPayload(b);
this.setPayloadLength(len);
}
/**
* Set the data and payload length.
*
* @param str
* the StringBuilder to set
*/
public void setData(StringBuilder str)
public String getPayloadAsText()
{
int len = str.length();
this.data = str;
this.setPayloadLength(len);
return new String(getPayload().array());
}
@Override
@ -71,7 +55,7 @@ public class TextFrame extends DataFrame
StringBuilder b = new StringBuilder();
b.append("TextFrame[");
b.append("len=").append(getPayloadLength());
b.append(",data=").append(data);
b.append(",data=").append(getPayload()); // TODO pp
b.append("]");
return b.toString();
}

View File

@ -16,6 +16,6 @@ public class BinaryFrameGenerator extends FrameGenerator<BinaryFrame>
@Override
public ByteBuffer payload(BinaryFrame binary)
{
return binary.getData();
return binary.getPayload();
}
}

View File

@ -3,9 +3,11 @@ package org.eclipse.jetty.websocket.generator;
import java.nio.ByteBuffer;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.websocket.api.OpCode;
import org.eclipse.jetty.websocket.api.PolicyViolationException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.BaseFrame;
import org.eclipse.jetty.websocket.frames.DataFrame;
public abstract class FrameGenerator<T extends BaseFrame>
{
@ -48,7 +50,24 @@ public abstract class FrameGenerator<T extends BaseFrame>
// TODO: extensions can negotiate this (somehow)
throw new PolicyViolationException("RSV3 not allowed to be set");
}
// TODO ewe
if ( frame instanceof DataFrame)
{
if ( ((DataFrame)frame).isContinuation() )
{
b |= OpCode.CONTINUATION.getCode() & 0x0F;
}
else
{
b |= (frame.getOpCode().getCode() & 0x0F);
}
}
else
{
b |= (frame.getOpCode().getCode() & 0x0F);
}
framing.put(b);
// is masked

View File

@ -18,18 +18,6 @@ public class TextFrameGenerator extends FrameGenerator<TextFrame>
@Override
public ByteBuffer payload(TextFrame text)
{
try
{
String data = text.getData().toString();
ByteBuffer payload = ByteBuffer.allocate(data.length());
payload.put(data.getBytes("UTF-8"));
return payload;
}
catch (UnsupportedEncodingException e)
{
// TODO improve ex handling
throw new WebSocketException("text frame was not correctly encoded");
}
return text.getPayload();
}
}

View File

@ -49,7 +49,7 @@ public class BinaryPayloadParser extends FrameParser<BinaryFrame>
if (payload.position() >= payloadLength)
{
frame.setData(payload);
frame.setPayload(payload);
return true;
}
}

View File

@ -12,6 +12,7 @@ import org.eclipse.jetty.websocket.api.OpCode;
import org.eclipse.jetty.websocket.api.WebSocketException;
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.BaseFrame;
import org.eclipse.jetty.websocket.frames.DataFrame;
/**
* Parsing of a frames in WebSocket land.
@ -139,7 +140,11 @@ public class Parser
}
parser.reset();
parser.initFrame(fin,rsv1,rsv2,rsv3,opcode);
parser.getFrame().setContinuationIndex(currentContinuationIndex);
if ( parser.getFrame() instanceof DataFrame )
{
((DataFrame)parser.getFrame()).setContinuationIndex(currentContinuationIndex);
}
state = State.BASE_FRAMING;
break;

View File

@ -49,7 +49,7 @@ public class TextPayloadParser extends FrameParser<TextFrame>
if (payload.position() >= payloadLength)
{
payload.flip();
frame.setData(BufferUtil.toString(payload,StringUtil.__UTF8_CHARSET));
frame.setPayload(BufferUtil.toString(payload,StringUtil.__UTF8_CHARSET));
return true;
}
}

View File

@ -47,7 +47,7 @@ public class GeneratorParserRoundtripTest
capture.assertHasFrame(TextFrame.class,1);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("Text parsed",txt.getData().toString(),is(message));
Assert.assertThat("Text parsed",txt.getPayloadAsText(),is(message));
}
@Test
@ -82,6 +82,6 @@ public class GeneratorParserRoundtripTest
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertTrue("Text.isMasked",txt.isMasked());
Assert.assertThat("Text parsed",txt.getData().toString(),is(message));
Assert.assertThat("Text parsed",txt.getPayloadAsText(),is(message));
}
}

View File

@ -40,8 +40,9 @@ public class RFC6455ExamplesGeneratorTest
t1.setFin(false);
t2.setFin(true);
t1.setData("Hel");
t2.setData("lo");
t2.setContinuation(true);
t1.setPayload("Hel");
t2.setPayload("lo");
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
@ -58,11 +59,6 @@ public class RFC6455ExamplesGeneratorTest
b2.flip();
g2.flip();
Assert.assertEquals(b1.get(),g1.get());
System.out.println(Integer.toHexString(b2.get()));
System.out.println(Integer.toHexString(g2.get()));
ByteBufferAssert.assertEquals("t1 buffers are not equal", b1, g1);
ByteBufferAssert.assertEquals("t2 buffers are not equal", b2, g2);
@ -149,7 +145,7 @@ public class RFC6455ExamplesGeneratorTest
{ (byte)0x81, (byte)0x85, 0x37, (byte)0xfa, 0x21, 0x3d, 0x7f, (byte)0x9f, 0x4d, 0x51, 0x58 });
TextFrame t1 = new TextFrame();
t1.setData("Hello");
t1.setPayload("Hello");
t1.setFin(true);
t1.setMasked(true);
t1.setMask(new byte[]{(byte)0xff,(byte)0xff,(byte)0xff,(byte)0xff});

View File

@ -51,9 +51,9 @@ public class RFC6455ExamplesParserTest
capture.assertHasFrame(TextFrame.class,2);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame[0].data",txt.getData().toString(),is("Hel"));
Assert.assertThat("TextFrame[0].data",txt.getPayloadAsText(),is("Hel"));
txt = (TextFrame)capture.getFrames().get(1);
Assert.assertThat("TextFrame[1].data",txt.getData().toString(),is("lo"));
Assert.assertThat("TextFrame[1].data",txt.getPayloadAsText(),is("lo"));
}
@Test
@ -99,7 +99,7 @@ public class RFC6455ExamplesParserTest
capture.assertHasFrame(TextFrame.class,1);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.data",txt.getData().toString(),is("Hello"));
Assert.assertThat("TextFrame.data",txt.getPayloadAsText(),is("Hello"));
}
@Test
@ -129,12 +129,12 @@ public class RFC6455ExamplesParserTest
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame bin = (BinaryFrame)capture.getFrames().get(0);
bin.getData().flip();
bin.getPayload().flip();
Assert.assertThat("BinaryFrame.payloadLength",bin.getPayloadLength(),is(dataSize));
ByteBufferAssert.assertSize("BinaryFrame.payload",dataSize,bin.getData());
ByteBufferAssert.assertSize("BinaryFrame.payload",dataSize,bin.getPayload());
ByteBuffer data = bin.getData();
ByteBuffer data = bin.getPayload();
for (int i = dataSize; i > 0; i--)
{
Assert.assertThat("BinaryFrame.data[" + i + "]",data.get(),is((byte)0x44));
@ -168,12 +168,12 @@ public class RFC6455ExamplesParserTest
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame bin = (BinaryFrame)capture.getFrames().get(0);
bin.getData().flip();
bin.getPayload().flip();
Assert.assertThat("BinaryFrame.payloadLength",bin.getPayloadLength(),is(dataSize));
ByteBufferAssert.assertSize("BinaryFrame.payload",dataSize,bin.getData());
ByteBufferAssert.assertSize("BinaryFrame.payload",dataSize,bin.getPayload());
ByteBuffer data = bin.getData();
ByteBuffer data = bin.getPayload();
for (int i = dataSize; i > 0; i--)
{
Assert.assertThat("BinaryFrame.data[" + i + "]",data.get(),is((byte)0x77));
@ -223,6 +223,6 @@ public class RFC6455ExamplesParserTest
capture.assertHasFrame(TextFrame.class,1);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.data", txt.getData().toString(), is("Hello"));
Assert.assertThat("TextFrame.data", txt.getPayloadAsText(), is("Hello"));
}
}

View File

@ -78,7 +78,7 @@ public class TextPayloadParserTest
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText));
Assert.assertThat("TextFrame.data",txt.getPayloadAsText(),is(expectedText));
}
@Test
@ -113,7 +113,7 @@ public class TextPayloadParserTest
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText));
Assert.assertThat("TextFrame.data",txt.getPayloadAsText(),is(expectedText));
}
@Test
@ -150,9 +150,9 @@ public class TextPayloadParserTest
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,2);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame[0].data",txt.getData().toString(),is(part1));
Assert.assertThat("TextFrame[0].data",txt.getPayloadAsText(),is(part1));
txt = (TextFrame)capture.getFrames().get(1);
Assert.assertThat("TextFrame[1].data",txt.getData().toString(),is(part2));
Assert.assertThat("TextFrame[1].data",txt.getPayloadAsText(),is(part2));
}
@Test
@ -177,7 +177,7 @@ public class TextPayloadParserTest
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText));
Assert.assertThat("TextFrame.data",txt.getPayloadAsText(),is(expectedText));
}
@Test
@ -203,6 +203,6 @@ public class TextPayloadParserTest
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame txt = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.data",txt.getData().toString(),is(expectedText));
Assert.assertThat("TextFrame.data",txt.getPayloadAsText(),is(expectedText));
}
}