Cleaning up close handshake and noisy tests
This commit is contained in:
parent
4f7c66ae81
commit
3e2aee293e
|
@ -18,10 +18,13 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer.ServerConnection;
|
||||
import org.eclipse.jetty.websocket.core.api.StatusCode;
|
||||
|
@ -32,16 +35,18 @@ import org.junit.After;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
/**
|
||||
* Tests for conditions due to bad networking.
|
||||
*/
|
||||
@Ignore("Not working yet")
|
||||
public class BadNetworkTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private WebSocketClientFactory factory;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import java.util.concurrent.Future;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.FutureCallback;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer.ServerConnection;
|
||||
|
@ -34,6 +35,7 @@ import org.junit.After;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -41,6 +43,9 @@ import org.junit.Test;
|
|||
*/
|
||||
public class ClientConnectTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private WebSocketClientFactory factory;
|
||||
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer.ServerConnection;
|
||||
|
@ -30,12 +33,14 @@ import org.eclipse.jetty.websocket.core.api.UpgradeResponse;
|
|||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class SlowClientTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private WebSocketClientFactory factory;
|
||||
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.toolchain.test.annotation.Slow;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer.ServerConnection;
|
||||
|
@ -30,12 +33,14 @@ import org.eclipse.jetty.websocket.core.api.UpgradeResponse;
|
|||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class SlowServerTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private WebSocketClientFactory factory;
|
||||
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.client.blockhead.BlockheadServer.ServerConnection;
|
||||
import org.eclipse.jetty.websocket.core.api.StatusCode;
|
||||
|
@ -30,16 +33,18 @@ import org.junit.After;
|
|||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.lessThanOrEqualTo;
|
||||
|
||||
/**
|
||||
* Various tests for Timeout handling
|
||||
*/
|
||||
@Ignore("Idle timeouts not working yet")
|
||||
public class TimeoutTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private WebSocketClientFactory factory;
|
||||
|
||||
|
|
|
@ -23,9 +23,11 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
@ -54,6 +56,9 @@ public class WebSocketClientBadUriTest
|
|||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private WebSocketClientFactory factory;
|
||||
private final String uriStr;
|
||||
private final URI uri;
|
||||
|
|
|
@ -18,15 +18,18 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class WebSocketClientFactoryTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
@Test
|
||||
public void testNewSocket()
|
||||
{
|
||||
|
|
|
@ -18,17 +18,22 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client.internal;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class ConnectionManagerTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private void assertToSocketAddress(String uriStr, String expectedHost, int expectedPort) throws URISyntaxException
|
||||
{
|
||||
URI uri = new URI(uriStr);
|
||||
|
|
|
@ -18,22 +18,25 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client.internal.io;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.websocket.core.api.UpgradeResponse;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
|
||||
public class HttpResponseHeaderParserTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private void appendUtf8(ByteBuffer buf, String line)
|
||||
{
|
||||
buf.put(ByteBuffer.wrap(StringUtil.getBytes(line,StringUtil.__UTF8)));
|
||||
|
|
|
@ -20,23 +20,14 @@ package org.eclipse.jetty.websocket.core.api;
|
|||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import org.eclipse.jetty.websocket.core.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.core.protocol.ConnectionState;
|
||||
|
||||
/**
|
||||
* Base Connection concepts
|
||||
*/
|
||||
public interface BaseConnection
|
||||
{
|
||||
public static enum State
|
||||
{
|
||||
/** Connection created, but not yet connected */
|
||||
OPENING,
|
||||
/** Connection created and connected */
|
||||
OPENED,
|
||||
/** Close handshake initiated, response pending. */
|
||||
CLOSING,
|
||||
/** Close handshake responded. */
|
||||
CLOSED
|
||||
}
|
||||
|
||||
/**
|
||||
* Connection suspend token
|
||||
*/
|
||||
|
@ -49,7 +40,7 @@ public interface BaseConnection
|
|||
}
|
||||
|
||||
/**
|
||||
* Send a websocket Close frame, {@link StatusCode#NORMAL}, without a reason.
|
||||
* Send a websocket Close frame, without a status code or reason.
|
||||
* <p>
|
||||
* Basic usage: results in an non-blocking async write, then connection close.
|
||||
*
|
||||
|
@ -84,11 +75,18 @@ public interface BaseConnection
|
|||
InetSocketAddress getRemoteAddress();
|
||||
|
||||
/**
|
||||
* Get the state of the connection.
|
||||
* Get the WebSocket connection State.
|
||||
*
|
||||
* @return the state of the connection.
|
||||
* @return the connection state.
|
||||
*/
|
||||
State getState();
|
||||
ConnectionState getState();
|
||||
|
||||
/**
|
||||
* Test if input is closed (as a result of receiving a close frame)
|
||||
*
|
||||
* @return true if input is closed.
|
||||
*/
|
||||
boolean isInputClosed();
|
||||
|
||||
/**
|
||||
* Simple test to see if connection is open (and not closed)
|
||||
|
@ -97,6 +95,13 @@ public interface BaseConnection
|
|||
*/
|
||||
boolean isOpen();
|
||||
|
||||
/**
|
||||
* Test if output is closed (as a result of sending a close frame)
|
||||
*
|
||||
* @return true if output is closed.
|
||||
*/
|
||||
boolean isOutputClosed();
|
||||
|
||||
/**
|
||||
* Tests if the connection is actively reading.
|
||||
*
|
||||
|
@ -105,9 +110,14 @@ public interface BaseConnection
|
|||
boolean isReading();
|
||||
|
||||
/**
|
||||
* Notify that the connection has entered the closing handshake
|
||||
* A close handshake frame has been detected
|
||||
*
|
||||
* @param incoming
|
||||
* true if part of an incoming frame, false if part of an outgoing frame.
|
||||
* @param close
|
||||
* the close details
|
||||
*/
|
||||
void notifyClosing();
|
||||
void onCloseHandshake(boolean incoming, CloseInfo close);
|
||||
|
||||
/**
|
||||
* Suspend a the incoming read events on the connection.
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.eclipse.jetty.websocket.core.api.StatusCode;
|
|||
import org.eclipse.jetty.websocket.core.api.WebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.core.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.core.protocol.ConnectionState;
|
||||
import org.eclipse.jetty.websocket.core.protocol.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.core.protocol.Generator;
|
||||
import org.eclipse.jetty.websocket.core.protocol.OpCode;
|
||||
|
@ -68,7 +69,9 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
private List<ExtensionConfig> extensions;
|
||||
private boolean flushing;
|
||||
private boolean isFilling;
|
||||
private BaseConnection.State connectionState;
|
||||
private ConnectionState connectionState;
|
||||
private final AtomicBoolean inputClosed;
|
||||
private final AtomicBoolean outputClosed;
|
||||
|
||||
public AbstractWebSocketConnection(EndPoint endp, Executor executor, Scheduler scheduler, WebSocketPolicy policy, ByteBufferPool bufferPool)
|
||||
{
|
||||
|
@ -81,7 +84,10 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
this.extensions = new ArrayList<>();
|
||||
this.queue = new FrameQueue();
|
||||
this.suspendToken = new AtomicBoolean(false);
|
||||
this.connectionState = BaseConnection.State.OPENING;
|
||||
this.connectionState = ConnectionState.CONNECTING;
|
||||
|
||||
this.inputClosed = new AtomicBoolean(false);
|
||||
this.outputClosed = new AtomicBoolean(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -116,7 +122,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
|
||||
public void disconnect(boolean onlyOutput)
|
||||
{
|
||||
connectionState = BaseConnection.State.CLOSED;
|
||||
connectionState = ConnectionState.CLOSED;
|
||||
EndPoint endPoint = getEndPoint();
|
||||
// We need to gently close first, to allow
|
||||
// SSL close alerts to be sent by Jetty
|
||||
|
@ -183,7 +189,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
LOG.debug("Flushing {}, {} frame(s) in queue",frameBytes,queue.size());
|
||||
}
|
||||
|
||||
if (connectionState != BaseConnection.State.CLOSED)
|
||||
if (connectionState != ConnectionState.CLOSED)
|
||||
{
|
||||
write(buffer,frameBytes);
|
||||
}
|
||||
|
@ -244,15 +250,27 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
}
|
||||
|
||||
@Override
|
||||
public BaseConnection.State getState()
|
||||
public ConnectionState getState()
|
||||
{
|
||||
return connectionState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInputClosed()
|
||||
{
|
||||
return inputClosed.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return (getState() != BaseConnection.State.CLOSED) && getEndPoint().isOpen();
|
||||
return (getState() != ConnectionState.CLOSED) && getEndPoint().isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutputClosed()
|
||||
{
|
||||
return outputClosed.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -261,17 +279,42 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
return isFilling;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyClosing()
|
||||
{
|
||||
this.connectionState = BaseConnection.State.CLOSING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
super.onClose();
|
||||
this.connectionState = BaseConnection.State.CLOSED;
|
||||
this.connectionState = ConnectionState.CLOSED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseHandshake(boolean incoming, CloseInfo close)
|
||||
{
|
||||
boolean in = inputClosed.get();
|
||||
boolean out = outputClosed.get();
|
||||
if (incoming)
|
||||
{
|
||||
in = true;
|
||||
this.inputClosed.set(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
out = true;
|
||||
this.outputClosed.set(true);
|
||||
}
|
||||
|
||||
LOG.debug("onCloseHandshake({},{}), input={}, output={}",incoming,close,in,out);
|
||||
|
||||
if (in && out)
|
||||
{
|
||||
LOG.debug("Close Handshake satisfied, disconnecting");
|
||||
this.disconnect(false);
|
||||
}
|
||||
|
||||
if (close.isHarsh())
|
||||
{
|
||||
LOG.debug("Close status code was harsh, disconnecting");
|
||||
this.disconnect(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -305,7 +348,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
this.connectionState = BaseConnection.State.OPENED;
|
||||
this.connectionState = ConnectionState.OPEN;
|
||||
LOG.debug("fillInterested");
|
||||
fillInterested();
|
||||
}
|
||||
|
@ -449,7 +492,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
LOG_FRAMES.debug("{} Writing {} frame bytes of {}",policy.getBehavior(),buffer.remaining(),frameBytes);
|
||||
}
|
||||
|
||||
if (connectionState == BaseConnection.State.CLOSED)
|
||||
if (connectionState == ConnectionState.CLOSED)
|
||||
{
|
||||
// connection is closed, STOP WRITING, geez.
|
||||
return;
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.nio.ByteBuffer;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.core.api.BaseConnection;
|
||||
import org.eclipse.jetty.websocket.core.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.core.protocol.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.protocol.WebSocketFrame;
|
||||
|
||||
|
@ -31,6 +31,7 @@ public class ControlFrameBytes<C> extends FrameBytes<C>
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(ControlFrameBytes.class);
|
||||
private ByteBuffer buffer;
|
||||
private ByteBuffer origPayload;
|
||||
|
||||
public ControlFrameBytes(AbstractWebSocketConnection connection, Callback<C> callback, C context, WebSocketFrame frame)
|
||||
{
|
||||
|
@ -46,22 +47,11 @@ public class ControlFrameBytes<C> extends FrameBytes<C>
|
|||
|
||||
if (frame.getOpCode() == OpCode.CLOSE)
|
||||
{
|
||||
// is this outgoing close frame a response to a close?
|
||||
if (connection.getState() == BaseConnection.State.CLOSING)
|
||||
{
|
||||
// Disconnect the connection (no more packets/frames)
|
||||
connection.disconnect(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Then this is the initiator for a close handshake.
|
||||
connection.notifyClosing();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
connection.flush();
|
||||
CloseInfo close = new CloseInfo(origPayload,false);
|
||||
connection.onCloseHandshake(false,close);
|
||||
}
|
||||
|
||||
connection.flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -69,6 +59,10 @@ public class ControlFrameBytes<C> extends FrameBytes<C>
|
|||
{
|
||||
if (buffer == null)
|
||||
{
|
||||
if (frame.hasPayload())
|
||||
{
|
||||
origPayload = frame.getPayload().slice();
|
||||
}
|
||||
buffer = connection.getGenerator().generate(frame);
|
||||
}
|
||||
return buffer;
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.eclipse.jetty.websocket.core.api.WebSocketConnection;
|
|||
import org.eclipse.jetty.websocket.core.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.core.io.event.EventDriver;
|
||||
import org.eclipse.jetty.websocket.core.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.core.protocol.ConnectionState;
|
||||
import org.eclipse.jetty.websocket.core.protocol.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.protocol.WebSocketFrame;
|
||||
|
||||
|
@ -99,7 +101,7 @@ public class WebSocketSession implements WebSocketConnection, IncomingFrames, Ou
|
|||
}
|
||||
|
||||
@Override
|
||||
public BaseConnection.State getState()
|
||||
public ConnectionState getState()
|
||||
{
|
||||
return baseConnection.getState();
|
||||
}
|
||||
|
@ -113,6 +115,10 @@ public class WebSocketSession implements WebSocketConnection, IncomingFrames, Ou
|
|||
@Override
|
||||
public void incoming(WebSocketException e)
|
||||
{
|
||||
if (baseConnection.isInputClosed())
|
||||
{
|
||||
return; // input is closed
|
||||
}
|
||||
// pass on incoming to websocket itself
|
||||
websocket.incoming(e);
|
||||
}
|
||||
|
@ -120,16 +126,32 @@ public class WebSocketSession implements WebSocketConnection, IncomingFrames, Ou
|
|||
@Override
|
||||
public void incoming(WebSocketFrame frame)
|
||||
{
|
||||
if (baseConnection.isInputClosed())
|
||||
{
|
||||
return; // input is closed
|
||||
}
|
||||
// pass on incoming to websocket itself
|
||||
websocket.incoming(frame);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInputClosed()
|
||||
{
|
||||
return baseConnection.isInputClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return baseConnection.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutputClosed()
|
||||
{
|
||||
return baseConnection.isOutputClosed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReading()
|
||||
{
|
||||
|
@ -137,9 +159,9 @@ public class WebSocketSession implements WebSocketConnection, IncomingFrames, Ou
|
|||
}
|
||||
|
||||
@Override
|
||||
public void notifyClosing()
|
||||
public void onCloseHandshake(boolean incoming, CloseInfo close)
|
||||
{
|
||||
baseConnection.notifyClosing();
|
||||
baseConnection.onCloseHandshake(incoming,close);
|
||||
}
|
||||
|
||||
public void onConnect()
|
||||
|
@ -206,6 +228,10 @@ public class WebSocketSession implements WebSocketConnection, IncomingFrames, Ou
|
|||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, byte[] buf, int offset, int len) throws IOException
|
||||
{
|
||||
if (baseConnection.isOutputClosed())
|
||||
{
|
||||
return; // output is closed
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("write(context,{},byte[],{},{})",callback,offset,len);
|
||||
|
@ -223,6 +249,10 @@ public class WebSocketSession implements WebSocketConnection, IncomingFrames, Ou
|
|||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, ByteBuffer buffer) throws IOException
|
||||
{
|
||||
if (baseConnection.isOutputClosed())
|
||||
{
|
||||
return; // output is closed
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("write(context,{},ByteBuffer->{})",callback,BufferUtil.toDetailString(buffer));
|
||||
|
@ -240,6 +270,10 @@ public class WebSocketSession implements WebSocketConnection, IncomingFrames, Ou
|
|||
@Override
|
||||
public <C> void write(C context, Callback<C> callback, String message) throws IOException
|
||||
{
|
||||
if (baseConnection.isOutputClosed())
|
||||
{
|
||||
return; // output is closed
|
||||
}
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("write(context,{},message.length:{})",callback,message.length());
|
||||
|
|
|
@ -27,7 +27,6 @@ import org.eclipse.jetty.util.StringUtil;
|
|||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.core.api.BaseConnection;
|
||||
import org.eclipse.jetty.websocket.core.api.CloseException;
|
||||
import org.eclipse.jetty.websocket.core.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketException;
|
||||
|
@ -70,7 +69,7 @@ public abstract class EventDriver implements IncomingFrames
|
|||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("incoming({})",e);
|
||||
LOG.debug("incoming(WebSocketException)",e);
|
||||
}
|
||||
|
||||
if (e instanceof CloseException)
|
||||
|
@ -100,22 +99,16 @@ public abstract class EventDriver implements IncomingFrames
|
|||
{
|
||||
boolean validate = true;
|
||||
CloseInfo close = new CloseInfo(frame,validate);
|
||||
|
||||
// notify user websocket pojo
|
||||
onClose(close);
|
||||
|
||||
// Is this close frame a response to a prior close?
|
||||
if (session.getState() == BaseConnection.State.CLOSING)
|
||||
{
|
||||
// Then this is close response handshake (to a prior
|
||||
// outgoing close frame)
|
||||
session.disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is the initiator for a close handshake
|
||||
// Trigger close response handshake.
|
||||
session.notifyClosing();
|
||||
session.close(close.getStatusCode(),close.getReason());
|
||||
}
|
||||
// respond
|
||||
session.close(close.getStatusCode(),close.getReason());
|
||||
|
||||
// process handshake
|
||||
session.onCloseHandshake(true,close);
|
||||
|
||||
return;
|
||||
}
|
||||
case OpCode.PING:
|
||||
|
|
|
@ -164,4 +164,15 @@ public class CloseInfo
|
|||
{
|
||||
return statusCode;
|
||||
}
|
||||
|
||||
public boolean isHarsh()
|
||||
{
|
||||
return !((statusCode == StatusCode.NORMAL) || (statusCode == StatusCode.NO_CODE));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("CloseInfo[code=%d,reason=%s]",statusCode,reason);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-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.core.protocol;
|
||||
|
||||
/**
|
||||
* Connection states as outlined in <a href="https://tools.ietf.org/html/rfc6455">RFC6455</a>.
|
||||
*/
|
||||
public enum ConnectionState
|
||||
{
|
||||
CONNECTING,
|
||||
OPEN,
|
||||
CLOSING,
|
||||
CLOSED;
|
||||
}
|
|
@ -201,7 +201,7 @@ public class Parser
|
|||
|
||||
protected void notifyWebSocketException(WebSocketException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
LOG.warn(e);
|
||||
if (incomingFramesHandler == null)
|
||||
{
|
||||
return;
|
||||
|
@ -217,6 +217,8 @@ public class Parser
|
|||
}
|
||||
try
|
||||
{
|
||||
// TODO: create DebugBuffer
|
||||
|
||||
// parse through all the frames in the buffer
|
||||
while (parseFrame(buffer))
|
||||
{
|
||||
|
@ -234,17 +236,16 @@ public class Parser
|
|||
}
|
||||
catch (WebSocketException e)
|
||||
{
|
||||
buffer.position(buffer.limit()); // consume remaining
|
||||
this.payload = null; // reset
|
||||
notifyWebSocketException(e);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
buffer.position(buffer.limit()); // consume remaining
|
||||
this.payload = null; // reset
|
||||
notifyWebSocketException(new WebSocketException(t));
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Be sure to consume after exceptions
|
||||
buffer.position(buffer.limit());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -20,17 +20,38 @@ package org.eclipse.jetty.websocket.core.ab;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.core.protocol.IncomingFramesCapture;
|
||||
import org.eclipse.jetty.websocket.core.protocol.Parser;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestABCase4
|
||||
{
|
||||
WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
|
||||
@BeforeClass
|
||||
public static void disableParserStacks()
|
||||
{
|
||||
enableStacks(Parser.class,false);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void enableParserStacks()
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
}
|
||||
|
||||
private static void enableStacks(Class<?> clazz, boolean enabled)
|
||||
{
|
||||
StdErrLog log = StdErrLog.getLogger(clazz);
|
||||
log.setHideStacks(!enabled);
|
||||
}
|
||||
|
||||
private WebSocketPolicy policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
|
||||
|
||||
@Test
|
||||
public void testParserControlOpCode11Case4_2_1()
|
||||
|
|
|
@ -25,6 +25,8 @@ import java.nio.ByteBuffer;
|
|||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.core.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.core.protocol.ConnectionState;
|
||||
import org.junit.rules.TestName;
|
||||
|
||||
public class LocalWebSocketConnection implements WebSocketConnection
|
||||
|
@ -74,7 +76,7 @@ public class LocalWebSocketConnection implements WebSocketConnection
|
|||
}
|
||||
|
||||
@Override
|
||||
public State getState()
|
||||
public ConnectionState getState()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
@ -85,12 +87,27 @@ public class LocalWebSocketConnection implements WebSocketConnection
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInputClosed()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isOutputClosed()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReading()
|
||||
{
|
||||
|
@ -98,8 +115,9 @@ public class LocalWebSocketConnection implements WebSocketConnection
|
|||
}
|
||||
|
||||
@Override
|
||||
public void notifyClosing()
|
||||
public void onCloseHandshake(boolean incoming, CloseInfo close)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.core.protocol;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -31,15 +33,9 @@ import org.eclipse.jetty.websocket.core.api.BadPayloadException;
|
|||
import org.eclipse.jetty.websocket.core.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.core.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.core.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.core.protocol.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.protocol.Parser;
|
||||
import org.eclipse.jetty.websocket.core.protocol.WebSocketFrame;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
public class ParserTest
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ParserTest.class);
|
||||
|
|
|
@ -168,7 +168,12 @@ public class Fuzzer
|
|||
public void expectNoMoreFrames()
|
||||
{
|
||||
// TODO Should test for no more frames. success if connection closed.
|
||||
}
|
||||
|
||||
public void expectServerClose() throws IOException
|
||||
{
|
||||
int val = client.read();
|
||||
Assert.assertThat("Should have detected EOF",val,is(-1));
|
||||
}
|
||||
|
||||
public SendMode getSendMode()
|
||||
|
@ -236,6 +241,8 @@ public class Fuzzer
|
|||
case SLOW:
|
||||
client.writeRawSlowly(buf,slowSendSegmentSize);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Whoops, unsupported sendMode: " + sendMode);
|
||||
}
|
||||
}
|
||||
else if (sendMode == SendMode.PER_FRAME)
|
||||
|
|
|
@ -24,9 +24,11 @@ import java.util.List;
|
|||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.core.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.core.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.core.protocol.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.protocol.Parser;
|
||||
import org.eclipse.jetty.websocket.core.protocol.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.server.helper.Hex;
|
||||
import org.junit.Test;
|
||||
|
@ -162,14 +164,23 @@ public class TestABCase6_BadUTF extends AbstractABCase
|
|||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
try
|
||||
{
|
||||
enableStacks(Parser.class,false);
|
||||
fuzzer.connect();
|
||||
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expectServerClose();
|
||||
}
|
||||
finally
|
||||
{
|
||||
fuzzer.close();
|
||||
enableStacks(Parser.class,true);
|
||||
}
|
||||
}
|
||||
|
||||
private void enableStacks(Class<?> clazz, boolean enabled)
|
||||
{
|
||||
StdErrLog log = StdErrLog.getLogger(clazz);
|
||||
log.setHideStacks(!enabled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,14 +23,17 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.core.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.core.protocol.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.core.protocol.OpCode;
|
||||
import org.eclipse.jetty.websocket.core.protocol.Parser;
|
||||
import org.eclipse.jetty.websocket.core.protocol.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.server.helper.Hex;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -38,6 +41,15 @@ import org.junit.Test;
|
|||
*/
|
||||
public class TestABCase7 extends AbstractABCase
|
||||
{
|
||||
private static void enableStacks(Class<?> clazz, boolean enabled)
|
||||
{
|
||||
StdErrLog log = StdErrLog.getLogger(clazz);
|
||||
log.setHideStacks(!enabled);
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
/**
|
||||
* Basic message then close frame, normal behavior
|
||||
*/
|
||||
|
@ -183,7 +195,6 @@ public class TestABCase7 extends AbstractABCase
|
|||
* 256k msg, then close, then ping
|
||||
*/
|
||||
@Test
|
||||
@Ignore("Problematic")
|
||||
public void testCase7_1_6() throws Exception
|
||||
{
|
||||
byte msg[] = new byte[256 * 1024];
|
||||
|
@ -195,7 +206,7 @@ public class TestABCase7 extends AbstractABCase
|
|||
send.add(new WebSocketFrame(OpCode.PING).setPayload("out of band"));
|
||||
|
||||
List<WebSocketFrame> expect = new ArrayList<>();
|
||||
send.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||
expect.add(new WebSocketFrame(OpCode.TEXT).setPayload(msg));
|
||||
expect.add(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
|
@ -258,6 +269,7 @@ public class TestABCase7 extends AbstractABCase
|
|||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
try
|
||||
{
|
||||
enableStacks(Parser.class,false);
|
||||
fuzzer.connect();
|
||||
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
|
@ -266,6 +278,7 @@ public class TestABCase7 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
@ -382,6 +395,7 @@ public class TestABCase7 extends AbstractABCase
|
|||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
try
|
||||
{
|
||||
enableStacks(Parser.class,false);
|
||||
fuzzer.connect();
|
||||
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
|
@ -390,12 +404,13 @@ public class TestABCase7 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* close with invalid payload (124 byte reason) (exceeds total allowed control frame payload bytes)
|
||||
* close with invalid UTF8 in payload
|
||||
*/
|
||||
@Test
|
||||
public void testCase7_5_1() throws Exception
|
||||
|
@ -409,8 +424,8 @@ public class TestABCase7 extends AbstractABCase
|
|||
BufferUtil.flipToFlush(payload,0);
|
||||
|
||||
List<WebSocketFrame> send = new ArrayList<>();
|
||||
WebSocketFrame close = new WebSocketFrame();
|
||||
close.setPayload(payload);
|
||||
WebSocketFrame close = new WebSocketFrame(); // anonymous (no opcode) intentionally
|
||||
close.setPayload(payload); // intentionally bad payload
|
||||
close.setOpCode(OpCode.CLOSE); // set opcode after payload (to prevent early bad payload detection)
|
||||
send.add(close);
|
||||
|
||||
|
@ -420,6 +435,7 @@ public class TestABCase7 extends AbstractABCase
|
|||
Fuzzer fuzzer = new Fuzzer(this);
|
||||
try
|
||||
{
|
||||
enableStacks(Parser.class,false);
|
||||
fuzzer.connect();
|
||||
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
|
@ -428,6 +444,7 @@ public class TestABCase7 extends AbstractABCase
|
|||
}
|
||||
finally
|
||||
{
|
||||
enableStacks(Parser.class,true);
|
||||
fuzzer.close();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -371,12 +371,23 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames
|
|||
}
|
||||
}
|
||||
|
||||
public int read() throws IOException
|
||||
{
|
||||
return in.read();
|
||||
}
|
||||
|
||||
public int read(ByteBuffer buf) throws IOException
|
||||
{
|
||||
int len = 0;
|
||||
int b;
|
||||
while ((in.available() > 0) && (buf.remaining() > 0))
|
||||
{
|
||||
buf.put((byte)in.read());
|
||||
b = in.read();
|
||||
if (b == (-1))
|
||||
{
|
||||
throw new EOFException("Hit EOF");
|
||||
}
|
||||
buf.put((byte)b);
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
|
|
|
@ -1,8 +1,5 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.LEVEL=INFO
|
||||
org.eclipse.jetty.STACKS=true
|
||||
org.eclipse.jetty.SOURCE=true
|
||||
# org.eclipse.jetty.LEVEL=INFO
|
||||
org.eclipse.jetty.LEVEL=WARN
|
||||
# org.eclipse.jetty.websocket.LEVEL=WARN
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.io.LEVEL=DEBUG
|
||||
|
@ -21,7 +18,7 @@ org.eclipse.jetty.SOURCE=true
|
|||
# org.eclipse.jetty.websocket.io.Frames.LEVEL=DEBUG
|
||||
|
||||
### Show state changes on BrowserDebugTool
|
||||
#org.eclipse.jetty.websocket.server.browser.LEVEL=DEBUG
|
||||
org.eclipse.jetty.websocket.server.browser.LEVEL=DEBUG
|
||||
|
||||
### Disabling intentional error out of RFCSocket
|
||||
org.eclipse.jetty.websocket.server.helper.RFCSocket.LEVEL=OFF
|
||||
|
|
Loading…
Reference in New Issue