mirror of
https://github.com/jetty/jetty.project.git
synced 2025-03-03 20:39:18 +00:00
merge with jetty-9
This commit is contained in:
commit
a4018d3484
@ -15,10 +15,12 @@ package org.eclipse.jetty.io.ssl;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLEngineResult;
|
import javax.net.ssl.SSLEngineResult;
|
||||||
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
import javax.net.ssl.SSLEngineResult.HandshakeStatus;
|
||||||
|
import javax.net.ssl.SSLEngineResult.Status;
|
||||||
import javax.net.ssl.SSLException;
|
import javax.net.ssl.SSLException;
|
||||||
|
|
||||||
import org.eclipse.jetty.io.AbstractAsyncConnection;
|
import org.eclipse.jetty.io.AbstractAsyncConnection;
|
||||||
@ -38,33 +40,54 @@ import org.eclipse.jetty.util.log.Log;
|
|||||||
import org.eclipse.jetty.util.log.Logger;
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An AsyncConnection that acts as an interceptor between and EndPoint and another
|
* An AsyncConnection that acts as an intercepter between an AsyncEndPoint providing SSL encrypted data
|
||||||
* Connection, that implements TLS encryption using an {@link SSLEngine}.
|
* and another consumer of an AsyncEndPoint (typically an {@link AsyncConnection} like HttpConnection) that
|
||||||
* <p/>
|
* wants unencrypted data.
|
||||||
* The connector uses an {@link EndPoint} (like {@link SelectChannelEndPoint}) as
|
* <p>
|
||||||
* it's source/sink of encrypted data. It then provides {@link #getSslEndPoint()} to
|
* The connector uses an {@link AsyncEndPoint} (typically {@link SelectChannelEndPoint}) as
|
||||||
|
* it's source/sink of encrypted data. It then provides an endpoint via {@link #getSslEndPoint()} to
|
||||||
* expose a source/sink of unencrypted data to another connection (eg HttpConnection).
|
* expose a source/sink of unencrypted data to another connection (eg HttpConnection).
|
||||||
|
* <p>
|
||||||
|
* The design of this class is based on a clear separation between the passive methods, which do not block nor schedule any
|
||||||
|
* asynchronous callbacks, and active methods that do schedule asynchronous callbacks.
|
||||||
|
* <p>
|
||||||
|
* The passive methods are {@link DecryptedEndPoint#fill(ByteBuffer)} and {@link DecryptedEndPoint#flush(ByteBuffer...)}. They make best
|
||||||
|
* effort attempts to progress the connection using only calls to the encrypted {@link AsyncEndPoint#fill(ByteBuffer)} and {@link AsyncEndPoint#flush(ByteBuffer...)}
|
||||||
|
* methods. They will never block nor schedule any readInterest or write callbacks. If a fill/flush cannot progress either because
|
||||||
|
* of network congestion or waiting for an SSL handshake message, then the fill/flush will simply return with zero bytes filled/flushed.
|
||||||
|
* Specifically, if a flush cannot proceed because it needs to receive a handshake message, then the flush will attempt to fill bytes from the
|
||||||
|
* encrypted endpoint, but if insufficient bytes are read it will NOT call {@link AsyncEndPoint#fillInterested(Object, Callback)}.
|
||||||
|
* <p>
|
||||||
|
* It is only the active methods : {@link DecryptedEndPoint#fillInterested(Object, Callback)} and
|
||||||
|
* {@link DecryptedEndPoint#write(Object, Callback, ByteBuffer...)} that may schedule callbacks by calling the encrypted
|
||||||
|
* {@link AsyncEndPoint#fillInterested(Object, Callback)} and {@link AsyncEndPoint#write(Object, Callback, ByteBuffer...)}
|
||||||
|
* methods. For normal data handling, the decrypted fillInterest method will result in an encrypted fillInterest and a decrypted
|
||||||
|
* write will result in an encrypted write. However, due to SSL handshaking requirements, it is also possible for a decrypted fill
|
||||||
|
* to call the encrypted write and for the decrypted flush to call the encrypted fillInterested methods.
|
||||||
|
* <p>
|
||||||
|
* MOST IMPORTANTLY, the encrypted callbacks from the active methods (#onFillable() and WriteFlusher#completeWrite()) do no filling or flushing
|
||||||
|
* themselves. Instead they simple make the callbacks to the decrypted callbacks, so that the passive encyrpted fill/flush will
|
||||||
|
* be called again and make another best effort attempt to progress the connection.
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
public class SslConnection extends AbstractAsyncConnection
|
public class SslConnection extends AbstractAsyncConnection
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(SslConnection.class);
|
private static final Logger LOG = Log.getLogger(SslConnection.class);
|
||||||
private final ByteBufferPool _bufferPool;
|
private final ByteBufferPool _bufferPool;
|
||||||
private final SSLEngine _sslEngine;
|
private final SSLEngine _sslEngine;
|
||||||
private final SslEndPoint _appEndPoint;
|
private final DecryptedEndPoint _decryptedEndPoint;
|
||||||
private ByteBuffer _appIn;
|
private ByteBuffer _decryptedInput;
|
||||||
private ByteBuffer _netIn;
|
private ByteBuffer _encryptedInput;
|
||||||
private ByteBuffer _netOut;
|
private ByteBuffer _encryptedOutput;
|
||||||
private final boolean _netDirect = false;
|
private final boolean _encryptedDirectBuffers = false;
|
||||||
private final boolean _appDirect = false;
|
private final boolean _decryptedDirectBuffers = false;
|
||||||
private SSLEngineResult _unwrapResult;
|
|
||||||
private SSLEngineResult _wrapResult;
|
|
||||||
|
|
||||||
public SslConnection(ByteBufferPool byteBufferPool, Executor executor, AsyncEndPoint endPoint, SSLEngine sslEngine)
|
public SslConnection(ByteBufferPool byteBufferPool, Executor executor, AsyncEndPoint endPoint, SSLEngine sslEngine)
|
||||||
{
|
{
|
||||||
super(endPoint, executor, true);
|
super(endPoint, executor, true);
|
||||||
this._bufferPool = byteBufferPool;
|
this._bufferPool = byteBufferPool;
|
||||||
this._sslEngine = sslEngine;
|
this._sslEngine = sslEngine;
|
||||||
this._appEndPoint = new SslEndPoint();
|
this._decryptedEndPoint = new DecryptedEndPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
public SSLEngine getSSLEngine()
|
public SSLEngine getSSLEngine()
|
||||||
@ -74,7 +97,7 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
|
|
||||||
public AsyncEndPoint getSslEndPoint()
|
public AsyncEndPoint getSslEndPoint()
|
||||||
{
|
{
|
||||||
return _appEndPoint;
|
return _decryptedEndPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -88,7 +111,7 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
_sslEngine.beginHandshake();
|
_sslEngine.beginHandshake();
|
||||||
|
|
||||||
if (_sslEngine.getUseClientMode())
|
if (_sslEngine.getUseClientMode())
|
||||||
_appEndPoint.write(null, new Callback.Empty<>(), BufferUtil.EMPTY_BUFFER);
|
_decryptedEndPoint.write(null, new Callback.Empty<>(), BufferUtil.EMPTY_BUFFER);
|
||||||
}
|
}
|
||||||
catch (SSLException x)
|
catch (SSLException x)
|
||||||
{
|
{
|
||||||
@ -101,18 +124,27 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
@Override
|
@Override
|
||||||
public void onFillable()
|
public void onFillable()
|
||||||
{
|
{
|
||||||
|
// onFillable means that there are encrypted bytes ready to be filled.
|
||||||
|
// however we do not fill them here on this callback, but instead wakeup
|
||||||
|
// the decrypted readInterest and/or writeFlusher so that they will attempt
|
||||||
|
// to do the fill and/or flush again and these calls will do the actually
|
||||||
|
// filling.
|
||||||
|
|
||||||
LOG.debug("{} onReadable", this);
|
LOG.debug("{} onReadable", this);
|
||||||
|
|
||||||
// wake up whoever is doing the fill or the flush so they can
|
synchronized(_decryptedEndPoint)
|
||||||
// do all the filling, unwrapping ,wrapping and flushing
|
|
||||||
if (_appEndPoint._readInterest.isInterested())
|
|
||||||
_appEndPoint._readInterest.readable();
|
|
||||||
|
|
||||||
// If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
|
|
||||||
if (_appEndPoint._writeFlusher.isWritePending() && _appEndPoint._flushUnwrap)
|
|
||||||
{
|
{
|
||||||
_appEndPoint._flushUnwrap = false;
|
// wake up whoever is doing the fill or the flush so they can
|
||||||
_appEndPoint._writeFlusher.completeWrite();
|
// do all the filling, unwrapping ,wrapping and flushing
|
||||||
|
if (_decryptedEndPoint._readInterest.isInterested())
|
||||||
|
_decryptedEndPoint._readInterest.readable();
|
||||||
|
|
||||||
|
// If we are handshaking, then wake up any waiting write as well as it may have been blocked on the read
|
||||||
|
if ( _decryptedEndPoint._flushRequiresFillToProgress)
|
||||||
|
{
|
||||||
|
_decryptedEndPoint._flushRequiresFillToProgress = false;
|
||||||
|
_decryptedEndPoint._writeFlusher.completeWrite();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,17 +152,25 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
@Override
|
@Override
|
||||||
public void onFillInterestedFailed(Throwable cause)
|
public void onFillInterestedFailed(Throwable cause)
|
||||||
{
|
{
|
||||||
|
// this means that the fill interest in encrypted bytes has failed.
|
||||||
|
// However we do not handle that here on this callback, but instead wakeup
|
||||||
|
// the decrypted readInterest and/or writeFlusher so that they will attempt
|
||||||
|
// to do the fill and/or flush again and these calls will do the actually
|
||||||
|
// handle the cause.
|
||||||
|
|
||||||
super.onFillInterestedFailed(cause);
|
super.onFillInterestedFailed(cause);
|
||||||
|
|
||||||
if (_appEndPoint._readInterest.isInterested())
|
synchronized(_decryptedEndPoint)
|
||||||
_appEndPoint._readInterest.failed(cause);
|
|
||||||
|
|
||||||
if (_appEndPoint._writeFlusher.isWritePending() && _appEndPoint._flushUnwrap)
|
|
||||||
{
|
{
|
||||||
_appEndPoint._flushUnwrap = false;
|
if (_decryptedEndPoint._readInterest.isInterested())
|
||||||
_appEndPoint._writeFlusher.failed(cause);
|
_decryptedEndPoint._readInterest.failed(cause);
|
||||||
}
|
|
||||||
|
|
||||||
|
if (_decryptedEndPoint._flushRequiresFillToProgress)
|
||||||
|
{
|
||||||
|
_decryptedEndPoint._flushRequiresFillToProgress = false;
|
||||||
|
_decryptedEndPoint._writeFlusher.failed(cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
@ -140,18 +180,18 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
return String.format("SslConnection@%x{%s,%s%s}",
|
return String.format("SslConnection@%x{%s,%s%s}",
|
||||||
hashCode(),
|
hashCode(),
|
||||||
_sslEngine.getHandshakeStatus(),
|
_sslEngine.getHandshakeStatus(),
|
||||||
_appEndPoint._readInterest.isInterested() ? "R" : "",
|
_decryptedEndPoint._readInterest.isInterested() ? "R" : "",
|
||||||
_appEndPoint._writeFlusher.isWritePending() ? "W" : "");
|
_decryptedEndPoint._writeFlusher.isWriting() ? "W" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------ */
|
/* ------------------------------------------------------------ */
|
||||||
public class SslEndPoint extends AbstractEndPoint implements AsyncEndPoint
|
public class DecryptedEndPoint extends AbstractEndPoint implements AsyncEndPoint
|
||||||
{
|
{
|
||||||
private AsyncConnection _connection;
|
private AsyncConnection _connection;
|
||||||
private boolean _fillWrap;
|
private boolean _fillRequiresFlushToProgress;
|
||||||
private boolean _flushUnwrap;
|
private boolean _flushRequiresFillToProgress;
|
||||||
private boolean _netWriting;
|
private boolean _cannotAcceptMoreAppDataToFlush;
|
||||||
private boolean _underflown;
|
private boolean _needToFillMoreDataToProgress;
|
||||||
private boolean _ishut = false;
|
private boolean _ishut = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -170,20 +210,24 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
@Override
|
@Override
|
||||||
public void completed(Void context)
|
public void completed(Void context)
|
||||||
{
|
{
|
||||||
synchronized (SslEndPoint.this)
|
// This means that a write of data has completed. Writes are done
|
||||||
|
// only if there is an active writeflusher or a read needed to write
|
||||||
|
// data. In either case the appropriate callback is passed on.
|
||||||
|
synchronized (DecryptedEndPoint.this)
|
||||||
{
|
{
|
||||||
LOG.debug("{} write.complete {}", SslConnection.this, _netWriting ? (_fillWrap ? "FW" : "F") : (_fillWrap ? "W" : ""));
|
LOG.debug("{} write.complete {}", SslConnection.this, _cannotAcceptMoreAppDataToFlush ? (_fillRequiresFlushToProgress ? "FW" : "F") : (_fillRequiresFlushToProgress ? "W" : ""));
|
||||||
|
|
||||||
releaseNetOut();
|
releaseNetOut();
|
||||||
|
|
||||||
_netWriting = false;
|
_cannotAcceptMoreAppDataToFlush = false;
|
||||||
if (_fillWrap)
|
|
||||||
|
if (_fillRequiresFlushToProgress)
|
||||||
{
|
{
|
||||||
_fillWrap = false;
|
_fillRequiresFlushToProgress = false;
|
||||||
_readInterest.readable();
|
_readInterest.readable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_writeFlusher.isWritePending())
|
if (_writeFlusher.isWriting())
|
||||||
_writeFlusher.completeWrite();
|
_writeFlusher.completeWrite();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,20 +235,25 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
@Override
|
@Override
|
||||||
public void failed(Void context, Throwable x)
|
public void failed(Void context, Throwable x)
|
||||||
{
|
{
|
||||||
synchronized (SslEndPoint.this)
|
// This means that a write of data has failed. Writes are done
|
||||||
|
// only if there is an active writeflusher or a read needed to write
|
||||||
|
// data. In either case the appropriate callback is passed on.
|
||||||
|
synchronized (DecryptedEndPoint.this)
|
||||||
{
|
{
|
||||||
LOG.debug("{} write.failed", SslConnection.this, x);
|
LOG.debug("{} write.failed", SslConnection.this, x);
|
||||||
if (_netOut != null)
|
if (_encryptedOutput != null)
|
||||||
BufferUtil.clear(_netOut);
|
BufferUtil.clear(_encryptedOutput);
|
||||||
releaseNetOut();
|
releaseNetOut();
|
||||||
_netWriting = false;
|
|
||||||
if (_fillWrap)
|
_cannotAcceptMoreAppDataToFlush = false;
|
||||||
|
|
||||||
|
if (_fillRequiresFlushToProgress)
|
||||||
{
|
{
|
||||||
_fillWrap = false;
|
_fillRequiresFlushToProgress = false;
|
||||||
_readInterest.failed(x);
|
_readInterest.failed(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_writeFlusher.isWritePending())
|
if (_writeFlusher.isWriting())
|
||||||
_writeFlusher.failed(x);
|
_writeFlusher.failed(x);
|
||||||
|
|
||||||
// TODO release all buffers??? or may in onClose
|
// TODO release all buffers??? or may in onClose
|
||||||
@ -217,39 +266,54 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
@Override
|
@Override
|
||||||
protected boolean needsFill() throws IOException
|
protected boolean needsFill() throws IOException
|
||||||
{
|
{
|
||||||
synchronized (SslEndPoint.this)
|
// This means that the decrypted data consumer has called the fillInterested
|
||||||
|
// method on the DecryptedEndPoint, so we have to work out if there is
|
||||||
|
// decrypted data to be filled or what callbacks to setup to be told when there
|
||||||
|
// might be more encrypted data available to attempt another call to fill
|
||||||
|
|
||||||
|
synchronized (DecryptedEndPoint.this)
|
||||||
{
|
{
|
||||||
// Do we already have some app data
|
// Do we already have some app data, then app can fill now so return true
|
||||||
if (BufferUtil.hasContent(_appIn))
|
if (BufferUtil.hasContent(_decryptedInput))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// If we are not underflown and have net data
|
// If we have no encrypted data to decrypt OR we have some, but it is not enough
|
||||||
if (!_underflown && BufferUtil.hasContent(_netIn))
|
if (BufferUtil.isEmpty(_encryptedInput) || _needToFillMoreDataToProgress)
|
||||||
return true;
|
|
||||||
|
|
||||||
// So we are not read ready
|
|
||||||
|
|
||||||
// Are we actually write blocked?
|
|
||||||
if (_fillWrap)
|
|
||||||
{
|
{
|
||||||
// we must be blocked trying to write before we can read
|
// We are not ready to read data
|
||||||
// If we have written the net data
|
|
||||||
if (BufferUtil.isEmpty(_netOut))
|
|
||||||
{
|
|
||||||
// pretend we are readable so the wrap is done by next readable callback
|
|
||||||
_fillWrap = false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// otherwise write the net data
|
// Are we actually write blocked?
|
||||||
_netWriting = true;
|
if (_fillRequiresFlushToProgress)
|
||||||
getEndPoint().write(null, _writeCallback, _netOut);
|
{
|
||||||
|
// we must be blocked trying to write before we can read
|
||||||
|
|
||||||
|
// Do we have data to write
|
||||||
|
if (BufferUtil.hasContent(_encryptedOutput))
|
||||||
|
{
|
||||||
|
// write it
|
||||||
|
_cannotAcceptMoreAppDataToFlush = true;
|
||||||
|
getEndPoint().write(null, _writeCallback, _encryptedOutput);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// we have already written the net data
|
||||||
|
// pretend we are readable so the wrap is done by next readable callback
|
||||||
|
_fillRequiresFlushToProgress = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
// Normal readable callback
|
||||||
|
// Get called back on onfillable when then is more data to fill
|
||||||
|
SslConnection.this.fillInterested();
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
// Normal readable callback
|
{
|
||||||
SslConnection.this.fillInterested();
|
// We are ready to read data
|
||||||
|
return true;
|
||||||
return false;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -259,16 +323,19 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
@Override
|
@Override
|
||||||
protected void onIncompleteFlushed()
|
protected void onIncompleteFlushed()
|
||||||
{
|
{
|
||||||
synchronized (SslEndPoint.this)
|
// This means that the decripted endpoint write method was called and not
|
||||||
|
// all data could be wrapped. So either we need to write some encrypted data,
|
||||||
|
// OR if we are handshaking we need to read some encrypted data OR
|
||||||
|
// if neither than we should just try the flush again.
|
||||||
|
synchronized (DecryptedEndPoint.this)
|
||||||
{
|
{
|
||||||
// If we have pending output data,
|
// If we have pending output data,
|
||||||
if (BufferUtil.hasContent(_netOut))
|
if (BufferUtil.hasContent(_encryptedOutput))
|
||||||
{
|
{
|
||||||
// write it
|
// write it
|
||||||
_netWriting = true;
|
_cannotAcceptMoreAppDataToFlush = true;
|
||||||
getEndPoint().write(null, _writeCallback, _netOut);
|
getEndPoint().write(null, _writeCallback, _encryptedOutput);
|
||||||
}
|
}
|
||||||
// TODO test this with _flushInwrap
|
|
||||||
else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
|
else if (_sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP)
|
||||||
// we are actually read blocked in order to write
|
// we are actually read blocked in order to write
|
||||||
SslConnection.this.fillInterested();
|
SslConnection.this.fillInterested();
|
||||||
@ -279,7 +346,7 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public SslEndPoint()
|
public DecryptedEndPoint()
|
||||||
{
|
{
|
||||||
super(getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
|
super(getEndPoint().getLocalAddress(), getEndPoint().getRemoteAddress());
|
||||||
}
|
}
|
||||||
@ -308,51 +375,52 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
// Do we already have some decrypted data?
|
// Do we already have some decrypted data?
|
||||||
if (BufferUtil.hasContent(_appIn))
|
if (BufferUtil.hasContent(_decryptedInput))
|
||||||
return BufferUtil.append(_appIn, buffer);
|
return BufferUtil.append(_decryptedInput, buffer);
|
||||||
|
|
||||||
// We will need a network buffer
|
// We will need a network buffer
|
||||||
if (_netIn == null)
|
if (_encryptedInput == null)
|
||||||
_netIn = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _netDirect);
|
_encryptedInput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize(), _encryptedDirectBuffers);
|
||||||
else
|
else
|
||||||
BufferUtil.compact(_netIn);
|
BufferUtil.compact(_encryptedInput);
|
||||||
|
|
||||||
// We also need an app buffer, but can use the passed buffer if it is big enough
|
// We also need an app buffer, but can use the passed buffer if it is big enough
|
||||||
ByteBuffer app_in;
|
ByteBuffer app_in;
|
||||||
if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize())
|
if (BufferUtil.space(buffer) > _sslEngine.getSession().getApplicationBufferSize())
|
||||||
app_in = buffer;
|
app_in = buffer;
|
||||||
else if (_appIn == null)
|
else if (_decryptedInput == null)
|
||||||
app_in = _appIn = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _appDirect);
|
app_in = _decryptedInput = _bufferPool.acquire(_sslEngine.getSession().getApplicationBufferSize(), _decryptedDirectBuffers);
|
||||||
else
|
else
|
||||||
app_in = _appIn;
|
app_in = _decryptedInput;
|
||||||
|
|
||||||
// loop filling and unwrapping until we have something
|
// loop filling and unwrapping until we have something
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// Let's try reading some encrypted data... even if we have some already.
|
// Let's try reading some encrypted data... even if we have some already.
|
||||||
int net_filled = getEndPoint().fill(_netIn);
|
int net_filled = getEndPoint().fill(_encryptedInput);
|
||||||
LOG.debug("{} filled {} encrypted bytes", SslConnection.this, net_filled);
|
LOG.debug("{} filled {} encrypted bytes", SslConnection.this, net_filled);
|
||||||
if (net_filled > 0)
|
if (net_filled > 0)
|
||||||
_underflown = false;
|
_needToFillMoreDataToProgress = false;
|
||||||
|
|
||||||
// Let's try the SSL thang even if we have no net data because in that
|
// Let's try the SSL thang even if we have no net data because in that
|
||||||
// case we want to fall through to the handshake handling
|
// case we want to fall through to the handshake handling
|
||||||
int pos = BufferUtil.flipToFill(app_in);
|
int pos = BufferUtil.flipToFill(app_in);
|
||||||
_unwrapResult = _sslEngine.unwrap(_netIn, app_in);
|
SSLEngineResult unwrapResult = _sslEngine.unwrap(_encryptedInput, app_in);
|
||||||
LOG.debug("{} unwrap {}", SslConnection.this, _unwrapResult);
|
LOG.debug("{} unwrap {}", SslConnection.this, unwrapResult);
|
||||||
BufferUtil.flipToFlush(app_in, pos);
|
BufferUtil.flipToFlush(app_in, pos);
|
||||||
|
|
||||||
// and deal with the results
|
// and deal with the results
|
||||||
switch (_unwrapResult.getStatus())
|
switch (unwrapResult.getStatus())
|
||||||
{
|
{
|
||||||
case BUFFER_OVERFLOW:
|
case BUFFER_OVERFLOW:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
|
|
||||||
case CLOSED:
|
case CLOSED:
|
||||||
// Dang! we have to care about the handshake state
|
// Dang! we have to care about the handshake state specially for close
|
||||||
switch (_sslEngine.getHandshakeStatus())
|
switch (_sslEngine.getHandshakeStatus())
|
||||||
{
|
{
|
||||||
case NOT_HANDSHAKING:
|
case NOT_HANDSHAKING:
|
||||||
|
// We were not handshaking, so just tell the app we are closed
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
case NEED_TASK:
|
case NEED_TASK:
|
||||||
@ -361,40 +429,47 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
case NEED_WRAP:
|
case NEED_WRAP:
|
||||||
// we need to send some handshake data
|
// we need to send some handshake data (probably to send a close handshake).
|
||||||
if (!_flushUnwrap)
|
if (_flushRequiresFillToProgress)
|
||||||
|
return -1; // we were called from flush, so it can deal with sending the close handshake
|
||||||
|
|
||||||
|
// We need to call flush to cause the wrap to happen
|
||||||
|
_fillRequiresFlushToProgress = true;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
_fillWrap = true;
|
// flushing an empty buffer will invoke the wrap mechanisms
|
||||||
try
|
flush(BufferUtil.EMPTY_BUFFER);
|
||||||
{
|
// If encrypted output is all written, we can proceed with close
|
||||||
flush(BufferUtil.EMPTY_BUFFER);
|
if (BufferUtil.isEmpty(_encryptedOutput))
|
||||||
}
|
|
||||||
catch(IOException e)
|
|
||||||
{
|
{
|
||||||
|
_fillRequiresFlushToProgress = false;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (BufferUtil.hasContent(_netOut))
|
|
||||||
return 0;
|
// Otherwise return as if a normal fill and let a subsequent call
|
||||||
_fillWrap = false;
|
// return -1 to the caller.
|
||||||
|
return unwrapResult.bytesProduced();
|
||||||
|
}
|
||||||
|
catch(IOException e)
|
||||||
|
{
|
||||||
|
LOG.debug(e);
|
||||||
|
// The flush failed, oh well nothing more to do than tell the app
|
||||||
|
// that the connection is closed.
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return -1;
|
|
||||||
|
|
||||||
default:
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
}
|
||||||
|
throw new IllegalStateException();
|
||||||
case BUFFER_UNDERFLOW:
|
|
||||||
_underflown = true;
|
|
||||||
|
|
||||||
//$FALL-THROUGH$ to deal with handshaking stuff
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// if we produced bytes, we don't care about the handshake state
|
if (unwrapResult.getStatus()==Status.BUFFER_UNDERFLOW)
|
||||||
if (_unwrapResult.bytesProduced() > 0)
|
_needToFillMoreDataToProgress=true;
|
||||||
|
|
||||||
|
// if we produced bytes, we don't care about the handshake state for now and it can be dealt with on another call to fill or flush
|
||||||
|
if (unwrapResult.bytesProduced() > 0)
|
||||||
{
|
{
|
||||||
if (app_in == buffer)
|
if (app_in == buffer)
|
||||||
return _unwrapResult.bytesProduced();
|
return unwrapResult.bytesProduced();
|
||||||
return BufferUtil.append(_appIn, buffer);
|
return BufferUtil.append(_decryptedInput, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dang! we have to care about the handshake state
|
// Dang! we have to care about the handshake state
|
||||||
@ -413,14 +488,17 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
|
|
||||||
case NEED_WRAP:
|
case NEED_WRAP:
|
||||||
// we need to send some handshake data
|
// we need to send some handshake data
|
||||||
if (_flushUnwrap)
|
if (_flushRequiresFillToProgress)
|
||||||
return 0;
|
return 0;
|
||||||
_fillWrap = true;
|
_fillRequiresFlushToProgress = true;
|
||||||
flush(BufferUtil.EMPTY_BUFFER);
|
flush(BufferUtil.EMPTY_BUFFER);
|
||||||
if (BufferUtil.hasContent(_netOut))
|
if (BufferUtil.isEmpty(_encryptedOutput))
|
||||||
return 0;
|
{
|
||||||
_fillWrap = false;
|
// the flush completed so continue
|
||||||
continue;
|
_fillRequiresFlushToProgress = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
|
||||||
case NEED_UNWRAP:
|
case NEED_UNWRAP:
|
||||||
// if we just filled some net data
|
// if we just filled some net data
|
||||||
@ -451,15 +529,15 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
if (_netIn != null && !_netIn.hasRemaining())
|
if (_encryptedInput != null && !_encryptedInput.hasRemaining())
|
||||||
{
|
{
|
||||||
_bufferPool.release(_netIn);
|
_bufferPool.release(_encryptedInput);
|
||||||
_netIn = null;
|
_encryptedInput = null;
|
||||||
}
|
}
|
||||||
if (_appIn != null && !_appIn.hasRemaining())
|
if (_decryptedInput != null && !_decryptedInput.hasRemaining())
|
||||||
{
|
{
|
||||||
_bufferPool.release(_appIn);
|
_bufferPool.release(_decryptedInput);
|
||||||
_appIn = null;
|
_decryptedInput = null;
|
||||||
}
|
}
|
||||||
LOG.debug("{} fill exit", SslConnection.this);
|
LOG.debug("{} fill exit", SslConnection.this);
|
||||||
}
|
}
|
||||||
@ -474,81 +552,90 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
// will return 0 (even if some handshake bytes were flushed and filled).
|
// will return 0 (even if some handshake bytes were flushed and filled).
|
||||||
// it is the applications responsibility to call flush again - either in a busy loop
|
// it is the applications responsibility to call flush again - either in a busy loop
|
||||||
// or better yet by using AsyncEndPoint#write to do the flushing.
|
// or better yet by using AsyncEndPoint#write to do the flushing.
|
||||||
|
|
||||||
LOG.debug("{} flush enter {}", SslConnection.this, appOuts);
|
LOG.debug("{} flush enter {}", SslConnection.this, Arrays.toString(appOuts));
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_netWriting)
|
if (_cannotAcceptMoreAppDataToFlush)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
// We will need a network buffer
|
// We will need a network buffer
|
||||||
if (_netOut == null)
|
if (_encryptedOutput == null)
|
||||||
_netOut = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize() * 2, _netDirect);
|
_encryptedOutput = _bufferPool.acquire(_sslEngine.getSession().getPacketBufferSize() * 2, _encryptedDirectBuffers);
|
||||||
|
|
||||||
|
int consumed=0;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
// do the funky SSL thang!
|
// do the funky SSL thang!
|
||||||
BufferUtil.compact(_netOut);
|
// We call sslEngine.wrap to try to take bytes from appOut buffers and encrypt them into the _netOut buffer
|
||||||
int pos = BufferUtil.flipToFill(_netOut);
|
BufferUtil.compact(_encryptedOutput);
|
||||||
_wrapResult = _sslEngine.wrap(appOuts, _netOut);
|
int pos = BufferUtil.flipToFill(_encryptedOutput);
|
||||||
LOG.debug("{} wrap {}", SslConnection.this, _wrapResult);
|
SSLEngineResult wrapResult = _sslEngine.wrap(appOuts, _encryptedOutput);
|
||||||
BufferUtil.flipToFlush(_netOut, pos);
|
LOG.debug("{} wrap {}", SslConnection.this, wrapResult);
|
||||||
|
BufferUtil.flipToFlush(_encryptedOutput, pos);
|
||||||
|
consumed+=wrapResult.bytesConsumed();
|
||||||
|
|
||||||
// and deal with the results
|
// and deal with the results returned from the sslEngineWrap
|
||||||
switch (_wrapResult.getStatus())
|
switch (wrapResult.getStatus())
|
||||||
{
|
{
|
||||||
case CLOSED:
|
case CLOSED:
|
||||||
if (BufferUtil.hasContent(_netOut))
|
// The SSL engine has close, but there may be close handshake that needs to be written
|
||||||
|
if (BufferUtil.hasContent(_encryptedOutput))
|
||||||
{
|
{
|
||||||
_netWriting = true;
|
_cannotAcceptMoreAppDataToFlush = true;
|
||||||
getEndPoint().flush(_netOut);
|
getEndPoint().flush(_encryptedOutput);
|
||||||
if (BufferUtil.hasContent(_netOut))
|
// If we failed to flush the close handshake then we will just pretend that
|
||||||
return 0;
|
// the write has progressed normally and let a subsequent call to flush (or WriteFlusher#onIncompleteFlushed)
|
||||||
|
// to finish writing the close handshake. The caller will find out about the close on a subsequent flush or fill.
|
||||||
|
if (BufferUtil.hasContent(_encryptedOutput))
|
||||||
|
return consumed;
|
||||||
}
|
}
|
||||||
if (_fillWrap)
|
|
||||||
return 0;
|
// If we we flushing because of a fill needing to wrap, return normally and it will handle the closed state.
|
||||||
|
if (_fillRequiresFlushToProgress)
|
||||||
|
return consumed;
|
||||||
|
|
||||||
|
// otherwise it is an exception to write to a closed endpoint
|
||||||
throw new EofException();
|
throw new EofException();
|
||||||
|
|
||||||
case BUFFER_UNDERFLOW:
|
case BUFFER_UNDERFLOW:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
|
|
||||||
case BUFFER_OVERFLOW:
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
LOG.debug("{} OVERFLOW {}", this, BufferUtil.toDetailString(_netOut));
|
|
||||||
|
|
||||||
//$FALL-THROUGH$
|
|
||||||
default:
|
default:
|
||||||
|
if (LOG.isDebugEnabled())
|
||||||
|
LOG.debug("{} {} {}", this, wrapResult.getStatus(), BufferUtil.toDetailString(_encryptedOutput));
|
||||||
|
|
||||||
// if we have net bytes, let's try to flush them
|
// if we have net bytes, let's try to flush them
|
||||||
if (BufferUtil.hasContent(_netOut))
|
if (BufferUtil.hasContent(_encryptedOutput))
|
||||||
{
|
getEndPoint().flush(_encryptedOutput);
|
||||||
getEndPoint().flush(_netOut);
|
|
||||||
return _wrapResult.bytesConsumed();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dang! we have to deal with handshake state
|
// But we also might have more to do for the handshaking state.
|
||||||
switch (_sslEngine.getHandshakeStatus())
|
switch (_sslEngine.getHandshakeStatus())
|
||||||
{
|
{
|
||||||
case NOT_HANDSHAKING:
|
case NOT_HANDSHAKING:
|
||||||
// we just didn't write anything. Strange?
|
// Return with the number of bytes consumed (which may be 0)
|
||||||
return 0;
|
return consumed;
|
||||||
|
|
||||||
case NEED_TASK:
|
case NEED_TASK:
|
||||||
// run the task
|
// run the task and continue
|
||||||
_sslEngine.getDelegatedTask().run();
|
_sslEngine.getDelegatedTask().run();
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case NEED_WRAP:
|
case NEED_WRAP:
|
||||||
// Hey we just wrapped!
|
// Hey we just wrapped! Oh well who knows what the sslEngine is thinking, so continue and we will wrap again
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
case NEED_UNWRAP:
|
case NEED_UNWRAP:
|
||||||
// Were we were not called from fill and not reading anyway
|
// Ah we need to fill some data so we can write.
|
||||||
if (!_fillWrap && !_readInterest.isInterested())
|
// So if we were not called from fill and the app is not reading anyway
|
||||||
|
if (!_fillRequiresFlushToProgress && !_readInterest.isInterested())
|
||||||
{
|
{
|
||||||
_flushUnwrap = true;
|
// Tell the onFillable method that there might be a write to complete
|
||||||
|
// TODO move this to the writeFlusher?
|
||||||
|
_flushRequiresFillToProgress = true;
|
||||||
fill(BufferUtil.EMPTY_BUFFER);
|
fill(BufferUtil.EMPTY_BUFFER);
|
||||||
}
|
}
|
||||||
return 0;
|
return consumed;
|
||||||
|
|
||||||
case FINISHED:
|
case FINISHED:
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
@ -571,10 +658,10 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
|
|
||||||
private void releaseNetOut()
|
private void releaseNetOut()
|
||||||
{
|
{
|
||||||
if (_netOut != null && !_netOut.hasRemaining())
|
if (_encryptedOutput != null && !_encryptedOutput.hasRemaining())
|
||||||
{
|
{
|
||||||
_bufferPool.release(_netOut);
|
_bufferPool.release(_encryptedOutput);
|
||||||
_netOut = null;
|
_encryptedOutput = null;
|
||||||
if (_sslEngine.isOutboundDone())
|
if (_sslEngine.isOutboundDone())
|
||||||
getEndPoint().shutdownOutput();
|
getEndPoint().shutdownOutput();
|
||||||
}
|
}
|
||||||
@ -640,7 +727,7 @@ public class SslConnection extends AbstractAsyncConnection
|
|||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
return String.format("%s{%s%s%s}", super.toString(), _readInterest.isInterested() ? "R" : "", _writeFlusher.isWritePending() ? "W" : "", _netWriting ? "w" : "");
|
return String.format("%s{%s%s%s}", super.toString(), _readInterest.isInterested() ? "R" : "", _writeFlusher.isWriting() ? "W" : "", _cannotAcceptMoreAppDataToFlush ? "w" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ public class SslSelectChannelConnector extends SelectChannelConnector implements
|
|||||||
request.setScheme(HttpScheme.HTTPS.asString());
|
request.setScheme(HttpScheme.HTTPS.asString());
|
||||||
super.customize(request);
|
super.customize(request);
|
||||||
|
|
||||||
SslConnection.SslEndPoint ssl_endp = (SslConnection.SslEndPoint)request.getHttpChannel().getEndPoint();
|
SslConnection.DecryptedEndPoint ssl_endp = (SslConnection.DecryptedEndPoint)request.getHttpChannel().getEndPoint();
|
||||||
SslConnection sslConnection = ssl_endp.getSslConnection();
|
SslConnection sslConnection = ssl_endp.getSslConnection();
|
||||||
SSLEngine sslEngine=sslConnection.getSSLEngine();
|
SSLEngine sslEngine=sslConnection.getSSLEngine();
|
||||||
SslCertificates.customize(sslEngine,request);
|
SslCertificates.customize(sslEngine,request);
|
||||||
|
@ -149,8 +149,8 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
|||||||
|
|
||||||
// Get the server side endpoint
|
// Get the server side endpoint
|
||||||
EndPoint endp = endpoint.exchange(null,10,TimeUnit.SECONDS);
|
EndPoint endp = endpoint.exchange(null,10,TimeUnit.SECONDS);
|
||||||
if (endp instanceof SslConnection.SslEndPoint)
|
if (endp instanceof SslConnection.DecryptedEndPoint)
|
||||||
endp=((SslConnection.SslEndPoint)endp).getAsyncConnection().getEndPoint();
|
endp=((SslConnection.DecryptedEndPoint)endp).getAsyncConnection().getEndPoint();
|
||||||
|
|
||||||
// read the response
|
// read the response
|
||||||
String result=IO.toString(is);
|
String result=IO.toString(is);
|
||||||
@ -222,8 +222,8 @@ public abstract class ConnectorTimeoutTest extends HttpServerTestFixture
|
|||||||
|
|
||||||
// Get the server side endpoint
|
// Get the server side endpoint
|
||||||
EndPoint endp = endpoint.exchange(null,10,TimeUnit.SECONDS);
|
EndPoint endp = endpoint.exchange(null,10,TimeUnit.SECONDS);
|
||||||
if (endp instanceof SslConnection.SslEndPoint)
|
if (endp instanceof SslConnection.DecryptedEndPoint)
|
||||||
endp=((SslConnection.SslEndPoint)endp).getAsyncConnection().getEndPoint();
|
endp=((SslConnection.DecryptedEndPoint)endp).getAsyncConnection().getEndPoint();
|
||||||
|
|
||||||
// read the response
|
// read the response
|
||||||
String result=IO.toString(is);
|
String result=IO.toString(is);
|
||||||
|
@ -78,6 +78,8 @@ public class SPDYAsyncConnection extends AbstractAsyncConnection implements Cont
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (endPoint.isInputShutdown())
|
||||||
|
return -1;
|
||||||
return endPoint.fill(buffer);
|
return endPoint.fill(buffer);
|
||||||
}
|
}
|
||||||
catch (IOException x)
|
catch (IOException x)
|
||||||
@ -91,8 +93,9 @@ public class SPDYAsyncConnection extends AbstractAsyncConnection implements Cont
|
|||||||
public int write(ByteBuffer buffer, final Callback<StandardSession.FrameBytes> callback, StandardSession.FrameBytes context)
|
public int write(ByteBuffer buffer, final Callback<StandardSession.FrameBytes> callback, StandardSession.FrameBytes context)
|
||||||
{
|
{
|
||||||
AsyncEndPoint endPoint = getEndPoint();
|
AsyncEndPoint endPoint = getEndPoint();
|
||||||
|
int remaining = buffer.remaining();
|
||||||
endPoint.write(context, callback, buffer);
|
endPoint.write(context, callback, buffer);
|
||||||
return -1; //TODO: void or have endPoint.write return int
|
return remaining - buffer.remaining();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -65,7 +65,7 @@ public class SynDataReplyDataLoadTest extends AbstractTest
|
|||||||
};
|
};
|
||||||
final Session session = startClient(startServer(serverSessionFrameListener), null);
|
final Session session = startClient(startServer(serverSessionFrameListener), null);
|
||||||
|
|
||||||
final int iterations = 500;
|
final int iterations = 100; // thomas 500
|
||||||
final int count = 50;
|
final int count = 50;
|
||||||
|
|
||||||
final Headers headers = new Headers();
|
final Headers headers = new Headers();
|
||||||
|
@ -179,6 +179,7 @@ public abstract class Utf8Appendable
|
|||||||
return _state == UTF8_ACCEPT;
|
return _state == UTF8_ACCEPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("serial")
|
||||||
public static class NotUtf8Exception extends IllegalArgumentException
|
public static class NotUtf8Exception extends IllegalArgumentException
|
||||||
{
|
{
|
||||||
public NotUtf8Exception(String reason)
|
public NotUtf8Exception(String reason)
|
||||||
|
@ -72,6 +72,6 @@ public class Utf8StringBuilder extends Utf8Appendable
|
|||||||
private void checkState()
|
private void checkState()
|
||||||
{
|
{
|
||||||
if (!isUtf8SequenceComplete())
|
if (!isUtf8SequenceComplete())
|
||||||
throw new IllegalArgumentException("Tried to read incomplete UTF8 decoded String");
|
throw new NotUtf8Exception("Tried to read incomplete UTF8 decoded String");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ public class StdErrLog extends AbstractLogger
|
|||||||
static
|
static
|
||||||
{
|
{
|
||||||
__props.putAll(Log.__props);
|
__props.putAll(Log.__props);
|
||||||
|
|
||||||
String deprecatedProperties[] =
|
String deprecatedProperties[] =
|
||||||
{ "DEBUG", "org.eclipse.jetty.util.log.DEBUG", "org.eclipse.jetty.util.log.stderr.DEBUG" };
|
{ "DEBUG", "org.eclipse.jetty.util.log.DEBUG", "org.eclipse.jetty.util.log.stderr.DEBUG" };
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ public class StdErrLog extends AbstractLogger
|
|||||||
// The abbreviated log name (used by default, unless _long is specified)
|
// The abbreviated log name (used by default, unless _long is specified)
|
||||||
private final String _abbrevname;
|
private final String _abbrevname;
|
||||||
private boolean _hideStacks = false;
|
private boolean _hideStacks = false;
|
||||||
|
|
||||||
public static StdErrLog getLogger(Class<?> clazz)
|
public static StdErrLog getLogger(Class<?> clazz)
|
||||||
{
|
{
|
||||||
Logger log = Log.getLogger(clazz);
|
Logger log = Log.getLogger(clazz);
|
||||||
@ -354,7 +354,7 @@ public class StdErrLog extends AbstractLogger
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
this._level = this._configuredLevel;
|
this._level = this._configuredLevel;
|
||||||
|
|
||||||
for (Logger log : Log.getLoggers().values())
|
for (Logger log : Log.getLoggers().values())
|
||||||
{
|
{
|
||||||
if (log.getName().startsWith(getName()) && log instanceof StdErrLog)
|
if (log.getName().startsWith(getName()) && log instanceof StdErrLog)
|
||||||
@ -460,6 +460,7 @@ public class StdErrLog extends AbstractLogger
|
|||||||
buffer.append(_abbrevname);
|
buffer.append(_abbrevname);
|
||||||
}
|
}
|
||||||
buffer.append(':');
|
buffer.append(':');
|
||||||
|
buffer.append(Thread.currentThread().getId()).append(": ");
|
||||||
if (_source)
|
if (_source)
|
||||||
{
|
{
|
||||||
Throwable source = new Throwable();
|
Throwable source = new Throwable();
|
||||||
@ -588,7 +589,7 @@ public class StdErrLog extends AbstractLogger
|
|||||||
// Let Level come from configured Properties instead - sel.setLevel(_level);
|
// Let Level come from configured Properties instead - sel.setLevel(_level);
|
||||||
logger.setSource(_source);
|
logger.setSource(_source);
|
||||||
logger._stderr = this._stderr;
|
logger._stderr = this._stderr;
|
||||||
|
|
||||||
// Force the child to have any programmatic configuration
|
// Force the child to have any programmatic configuration
|
||||||
if (_level!=_configuredLevel)
|
if (_level!=_configuredLevel)
|
||||||
logger._level=_level;
|
logger._level=_level;
|
||||||
|
@ -45,14 +45,14 @@ public class StdErrLogTest
|
|||||||
log.info("testing:{}",null,null);
|
log.info("testing:{}",null,null);
|
||||||
log.info("testing",null,null);
|
log.info("testing",null,null);
|
||||||
|
|
||||||
output.assertContains("INFO:oejul.LogTest:testing:test,format1");
|
output.assertContains("INFO:oejul.LogTest:1: testing:test,format1");
|
||||||
output.assertContains("INFO:oejul.LogTest:testing:test,format1");
|
output.assertContains("INFO:oejul.LogTest:1: testing:test,format1");
|
||||||
output.assertContains("INFO:oejul.LogTest:testing:test format2");
|
output.assertContains("INFO:oejul.LogTest:1: testing:test format2");
|
||||||
output.assertContains("INFO:oejul.LogTest:testing test format3");
|
output.assertContains("INFO:oejul.LogTest:1: testing test format3");
|
||||||
output.assertContains("INFO:oejul.LogTest:testing:test,null");
|
output.assertContains("INFO:oejul.LogTest:1: testing:test,null");
|
||||||
output.assertContains("INFO:oejul.LogTest:testing null null");
|
output.assertContains("INFO:oejul.LogTest:1: testing null null");
|
||||||
output.assertContains("INFO:oejul.LogTest:testing:null");
|
output.assertContains("INFO:oejul.LogTest:1: testing:null");
|
||||||
output.assertContains("INFO:oejul.LogTest:testing");
|
output.assertContains("INFO:oejul.LogTest:1: testing");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -75,12 +75,12 @@ public class StdErrLogTest
|
|||||||
log.setDebugEnabled(false);
|
log.setDebugEnabled(false);
|
||||||
log.debug("testing {} {}","test","debug-deprecated-false");
|
log.debug("testing {} {}","test","debug-deprecated-false");
|
||||||
|
|
||||||
output.assertContains("DBUG:xxx:testing test debug");
|
output.assertContains("DBUG:xxx:1: testing test debug");
|
||||||
output.assertContains("INFO:xxx:testing test info");
|
output.assertContains("INFO:xxx:1: testing test info");
|
||||||
output.assertContains("WARN:xxx:testing test warn");
|
output.assertContains("WARN:xxx:1: testing test warn");
|
||||||
output.assertNotContains("YOU SHOULD NOT SEE THIS!");
|
output.assertNotContains("YOU SHOULD NOT SEE THIS!");
|
||||||
output.assertContains("DBUG:xxx:testing test debug-deprecated");
|
output.assertContains("DBUG:xxx:1: testing test debug-deprecated");
|
||||||
output.assertNotContains("DBUG:xxx:testing test debug-depdeprecated-false");
|
output.assertNotContains("DBUG:xxx:1: testing test debug-depdeprecated-false");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -95,7 +95,7 @@ public class StdErrLogTest
|
|||||||
Assert.assertThat("Log.name(child)", next.getName(), is("test.next"));
|
Assert.assertThat("Log.name(child)", next.getName(), is("test.next"));
|
||||||
next.info("testing {} {}","next","info");
|
next.info("testing {} {}","next","info");
|
||||||
|
|
||||||
output.assertContains(":test.next:testing next info");
|
output.assertContains(":test.next:1: testing next info");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -307,7 +307,7 @@ public class StdErrLogTest
|
|||||||
output.assertContains("Cheer Me");
|
output.assertContains("Cheer Me");
|
||||||
|
|
||||||
// Validate Stack Traces
|
// Validate Stack Traces
|
||||||
output.assertContains(".StdErrLogTest:<zoom>");
|
output.assertContains(".StdErrLogTest:1: <zoom>");
|
||||||
output.assertContains("java.lang.Throwable: out of focus");
|
output.assertContains("java.lang.Throwable: out of focus");
|
||||||
output.assertContains("java.lang.Throwable: scene lost");
|
output.assertContains("java.lang.Throwable: scene lost");
|
||||||
}
|
}
|
||||||
@ -354,7 +354,7 @@ public class StdErrLogTest
|
|||||||
output.assertNotContains("<spoken line>");
|
output.assertNotContains("<spoken line>");
|
||||||
output.assertNotContains("on editing room floor");
|
output.assertNotContains("on editing room floor");
|
||||||
|
|
||||||
output.assertContains(".StdErrLogTest:<zoom>");
|
output.assertContains(".StdErrLogTest:1: <zoom>");
|
||||||
output.assertContains("java.lang.Throwable: out of focus");
|
output.assertContains("java.lang.Throwable: out of focus");
|
||||||
output.assertContains("java.lang.Throwable: scene lost");
|
output.assertContains("java.lang.Throwable: scene lost");
|
||||||
}
|
}
|
||||||
@ -427,7 +427,7 @@ public class StdErrLogTest
|
|||||||
output.assertNotContains("<spoken line>");
|
output.assertNotContains("<spoken line>");
|
||||||
output.assertNotContains("on editing room floor");
|
output.assertNotContains("on editing room floor");
|
||||||
|
|
||||||
output.assertContains(".StdErrLogTest:<zoom>");
|
output.assertContains(".StdErrLogTest:1: <zoom>");
|
||||||
output.assertContains("java.lang.Throwable: out of focus");
|
output.assertContains("java.lang.Throwable: out of focus");
|
||||||
output.assertContains("java.lang.Throwable: scene lost");
|
output.assertContains("java.lang.Throwable: scene lost");
|
||||||
}
|
}
|
||||||
|
@ -67,7 +67,7 @@ public class TestClient
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void send(OpCode op, byte[] data, int maxFragmentLength)
|
public void send(byte op, byte[] data, int maxFragmentLength)
|
||||||
{
|
{
|
||||||
_starts.add(System.nanoTime());
|
_starts.add(System.nanoTime());
|
||||||
|
|
||||||
@ -215,7 +215,7 @@ public class TestClient
|
|||||||
{
|
{
|
||||||
long next = System.currentTimeMillis() + delay;
|
long next = System.currentTimeMillis() + delay;
|
||||||
|
|
||||||
OpCode op = OpCode.TEXT;
|
byte op = OpCode.TEXT;
|
||||||
if (binary)
|
if (binary)
|
||||||
{
|
{
|
||||||
op = OpCode.BINARY;
|
op = OpCode.BINARY;
|
||||||
@ -225,7 +225,7 @@ public class TestClient
|
|||||||
|
|
||||||
switch (op)
|
switch (op)
|
||||||
{
|
{
|
||||||
case TEXT:
|
case OpCode.TEXT:
|
||||||
{
|
{
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
while (b.length() < size)
|
while (b.length() < size)
|
||||||
@ -235,7 +235,7 @@ public class TestClient
|
|||||||
data = b.toString().getBytes(StringUtil.__UTF8_CHARSET);
|
data = b.toString().getBytes(StringUtil.__UTF8_CHARSET);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BINARY:
|
case OpCode.BINARY:
|
||||||
{
|
{
|
||||||
data = new byte[size];
|
data = new byte[size];
|
||||||
__random.nextBytes(data);
|
__random.nextBytes(data);
|
||||||
@ -328,7 +328,7 @@ public class TestClient
|
|||||||
client.connect(wsUri,socket).get(10,TimeUnit.SECONDS);
|
client.connect(wsUri,socket).get(10,TimeUnit.SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void send(OpCode op, byte[] data, int fragment)
|
private void send(byte op, byte[] data, int fragment)
|
||||||
{
|
{
|
||||||
socket.send(op,data,fragment);
|
socket.send(op,data,fragment);
|
||||||
}
|
}
|
||||||
|
@ -179,7 +179,7 @@ public class WebSocketEventDriver implements IncomingFrames
|
|||||||
{
|
{
|
||||||
switch (frame.getOpCode())
|
switch (frame.getOpCode())
|
||||||
{
|
{
|
||||||
case CLOSE:
|
case OpCode.CLOSE:
|
||||||
{
|
{
|
||||||
CloseInfo close = new CloseInfo(frame);
|
CloseInfo close = new CloseInfo(frame);
|
||||||
if (events.onClose != null)
|
if (events.onClose != null)
|
||||||
@ -188,7 +188,7 @@ public class WebSocketEventDriver implements IncomingFrames
|
|||||||
}
|
}
|
||||||
throw new CloseException(close.getStatusCode(),close.getReason());
|
throw new CloseException(close.getStatusCode(),close.getReason());
|
||||||
}
|
}
|
||||||
case PING:
|
case OpCode.PING:
|
||||||
{
|
{
|
||||||
WebSocketFrame pong = new WebSocketFrame(OpCode.PONG);
|
WebSocketFrame pong = new WebSocketFrame(OpCode.PONG);
|
||||||
if (frame.getPayloadLength() > 0)
|
if (frame.getPayloadLength() > 0)
|
||||||
@ -203,7 +203,7 @@ public class WebSocketEventDriver implements IncomingFrames
|
|||||||
session.output("pong",new FutureCallback<String>(),pong);
|
session.output("pong",new FutureCallback<String>(),pong);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BINARY:
|
case OpCode.BINARY:
|
||||||
{
|
{
|
||||||
if (events.onBinary == null)
|
if (events.onBinary == null)
|
||||||
{
|
{
|
||||||
@ -273,7 +273,7 @@ public class WebSocketEventDriver implements IncomingFrames
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case TEXT:
|
case OpCode.TEXT:
|
||||||
{
|
{
|
||||||
if (events.onText == null)
|
if (events.onText == null)
|
||||||
{
|
{
|
||||||
|
@ -114,7 +114,7 @@ public class DeflateFrameExtension extends Extension
|
|||||||
@Override
|
@Override
|
||||||
public void incoming(WebSocketFrame frame)
|
public void incoming(WebSocketFrame frame)
|
||||||
{
|
{
|
||||||
if (frame.getOpCode().isControlFrame() || !frame.isRsv1())
|
if (frame.isControlFrame() || !frame.isRsv1())
|
||||||
{
|
{
|
||||||
// Cannot modify incoming control frames or ones with RSV1 set.
|
// Cannot modify incoming control frames or ones with RSV1 set.
|
||||||
super.incoming(frame);
|
super.incoming(frame);
|
||||||
@ -183,7 +183,7 @@ public class DeflateFrameExtension extends Extension
|
|||||||
@Override
|
@Override
|
||||||
public <C> void output(C context, Callback<C> callback, WebSocketFrame frame) throws IOException
|
public <C> void output(C context, Callback<C> callback, WebSocketFrame frame) throws IOException
|
||||||
{
|
{
|
||||||
if (frame.getOpCode().isControlFrame())
|
if (frame.isControlFrame())
|
||||||
{
|
{
|
||||||
// skip, cannot compress control frames.
|
// skip, cannot compress control frames.
|
||||||
nextOutput(context,callback,frame);
|
nextOutput(context,callback,frame);
|
||||||
|
@ -31,7 +31,7 @@ public class FragmentExtension extends Extension
|
|||||||
@Override
|
@Override
|
||||||
public <C> void output(C context, Callback<C> callback, WebSocketFrame frame) throws IOException
|
public <C> void output(C context, Callback<C> callback, WebSocketFrame frame) throws IOException
|
||||||
{
|
{
|
||||||
if (frame.getOpCode().isControlFrame())
|
if (frame.isControlFrame())
|
||||||
{
|
{
|
||||||
// Cannot fragment Control Frames
|
// Cannot fragment Control Frames
|
||||||
nextOutput(context,callback,frame);
|
nextOutput(context,callback,frame);
|
||||||
@ -40,7 +40,7 @@ public class FragmentExtension extends Extension
|
|||||||
|
|
||||||
int length = frame.getPayloadLength();
|
int length = frame.getPayloadLength();
|
||||||
|
|
||||||
OpCode opcode = frame.getOpCode(); // original opcode
|
byte opcode = frame.getOpCode(); // original opcode
|
||||||
ByteBuffer payload = frame.getPayload().slice();
|
ByteBuffer payload = frame.getPayload().slice();
|
||||||
int originalLimit = payload.limit();
|
int originalLimit = payload.limit();
|
||||||
int currentPosition = payload.position();
|
int currentPosition = payload.position();
|
||||||
|
@ -36,7 +36,7 @@ public class ControlFrameBytes<C> extends FrameBytes<C>
|
|||||||
|
|
||||||
super.completed(context);
|
super.completed(context);
|
||||||
|
|
||||||
if(frame.getOpCode() == OpCode.CLOSE)
|
if (frame.getOpCode() == OpCode.CLOSE)
|
||||||
{
|
{
|
||||||
// Disconnect the connection (no more packets/frames)
|
// Disconnect the connection (no more packets/frames)
|
||||||
connection.disconnect(false);
|
connection.disconnect(false);
|
||||||
|
@ -244,7 +244,7 @@ public abstract class WebSocketAsyncConnection extends AbstractAsyncConnection i
|
|||||||
{
|
{
|
||||||
FrameBytes<C> bytes = null;
|
FrameBytes<C> bytes = null;
|
||||||
|
|
||||||
if (frame.getOpCode().isControlFrame())
|
if (frame.isControlFrame())
|
||||||
{
|
{
|
||||||
bytes = new ControlFrameBytes<C>(this,callback,context,frame);
|
bytes = new ControlFrameBytes<C>(this,callback,context,frame);
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ public interface Frame
|
|||||||
{
|
{
|
||||||
public byte[] getMask();
|
public byte[] getMask();
|
||||||
|
|
||||||
public OpCode getOpCode();
|
public byte getOpCode();
|
||||||
|
|
||||||
public ByteBuffer getPayload();
|
public ByteBuffer getPayload();
|
||||||
|
|
||||||
|
@ -125,7 +125,7 @@ public class Generator
|
|||||||
throw new ProtocolException("RSV3 not allowed to be set");
|
throw new ProtocolException("RSV3 not allowed to be set");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (frame.getOpCode().isControlFrame())
|
if (frame.isControlFrame())
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* RFC 6455 Section 5.5
|
* RFC 6455 Section 5.5
|
||||||
@ -229,12 +229,12 @@ public class Generator
|
|||||||
b |= 0x10;
|
b |= 0x10;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte opcode = frame.getOpCode().getCode();
|
byte opcode = frame.getOpCode();
|
||||||
|
|
||||||
if (frame.isContinuation())
|
if (frame.isContinuation())
|
||||||
{
|
{
|
||||||
// Continuations are not the same OPCODE
|
// Continuations are not the same OPCODE
|
||||||
opcode = OpCode.CONTINUATION.getCode();
|
opcode = OpCode.CONTINUATION;
|
||||||
}
|
}
|
||||||
|
|
||||||
b |= opcode & 0x0F;
|
b |= opcode & 0x0F;
|
||||||
|
@ -15,89 +15,92 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
package org.eclipse.jetty.websocket.protocol;
|
package org.eclipse.jetty.websocket.protocol;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public enum OpCode
|
public final class OpCode
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* OpCode for a Continuation Frame
|
* OpCode for a Continuation Frame
|
||||||
*
|
*
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
||||||
*/
|
*/
|
||||||
CONTINUATION((byte)0x00),
|
public static final byte CONTINUATION = (byte)0x00;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpCode for a Text Frame
|
* OpCode for a Text Frame
|
||||||
*
|
*
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
||||||
*/
|
*/
|
||||||
TEXT((byte)0x01),
|
public static final byte TEXT = (byte)0x01;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpCode for a Binary Frame
|
* OpCode for a Binary Frame
|
||||||
*
|
*
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
||||||
*/
|
*/
|
||||||
BINARY((byte)0x02),
|
public static final byte BINARY = (byte)0x02;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpCode for a Close Frame
|
* OpCode for a Close Frame
|
||||||
*
|
*
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
||||||
*/
|
*/
|
||||||
CLOSE((byte)0x08),
|
public static final byte CLOSE = (byte)0x08;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpCode for a Ping Frame
|
* OpCode for a Ping Frame
|
||||||
*
|
*
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
||||||
*/
|
*/
|
||||||
PING((byte)0x09),
|
public static final byte PING = (byte)0x09;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OpCode for a Pong Frame
|
* OpCode for a Pong Frame
|
||||||
*
|
*
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
* @see <a href="https://tools.ietf.org/html/rfc6455#section-11.8">RFC 6455, Section 11.8 (WebSocket Opcode Registry</a>
|
||||||
*/
|
*/
|
||||||
PONG((byte)0x0A);
|
public static final byte PONG = (byte)0x0A;
|
||||||
|
|
||||||
private static class Codes
|
public static boolean isControlFrame(byte opcode)
|
||||||
{
|
{
|
||||||
private static final Map<Byte, OpCode> codes = new HashMap<>();
|
return (opcode >= CLOSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isDataFrame(byte opcode)
|
||||||
|
{
|
||||||
|
return (opcode == TEXT) || (opcode == BINARY);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get OpCode from specified value.
|
* Test for known opcodes (per the RFC spec)
|
||||||
*
|
*
|
||||||
* @param opcode
|
* @param opcode
|
||||||
* @return
|
* the opcode to test
|
||||||
|
* @return true if known. false if unknown, undefined, or reserved
|
||||||
*/
|
*/
|
||||||
public static OpCode from(byte opcode)
|
public static boolean isKnown(byte opcode)
|
||||||
{
|
{
|
||||||
return Codes.codes.get(opcode);
|
return (opcode == CONTINUATION) || (opcode == TEXT) || (opcode == BINARY) || (opcode == CLOSE) || (opcode == PING) || (opcode == PONG);
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte opcode;
|
public static String name(byte opcode)
|
||||||
|
|
||||||
private OpCode(byte opcode)
|
|
||||||
{
|
{
|
||||||
this.opcode = opcode;
|
switch (opcode)
|
||||||
Codes.codes.put(opcode,this);
|
{
|
||||||
}
|
case -1:
|
||||||
|
return "NO-OP";
|
||||||
public byte getCode()
|
case CONTINUATION:
|
||||||
{
|
return "CONTINUATION";
|
||||||
return this.opcode;
|
case TEXT:
|
||||||
}
|
return "TEXT";
|
||||||
|
case BINARY: return "BINARY";
|
||||||
public boolean isControlFrame()
|
case CLOSE:
|
||||||
{
|
return "CLOSE";
|
||||||
return (opcode >= CLOSE.opcode);
|
case PING:
|
||||||
}
|
return "PING";
|
||||||
|
case PONG:
|
||||||
public boolean isDataFrame()
|
return "PONG";
|
||||||
{
|
default:
|
||||||
return (this == TEXT) || (this == BINARY);
|
return "NON-SPEC[" + opcode + "]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,21 +49,24 @@ public class Parser
|
|||||||
private int cursor = 0;
|
private int cursor = 0;
|
||||||
// Frame
|
// Frame
|
||||||
private WebSocketFrame frame;
|
private WebSocketFrame frame;
|
||||||
private OpCode lastDataOpcode;
|
private byte lastDataOpcode;
|
||||||
// payload specific
|
// payload specific
|
||||||
private ByteBuffer payload;
|
private ByteBuffer payload;
|
||||||
private int payloadLength;
|
private int payloadLength;
|
||||||
|
|
||||||
|
/** Is there an extension using RSV1 */
|
||||||
|
private boolean rsv1InUse = false;
|
||||||
|
/** Is there an extension using RSV2 */
|
||||||
|
private boolean rsv2InUse = false;
|
||||||
|
/** Is there an extension using RSV3 */
|
||||||
|
private boolean rsv3InUse = false;
|
||||||
|
|
||||||
private static final Logger LOG = Log.getLogger(Parser.class);
|
private static final Logger LOG = Log.getLogger(Parser.class);
|
||||||
private IncomingFrames incomingFramesHandler;
|
private IncomingFrames incomingFramesHandler;
|
||||||
private WebSocketPolicy policy;
|
private WebSocketPolicy policy;
|
||||||
|
|
||||||
public Parser(WebSocketPolicy wspolicy)
|
public Parser(WebSocketPolicy wspolicy)
|
||||||
{
|
{
|
||||||
/*
|
|
||||||
* TODO: Investigate addition of decompression factory similar to SPDY work in situation of negotiated deflate extension?
|
|
||||||
*/
|
|
||||||
|
|
||||||
this.policy = wspolicy;
|
this.policy = wspolicy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,14 +83,14 @@ public class Parser
|
|||||||
|
|
||||||
switch (frame.getOpCode())
|
switch (frame.getOpCode())
|
||||||
{
|
{
|
||||||
case CLOSE:
|
case OpCode.CLOSE:
|
||||||
if (len == 1)
|
if (len == 1)
|
||||||
{
|
{
|
||||||
throw new ProtocolException("Invalid close frame payload length, [" + payloadLength + "]");
|
throw new ProtocolException("Invalid close frame payload length, [" + payloadLength + "]");
|
||||||
}
|
}
|
||||||
// fall thru
|
// fall thru
|
||||||
case PING:
|
case OpCode.PING:
|
||||||
case PONG:
|
case OpCode.PONG:
|
||||||
if (len > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
if (len > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
||||||
{
|
{
|
||||||
throw new ProtocolException("Invalid control frame payload length, [" + payloadLength + "] cannot exceed ["
|
throw new ProtocolException("Invalid control frame payload length, [" + payloadLength + "] cannot exceed ["
|
||||||
@ -107,6 +110,21 @@ public class Parser
|
|||||||
return policy;
|
return policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isRsv1InUse()
|
||||||
|
{
|
||||||
|
return rsv1InUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRsv2InUse()
|
||||||
|
{
|
||||||
|
return rsv2InUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRsv3InUse()
|
||||||
|
{
|
||||||
|
return rsv3InUse;
|
||||||
|
}
|
||||||
|
|
||||||
protected void notifyFrame(final WebSocketFrame f)
|
protected void notifyFrame(final WebSocketFrame f)
|
||||||
{
|
{
|
||||||
if (LOG_FRAMES.isDebugEnabled())
|
if (LOG_FRAMES.isDebugEnabled())
|
||||||
@ -219,18 +237,39 @@ public class Parser
|
|||||||
boolean rsv2 = ((b & 0x20) != 0);
|
boolean rsv2 = ((b & 0x20) != 0);
|
||||||
boolean rsv3 = ((b & 0x10) != 0);
|
boolean rsv3 = ((b & 0x10) != 0);
|
||||||
byte opc = (byte)(b & 0x0F);
|
byte opc = (byte)(b & 0x0F);
|
||||||
OpCode opcode = OpCode.from(opc);
|
byte opcode = opc;
|
||||||
|
|
||||||
if (opcode == null)
|
if (!OpCode.isKnown(opcode))
|
||||||
{
|
{
|
||||||
throw new WebSocketException("Unknown opcode: " + opc);
|
throw new ProtocolException("Unknown opcode: " + opc);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG.debug("OpCode {}, fin={}",opcode.name(),fin);
|
LOG.debug("OpCode {}, fin={}",OpCode.name(opcode),fin);
|
||||||
|
|
||||||
if (opcode.isControlFrame() && !fin)
|
/*
|
||||||
|
* RFC 6455 Section 5.2
|
||||||
|
*
|
||||||
|
* MUST be 0 unless an extension is negotiated that defines meanings for non-zero values. If a nonzero value is received and none of the
|
||||||
|
* negotiated extensions defines the meaning of such a nonzero value, the receiving endpoint MUST _Fail the WebSocket Connection_.
|
||||||
|
*/
|
||||||
|
if (!rsv1InUse && rsv1)
|
||||||
{
|
{
|
||||||
throw new ProtocolException("Fragmented Control Frame [" + opcode.name() + "]");
|
throw new ProtocolException("RSV1 not allowed to be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rsv2InUse && rsv2)
|
||||||
|
{
|
||||||
|
throw new ProtocolException("RSV2 not allowed to be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!rsv3InUse && rsv3)
|
||||||
|
{
|
||||||
|
throw new ProtocolException("RSV3 not allowed to be set");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (OpCode.isControlFrame(opcode) && !fin)
|
||||||
|
{
|
||||||
|
throw new ProtocolException("Fragmented Control Frame [" + OpCode.name(opcode) + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode == OpCode.CONTINUATION)
|
if (opcode == OpCode.CONTINUATION)
|
||||||
@ -251,7 +290,7 @@ public class Parser
|
|||||||
frame.setRsv3(rsv3);
|
frame.setRsv3(rsv3);
|
||||||
frame.setOpCode(opcode);
|
frame.setOpCode(opcode);
|
||||||
|
|
||||||
if (opcode.isDataFrame())
|
if (frame.isDataFrame())
|
||||||
{
|
{
|
||||||
lastDataOpcode = opcode;
|
lastDataOpcode = opcode;
|
||||||
}
|
}
|
||||||
@ -442,6 +481,21 @@ public class Parser
|
|||||||
this.incomingFramesHandler = incoming;
|
this.incomingFramesHandler = incoming;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setRsv1InUse(boolean rsv1InUse)
|
||||||
|
{
|
||||||
|
this.rsv1InUse = rsv1InUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRsv2InUse(boolean rsv2InUse)
|
||||||
|
{
|
||||||
|
this.rsv2InUse = rsv2InUse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRsv3InUse(boolean rsv3InUse)
|
||||||
|
{
|
||||||
|
this.rsv3InUse = rsv3InUse;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
|
@ -84,7 +84,7 @@ public class WebSocketFrame implements Frame
|
|||||||
private boolean rsv1 = false;
|
private boolean rsv1 = false;
|
||||||
private boolean rsv2 = false;
|
private boolean rsv2 = false;
|
||||||
private boolean rsv3 = false;
|
private boolean rsv3 = false;
|
||||||
private OpCode opcode = null;
|
private byte opcode = -1;
|
||||||
private boolean masked = false;
|
private boolean masked = false;
|
||||||
private byte mask[];
|
private byte mask[];
|
||||||
/**
|
/**
|
||||||
@ -111,7 +111,7 @@ public class WebSocketFrame implements Frame
|
|||||||
/**
|
/**
|
||||||
* Construct form opcode
|
* Construct form opcode
|
||||||
*/
|
*/
|
||||||
public WebSocketFrame(OpCode opcode)
|
public WebSocketFrame(byte opcode)
|
||||||
{
|
{
|
||||||
reset();
|
reset();
|
||||||
this.opcode = opcode;
|
this.opcode = opcode;
|
||||||
@ -151,7 +151,7 @@ public class WebSocketFrame implements Frame
|
|||||||
|
|
||||||
public void assertValid()
|
public void assertValid()
|
||||||
{
|
{
|
||||||
if (opcode.isControlFrame())
|
if (OpCode.isControlFrame(opcode))
|
||||||
{
|
{
|
||||||
if (getPayloadLength() > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
if (getPayloadLength() > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
||||||
{
|
{
|
||||||
@ -211,7 +211,7 @@ public class WebSocketFrame implements Frame
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final OpCode getOpCode()
|
public final byte getOpCode()
|
||||||
{
|
{
|
||||||
return opcode;
|
return opcode;
|
||||||
}
|
}
|
||||||
@ -275,6 +275,16 @@ public class WebSocketFrame implements Frame
|
|||||||
return continuation;
|
return continuation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isControlFrame()
|
||||||
|
{
|
||||||
|
return OpCode.isControlFrame(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isDataFrame()
|
||||||
|
{
|
||||||
|
return OpCode.isDataFrame(opcode);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isFin()
|
public boolean isFin()
|
||||||
{
|
{
|
||||||
@ -348,7 +358,7 @@ public class WebSocketFrame implements Frame
|
|||||||
rsv1 = false;
|
rsv1 = false;
|
||||||
rsv2 = false;
|
rsv2 = false;
|
||||||
rsv3 = false;
|
rsv3 = false;
|
||||||
opcode = null;
|
opcode = -1;
|
||||||
masked = false;
|
masked = false;
|
||||||
data = null;
|
data = null;
|
||||||
payloadLength = 0;
|
payloadLength = 0;
|
||||||
@ -388,9 +398,9 @@ public class WebSocketFrame implements Frame
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public WebSocketFrame setOpCode(OpCode opCode)
|
public WebSocketFrame setOpCode(byte op)
|
||||||
{
|
{
|
||||||
this.opcode = opCode;
|
this.opcode = op;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,7 +418,7 @@ public class WebSocketFrame implements Frame
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode.isControlFrame())
|
if (OpCode.isControlFrame(opcode))
|
||||||
{
|
{
|
||||||
if (buf.length > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
if (buf.length > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
||||||
{
|
{
|
||||||
@ -436,7 +446,7 @@ public class WebSocketFrame implements Frame
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode.isControlFrame())
|
if (OpCode.isControlFrame(opcode))
|
||||||
{
|
{
|
||||||
if (len > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
if (len > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
||||||
{
|
{
|
||||||
@ -468,7 +478,7 @@ public class WebSocketFrame implements Frame
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (opcode.isControlFrame())
|
if (OpCode.isControlFrame(opcode))
|
||||||
{
|
{
|
||||||
if (buf.remaining() > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
if (buf.remaining() > WebSocketFrame.MAX_CONTROL_PAYLOAD)
|
||||||
{
|
{
|
||||||
@ -510,14 +520,7 @@ public class WebSocketFrame implements Frame
|
|||||||
public String toString()
|
public String toString()
|
||||||
{
|
{
|
||||||
StringBuilder b = new StringBuilder();
|
StringBuilder b = new StringBuilder();
|
||||||
if (opcode != null)
|
b.append(OpCode.name(opcode));
|
||||||
{
|
|
||||||
b.append(opcode.name());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
b.append("NO-OP");
|
|
||||||
}
|
|
||||||
b.append('[');
|
b.append('[');
|
||||||
b.append("len=").append(payloadLength);
|
b.append("len=").append(payloadLength);
|
||||||
b.append(",fin=").append(fin);
|
b.append(",fin=").append(fin);
|
||||||
|
@ -23,9 +23,6 @@ import org.eclipse.jetty.util.StringUtil;
|
|||||||
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;
|
||||||
import org.eclipse.jetty.websocket.protocol.CloseInfo;
|
|
||||||
import org.eclipse.jetty.websocket.protocol.OpCode;
|
|
||||||
import org.eclipse.jetty.websocket.protocol.Parser;
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
@ -43,7 +40,7 @@ public class ClosePayloadParserTest
|
|||||||
payload.flip();
|
payload.flip();
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(24);
|
ByteBuffer buf = ByteBuffer.allocate(24);
|
||||||
buf.put((byte)(0x80 | OpCode.CLOSE.getCode())); // fin + close
|
buf.put((byte)(0x80 | OpCode.CLOSE)); // fin + close
|
||||||
buf.put((byte)(0x80 | payload.remaining()));
|
buf.put((byte)(0x80 | payload.remaining()));
|
||||||
MaskedByteBuffer.putMask(buf);
|
MaskedByteBuffer.putMask(buf);
|
||||||
MaskedByteBuffer.putPayload(buf,payload);
|
MaskedByteBuffer.putPayload(buf,payload);
|
||||||
|
@ -47,14 +47,14 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||||||
Assert.assertThat(errorType.getSimpleName(),getErrorCount(errorType),is(expectedCount));
|
Assert.assertThat(errorType.getSimpleName(),getErrorCount(errorType),is(expectedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasFrame(OpCode op)
|
public void assertHasFrame(byte op)
|
||||||
{
|
{
|
||||||
Assert.assertThat(op.name(),getFrameCount(op),greaterThanOrEqualTo(1));
|
Assert.assertThat(OpCode.name(op),getFrameCount(op),greaterThanOrEqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasFrame(OpCode op, int expectedCount)
|
public void assertHasFrame(byte op, int expectedCount)
|
||||||
{
|
{
|
||||||
Assert.assertThat(op.name(),getFrameCount(op),is(expectedCount));
|
Assert.assertThat(OpCode.name(op),getFrameCount(op),is(expectedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasNoFrames()
|
public void assertHasNoFrames()
|
||||||
@ -95,7 +95,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFrameCount(OpCode op)
|
public int getFrameCount(byte op)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for(WebSocketFrame frame: frames) {
|
for(WebSocketFrame frame: frames) {
|
||||||
|
@ -40,14 +40,14 @@ public class OutgoingFramesCapture implements OutgoingFrames
|
|||||||
Assert.assertThat("Captured frame count",writes.size(),is(expectedCount));
|
Assert.assertThat("Captured frame count",writes.size(),is(expectedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasFrame(OpCode op)
|
public void assertHasFrame(byte op)
|
||||||
{
|
{
|
||||||
Assert.assertThat(op.name(),getFrameCount(op),greaterThanOrEqualTo(1));
|
Assert.assertThat(OpCode.name(op),getFrameCount(op),greaterThanOrEqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasFrame(OpCode op, int expectedCount)
|
public void assertHasFrame(byte op, int expectedCount)
|
||||||
{
|
{
|
||||||
Assert.assertThat(op.name(),getFrameCount(op),is(expectedCount));
|
Assert.assertThat(OpCode.name(op),getFrameCount(op),is(expectedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasNoFrames()
|
public void assertHasNoFrames()
|
||||||
@ -66,7 +66,7 @@ public class OutgoingFramesCapture implements OutgoingFrames
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFrameCount(OpCode op)
|
public int getFrameCount(byte op)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (Write<?> write : writes)
|
for (Write<?> write : writes)
|
||||||
|
@ -388,14 +388,17 @@ public class WebSocketServerFactory extends AbstractLifeCycle implements WebSock
|
|||||||
if (ext.useRsv1())
|
if (ext.useRsv1())
|
||||||
{
|
{
|
||||||
connection.getGenerator().setRsv1InUse(true);
|
connection.getGenerator().setRsv1InUse(true);
|
||||||
|
connection.getParser().setRsv1InUse(true);
|
||||||
}
|
}
|
||||||
if (ext.useRsv2())
|
if (ext.useRsv2())
|
||||||
{
|
{
|
||||||
connection.getGenerator().setRsv2InUse(true);
|
connection.getGenerator().setRsv2InUse(true);
|
||||||
|
connection.getParser().setRsv2InUse(true);
|
||||||
}
|
}
|
||||||
if (ext.useRsv3())
|
if (ext.useRsv3())
|
||||||
{
|
{
|
||||||
connection.getGenerator().setRsv3InUse(true);
|
connection.getGenerator().setRsv3InUse(true);
|
||||||
|
connection.getParser().setRsv3InUse(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,11 @@ public class ByteBufferAssert
|
|||||||
|
|
||||||
public static void assertEquals(String message, ByteBuffer expectedBuffer, ByteBuffer actualBuffer)
|
public static void assertEquals(String message, ByteBuffer expectedBuffer, ByteBuffer actualBuffer)
|
||||||
{
|
{
|
||||||
|
if (expectedBuffer == null)
|
||||||
|
{
|
||||||
|
Assert.assertThat(message,actualBuffer,nullValue());
|
||||||
|
return;
|
||||||
|
}
|
||||||
byte expectedBytes[] = BufferUtil.toArray(expectedBuffer);
|
byte expectedBytes[] = BufferUtil.toArray(expectedBuffer);
|
||||||
byte actualBytes[] = BufferUtil.toArray(actualBuffer);
|
byte actualBytes[] = BufferUtil.toArray(actualBuffer);
|
||||||
assertEquals(message,expectedBytes,actualBytes);
|
assertEquals(message,expectedBytes,actualBytes);
|
||||||
|
@ -26,6 +26,7 @@ import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
|
|||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
import org.junit.Ignore;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class DeflateExtensionTest
|
public class DeflateExtensionTest
|
||||||
@ -46,6 +47,7 @@ public class DeflateExtensionTest
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("FIXME")
|
||||||
public void testDeflateFrameExtension() throws Exception
|
public void testDeflateFrameExtension() throws Exception
|
||||||
{
|
{
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||||
|
@ -4,6 +4,7 @@ import java.nio.ByteBuffer;
|
|||||||
|
|
||||||
import org.eclipse.jetty.io.ByteBufferPool;
|
import org.eclipse.jetty.io.ByteBufferPool;
|
||||||
import org.eclipse.jetty.io.StandardByteBufferPool;
|
import org.eclipse.jetty.io.StandardByteBufferPool;
|
||||||
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||||
import org.eclipse.jetty.websocket.protocol.Generator;
|
import org.eclipse.jetty.websocket.protocol.Generator;
|
||||||
import org.eclipse.jetty.websocket.server.SimpleServletServer;
|
import org.eclipse.jetty.websocket.server.SimpleServletServer;
|
||||||
@ -44,6 +45,36 @@ public abstract class AbstractABCase
|
|||||||
server.stop();
|
server.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String toUtf8String(byte[] buf)
|
||||||
|
{
|
||||||
|
String raw = StringUtil.toUTF8String(buf,0,buf.length);
|
||||||
|
StringBuilder ret = new StringBuilder();
|
||||||
|
int len = raw.length();
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
int codepoint = raw.codePointAt(i);
|
||||||
|
if (Character.isUnicodeIdentifierPart(codepoint))
|
||||||
|
{
|
||||||
|
ret.append(String.format("\\u%04X",codepoint));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ret.append(Character.toChars(codepoint));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Generator getLaxGenerator()
|
||||||
|
{
|
||||||
|
return laxGenerator;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleServletServer getServer()
|
||||||
|
{
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
protected byte[] masked(final byte[] data)
|
protected byte[] masked(final byte[] data)
|
||||||
{
|
{
|
||||||
int len = data.length;
|
int len = data.length;
|
||||||
|
@ -5,7 +5,7 @@ import org.junit.runners.Suite;
|
|||||||
|
|
||||||
@RunWith(Suite.class)
|
@RunWith(Suite.class)
|
||||||
@Suite.SuiteClasses(
|
@Suite.SuiteClasses(
|
||||||
{ TestABCase1.class, TestABCase5.class, TestABCase7_9.class })
|
{ TestABCase1.class, TestABCase2.class, TestABCase3.class, TestABCase4.class, TestABCase5.class, TestABCase6.class, TestABCase7_9.class })
|
||||||
public class AllTests
|
public class AllTests
|
||||||
{
|
{
|
||||||
/* let junit do the rest */
|
/* let junit do the rest */
|
||||||
|
@ -0,0 +1,213 @@
|
|||||||
|
package org.eclipse.jetty.websocket.server.ab;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.concurrent.TimeoutException;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.BufferUtil;
|
||||||
|
import org.eclipse.jetty.util.log.Log;
|
||||||
|
import org.eclipse.jetty.util.log.Logger;
|
||||||
|
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.ByteBufferAssert;
|
||||||
|
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
|
||||||
|
import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
|
||||||
|
import org.junit.Assert;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fuzzing utility for the AB tests.
|
||||||
|
*/
|
||||||
|
public class Fuzzer
|
||||||
|
{
|
||||||
|
public static enum SendMode
|
||||||
|
{
|
||||||
|
BULK,
|
||||||
|
PER_FRAME,
|
||||||
|
SLOW
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final Logger LOG = Log.getLogger(Fuzzer.class);
|
||||||
|
|
||||||
|
// Client side framing mask
|
||||||
|
protected static final byte[] MASK =
|
||||||
|
{ 0x11, 0x22, 0x33, 0x44 };
|
||||||
|
|
||||||
|
private final BlockheadClient client;
|
||||||
|
private final Generator generator;
|
||||||
|
private SendMode sendMode = SendMode.BULK;
|
||||||
|
private int slowSendSegmentSize = 5;
|
||||||
|
|
||||||
|
public Fuzzer(AbstractABCase testcase) throws Exception
|
||||||
|
{
|
||||||
|
this.client = new BlockheadClient(testcase.getServer().getServerUri());
|
||||||
|
this.generator = testcase.getLaxGenerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ByteBuffer asNetworkBuffer(List<WebSocketFrame> send)
|
||||||
|
{
|
||||||
|
int buflen = 0;
|
||||||
|
for (WebSocketFrame f : send)
|
||||||
|
{
|
||||||
|
buflen += f.getPayloadLength() + Generator.OVERHEAD;
|
||||||
|
}
|
||||||
|
ByteBuffer buf = ByteBuffer.allocate(buflen);
|
||||||
|
BufferUtil.clearToFill(buf);
|
||||||
|
|
||||||
|
// Generate frames
|
||||||
|
for (WebSocketFrame f : send)
|
||||||
|
{
|
||||||
|
f.setMask(MASK); // make sure we have mask set
|
||||||
|
BufferUtil.put(generator.generate(f),buf);
|
||||||
|
}
|
||||||
|
BufferUtil.flipToFlush(buf,0);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close()
|
||||||
|
{
|
||||||
|
this.client.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void connect() throws IOException
|
||||||
|
{
|
||||||
|
if (!client.isConnected())
|
||||||
|
{
|
||||||
|
client.connect();
|
||||||
|
client.sendStandardRequest();
|
||||||
|
client.expectUpgradeResponse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expect(List<WebSocketFrame> expect) throws IOException, TimeoutException
|
||||||
|
{
|
||||||
|
int expectedCount = expect.size();
|
||||||
|
|
||||||
|
// Read frames
|
||||||
|
IncomingFramesCapture capture = client.readFrames(expect.size(),TimeUnit.MILLISECONDS,500);
|
||||||
|
|
||||||
|
String prefix = "";
|
||||||
|
for (int i = 0; i < expectedCount; i++)
|
||||||
|
{
|
||||||
|
WebSocketFrame expected = expect.get(i);
|
||||||
|
WebSocketFrame actual = capture.getFrames().pop();
|
||||||
|
|
||||||
|
prefix = "Frame[" + i + "]";
|
||||||
|
|
||||||
|
Assert.assertThat(prefix + ".opcode",OpCode.name(actual.getOpCode()),is(OpCode.name(expected.getOpCode())));
|
||||||
|
prefix += "/" + actual.getOpCode();
|
||||||
|
if (expected.getOpCode() == OpCode.CLOSE)
|
||||||
|
{
|
||||||
|
CloseInfo expectedClose = new CloseInfo(expected);
|
||||||
|
CloseInfo actualClose = new CloseInfo(actual);
|
||||||
|
Assert.assertThat(prefix + ".statusCode",actualClose.getStatusCode(),is(expectedClose.getStatusCode()));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.assertThat(prefix + ".payloadLength",actual.getPayloadLength(),is(expected.getPayloadLength()));
|
||||||
|
ByteBufferAssert.assertEquals(prefix + ".payload",expected.getPayload(),actual.getPayload());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void expect(WebSocketFrame expect) throws IOException, TimeoutException
|
||||||
|
{
|
||||||
|
expect(Collections.singletonList(expect));
|
||||||
|
}
|
||||||
|
|
||||||
|
public SendMode getSendMode()
|
||||||
|
{
|
||||||
|
return sendMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getSlowSendSegmentSize()
|
||||||
|
{
|
||||||
|
return slowSendSegmentSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(ByteBuffer buf) throws IOException
|
||||||
|
{
|
||||||
|
Assert.assertThat("Client connected",client.isConnected(),is(true));
|
||||||
|
LOG.debug("Sending bytes {}",BufferUtil.toDetailString(buf));
|
||||||
|
if (sendMode == SendMode.SLOW)
|
||||||
|
{
|
||||||
|
client.writeRawSlowly(buf,slowSendSegmentSize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
client.writeRaw(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(ByteBuffer buf, int numBytes) throws IOException
|
||||||
|
{
|
||||||
|
client.writeRaw(buf,numBytes);
|
||||||
|
client.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(List<WebSocketFrame> send) throws IOException
|
||||||
|
{
|
||||||
|
Assert.assertThat("Client connected",client.isConnected(),is(true));
|
||||||
|
LOG.debug("Sending {} frames (mode {})",send.size(),sendMode);
|
||||||
|
if ((sendMode == SendMode.BULK) || (sendMode == SendMode.SLOW))
|
||||||
|
{
|
||||||
|
int buflen = 0;
|
||||||
|
for (WebSocketFrame f : send)
|
||||||
|
{
|
||||||
|
buflen += f.getPayloadLength() + Generator.OVERHEAD;
|
||||||
|
}
|
||||||
|
ByteBuffer buf = ByteBuffer.allocate(buflen);
|
||||||
|
BufferUtil.clearToFill(buf);
|
||||||
|
|
||||||
|
// Generate frames
|
||||||
|
for (WebSocketFrame f : send)
|
||||||
|
{
|
||||||
|
f.setMask(MASK); // make sure we have mask set
|
||||||
|
BufferUtil.put(generator.generate(f),buf);
|
||||||
|
}
|
||||||
|
BufferUtil.flipToFlush(buf,0);
|
||||||
|
|
||||||
|
// Write Data Frame
|
||||||
|
switch (sendMode)
|
||||||
|
{
|
||||||
|
case BULK:
|
||||||
|
client.writeRaw(buf);
|
||||||
|
break;
|
||||||
|
case SLOW:
|
||||||
|
client.writeRawSlowly(buf,slowSendSegmentSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sendMode == SendMode.PER_FRAME)
|
||||||
|
{
|
||||||
|
for (WebSocketFrame f : send)
|
||||||
|
{
|
||||||
|
f.setMask(MASK); // make sure we have mask set
|
||||||
|
// Using lax generator, generate and send
|
||||||
|
client.writeRaw(generator.generate(f));
|
||||||
|
client.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void send(WebSocketFrame send) throws IOException
|
||||||
|
{
|
||||||
|
send(Collections.singletonList(send));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSendMode(SendMode sendMode)
|
||||||
|
{
|
||||||
|
this.sendMode = sendMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSlowSendSegmentSize(int segmentSize)
|
||||||
|
{
|
||||||
|
this.slowSendSegmentSize = segmentSize;
|
||||||
|
}
|
||||||
|
}
|
@ -15,201 +15,45 @@
|
|||||||
//========================================================================
|
//========================================================================
|
||||||
package org.eclipse.jetty.websocket.server.ab;
|
package org.eclipse.jetty.websocket.server.ab;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
|
||||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
import org.eclipse.jetty.websocket.protocol.CloseInfo;
|
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.protocol.WebSocketFrame;
|
||||||
import org.eclipse.jetty.websocket.server.ByteBufferAssert;
|
import org.eclipse.jetty.websocket.server.ab.Fuzzer.SendMode;
|
||||||
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
|
import org.junit.Ignore;
|
||||||
import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class TestABCase1 extends AbstractABCase
|
public class TestABCase1 extends AbstractABCase
|
||||||
{
|
{
|
||||||
private void assertEchoEmptyFrame(OpCode opcode) throws Exception
|
|
||||||
{
|
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
client.connect();
|
|
||||||
client.sendStandardRequest();
|
|
||||||
client.expectUpgradeResponse();
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(Generator.OVERHEAD);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | opcode.getCode()));
|
|
||||||
putPayloadLength(buf,0);
|
|
||||||
putMask(buf);
|
|
||||||
|
|
||||||
// Write Data Frame
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
client.writeRaw(buf);
|
|
||||||
|
|
||||||
// Prepare Close Frame
|
|
||||||
CloseInfo close = new CloseInfo(StatusCode.NORMAL);
|
|
||||||
buf = strictGenerator.generate(close.asFrame());
|
|
||||||
|
|
||||||
// Write Close Frame
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(2,TimeUnit.MILLISECONDS,500);
|
|
||||||
|
|
||||||
// Validate echo'd frame
|
|
||||||
WebSocketFrame frame = capture.getFrames().get(0);
|
|
||||||
Assert.assertThat("frame should be " + opcode + " frame",frame.getOpCode(),is(opcode));
|
|
||||||
Assert.assertThat(opcode + ".payloadLength",frame.getPayloadLength(),is(0));
|
|
||||||
|
|
||||||
// Validate close
|
|
||||||
frame = capture.getFrames().get(1);
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.NORMAL));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertEchoFrame(OpCode opcode, byte[] payload) throws Exception
|
|
||||||
{
|
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
client.connect();
|
|
||||||
client.sendStandardRequest();
|
|
||||||
client.expectUpgradeResponse();
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(payload.length + Generator.OVERHEAD);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | opcode.getCode()));
|
|
||||||
putPayloadLength(buf,payload.length);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(payload));
|
|
||||||
|
|
||||||
// Write Data Frame
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
client.writeRaw(buf);
|
|
||||||
|
|
||||||
// Prepare Close Frame
|
|
||||||
CloseInfo close = new CloseInfo(StatusCode.NORMAL);
|
|
||||||
WebSocketFrame closeFrame = close.asFrame();
|
|
||||||
closeFrame.setMask(MASK);
|
|
||||||
buf = strictGenerator.generate(closeFrame);
|
|
||||||
|
|
||||||
// Write Close Frame
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(2,TimeUnit.MILLISECONDS,1000);
|
|
||||||
|
|
||||||
// Validate echo'd frame
|
|
||||||
WebSocketFrame frame = capture.getFrames().get(0);
|
|
||||||
Assert.assertThat("frame should be " + opcode + " frame",frame.getOpCode(),is(opcode));
|
|
||||||
Assert.assertThat(opcode + ".payloadLength",frame.getPayloadLength(),is(payload.length));
|
|
||||||
ByteBufferAssert.assertEquals(opcode + ".payload",payload,frame.getPayload());
|
|
||||||
|
|
||||||
// Validate close
|
|
||||||
frame = capture.getFrames().get(1);
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.NORMAL));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertEchoSegmentedFrame(OpCode opcode, byte payload[], int segmentSize) throws Exception
|
|
||||||
{
|
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
client.connect();
|
|
||||||
client.sendStandardRequest();
|
|
||||||
client.expectUpgradeResponse();
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(payload.length + Generator.OVERHEAD);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | opcode.getCode()));
|
|
||||||
putPayloadLength(buf,payload.length);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(payload));
|
|
||||||
|
|
||||||
// Write frame, in small blocks of segmentSize
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
int origLimit = buf.limit();
|
|
||||||
int limit = buf.limit();
|
|
||||||
int len;
|
|
||||||
int pos = buf.position();
|
|
||||||
int overallLeft = buf.remaining();
|
|
||||||
while (overallLeft > 0)
|
|
||||||
{
|
|
||||||
buf.position(pos);
|
|
||||||
limit = Math.min(origLimit,pos + segmentSize);
|
|
||||||
buf.limit(limit);
|
|
||||||
len = buf.remaining();
|
|
||||||
overallLeft -= len;
|
|
||||||
pos += len;
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare Close Frame
|
|
||||||
CloseInfo close = new CloseInfo(StatusCode.NORMAL);
|
|
||||||
buf = strictGenerator.generate(close.asFrame());
|
|
||||||
|
|
||||||
// Write Close Frame
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(2,TimeUnit.MILLISECONDS,500);
|
|
||||||
|
|
||||||
// Validate echo'd frame
|
|
||||||
WebSocketFrame frame = capture.getFrames().get(0);
|
|
||||||
Assert.assertThat("frame should be " + opcode + " frame",frame.getOpCode(),is(opcode));
|
|
||||||
Assert.assertThat(opcode + ".payloadLength",frame.getPayloadLength(),is(payload.length));
|
|
||||||
ByteBufferAssert.assertEquals(opcode + ".payload",payload,frame.getPayload());
|
|
||||||
|
|
||||||
// Validate close
|
|
||||||
frame = capture.getFrames().get(1);
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.NORMAL));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Echo 0 byte TEXT message
|
* Echo 0 byte TEXT message
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCase1_1_1() throws Exception
|
public void testCase1_1_1() throws Exception
|
||||||
{
|
{
|
||||||
assertEchoEmptyFrame(OpCode.TEXT);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text());
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text());
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -221,7 +65,26 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
byte payload[] = new byte[125];
|
byte payload[] = new byte[125];
|
||||||
Arrays.fill(payload,(byte)'*');
|
Arrays.fill(payload,(byte)'*');
|
||||||
|
|
||||||
assertEchoFrame(OpCode.TEXT,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -233,7 +96,26 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
byte payload[] = new byte[126];
|
byte payload[] = new byte[126];
|
||||||
Arrays.fill(payload,(byte)'*');
|
Arrays.fill(payload,(byte)'*');
|
||||||
|
|
||||||
assertEchoFrame(OpCode.TEXT,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,7 +127,26 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
byte payload[] = new byte[127];
|
byte payload[] = new byte[127];
|
||||||
Arrays.fill(payload,(byte)'*');
|
Arrays.fill(payload,(byte)'*');
|
||||||
|
|
||||||
assertEchoFrame(OpCode.TEXT,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -257,31 +158,90 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
byte payload[] = new byte[128];
|
byte payload[] = new byte[128];
|
||||||
Arrays.fill(payload,(byte)'*');
|
Arrays.fill(payload,(byte)'*');
|
||||||
|
|
||||||
assertEchoFrame(OpCode.TEXT,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Echo 65535 byte TEXT message (uses medium 2 byte payload length)
|
* Echo 65535 byte TEXT message (uses medium 2 byte payload length)
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("FIXME")
|
||||||
public void testCase1_1_6() throws Exception
|
public void testCase1_1_6() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = new byte[65535];
|
byte payload[] = new byte[65535];
|
||||||
Arrays.fill(payload,(byte)'*');
|
Arrays.fill(payload,(byte)'*');
|
||||||
|
|
||||||
assertEchoFrame(OpCode.TEXT,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Echo 65536 byte TEXT message (uses large 8 byte payload length)
|
* Echo 65536 byte TEXT message (uses large 8 byte payload length)
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("FIXME")
|
||||||
public void testCase1_1_7() throws Exception
|
public void testCase1_1_7() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = new byte[65536];
|
byte payload[] = new byte[65536];
|
||||||
Arrays.fill(payload,(byte)'*');
|
Arrays.fill(payload,(byte)'*');
|
||||||
|
|
||||||
assertEchoFrame(OpCode.TEXT,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -292,13 +252,34 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
* This is done to test the parsing together of the frame on the server side.
|
* This is done to test the parsing together of the frame on the server side.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("FIXME")
|
||||||
public void testCase1_1_8() throws Exception
|
public void testCase1_1_8() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = new byte[65536];
|
byte payload[] = new byte[65536];
|
||||||
Arrays.fill(payload,(byte)'*');
|
Arrays.fill(payload,(byte)'*');
|
||||||
int segmentSize = 997;
|
int segmentSize = 997;
|
||||||
|
|
||||||
assertEchoSegmentedFrame(OpCode.TEXT,payload,segmentSize);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.SLOW);
|
||||||
|
fuzzer.setSlowSendSegmentSize(segmentSize);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -307,7 +288,26 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
@Test
|
@Test
|
||||||
public void testCase1_2_1() throws Exception
|
public void testCase1_2_1() throws Exception
|
||||||
{
|
{
|
||||||
assertEchoEmptyFrame(OpCode.BINARY);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary());
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.binary());
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -319,7 +319,26 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
byte payload[] = new byte[125];
|
byte payload[] = new byte[125];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
|
|
||||||
assertEchoFrame(OpCode.BINARY,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -331,7 +350,26 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
byte payload[] = new byte[126];
|
byte payload[] = new byte[126];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
|
|
||||||
assertEchoFrame(OpCode.BINARY,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -343,7 +381,26 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
byte payload[] = new byte[127];
|
byte payload[] = new byte[127];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
|
|
||||||
assertEchoFrame(OpCode.BINARY,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -355,31 +412,90 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
byte payload[] = new byte[128];
|
byte payload[] = new byte[128];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
|
|
||||||
assertEchoFrame(OpCode.BINARY,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Echo 65535 byte BINARY message (uses medium 2 byte payload length)
|
* Echo 65535 byte BINARY message (uses medium 2 byte payload length)
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("FIXME")
|
||||||
public void testCase1_2_6() throws Exception
|
public void testCase1_2_6() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = new byte[65535];
|
byte payload[] = new byte[65535];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
|
|
||||||
assertEchoFrame(OpCode.BINARY,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Echo 65536 byte BINARY message (uses large 8 byte payload length)
|
* Echo 65536 byte BINARY message (uses large 8 byte payload length)
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("FIXME")
|
||||||
public void testCase1_2_7() throws Exception
|
public void testCase1_2_7() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = new byte[65536];
|
byte payload[] = new byte[65536];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
|
|
||||||
assertEchoFrame(OpCode.BINARY,payload);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -390,12 +506,33 @@ public class TestABCase1 extends AbstractABCase
|
|||||||
* This is done to test the parsing together of the frame on the server side.
|
* This is done to test the parsing together of the frame on the server side.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("FIXME")
|
||||||
public void testCase1_2_8() throws Exception
|
public void testCase1_2_8() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = new byte[65536];
|
byte payload[] = new byte[65536];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
int segmentSize = 997;
|
int segmentSize = 997;
|
||||||
|
|
||||||
assertEchoSegmentedFrame(OpCode.BINARY,payload,segmentSize);
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.binary().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(SendMode.SLOW);
|
||||||
|
fuzzer.setSlowSendSegmentSize(segmentSize);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,224 +1,41 @@
|
|||||||
package org.eclipse.jetty.websocket.server.ab;
|
package org.eclipse.jetty.websocket.server.ab;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.List;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
import org.eclipse.jetty.websocket.protocol.CloseInfo;
|
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.OpCode;
|
||||||
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
||||||
import org.eclipse.jetty.websocket.server.ByteBufferAssert;
|
import org.junit.Ignore;
|
||||||
import org.eclipse.jetty.websocket.server.blockhead.BlockheadClient;
|
|
||||||
import org.eclipse.jetty.websocket.server.helper.IncomingFramesCapture;
|
|
||||||
import org.junit.Assert;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class TestABCase2 extends AbstractABCase
|
public class TestABCase2 extends AbstractABCase
|
||||||
{
|
{
|
||||||
private void assertPingFrame(byte[] payload) throws Exception
|
|
||||||
{
|
|
||||||
boolean hasPayload = ((payload != null) && (payload.length > 0));
|
|
||||||
|
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
client.connect();
|
|
||||||
client.sendStandardRequest();
|
|
||||||
client.expectUpgradeResponse();
|
|
||||||
|
|
||||||
int len = 0;
|
|
||||||
if (hasPayload)
|
|
||||||
{
|
|
||||||
len = payload.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(len + Generator.OVERHEAD);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare PING Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.PING.getCode()));
|
|
||||||
putPayloadLength(buf,len);
|
|
||||||
putMask(buf);
|
|
||||||
if (hasPayload)
|
|
||||||
{
|
|
||||||
buf.put(masked(payload));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare CLOSE Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.CLOSE.getCode()));
|
|
||||||
putPayloadLength(buf,2);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(new byte[]
|
|
||||||
{ 0x03, (byte)0xE8 }));
|
|
||||||
|
|
||||||
// Write Data Frame
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(2,TimeUnit.MILLISECONDS,500);
|
|
||||||
|
|
||||||
// Validate echo'd frame
|
|
||||||
WebSocketFrame frame = capture.getFrames().get(0);
|
|
||||||
Assert.assertThat("frame should be PONG frame",frame.getOpCode(),is(OpCode.PONG));
|
|
||||||
if (hasPayload)
|
|
||||||
{
|
|
||||||
Assert.assertThat("PONG.payloadLength",frame.getPayloadLength(),is(payload.length));
|
|
||||||
ByteBufferAssert.assertEquals("PONG.payload",payload,frame.getPayload());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Assert.assertThat("PONG.payloadLength",frame.getPayloadLength(),is(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate close
|
|
||||||
frame = capture.getFrames().get(1);
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
CloseInfo close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.NORMAL));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void assertProtocolError(byte[] payload) throws Exception
|
|
||||||
{
|
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
client.connect();
|
|
||||||
client.sendStandardRequest();
|
|
||||||
client.expectUpgradeResponse();
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(payload.length + Generator.OVERHEAD);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare PING Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.PING.getCode()));
|
|
||||||
putPayloadLength(buf,payload.length);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(payload));
|
|
||||||
|
|
||||||
// Prepare CLOSE Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.CLOSE.getCode()));
|
|
||||||
putPayloadLength(buf,2);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(new byte[]
|
|
||||||
{ 0x03, (byte)0xE8 }));
|
|
||||||
|
|
||||||
// Write Data Frame
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,500);
|
|
||||||
|
|
||||||
// Validate close w/ Protocol Error
|
|
||||||
WebSocketFrame frame = capture.getFrames().pop();
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
CloseInfo close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.PROTOCOL));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Send a ping frame as separate segments, in an inefficient way.
|
|
||||||
*
|
|
||||||
* @param payload
|
|
||||||
* the payload
|
|
||||||
* @param segmentSize
|
|
||||||
* the segment size for each inefficient segment (flush between)
|
|
||||||
*/
|
|
||||||
private void assertSegmentedPingFrame(byte[] payload, int segmentSize) throws Exception
|
|
||||||
{
|
|
||||||
Assert.assertThat("payload exists for segmented send",payload,notNullValue());
|
|
||||||
Assert.assertThat("payload exists for segmented send",payload.length,greaterThan(0));
|
|
||||||
|
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
|
||||||
try
|
|
||||||
{
|
|
||||||
client.connect();
|
|
||||||
client.sendStandardRequest();
|
|
||||||
client.expectUpgradeResponse();
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(payload.length + Generator.OVERHEAD);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare PING Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.PING.getCode()));
|
|
||||||
putPayloadLength(buf,payload.length);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(payload));
|
|
||||||
|
|
||||||
// Prepare CLOSE Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.CLOSE.getCode()));
|
|
||||||
putPayloadLength(buf,2);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(new byte[]
|
|
||||||
{ 0x03, (byte)0xE8 }));
|
|
||||||
|
|
||||||
// Write Data Frame
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
int origLimit = buf.limit();
|
|
||||||
int limit = buf.limit();
|
|
||||||
int len;
|
|
||||||
int pos = buf.position();
|
|
||||||
int overallLeft = buf.remaining();
|
|
||||||
while (overallLeft > 0)
|
|
||||||
{
|
|
||||||
buf.position(pos);
|
|
||||||
limit = Math.min(origLimit,pos + segmentSize);
|
|
||||||
buf.limit(limit);
|
|
||||||
len = buf.remaining();
|
|
||||||
overallLeft -= len;
|
|
||||||
pos += len;
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(2,TimeUnit.MILLISECONDS,500);
|
|
||||||
|
|
||||||
// Validate echo'd frame
|
|
||||||
WebSocketFrame frame = capture.getFrames().get(0);
|
|
||||||
Assert.assertThat("frame should be PONG frame",frame.getOpCode(),is(OpCode.PONG));
|
|
||||||
Assert.assertThat("PONG.payloadLength",frame.getPayloadLength(),is(payload.length));
|
|
||||||
ByteBufferAssert.assertEquals("PONG.payload",payload,frame.getPayload());
|
|
||||||
|
|
||||||
// Validate close
|
|
||||||
frame = capture.getFrames().get(1);
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
CloseInfo close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.NORMAL));
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
client.disconnect();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ping without payload
|
* Ping without payload
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testCase2_1() throws Exception
|
public void testCase2_1() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = new byte[0];
|
WebSocketFrame send = WebSocketFrame.ping();
|
||||||
assertPingFrame(payload);
|
|
||||||
|
WebSocketFrame expect = WebSocketFrame.pong();
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -229,20 +46,76 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
{
|
{
|
||||||
// send 10 pings each with unique payload
|
// send 10 pings each with unique payload
|
||||||
// send close
|
// send close
|
||||||
// expect 10 pongs with OUR payload
|
// expect 10 pongs with our unique payload
|
||||||
// expect close
|
// expect close
|
||||||
|
|
||||||
|
int pingCount = 10;
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < pingCount; i++)
|
||||||
|
{
|
||||||
|
String payload = String.format("ping-%d[%X]",i,i);
|
||||||
|
send.add(WebSocketFrame.ping().setPayload(payload));
|
||||||
|
expect.add(WebSocketFrame.pong().setPayload(payload));
|
||||||
|
}
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 10 pings, sent slowly
|
* 10 pings, sent slowly
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
|
@Ignore("FIXME")
|
||||||
public void testCase2_11() throws Exception
|
public void testCase2_11() throws Exception
|
||||||
{
|
{
|
||||||
// send 10 pings (slowly) each with unique payload
|
// send 10 pings (slowly) each with unique payload
|
||||||
// send close
|
// send close
|
||||||
// expect 10 pongs with OUR payload
|
// expect 10 pongs with OUR payload
|
||||||
// expect close
|
// expect close
|
||||||
|
|
||||||
|
int pingCount = 10;
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < pingCount; i++)
|
||||||
|
{
|
||||||
|
String payload = String.format("ping-%d[%X]",i,i);
|
||||||
|
send.add(WebSocketFrame.ping().setPayload(payload));
|
||||||
|
expect.add(WebSocketFrame.pong().setPayload(payload));
|
||||||
|
}
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.SLOW);
|
||||||
|
fuzzer.setSlowSendSegmentSize(5);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -252,7 +125,27 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
public void testCase2_2() throws Exception
|
public void testCase2_2() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = StringUtil.getUtf8Bytes("Hello world");
|
byte payload[] = StringUtil.getUtf8Bytes("Hello world");
|
||||||
assertPingFrame(payload);
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.ping().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.pong().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -263,7 +156,27 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
{
|
{
|
||||||
byte payload[] = new byte[]
|
byte payload[] = new byte[]
|
||||||
{ 0x00, (byte)0xFF, (byte)0xFE, (byte)0xFD, (byte)0xFC, (byte)0xFB, 0x00, (byte)0xFF };
|
{ 0x00, (byte)0xFF, (byte)0xFE, (byte)0xFD, (byte)0xFC, (byte)0xFB, 0x00, (byte)0xFF };
|
||||||
assertPingFrame(payload);
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.ping().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.pong().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -274,7 +187,27 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
{
|
{
|
||||||
byte payload[] = new byte[125];
|
byte payload[] = new byte[125];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
assertPingFrame(payload);
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.ping().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.pong().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -283,9 +216,29 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
@Test
|
@Test
|
||||||
public void testCase2_5() throws Exception
|
public void testCase2_5() throws Exception
|
||||||
{
|
{
|
||||||
byte payload[] = new byte[126];
|
byte payload[] = new byte[126]; // intentionally too big
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
assertProtocolError(payload);
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
// trick websocket frame into making extra large payload for ping
|
||||||
|
send.add(WebSocketFrame.binary(payload).setOpCode(OpCode.PING));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -296,7 +249,28 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
{
|
{
|
||||||
byte payload[] = new byte[125];
|
byte payload[] = new byte[125];
|
||||||
Arrays.fill(payload,(byte)0xFE);
|
Arrays.fill(payload,(byte)0xFE);
|
||||||
assertSegmentedPingFrame(payload,1);
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.ping().setPayload(payload));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.pong().setPayload(payload));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.SLOW);
|
||||||
|
fuzzer.setSlowSendSegmentSize(1);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -305,50 +279,25 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
@Test
|
@Test
|
||||||
public void testCase2_7() throws Exception
|
public void testCase2_7() throws Exception
|
||||||
{
|
{
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.pong()); // unsolicited pong
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
client.connect();
|
fuzzer.connect();
|
||||||
client.sendStandardRequest();
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
client.expectUpgradeResponse();
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
byte payload[] = new byte[0];
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(256);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare Unsolicited PONG Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.PONG.getCode()));
|
|
||||||
putPayloadLength(buf,payload.length);
|
|
||||||
putMask(buf);
|
|
||||||
// buf.put(masked(payload));
|
|
||||||
|
|
||||||
// Prepare CLOSE Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.CLOSE.getCode()));
|
|
||||||
putPayloadLength(buf,2);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(new byte[]
|
|
||||||
{ 0x03, (byte)0xE8 }));
|
|
||||||
|
|
||||||
// Write Data Frame
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,500);
|
|
||||||
|
|
||||||
// Validate close
|
|
||||||
WebSocketFrame frame = capture.getFrames().pop();
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
CloseInfo close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.NORMAL));
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
client.disconnect();
|
fuzzer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -357,48 +306,24 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
@Test
|
@Test
|
||||||
public void testCase2_8() throws Exception
|
public void testCase2_8() throws Exception
|
||||||
{
|
{
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.pong().setPayload("unsolicited")); // unsolicited pong
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
client.connect();
|
fuzzer.connect();
|
||||||
client.sendStandardRequest();
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
client.expectUpgradeResponse();
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
byte payload[] = StringUtil.getUtf8Bytes("unsolicited");
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(256);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare Unsolicited PONG Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.PONG.getCode()));
|
|
||||||
putPayloadLength(buf,payload.length);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(payload));
|
|
||||||
|
|
||||||
// Prepare CLOSE Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.CLOSE.getCode()));
|
|
||||||
putPayloadLength(buf,2);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(new byte[]
|
|
||||||
{ 0x03, (byte)0xE8 }));
|
|
||||||
|
|
||||||
// Write Data Frame
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(1,TimeUnit.MILLISECONDS,500);
|
|
||||||
|
|
||||||
// Validate close
|
|
||||||
WebSocketFrame frame = capture.getFrames().pop();
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
CloseInfo close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.NORMAL));
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
client.disconnect();
|
fuzzer.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -408,69 +333,26 @@ public class TestABCase2 extends AbstractABCase
|
|||||||
@Test
|
@Test
|
||||||
public void testCase2_9() throws Exception
|
public void testCase2_9() throws Exception
|
||||||
{
|
{
|
||||||
// send unsolicited pong with payload.
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
// send OUR ping with payload
|
send.add(WebSocketFrame.pong().setPayload("unsolicited")); // unsolicited pong
|
||||||
// send close
|
send.add(WebSocketFrame.ping().setPayload("our ping")); // our ping
|
||||||
// expect pong with OUR payload
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
// expect close
|
|
||||||
|
|
||||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.pong().setPayload("our ping")); // our pong
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
client.connect();
|
fuzzer.connect();
|
||||||
client.sendStandardRequest();
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
client.expectUpgradeResponse();
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
byte pongPayload[] = StringUtil.getUtf8Bytes("unsolicited");
|
|
||||||
|
|
||||||
ByteBuffer buf = ByteBuffer.allocate(512);
|
|
||||||
BufferUtil.clearToFill(buf);
|
|
||||||
|
|
||||||
// Prepare Unsolicited PONG Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.PONG.getCode()));
|
|
||||||
putPayloadLength(buf,pongPayload.length);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(pongPayload));
|
|
||||||
|
|
||||||
// Prepare our PING with payload
|
|
||||||
byte pingPayload[] = StringUtil.getUtf8Bytes("ping me");
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.PING.getCode()));
|
|
||||||
putPayloadLength(buf,pingPayload.length);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(pingPayload));
|
|
||||||
|
|
||||||
// Prepare CLOSE Frame
|
|
||||||
buf.put((byte)(0x00 | FIN | OpCode.CLOSE.getCode()));
|
|
||||||
putPayloadLength(buf,2);
|
|
||||||
putMask(buf);
|
|
||||||
buf.put(masked(new byte[]
|
|
||||||
{ 0x03, (byte)0xE8 }));
|
|
||||||
|
|
||||||
// Write Data Frame
|
|
||||||
BufferUtil.flipToFlush(buf,0);
|
|
||||||
client.writeRaw(buf);
|
|
||||||
client.flush();
|
|
||||||
|
|
||||||
// Read frames
|
|
||||||
IncomingFramesCapture capture = client.readFrames(2,TimeUnit.MILLISECONDS,500);
|
|
||||||
|
|
||||||
// Validate PONG
|
|
||||||
WebSocketFrame frame = capture.getFrames().pop();
|
|
||||||
Assert.assertThat("frame should be PONG frame",frame.getOpCode(),is(OpCode.PONG));
|
|
||||||
Assert.assertThat("PONG.payloadLength",frame.getPayloadLength(),is(pingPayload.length));
|
|
||||||
ByteBufferAssert.assertEquals("PONG.payload",pingPayload,frame.getPayload());
|
|
||||||
|
|
||||||
// Validate close
|
|
||||||
frame = capture.getFrames().pop();
|
|
||||||
Assert.assertThat("CLOSE.frame.opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
|
||||||
CloseInfo close = new CloseInfo(frame);
|
|
||||||
Assert.assertThat("CLOSE.statusCode",close.getStatusCode(),is(StatusCode.NORMAL));
|
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
client.disconnect();
|
fuzzer.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,231 @@
|
|||||||
|
// ========================================================================
|
||||||
|
// Copyright 2011-2012 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.server.ab;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
|
import org.eclipse.jetty.websocket.protocol.CloseInfo;
|
||||||
|
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class TestABCase3 extends AbstractABCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Send small text frame, with RSV1 == true, with no extensions defined.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase3_1() throws Exception
|
||||||
|
{
|
||||||
|
WebSocketFrame send = WebSocketFrame.text("small").setRsv1(true); // intentionally bad
|
||||||
|
|
||||||
|
WebSocketFrame expect = new CloseInfo(StatusCode.PROTOCOL).asFrame();
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text frame, send again with RSV2 == true, then ping, with no extensions defined.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase3_2() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("small"));
|
||||||
|
send.add(WebSocketFrame.text("small").setRsv2(true)); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping().setPayload("ping"));
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("small")); // echo on good frame
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text frame, send again with (RSV1 & RSV2), then ping, with no extensions defined.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase3_3() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("small"));
|
||||||
|
send.add(WebSocketFrame.text("small").setRsv1(true).setRsv2(true)); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping().setPayload("ping"));
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("small")); // echo on good frame
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.PER_FRAME);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text frame, send again with (RSV3), then ping, with no extensions defined.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase3_4() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("small"));
|
||||||
|
send.add(WebSocketFrame.text("small").setRsv3(true)); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping().setPayload("ping"));
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("small")); // echo on good frame
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.SLOW);
|
||||||
|
fuzzer.setSlowSendSegmentSize(1);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send binary frame with (RSV3 & RSV1), with no extensions defined.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase3_5() throws Exception
|
||||||
|
{
|
||||||
|
byte payload[] = new byte[8];
|
||||||
|
Arrays.fill(payload,(byte)0xFF);
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.binary(payload).setRsv3(true).setRsv1(true)); // intentionally bad
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send ping frame with (RSV3 & RSV2), with no extensions defined.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase3_6() throws Exception
|
||||||
|
{
|
||||||
|
byte payload[] = new byte[8];
|
||||||
|
Arrays.fill(payload,(byte)0xFF);
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.ping().setPayload(payload).setRsv3(true).setRsv2(true)); // intentionally bad
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send close frame with (RSV3 & RSV2 & RSV1), with no extensions defined.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase3_7() throws Exception
|
||||||
|
{
|
||||||
|
byte payload[] = new byte[8];
|
||||||
|
Arrays.fill(payload,(byte)0xFF);
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
WebSocketFrame frame = new CloseInfo(StatusCode.NORMAL).asFrame();
|
||||||
|
frame.setRsv1(true);
|
||||||
|
frame.setRsv2(true);
|
||||||
|
frame.setRsv3(true);
|
||||||
|
send.add(frame); // intentionally bad
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,293 @@
|
|||||||
|
package org.eclipse.jetty.websocket.server.ab;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
|
import org.eclipse.jetty.websocket.protocol.CloseInfo;
|
||||||
|
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
public class TestABCase4 extends AbstractABCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Send opcode 3 (reserved)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_1_1() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame((byte)3)); // intentionally bad
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send opcode 4 (reserved), with payload
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_1_2() throws Exception
|
||||||
|
{
|
||||||
|
byte payload[] = StringUtil.getUtf8Bytes("reserved payload");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame((byte)4).setPayload(payload)); // intentionally bad
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text, then frame with opcode 5 (reserved), then ping
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_1_3() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("hello"));
|
||||||
|
send.add(new WebSocketFrame((byte)5)); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("hello")); // echo
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text, then frame with opcode 6 (reserved) w/payload, then ping
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_1_4() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("hello"));
|
||||||
|
send.add(new WebSocketFrame((byte)6).setPayload("bad")); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("hello")); // echo
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text, then frame with opcode 7 (reserved) w/payload, then ping
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_1_5() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("hello"));
|
||||||
|
send.add(new WebSocketFrame((byte)7).setPayload("bad")); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("hello")); // echo
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send opcode 11 (reserved)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_2_1() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame((byte)11)); // intentionally bad
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send opcode 12 (reserved)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_2_2() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame((byte)12).setPayload("bad")); // intentionally bad
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text, then frame with opcode 13 (reserved), then ping
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_2_3() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("hello"));
|
||||||
|
send.add(new WebSocketFrame((byte)13)); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("hello")); // echo
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text, then frame with opcode 14 (reserved), then ping
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_2_4() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("hello"));
|
||||||
|
send.add(new WebSocketFrame((byte)14).setPayload("bad")); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("hello")); // echo
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send small text, then frame with opcode 15 (reserved), then ping
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase4_2_5() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text("hello"));
|
||||||
|
send.add(new WebSocketFrame((byte)15).setPayload("bad")); // intentionally bad
|
||||||
|
send.add(WebSocketFrame.ping());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("hello")); // echo
|
||||||
|
expect.add(new CloseInfo(StatusCode.PROTOCOL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,846 @@
|
|||||||
|
// ========================================================================
|
||||||
|
// Copyright 2011-2012 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.server.ab;
|
||||||
|
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||||
|
import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
||||||
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
|
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||||
|
import org.eclipse.jetty.websocket.protocol.CloseInfo;
|
||||||
|
import org.eclipse.jetty.websocket.protocol.OpCode;
|
||||||
|
import org.eclipse.jetty.websocket.protocol.WebSocketFrame;
|
||||||
|
import org.eclipse.jetty.websocket.server.helper.Hex;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UTF-8 Tests
|
||||||
|
*/
|
||||||
|
@RunWith(AdvancedRunner.class)
|
||||||
|
public class TestABCase6 extends AbstractABCase
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* text message, 1 frame, 0 length
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_1_1() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(WebSocketFrame.text());
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text());
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* text message, 0 length, 3 fragments
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_1_2() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setFin(false));
|
||||||
|
send.add(new WebSocketFrame(OpCode.CONTINUATION).setFin(false));
|
||||||
|
send.add(new WebSocketFrame(OpCode.CONTINUATION).setFin(true));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text());
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* text message, small length, 3 fragments (only middle frame has payload)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_1_3() throws Exception
|
||||||
|
{
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setFin(false));
|
||||||
|
send.add(new WebSocketFrame(OpCode.CONTINUATION).setFin(false).setPayload("middle"));
|
||||||
|
send.add(new WebSocketFrame(OpCode.CONTINUATION).setFin(true));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(WebSocketFrame.text("middle"));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, 1 frame/fragment.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_2_1() throws Exception
|
||||||
|
{
|
||||||
|
String utf8 = "Hello-\uC2B5@\uC39F\uC3A4\uC3BC\uC3A0\uC3A1-UTF-8!!";
|
||||||
|
byte msg[] = StringUtil.getUtf8Bytes(utf8);
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, 2 fragments (on UTF8 code point boundary)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_2_2() throws Exception
|
||||||
|
{
|
||||||
|
String utf8[] =
|
||||||
|
{ "Hello-\uC2B5@\uC39F\uC3A4", "\uC3BC\uC3A0\uC3A1-UTF-8!!" };
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(utf8[0]).setFin(false));
|
||||||
|
send.add(new WebSocketFrame(OpCode.CONTINUATION).setPayload(utf8[1]).setFin(true));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(utf8[0] + utf8[1]));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, many fragments (1 byte each)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_2_3() throws Exception
|
||||||
|
{
|
||||||
|
String utf8 = "Hello-\uC2B5@\uC39F\uC3A4\uC3BC\uC3A0\uC3A1-UTF-8!!";
|
||||||
|
byte msg[] = StringUtil.getUtf8Bytes(utf8);
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
int len = msg.length;
|
||||||
|
byte opcode = OpCode.TEXT;
|
||||||
|
byte mini[];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
WebSocketFrame frame = new WebSocketFrame(opcode);
|
||||||
|
mini = new byte[1];
|
||||||
|
mini[0] = msg[i];
|
||||||
|
frame.setPayload(mini);
|
||||||
|
frame.setFin(!(i < (len - 1)));
|
||||||
|
send.add(frame);
|
||||||
|
}
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, many fragments (1 byte each)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_2_4() throws Exception
|
||||||
|
{
|
||||||
|
byte msg[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
int len = msg.length;
|
||||||
|
byte opcode = OpCode.TEXT;
|
||||||
|
byte mini[];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
WebSocketFrame frame = new WebSocketFrame(opcode);
|
||||||
|
mini = new byte[1];
|
||||||
|
mini[0] = msg[i];
|
||||||
|
frame.setPayload(mini);
|
||||||
|
frame.setFin(!(i < (len - 1)));
|
||||||
|
send.add(frame);
|
||||||
|
}
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid utf8 text message, 1 frame/fragments
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_3_1() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5EDA080656469746564");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(invalid));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid utf8 text message, many fragments (1 byte each)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_3_2() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5EDA080656469746564");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
int len = invalid.length;
|
||||||
|
byte opcode = OpCode.TEXT;
|
||||||
|
byte mini[];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
WebSocketFrame frame = new WebSocketFrame(opcode);
|
||||||
|
mini = new byte[1];
|
||||||
|
mini[0] = invalid[i];
|
||||||
|
frame.setPayload(mini);
|
||||||
|
frame.setFin(!(i < (len - 1)));
|
||||||
|
send.add(frame);
|
||||||
|
}
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid text message, 3 fragments.
|
||||||
|
* <p>
|
||||||
|
* fragment #1 and fragment #3 are both valid in themselves.
|
||||||
|
* <p>
|
||||||
|
* fragment #2 contains the invalid utf8 code point.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Slow
|
||||||
|
public void testCase6_4_1() throws Exception
|
||||||
|
{
|
||||||
|
byte part1[] = StringUtil.getUtf8Bytes("\u03BA\u1F79\u03C3\u03BC\u03B5");
|
||||||
|
byte part2[] = Hex.asByteArray("F4908080"); // invalid
|
||||||
|
byte part3[] = StringUtil.getUtf8Bytes("edited");
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
|
||||||
|
fuzzer.send(new WebSocketFrame(OpCode.TEXT).setPayload(part1).setFin(false));
|
||||||
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
fuzzer.send(new WebSocketFrame(OpCode.CONTINUATION).setPayload(part2).setFin(false));
|
||||||
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
fuzzer.send(new WebSocketFrame(OpCode.CONTINUATION).setPayload(part3).setFin(true));
|
||||||
|
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid text message, 3 fragments.
|
||||||
|
* <p>
|
||||||
|
* fragment #1 is valid and ends in the middle of an incomplete code point.
|
||||||
|
* <p>
|
||||||
|
* fragment #2 finishes the UTF8 code point but it is invalid
|
||||||
|
* <p>
|
||||||
|
* fragment #3 contains the remainder of the message.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Slow
|
||||||
|
public void testCase6_4_2() throws Exception
|
||||||
|
{
|
||||||
|
byte part1[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5F4"); // split code point
|
||||||
|
byte part2[] = Hex.asByteArray("90"); // continue code point & invalid
|
||||||
|
byte part3[] = Hex.asByteArray("8080656469746564"); // continue code point & finish
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(new WebSocketFrame(OpCode.TEXT).setPayload(part1).setFin(false));
|
||||||
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
fuzzer.send(new WebSocketFrame(OpCode.CONTINUATION).setPayload(part2).setFin(false));
|
||||||
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
fuzzer.send(new WebSocketFrame(OpCode.CONTINUATION).setPayload(part3).setFin(true));
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid text message, 1 frame/fragment (slowly, and split within code points)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Slow
|
||||||
|
public void testCase6_4_3() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5F49080808080656469746564");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(invalid));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
|
||||||
|
ByteBuffer net = fuzzer.asNetworkBuffer(send);
|
||||||
|
fuzzer.send(net,6);
|
||||||
|
fuzzer.send(net,11);
|
||||||
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
fuzzer.send(net,4);
|
||||||
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
fuzzer.send(net,100); // the rest
|
||||||
|
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid text message, 1 frame/fragment (slowly, and split within code points)
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Slow
|
||||||
|
public void testCase6_4_4() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5F49080808080656469746564");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(invalid));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
|
||||||
|
ByteBuffer net = fuzzer.asNetworkBuffer(send);
|
||||||
|
fuzzer.send(net,6);
|
||||||
|
fuzzer.send(net,11);
|
||||||
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
fuzzer.send(net,1);
|
||||||
|
TimeUnit.SECONDS.sleep(1);
|
||||||
|
fuzzer.send(net,100); // the rest
|
||||||
|
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, 1 frame/fragment.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_5_1() throws Exception
|
||||||
|
{
|
||||||
|
byte msg[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid utf8 (incomplete code point) text message, 1 frame/fragment.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_1() throws Exception
|
||||||
|
{
|
||||||
|
byte incomplete[] = Hex.asByteArray("CE");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(incomplete));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid utf8 text message, 1 frame/fragment, 4 valid code points + 1 partial code point
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_10() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCE");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(invalid));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, 1 frame/fragment, 5 valid code points (preserved on echo).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_11() throws Exception
|
||||||
|
{
|
||||||
|
byte msg[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, 1 frame/fragment, 1 valid code point (preserved on echo).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_2() throws Exception
|
||||||
|
{
|
||||||
|
byte msg[] = Hex.asByteArray("CEBA");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid utf8 text message, 1 frame/fragment, 1 valid code point + 1 partial code point
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_3() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(invalid));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid utf8 text message, 1 frame/fragment, 1 valid code point + 1 invalid code point
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_4() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1BD");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(invalid));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, 1 frame/fragment, 2 valid code points (preserved on echo).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_5() throws Exception
|
||||||
|
{
|
||||||
|
byte msg[] = Hex.asByteArray("CEBAE1BDB9");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid utf8 text message, 1 frame/fragment, 2 valid code points + 1 partial code point
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_6() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(invalid));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, 1 frame/fragment, 3 valid code points (preserved on echo).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_7() throws Exception
|
||||||
|
{
|
||||||
|
byte msg[] = Hex.asByteArray("CEBAE1BDB9CF83");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* invalid utf8 text message, 1 frame/fragment, 3 valid code points + 1 partial code point
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_8() throws Exception
|
||||||
|
{
|
||||||
|
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CE");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(invalid));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new CloseInfo(StatusCode.BAD_PAYLOAD).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* valid utf8 text message, 1 frame/fragment, 4 valid code points (preserved on echo).
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testCase6_6_9() throws Exception
|
||||||
|
{
|
||||||
|
byte msg[] = Hex.asByteArray("CEBAE1BDB9CF83CEBC");
|
||||||
|
|
||||||
|
List<WebSocketFrame> send = new ArrayList<>();
|
||||||
|
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
send.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
List<WebSocketFrame> expect = new ArrayList<>();
|
||||||
|
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||||
|
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||||
|
|
||||||
|
Fuzzer fuzzer = new Fuzzer(this);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
fuzzer.connect();
|
||||||
|
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||||
|
fuzzer.send(send);
|
||||||
|
fuzzer.expect(expect);
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
fuzzer.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -118,7 +118,7 @@ public class TestABCase7_9
|
|||||||
BufferUtil.clearToFill(buf);
|
BufferUtil.clearToFill(buf);
|
||||||
|
|
||||||
// Create Close Frame manually, as we are testing the server's behavior of a bad client.
|
// Create Close Frame manually, as we are testing the server's behavior of a bad client.
|
||||||
buf.put((byte)(0x80 | OpCode.CLOSE.getCode()));
|
buf.put((byte)(0x80 | OpCode.CLOSE));
|
||||||
buf.put((byte)(0x80 | 2));
|
buf.put((byte)(0x80 | 2));
|
||||||
byte mask[] = new byte[]
|
byte mask[] = new byte[]
|
||||||
{ 0x44, 0x44, 0x44, 0x44 };
|
{ 0x44, 0x44, 0x44, 0x44 };
|
||||||
@ -159,7 +159,7 @@ public class TestABCase7_9
|
|||||||
BufferUtil.clearToFill(buf);
|
BufferUtil.clearToFill(buf);
|
||||||
|
|
||||||
// Create Close Frame manually, as we are testing the server's behavior of a bad client.
|
// Create Close Frame manually, as we are testing the server's behavior of a bad client.
|
||||||
buf.put((byte)(0x80 | OpCode.CLOSE.getCode()));
|
buf.put((byte)(0x80 | OpCode.CLOSE));
|
||||||
buf.put((byte)(0x80 | (2 + reason.length())));
|
buf.put((byte)(0x80 | (2 + reason.length())));
|
||||||
byte mask[] = new byte[]
|
byte mask[] = new byte[]
|
||||||
{ 0x44, 0x44, 0x44, 0x44 };
|
{ 0x44, 0x44, 0x44, 0x44 };
|
||||||
|
@ -174,13 +174,16 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames
|
|||||||
LOG.debug("disconnect");
|
LOG.debug("disconnect");
|
||||||
IO.close(in);
|
IO.close(in);
|
||||||
IO.close(out);
|
IO.close(out);
|
||||||
try
|
if (socket != null)
|
||||||
{
|
{
|
||||||
socket.close();
|
try
|
||||||
}
|
{
|
||||||
catch (IOException ignore)
|
socket.close();
|
||||||
{
|
}
|
||||||
/* ignore */
|
catch (IOException ignore)
|
||||||
|
{
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,6 +321,11 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames
|
|||||||
incomingFrameQueue.incoming(copy);
|
incomingFrameQueue.incoming(copy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isConnected()
|
||||||
|
{
|
||||||
|
return (socket != null) && (socket.isConnected());
|
||||||
|
}
|
||||||
|
|
||||||
public void lookFor(String string) throws IOException
|
public void lookFor(String string) throws IOException
|
||||||
{
|
{
|
||||||
String orig = string;
|
String orig = string;
|
||||||
@ -542,9 +550,26 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames
|
|||||||
BufferUtil.writeTo(buf,out);
|
BufferUtil.writeTo(buf,out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeRaw(ByteBuffer buf, int numBytes) throws IOException
|
||||||
|
{
|
||||||
|
int len = Math.min(numBytes,buf.remaining());
|
||||||
|
byte arr[] = new byte[len];
|
||||||
|
buf.get(arr,0,len);
|
||||||
|
out.write(arr);
|
||||||
|
}
|
||||||
|
|
||||||
public void writeRaw(String str) throws IOException
|
public void writeRaw(String str) throws IOException
|
||||||
{
|
{
|
||||||
LOG.debug("write((String)[{}]){}{})",str.length(),'\n',str);
|
LOG.debug("write((String)[{}]){}{})",str.length(),'\n',str);
|
||||||
out.write(StringUtil.getBytes(str,StringUtil.__ISO_8859_1));
|
out.write(StringUtil.getBytes(str,StringUtil.__ISO_8859_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void writeRawSlowly(ByteBuffer buf, int segmentSize) throws IOException
|
||||||
|
{
|
||||||
|
while (buf.remaining() > 0)
|
||||||
|
{
|
||||||
|
writeRaw(buf,segmentSize);
|
||||||
|
flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,6 +25,7 @@ import org.eclipse.jetty.websocket.annotations.OnWebSocketFrame;
|
|||||||
import org.eclipse.jetty.websocket.annotations.WebSocket;
|
import org.eclipse.jetty.websocket.annotations.WebSocket;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketConnection;
|
import org.eclipse.jetty.websocket.api.WebSocketConnection;
|
||||||
import org.eclipse.jetty.websocket.protocol.Frame;
|
import org.eclipse.jetty.websocket.protocol.Frame;
|
||||||
|
import org.eclipse.jetty.websocket.protocol.OpCode;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Echo back the incoming text or binary as 2 frames of (roughly) equal size.
|
* Echo back the incoming text or binary as 2 frames of (roughly) equal size.
|
||||||
@ -35,7 +36,7 @@ public class EchoFragmentSocket
|
|||||||
@OnWebSocketFrame
|
@OnWebSocketFrame
|
||||||
public void onFrame(WebSocketConnection conn, Frame frame)
|
public void onFrame(WebSocketConnection conn, Frame frame)
|
||||||
{
|
{
|
||||||
if (!frame.getOpCode().isDataFrame())
|
if (!OpCode.isDataFrame(frame.getOpCode()))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -55,11 +56,11 @@ public class EchoFragmentSocket
|
|||||||
{
|
{
|
||||||
switch (frame.getOpCode())
|
switch (frame.getOpCode())
|
||||||
{
|
{
|
||||||
case BINARY:
|
case OpCode.BINARY:
|
||||||
conn.write(null,nop,buf1);
|
conn.write(null,nop,buf1);
|
||||||
conn.write(null,nop,buf2);
|
conn.write(null,nop,buf2);
|
||||||
break;
|
break;
|
||||||
case TEXT:
|
case OpCode.TEXT:
|
||||||
// NOTE: This impl is not smart enough to split on a UTF8 boundary
|
// NOTE: This impl is not smart enough to split on a UTF8 boundary
|
||||||
conn.write(null,nop,BufferUtil.toUTF8String(buf1));
|
conn.write(null,nop,BufferUtil.toUTF8String(buf1));
|
||||||
conn.write(null,nop,BufferUtil.toUTF8String(buf2));
|
conn.write(null,nop,BufferUtil.toUTF8String(buf2));
|
||||||
|
@ -0,0 +1,60 @@
|
|||||||
|
//========================================================================
|
||||||
|
//Copyright 2011-2012 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.server.helper;
|
||||||
|
|
||||||
|
public final class Hex
|
||||||
|
{
|
||||||
|
private static final char[] hexcodes = "0123456789ABCDEF".toCharArray();
|
||||||
|
|
||||||
|
public static byte[] asByteArray(String hstr)
|
||||||
|
{
|
||||||
|
if ((hstr.length() < 0) || ((hstr.length() % 2) != 0))
|
||||||
|
{
|
||||||
|
throw new IllegalArgumentException(String.format("Invalid string length of <%d>",hstr.length()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int size = hstr.length() / 2;
|
||||||
|
byte buf[] = new byte[size];
|
||||||
|
byte hex;
|
||||||
|
int len = hstr.length();
|
||||||
|
|
||||||
|
int idx = (int)Math.floor(((size * 2) - (double)len) / 2);
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
hex = 0;
|
||||||
|
if (i >= 0)
|
||||||
|
{
|
||||||
|
hex = (byte)(Character.digit(hstr.charAt(i),16) << 4);
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
hex += (byte)(Character.digit(hstr.charAt(i),16));
|
||||||
|
|
||||||
|
buf[idx] = hex;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String asHex(byte buf[])
|
||||||
|
{
|
||||||
|
int len = buf.length;
|
||||||
|
char out[] = new char[len * 2];
|
||||||
|
for (int i = 0; i < len; i++)
|
||||||
|
{
|
||||||
|
out[i * 2] = hexcodes[(buf[i] & 0xF0) >> 4];
|
||||||
|
out[(i * 2) + 1] = hexcodes[(buf[i] & 0x0F)];
|
||||||
|
}
|
||||||
|
return String.valueOf(out);
|
||||||
|
}
|
||||||
|
}
|
@ -49,14 +49,14 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||||||
Assert.assertThat(errorType.getSimpleName(),getErrorCount(errorType),is(expectedCount));
|
Assert.assertThat(errorType.getSimpleName(),getErrorCount(errorType),is(expectedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasFrame(OpCode op)
|
public void assertHasFrame(byte op)
|
||||||
{
|
{
|
||||||
Assert.assertThat(op.name(),getFrameCount(op),greaterThanOrEqualTo(1));
|
Assert.assertThat(OpCode.name(op),getFrameCount(op),greaterThanOrEqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasFrame(OpCode op, int expectedCount)
|
public void assertHasFrame(byte op, int expectedCount)
|
||||||
{
|
{
|
||||||
Assert.assertThat(op.name(),getFrameCount(op),is(expectedCount));
|
Assert.assertThat(OpCode.name(op),getFrameCount(op),is(expectedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasNoFrames()
|
public void assertHasNoFrames()
|
||||||
@ -98,7 +98,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFrameCount(OpCode op)
|
public int getFrameCount(byte op)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (WebSocketFrame frame : frames)
|
for (WebSocketFrame frame : frames)
|
||||||
|
@ -42,14 +42,14 @@ public class OutgoingFramesCapture implements OutgoingFrames
|
|||||||
Assert.assertThat("Captured frame count",writes.size(),is(expectedCount));
|
Assert.assertThat("Captured frame count",writes.size(),is(expectedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasFrame(OpCode op)
|
public void assertHasFrame(byte op)
|
||||||
{
|
{
|
||||||
Assert.assertThat(op.name(),getFrameCount(op),greaterThanOrEqualTo(1));
|
Assert.assertThat(OpCode.name(op),getFrameCount(op),greaterThanOrEqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasFrame(OpCode op, int expectedCount)
|
public void assertHasFrame(byte op, int expectedCount)
|
||||||
{
|
{
|
||||||
Assert.assertThat(op.name(),getFrameCount(op),is(expectedCount));
|
Assert.assertThat(OpCode.name(op),getFrameCount(op),is(expectedCount));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void assertHasNoFrames()
|
public void assertHasNoFrames()
|
||||||
@ -68,7 +68,7 @@ public class OutgoingFramesCapture implements OutgoingFrames
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getFrameCount(OpCode op)
|
public int getFrameCount(byte op)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
for (Write<?> write : writes)
|
for (Write<?> write : writes)
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||||
org.eclipse.jetty.io.LEVEL=WARN
|
org.eclipse.jetty.LEVEL=WARN
|
||||||
org.eclipse.jetty.server.LEVEL=WARN
|
org.eclipse.jetty.server.LEVEL=WARN
|
||||||
# org.eclipse.jetty.websocket.LEVEL=WARN
|
# org.eclipse.jetty.websocket.LEVEL=WARN
|
||||||
org.eclipse.jetty.websocket.server.helper.RFCSocket.LEVEL=OFF
|
org.eclipse.jetty.websocket.server.helper.RFCSocket.LEVEL=OFF
|
||||||
# See the read/write traffic
|
# See the read/write traffic
|
||||||
org.eclipse.jetty.websocket.io.Frames.LEVEL=DEBUG
|
# org.eclipse.jetty.websocket.io.Frames.LEVEL=DEBUG
|
||||||
# org.eclipse.jetty.websocket.io.LEVEL=DEBUG
|
# org.eclipse.jetty.websocket.io.LEVEL=DEBUG
|
||||||
# org.eclipse.jetty.websocket.io.WebSocketAsyncConnection.LEVEL=DEBUG
|
# org.eclipse.jetty.websocket.io.WebSocketAsyncConnection.LEVEL=DEBUG
|
||||||
# org.eclipse.jetty.util.thread.QueuedThreadPool.LEVEL=DEBUG
|
# org.eclipse.jetty.util.thread.QueuedThreadPool.LEVEL=DEBUG
|
||||||
# org.eclipse.jetty.io.SelectorManager.LEVEL=INFO
|
# org.eclipse.jetty.io.SelectorManager.LEVEL=INFO
|
||||||
org.eclipse.jetty.websocket.LEVEL=DEBUG
|
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||||
# org.eclipse.jetty.websocket.driver.WebSocketEventDriver.LEVEL=DEBUG
|
# org.eclipse.jetty.websocket.driver.WebSocketEventDriver.LEVEL=DEBUG
|
||||||
# org.eclipse.jetty.websocket.extensions.LEVEL=DEBUG
|
# org.eclipse.jetty.websocket.extensions.LEVEL=DEBUG
|
||||||
# org.eclipse.jetty.websocket.protocol.Generator.LEVEL=INFO
|
# org.eclipse.jetty.websocket.protocol.Generator.LEVEL=INFO
|
||||||
|
Loading…
x
Reference in New Issue
Block a user