Cleaning up close handshake and noisy tests

This commit is contained in:
Joakim Erdfelt 2012-10-23 12:16:24 -07:00
parent 4f7c66ae81
commit 3e2aee293e
25 changed files with 349 additions and 114 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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()
{

View File

@ -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);

View File

@ -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)));

View File

@ -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.

View File

@ -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;

View File

@ -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;

View File

@ -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());

View File

@ -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:

View File

@ -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);
}
}

View File

@ -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;
}

View File

@ -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());
}
}
/**

View File

@ -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()

View File

@ -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

View File

@ -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);

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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();
}
}

View File

@ -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;

View File

@ -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