Merge branch 'jetty-9' of ssh://git.eclipse.org/gitroot/jetty/org.eclipse.jetty.project into jetty-9

This commit is contained in:
Jesse McConnell 2012-06-27 09:10:33 -05:00
commit a4ef07443a
16 changed files with 1258 additions and 1614 deletions

View File

@ -1,43 +0,0 @@
/*******************************************************************************
* Copyright (c) 2011 Intalio, Inc.
* ======================================================================
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*******************************************************************************/
// ========================================================================
// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.websocket;
import java.io.IOException;
/* ------------------------------------------------------------ */
/** WebSocketGenerator.
*/
public interface WebSocketGenerator
{
int flush() throws IOException;
boolean isBufferEmpty();
void addFrame(byte flags,byte opcode, byte[] content, int offset, int length) throws IOException;
}

View File

@ -1,275 +0,0 @@
/*******************************************************************************
* Copyright (c) 2011 Intalio, Inc.
* ======================================================================
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*******************************************************************************/
// ========================================================================
// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
package org.eclipse.jetty.websocket;
import java.nio.ByteBuffer;
import org.eclipse.jetty.websocket.generator.Generator;
/* ------------------------------------------------------------ */
/** WebSocketGenerator.
* This class generates websocket packets.
* It is fully synchronized because it is likely that async
* threads will call the addMessage methods while other
* threads are flushing the generator.
* @deprecated see {@link Generator} replacement
*/
@Deprecated
public class WebSocketGeneratorRFC6455 /* implements WebSocketGenerator */
{
// final private WebSocketBuffers _buffers;
// final private EndPoint _endp;
private ByteBuffer _buffer;
// private final byte[] _mask=new byte[4];
private int _m;
private boolean _opsent;
// private final MaskGen _maskGen;
private boolean _closed;
/* TODO: Migrate to new Jetty9 IO
public WebSocketGeneratorRFC6455(WebSocketBuffers buffers, EndPoint endp)
{
_buffers=buffers;
_endp=endp;
_maskGen=null;
}
public WebSocketGeneratorRFC6455(WebSocketBuffers buffers, EndPoint endp, MaskGen maskGen)
{
_buffers=buffers;
_endp=endp;
_maskGen=maskGen;
}
*/
public synchronized ByteBuffer getBuffer()
{
return _buffer;
}
/* TODO: Migrate to new Jetty9 IO
public synchronized void addFrame(byte flags, byte opcode, byte[] content, int offset, int length) throws IOException
{
// System.err.printf("<< %s %s %s\n",TypeUtil.toHexString(flags),TypeUtil.toHexString(opcode),length);
if (_closed)
throw new EofException("Closed");
if (opcode==WebSocketConnectionRFC6455.OP_CLOSE)
_closed=true;
boolean mask=_maskGen!=null;
if (_buffer==null)
_buffer=mask?_buffers.getData():_buffers.getDirectBuffer();
boolean last=WebSocketConnectionRFC6455.isLastFrame(flags);
int space=mask?14:10;
do
{
opcode = _opsent?WebSocketConnectionRFC6455.OP_CONTINUATION:opcode;
opcode=(byte)(((0xf&flags)<<4)+(0xf&opcode));
_opsent=true;
int payload=length;
if (payload+space>_buffer.capacity())
{
// We must fragement, so clear FIN bit
opcode=(byte)(opcode&0x7F); // Clear the FIN bit
payload=_buffer.capacity()-space;
}
else if (last)
opcode= (byte)(opcode|0x80); // Set the FIN bit
// ensure there is space for header
if (_buffer.space() <= space)
{
flushBuffer();
if (_buffer.space() <= space)
flush();
}
// write the opcode and length
if (payload>0xffff)
{
_buffer.put(new byte[]{
opcode,
mask?(byte)0xff:(byte)0x7f,
(byte)0,
(byte)0,
(byte)0,
(byte)0,
(byte)((payload>>24)&0xff),
(byte)((payload>>16)&0xff),
(byte)((payload>>8)&0xff),
(byte)(payload&0xff)});
}
else if (payload >=0x7e)
{
_buffer.put(new byte[]{
opcode,
mask?(byte)0xfe:(byte)0x7e,
(byte)(payload>>8),
(byte)(payload&0xff)});
}
else
{
_buffer.put(new byte[]{
opcode,
(byte)(mask?(0x80|payload):payload)});
}
// write mask
if (mask)
{
_maskGen.genMask(_mask);
_m=0;
_buffer.put(_mask);
}
// write payload
int remaining = payload;
while (remaining > 0)
{
_buffer.compact();
int chunk = remaining < _buffer.space() ? remaining : _buffer.space();
if (mask)
{
for (int i=0;i<chunk;i++)
_buffer.put((byte)(content[offset+ (payload-remaining)+i]^_mask[+_m++%4]));
}
else
_buffer.put(content, offset + (payload - remaining), chunk);
remaining -= chunk;
if (_buffer.space() > 0)
{
// Gently flush the data, issuing a non-blocking write
flushBuffer();
}
else
{
// Forcibly flush the data, issuing a blocking write
flush();
if (remaining == 0)
{
// Gently flush the data, issuing a non-blocking write
flushBuffer();
}
}
}
offset+=payload;
length-=payload;
}
while (length>0);
_opsent=!last;
if (_buffer!=null && _buffer.length()==0)
{
_buffers.returnBuffer(_buffer);
_buffer=null;
}
}
public synchronized int flushBuffer() throws IOException
{
if (!_endp.isOpen())
throw new EofException();
if (_buffer!=null)
{
int flushed=_buffer.hasContent()?_endp.flush(_buffer):0;
if (_closed&&_buffer.length()==0)
_endp.shutdownOutput();
return flushed;
}
return 0;
}
public synchronized int flush() throws IOException
{
if (_buffer==null)
return 0;
int result = flushBuffer();
if (!_endp.isBlocking())
{
long now = System.currentTimeMillis();
long end=now+_endp.getMaxIdleTime();
while (_buffer.length()>0)
{
boolean ready = _endp.blockWritable(end-now);
if (!ready)
{
now = System.currentTimeMillis();
if (now<end)
continue;
throw new IOException("Write timeout");
}
result += flushBuffer();
}
}
_buffer.compact();
return result;
}
public synchronized boolean isBufferEmpty()
{
return _buffer==null || _buffer.length()==0;
}
public synchronized void returnBuffer()
{
if (_buffer!=null && _buffer.length()==0)
{
_buffers.returnBuffer(_buffer);
_buffer=null;
}
}
@Override
public String toString()
{
// Do NOT use synchronized (this)
// because it's very easy to deadlock when debugging is enabled.
// We do a best effort to print the right toString() and that's it.
ByteBuffer buffer = _buffer;
return String.format("%s@%x closed=%b buffer=%d",
getClass().getSimpleName(),
hashCode(),
_closed,
buffer == null ? -1 : buffer.length());
}
*/
}

View File

@ -0,0 +1,31 @@
package org.eclipse.jetty.websocket.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.nio.ByteBuffer;
import org.eclipse.jetty.websocket.api.WebSocketConnection;
/**
* Annotation for tagging methods to receive Binary message events.
* <p>
* Acceptable method patterns.<br>
* Note: <code><u>methodName</u></code> can be any name you want to use.
* <ol>
* <li><code>public void methodName(byte payload[], int offset, int length)</code></li>
* <li><code>public void methodName({@link ByteBuffer} payload)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, byte payload[], int offset, int length)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, {@link ByteBuffer} payload)</code></li>
* </ol>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value =
{ ElementType.METHOD })
public @interface OnWebSocketBinary
{
/* no config */
}

View File

@ -0,0 +1,28 @@
package org.eclipse.jetty.websocket.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.eclipse.jetty.websocket.api.WebSocketConnection;
/**
* Annotation for tagging methods to receive connection close events.
* <p>
* Acceptable method patterns.<br>
* Note: <code>methodName</code> can be any name you want to use.
* <ol>
* <li><code>public void methodName(int statusCode, String reason)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, int statusCode, String reason)</code></li>
* </ol>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value =
{ ElementType.METHOD })
public @interface OnWebSocketClose
{
/* no config */
}

View File

@ -0,0 +1,27 @@
package org.eclipse.jetty.websocket.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.eclipse.jetty.websocket.api.WebSocketConnection;
/**
* Annotation for tagging methods to receive connection open events.
* <p>
* Only 1 acceptable method pattern for this annotation.<br>
* Note: <code>methodName</code> can be any name you want to use.
* <ol>
* <li><code>public void methodName({@link WebSocketConnection} conn)</code></li>
* </ol>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value =
{ ElementType.METHOD })
public @interface OnWebSocketConnect
{
/* no config */
}

View File

@ -0,0 +1,45 @@
package org.eclipse.jetty.websocket.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.eclipse.jetty.websocket.api.WebSocketConnection;
import org.eclipse.jetty.websocket.frames.BaseFrame;
/**
* (ADVANCED) Annotation for tagging methods to receive frame events.
* <p>
* Note: any frame derived from {@link BaseFrame} is acceptable to use as the last parameter here.
* <p>
* Acceptable method patterns.<br>
* Note: <code>methodName</code> can be any name you want to use.
* <ol>
* <li><code>public void methodName({@link BaseFrame} frame)</code></li>
* <li><code>public void methodName(BinaryFrame frame)</code></li>
* <li><code>public void methodName(CloseFrame frame)</code></li>
* <li><code>public void methodName(ControlFrame frame)</code></li>
* <li><code>public void methodName(DataFrame frame)</code></li>
* <li><code>public void methodName(PingFrame frame)</code></li>
* <li><code>public void methodName(PongFrame frame)</code></li>
* <li><code>public void methodName(TextFrame frame)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, {@link BaseFrame} frame)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, BinaryFrame frame)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, CloseFrame frame)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, ControlFrame frame)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, DataFrame frame)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, PingFrame frame)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, PongFrame frame)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, TextFrame frame)</code></li>
* </ol>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value =
{ ElementType.METHOD })
public @interface OnWebSocketFrame
{
/* no config */
}

View File

@ -0,0 +1,28 @@
package org.eclipse.jetty.websocket.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.eclipse.jetty.websocket.api.WebSocketConnection;
/**
* Annotation for tagging methods to receive Text message events.
* <p>
* Acceptable method patterns.<br>
* Note: <code>methodName</code> can be any name you want to use.
* <ol>
* <li><code>public void methodName(String text)</code></li>
* <li><code>public void methodName({@link WebSocketConnection} conn, String text)</code></li>
* </ol>
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value =
{ ElementType.METHOD })
public @interface OnWebSocketText
{
/* no config */
}

View File

@ -0,0 +1,23 @@
package org.eclipse.jetty.websocket.annotations;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Tags a POJO as being a WebSocket class.
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value =
{ ElementType.TYPE })
public @interface WebSocket
{
int maxBinarySize() default 8192;
int maxBufferSize() default 8192;
int maxTextSize() default 8192;
}

View File

@ -1,163 +0,0 @@
package org.eclipse.jetty.websocket.api;
import java.io.IOException;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.websocket.frames.BaseFrame;
import org.eclipse.jetty.websocket.frames.BinaryFrame;
import org.eclipse.jetty.websocket.frames.TextFrame;
/**
* Constants for WebSocket protocol as-defined in <a href="https://tools.ietf.org/html/rfc6455">RFC-6455</a>.
* <p>
* NOTE: Proposed interface for API (not yet settled)
*/
public interface WebSocket
{
/**
* Advanced usage, for those interested in flags
*/
public static interface BinaryFrameListener
{
void onWebSocketBinary(BinaryFrame frame);
}
/**
* Basic usage.
*/
public static interface BinaryListener
{
void onWebSocketBinary(byte buf[], int offset, int len);
}
/**
* NIO flavored basic usage.
*/
public static interface ByteBufferListener
{
void onWebSocketBinary(ByteBuffer... buffer);
}
public static interface Connection
{
/**
* Terminate connection, normally, without a reason.
* <p>
* Issues a CloseFrame via {@link #write(Object, Callback, BaseFrame...)}
*
* @TODO: determine contract for dealing with pending incoming frames.
*/
void close();
/**
* Terminate connection, with status code.
* <p>
* Issues a CloseFrame via {@link #write(Object, Callback, BaseFrame...)}
*
* @param statusCode
* the status code
* @param reason
* the (optional) reason. (can be null for no reason)
* @TODO: determine contract for dealing with pending incoming frames.
*/
void close(int statusCode, String reason);
String getSubProtocol();
boolean isOpen();
/**
* Basic usage, results in non-blocking call to {@link #write(Object, Callback, ByteBuffer...)}
*/
void sendBinary(byte[] data, int offset, int length) throws IOException;
/**
* Basic usage, results in non-blocking call to {@link #write(Object, Callback, ByteBuffer...)}
*/
void sendBinary(ByteBuffer buffer) throws IOException;
/**
* Basic usage, results in non-blocking call to {@link #write(Object, Callback, ByteBuffer...)}
*/
void sendBinary(ByteBuffer... buffers) throws IOException;
/**
* Basic usage, results in non-blocking call to {@link #write(Object, Callback, String...)}
*/
void sendText(String message) throws IOException;
/**
* Advanced usage, with callbacks, enters into outgoing queue
*/
<C> void write(C context, Callback<C> callback, BaseFrame... frames) throws IOException;
/**
* Advanced usage, with callbacks, enters into outgoing queue
*/
<C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws IOException;
/**
* Advanced usage, with callbacks, enters into outgoing queue
*/
<C> void write(C context, Callback<C> callback, String... messages) throws IOException;
}
/**
* Advanced usage, text frame access to flags as well
*/
public static interface TextFrameListener
{
void onWebSocketTextFrame(TextFrame frame);
}
/**
* Basic usage
*/
public static interface TextListener
{
void onWebSocketText(String message);
}
/**
* Per <a href="https://tools.ietf.org/html/rfc6455#section-1.3">RFC 6455, section 1.3</a> - Opening Handshake - this version is "13"
*/
public final static int VERSION = 13;
void onClose(int statusCode, String reason);
void onConnect(WebSocket.Connection connection);
/**
* Annotation Ideas (Various WebSocket Events):
*
* <pre>
* @OnWebSocketHandshake (server side only?)
* public void {methodname}(WebSocket.Connection conn)
*
* @OnWebSocketConnect
* public void {methodname}(WebSocket.Connection conn)
*
* @OnWebSocketDisconnect
* public void {methodname}(WebSocket.Connection conn)
*
* @OnWebSocketFrame(type=CloseFrame.class)
* public void {methodname}(CloseFrame frame);
* public void {methodname}(WebSocket.Connection conn, CloseFrame frame);
*
* @OnWebSocketText
* public void {methodname}(String text);
* public void {methodname}(WebSocket.Connection conn, String text);
*
* @OnWebSocketBinary
* public void {methodname}(byte buf[], int offset, int length);
* public void {methodname}(WebSocket.Connection conn, byte buf[], int offset, int length);
* public void {methodname}(ByteBuffer buffer);
* public void {methodname}(WebSocket.Connection conn, ByteBuffer buffer);
*
* @OnWebSocketClose
* public void {methodnamne}(int statusCode, String reason);
* public void {methodnamne}(WebSocket.Connection conn, int statusCode, String reason);
* </pre>
*/
}

View File

@ -0,0 +1,104 @@
package org.eclipse.jetty.websocket.api;
import java.io.IOException;
import java.net.InetAddress;
import java.nio.ByteBuffer;
import org.eclipse.jetty.util.Callback;
/**
* Connection interface for WebSocket protocol <a href="https://tools.ietf.org/html/rfc6455">RFC-6455</a>.
*/
public interface WebSocketConnection
{
/**
* Terminate connection, {@link StatusCode#NORMAL}, without a reason.
* <p>
* Basic usage: results in an non-blocking async write, then connection close.
*/
void close();
/**
* Terminate connection, with status code.
* <p>
* Advanced usage: results in an non-blocking async write, then connection close.
*
* @param statusCode
* the status code
* @param reason
* the (optional) reason. (can be null for no reason)
* @see StatusCode
*/
void close(int statusCode, String reason);
/**
* Access the (now read-only) {@link WebSocketPolicy} in use for this connection.
*
* @return the policy in use
*/
WebSocketPolicy getPolicy();
/**
* Get the remote Address in use for this connection.
*
* @return the remote address if available. (situations like mux extension and proxying makes this information unreliable)
*/
InetAddress getRemoteAddress();
/**
* Get the SubProtocol in use for this connection.
*
* @return the negotiated sub protocol name in use for this connection.
*/
String getSubProtocol();
/**
* Simple test to see if connection is open (and not closed)
*
* @return true if connection still open
*/
boolean isOpen();
/**
* Send a binary message.
* <p>
* Basic usage, results in an non-blocking async write.
*/
void write(byte[] data, int offset, int length) throws IOException;
/**
* Send a series of binary messages.
* <p>
* Note: each buffer results in its own binary message frame.
* <p>
* Basic usage, results in a series of non-blocking async writes.
*/
void write(ByteBuffer... buffers) throws IOException;
/**
* Send a series of binary messages.
* <p>
* Note: each buffer results in its own binary message frame.
* <p>
* Advanced usage, with callbacks, allows for concurrent NIO style results of the entire write operation. (Callback is only called once at the end of
* processing all of the buffers)
*/
<C> void write(C context, Callback<C> callback, ByteBuffer... buffers) throws IOException;
/**
* Send a series of text messages.
* <p>
* Note: each messages results in its own text message frame.
* <p>
* Advanced usage, with callbacks, allows for concurrent NIO style results of the entire write operation. (Callback is only called once at the end of
* processing all of the buffers)
*/
<C> void write(C context, Callback<C> callback, String... messages) throws IOException;
/**
* Send a text message.
* <p>
* Basic usage, results in an non-blocking async write.
*/
void write(String message) throws IOException;
}

View File

@ -0,0 +1,60 @@
package org.eclipse.jetty.websocket.api;
/**
* Basic WebSocket Listener interface for incoming WebSocket events.
*/
public interface WebSocketListener
{
/**
* A WebSocket binary frame has been received.
*
* @param payload the raw payload array received
* @param offset the offset in the payload array where the data starts
* @param len the length of bytes in the payload
*/
void onWebSocketBinary(byte payload[], int offset, int len);
/**
* A Close Event was received.
* <p>
* The underlying {@link WebSocketConnection} will be considered closed at this point.
*
* @param statusCode
* the close status code. (See {@link StatusCode})
* @param reason
* the optional reason for the close.
*/
void onWebSocketClose(int statusCode, String reason);
/**
* A WebSocketConnection has connected successfully and is ready to be used.
* <p>
* Note: It is a good idea to track this connection as a field in your object so that you can write messages back.
*
* @param connection
* the connection to use to send messages on.
*/
void onWebSocketConnect(WebSocketConnection connection);
/**
* A WebSocket exception has occurred.
* <p>
* Usually this occurs from bad / malformed incoming packets. (example: bad UTF8 data, frames that are too big, violations of the spec)
* <p>
* This will result in the {@link WebSocketConnection} being closed by the implementing side.
* <p>
* Note: you will receive no {@link #onWebSocketClose(int, String)} as this condition results in the API calling
* {@link WebSocketConnection#close(int, String)} for you.
*
* @param error
* the error that occurred.
*/
void onWebSocketException(WebSocketException error);
/**
* A WebSocket Text frame was received.
*
* @param message
*/
void onWebSocketText(String message);
}

View File

@ -1,26 +1,281 @@
package org.eclipse.jetty.websocket.ab; package org.eclipse.jetty.websocket.ab;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.is;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.eclipse.jetty.io.StandardByteBufferPool;
import org.eclipse.jetty.websocket.ByteBufferAssert; 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.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.TextFrame; import org.eclipse.jetty.websocket.frames.TextFrame;
import org.eclipse.jetty.websocket.generator.Generator; import org.eclipse.jetty.websocket.generator.Generator;
import org.eclipse.jetty.websocket.parser.FrameParseCapture; import org.eclipse.jetty.websocket.parser.FrameParseCapture;
import org.eclipse.jetty.websocket.parser.Parser; import org.eclipse.jetty.websocket.parser.Parser;
import org.eclipse.jetty.websocket.parser.TextPayloadParser;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
/**
* Text Message Spec testing the {@link Generator} and {@link Parser}
*/
public class ABCase1_1 public class ABCase1_1
{ {
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER); private WebSocketPolicy policy = WebSocketPolicy.newServerPolicy();
@Test
public void testGenerate125ByteTextCase1_1_2()
{
int length = 125;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length + 16);
generator.generate(actual,textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7F;
expected.put(b);
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testGenerate126ByteTextCase1_1_3()
{
int length = 126;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length + 16);
generator.generate(actual,textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
// expected.put((byte)((length>>8) & 0xFF));
// expected.put((byte)(length & 0xFF));
expected.putShort((short)length);
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testGenerate127ByteTextCase1_1_4()
{
int length = 127;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length + 16);
generator.generate(actual,textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
// expected.put((byte)((length>>8) & 0xFF));
// expected.put((byte)(length & 0xFF));
expected.putShort((short)length);
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testGenerate128ByteTextCase1_1_5()
{
int length = 128;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length + 16);
generator.generate(actual,textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.put((byte)(length >> 8));
expected.put((byte)(length & 0xFF));
// expected.putShort((short)length);
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testGenerate65535ByteTextCase1_1_6()
{
int length = 65535;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length + 16);
generator.generate(actual,textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.put(new byte[]
{ (byte)0xff, (byte)0xff });
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testGenerate65536ByteTextCase1_1_7()
{
int length = 65536;
StringBuilder builder = new StringBuilder();
for (int i = 0; i < length; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length + 16);
generator.generate(actual,textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 11);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7F;
expected.put(b);
expected.put(new byte[]
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 });
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test @Test
public void testGenerateEmptyTextCase1_1_1() public void testGenerateEmptyTextCase1_1_1()
@ -30,7 +285,7 @@ public class ABCase1_1
Generator generator = new Generator(policy); Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(10); ByteBuffer actual = ByteBuffer.allocate(10);
generator.generate(actual, textFrame); generator.generate(actual,textFrame);
ByteBuffer expected = ByteBuffer.allocate(5); ByteBuffer expected = ByteBuffer.allocate(5);
@ -44,6 +299,217 @@ public class ABCase1_1
} }
@Test
public void testParse125ByteTextCase1_1_2()
{
int length = 125;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7F;
expected.put(b);
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse126ByteTextCase1_1_3()
{
int length = 126;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
expected.putShort((short)length);
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse127ByteTextCase1_1_4()
{
int length = 127;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
expected.putShort((short)length);
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse128ByteTextCase1_1_5()
{
int length = 128;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.putShort((short)length);
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse65535ByteTextCase1_1_6()
{
// Debug.enableDebugLogging(Parser.class);
// Debug.enableDebugLogging(TextPayloadParser.class);
int length = 65535;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.put(new byte[]
{ (byte)0xff, (byte)0xff });
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setMaxTextMessageSize(length);
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse65536ByteTextCase1_1_7()
{
int length = 65536;
ByteBuffer expected = ByteBuffer.allocate(length + 11);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7F;
expected.put(b);
expected.put(new byte[]
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00 });
for (int i = 0; i < length; ++i)
{
expected.put("*".getBytes());
}
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setMaxTextMessageSize(length);
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test @Test
public void testParseEmptyTextCase1_1_1() public void testParseEmptyTextCase1_1_1()
{ {
@ -67,469 +533,4 @@ public class ABCase1_1
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(0)); Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(0));
ByteBufferAssert.assertSize("TextFrame.payload",0,pActual.getPayload()); ByteBufferAssert.assertSize("TextFrame.payload",0,pActual.getPayload());
} }
@Test
public void testGenerate125ByteTextCase1_1_2()
{
int length = 125;
StringBuilder builder = new StringBuilder();
for ( int i = 0 ; i < length ; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length+16);
generator.generate(actual, textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7F;
expected.put(b);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParse125ByteTextCase1_1_2()
{
int length = 125;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7F;
expected.put(b);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testGenerate126ByteTextCase1_1_3()
{
int length = 126;
StringBuilder builder = new StringBuilder();
for ( int i = 0 ; i < length ; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length+16);
generator.generate(actual, textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
//expected.put((byte)((length>>8) & 0xFF));
//expected.put((byte)(length & 0xFF));
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParse126ByteTextCase1_1_3()
{
int length = 126;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testGenerate127ByteTextCase1_1_4()
{
int length = 127;
StringBuilder builder = new StringBuilder();
for ( int i = 0 ; i < length ; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length+16);
generator.generate(actual, textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
//expected.put((byte)((length>>8) & 0xFF));
//expected.put((byte)(length & 0xFF));
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParse127ByteTextCase1_1_4()
{
int length = 127;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testGenerate128ByteTextCase1_1_5()
{
int length = 128;
StringBuilder builder = new StringBuilder();
for ( int i = 0 ; i < length ; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length+16);
generator.generate(actual, textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.put((byte)(length>>8));
expected.put((byte)(length & 0xFF));
//expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParse128ByteTextCase1_1_5()
{
int length = 128;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testGenerate65535ByteTextCase1_1_6()
{
int length = 65535;
StringBuilder builder = new StringBuilder();
for ( int i = 0 ; i < length ; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length+16);
generator.generate(actual, textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.put(new byte[]{ (byte)0xff, (byte)0xff});
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParse65535ByteTextCase1_1_6()
{
//Debug.enableDebugLogging(Parser.class);
//Debug.enableDebugLogging(TextPayloadParser.class);
int length = 65535;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.put(new byte[]{ (byte)0xff, (byte)0xff});
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setMaxTextMessageSize(length);
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
@Test
public void testGenerate65536ByteTextCase1_1_7()
{
int length = 65536;
StringBuilder builder = new StringBuilder();
for ( int i = 0 ; i < length ; ++i)
{
builder.append("*");
}
TextFrame textFrame = new TextFrame(builder.toString());
textFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(length+16);
generator.generate(actual, textFrame);
ByteBuffer expected = ByteBuffer.allocate(length + 11);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7F;
expected.put(b);
expected.put(new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00});
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParse65536ByteTextCase1_1_7()
{
int length = 65536;
ByteBuffer expected = ByteBuffer.allocate(length + 11);
expected.put(new byte[]
{ (byte)0x81 });
byte b = 0x00; // no masking
b |= 0x7F;
expected.put(b);
expected.put(new byte[]{0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00});
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setMaxTextMessageSize(length);
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(TextFrame.class,1);
TextFrame pActual = (TextFrame)capture.getFrames().get(0);
Assert.assertThat("TextFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("TextFrame.payload",length,pActual.getPayload());
}
} }

View File

@ -1,76 +1,26 @@
package org.eclipse.jetty.websocket.ab; package org.eclipse.jetty.websocket.ab;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.is;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import org.eclipse.jetty.io.StandardByteBufferPool;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.websocket.ByteBufferAssert; 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.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.WebSocketPolicy;
import org.eclipse.jetty.websocket.frames.BinaryFrame; import org.eclipse.jetty.websocket.frames.BinaryFrame;
import org.eclipse.jetty.websocket.frames.TextFrame;
import org.eclipse.jetty.websocket.generator.Generator; import org.eclipse.jetty.websocket.generator.Generator;
import org.eclipse.jetty.websocket.parser.FrameParseCapture; import org.eclipse.jetty.websocket.parser.FrameParseCapture;
import org.eclipse.jetty.websocket.parser.Parser; import org.eclipse.jetty.websocket.parser.Parser;
import org.eclipse.jetty.websocket.parser.TextPayloadParser;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Test; import org.junit.Test;
/**
* Binary Message Spec testing the {@link Generator} and {@link Parser}
*/
public class ABCase1_2 public class ABCase1_2
{ {
StandardByteBufferPool bufferPool = new StandardByteBufferPool(); private WebSocketPolicy policy = WebSocketPolicy.newServerPolicy();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
@Test
public void testGenerateEmptyBinaryCase1_2_1()
{
BinaryFrame binaryFrame = new BinaryFrame(new byte[]{});
binaryFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(32);
generator.generate(actual, binaryFrame);
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x82, (byte)0x00 });
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParseEmptyBinaryCase1_2_1()
{
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x82, (byte)0x00 });
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(0));
ByteBufferAssert.assertSize("BinaryFrame.payload",0,pActual.getPayload());
}
@Test @Test
public void testGenerate125ByteBinaryCase1_2_2() public void testGenerate125ByteBinaryCase1_2_2()
@ -116,39 +66,6 @@ public class ABCase1_2
} }
@Test
public void testParse125ByteBinaryCase1_2_2()
{
int length = 125;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= length & 0x7F;
expected.put(b);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test @Test
public void testGenerate126ByteBinaryCase1_2_3() public void testGenerate126ByteBinaryCase1_2_3()
{ {
@ -197,40 +114,6 @@ public class ABCase1_2
} }
@Test
public void testParse126ByteBinaryCase1_2_3()
{
int length = 126;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test @Test
public void testGenerate127ByteBinaryCase1_2_4() public void testGenerate127ByteBinaryCase1_2_4()
{ {
@ -279,40 +162,6 @@ public class ABCase1_2
} }
@Test
public void testParse127ByteBinaryCase1_2_4()
{
int length = 127;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test @Test
public void testGenerate128ByteBinaryCase1_2_5() public void testGenerate128ByteBinaryCase1_2_5()
{ {
@ -359,40 +208,6 @@ public class ABCase1_2
} }
@Test
public void testParse128ByteBinaryCase1_2_5()
{
int length = 128;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test @Test
public void testGenerate65535ByteBinaryCase1_2_6() public void testGenerate65535ByteBinaryCase1_2_6()
{ {
@ -437,42 +252,6 @@ public class ABCase1_2
} }
@Test
public void testParse65535ByteBinaryCase1_2_6()
{
int length = 65535;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.put(new byte[]{ (byte)0xff, (byte)0xff});
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setMaxTextMessageSize(length);
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test @Test
public void testGenerate65536ByteBinaryCase1_2_7() public void testGenerate65536ByteBinaryCase1_2_7()
{ {
@ -518,6 +297,199 @@ public class ABCase1_2
} }
@Test
public void testGenerateEmptyBinaryCase1_2_1()
{
BinaryFrame binaryFrame = new BinaryFrame(new byte[]{});
binaryFrame.setFin(true);
Generator generator = new Generator(policy);
ByteBuffer actual = ByteBuffer.allocate(32);
generator.generate(actual, binaryFrame);
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x82, (byte)0x00 });
actual.flip();
expected.flip();
ByteBufferAssert.assertEquals("buffers do not match",expected,actual);
}
@Test
public void testParse125ByteBinaryCase1_2_2()
{
int length = 125;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= length & 0x7F;
expected.put(b);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse126ByteBinaryCase1_2_3()
{
int length = 126;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse127ByteBinaryCase1_2_4()
{
int length = 127;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= length & 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse128ByteBinaryCase1_2_5()
{
int length = 128;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.putShort((short)length);
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test
public void testParse65535ByteBinaryCase1_2_6()
{
int length = 65535;
ByteBuffer expected = ByteBuffer.allocate(length + 5);
expected.put(new byte[]
{ (byte)0x82 });
byte b = 0x00; // no masking
b |= 0x7E;
expected.put(b);
expected.put(new byte[]{ (byte)0xff, (byte)0xff});
for ( int i = 0 ; i < length ; ++i )
{
expected.put("*".getBytes());
}
expected.flip();
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
policy.setMaxTextMessageSize(length);
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
}
@Test @Test
public void testParse65536ByteBinaryCase1_2_7() public void testParse65536ByteBinaryCase1_2_7()
{ {
@ -553,4 +525,28 @@ public class ABCase1_2
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length)); Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(length));
ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload()); ByteBufferAssert.assertSize("BinaryFrame.payload",length,pActual.getPayload());
} }
@Test
public void testParseEmptyBinaryCase1_2_1()
{
ByteBuffer expected = ByteBuffer.allocate(5);
expected.put(new byte[]
{ (byte)0x82, (byte)0x00 });
expected.flip();
Parser parser = new Parser(policy);
FrameParseCapture capture = new FrameParseCapture();
parser.addListener(capture);
parser.parse(expected);
capture.assertNoErrors();
capture.assertHasFrame(BinaryFrame.class,1);
BinaryFrame pActual = (BinaryFrame)capture.getFrames().get(0);
Assert.assertThat("BinaryFrame.payloadLength",pActual.getPayloadLength(),is(0));
ByteBufferAssert.assertSize("BinaryFrame.payload",0,pActual.getPayload());
}
} }

View File

@ -5,7 +5,6 @@ import static org.hamcrest.Matchers.*;
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.Debug;
import org.eclipse.jetty.websocket.api.StatusCode; import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.WebSocketBehavior; import org.eclipse.jetty.websocket.api.WebSocketBehavior;
import org.eclipse.jetty.websocket.api.WebSocketPolicy; import org.eclipse.jetty.websocket.api.WebSocketPolicy;
@ -18,8 +17,6 @@ public class ClosePayloadParserTest
@Test @Test
public void testGameOver() public void testGameOver()
{ {
Debug.enableDebugLogging(Parser.class);
Debug.enableDebugLogging(ClosePayloadParser.class);
String expectedReason = "Game Over"; String expectedReason = "Game Over";
byte utf[] = expectedReason.getBytes(StringUtil.__UTF8_CHARSET); byte utf[] = expectedReason.getBytes(StringUtil.__UTF8_CHARSET);

View File

@ -61,10 +61,10 @@ public class TextPayloadParserTest
Assert.assertThat("Must be a long length payload",utf.length,greaterThan(0xFFFF)); Assert.assertThat("Must be a long length payload",utf.length,greaterThan(0xFFFF));
ByteBuffer buf = ByteBuffer.allocate(utf.length + 10); ByteBuffer buf = ByteBuffer.allocate(utf.length + 32);
buf.put((byte)0x81); buf.put((byte)0x81);
buf.put((byte)(0x80 | 0x7F)); // 0x7F == 127 (a 4 byte payload length) buf.put((byte)(0x80 | 0x7F)); // 0x7F == 127 (a 8 byte payload length)
buf.putInt(utf.length); buf.putLong(utf.length);
MaskedByteBuffer.putMask(buf); MaskedByteBuffer.putMask(buf);
MaskedByteBuffer.putPayload(buf,utf); MaskedByteBuffer.putPayload(buf,utf);
buf.flip(); buf.flip();