Initial pass at testing
This commit is contained in:
parent
f3532f9bd9
commit
7227a86254
|
@ -54,18 +54,7 @@ public class BaseFrame
|
|||
*/
|
||||
public BaseFrame(BaseFrame copy) {
|
||||
this();
|
||||
this.fin = copy.fin;
|
||||
this.rsv1 = copy.rsv1;
|
||||
this.rsv2 = copy.rsv2;
|
||||
this.rsv3 = copy.rsv3;
|
||||
this.opcode = copy.opcode;
|
||||
this.masked = copy.masked;
|
||||
this.payloadLength = copy.payloadLength;
|
||||
if(copy.mask != null) {
|
||||
int mlen = copy.mask.length;
|
||||
this.mask = new byte[mlen];
|
||||
System.arraycopy(copy.mask,0,this.mask,0,mlen);
|
||||
}
|
||||
copy(copy);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -76,6 +65,27 @@ public class BaseFrame
|
|||
this.opcode = opcode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the baseframe values
|
||||
*
|
||||
* @param copy
|
||||
*/
|
||||
public void copy(BaseFrame copy) {
|
||||
this.fin = copy.fin;
|
||||
this.rsv1 = copy.rsv1;
|
||||
this.rsv2 = copy.rsv2;
|
||||
this.rsv3 = copy.rsv3;
|
||||
this.opcode = copy.opcode;
|
||||
this.masked = copy.masked;
|
||||
this.payloadLength = copy.payloadLength;
|
||||
if (copy.mask != null)
|
||||
{
|
||||
int mlen = copy.mask.length;
|
||||
this.mask = new byte[mlen];
|
||||
System.arraycopy(copy.mask,0,this.mask,0,mlen);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] getMask()
|
||||
{
|
||||
if (!masked)
|
||||
|
|
|
@ -1,20 +1,33 @@
|
|||
package org.eclipse.jetty.websocket.frames;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.OpCode;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.OpCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
|
||||
/**
|
||||
* Representation of a <a href="https://tools.ietf.org/html/rfc6455#section-5.5.2">Ping Frame (0x09)</a>.
|
||||
*/
|
||||
public class PingFrame extends ControlFrame
|
||||
{
|
||||
{
|
||||
private ByteBuffer payload;
|
||||
|
||||
public PingFrame(ByteBuffer payload)
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public PingFrame()
|
||||
{
|
||||
super(OpCode.PING);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct Ping Frame from known bytebuffer
|
||||
*
|
||||
* @param payload
|
||||
*/
|
||||
public PingFrame(ByteBuffer payload)
|
||||
{
|
||||
this();
|
||||
setPayload(payload);
|
||||
}
|
||||
|
||||
|
@ -24,6 +37,11 @@ public class PingFrame extends ControlFrame
|
|||
return OpCode.PING;
|
||||
}
|
||||
|
||||
public ByteBuffer getPayload()
|
||||
{
|
||||
return payload;
|
||||
}
|
||||
|
||||
public void setPayload(ByteBuffer payload)
|
||||
{
|
||||
if ( payload.array().length >= 126 )
|
||||
|
@ -36,12 +54,7 @@ public class PingFrame extends ControlFrame
|
|||
throw new WebSocketException("too long, catch this better");
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBuffer getPayload()
|
||||
{
|
||||
return payload;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -4,6 +4,12 @@ import java.nio.ByteBuffer;
|
|||
|
||||
public class BinaryPayloadParser extends PayloadParser
|
||||
{
|
||||
private Parser baseParser;
|
||||
|
||||
public BinaryPayloadParser(Parser parser)
|
||||
{
|
||||
this.baseParser = parser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse(ByteBuffer buffer)
|
||||
|
@ -12,4 +18,11 @@ public class BinaryPayloadParser extends PayloadParser
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,12 @@ import java.nio.ByteBuffer;
|
|||
|
||||
public class ClosePayloadParser extends PayloadParser
|
||||
{
|
||||
private Parser baseParser;
|
||||
|
||||
public ClosePayloadParser(Parser parser)
|
||||
{
|
||||
this.baseParser = parser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse(ByteBuffer buffer)
|
||||
|
@ -12,4 +18,11 @@ public class ClosePayloadParser extends PayloadParser
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,12 @@ import java.nio.ByteBuffer;
|
|||
|
||||
public class ContinuationPayloadParser extends PayloadParser
|
||||
{
|
||||
private Parser baseParser;
|
||||
|
||||
public ContinuationPayloadParser(Parser parser)
|
||||
{
|
||||
this.baseParser = parser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse(ByteBuffer buffer)
|
||||
|
@ -12,4 +18,10 @@ public class ContinuationPayloadParser extends PayloadParser
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,12 +94,12 @@ public class Parser {
|
|||
baseframe = new BaseFrame();
|
||||
reset();
|
||||
|
||||
parsers.put(OpCode.CONTINUATION,new ContinuationPayloadParser());
|
||||
parsers.put(OpCode.TEXT,new TextPayloadParser());
|
||||
parsers.put(OpCode.BINARY,new BinaryPayloadParser());
|
||||
parsers.put(OpCode.CLOSE,new ClosePayloadParser());
|
||||
parsers.put(OpCode.PING,new PingPayloadParser());
|
||||
parsers.put(OpCode.PONG,new PongPayloadParser());
|
||||
parsers.put(OpCode.CONTINUATION,new ContinuationPayloadParser(this));
|
||||
parsers.put(OpCode.TEXT,new TextPayloadParser(this));
|
||||
parsers.put(OpCode.BINARY,new BinaryPayloadParser(this));
|
||||
parsers.put(OpCode.CLOSE,new ClosePayloadParser(this));
|
||||
parsers.put(OpCode.PING,new PingPayloadParser(this));
|
||||
parsers.put(OpCode.PONG,new PongPayloadParser(this));
|
||||
}
|
||||
|
||||
public void addListener(Listener listener)
|
||||
|
@ -107,6 +107,11 @@ public class Parser {
|
|||
listeners.add(listener);
|
||||
}
|
||||
|
||||
protected BaseFrame getBaseFrame()
|
||||
{
|
||||
return baseframe;
|
||||
}
|
||||
|
||||
protected void notifyControlFrame(final ControlFrame f)
|
||||
{
|
||||
LOG.debug("Notify Control Frame: {}",f);
|
||||
|
|
|
@ -5,4 +5,5 @@ import java.nio.ByteBuffer;
|
|||
public abstract class PayloadParser
|
||||
{
|
||||
public abstract boolean parse(ByteBuffer buffer);
|
||||
public abstract void reset();
|
||||
}
|
||||
|
|
|
@ -2,14 +2,60 @@ package org.eclipse.jetty.websocket.parser;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.frames.PingFrame;
|
||||
|
||||
/**
|
||||
* Parsing for the {@link PingFrame}.
|
||||
*/
|
||||
public class PingPayloadParser extends PayloadParser
|
||||
{
|
||||
private Parser baseParser;
|
||||
private ByteBuffer payload;
|
||||
private int payloadLength;
|
||||
|
||||
public PingPayloadParser(Parser parser)
|
||||
{
|
||||
this.baseParser = parser;
|
||||
}
|
||||
|
||||
private void onPingFrame()
|
||||
{
|
||||
PingFrame ping = new PingFrame();
|
||||
ping.copy(baseParser.getBaseFrame());
|
||||
ping.setPayload(payload);
|
||||
baseParser.notifyControlFrame(ping);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse(ByteBuffer buffer)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
payloadLength = baseParser.getBaseFrame().getPayloadLength();
|
||||
while (buffer.hasRemaining())
|
||||
{
|
||||
if (payload == null)
|
||||
{
|
||||
// TODO: buffer size limits
|
||||
payload = ByteBuffer.allocate(payloadLength);
|
||||
}
|
||||
|
||||
int size = Math.min(payloadLength,buffer.remaining());
|
||||
int limit = buffer.limit();
|
||||
buffer.limit(buffer.position() + size);
|
||||
ByteBuffer bytes = buffer.slice();
|
||||
buffer.limit(limit);
|
||||
payload.put(bytes);
|
||||
if (payload.position() >= payloadLength)
|
||||
{
|
||||
onPingFrame();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
payload = null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,12 @@ import java.nio.ByteBuffer;
|
|||
|
||||
public class PongPayloadParser extends PayloadParser
|
||||
{
|
||||
private Parser baseParser;
|
||||
|
||||
public PongPayloadParser(Parser parser)
|
||||
{
|
||||
this.baseParser = parser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse(ByteBuffer buffer)
|
||||
|
@ -12,4 +18,11 @@ public class PongPayloadParser extends PayloadParser
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,12 @@ import java.nio.ByteBuffer;
|
|||
|
||||
public class TextPayloadParser extends PayloadParser
|
||||
{
|
||||
private Parser baseParser;
|
||||
|
||||
public TextPayloadParser(Parser parser)
|
||||
{
|
||||
this.baseParser = parser;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean parse(ByteBuffer buffer)
|
||||
|
@ -12,4 +18,11 @@ public class TextPayloadParser extends PayloadParser
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -12,4 +12,11 @@ public class UnknownPayloadParser extends PayloadParser
|
|||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package org.eclipse.jetty.websocket;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
|
||||
/**
|
||||
* Utility class for managing logging levels during unit testing
|
||||
*/
|
||||
public class TestLogging
|
||||
{
|
||||
public static void enableDebug(Class<?> clazz)
|
||||
{
|
||||
setLevel(clazz,StdErrLog.LEVEL_DEBUG);
|
||||
}
|
||||
|
||||
public static void setLevel(Class<?> clazz, int level)
|
||||
{
|
||||
Logger log = Log.getLogger(clazz);
|
||||
if(log instanceof StdErrLog) {
|
||||
((StdErrLog)log).setLevel(level);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package org.eclipse.jetty.websocket.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.frames.BaseFrame;
|
||||
import org.eclipse.jetty.websocket.frames.ControlFrame;
|
||||
import org.eclipse.jetty.websocket.frames.DataFrame;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class FrameParseCapture implements Parser.Listener
|
||||
{
|
||||
private List<BaseFrame> frames = new ArrayList<>();
|
||||
private List<WebSocketException> errors = new ArrayList<>();
|
||||
|
||||
public void assertHasFrame(Class<? extends BaseFrame> frameType)
|
||||
{
|
||||
Assert.assertThat(frameType.getSimpleName(),getFrameCount(frameType),greaterThanOrEqualTo(1));
|
||||
}
|
||||
|
||||
public void assertHasFrame(Class<? extends BaseFrame> frameType, int expectedCount)
|
||||
{
|
||||
Assert.assertThat(frameType.getSimpleName(),getFrameCount(frameType),is(expectedCount));
|
||||
}
|
||||
|
||||
public void assertNoErrors()
|
||||
{
|
||||
Assert.assertThat("Has no errors",errors.size(),is(0));
|
||||
}
|
||||
|
||||
public List<WebSocketException> getErrors()
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
|
||||
public int getFrameCount(Class<? extends BaseFrame> frameType)
|
||||
{
|
||||
int count = 0;
|
||||
for(BaseFrame frame: frames) {
|
||||
if (frame.getClass().isInstance(frameType))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public List<BaseFrame> getFrames()
|
||||
{
|
||||
return frames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onControlFrame(ControlFrame frame)
|
||||
{
|
||||
frames.add(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDataFrame(DataFrame frame)
|
||||
{
|
||||
frames.add(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketException(WebSocketException e)
|
||||
{
|
||||
errors.add(e);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package org.eclipse.jetty.websocket.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ParserTest
|
||||
{
|
||||
@Test
|
||||
public void testParseNothing()
|
||||
{
|
||||
ByteBuffer buf = ByteBuffer.allocate(16);
|
||||
// Put nothing in the buffer.
|
||||
buf.flip();
|
||||
|
||||
Parser parser = new Parser();
|
||||
FrameParseCapture capture = new FrameParseCapture();
|
||||
parser.addListener(capture);
|
||||
parser.parse(buf);
|
||||
|
||||
capture.assertNoErrors();
|
||||
Assert.assertThat("Frame Count",capture.getFrames().size(),is(0));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.eclipse.jetty.websocket.parser;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.TestLogging;
|
||||
import org.eclipse.jetty.websocket.frames.PingFrame;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PingParserTest
|
||||
{
|
||||
@Test
|
||||
public void testBasicPingParsing()
|
||||
{
|
||||
TestLogging.enableDebug(Parser.class);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(16);
|
||||
// Raw bytes as found in RFC 6455, Section 5.7 - Examples
|
||||
// Unmasked Ping request
|
||||
buf.put(new byte[]
|
||||
{ (byte)0x89, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f });
|
||||
buf.flip();
|
||||
|
||||
Parser parser = new Parser();
|
||||
FrameParseCapture capture = new FrameParseCapture();
|
||||
parser.addListener(capture);
|
||||
parser.parse(buf);
|
||||
|
||||
capture.assertNoErrors();
|
||||
capture.assertHasFrame(PingFrame.class,1);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue