Fixing various things around generate/parse of windowed fragments.
+ @WebSocket annotation's policy configuraiton is now optional + WebSocketPolicy.clonePolicy() fixed for other fields + WebSocketEventDriver now has internal WebSocket POJO specific logger to allow for logging control of the WebSocket POJO itself in case of runtime exceptions. + WebSocketEventDriver now honors bufferSize correctly. + DataFrameBytes always requests windowSize from generator, allowing generator to determine ultimate byteBuffer utilization itself. + MessageInputStream / MessageReader now clears the starting buffer + Generator now honors windowSize correctly (even if buffer obtained from ByteBufferPool.acquire() is much larger + Parser now demasks the payload after a successful parse of the framing + Various testing cleanup to produce less noisy output during testing.
This commit is contained in:
parent
99bffa6ce0
commit
47f882e6dc
|
@ -6,6 +6,9 @@
|
|||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="1"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
|
||||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
||||
|
|
|
@ -30,11 +30,11 @@ import java.lang.annotation.Target;
|
|||
{ ElementType.TYPE })
|
||||
public @interface WebSocket
|
||||
{
|
||||
int maxBinarySize() default 8192;
|
||||
int maxBinarySize() default -2;
|
||||
|
||||
int maxBufferSize() default 8192;
|
||||
int maxBufferSize() default -2;
|
||||
|
||||
int maxIdleTime() default 300000;
|
||||
int maxIdleTime() default -2;
|
||||
|
||||
int maxTextSize() default 8192;
|
||||
int maxTextSize() default -2;
|
||||
}
|
||||
|
|
|
@ -128,10 +128,12 @@ public class WebSocketPolicy
|
|||
public WebSocketPolicy clonePolicy()
|
||||
{
|
||||
WebSocketPolicy clone = new WebSocketPolicy(this.behavior);
|
||||
clone.bufferSize = this.bufferSize;
|
||||
clone.autoFragment = this.autoFragment;
|
||||
clone.masker = this.masker;
|
||||
clone.maxBinaryMessageSize = this.maxBinaryMessageSize;
|
||||
clone.idleTimeout = this.idleTimeout;
|
||||
clone.bufferSize = this.bufferSize;
|
||||
clone.maxPayloadSize = this.maxPayloadSize;
|
||||
clone.maxBinaryMessageSize = this.maxBinaryMessageSize;
|
||||
clone.maxTextMessageSize = this.maxTextMessageSize;
|
||||
return clone;
|
||||
}
|
||||
|
@ -146,6 +148,11 @@ public class WebSocketPolicy
|
|||
return bufferSize;
|
||||
}
|
||||
|
||||
public int getIdleTimeout()
|
||||
{
|
||||
return idleTimeout;
|
||||
}
|
||||
|
||||
public Masker getMasker()
|
||||
{
|
||||
return masker;
|
||||
|
@ -156,11 +163,6 @@ public class WebSocketPolicy
|
|||
return maxBinaryMessageSize;
|
||||
}
|
||||
|
||||
public int getIdleTimeout()
|
||||
{
|
||||
return idleTimeout;
|
||||
}
|
||||
|
||||
public int getMaxPayloadSize()
|
||||
{
|
||||
return maxPayloadSize;
|
||||
|
@ -186,6 +188,11 @@ public class WebSocketPolicy
|
|||
this.bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
public void setIdleTimeout(int idleTimeout)
|
||||
{
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
public void setMasker(Masker masker)
|
||||
{
|
||||
this.masker = masker;
|
||||
|
@ -196,11 +203,6 @@ public class WebSocketPolicy
|
|||
this.maxBinaryMessageSize = maxBinaryMessageSize;
|
||||
}
|
||||
|
||||
public void setIdleTimeout(int idleTimeout)
|
||||
{
|
||||
this.idleTimeout = idleTimeout;
|
||||
}
|
||||
|
||||
public void setMaxPayloadSize(int maxPayloadSize)
|
||||
{
|
||||
if (maxPayloadSize < bufferSize)
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
|||
public class WebSocketEventDriver implements IncomingFrames
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(WebSocketEventDriver.class);
|
||||
private final Logger socketLog;
|
||||
private final Object websocket;
|
||||
private final WebSocketPolicy policy;
|
||||
private final EventMethods events;
|
||||
|
@ -74,29 +75,48 @@ public class WebSocketEventDriver implements IncomingFrames
|
|||
this.events = methodsCache.getMethods(websocket.getClass());
|
||||
this.bufferPool = bufferPool;
|
||||
|
||||
this.socketLog = Log.getLogger(websocket.getClass());
|
||||
|
||||
if (events.isAnnotated())
|
||||
{
|
||||
WebSocket anno = websocket.getClass().getAnnotation(WebSocket.class);
|
||||
// Setup the policy
|
||||
policy.setBufferSize(anno.maxBufferSize());
|
||||
policy.setMaxBinaryMessageSize(anno.maxBinarySize());
|
||||
policy.setMaxTextMessageSize(anno.maxTextSize());
|
||||
policy.setIdleTimeout(anno.maxIdleTime());
|
||||
if (anno.maxBufferSize() > 0)
|
||||
{
|
||||
this.policy.setBufferSize(anno.maxBufferSize());
|
||||
}
|
||||
if (anno.maxBinarySize() > 0)
|
||||
{
|
||||
this.policy.setMaxBinaryMessageSize(anno.maxBinarySize());
|
||||
}
|
||||
if (anno.maxTextSize() > 0)
|
||||
{
|
||||
this.policy.setMaxTextMessageSize(anno.maxTextSize());
|
||||
}
|
||||
if (anno.maxIdleTime() > 0)
|
||||
{
|
||||
this.policy.setIdleTimeout(anno.maxIdleTime());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void appendBuffer(ByteBuffer msgBuf, ByteBuffer byteBuffer)
|
||||
private void appendBuffer(ByteBuffer msgBuf, ByteBuffer payloadBuf)
|
||||
{
|
||||
if (byteBuffer == null)
|
||||
if (payloadBuf == null)
|
||||
{
|
||||
// nothing to do (empty payload is possible)
|
||||
return;
|
||||
}
|
||||
if (msgBuf.remaining() < byteBuffer.remaining())
|
||||
if (msgBuf.remaining() < payloadBuf.remaining())
|
||||
{
|
||||
throw new MessageTooLargeException("Message exceeded maximum buffer");
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug(" msgBuf = {}",BufferUtil.toDetailString(msgBuf));
|
||||
LOG.debug("payloadBuf = {}",BufferUtil.toDetailString(msgBuf));
|
||||
}
|
||||
throw new MessageTooLargeException("Message exceeded maximum buffer size of [" + payloadBuf.capacity() + "]");
|
||||
}
|
||||
msgBuf.put(byteBuffer);
|
||||
msgBuf.put(payloadBuf);
|
||||
}
|
||||
|
||||
public WebSocketPolicy getPolicy()
|
||||
|
@ -389,7 +409,7 @@ public class WebSocketEventDriver implements IncomingFrames
|
|||
|
||||
private void unhandled(Throwable t)
|
||||
{
|
||||
LOG.warn("Unhandled Error (closing connection)",t);
|
||||
socketLog.warn("Unhandled Error (closing connection)",t);
|
||||
|
||||
// Unhandled Error, close the connection.
|
||||
switch (policy.getBehavior())
|
||||
|
|
|
@ -62,15 +62,9 @@ public class DataFrameBytes<C> extends FrameBytes<C>
|
|||
try
|
||||
{
|
||||
int windowSize = connection.getPolicy().getBufferSize();
|
||||
// TODO: create a window size?
|
||||
|
||||
size = frame.getPayloadLength();
|
||||
if (size > windowSize)
|
||||
{
|
||||
size = windowSize;
|
||||
}
|
||||
|
||||
buffer = connection.getGenerator().generate(size,frame);
|
||||
// TODO: windowSize should adjust according to some sort of flow control rules.
|
||||
buffer = connection.getGenerator().generate(windowSize,frame);
|
||||
return buffer;
|
||||
}
|
||||
catch (Throwable x)
|
||||
|
|
|
@ -19,6 +19,8 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
||||
/**
|
||||
* Support class for reading binary message data as an InputStream.
|
||||
*/
|
||||
|
@ -28,6 +30,7 @@ public class MessageInputStream extends InputStream implements StreamAppender
|
|||
|
||||
public MessageInputStream(ByteBuffer buf)
|
||||
{
|
||||
BufferUtil.clearToFill(buf);
|
||||
this.buffer = buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,8 @@ import java.io.IOException;
|
|||
import java.io.Reader;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
||||
/**
|
||||
* Support class for reading text message data as an Reader.
|
||||
* <p>
|
||||
|
@ -30,6 +32,7 @@ public class MessageReader extends Reader implements StreamAppender
|
|||
|
||||
public MessageReader(ByteBuffer buf)
|
||||
{
|
||||
BufferUtil.clearToFill(buf);
|
||||
this.buffer = buf;
|
||||
}
|
||||
|
||||
|
|
|
@ -160,15 +160,17 @@ public class Generator
|
|||
|
||||
}
|
||||
|
||||
/*
|
||||
* The generate method needs to perform two functions.
|
||||
*
|
||||
* 1 - on the initial call for a given frame it needs to generate the framing bytecode and as much of the payload as will fit in the given buffer size
|
||||
*
|
||||
* 2 - on subsequent calls it needs to return as much of the payload as will fit in the given buffer size
|
||||
/**
|
||||
* Generate, into a ByteBuffer, no more than bufferSize of contents from the frame. If the frame exceeds the bufferSize, then multiple calls to
|
||||
* {@link #generate(int, WebSocketFrame)} are required to obtain each window of ByteBuffer to complete the frame.
|
||||
*/
|
||||
public ByteBuffer generate(int bufferSize, WebSocketFrame frame)
|
||||
public ByteBuffer generate(int windowSize, WebSocketFrame frame)
|
||||
{
|
||||
if (windowSize < OVERHEAD)
|
||||
{
|
||||
throw new IllegalArgumentException("Cannot have windowSize less than " + OVERHEAD);
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
StringBuilder dbg = new StringBuilder();
|
||||
|
@ -192,8 +194,11 @@ public class Generator
|
|||
/*
|
||||
* prepare the byte buffer to put frame into
|
||||
*/
|
||||
ByteBuffer buffer = bufferPool.acquire(bufferSize + OVERHEAD,true);
|
||||
ByteBuffer buffer = bufferPool.acquire(windowSize,true);
|
||||
BufferUtil.clearToFill(buffer);
|
||||
// since the buffer from the pool can exceed the window size, artificially
|
||||
// limit the buffer to the window size.
|
||||
buffer.limit(buffer.position() + windowSize);
|
||||
|
||||
if (frame.remaining() == frame.getPayloadLength())
|
||||
{
|
||||
|
|
|
@ -95,41 +95,6 @@ public class Parser
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the bytes from one buffer to the other, demasking the content if necessary.
|
||||
*
|
||||
* @param src
|
||||
* the source {@link ByteBuffer}
|
||||
* @param dest
|
||||
* the destination {@link ByteBuffer}
|
||||
* @param length
|
||||
* the length of bytes to worry about
|
||||
* @return the number of bytes copied
|
||||
*/
|
||||
protected int copyBuffer(ByteBuffer src, ByteBuffer dest, int length)
|
||||
{
|
||||
int amt = Math.min(length,src.remaining());
|
||||
if (frame.isMasked())
|
||||
{
|
||||
// Demask the content 1 byte at a time
|
||||
// FIXME: on partially parsed frames this needs an offset from prior parse
|
||||
byte mask[] = frame.getMask();
|
||||
for (int i = 0; i < amt; i++)
|
||||
{
|
||||
dest.put((byte)(src.get() ^ mask[i % 4]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Copy the content as-is
|
||||
// TODO: Look into having a BufferUtil.put(from,to,len) method
|
||||
byte b[] = new byte[amt];
|
||||
src.get(b,0,amt);
|
||||
dest.put(b,0,amt);
|
||||
}
|
||||
return amt;
|
||||
}
|
||||
|
||||
public IncomingFrames getIncomingFramesHandler()
|
||||
{
|
||||
return incomingFramesHandler;
|
||||
|
@ -441,11 +406,23 @@ public class Parser
|
|||
payload = ByteBuffer.allocate(payloadLength);
|
||||
}
|
||||
|
||||
copyBuffer(buffer,payload,payload.remaining());
|
||||
BufferUtil.put(buffer,payload);
|
||||
|
||||
if (payload.position() >= payloadLength)
|
||||
{
|
||||
BufferUtil.flipToFlush(payload,0);
|
||||
|
||||
// demask (if needed)
|
||||
if (frame.isMasked())
|
||||
{
|
||||
byte mask[] = frame.getMask();
|
||||
int end = payload.limit();
|
||||
for (int i = payload.position(); i < end; i++)
|
||||
{
|
||||
payload.put(i,(byte)(payload.get(i) ^ mask[i % 4]));
|
||||
}
|
||||
}
|
||||
|
||||
frame.setPayload(payload);
|
||||
this.payload = null;
|
||||
return true;
|
||||
|
|
|
@ -391,10 +391,6 @@ public class DeflateFrameExtensionTest
|
|||
ByteBuffer compressed = actual.getPayload().slice();
|
||||
ByteBuffer uncompressed = ext.inflate(compressed);
|
||||
|
||||
System.err.printf("Expected : %s%n",BufferUtil.toDetailString(expected));
|
||||
System.err.printf("Compressed : %s%n",BufferUtil.toDetailString(compressed));
|
||||
System.err.printf("Uncompressed: %s%n",BufferUtil.toDetailString(uncompressed));
|
||||
|
||||
Assert.assertThat(prefix + ".payloadLength",uncompressed.remaining(),is(expected.remaining()));
|
||||
ByteBufferAssert.assertEquals(prefix + ".payload",expected,uncompressed);
|
||||
}
|
||||
|
|
|
@ -2,15 +2,19 @@ package org.eclipse.jetty.websocket.io;
|
|||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.driver.WebSocketEventDriver;
|
||||
import org.eclipse.jetty.websocket.protocol.OutgoingFramesCapture;
|
||||
import org.junit.rules.TestName;
|
||||
|
||||
public class LocalWebSocketSession extends WebSocketSession
|
||||
{
|
||||
private String id;
|
||||
private OutgoingFramesCapture outgoingCapture;
|
||||
|
||||
public LocalWebSocketSession(TestName testname)
|
||||
{
|
||||
this(testname,null);
|
||||
outgoingCapture = new OutgoingFramesCapture();
|
||||
setOutgoing(outgoingCapture);
|
||||
}
|
||||
|
||||
public LocalWebSocketSession(TestName testname, WebSocketEventDriver driver)
|
||||
|
@ -19,6 +23,11 @@ public class LocalWebSocketSession extends WebSocketSession
|
|||
this.id = testname.getMethodName();
|
||||
}
|
||||
|
||||
public OutgoingFramesCapture getOutgoingCapture()
|
||||
{
|
||||
return outgoingCapture;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -12,29 +12,37 @@ import org.junit.Test;
|
|||
|
||||
public class GeneratorTest
|
||||
{
|
||||
/**
|
||||
* Test the windowed generate of a frame that has no masking.
|
||||
*/
|
||||
@Test
|
||||
public void testWindowedGenerate()
|
||||
{
|
||||
// A decent sized frame, no masking
|
||||
byte payload[] = new byte[10240];
|
||||
Arrays.fill(payload,(byte)0x44);
|
||||
|
||||
WebSocketFrame frame = WebSocketFrame.binary(payload);
|
||||
|
||||
// tracking values
|
||||
int totalParts = 0;
|
||||
int totalBytes = 0;
|
||||
int windowSize = 1024;
|
||||
int expectedHeaderSize = 4;
|
||||
int expectedParts = (int)Math.ceil((double)(payload.length + expectedHeaderSize) / windowSize);
|
||||
|
||||
// the generator
|
||||
Generator generator = new UnitGenerator();
|
||||
|
||||
// lets see how many parts the generator makes
|
||||
boolean done = false;
|
||||
while (!done)
|
||||
{
|
||||
Assert.assertThat("Too many parts",totalParts,lessThan(20));
|
||||
// sanity check in loop, our test should fail if this is true.
|
||||
Assert.assertThat("Too many parts",totalParts,lessThanOrEqualTo(expectedParts));
|
||||
|
||||
ByteBuffer buf = generator.generate(windowSize,frame);
|
||||
// System.out.printf("Generated buf.limit() = %,d%n",buf.limit());
|
||||
Assert.assertThat("Generated should not exceed window size",buf.remaining(),lessThanOrEqualTo(windowSize));
|
||||
|
||||
totalBytes += buf.remaining();
|
||||
totalParts++;
|
||||
|
@ -42,6 +50,7 @@ public class GeneratorTest
|
|||
done = (frame.remaining() <= 0);
|
||||
}
|
||||
|
||||
// validate
|
||||
Assert.assertThat("Created Parts",totalParts,is(expectedParts));
|
||||
Assert.assertThat("Created Bytes",totalBytes,is(payload.length + expectedHeaderSize));
|
||||
}
|
||||
|
@ -49,6 +58,7 @@ public class GeneratorTest
|
|||
@Test
|
||||
public void testWindowedGenerateWithMasking()
|
||||
{
|
||||
// A decent sized frame, with masking
|
||||
byte payload[] = new byte[10240];
|
||||
Arrays.fill(payload,(byte)0x55);
|
||||
|
||||
|
@ -56,15 +66,17 @@ public class GeneratorTest
|
|||
{ 0x2A, (byte)0xF0, 0x0F, 0x00 };
|
||||
|
||||
WebSocketFrame frame = WebSocketFrame.binary(payload);
|
||||
frame.setMask(mask);
|
||||
frame.setMask(mask); // masking!
|
||||
|
||||
// tracking values
|
||||
int totalParts = 0;
|
||||
int totalBytes = 0;
|
||||
int windowSize = 2929; // important, use an odd # window size to test masking across window barriers
|
||||
int windowSize = 2929; // important for test, use an odd # window size to test masking across window barriers
|
||||
int expectedHeaderSize = 8;
|
||||
int expectedParts = (int)Math.ceil((double)(payload.length + expectedHeaderSize) / windowSize);
|
||||
|
||||
// Buffer to capture generated bytes
|
||||
// Buffer to capture generated bytes (we do this to validate that the masking
|
||||
// is working correctly
|
||||
ByteBuffer completeBuf = ByteBuffer.allocate(payload.length + expectedHeaderSize);
|
||||
BufferUtil.clearToFill(completeBuf);
|
||||
|
||||
|
@ -74,10 +86,11 @@ public class GeneratorTest
|
|||
boolean done = false;
|
||||
while (!done)
|
||||
{
|
||||
Assert.assertThat("Too many parts",totalParts,lessThan(20));
|
||||
// sanity check in loop, our test should fail if this is true.
|
||||
Assert.assertThat("Too many parts",totalParts,lessThanOrEqualTo(expectedParts));
|
||||
|
||||
ByteBuffer buf = generator.generate(windowSize,frame);
|
||||
// System.out.printf("Generated buf.limit() = %,d%n",buf.limit());
|
||||
Assert.assertThat("Generated should not exceed window size",buf.remaining(),lessThanOrEqualTo(windowSize));
|
||||
|
||||
totalBytes += buf.remaining();
|
||||
totalParts++;
|
||||
|
@ -104,7 +117,7 @@ public class GeneratorTest
|
|||
Assert.assertThat("Frame.opcode",actual.getOpCode(),is(OpCode.BINARY));
|
||||
Assert.assertThat("Frame.payloadLength",actual.getPayloadLength(),is(payload.length));
|
||||
|
||||
// Validate payload content for proper masking
|
||||
// Validate payload contents for proper masking
|
||||
ByteBuffer actualData = actual.getPayload().slice();
|
||||
Assert.assertThat("Frame.payload.remaining",actualData.remaining(),is(payload.length));
|
||||
while (actualData.remaining() > 0)
|
||||
|
|
|
@ -19,11 +19,9 @@ import static org.hamcrest.Matchers.*;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.protocol.OpCode;
|
||||
import org.eclipse.jetty.websocket.protocol.Parser;
|
||||
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
|
@ -41,23 +39,24 @@ public class RFC6455ExamplesParserTest
|
|||
parser.setIncomingFramesHandler(capture);
|
||||
|
||||
ByteBuffer buf = ByteBuffer.allocate(16);
|
||||
BufferUtil.clearToFill(buf);
|
||||
|
||||
// Raw bytes as found in RFC 6455, Section 5.7 - Examples
|
||||
// A fragmented unmasked text message (part 1 of 2 "Hel")
|
||||
buf.put(new byte[]
|
||||
{ (byte)0x01, (byte)0x03, 0x48, (byte)0x65, 0x6c });
|
||||
buf.flip();
|
||||
|
||||
// Parse #1
|
||||
BufferUtil.flipToFlush(buf,0);
|
||||
parser.parse(buf);
|
||||
|
||||
// part 2 of 2 "lo" (A continuation frame of the prior text message)
|
||||
buf.flip();
|
||||
BufferUtil.flipToFill(buf);
|
||||
buf.put(new byte[]
|
||||
{ (byte)0x80, 0x02, 0x6c, 0x6f });
|
||||
buf.flip();
|
||||
|
||||
// Parse #2
|
||||
BufferUtil.flipToFlush(buf,0);
|
||||
parser.parse(buf);
|
||||
|
||||
capture.assertNoErrors();
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
org.eclipse.jetty.websocket.LEVEL=WARN
|
|
@ -6,6 +6,9 @@
|
|||
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
|
||||
<listEntry value="1"/>
|
||||
</listAttribute>
|
||||
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
|
||||
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
|
||||
</listAttribute>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value=""/>
|
||||
<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
|
||||
<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
|
||||
|
|
|
@ -17,28 +17,21 @@ package org.eclipse.jetty.websocket.server;
|
|||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.protocol.Generator;
|
||||
import org.eclipse.jetty.websocket.protocol.OpCode;
|
||||
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.server.helper.RFCServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -52,68 +45,6 @@ import org.junit.Test;
|
|||
*/
|
||||
public class WebSocketServletRFCTest
|
||||
{
|
||||
@SuppressWarnings("serial")
|
||||
public static class RFCServlet extends WebSocketServlet
|
||||
{
|
||||
@Override
|
||||
public void registerWebSockets(WebSocketServerFactory factory)
|
||||
{
|
||||
factory.register(RFCSocket.class);
|
||||
}
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class RFCSocket
|
||||
{
|
||||
private static Logger LOG = Log.getLogger(RFCSocket.class);
|
||||
|
||||
private WebSocketConnection conn;
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onBinary(byte buf[], int offset, int len)
|
||||
{
|
||||
LOG.debug("onBinary(byte[{}],{},{})",buf.length,offset,len);
|
||||
|
||||
// echo the message back.
|
||||
try
|
||||
{
|
||||
this.conn.write(null,new FutureCallback<Void>(),buf,offset,len);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onOpen(WebSocketConnection conn)
|
||||
{
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onText(String message)
|
||||
{
|
||||
LOG.debug("onText({})",message);
|
||||
// Test the RFC 6455 close code 1011 that should close
|
||||
// trigger a WebSocket server terminated close.
|
||||
if (message.equals("CRASH"))
|
||||
{
|
||||
throw new RuntimeException("Something bad happened");
|
||||
}
|
||||
|
||||
// echo the message back.
|
||||
try
|
||||
{
|
||||
this.conn.write(null,new FutureCallback<Void>(),message);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static Generator generator = new UnitGenerator();
|
||||
private static SimpleServletServer server;
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package org.eclipse.jetty.websocket.server.ab;
|
||||
|
||||
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketServlet;
|
||||
|
||||
/**
|
||||
* Servlet with bigger message policy sizes, with registered simple echo socket.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ABServlet extends WebSocketServlet
|
||||
{
|
||||
private static final int KBYTE = 1024;
|
||||
private static final int MBYTE = KBYTE * KBYTE;
|
||||
|
||||
@Override
|
||||
public void registerWebSockets(WebSocketServerFactory factory)
|
||||
{
|
||||
factory.register(ABSocket.class);
|
||||
|
||||
factory.getPolicy().setBufferSize(2 * MBYTE);
|
||||
factory.getPolicy().setMaxTextMessageSize(2 * MBYTE);
|
||||
factory.getPolicy().setMaxBinaryMessageSize(2 * MBYTE);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package org.eclipse.jetty.websocket.server.ab;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketConnection;
|
||||
|
||||
/**
|
||||
* Simple Echo WebSocket, using async writes of echo
|
||||
*/
|
||||
@WebSocket
|
||||
public class ABSocket
|
||||
{
|
||||
private static Logger LOG = Log.getLogger(ABSocket.class);
|
||||
|
||||
private WebSocketConnection conn;
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onBinary(byte buf[], int offset, int len)
|
||||
{
|
||||
LOG.debug("onBinary(byte[{}],{},{})",buf.length,offset,len);
|
||||
|
||||
// echo the message back.
|
||||
try
|
||||
{
|
||||
this.conn.write(null,new FutureCallback<Void>(),buf,offset,len);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onOpen(WebSocketConnection conn)
|
||||
{
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onText(String message)
|
||||
{
|
||||
LOG.debug("onText({})",message);
|
||||
|
||||
// echo the message back.
|
||||
try
|
||||
{
|
||||
this.conn.write(null,new FutureCallback<Void>(),message);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -3,7 +3,6 @@ package org.eclipse.jetty.websocket.server.ab;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.server.SimpleServletServer;
|
||||
import org.eclipse.jetty.websocket.server.examples.MyEchoServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
||||
|
@ -20,7 +19,7 @@ public abstract class AbstractABCase
|
|||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new SimpleServletServer(new MyEchoServlet());
|
||||
server = new SimpleServletServer(new ABServlet());
|
||||
server.start();
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package org.eclipse.jetty.websocket.server.helper;
|
||||
|
||||
import org.eclipse.jetty.websocket.server.WebSocketServerFactory;
|
||||
import org.eclipse.jetty.websocket.server.WebSocketServlet;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class RFCServlet extends WebSocketServlet
|
||||
{
|
||||
@Override
|
||||
public void registerWebSockets(WebSocketServerFactory factory)
|
||||
{
|
||||
factory.register(RFCSocket.class);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package org.eclipse.jetty.websocket.server.helper;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketConnection;
|
||||
|
||||
@WebSocket
|
||||
public class RFCSocket
|
||||
{
|
||||
private static Logger LOG = Log.getLogger(RFCSocket.class);
|
||||
|
||||
private WebSocketConnection conn;
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onBinary(byte buf[], int offset, int len)
|
||||
{
|
||||
LOG.debug("onBinary(byte[{}],{},{})",buf.length,offset,len);
|
||||
|
||||
// echo the message back.
|
||||
try
|
||||
{
|
||||
this.conn.write(null,new FutureCallback<Void>(),buf,offset,len);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onOpen(WebSocketConnection conn)
|
||||
{
|
||||
this.conn = conn;
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onText(String message)
|
||||
{
|
||||
LOG.debug("onText({})",message);
|
||||
// Test the RFC 6455 close code 1011 that should close
|
||||
// trigger a WebSocket server terminated close.
|
||||
if (message.equals("CRASH"))
|
||||
{
|
||||
throw new RuntimeException("Something bad happened");
|
||||
}
|
||||
|
||||
// echo the message back.
|
||||
try
|
||||
{
|
||||
this.conn.write(null,new FutureCallback<Void>(),message);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.io.LEVEL=WARN
|
||||
org.eclipse.jetty.server.LEVEL=WARN
|
||||
org.eclipse.jetty.websocket.server.helper.RFCSocket.LEVEL=OFF
|
||||
# org.eclipse.jetty.util.thread.QueuedThreadPool.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.io.SelectorManager.LEVEL=INFO
|
||||
org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.extensions.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.protocol.Generator.LEVEL=INFO
|
||||
# org.eclipse.jetty.websocket.protocol.Parser.LEVEL=INFO
|
||||
|
|
Loading…
Reference in New Issue