Merge branch 'jetty-9.4.x-2282-websocket-test-remove-eventqueue' into jetty-9.4.x
This commit is contained in:
commit
eaefc6a9c2
|
@ -23,7 +23,9 @@ import java.io.IOException;
|
|||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
|
@ -36,19 +38,23 @@ import javax.websocket.OnClose;
|
|||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
@Ignore("Not working atm")
|
||||
|
@ -90,7 +96,7 @@ public class DecoderReaderManySmallTest
|
|||
@ClientEndpoint(decoders = { EventIdDecoder.class })
|
||||
public static class EventIdSocket
|
||||
{
|
||||
public EventQueue<EventId> messageQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<EventId> messageQueue = new LinkedBlockingQueue<>();
|
||||
private CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
|
||||
@OnClose
|
||||
|
@ -102,7 +108,7 @@ public class DecoderReaderManySmallTest
|
|||
@OnMessage
|
||||
public void onMessage(EventId msg)
|
||||
{
|
||||
messageQueue.add(msg);
|
||||
messageQueue.offer(msg);
|
||||
}
|
||||
|
||||
public void awaitClose() throws InterruptedException
|
||||
|
@ -111,63 +117,9 @@ public class DecoderReaderManySmallTest
|
|||
}
|
||||
}
|
||||
|
||||
private static class EventIdServer implements Runnable
|
||||
{
|
||||
private BlockheadServer server;
|
||||
private IBlockheadServerConnection sconnection;
|
||||
private CountDownLatch connectLatch = new CountDownLatch(1);
|
||||
|
||||
public EventIdServer(BlockheadServer server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
sconnection = server.accept();
|
||||
sconnection.setSoTimeout(60000);
|
||||
sconnection.upgrade();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
connectLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
public void writeSequentialIds(int from, int to) throws IOException
|
||||
{
|
||||
for (int id = from; id < to; id++)
|
||||
{
|
||||
TextFrame frame = new TextFrame();
|
||||
frame.setPayload(Integer.toString(id));
|
||||
sconnection.write(frame);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
sconnection.close();
|
||||
}
|
||||
|
||||
public void awaitConnect() throws InterruptedException
|
||||
{
|
||||
connectLatch.await(1,TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Log.getLogger(DecoderReaderManySmallTest.class);
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private static BlockheadServer server;
|
||||
private WebSocketContainer client;
|
||||
|
||||
@Before
|
||||
|
@ -182,15 +134,15 @@ public class DecoderReaderManySmallTest
|
|||
((LifeCycle)client).stop();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
@ -198,31 +150,55 @@ public class DecoderReaderManySmallTest
|
|||
@Test
|
||||
public void testManyIds() throws Exception
|
||||
{
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
EventIdSocket ids = new EventIdSocket();
|
||||
EventIdServer idserver = new EventIdServer(server);
|
||||
new Thread(idserver).start();
|
||||
client.connectToServer(ids,server.getWsUri());
|
||||
idserver.awaitConnect();
|
||||
int from = 1000;
|
||||
int to = 2000;
|
||||
idserver.writeSequentialIds(from,to);
|
||||
idserver.close();
|
||||
|
||||
final int from = 1000;
|
||||
final int to = 2000;
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Setup echo of frames on server side
|
||||
serverConn.setIncomingFrameConsumer((frame) ->
|
||||
{
|
||||
WebSocketFrame wsFrame = (WebSocketFrame) frame;
|
||||
if (wsFrame.getOpCode() == OpCode.TEXT)
|
||||
{
|
||||
String msg = wsFrame.getPayloadAsUTF8();
|
||||
if (msg == "generate")
|
||||
{
|
||||
for (int id = from; id < to; id++)
|
||||
{
|
||||
TextFrame event = new TextFrame();
|
||||
event.setPayload(Integer.toString(id));
|
||||
serverConn.write(event);
|
||||
}
|
||||
serverConn.write(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
int count = from - to;
|
||||
ids.messageQueue.awaitEventCount(count,4,TimeUnit.SECONDS);
|
||||
ids.awaitClose();
|
||||
// collect seen ids
|
||||
List<Integer> seen = new ArrayList<>();
|
||||
for(EventId id: ids.messageQueue)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
EventId id = ids.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
// validate that ids don't repeat.
|
||||
Assert.assertFalse("Already saw ID: " + id.eventId, seen.contains(id.eventId));
|
||||
seen.add(id.eventId);
|
||||
}
|
||||
|
||||
// validate that all expected ids have been seen (order is irrelevant here)
|
||||
for(int expected=from; expected<to; expected++)
|
||||
for (int expected = from; expected < to; expected++)
|
||||
{
|
||||
Assert.assertTrue("Has expected id:"+expected,seen.contains(expected));
|
||||
Assert.assertTrue("Has expected id:" + expected, seen.contains(expected));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
|
@ -27,7 +27,10 @@ import java.io.IOException;
|
|||
import java.io.Reader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
|
@ -40,9 +43,7 @@ import javax.websocket.OnClose;
|
|||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -50,13 +51,14 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.ContinuationFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DecoderReaderTest
|
||||
|
@ -126,7 +128,8 @@ public class DecoderReaderTest
|
|||
@ClientEndpoint(decoders = { QuotesDecoder.class })
|
||||
public static class QuotesSocket
|
||||
{
|
||||
public EventQueue<Quotes> messageQueue = new EventQueue<>();
|
||||
private static final Logger LOG = Log.getLogger(QuotesSocket.class);
|
||||
public LinkedBlockingQueue<Quotes> messageQueue = new LinkedBlockingQueue<>();
|
||||
private CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
|
||||
@OnClose
|
||||
|
@ -138,12 +141,15 @@ public class DecoderReaderTest
|
|||
@OnMessage
|
||||
public synchronized void onMessage(Quotes msg)
|
||||
{
|
||||
Integer h=hashCode();
|
||||
messageQueue.add(msg);
|
||||
System.out.printf("%x: Quotes from: %s%n",h,msg.author);
|
||||
messageQueue.offer(msg);
|
||||
if(LOG.isDebugEnabled())
|
||||
{
|
||||
String hashcode = Integer.toHexString(Objects.hashCode(this));
|
||||
LOG.debug("{}: Quotes from: {}", hashcode, msg.author);
|
||||
for (String quote : msg.quotes)
|
||||
{
|
||||
System.out.printf("%x: - %s%n",h,quote);
|
||||
LOG.debug("{}: - {}", hashcode, quote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,37 +159,87 @@ public class DecoderReaderTest
|
|||
}
|
||||
}
|
||||
|
||||
private static class QuoteServer implements Runnable
|
||||
{
|
||||
private BlockheadServer server;
|
||||
private IBlockheadServerConnection sconnection;
|
||||
private CountDownLatch connectLatch = new CountDownLatch(1);
|
||||
private static BlockheadServer server;
|
||||
private WebSocketContainer client;
|
||||
|
||||
public QuoteServer(BlockheadServer server)
|
||||
@Before
|
||||
public void initClient()
|
||||
{
|
||||
this.server = server;
|
||||
client = ContainerProvider.getWebSocketContainer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
@After
|
||||
public void stopClient() throws Exception
|
||||
{
|
||||
try
|
||||
{
|
||||
sconnection = server.accept();
|
||||
sconnection.setSoTimeout(60000);
|
||||
sconnection.upgrade();
|
||||
((LifeCycle)client).stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
LOG.warn(e);
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
}
|
||||
finally
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
connectLatch.countDown();
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleQuotes() throws Exception
|
||||
{
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
QuotesSocket quoter = new QuotesSocket();
|
||||
client.connectToServer(quoter,server.getWsUri());
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
writeQuotes(serverConn, "quotes-ben.txt");
|
||||
|
||||
Quotes quotes = quoter.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Quotes Author", quotes.author, is("Benjamin Franklin"));
|
||||
Assert.assertThat("Quotes Count", quotes.quotes.size(), is(3));
|
||||
}
|
||||
}
|
||||
|
||||
public void writeQuotes(String filename) throws IOException
|
||||
/**
|
||||
* Test that multiple quotes can go through decoder without issue.
|
||||
* <p>
|
||||
* Since this decoder is Reader based, this is a useful test to ensure
|
||||
* that the Reader creation / dispatch / hand off to the user endpoint
|
||||
* works properly.
|
||||
* </p>
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testTwoQuotes() throws Exception
|
||||
{
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
QuotesSocket quoter = new QuotesSocket();
|
||||
client.connectToServer(quoter,server.getWsUri());
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
writeQuotes( serverConn,"quotes-ben.txt");
|
||||
Quotes quotes = quoter.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Quotes Author", quotes.author, is("Benjamin Franklin"));
|
||||
Assert.assertThat("Quotes Count", quotes.quotes.size(), is(3));
|
||||
|
||||
writeQuotes( serverConn,"quotes-twain.txt");
|
||||
quotes = quoter.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Quotes Author", quotes.author, is("Mark Twain"));
|
||||
}
|
||||
}
|
||||
|
||||
private void writeQuotes(BlockheadConnection conn, String filename) throws IOException
|
||||
{
|
||||
// read file
|
||||
File qfile = MavenTestingUtils.getTestResourceFile(filename);
|
||||
|
@ -211,90 +267,7 @@ public class DecoderReaderTest
|
|||
}
|
||||
frame.setFin((i >= (lines.size() - 1)));
|
||||
frame.setPayload(BufferUtil.toBuffer(lines.get(i) + "\n"));
|
||||
sconnection.write(frame);
|
||||
conn.write(frame);
|
||||
}
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
sconnection.close();
|
||||
}
|
||||
|
||||
public void awaitConnect() throws InterruptedException
|
||||
{
|
||||
connectLatch.await(1,TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Log.getLogger(DecoderReaderTest.class);
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private WebSocketContainer client;
|
||||
|
||||
@Before
|
||||
public void initClient()
|
||||
{
|
||||
client = ContainerProvider.getWebSocketContainer();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopClient() throws Exception
|
||||
{
|
||||
((LifeCycle)client).stop();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
// TODO analyse and fix
|
||||
@Ignore
|
||||
@Test
|
||||
public void testSingleQuotes() throws Exception
|
||||
{
|
||||
QuotesSocket quoter = new QuotesSocket();
|
||||
QuoteServer qserver = new QuoteServer(server);
|
||||
new Thread(qserver).start();
|
||||
client.connectToServer(quoter,server.getWsUri());
|
||||
qserver.awaitConnect();
|
||||
qserver.writeQuotes("quotes-ben.txt");
|
||||
quoter.messageQueue.awaitEventCount(1,1000,TimeUnit.MILLISECONDS);
|
||||
qserver.close();
|
||||
quoter.awaitClose();
|
||||
Quotes quotes = quoter.messageQueue.poll();
|
||||
Assert.assertThat("Quotes Author",quotes.author,is("Benjamin Franklin"));
|
||||
Assert.assertThat("Quotes Count",quotes.quotes.size(),is(3));
|
||||
}
|
||||
|
||||
// TODO analyse and fix
|
||||
@Test
|
||||
@Ignore ("Quotes appear to be able to arrive in any order?")
|
||||
public void testTwoQuotes() throws Exception
|
||||
{
|
||||
QuotesSocket quoter = new QuotesSocket();
|
||||
QuoteServer qserver = new QuoteServer(server);
|
||||
new Thread(qserver).start();
|
||||
client.connectToServer(quoter,server.getWsUri());
|
||||
qserver.awaitConnect();
|
||||
qserver.writeQuotes("quotes-ben.txt");
|
||||
qserver.writeQuotes("quotes-twain.txt");
|
||||
quoter.messageQueue.awaitEventCount(2,1000,TimeUnit.MILLISECONDS);
|
||||
qserver.close();
|
||||
quoter.awaitClose();
|
||||
Quotes quotes = quoter.messageQueue.poll();
|
||||
Assert.assertThat("Quotes Author",quotes.author,is("Benjamin Franklin"));
|
||||
Assert.assertThat("Quotes Count",quotes.quotes.size(),is(3));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,9 @@ import java.io.FileReader;
|
|||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.ContainerProvider;
|
||||
|
@ -39,77 +40,25 @@ import javax.websocket.MessageHandler;
|
|||
import javax.websocket.Session;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class EncoderTest
|
||||
{
|
||||
private static class EchoServer implements Runnable
|
||||
{
|
||||
private Thread thread;
|
||||
private BlockheadServer server;
|
||||
private IBlockheadServerConnection sconnection;
|
||||
private CountDownLatch connectLatch = new CountDownLatch(1);
|
||||
|
||||
public EchoServer(BlockheadServer server)
|
||||
{
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
try
|
||||
{
|
||||
sconnection = server.accept();
|
||||
sconnection.setSoTimeout(60000);
|
||||
sconnection.upgrade();
|
||||
sconnection.startEcho();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
connectLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
public void start()
|
||||
{
|
||||
this.thread = new Thread(this,"EchoServer");
|
||||
this.thread.start();
|
||||
}
|
||||
|
||||
public void stop()
|
||||
{
|
||||
if (this.sconnection != null)
|
||||
{
|
||||
this.sconnection.stopEcho();
|
||||
try
|
||||
{
|
||||
this.sconnection.close();
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Quotes
|
||||
{
|
||||
private String author;
|
||||
|
@ -166,12 +115,12 @@ public class EncoderTest
|
|||
public static class QuotesSocket extends Endpoint implements MessageHandler.Whole<String>
|
||||
{
|
||||
private Session session;
|
||||
private EventQueue<String> messageQueue = new EventQueue<>();
|
||||
private LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
@Override
|
||||
public void onMessage(String message)
|
||||
{
|
||||
messageQueue.add(message);
|
||||
messageQueue.offer(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -191,12 +140,22 @@ public class EncoderTest
|
|||
|
||||
private static final Logger LOG = Log.getLogger(EncoderTest.class);
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
private BlockheadServer server;
|
||||
|
||||
private static BlockheadServer server;
|
||||
private WebSocketContainer client;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
private void assertReceivedQuotes(String result, Quotes quotes)
|
||||
{
|
||||
Assert.assertThat("Quote Author",result,containsString("Author: " + quotes.getAuthor()));
|
||||
|
@ -236,6 +195,7 @@ public class EncoderTest
|
|||
public void initClient()
|
||||
{
|
||||
client = ContainerProvider.getWebSocketContainer();
|
||||
client.setDefaultMaxSessionIdleTimeout(10000);
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -244,26 +204,12 @@ public class EncoderTest
|
|||
((LifeCycle)client).stop();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(timeout = 10000)
|
||||
public void testSingleQuotes() throws Exception
|
||||
{
|
||||
EchoServer eserver = new EchoServer(server);
|
||||
try
|
||||
{
|
||||
eserver.start();
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
QuotesSocket quoter = new QuotesSocket();
|
||||
|
||||
|
@ -274,27 +220,25 @@ public class EncoderTest
|
|||
ClientEndpointConfig cec = builder.build();
|
||||
client.connectToServer(quoter,cec,server.getWsUri());
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Setup echo of frames on server side
|
||||
serverConn.setIncomingFrameConsumer(new DataFrameEcho(serverConn));
|
||||
|
||||
Quotes ben = getQuotes("quotes-ben.txt");
|
||||
quoter.write(ben);
|
||||
|
||||
quoter.messageQueue.awaitEventCount(1,1000,TimeUnit.MILLISECONDS);
|
||||
|
||||
String result = quoter.messageQueue.poll();
|
||||
String result = quoter.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertReceivedQuotes(result,ben);
|
||||
}
|
||||
finally
|
||||
{
|
||||
eserver.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test(timeout = 10000)
|
||||
public void testTwoQuotes() throws Exception
|
||||
{
|
||||
EchoServer eserver = new EchoServer(server);
|
||||
try
|
||||
{
|
||||
eserver.start();
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
QuotesSocket quoter = new QuotesSocket();
|
||||
ClientEndpointConfig.Builder builder = ClientEndpointConfig.Builder.create();
|
||||
|
@ -304,21 +248,41 @@ public class EncoderTest
|
|||
ClientEndpointConfig cec = builder.build();
|
||||
client.connectToServer(quoter,cec,server.getWsUri());
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Setup echo of frames on server side
|
||||
serverConn.setIncomingFrameConsumer(new DataFrameEcho(serverConn));
|
||||
|
||||
Quotes ben = getQuotes("quotes-ben.txt");
|
||||
Quotes twain = getQuotes("quotes-twain.txt");
|
||||
quoter.write(ben);
|
||||
quoter.write(twain);
|
||||
|
||||
quoter.messageQueue.awaitEventCount(2,1000,TimeUnit.MILLISECONDS);
|
||||
|
||||
String result = quoter.messageQueue.poll();
|
||||
String result = quoter.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertReceivedQuotes(result,ben);
|
||||
result = quoter.messageQueue.poll();
|
||||
result = quoter.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertReceivedQuotes(result,twain);
|
||||
}
|
||||
finally
|
||||
}
|
||||
|
||||
private static class DataFrameEcho implements Consumer<Frame>
|
||||
{
|
||||
eserver.stop();
|
||||
private final BlockheadConnection connection;
|
||||
|
||||
public DataFrameEcho(BlockheadConnection connection)
|
||||
{
|
||||
this.connection = connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(Frame frame)
|
||||
{
|
||||
if (OpCode.isDataFrame(frame.getOpCode()))
|
||||
{
|
||||
WebSocketFrame copy = WebSocketFrame.copy(frame);
|
||||
copy.setMask(null); // remove client masking
|
||||
connection.write(copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,15 +23,16 @@ import static org.hamcrest.Matchers.is;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents;
|
||||
|
@ -118,9 +119,8 @@ public class OnCloseTest
|
|||
driver.onClose(new CloseInfo(StatusCode.NORMAL,"normal"));
|
||||
|
||||
// Test captured event
|
||||
EventQueue<String> events = endpoint.eventQueue;
|
||||
Assert.assertThat("Number of Events Captured",events.size(),is(1));
|
||||
String closeEvent = events.poll();
|
||||
LinkedBlockingQueue<String> events = endpoint.eventQueue;
|
||||
String closeEvent = events.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Close Event",closeEvent,is(testcase.expectedCloseEvent));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,12 +23,12 @@ import static org.hamcrest.Matchers.is;
|
|||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.CloseReason.CloseCode;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
|
@ -41,8 +41,8 @@ public abstract class TrackingSocket
|
|||
private static final Logger LOG = Log.getLogger(TrackingSocket.class);
|
||||
|
||||
public CloseReason closeReason;
|
||||
public EventQueue<String> eventQueue = new EventQueue<String>();
|
||||
public EventQueue<Throwable> errorQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> eventQueue = new LinkedBlockingQueue<>();
|
||||
public LinkedBlockingQueue<Throwable> errorQueue = new LinkedBlockingQueue<>();
|
||||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
public CountDownLatch dataLatch = new CountDownLatch(1);
|
||||
|
@ -50,12 +50,12 @@ public abstract class TrackingSocket
|
|||
protected void addError(Throwable t)
|
||||
{
|
||||
LOG.warn(t);
|
||||
errorQueue.add(t);
|
||||
errorQueue.offer(t);
|
||||
}
|
||||
|
||||
protected void addEvent(String format, Object... args)
|
||||
{
|
||||
eventQueue.add(String.format(format,args));
|
||||
eventQueue.offer(String.format(format,args));
|
||||
}
|
||||
|
||||
public void assertClose(CloseCode expectedCode, String expectedReason) throws InterruptedException
|
||||
|
@ -76,12 +76,6 @@ public abstract class TrackingSocket
|
|||
Assert.assertThat("Close Reason",closeReason.getReasonPhrase(),is(expectedReason));
|
||||
}
|
||||
|
||||
public void assertEvent(String expected)
|
||||
{
|
||||
String actual = eventQueue.poll();
|
||||
Assert.assertEquals("Event",expected,actual);
|
||||
}
|
||||
|
||||
public void assertIsOpen() throws InterruptedException
|
||||
{
|
||||
assertWasOpened();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.LEVEL=WARN
|
||||
|
||||
# org.eclipse.jetty.websocket.LEVEL=INFO
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.LEVEL=ALL
|
||||
# org.eclipse.jetty.websocket.jsr356.LEVEL=DEBUG
|
||||
|
|
|
@ -23,8 +23,8 @@ import static org.hamcrest.CoreMatchers.nullValue;
|
|||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
|
@ -34,6 +34,7 @@ import org.eclipse.jetty.toolchain.test.TestingDir;
|
|||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoSocket;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
|
@ -81,8 +82,8 @@ public class AltFilterTest
|
|||
// wait for connect
|
||||
future.get(1,TimeUnit.SECONDS);
|
||||
clientEcho.sendMessage("Hello Echo");
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
Assert.assertEquals("Expected message","Hello Echo",msgs.poll());
|
||||
LinkedBlockingQueue<String> msgs = clientEcho.incomingMessages;
|
||||
Assert.assertEquals("Expected message","Hello Echo",msgs.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -22,8 +22,8 @@ import static org.hamcrest.Matchers.containsString;
|
|||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
|
@ -33,6 +33,7 @@ import org.eclipse.jetty.webapp.WebAppContext;
|
|||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.beans.DateDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.beans.TimeEncoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.ConfiguredEchoSocket;
|
||||
|
@ -40,7 +41,6 @@ import org.eclipse.jetty.websocket.jsr356.server.samples.echo.EchoSocketConfigur
|
|||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -90,9 +90,9 @@ public class AnnotatedServerEndpointTest
|
|||
foo.get(1,TimeUnit.SECONDS);
|
||||
|
||||
clientEcho.sendMessage(message);
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
LinkedBlockingQueue<String> msgs = clientEcho.incomingMessages;
|
||||
|
||||
String response = msgs.poll();
|
||||
String response = msgs.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
for (String expected : expectedTexts)
|
||||
{
|
||||
Assert.assertThat("Expected message",response,containsString(expected));
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.toolchain.test.TestingDir;
|
|||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoEndpoint;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoEndpointConfigContextListener;
|
||||
import org.junit.Assert;
|
||||
|
@ -73,8 +74,8 @@ public class BasicEndpointTest
|
|||
// wait for connect
|
||||
future.get(1,TimeUnit.SECONDS);
|
||||
clientEcho.sendMessage("Hello World");
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
Assert.assertEquals("Expected message","Hello World",msgs.poll());
|
||||
LinkedBlockingQueue<String> msgs = clientEcho.incomingMessages;
|
||||
Assert.assertEquals("Expected message","Hello World",msgs.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -35,6 +35,8 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
@ -51,18 +53,21 @@ import javax.websocket.server.HandshakeRequest;
|
|||
import javax.websocket.server.ServerEndpoint;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.util.QuoteUtil;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.HttpResponse;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
|
@ -357,6 +362,7 @@ public class ConfiguratorTest
|
|||
}
|
||||
}
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static Server server;
|
||||
private static URI baseServerUri;
|
||||
|
||||
|
@ -408,18 +414,35 @@ public class ConfiguratorTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyConfigurator() throws Exception
|
||||
{
|
||||
URI uri = baseServerUri.resolve("/empty");
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, "identity");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.addExtensions("identity");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
HttpResponse response = client.readResponseHeader();
|
||||
Assert.assertThat("response.extensions", response.getExtensionsHeader(), is("identity"));
|
||||
HttpFields responseHeaders = clientConn.getUpgradeResponseHeaders();
|
||||
HttpField extensionHeader = responseHeaders.getField(HttpHeader.SEC_WEBSOCKET_EXTENSIONS);
|
||||
Assert.assertThat("response.extensions", extensionHeader.getValue(), is("identity"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -428,17 +451,20 @@ public class ConfiguratorTest
|
|||
{
|
||||
URI uri = baseServerUri.resolve("/no-extensions");
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.addExtensions("identity");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
HttpResponse response = client.expectUpgradeResponse();
|
||||
assertThat("response.extensions", response.getExtensionsHeader(), nullValue());
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, "identity");
|
||||
|
||||
client.write(new TextFrame().setPayload("NegoExts"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
HttpFields responseHeaders = clientConn.getUpgradeResponseHeaders();
|
||||
HttpField extensionHeader = responseHeaders.getField(HttpHeader.SEC_WEBSOCKET_EXTENSIONS);
|
||||
assertThat("response.extensions", extensionHeader, is(nullValue()));
|
||||
|
||||
clientConn.write(new TextFrame().setPayload("NegoExts"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Frame Response", frame.getPayloadAsUTF8(), is("negotiatedExtensions=[]"));
|
||||
}
|
||||
}
|
||||
|
@ -448,16 +474,16 @@ public class ConfiguratorTest
|
|||
{
|
||||
URI uri = baseServerUri.resolve("/capture-request-headers");
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.addHeader("X-Dummy: Bogus\r\n");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
request.header("X-Dummy", "Bogus");
|
||||
|
||||
client.write(new TextFrame().setPayload("X-Dummy"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
clientConn.write(new TextFrame().setPayload("X-Dummy"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Request Header [X-Dummy]: \"Bogus\""));
|
||||
}
|
||||
}
|
||||
|
@ -468,33 +494,32 @@ public class ConfiguratorTest
|
|||
URI uri = baseServerUri.resolve("/unique-user-props");
|
||||
|
||||
// First request
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
client.write(new TextFrame().setPayload("apple"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
clientConn.write(new TextFrame().setPayload("apple"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested User Property: [apple] = \"fruit from tree\""));
|
||||
}
|
||||
|
||||
// Second request
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
|
||||
client.write(new TextFrame().setPayload("apple"));
|
||||
client.write(new TextFrame().setPayload("blueberry"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(2, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
request = client.newWsRequest(uri);
|
||||
connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
clientConn.write(new TextFrame().setPayload("apple"));
|
||||
clientConn.write(new TextFrame().setPayload("blueberry"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
// should have no value
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested User Property: [apple] = <null>"));
|
||||
|
||||
frame = frames.poll();
|
||||
frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested User Property: [blueberry] = \"fruit from bush\""));
|
||||
}
|
||||
}
|
||||
|
@ -504,19 +529,17 @@ public class ConfiguratorTest
|
|||
{
|
||||
URI uri = baseServerUri.resolve("/addr");
|
||||
|
||||
// First request
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
InetSocketAddress expectedLocal = clientConn.getLocalSocketAddress();
|
||||
InetSocketAddress expectedRemote = clientConn.getRemoteSocketAddress();
|
||||
|
||||
InetSocketAddress expectedLocal = client.getLocalSocketAddress();
|
||||
InetSocketAddress expectedRemote = client.getRemoteSocketAddress();
|
||||
|
||||
client.write(new TextFrame().setPayload("addr"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
clientConn.write(new TextFrame().setPayload("addr"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
|
||||
StringWriter expected = new StringWriter();
|
||||
PrintWriter out = new PrintWriter(expected);
|
||||
|
@ -540,16 +563,15 @@ public class ConfiguratorTest
|
|||
URI uri = baseServerUri.resolve("/protocols");
|
||||
ProtocolsConfigurator.seenProtocols.set(null);
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.addHeader("Sec-WebSocket-Protocol: echo\r\n");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "echo");
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
client.write(new TextFrame().setPayload("getProtocols"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
clientConn.write(new TextFrame().setPayload("getProtocols"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested Protocols: [\"echo\"]"));
|
||||
}
|
||||
}
|
||||
|
@ -564,16 +586,15 @@ public class ConfiguratorTest
|
|||
URI uri = baseServerUri.resolve("/protocols");
|
||||
ProtocolsConfigurator.seenProtocols.set(null);
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.addHeader("Sec-WebSocket-Protocol: echo, chat, status\r\n");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "echo, chat, status");
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
client.write(new TextFrame().setPayload("getProtocols"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
clientConn.write(new TextFrame().setPayload("getProtocols"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested Protocols: [\"echo\",\"chat\",\"status\"]"));
|
||||
}
|
||||
}
|
||||
|
@ -588,16 +609,15 @@ public class ConfiguratorTest
|
|||
URI uri = baseServerUri.resolve("/protocols");
|
||||
ProtocolsConfigurator.seenProtocols.set(null);
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.addHeader("sec-websocket-protocol: echo, chat, status\r\n");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
request.header("sec-websocket-protocol", "echo, chat, status");
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
client.write(new TextFrame().setPayload("getProtocols"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
clientConn.write(new TextFrame().setPayload("getProtocols"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested Protocols: [\"echo\",\"chat\",\"status\"]"));
|
||||
}
|
||||
}
|
||||
|
@ -612,16 +632,16 @@ public class ConfiguratorTest
|
|||
URI uri = baseServerUri.resolve("/protocols");
|
||||
ProtocolsConfigurator.seenProtocols.set(null);
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.addHeader("Sec-Websocket-Protocol: echo, chat, status\r\n");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
// We see "Websocket" (no capital "S" often)
|
||||
request.header("Sec-Websocket-Protocol", "echo, chat, status");
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
client.write(new TextFrame().setPayload("getProtocols"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
clientConn.write(new TextFrame().setPayload("getProtocols"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("Requested Protocols: [\"echo\",\"chat\",\"status\"]"));
|
||||
}
|
||||
}
|
||||
|
@ -634,16 +654,16 @@ public class ConfiguratorTest
|
|||
{
|
||||
URI uri = baseServerUri.resolve("/timedecoder");
|
||||
|
||||
try (BlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.addHeader("Sec-Websocket-Protocol: gmt\r\n");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
// We see "Websocket" (no capital "S" often)
|
||||
request.header("SeC-WeBsOcKeT-PrOtOcOl", "gmt");
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
client.write(new TextFrame().setPayload("2016-06-20T14:27:44"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1, TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
clientConn.write(new TextFrame().setPayload("2016-06-20T14:27:44"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame Response", frame.getPayloadAsUTF8(), is("cal=2016.06.20 AD at 14:27:44 +0000"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@ package org.eclipse.jetty.websocket.jsr356.server;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.CloseReason;
|
||||
|
@ -38,15 +36,9 @@ import org.eclipse.jetty.util.BufferUtil;
|
|||
@ClientEndpoint
|
||||
public class EchoClientSocket extends TrackingSocket
|
||||
{
|
||||
public final CountDownLatch eventCountLatch;
|
||||
private Session session;
|
||||
private Basic remote;
|
||||
|
||||
public EchoClientSocket(int expectedEventCount)
|
||||
{
|
||||
this.eventCountLatch = new CountDownLatch(expectedEventCount);
|
||||
}
|
||||
|
||||
public void close() throws IOException
|
||||
{
|
||||
if (session != null)
|
||||
|
@ -88,12 +80,6 @@ public class EchoClientSocket extends TrackingSocket
|
|||
public void onText(String text)
|
||||
{
|
||||
addEvent(text);
|
||||
eventCountLatch.countDown();
|
||||
}
|
||||
|
||||
public boolean awaitAllEvents(long timeout, TimeUnit unit) throws InterruptedException
|
||||
{
|
||||
return eventCountLatch.await(timeout,unit);
|
||||
}
|
||||
|
||||
public void sendObject(Object obj) throws IOException, EncodeException
|
||||
|
|
|
@ -18,22 +18,23 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.websocket.ContainerProvider;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.EchoCase.PartialBinary;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.EchoCase.PartialText;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.binary.ByteBufferSocket;
|
||||
|
@ -248,14 +249,13 @@ public class EchoTest
|
|||
public EchoTest(EchoCase testcase)
|
||||
{
|
||||
this.testcase = testcase;
|
||||
System.err.println(testcase);
|
||||
}
|
||||
|
||||
@Test(timeout=2000)
|
||||
public void testEcho() throws Exception
|
||||
{
|
||||
int messageCount = testcase.getMessageCount();
|
||||
EchoClientSocket socket = new EchoClientSocket(messageCount);
|
||||
EchoClientSocket socket = new EchoClientSocket();
|
||||
URI toUri = serverUri.resolve(testcase.path.substring(1));
|
||||
|
||||
try
|
||||
|
@ -284,13 +284,13 @@ public class EchoTest
|
|||
}
|
||||
|
||||
// Collect Responses
|
||||
socket.awaitAllEvents(1,TimeUnit.SECONDS);
|
||||
EventQueue<String> received = socket.eventQueue;
|
||||
LinkedBlockingQueue<String> received = socket.eventQueue;
|
||||
|
||||
// Validate Responses
|
||||
for (String expected : testcase.expectedStrings)
|
||||
{
|
||||
Assert.assertThat("Received Echo Responses",received,contains(expected));
|
||||
String actual = received.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Received Echo Responses",actual,containsString(expected));
|
||||
}
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -18,15 +18,14 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
|
@ -35,6 +34,7 @@ import org.eclipse.jetty.util.log.StacklessLogging;
|
|||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.idletimeout.IdleTimeoutContextListener;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.idletimeout.OnOpenIdleTimeoutEndpoint;
|
||||
|
@ -100,10 +100,12 @@ public class IdleTimeoutTest
|
|||
clientEcho.sendMessage("You shouldn't be there");
|
||||
try
|
||||
{
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
assertThat("Should not have received messages echoed back",msgs,is(empty()));
|
||||
LinkedBlockingQueue<String> msgs = clientEcho.incomingMessages;
|
||||
// should not have a message.
|
||||
String received = msgs.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Should not have received messages echoed back",received,is(nullValue()));
|
||||
}
|
||||
catch (TimeoutException | InterruptedException e)
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
// valid success path
|
||||
}
|
||||
|
|
|
@ -19,13 +19,10 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
|
@ -50,13 +47,7 @@ public class JettyEchoSocket
|
|||
private Session session;
|
||||
private Lock remoteLock = new ReentrantLock();
|
||||
private RemoteEndpoint remote;
|
||||
private EventQueue<String> incomingMessages = new EventQueue<>();
|
||||
|
||||
public Queue<String> awaitMessages(int expected) throws TimeoutException, InterruptedException
|
||||
{
|
||||
incomingMessages.awaitEventCount(expected,2,TimeUnit.SECONDS);
|
||||
return incomingMessages;
|
||||
}
|
||||
public LinkedBlockingQueue<String> incomingMessages = new LinkedBlockingQueue<>();
|
||||
|
||||
public boolean getClosed()
|
||||
{
|
||||
|
|
|
@ -21,8 +21,8 @@ package org.eclipse.jetty.websocket.jsr356.server;
|
|||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
|
@ -31,6 +31,7 @@ import org.eclipse.jetty.toolchain.test.TestingDir;
|
|||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.LargeEchoConfiguredSocket;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
|
@ -78,8 +79,8 @@ public class LargeAnnotatedTest
|
|||
Arrays.fill(txt,(byte)'o');
|
||||
String msg = new String(txt,StandardCharsets.UTF_8);
|
||||
clientEcho.sendMessage(msg);
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
Assert.assertEquals("Expected message",msg,msgs.poll());
|
||||
LinkedBlockingQueue<String> msgs = clientEcho.incomingMessages;
|
||||
Assert.assertEquals("Expected message",msg,msgs.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -21,8 +21,8 @@ package org.eclipse.jetty.websocket.jsr356.server;
|
|||
import java.net.URI;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
|
@ -31,6 +31,7 @@ import org.eclipse.jetty.toolchain.test.TestingDir;
|
|||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.LargeEchoDefaultSocket;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
|
@ -78,8 +79,8 @@ public class LargeContainerTest
|
|||
Arrays.fill(txt,(byte)'o');
|
||||
String msg = new String(txt,StandardCharsets.UTF_8);
|
||||
clientEcho.sendMessage(msg);
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
Assert.assertEquals("Expected message",msg,msgs.poll());
|
||||
LinkedBlockingQueue<String> msgs = clientEcho.incomingMessages;
|
||||
Assert.assertEquals("Expected message",msg,msgs.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
||||
import java.io.File;
|
||||
|
@ -28,9 +27,9 @@ import java.util.concurrent.TimeUnit;
|
|||
import javax.websocket.ContainerProvider;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.pong.PongContextListener;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.pong.PongMessageEndpoint;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.pong.PongSocket;
|
||||
|
@ -78,7 +77,7 @@ public class PingPongTest
|
|||
@Test(timeout = 2000)
|
||||
public void testPingEndpoint() throws Exception
|
||||
{
|
||||
EchoClientSocket socket = new EchoClientSocket(1);
|
||||
EchoClientSocket socket = new EchoClientSocket();
|
||||
URI toUri = serverUri.resolve("ping");
|
||||
|
||||
try
|
||||
|
@ -91,12 +90,8 @@ public class PingPongTest
|
|||
String msg = "hello";
|
||||
socket.sendPing(msg);
|
||||
|
||||
// Collect Responses
|
||||
socket.awaitAllEvents(1,TimeUnit.SECONDS);
|
||||
EventQueue<String> received = socket.eventQueue;
|
||||
|
||||
// Validate Responses
|
||||
String actual = received.poll();
|
||||
String actual = socket.eventQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Received Ping Response",actual,containsString("PongMessage[/ping]:" + msg));
|
||||
}
|
||||
finally
|
||||
|
@ -109,7 +104,7 @@ public class PingPongTest
|
|||
@Test(timeout = 2000)
|
||||
public void testPongEndpoint() throws Exception
|
||||
{
|
||||
EchoClientSocket socket = new EchoClientSocket(1);
|
||||
EchoClientSocket socket = new EchoClientSocket();
|
||||
URI toUri = serverUri.resolve("pong");
|
||||
|
||||
try
|
||||
|
@ -122,12 +117,9 @@ public class PingPongTest
|
|||
String msg = "hello";
|
||||
socket.sendPong(msg);
|
||||
|
||||
// Collect Responses
|
||||
socket.awaitAllEvents(1,TimeUnit.SECONDS);
|
||||
EventQueue<String> received = socket.eventQueue;
|
||||
|
||||
// Validate Responses
|
||||
Assert.assertThat("Received Ping Responses",received,contains("PongMessage[/pong]:" + msg));
|
||||
String received = socket.eventQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Received Ping Responses",received,containsString("PongMessage[/pong]:" + msg));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -139,7 +131,7 @@ public class PingPongTest
|
|||
@Test(timeout = 2000)
|
||||
public void testPingSocket() throws Exception
|
||||
{
|
||||
EchoClientSocket socket = new EchoClientSocket(1);
|
||||
EchoClientSocket socket = new EchoClientSocket();
|
||||
URI toUri = serverUri.resolve("ping-socket");
|
||||
|
||||
try
|
||||
|
@ -152,12 +144,8 @@ public class PingPongTest
|
|||
String msg = "hello";
|
||||
socket.sendPing(msg);
|
||||
|
||||
// Collect Responses
|
||||
socket.awaitAllEvents(1,TimeUnit.SECONDS);
|
||||
EventQueue<String> received = socket.eventQueue;
|
||||
|
||||
// Validate Responses
|
||||
String actual = received.poll();
|
||||
String actual = socket.eventQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Received Ping Response",actual,containsString("@OnMessage(PongMessage)[/ping-socket]:" + msg));
|
||||
}
|
||||
finally
|
||||
|
@ -170,7 +158,7 @@ public class PingPongTest
|
|||
@Test(timeout = 2000)
|
||||
public void testPongSocket() throws Exception
|
||||
{
|
||||
EchoClientSocket socket = new EchoClientSocket(1);
|
||||
EchoClientSocket socket = new EchoClientSocket();
|
||||
URI toUri = serverUri.resolve("pong-socket");
|
||||
|
||||
try
|
||||
|
@ -183,12 +171,9 @@ public class PingPongTest
|
|||
String msg = "hello";
|
||||
socket.sendPong(msg);
|
||||
|
||||
// Collect Responses
|
||||
socket.awaitAllEvents(1,TimeUnit.SECONDS);
|
||||
EventQueue<String> received = socket.eventQueue;
|
||||
|
||||
// Validate Responses
|
||||
Assert.assertThat("Received Ping Responses",received,contains("@OnMessage(PongMessage)[/pong-socket]:" + msg));
|
||||
String received = socket.eventQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Received Ping Responses",received,containsString("@OnMessage(PongMessage)[/pong-socket]:" + msg));
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
|
|
@ -179,7 +179,6 @@ public class ServerAnnotatedEndpointScanner_GoodSignaturesTest
|
|||
public ServerAnnotatedEndpointScanner_GoodSignaturesTest(Case testcase)
|
||||
{
|
||||
this.testcase = testcase;
|
||||
System.err.printf("Testing signature of %s%n",testcase.pojo.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -30,8 +30,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.servlet.DefaultServlet;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
|
@ -101,8 +99,6 @@ public class SessionTest
|
|||
return cases;
|
||||
}
|
||||
|
||||
public ByteBufferPool bufferPool = new MappedByteBufferPool();
|
||||
|
||||
private final Case testcase;
|
||||
private final static AtomicInteger ID = new AtomicInteger(0);
|
||||
private WSServer server;
|
||||
|
@ -136,7 +132,7 @@ public class SessionTest
|
|||
|
||||
private void assertResponse(String requestPath, String requestMessage, String expectedResponse) throws Exception
|
||||
{
|
||||
WebSocketClient client = new WebSocketClient(bufferPool);
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
|
|
|
@ -23,12 +23,12 @@ import static org.hamcrest.Matchers.is;
|
|||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.CloseReason.CloseCode;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
|
@ -41,8 +41,8 @@ public abstract class TrackingSocket
|
|||
private static final Logger LOG = Log.getLogger(TrackingSocket.class);
|
||||
|
||||
public CloseReason closeReason;
|
||||
public EventQueue<String> eventQueue = new EventQueue<String>();
|
||||
public EventQueue<Throwable> errorQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> eventQueue = new LinkedBlockingQueue<>();
|
||||
public LinkedBlockingQueue<Throwable> errorQueue = new LinkedBlockingQueue<>();
|
||||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
public CountDownLatch dataLatch = new CountDownLatch(1);
|
||||
|
@ -50,12 +50,12 @@ public abstract class TrackingSocket
|
|||
protected void addError(Throwable t)
|
||||
{
|
||||
LOG.warn(t);
|
||||
errorQueue.add(t);
|
||||
errorQueue.offer(t);
|
||||
}
|
||||
|
||||
protected void addEvent(String format, Object... args)
|
||||
{
|
||||
eventQueue.add(String.format(format,args));
|
||||
eventQueue.offer(String.format(format,args));
|
||||
}
|
||||
|
||||
public void assertClose(CloseCode expectedCode, String expectedReason) throws InterruptedException
|
||||
|
@ -76,12 +76,6 @@ public abstract class TrackingSocket
|
|||
Assert.assertThat("Close Reason",closeReason.getReasonPhrase(),is(expectedReason));
|
||||
}
|
||||
|
||||
public void assertEvent(String expected)
|
||||
{
|
||||
String actual = eventQueue.poll();
|
||||
Assert.assertEquals("Event",expected,actual);
|
||||
}
|
||||
|
||||
public void assertIsOpen() throws InterruptedException
|
||||
{
|
||||
assertWasOpened();
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.server.samples.echo;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.OnMessage;
|
||||
|
@ -26,14 +27,12 @@ import javax.websocket.OnOpen;
|
|||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
|
||||
@ServerEndpoint(value = "/echoreturn")
|
||||
public class EchoReturnEndpoint
|
||||
{
|
||||
private Session session = null;
|
||||
public CloseReason close = null;
|
||||
public EventQueue<String> messageQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
public void onClose(CloseReason close)
|
||||
{
|
||||
|
|
|
@ -40,6 +40,12 @@
|
|||
<artifactId>websocket-common</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.websocket</groupId>
|
||||
<artifactId>websocket-common</artifactId>
|
||||
|
|
|
@ -19,19 +19,21 @@
|
|||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -39,12 +41,9 @@ import org.junit.Test;
|
|||
*/
|
||||
public class BadNetworkTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
public ByteBufferPool bufferPool = new MappedByteBufferPool();
|
||||
|
||||
private BlockheadServer server;
|
||||
private static BlockheadServer server;
|
||||
private WebSocketClient client;
|
||||
|
||||
@Before
|
||||
|
@ -55,8 +54,8 @@ public class BadNetworkTest
|
|||
client.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
|
@ -68,8 +67,8 @@ public class BadNetworkTest
|
|||
client.stop();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
@ -82,12 +81,9 @@ public class BadNetworkTest
|
|||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection ssocket = server.accept();
|
||||
ssocket.upgrade();
|
||||
|
||||
// Validate that we are connected
|
||||
future.get(30,TimeUnit.SECONDS);
|
||||
wsocket.waitForConnected(30,TimeUnit.SECONDS);
|
||||
wsocket.waitForConnected();
|
||||
|
||||
// Have client disconnect abruptly
|
||||
Session session = wsocket.getSession();
|
||||
|
@ -107,25 +103,28 @@ public class BadNetworkTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection ssocket = server.accept();
|
||||
ssocket.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Validate that we are connected
|
||||
future.get(30,TimeUnit.SECONDS);
|
||||
wsocket.waitForConnected(30,TimeUnit.SECONDS);
|
||||
future.get(30, TimeUnit.SECONDS);
|
||||
wsocket.waitForConnected();
|
||||
|
||||
// Have server disconnect abruptly
|
||||
ssocket.disconnect();
|
||||
serverConn.abort();
|
||||
|
||||
// Wait for close (as response to idle timeout)
|
||||
wsocket.waitForClose(10,TimeUnit.SECONDS);
|
||||
wsocket.waitForClose(10, TimeUnit.SECONDS);
|
||||
|
||||
// Client Socket should see a close event, with status NO_CLOSE
|
||||
// This event is automatically supplied by the underlying WebSocketClientConnection
|
||||
// in the situation of a bad network connection.
|
||||
wsocket.assertCloseCode(StatusCode.NO_CLOSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,9 +34,13 @@ import java.nio.ByteBuffer;
|
|||
import java.nio.channels.SelectableChannel;
|
||||
import java.nio.channels.SelectionKey;
|
||||
import java.nio.channels.SocketChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
@ -50,8 +54,6 @@ import org.eclipse.jetty.io.EofException;
|
|||
import org.eclipse.jetty.io.ManagedSelector;
|
||||
import org.eclipse.jetty.io.SelectorManager;
|
||||
import org.eclipse.jetty.io.SocketChannelEndPoint;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -68,15 +70,16 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.IncomingFramesCapture;
|
||||
import org.eclipse.jetty.websocket.common.test.RawFrameBuilder;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ClientCloseTest
|
||||
|
@ -94,7 +97,7 @@ public class ClientCloseTest
|
|||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch errorLatch = new CountDownLatch(1);
|
||||
|
||||
public EventQueue<String> messageQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
|
||||
public AtomicReference<Throwable> error = new AtomicReference<>();
|
||||
|
||||
public void assertNoCloseEvent()
|
||||
|
@ -178,13 +181,10 @@ public class ClientCloseTest
|
|||
}
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private static BlockheadServer server;
|
||||
private WebSocketClient client;
|
||||
|
||||
private void confirmConnection(CloseTrackingSocket clientSocket, Future<Session> clientFuture, IBlockheadServerConnection serverConns) throws Exception
|
||||
private void confirmConnection(CloseTrackingSocket clientSocket, Future<Session> clientFuture, BlockheadConnection serverConns) throws Exception
|
||||
{
|
||||
// Wait for client connect on via future
|
||||
clientFuture.get(30,TimeUnit.SECONDS);
|
||||
|
@ -199,24 +199,19 @@ public class ClientCloseTest
|
|||
Future<Void> testFut = clientSocket.getRemote().sendStringByFuture(echoMsg);
|
||||
|
||||
// Wait for send future
|
||||
testFut.get(30,TimeUnit.SECONDS);
|
||||
testFut.get(Timeouts.SEND, Timeouts.SEND_UNIT);
|
||||
|
||||
// Read Frame on server side
|
||||
IncomingFramesCapture serverCapture = serverConns.readFrames(1,30,TimeUnit.SECONDS);
|
||||
serverCapture.assertNoErrors();
|
||||
serverCapture.assertFrameCount(1);
|
||||
WebSocketFrame frame = serverCapture.getFrames().poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> serverCapture = serverConns.getFrameQueue();
|
||||
WebSocketFrame frame = serverCapture.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Server received frame",frame.getOpCode(),is(OpCode.TEXT));
|
||||
assertThat("Server received frame payload",frame.getPayloadAsUTF8(),is(echoMsg));
|
||||
|
||||
// Server send echo reply
|
||||
serverConns.write(new TextFrame().setPayload(echoMsg));
|
||||
|
||||
// Wait for received echo
|
||||
clientSocket.messageQueue.awaitEventCount(1,1,TimeUnit.SECONDS);
|
||||
|
||||
// Verify received message
|
||||
String recvMsg = clientSocket.messageQueue.poll();
|
||||
String recvMsg = clientSocket.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Received message",recvMsg,is(echoMsg));
|
||||
|
||||
// Verify that there are no errors
|
||||
|
@ -228,14 +223,11 @@ public class ClientCloseTest
|
|||
}
|
||||
}
|
||||
|
||||
private void confirmServerReceivedCloseFrame(IBlockheadServerConnection serverConn, int expectedCloseCode, Matcher<String> closeReasonMatcher) throws IOException,
|
||||
TimeoutException
|
||||
private void confirmServerReceivedCloseFrame(BlockheadConnection serverConn, int expectedCloseCode, Matcher<String> closeReasonMatcher) throws InterruptedException
|
||||
{
|
||||
IncomingFramesCapture serverCapture = serverConn.readFrames(1,30,TimeUnit.SECONDS);
|
||||
serverCapture.assertNoErrors();
|
||||
serverCapture.assertFrameCount(1);
|
||||
serverCapture.assertHasFrame(OpCode.CLOSE,1);
|
||||
WebSocketFrame frame = serverCapture.getFrames().poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> serverCapture = serverConn.getFrameQueue();
|
||||
WebSocketFrame frame = serverCapture.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Server close frame", frame, is(notNullValue()));
|
||||
assertThat("Server received close frame",frame.getOpCode(),is(OpCode.CLOSE));
|
||||
CloseInfo closeInfo = new CloseInfo(frame);
|
||||
assertThat("Server received close code",closeInfo.getStatusCode(),is(expectedCloseCode));
|
||||
|
@ -293,8 +285,8 @@ public class ClientCloseTest
|
|||
client.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
|
@ -306,8 +298,8 @@ public class ClientCloseTest
|
|||
client.stop();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
@ -316,49 +308,49 @@ public class ClientCloseTest
|
|||
public void testHalfClose() throws Exception
|
||||
{
|
||||
// Set client timeout
|
||||
final int timeout = 1000;
|
||||
final int timeout = 5000;
|
||||
client.setMaxIdleTimeout(timeout);
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Client connects
|
||||
CloseTrackingSocket clientSocket = new CloseTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
|
||||
|
||||
// Server accepts connect
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
serverConn.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// client confirms connection via echo
|
||||
confirmConnection(clientSocket,clientConnectFuture,serverConn);
|
||||
confirmConnection(clientSocket, clientConnectFuture, serverConn);
|
||||
|
||||
// client sends close frame (code 1000, normal)
|
||||
final String origCloseReason = "Normal Close";
|
||||
clientSocket.getSession().close(StatusCode.NORMAL,origCloseReason);
|
||||
clientSocket.getSession().close(StatusCode.NORMAL, origCloseReason);
|
||||
|
||||
// server receives close frame
|
||||
confirmServerReceivedCloseFrame(serverConn,StatusCode.NORMAL,is(origCloseReason));
|
||||
confirmServerReceivedCloseFrame(serverConn, StatusCode.NORMAL, is(origCloseReason));
|
||||
|
||||
// server sends 2 messages
|
||||
serverConn.write(new TextFrame().setPayload("Hello"));
|
||||
serverConn.write(new TextFrame().setPayload("World"));
|
||||
|
||||
// server sends close frame (code 1000, no reason)
|
||||
CloseInfo sclose = new CloseInfo(StatusCode.NORMAL,"From Server");
|
||||
CloseInfo sclose = new CloseInfo(StatusCode.NORMAL, "From Server");
|
||||
serverConn.write(sclose.asFrame());
|
||||
|
||||
// client receives 2 messages
|
||||
clientSocket.messageQueue.awaitEventCount(2,1,TimeUnit.SECONDS);
|
||||
|
||||
// Verify received messages
|
||||
String recvMsg = clientSocket.messageQueue.poll();
|
||||
assertThat("Received message 1",recvMsg,is("Hello"));
|
||||
recvMsg = clientSocket.messageQueue.poll();
|
||||
assertThat("Received message 2",recvMsg,is("World"));
|
||||
String recvMsg = clientSocket.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Received message 1", recvMsg, is("Hello"));
|
||||
recvMsg = clientSocket.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Received message 2", recvMsg, is("World"));
|
||||
|
||||
// Verify that there are no errors
|
||||
assertThat("Error events",clientSocket.error.get(),nullValue());
|
||||
assertThat("Error events", clientSocket.error.get(), nullValue());
|
||||
|
||||
// client close event on ws-endpoint
|
||||
clientSocket.assertReceivedCloseEvent(timeout,is(StatusCode.NORMAL),containsString("From Server"));
|
||||
clientSocket.assertReceivedCloseEvent(timeout, is(StatusCode.NORMAL), containsString("From Server"));
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("Need sbordet's help here")
|
||||
|
@ -369,24 +361,26 @@ public class ClientCloseTest
|
|||
final int timeout = 1000;
|
||||
client.setMaxIdleTimeout(timeout);
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Client connects
|
||||
CloseTrackingSocket clientSocket = new CloseTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
|
||||
|
||||
// Server accepts connect
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
serverConn.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// client confirms connection via echo
|
||||
confirmConnection(clientSocket,clientConnectFuture,serverConn);
|
||||
confirmConnection(clientSocket, clientConnectFuture, serverConn);
|
||||
|
||||
// client sends BIG frames (until it cannot write anymore)
|
||||
// server must not read (for test purpose, in order to congest connection)
|
||||
// when write is congested, client enqueue close frame
|
||||
// client initiate write, but write never completes
|
||||
EndPoint endp = clientSocket.getEndPoint();
|
||||
assertThat("EndPoint is testable",endp,instanceOf(TestEndPoint.class));
|
||||
TestEndPoint testendp = (TestEndPoint)endp;
|
||||
assertThat("EndPoint is testable", endp, instanceOf(TestEndPoint.class));
|
||||
TestEndPoint testendp = (TestEndPoint) endp;
|
||||
|
||||
char msg[] = new char[10240];
|
||||
int writeCount = 0;
|
||||
|
@ -395,18 +389,19 @@ public class ClientCloseTest
|
|||
while (!testendp.congestedFlush.get())
|
||||
{
|
||||
int z = i - ((i / 26) * 26);
|
||||
char c = (char)('a' + z);
|
||||
Arrays.fill(msg,c);
|
||||
char c = (char) ('a' + z);
|
||||
Arrays.fill(msg, c);
|
||||
clientSocket.getRemote().sendStringByFuture(String.valueOf(msg));
|
||||
writeCount++;
|
||||
writeSize += msg.length;
|
||||
}
|
||||
LOG.info("Wrote {} frames totalling {} bytes of payload before congestion kicked in",writeCount,writeSize);
|
||||
LOG.info("Wrote {} frames totalling {} bytes of payload before congestion kicked in", writeCount, writeSize);
|
||||
|
||||
// Verify timeout error
|
||||
assertThat("OnError Latch", clientSocket.errorLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat("OnError", clientSocket.error.get(), instanceOf(SocketTimeoutException.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProtocolException() throws Exception
|
||||
|
@ -415,32 +410,35 @@ public class ClientCloseTest
|
|||
final int timeout = 1000;
|
||||
client.setMaxIdleTimeout(timeout);
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Client connects
|
||||
CloseTrackingSocket clientSocket = new CloseTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
|
||||
|
||||
// Server accepts connect
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
serverConn.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// client confirms connection via echo
|
||||
confirmConnection(clientSocket,clientConnectFuture,serverConn);
|
||||
confirmConnection(clientSocket, clientConnectFuture, serverConn);
|
||||
|
||||
// client should not have received close message (yet)
|
||||
clientSocket.assertNoCloseEvent();
|
||||
|
||||
// server sends bad close frame (too big of a reason message)
|
||||
byte msg[] = new byte[400];
|
||||
Arrays.fill(msg,(byte)'x');
|
||||
Arrays.fill(msg, (byte) 'x');
|
||||
ByteBuffer bad = ByteBuffer.allocate(500);
|
||||
RawFrameBuilder.putOpFin(bad,OpCode.CLOSE,true);
|
||||
RawFrameBuilder.putLength(bad,msg.length + 2,false);
|
||||
bad.putShort((short)StatusCode.NORMAL);
|
||||
RawFrameBuilder.putOpFin(bad, OpCode.CLOSE, true);
|
||||
RawFrameBuilder.putLength(bad, msg.length + 2, false);
|
||||
bad.putShort((short) StatusCode.NORMAL);
|
||||
bad.put(msg);
|
||||
BufferUtil.flipToFlush(bad,0);
|
||||
try (StacklessLogging quiet = new StacklessLogging(Parser.class))
|
||||
BufferUtil.flipToFlush(bad, 0);
|
||||
|
||||
try (StacklessLogging ignore = new StacklessLogging(Parser.class))
|
||||
{
|
||||
serverConn.write(bad);
|
||||
serverConn.writeRaw(bad);
|
||||
|
||||
// client should have noticed the error
|
||||
assertThat("OnError Latch", clientSocket.errorLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
|
@ -448,11 +446,9 @@ public class ClientCloseTest
|
|||
assertThat("OnError", clientSocket.error.get().getMessage(), containsString("Invalid control frame"));
|
||||
|
||||
// client parse invalid frame, notifies server of close (protocol error)
|
||||
confirmServerReceivedCloseFrame(serverConn,StatusCode.PROTOCOL,allOf(containsString("Invalid control frame"),containsString("length")));
|
||||
confirmServerReceivedCloseFrame(serverConn, StatusCode.PROTOCOL, allOf(containsString("Invalid control frame"), containsString("length")));
|
||||
}
|
||||
}
|
||||
|
||||
// server disconnects
|
||||
serverConn.disconnect();
|
||||
|
||||
// client triggers close event on client ws-endpoint
|
||||
clientSocket.assertReceivedCloseEvent(timeout,is(StatusCode.PROTOCOL),allOf(containsString("Invalid control frame"),containsString("length")));
|
||||
|
@ -465,38 +461,41 @@ public class ClientCloseTest
|
|||
final int timeout = 1000;
|
||||
client.setMaxIdleTimeout(timeout);
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Client connects
|
||||
CloseTrackingSocket clientSocket = new CloseTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
|
||||
|
||||
// Server accepts connect
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
serverConn.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// client confirms connection via echo
|
||||
confirmConnection(clientSocket,clientConnectFuture,serverConn);
|
||||
confirmConnection(clientSocket, clientConnectFuture, serverConn);
|
||||
|
||||
// client sends close frame
|
||||
final String origCloseReason = "Normal Close";
|
||||
clientSocket.getSession().close(StatusCode.NORMAL,origCloseReason);
|
||||
clientSocket.getSession().close(StatusCode.NORMAL, origCloseReason);
|
||||
|
||||
// server receives close frame
|
||||
confirmServerReceivedCloseFrame(serverConn,StatusCode.NORMAL,is(origCloseReason));
|
||||
confirmServerReceivedCloseFrame(serverConn, StatusCode.NORMAL, is(origCloseReason));
|
||||
|
||||
// client should not have received close message (yet)
|
||||
clientSocket.assertNoCloseEvent();
|
||||
|
||||
// server shuts down connection (no frame reply)
|
||||
serverConn.disconnect();
|
||||
serverConn.abort();
|
||||
|
||||
// client reads -1 (EOF)
|
||||
// client triggers close event on client ws-endpoint
|
||||
clientSocket.assertReceivedCloseEvent(timeout,is(StatusCode.ABNORMAL),
|
||||
clientSocket.assertReceivedCloseEvent(timeout, is(StatusCode.ABNORMAL),
|
||||
anyOf(
|
||||
containsString("EOF"),
|
||||
containsString("Disconnected")
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testServerNoCloseHandshake() throws Exception
|
||||
|
@ -505,23 +504,25 @@ public class ClientCloseTest
|
|||
final int timeout = 1000;
|
||||
client.setMaxIdleTimeout(timeout);
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Client connects
|
||||
CloseTrackingSocket clientSocket = new CloseTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
|
||||
|
||||
// Server accepts connect
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
serverConn.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// client confirms connection via echo
|
||||
confirmConnection(clientSocket,clientConnectFuture,serverConn);
|
||||
confirmConnection(clientSocket, clientConnectFuture, serverConn);
|
||||
|
||||
// client sends close frame
|
||||
final String origCloseReason = "Normal Close";
|
||||
clientSocket.getSession().close(StatusCode.NORMAL,origCloseReason);
|
||||
clientSocket.getSession().close(StatusCode.NORMAL, origCloseReason);
|
||||
|
||||
// server receives close frame
|
||||
confirmServerReceivedCloseFrame(serverConn,StatusCode.NORMAL,is(origCloseReason));
|
||||
confirmServerReceivedCloseFrame(serverConn, StatusCode.NORMAL, is(origCloseReason));
|
||||
|
||||
// client should not have received close message (yet)
|
||||
clientSocket.assertNoCloseEvent();
|
||||
|
@ -533,6 +534,7 @@ public class ClientCloseTest
|
|||
assertThat("OnError Latch", clientSocket.errorLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat("OnError", clientSocket.error.get(), instanceOf(TimeoutException.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout = 5000L)
|
||||
public void testStopLifecycle() throws Exception
|
||||
|
@ -542,38 +544,59 @@ public class ClientCloseTest
|
|||
client.setMaxIdleTimeout(timeout);
|
||||
|
||||
int clientCount = 3;
|
||||
CloseTrackingSocket clientSockets[] = new CloseTrackingSocket[clientCount];
|
||||
IBlockheadServerConnection serverConns[] = new IBlockheadServerConnection[clientCount];
|
||||
List<CloseTrackingSocket> clientSockets = new ArrayList<>();
|
||||
List<CompletableFuture<BlockheadConnection>> serverConnFuts = new ArrayList<>();
|
||||
List<BlockheadConnection> serverConns = new ArrayList<>();
|
||||
|
||||
// Connect Multiple Clients
|
||||
try
|
||||
{
|
||||
// Open Multiple Clients
|
||||
for (int i = 0; i < clientCount; i++)
|
||||
{
|
||||
// Client Request Upgrade
|
||||
clientSockets[i] = new CloseTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSockets[i],server.getWsUri());
|
||||
CloseTrackingSocket clientSocket = new CloseTrackingSocket();
|
||||
clientSockets.add(clientSocket);
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket, server.getWsUri());
|
||||
|
||||
// Server accepts connection
|
||||
serverConns[i] = server.accept();
|
||||
serverConns[i].upgrade();
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
serverConnFuts.add(serverConnFut);
|
||||
server.addConnectFuture(serverConnFut);
|
||||
BlockheadConnection serverConn = serverConnFut.get();
|
||||
serverConns.add(serverConn);
|
||||
|
||||
// client confirms connection via echo
|
||||
confirmConnection(clientSockets[i],clientConnectFuture,serverConns[i]);
|
||||
confirmConnection(clientSocket, clientConnectFuture, serverConn);
|
||||
}
|
||||
|
||||
// client lifecycle stop
|
||||
// client lifecycle stop (the meat of this test)
|
||||
client.stop();
|
||||
|
||||
// clients send close frames (code 1001, shutdown)
|
||||
for (int i = 0; i < clientCount; i++)
|
||||
{
|
||||
// server receives close frame
|
||||
confirmServerReceivedCloseFrame(serverConns[i],StatusCode.SHUTDOWN,containsString("Shutdown"));
|
||||
confirmServerReceivedCloseFrame(serverConns.get(i), StatusCode.SHUTDOWN, containsString("Shutdown"));
|
||||
}
|
||||
|
||||
// clients disconnect
|
||||
for (int i = 0; i < clientCount; i++)
|
||||
{
|
||||
clientSockets[i].assertReceivedCloseEvent(timeout,is(StatusCode.SHUTDOWN),containsString("Shutdown"));
|
||||
clientSockets.get(i).assertReceivedCloseEvent(timeout, is(StatusCode.SHUTDOWN), containsString("Shutdown"));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
for(BlockheadConnection serverConn: serverConns)
|
||||
{
|
||||
try
|
||||
{
|
||||
serverConn.close();
|
||||
}
|
||||
catch (Exception ignore)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -584,16 +607,18 @@ public class ClientCloseTest
|
|||
final int timeout = 1000;
|
||||
client.setMaxIdleTimeout(timeout);
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Client connects
|
||||
CloseTrackingSocket clientSocket = new CloseTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
|
||||
|
||||
// Server accepts connect
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
serverConn.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// client confirms connection via echo
|
||||
confirmConnection(clientSocket,clientConnectFuture,serverConn);
|
||||
confirmConnection(clientSocket, clientConnectFuture, serverConn);
|
||||
|
||||
// setup client endpoint for write failure (test only)
|
||||
EndPoint endp = clientSocket.getEndPoint();
|
||||
|
@ -602,7 +627,7 @@ public class ClientCloseTest
|
|||
// client enqueue close frame
|
||||
// client write failure
|
||||
final String origCloseReason = "Normal Close";
|
||||
clientSocket.getSession().close(StatusCode.NORMAL,origCloseReason);
|
||||
clientSocket.getSession().close(StatusCode.NORMAL, origCloseReason);
|
||||
|
||||
assertThat("OnError Latch", clientSocket.errorLatch.await(2, TimeUnit.SECONDS), is(true));
|
||||
assertThat("OnError", clientSocket.error.get(), instanceOf(EofException.class));
|
||||
|
@ -610,6 +635,7 @@ public class ClientCloseTest
|
|||
// client triggers close event on client ws-endpoint
|
||||
// assert - close code==1006 (abnormal)
|
||||
// assert - close reason message contains (write failure)
|
||||
clientSocket.assertReceivedCloseEvent(timeout,is(StatusCode.ABNORMAL),containsString("EOF"));
|
||||
clientSocket.assertReceivedCloseEvent(timeout, is(StatusCode.ABNORMAL), containsString("EOF"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,29 +27,37 @@ import static org.junit.Assert.assertThat;
|
|||
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeException;
|
||||
import org.eclipse.jetty.websocket.common.AcceptHash;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -58,13 +66,9 @@ import org.junit.Test;
|
|||
@SuppressWarnings("Duplicates")
|
||||
public class ClientConnectTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
public ByteBufferPool bufferPool = new MappedByteBufferPool();
|
||||
|
||||
private final int timeout = 500;
|
||||
private BlockheadServer server;
|
||||
private static BlockheadServer server;
|
||||
private WebSocketClient client;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -93,25 +97,32 @@ public class ClientConnectTest
|
|||
{
|
||||
client = new WebSocketClient();
|
||||
client.setBufferPool(bufferPool);
|
||||
client.setConnectTimeout(timeout);
|
||||
client.setConnectTimeout(Timeouts.CONNECT_UNIT.toMillis(Timeouts.CONNECT));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void resetServerHandler()
|
||||
{
|
||||
// for each test, reset the server request handling to default
|
||||
server.resetRequestHandling();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
@ -124,12 +135,9 @@ public class ClientConnectTest
|
|||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
connection.upgrade();
|
||||
|
||||
Session sess = future.get(30,TimeUnit.SECONDS);
|
||||
|
||||
wsocket.waitForConnected(1, TimeUnit.SECONDS);
|
||||
wsocket.waitForConnected();
|
||||
|
||||
assertThat("Connect.UpgradeRequest", wsocket.connectUpgradeRequest, notNullValue());
|
||||
assertThat("Connect.UpgradeResponse", wsocket.connectUpgradeResponse, notNullValue());
|
||||
|
@ -144,21 +152,25 @@ public class ClientConnectTest
|
|||
URI wsUri = server.getWsUri();
|
||||
|
||||
HttpClient httpClient = new HttpClient();
|
||||
try
|
||||
{
|
||||
httpClient.start();
|
||||
|
||||
WebSocketUpgradeRequest req = new WebSocketUpgradeRequest(new WebSocketClient(), httpClient, wsUri, wsocket);
|
||||
req.header("X-Foo","Req");
|
||||
req.header("X-Foo", "Req");
|
||||
CompletableFuture<Session> sess = req.sendAsync();
|
||||
|
||||
sess.thenAccept((s) -> {
|
||||
System.out.printf("Session: %s%n",s);
|
||||
System.out.printf("Session: %s%n", s);
|
||||
s.close();
|
||||
assertThat("Connect.UpgradeRequest",wsocket.connectUpgradeRequest,notNullValue());
|
||||
assertThat("Connect.UpgradeResponse",wsocket.connectUpgradeResponse,notNullValue());
|
||||
assertThat("Connect.UpgradeRequest", wsocket.connectUpgradeRequest, notNullValue());
|
||||
assertThat("Connect.UpgradeResponse", wsocket.connectUpgradeResponse, notNullValue());
|
||||
});
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
connection.upgrade();
|
||||
}
|
||||
finally
|
||||
{
|
||||
httpClient.stop();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -166,26 +178,31 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
ClientUpgradeRequest upgradeRequest = new ClientUpgradeRequest();
|
||||
// actual value for this test is irrelevant, its important that this
|
||||
// header actually be sent with a value (the value specified)
|
||||
upgradeRequest.setHeader("Authorization", "Bogus SHA1");
|
||||
upgradeRequest.setHeader("Authorization", "Basic YWxhZGRpbjpvcGVuc2VzYW1l");
|
||||
Future<Session> future = client.connect(wsocket,wsUri,upgradeRequest);
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
List<String> requestLines = connection.upgrade();
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
HttpFields upgradeRequestHeaders = serverConn.getUpgradeRequestHeaders();
|
||||
|
||||
Session sess = future.get(30,TimeUnit.SECONDS);
|
||||
sess.close();
|
||||
Session sess = future.get(30, TimeUnit.SECONDS);
|
||||
|
||||
String authLine = requestLines.stream()
|
||||
.filter((line) -> line.startsWith("Authorization:"))
|
||||
.findFirst().get();
|
||||
|
||||
assertThat("Request Container Authorization", authLine, is("Authorization: Bogus SHA1"));
|
||||
HttpField authHeader = upgradeRequestHeaders.getField(HttpHeader.AUTHORIZATION);
|
||||
assertThat("Server Request Authorization Header", authHeader, is(notNullValue()));
|
||||
assertThat("Server Request Authorization Value", authHeader.getValue(), is("Basic YWxhZGRpbjpvcGVuc2VzYW1l"));
|
||||
assertThat("Connect.UpgradeRequest", wsocket.connectUpgradeRequest, notNullValue());
|
||||
assertThat("Connect.UpgradeResponse", wsocket.connectUpgradeResponse, notNullValue());
|
||||
|
||||
sess.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -193,16 +210,15 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
// Force 404 response, no upgrade for this test
|
||||
server.setRequestHandling((req, resp) -> {
|
||||
resp.setStatus(HttpServletResponse.SC_NOT_FOUND);
|
||||
return true;
|
||||
});
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
connection.readRequest();
|
||||
// no upgrade, just fail with a 404 error
|
||||
connection.respond("HTTP/1.1 404 NOT FOUND\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"\r\n");
|
||||
|
||||
// The attempt to get upgrade response future should throw error
|
||||
try
|
||||
{
|
||||
|
@ -224,16 +240,15 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
// Force 200 response, no response body content, no upgrade for this test
|
||||
server.setRequestHandling((req, resp) -> {
|
||||
resp.setStatus(HttpServletResponse.SC_OK);
|
||||
return true;
|
||||
});
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
connection.readRequest();
|
||||
// Send OK to GET but not upgrade
|
||||
connection.respond("HTTP/1.1 200 OK\r\n" +
|
||||
"Content-Length: 0\r\n" +
|
||||
"\r\n");
|
||||
|
||||
// The attempt to get upgrade response future should throw error
|
||||
try
|
||||
{
|
||||
|
@ -255,22 +270,17 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
// Force 200 response, no response body content, incomplete websocket response headers, no actual upgrade for this test
|
||||
server.setRequestHandling((req, resp) -> {
|
||||
String key = req.getHeader(HttpHeader.SEC_WEBSOCKET_KEY.toString());
|
||||
resp.setStatus(HttpServletResponse.SC_OK);
|
||||
resp.setHeader(HttpHeader.SEC_WEBSOCKET_ACCEPT.toString(), AcceptHash.hashKey(key));
|
||||
return true;
|
||||
});
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
List<String> requestLines = connection.readRequestLines();
|
||||
String key = connection.parseWebSocketKey(requestLines);
|
||||
|
||||
// Send OK to GET but not upgrade
|
||||
StringBuilder resp = new StringBuilder();
|
||||
resp.append("HTTP/1.1 200 OK\r\n"); // intentionally 200 (not 101)
|
||||
// Include a value accept key
|
||||
resp.append("Sec-WebSocket-Accept: ").append(AcceptHash.hashKey(key)).append("\r\n");
|
||||
resp.append("Content-Length: 0\r\n");
|
||||
resp.append("\r\n");
|
||||
connection.respond(resp.toString());
|
||||
|
||||
// The attempt to get upgrade response future should throw error
|
||||
try
|
||||
{
|
||||
|
@ -292,21 +302,18 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
// Force 101 response, with invalid Connection header, invalid handshake
|
||||
server.setRequestHandling((req, resp) -> {
|
||||
String key = req.getHeader(HttpHeader.SEC_WEBSOCKET_KEY.toString());
|
||||
resp.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
|
||||
resp.setHeader(HttpHeader.CONNECTION.toString(), "close");
|
||||
resp.setHeader(HttpHeader.SEC_WEBSOCKET_ACCEPT.toString(), AcceptHash.hashKey(key));
|
||||
return true;
|
||||
});
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
List<String> requestLines = connection.readRequestLines();
|
||||
String key = connection.parseWebSocketKey(requestLines);
|
||||
|
||||
// Send Switching Protocols 101, but invalid 'Connection' header
|
||||
StringBuilder resp = new StringBuilder();
|
||||
resp.append("HTTP/1.1 101 Switching Protocols\r\n");
|
||||
resp.append("Sec-WebSocket-Accept: ").append(AcceptHash.hashKey(key)).append("\r\n");
|
||||
resp.append("Connection: close\r\n");
|
||||
resp.append("\r\n");
|
||||
connection.respond(resp.toString());
|
||||
|
||||
// The attempt to get upgrade response future should throw error
|
||||
try
|
||||
{
|
||||
|
@ -328,21 +335,18 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
// Force 101 response, with no Connection header, invalid handshake
|
||||
server.setRequestHandling((req, resp) -> {
|
||||
String key = req.getHeader(HttpHeader.SEC_WEBSOCKET_KEY.toString());
|
||||
resp.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
|
||||
// Intentionally leave out Connection header
|
||||
resp.setHeader(HttpHeader.SEC_WEBSOCKET_ACCEPT.toString(), AcceptHash.hashKey(key));
|
||||
return true;
|
||||
});
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
List<String> requestLines = connection.readRequestLines();
|
||||
String key = connection.parseWebSocketKey(requestLines);
|
||||
|
||||
// Send Switching Protocols 101, but no 'Connection' header
|
||||
StringBuilder resp = new StringBuilder();
|
||||
resp.append("HTTP/1.1 101 Switching Protocols\r\n");
|
||||
resp.append("Sec-WebSocket-Accept: ").append(AcceptHash.hashKey(key)).append("\r\n");
|
||||
// Intentionally leave out Connection header
|
||||
resp.append("\r\n");
|
||||
connection.respond(resp.toString());
|
||||
|
||||
// The attempt to get upgrade response future should throw error
|
||||
try
|
||||
{
|
||||
|
@ -364,14 +368,16 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
// Force 101 response, with invalid response accept header
|
||||
server.setRequestHandling((req, resp) -> {
|
||||
resp.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
|
||||
resp.setHeader(HttpHeader.SEC_WEBSOCKET_ACCEPT.toString(), "rubbish");
|
||||
return true;
|
||||
});
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection connection = server.accept();
|
||||
connection.readRequest();
|
||||
// Upgrade badly
|
||||
connection.respond("HTTP/1.1 101 Upgrade\r\n" + "Sec-WebSocket-Accept: rubbish\r\n" + "\r\n");
|
||||
|
||||
// The attempt to get upgrade response future should throw error
|
||||
try
|
||||
{
|
||||
|
@ -393,20 +399,26 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
try(ServerSocket serverSocket = new ServerSocket())
|
||||
{
|
||||
InetAddress addr = InetAddress.getByName("localhost");
|
||||
InetSocketAddress endpoint = new InetSocketAddress(addr, 0);
|
||||
serverSocket.bind(endpoint, 1);
|
||||
int port = serverSocket.getLocalPort();
|
||||
URI wsUri = URI.create(String.format("ws://%s:%d/", addr.getHostAddress(), port));
|
||||
Future<Session> future = client.connect(wsocket, wsUri);
|
||||
|
||||
// Intentionally not accept incoming socket.
|
||||
// server.accept();
|
||||
// serverSocket.accept();
|
||||
|
||||
try
|
||||
{
|
||||
future.get(3,TimeUnit.SECONDS);
|
||||
future.get(3, TimeUnit.SECONDS);
|
||||
Assert.fail("Should have Timed Out");
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
assertExpectedError(e,wsocket,instanceOf(UpgradeException.class));
|
||||
assertExpectedError(e, wsocket, instanceOf(UpgradeException.class));
|
||||
// Possible Passing Path (active session wait timeout)
|
||||
wsocket.assertNotOpened();
|
||||
}
|
||||
|
@ -416,6 +428,7 @@ public class ClientConnectTest
|
|||
wsocket.assertNotOpened();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionRefused() throws Exception
|
||||
|
@ -454,24 +467,29 @@ public class ClientConnectTest
|
|||
{
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
try(ServerSocket serverSocket = new ServerSocket())
|
||||
{
|
||||
InetAddress addr = InetAddress.getByName("localhost");
|
||||
InetSocketAddress endpoint = new InetSocketAddress(addr, 0);
|
||||
serverSocket.bind(endpoint, 1);
|
||||
int port = serverSocket.getLocalPort();
|
||||
URI wsUri = URI.create(String.format("ws://%s:%d/", addr.getHostAddress(), port));
|
||||
Future<Session> future = client.connect(wsocket, wsUri);
|
||||
|
||||
IBlockheadServerConnection ssocket = server.accept();
|
||||
Assert.assertNotNull(ssocket);
|
||||
// Intentionally don't upgrade
|
||||
// ssocket.upgrade();
|
||||
// Accept the connection, but do nothing on it (no response, no upgrade, etc)
|
||||
serverSocket.accept();
|
||||
|
||||
// The attempt to get upgrade response future should throw error
|
||||
try
|
||||
{
|
||||
future.get(3,TimeUnit.SECONDS);
|
||||
future.get(3, TimeUnit.SECONDS);
|
||||
Assert.fail("Expected ExecutionException -> TimeoutException");
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
// Expected path - java.net.ConnectException ?
|
||||
assertExpectedError(e,wsocket,instanceOf(ConnectException.class));
|
||||
assertExpectedError(e, wsocket, instanceOf(ConnectException.class));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,17 +24,12 @@ import java.net.InetSocketAddress;
|
|||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.websocket.client.io.ConnectionManager;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
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);
|
||||
|
|
|
@ -19,32 +19,36 @@
|
|||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.net.CookieManager;
|
||||
import java.net.HttpCookie;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
import org.eclipse.jetty.websocket.api.util.QuoteUtil;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class CookieTest
|
||||
|
@ -53,8 +57,8 @@ public class CookieTest
|
|||
|
||||
public static class CookieTrackingSocket extends WebSocketAdapter
|
||||
{
|
||||
public EventQueue<String> messageQueue = new EventQueue<>();
|
||||
public EventQueue<Throwable> errorQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
|
||||
public LinkedBlockingQueue<Throwable> errorQueue = new LinkedBlockingQueue<>();
|
||||
private CountDownLatch openLatch = new CountDownLatch(1);
|
||||
|
||||
@Override
|
||||
|
@ -84,8 +88,8 @@ public class CookieTest
|
|||
}
|
||||
}
|
||||
|
||||
private static BlockheadServer server;
|
||||
private WebSocketClient client;
|
||||
private BlockheadServer server;
|
||||
|
||||
@Before
|
||||
public void startClient() throws Exception
|
||||
|
@ -94,8 +98,8 @@ public class CookieTest
|
|||
client.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
|
@ -110,8 +114,8 @@ public class CookieTest
|
|||
}
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
@ -133,18 +137,22 @@ public class CookieTest
|
|||
cookie.setMaxAge(100000);
|
||||
cookieMgr.getCookieStore().add(server.getWsUri(),cookie);
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Client connects
|
||||
CookieTrackingSocket clientSocket = new CookieTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri());
|
||||
|
||||
// Server accepts connect
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// client confirms upgrade and receipt of frame
|
||||
String serverCookies = confirmClientUpgradeAndCookies(clientSocket,clientConnectFuture,serverConn);
|
||||
String serverCookies = confirmClientUpgradeAndCookies(clientSocket, clientConnectFuture, serverConn);
|
||||
|
||||
assertThat("Cookies seen at server side",serverCookies,containsString("hello=world"));
|
||||
assertThat("Cookies seen at server side",serverCookies,containsString("foo=bar is the word"));
|
||||
assertThat("Cookies seen at server side", serverCookies, containsString("hello=world"));
|
||||
assertThat("Cookies seen at server side", serverCookies, containsString("foo=bar is the word"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -158,53 +166,46 @@ public class CookieTest
|
|||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
request.setCookies(Collections.singletonList(cookie));
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Client connects
|
||||
CookieTrackingSocket clientSocket = new CookieTrackingSocket();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,server.getWsUri(),request);
|
||||
|
||||
// Server accepts connect
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// client confirms upgrade and receipt of frame
|
||||
String serverCookies = confirmClientUpgradeAndCookies(clientSocket,clientConnectFuture,serverConn);
|
||||
String serverCookies = confirmClientUpgradeAndCookies(clientSocket, clientConnectFuture, serverConn);
|
||||
|
||||
Assert.assertThat("Cookies seen at server side",serverCookies,containsString("hello=world"));
|
||||
Assert.assertThat("Cookies seen at server side", serverCookies, containsString("hello=world"));
|
||||
}
|
||||
}
|
||||
|
||||
private String confirmClientUpgradeAndCookies(CookieTrackingSocket clientSocket, Future<Session> clientConnectFuture, IBlockheadServerConnection serverConn)
|
||||
private String confirmClientUpgradeAndCookies(CookieTrackingSocket clientSocket, Future<Session> clientConnectFuture, BlockheadConnection serverConn)
|
||||
throws Exception
|
||||
{
|
||||
// Server upgrades
|
||||
List<String> upgradeRequestLines = serverConn.upgrade();
|
||||
List<String> upgradeRequestCookies = serverConn.regexFind(upgradeRequestLines,"^Cookie: (.*)$");
|
||||
// Server side upgrade information
|
||||
HttpFields upgradeRequestHeaders = serverConn.getUpgradeRequestHeaders();
|
||||
HttpField cookieField = upgradeRequestHeaders.getField(HttpHeader.COOKIE);
|
||||
|
||||
// Server responds with cookies it knows about
|
||||
TextFrame serverCookieFrame = new TextFrame();
|
||||
serverCookieFrame.setFin(true);
|
||||
serverCookieFrame.setPayload(QuoteUtil.join(upgradeRequestCookies,","));
|
||||
serverCookieFrame.setPayload(cookieField.getValue());
|
||||
serverConn.write(serverCookieFrame);
|
||||
serverConn.flush();
|
||||
|
||||
// Confirm client connect on future
|
||||
clientConnectFuture.get(10,TimeUnit.SECONDS);
|
||||
clientSocket.awaitOpen(2,TimeUnit.SECONDS);
|
||||
|
||||
try
|
||||
{
|
||||
// Wait for client receipt of cookie frame via client websocket
|
||||
clientSocket.messageQueue.awaitEventCount(1, 3, TimeUnit.SECONDS);
|
||||
}
|
||||
catch (TimeoutException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
assertThat("Message Count", clientSocket.messageQueue.size(), is(1));
|
||||
}
|
||||
|
||||
String cookies = clientSocket.messageQueue.poll();
|
||||
String cookies = clientSocket.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
LOG.debug("Cookies seen at server: {}",cookies);
|
||||
|
||||
// Server closes connection
|
||||
serverConn.close(StatusCode.NORMAL);
|
||||
serverConn.write(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
return cookies;
|
||||
}
|
||||
|
|
|
@ -25,16 +25,16 @@ import static org.junit.Assert.assertThat;
|
|||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Exchanger;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
@ -52,8 +52,8 @@ public class JettyTrackingSocket extends WebSocketAdapter
|
|||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
public CountDownLatch dataLatch = new CountDownLatch(1);
|
||||
public EventQueue<String> messageQueue = new EventQueue<>();
|
||||
public EventQueue<Throwable> errorQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
|
||||
public LinkedBlockingQueue<Throwable> errorQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
public void assertClose(int expectedStatusCode, String expectedReason) throws InterruptedException
|
||||
{
|
||||
|
@ -78,12 +78,6 @@ public class JettyTrackingSocket extends WebSocketAdapter
|
|||
assertNotClosed();
|
||||
}
|
||||
|
||||
public void assertMessage(String expected)
|
||||
{
|
||||
String actual = messageQueue.poll();
|
||||
Assert.assertEquals("Message",expected,actual);
|
||||
}
|
||||
|
||||
public void assertNotClosed()
|
||||
{
|
||||
LOG.debug("assertNotClosed() - {}", closeLatch.getCount());
|
||||
|
@ -102,11 +96,6 @@ public class JettyTrackingSocket extends WebSocketAdapter
|
|||
Assert.assertThat("Was Opened",openLatch.await(30,TimeUnit.SECONDS),is(true));
|
||||
}
|
||||
|
||||
public void awaitMessage(int expectedMessageCount, TimeUnit timeoutUnit, int timeoutDuration) throws TimeoutException, InterruptedException
|
||||
{
|
||||
messageQueue.awaitEventCount(expectedMessageCount,timeoutDuration,timeoutUnit);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
messageQueue.clear();
|
||||
|
@ -171,9 +160,9 @@ public class JettyTrackingSocket extends WebSocketAdapter
|
|||
Assert.assertThat("Client Socket Closed",closeLatch.await(timeoutDuration,timeoutUnit),is(true));
|
||||
}
|
||||
|
||||
public void waitForConnected(int timeoutDuration, TimeUnit timeoutUnit) throws InterruptedException
|
||||
public void waitForConnected() throws InterruptedException
|
||||
{
|
||||
Assert.assertThat("Client Socket Connected",openLatch.await(timeoutDuration,timeoutUnit),is(true));
|
||||
Assert.assertThat("Client Socket Connected",openLatch.await(Timeouts.CONNECT,Timeouts.CONNECT_UNIT),is(true));
|
||||
}
|
||||
|
||||
public void waitForMessage(int timeoutDuration, TimeUnit timeoutUnit) throws InterruptedException
|
||||
|
|
|
@ -21,9 +21,9 @@ package org.eclipse.jetty.websocket.client;
|
|||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
|
@ -42,8 +42,8 @@ public class MaxMessageSocket
|
|||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
public CountDownLatch dataLatch = new CountDownLatch(1);
|
||||
public EventQueue<String> messageQueue = new EventQueue<>();
|
||||
public EventQueue<Throwable> errorQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
|
||||
public LinkedBlockingQueue<Throwable> errorQueue = new LinkedBlockingQueue<>();
|
||||
public int closeCode = -1;
|
||||
public StringBuilder closeMessage = new StringBuilder();
|
||||
|
||||
|
|
|
@ -1,132 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
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.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class ServerReadThread extends Thread
|
||||
{
|
||||
private static final int BUFFER_SIZE = 8192;
|
||||
private static final Logger LOG = Log.getLogger(ServerReadThread.class);
|
||||
private final IBlockheadServerConnection conn;
|
||||
private boolean active = true;
|
||||
private int slowness = -1; // disabled is default
|
||||
private final AtomicInteger frameCount = new AtomicInteger();
|
||||
private final CountDownLatch expectedMessageCount;
|
||||
|
||||
public ServerReadThread(IBlockheadServerConnection sconnection, int expectedMessages)
|
||||
{
|
||||
this.conn = sconnection;
|
||||
this.expectedMessageCount = new CountDownLatch(expectedMessages);
|
||||
}
|
||||
|
||||
public void cancel()
|
||||
{
|
||||
active = false;
|
||||
}
|
||||
|
||||
public int getFrameCount()
|
||||
{
|
||||
return frameCount.get();
|
||||
}
|
||||
|
||||
public int getSlowness()
|
||||
{
|
||||
return slowness;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
ByteBufferPool bufferPool = conn.getBufferPool();
|
||||
ByteBuffer buf = bufferPool.acquire(BUFFER_SIZE,false);
|
||||
BufferUtil.clearToFill(buf);
|
||||
|
||||
try
|
||||
{
|
||||
while (active)
|
||||
{
|
||||
BufferUtil.clearToFill(buf);
|
||||
int len = conn.read(buf);
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
LOG.debug("Read {} bytes",len);
|
||||
BufferUtil.flipToFlush(buf,0);
|
||||
conn.getParser().parse(buf);
|
||||
}
|
||||
|
||||
Queue<WebSocketFrame> frames = conn.getIncomingFrames().getFrames();
|
||||
WebSocketFrame frame;
|
||||
while ((frame = frames.poll()) != null)
|
||||
{
|
||||
frameCount.incrementAndGet();
|
||||
if (frame.getOpCode() == OpCode.CLOSE)
|
||||
{
|
||||
active = false;
|
||||
// automatically response to close frame
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
conn.close(close.getStatusCode());
|
||||
}
|
||||
|
||||
expectedMessageCount.countDown();
|
||||
}
|
||||
if (slowness > 0)
|
||||
{
|
||||
TimeUnit.MILLISECONDS.sleep(getSlowness());
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException | InterruptedException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
bufferPool.release(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public void setSlowness(int slowness)
|
||||
{
|
||||
this.slowness = slowness;
|
||||
}
|
||||
|
||||
public void waitForExpectedMessageCount(int timeoutDuration, TimeUnit timeoutUnit) throws InterruptedException
|
||||
{
|
||||
Assert.assertThat("Expected Message Count attained",expectedMessageCount.await(timeoutDuration,timeoutUnit),is(true));
|
||||
}
|
||||
}
|
|
@ -18,24 +18,23 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
|
||||
public class ServerWriteThread extends Thread
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ServerWriteThread.class);
|
||||
private final IBlockheadServerConnection conn;
|
||||
private final BlockheadConnection conn;
|
||||
private int slowness = -1;
|
||||
private int messageCount = 100;
|
||||
private String message = "Hello";
|
||||
|
||||
public ServerWriteThread(IBlockheadServerConnection conn)
|
||||
public ServerWriteThread(BlockheadConnection conn)
|
||||
{
|
||||
this.conn = conn;
|
||||
}
|
||||
|
@ -74,7 +73,7 @@ public class ServerWriteThread extends Thread
|
|||
}
|
||||
}
|
||||
}
|
||||
catch (InterruptedException | IOException e)
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
|
|
|
@ -18,39 +18,45 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.junit.After;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SessionTest
|
||||
{
|
||||
private BlockheadServer server;
|
||||
private static BlockheadServer server;
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
@ -65,6 +71,10 @@ public class SessionTest
|
|||
{
|
||||
JettyTrackingSocket cliSock = new JettyTrackingSocket();
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
client.getPolicy().setIdleTimeout(10000);
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
|
@ -72,20 +82,25 @@ public class SessionTest
|
|||
request.setSubProtocols("echo");
|
||||
Future<Session> future = client.connect(cliSock,wsUri,request);
|
||||
|
||||
final IBlockheadServerConnection srvSock = server.accept();
|
||||
srvSock.upgrade();
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Setup echo of frames on server side
|
||||
serverConn.setIncomingFrameConsumer((frame)->{
|
||||
WebSocketFrame copy = WebSocketFrame.copy(frame);
|
||||
serverConn.write(copy);
|
||||
});
|
||||
|
||||
Session sess = future.get(30000,TimeUnit.MILLISECONDS);
|
||||
Assert.assertThat("Session",sess,notNullValue());
|
||||
Assert.assertThat("Session.open",sess.isOpen(),is(true));
|
||||
Assert.assertThat("Session.upgradeRequest",sess.getUpgradeRequest(),notNullValue());
|
||||
Assert.assertThat("Session.upgradeResponse",sess.getUpgradeResponse(),notNullValue());
|
||||
Session sess = future.get(30000, TimeUnit.MILLISECONDS);
|
||||
Assert.assertThat("Session", sess, notNullValue());
|
||||
Assert.assertThat("Session.open", sess.isOpen(), is(true));
|
||||
Assert.assertThat("Session.upgradeRequest", sess.getUpgradeRequest(), notNullValue());
|
||||
Assert.assertThat("Session.upgradeResponse", sess.getUpgradeResponse(), notNullValue());
|
||||
|
||||
cliSock.assertWasOpened();
|
||||
cliSock.assertNotClosed();
|
||||
|
||||
Collection<WebSocketSession> sessions = client.getBeans(WebSocketSession.class);
|
||||
Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
|
||||
Assert.assertThat("client.connectionManager.sessions.size", sessions.size(), is(1));
|
||||
|
||||
RemoteEndpoint remote = cliSock.getSession().getRemote();
|
||||
remote.sendStringByFuture("Hello World!");
|
||||
|
@ -93,19 +108,22 @@ public class SessionTest
|
|||
{
|
||||
remote.flush();
|
||||
}
|
||||
srvSock.echoMessage(1,30000,TimeUnit.MILLISECONDS);
|
||||
|
||||
// wait for response from server
|
||||
cliSock.waitForMessage(30000,TimeUnit.MILLISECONDS);
|
||||
cliSock.waitForMessage(30000, TimeUnit.MILLISECONDS);
|
||||
|
||||
Set<WebSocketSession> open = client.getOpenSessions();
|
||||
Assert.assertThat("(Before Close) Open Sessions.size", open.size(), is(1));
|
||||
|
||||
cliSock.assertMessage("Hello World!");
|
||||
cliSock.close();
|
||||
srvSock.close();
|
||||
String received = cliSock.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Message", received, containsString("Hello World!"));
|
||||
|
||||
cliSock.close();
|
||||
}
|
||||
|
||||
cliSock.waitForClose(30000, TimeUnit.MILLISECONDS);
|
||||
Set<WebSocketSession> open = client.getOpenSessions();
|
||||
|
||||
cliSock.waitForClose(30000,TimeUnit.MILLISECONDS);
|
||||
open = client.getOpenSessions();
|
||||
// TODO this sometimes fails!
|
||||
Assert.assertThat("(After Close) Open Sessions.size", open.size(), is(0));
|
||||
}
|
||||
|
|
|
@ -18,30 +18,33 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
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.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class SlowClientTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private static BlockheadServer server;
|
||||
private WebSocketClient client;
|
||||
|
||||
@Before
|
||||
|
@ -52,8 +55,8 @@ public class SlowClientTest
|
|||
client.start();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
|
@ -65,14 +68,13 @@ public class SlowClientTest
|
|||
client.stop();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Slow
|
||||
public void testClientSlowToSend() throws Exception
|
||||
{
|
||||
JettyTrackingSocket tsocket = new JettyTrackingSocket();
|
||||
|
@ -81,20 +83,17 @@ public class SlowClientTest
|
|||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(tsocket, wsUri);
|
||||
|
||||
IBlockheadServerConnection sconnection = server.accept();
|
||||
sconnection.setSoTimeout(60000);
|
||||
sconnection.upgrade();
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Confirm connected
|
||||
future.get(30,TimeUnit.SECONDS);
|
||||
tsocket.waitForConnected(30,TimeUnit.SECONDS);
|
||||
future.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
tsocket.waitForConnected();
|
||||
|
||||
int messageCount = 10;
|
||||
|
||||
// Setup server read thread
|
||||
ServerReadThread reader = new ServerReadThread(sconnection, messageCount);
|
||||
reader.start();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Have client write slowly.
|
||||
ClientWriteThread writer = new ClientWriteThread(tsocket.getSession());
|
||||
writer.setMessageCount(messageCount);
|
||||
|
@ -103,17 +102,31 @@ public class SlowClientTest
|
|||
writer.start();
|
||||
writer.join();
|
||||
|
||||
reader.waitForExpectedMessageCount(1, TimeUnit.MINUTES);
|
||||
LinkedBlockingQueue<WebSocketFrame> serverFrames = serverConn.getFrameQueue();
|
||||
|
||||
// Verify receive
|
||||
Assert.assertThat("Frame Receive Count", reader.getFrameCount(), is(messageCount));
|
||||
for (int i = 0; i < messageCount; i++)
|
||||
{
|
||||
WebSocketFrame serverFrame = serverFrames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
String prefix = "Server frame[" + i + "]";
|
||||
assertThat(prefix + ".opcode", serverFrame.getOpCode(), is(OpCode.TEXT));
|
||||
assertThat(prefix + ".payload", serverFrame.getPayloadAsUTF8(), is("Hello/" + i + "/"));
|
||||
}
|
||||
|
||||
// Close
|
||||
tsocket.getSession().close(StatusCode.NORMAL, "Done");
|
||||
|
||||
// confirm close received on server
|
||||
WebSocketFrame serverFrame = serverFrames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("close frame", serverFrame.getOpCode(), is(OpCode.CLOSE));
|
||||
CloseInfo closeInfo = new CloseInfo(serverFrame);
|
||||
assertThat("close info", closeInfo.getStatusCode(), is(StatusCode.NORMAL));
|
||||
WebSocketFrame respClose = WebSocketFrame.copy(serverFrame);
|
||||
respClose.setMask(null); // remove client mask (if present)
|
||||
serverConn.write(respClose);
|
||||
|
||||
// Verify server response
|
||||
Assert.assertTrue("Client Socket Closed", tsocket.closeLatch.await(3, TimeUnit.MINUTES));
|
||||
tsocket.assertCloseCode(StatusCode.NORMAL);
|
||||
|
||||
reader.cancel(); // stop reading
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,31 +19,28 @@
|
|||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
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.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.client.masks.ZeroMasker;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
@Ignore("TODO: Flappy Test")
|
||||
public class SlowServerTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private BlockheadServer server;
|
||||
private WebSocketClient client;
|
||||
|
||||
|
@ -75,31 +72,37 @@ public class SlowServerTest
|
|||
}
|
||||
|
||||
@Test
|
||||
@Slow
|
||||
public void testServerSlowToRead() throws Exception
|
||||
{
|
||||
JettyTrackingSocket tsocket = new JettyTrackingSocket();
|
||||
client.setMasker(new ZeroMasker());
|
||||
client.setMaxIdleTimeout(60000);
|
||||
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(tsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection sconnection = server.accept();
|
||||
sconnection.setSoTimeout(60000);
|
||||
sconnection.upgrade();
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// slow down reads
|
||||
serverConn.setIncomingFrameConsumer((frame)-> {
|
||||
try
|
||||
{
|
||||
TimeUnit.MILLISECONDS.sleep(100);
|
||||
}
|
||||
catch (InterruptedException ignore)
|
||||
{
|
||||
}
|
||||
});
|
||||
|
||||
// Confirm connected
|
||||
future.get(30,TimeUnit.SECONDS);
|
||||
tsocket.waitForConnected(30,TimeUnit.SECONDS);
|
||||
future.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
tsocket.waitForConnected();
|
||||
|
||||
int messageCount = 10;
|
||||
|
||||
// Setup slow server read thread
|
||||
ServerReadThread reader = new ServerReadThread(sconnection, messageCount);
|
||||
reader.setSlowness(100); // slow it down
|
||||
reader.start();
|
||||
|
||||
// Have client write as quickly as it can.
|
||||
ClientWriteThread writer = new ClientWriteThread(tsocket.getSession());
|
||||
writer.setMessageCount(messageCount);
|
||||
|
@ -109,36 +112,35 @@ public class SlowServerTest
|
|||
writer.join();
|
||||
|
||||
// Verify receive
|
||||
reader.waitForExpectedMessageCount(10,TimeUnit.SECONDS);
|
||||
Assert.assertThat("Frame Receive Count",reader.getFrameCount(),is(messageCount));
|
||||
|
||||
// Close
|
||||
tsocket.getSession().close(StatusCode.NORMAL,"Done");
|
||||
|
||||
Assert.assertTrue("Client Socket Closed",tsocket.closeLatch.await(10,TimeUnit.SECONDS));
|
||||
tsocket.assertCloseCode(StatusCode.NORMAL);
|
||||
|
||||
reader.cancel(); // stop reading
|
||||
LinkedBlockingQueue<WebSocketFrame> serverFrames = serverConn.getFrameQueue();
|
||||
for(int i=0; i< messageCount; i++)
|
||||
{
|
||||
WebSocketFrame serverFrame = serverFrames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
String prefix = "Server Frame[" + i + "]";
|
||||
Assert.assertThat(prefix, serverFrame, is(notNullValue()));
|
||||
Assert.assertThat(prefix + ".opCode", serverFrame.getOpCode(), is(OpCode.TEXT));
|
||||
Assert.assertThat(prefix + ".payload", serverFrame.getPayloadAsUTF8(), is("Hello/" + i + "/"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Slow
|
||||
public void testServerSlowToSend() throws Exception
|
||||
{
|
||||
JettyTrackingSocket clientSocket = new JettyTrackingSocket();
|
||||
client.setMasker(new ZeroMasker());
|
||||
client.setMaxIdleTimeout(60000);
|
||||
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> clientConnectFuture = client.connect(clientSocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection serverConn = server.accept();
|
||||
serverConn.setSoTimeout(60000);
|
||||
serverConn.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Confirm connected
|
||||
clientConnectFuture.get(30,TimeUnit.SECONDS);
|
||||
clientSocket.waitForConnected(30,TimeUnit.SECONDS);
|
||||
clientConnectFuture.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
clientSocket.waitForConnected();
|
||||
|
||||
// Have server write slowly.
|
||||
int messageCount = 1000;
|
||||
|
@ -151,12 +153,7 @@ public class SlowServerTest
|
|||
writer.join();
|
||||
|
||||
// Verify receive
|
||||
Assert.assertThat("Message Receive Count",clientSocket.messageQueue.size(),is(messageCount));
|
||||
|
||||
// Close
|
||||
serverConn.close(StatusCode.NORMAL);
|
||||
|
||||
Assert.assertTrue("Client Socket Closed",clientSocket.closeLatch.await(10,TimeUnit.SECONDS));
|
||||
clientSocket.assertCloseCode(StatusCode.NORMAL);
|
||||
Assert.assertThat("Message Receive Count", clientSocket.messageQueue.size(), is(messageCount));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,19 @@ package org.eclipse.jetty.websocket.client;
|
|||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TomcatServerQuirksTest
|
||||
|
@ -59,6 +63,21 @@ public class TomcatServerQuirksTest
|
|||
}
|
||||
}
|
||||
|
||||
private static BlockheadServer server;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for when encountering a "Transfer-Encoding: chunked" on a Upgrade Response header.
|
||||
* <ul>
|
||||
|
@ -71,57 +90,55 @@ public class TomcatServerQuirksTest
|
|||
@Test
|
||||
public void testTomcat7_0_32_WithTransferEncoding() throws Exception
|
||||
{
|
||||
BlockheadServer server = new BlockheadServer();
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
|
||||
server.setRequestHandling((req, resp) -> {
|
||||
// Add the extra problematic header that triggers bug found in jetty-io
|
||||
resp.setHeader("Transfer-Encoding", "chunked");
|
||||
return false;
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
final int bufferSize = 512;
|
||||
|
||||
server.start();
|
||||
|
||||
// Setup Client Factory
|
||||
client.start();
|
||||
|
||||
// Create End User WebSocket Class
|
||||
LatchedSocket websocket = new LatchedSocket();
|
||||
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
// Open connection
|
||||
URI wsURI = server.getWsUri();
|
||||
client.connect(websocket,wsURI);
|
||||
|
||||
// Accept incoming connection
|
||||
IBlockheadServerConnection socket = server.accept();
|
||||
socket.setSoTimeout(2000); // timeout
|
||||
|
||||
// Issue upgrade
|
||||
// Add the extra problematic header that triggers bug found in jetty-io
|
||||
socket.addResponseHeader("Transfer-Encoding","chunked");
|
||||
socket.upgrade();
|
||||
|
||||
// Wait for proper upgrade
|
||||
Assert.assertTrue("Timed out waiting for Client side WebSocket open event",websocket.openLatch.await(1,TimeUnit.SECONDS));
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Have server write frame.
|
||||
byte payload[] = new byte[bufferSize / 2];
|
||||
Arrays.fill(payload,(byte)'x');
|
||||
Arrays.fill(payload, (byte) 'x');
|
||||
ByteBuffer serverFrame = BufferUtil.allocate(bufferSize);
|
||||
BufferUtil.flipToFill(serverFrame);
|
||||
serverFrame.put((byte)(0x80 | 0x01)); // FIN + TEXT
|
||||
serverFrame.put((byte)0x7E); // No MASK and 2 bytes length
|
||||
serverFrame.put((byte)(payload.length >> 8)); // first length byte
|
||||
serverFrame.put((byte)(payload.length & 0xFF)); // second length byte
|
||||
serverFrame.put((byte) (0x80 | 0x01)); // FIN + TEXT
|
||||
serverFrame.put((byte) 0x7E); // No MASK and 2 bytes length
|
||||
serverFrame.put((byte) (payload.length >> 8)); // first length byte
|
||||
serverFrame.put((byte) (payload.length & 0xFF)); // second length byte
|
||||
serverFrame.put(payload);
|
||||
BufferUtil.flipToFlush(serverFrame,0);
|
||||
socket.write(serverFrame);
|
||||
socket.flush();
|
||||
BufferUtil.flipToFlush(serverFrame, 0);
|
||||
serverConn.writeRaw(serverFrame);
|
||||
}
|
||||
|
||||
Assert.assertTrue(websocket.dataLatch.await(1000,TimeUnit.SECONDS));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
server.stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,9 @@ 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;
|
||||
|
@ -56,9 +54,6 @@ public class WebSocketClientBadUriTest
|
|||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private WebSocketClient client;
|
||||
private final String uriStr;
|
||||
private final URI uri;
|
||||
|
|
|
@ -18,56 +18,73 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.client;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.URI;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.io.FutureWriteCallback;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadServer;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class WebSocketClientTest
|
||||
{
|
||||
private BlockheadServer server;
|
||||
private static BlockheadServer server;
|
||||
private WebSocketClient client;
|
||||
|
||||
@Before
|
||||
public void startClientServer() throws Exception
|
||||
public void startClient() throws Exception
|
||||
{
|
||||
client = new WebSocketClient();
|
||||
client.start();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
{
|
||||
server = new BlockheadServer();
|
||||
server.getPolicy().setMaxTextMessageSize(200 * 1024);
|
||||
server.getPolicy().setMaxBinaryMessageSize(200 * 1024);
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopClientServer() throws Exception
|
||||
public void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer() throws Exception
|
||||
{
|
||||
server.stop();
|
||||
}
|
||||
|
||||
|
@ -94,35 +111,45 @@ public class WebSocketClientTest
|
|||
|
||||
client.getPolicy().setIdleTimeout(10000);
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
request.setSubProtocols("echo");
|
||||
Future<Session> future = client.connect(cliSock,wsUri,request);
|
||||
|
||||
final IBlockheadServerConnection srvSock = server.accept();
|
||||
srvSock.upgrade();
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Setup echo of frames on server side
|
||||
serverConn.setIncomingFrameConsumer((frame)->{
|
||||
WebSocketFrame copy = WebSocketFrame.copy(frame);
|
||||
copy.setMask(null); // strip client mask (if present)
|
||||
serverConn.write(copy);
|
||||
});
|
||||
|
||||
Session sess = future.get(30,TimeUnit.SECONDS);
|
||||
Assert.assertThat("Session",sess,notNullValue());
|
||||
Assert.assertThat("Session.open",sess.isOpen(),is(true));
|
||||
Assert.assertThat("Session.upgradeRequest",sess.getUpgradeRequest(),notNullValue());
|
||||
Assert.assertThat("Session.upgradeResponse",sess.getUpgradeResponse(),notNullValue());
|
||||
assertThat("Session",sess,notNullValue());
|
||||
assertThat("Session.open",sess.isOpen(),is(true));
|
||||
assertThat("Session.upgradeRequest",sess.getUpgradeRequest(),notNullValue());
|
||||
assertThat("Session.upgradeResponse",sess.getUpgradeResponse(),notNullValue());
|
||||
|
||||
cliSock.assertWasOpened();
|
||||
cliSock.assertNotClosed();
|
||||
|
||||
Collection<WebSocketSession> sessions = client.getOpenSessions();
|
||||
Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
|
||||
assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
|
||||
|
||||
RemoteEndpoint remote = cliSock.getSession().getRemote();
|
||||
remote.sendStringByFuture("Hello World!");
|
||||
if (remote.getBatchMode() == BatchMode.ON)
|
||||
remote.flush();
|
||||
srvSock.echoMessage(1,30,TimeUnit.SECONDS);
|
||||
// wait for response from server
|
||||
cliSock.waitForMessage(30,TimeUnit.SECONDS);
|
||||
|
||||
cliSock.assertMessage("Hello World!");
|
||||
// wait for response from server
|
||||
String received = cliSock.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Message", received, containsString("Hello World"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -131,58 +158,65 @@ public class WebSocketClientTest
|
|||
client.setMaxIdleTimeout(160000);
|
||||
JettyTrackingSocket cliSock = new JettyTrackingSocket();
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
request.setSubProtocols("echo");
|
||||
Future<Session> future = client.connect(cliSock,wsUri,request);
|
||||
|
||||
final IBlockheadServerConnection srvSock = server.accept();
|
||||
srvSock.upgrade();
|
||||
|
||||
Session sess = future.get(30,TimeUnit.SECONDS);
|
||||
Assert.assertThat("Session",sess,notNullValue());
|
||||
Assert.assertThat("Session.open",sess.isOpen(),is(true));
|
||||
Assert.assertThat("Session.upgradeRequest",sess.getUpgradeRequest(),notNullValue());
|
||||
Assert.assertThat("Session.upgradeResponse",sess.getUpgradeResponse(),notNullValue());
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
Session sess = future.get(30, TimeUnit.SECONDS);
|
||||
assertThat("Session", sess, notNullValue());
|
||||
assertThat("Session.open", sess.isOpen(), is(true));
|
||||
assertThat("Session.upgradeRequest", sess.getUpgradeRequest(), notNullValue());
|
||||
assertThat("Session.upgradeResponse", sess.getUpgradeResponse(), notNullValue());
|
||||
|
||||
cliSock.assertWasOpened();
|
||||
cliSock.assertNotClosed();
|
||||
|
||||
Collection<WebSocketSession> sessions = client.getBeans(WebSocketSession.class);
|
||||
Assert.assertThat("client.connectionManager.sessions.size",sessions.size(),is(1));
|
||||
assertThat("client.connectionManager.sessions.size", sessions.size(), is(1));
|
||||
|
||||
FutureWriteCallback callback = new FutureWriteCallback();
|
||||
|
||||
cliSock.getSession().getRemote().sendString("Hello World!",callback);
|
||||
callback.get(1,TimeUnit.SECONDS);
|
||||
cliSock.getSession().getRemote().sendString("Hello World!", callback);
|
||||
callback.get(1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBasicEcho_FromServer() throws Exception
|
||||
{
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
Future<Session> future = client.connect(wsocket,server.getWsUri());
|
||||
|
||||
// Server
|
||||
final IBlockheadServerConnection srvSock = server.accept();
|
||||
srvSock.upgrade();
|
||||
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Validate connect
|
||||
Session sess = future.get(30,TimeUnit.SECONDS);
|
||||
Assert.assertThat("Session",sess,notNullValue());
|
||||
Assert.assertThat("Session.open",sess.isOpen(),is(true));
|
||||
Assert.assertThat("Session.upgradeRequest",sess.getUpgradeRequest(),notNullValue());
|
||||
Assert.assertThat("Session.upgradeResponse",sess.getUpgradeResponse(),notNullValue());
|
||||
Session sess = future.get(30, TimeUnit.SECONDS);
|
||||
assertThat("Session", sess, notNullValue());
|
||||
assertThat("Session.open", sess.isOpen(), is(true));
|
||||
assertThat("Session.upgradeRequest", sess.getUpgradeRequest(), notNullValue());
|
||||
assertThat("Session.upgradeResponse", sess.getUpgradeResponse(), notNullValue());
|
||||
|
||||
// Have server send initial message
|
||||
srvSock.write(new TextFrame().setPayload("Hello World"));
|
||||
serverConn.write(new TextFrame().setPayload("Hello World"));
|
||||
|
||||
// Verify connect
|
||||
future.get(30,TimeUnit.SECONDS);
|
||||
future.get(30, TimeUnit.SECONDS);
|
||||
wsocket.assertWasOpened();
|
||||
wsocket.awaitMessage(1,TimeUnit.SECONDS,2);
|
||||
|
||||
wsocket.assertMessage("Hello World");
|
||||
String received = wsocket.messageQueue.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("Message", received, containsString("Hello World"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -193,9 +227,6 @@ public class WebSocketClientTest
|
|||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection ssocket = server.accept();
|
||||
ssocket.upgrade();
|
||||
|
||||
future.get(30,TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertTrue(wsocket.openLatch.await(1,TimeUnit.SECONDS));
|
||||
|
@ -203,46 +234,16 @@ public class WebSocketClientTest
|
|||
InetSocketAddress local = wsocket.getSession().getLocalAddress();
|
||||
InetSocketAddress remote = wsocket.getSession().getRemoteAddress();
|
||||
|
||||
Assert.assertThat("Local Socket Address",local,notNullValue());
|
||||
Assert.assertThat("Remote Socket Address",remote,notNullValue());
|
||||
assertThat("Local Socket Address",local,notNullValue());
|
||||
assertThat("Remote Socket Address",remote,notNullValue());
|
||||
|
||||
// Hard to validate (in a portable unit test) the local address that was used/bound in the low level Jetty Endpoint
|
||||
Assert.assertThat("Local Socket Address / Host",local.getAddress().getHostAddress(),notNullValue());
|
||||
Assert.assertThat("Local Socket Address / Port",local.getPort(),greaterThan(0));
|
||||
assertThat("Local Socket Address / Host",local.getAddress().getHostAddress(),notNullValue());
|
||||
assertThat("Local Socket Address / Port",local.getPort(),greaterThan(0));
|
||||
|
||||
Assert.assertThat("Remote Socket Address / Host",remote.getAddress().getHostAddress(),is(wsUri.getHost()));
|
||||
Assert.assertThat("Remote Socket Address / Port",remote.getPort(),greaterThan(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageBiggerThanBufferSize() throws Exception
|
||||
{
|
||||
int bufferSize = 512;
|
||||
|
||||
JettyTrackingSocket wsocket = new JettyTrackingSocket();
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection ssocket = server.accept();
|
||||
ssocket.upgrade();
|
||||
|
||||
future.get(30,TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertTrue(wsocket.openLatch.await(1,TimeUnit.SECONDS));
|
||||
|
||||
int length = bufferSize + (bufferSize / 2); // 1.5 times buffer size
|
||||
ssocket.write(0x80 | 0x01); // FIN + TEXT
|
||||
ssocket.write(0x7E); // No MASK and 2 bytes length
|
||||
ssocket.write(length >> 8); // first length byte
|
||||
ssocket.write(length & 0xFF); // second length byte
|
||||
for (int i = 0; i < length; ++i)
|
||||
{
|
||||
ssocket.write('x');
|
||||
}
|
||||
ssocket.flush();
|
||||
|
||||
Assert.assertTrue(wsocket.dataLatch.await(1000,TimeUnit.SECONDS));
|
||||
String uriHostAddress = InetAddress.getByName(wsUri.getHost()).getHostAddress();
|
||||
assertThat("Remote Socket Address / Host",remote.getAddress().getHostAddress(),is(uriHostAddress));
|
||||
assertThat("Remote Socket Address / Port",remote.getPort(),greaterThan(0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -256,17 +257,27 @@ public class WebSocketClientTest
|
|||
{
|
||||
MaxMessageSocket wsocket = new MaxMessageSocket();
|
||||
|
||||
// Hook into server connection creation
|
||||
CompletableFuture<BlockheadConnection> serverConnFut = new CompletableFuture<>();
|
||||
server.addConnectFuture(serverConnFut);
|
||||
|
||||
URI wsUri = server.getWsUri();
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection ssocket = server.accept();
|
||||
ssocket.upgrade();
|
||||
try (BlockheadConnection serverConn = serverConnFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Setup echo of frames on server side
|
||||
serverConn.setIncomingFrameConsumer((frame)->{
|
||||
WebSocketFrame copy = WebSocketFrame.copy(frame);
|
||||
copy.setMask(null); // strip client mask (if present)
|
||||
serverConn.write(copy);
|
||||
});
|
||||
|
||||
wsocket.awaitConnect(1,TimeUnit.SECONDS);
|
||||
|
||||
Session sess = future.get(30,TimeUnit.SECONDS);
|
||||
Assert.assertThat("Session",sess,notNullValue());
|
||||
Assert.assertThat("Session.open",sess.isOpen(),is(true));
|
||||
assertThat("Session",sess,notNullValue());
|
||||
assertThat("Session.open",sess.isOpen(),is(true));
|
||||
|
||||
// Create string that is larger than default size of 64k
|
||||
// but smaller than maxMessageSize of 100k
|
||||
|
@ -275,13 +286,14 @@ public class WebSocketClientTest
|
|||
String msg = StringUtil.toUTF8String(buf,0,buf.length);
|
||||
|
||||
wsocket.getSession().getRemote().sendStringByFuture(msg);
|
||||
ssocket.echoMessage(1,2,TimeUnit.SECONDS);
|
||||
|
||||
// wait for response from server
|
||||
wsocket.waitForMessage(1,TimeUnit.SECONDS);
|
||||
wsocket.waitForMessage(1, TimeUnit.SECONDS);
|
||||
|
||||
wsocket.assertMessage(msg);
|
||||
|
||||
Assert.assertTrue(wsocket.dataLatch.await(2,TimeUnit.SECONDS));
|
||||
Assert.assertTrue(wsocket.dataLatch.await(2, TimeUnit.SECONDS));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -292,24 +304,21 @@ public class WebSocketClientTest
|
|||
URI wsUri = server.getWsUri().resolve("/test?snack=cashews&amount=handful&brand=off");
|
||||
Future<Session> future = client.connect(wsocket,wsUri);
|
||||
|
||||
IBlockheadServerConnection ssocket = server.accept();
|
||||
ssocket.upgrade();
|
||||
|
||||
future.get(30,TimeUnit.SECONDS);
|
||||
|
||||
Assert.assertTrue(wsocket.openLatch.await(1,TimeUnit.SECONDS));
|
||||
|
||||
Session session = wsocket.getSession();
|
||||
UpgradeRequest req = session.getUpgradeRequest();
|
||||
Assert.assertThat("Upgrade Request",req,notNullValue());
|
||||
assertThat("Upgrade Request",req,notNullValue());
|
||||
|
||||
Map<String, List<String>> parameterMap = req.getParameterMap();
|
||||
Assert.assertThat("Parameter Map",parameterMap,notNullValue());
|
||||
assertThat("Parameter Map",parameterMap,notNullValue());
|
||||
|
||||
Assert.assertThat("Parameter[snack]",parameterMap.get("snack"),is(Arrays.asList(new String[] { "cashews" })));
|
||||
Assert.assertThat("Parameter[amount]",parameterMap.get("amount"),is(Arrays.asList(new String[] { "handful" })));
|
||||
Assert.assertThat("Parameter[brand]",parameterMap.get("brand"),is(Arrays.asList(new String[] { "off" })));
|
||||
assertThat("Parameter[snack]",parameterMap.get("snack"),is(Arrays.asList(new String[] { "cashews" })));
|
||||
assertThat("Parameter[amount]",parameterMap.get("amount"),is(Arrays.asList(new String[] { "handful" })));
|
||||
assertThat("Parameter[brand]",parameterMap.get("brand"),is(Arrays.asList(new String[] { "off" })));
|
||||
|
||||
Assert.assertThat("Parameter[cost]",parameterMap.get("cost"),nullValue());
|
||||
assertThat("Parameter[cost]",parameterMap.get("cost"),nullValue());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ org.eclipse.jetty.LEVEL=WARN
|
|||
# org.eclipse.jetty.websocket.client.ClientCloseTest.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.common.io.IOState.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.common.test.LEVEL=DEBUG
|
||||
|
||||
# org.eclipse.jetty.websocket.common.Generator.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.common.Parser.LEVEL=DEBUG
|
||||
|
|
|
@ -30,6 +30,18 @@
|
|||
<artifactId>jetty-io</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty.toolchain</groupId>
|
||||
<artifactId>jetty-test-helper</artifactId>
|
||||
|
|
|
@ -29,12 +29,12 @@ public class AdapterConnectCloseSocket extends WebSocketAdapter
|
|||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session sess)
|
||||
{
|
||||
capture.add("onWebSocketConnect(%s)",sess);
|
||||
capture.offer("onWebSocketConnect(%s)",sess);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,19 +33,19 @@ public class AnnotatedBinaryArraySocket
|
|||
@OnWebSocketMessage
|
||||
public void onBinary(byte payload[], int offset, int length)
|
||||
{
|
||||
capture.add("onBinary([%d],%d,%d)",payload.length,offset,length);
|
||||
capture.offer("onBinary([%d],%d,%d)",payload.length,offset,length);
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session sess)
|
||||
{
|
||||
capture.add("onConnect(%s)",sess);
|
||||
capture.offer("onConnect(%s)",sess);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,18 +39,18 @@ public class AnnotatedBinaryStreamSocket
|
|||
{
|
||||
new RuntimeException("Stream cannot be null").printStackTrace(System.err);
|
||||
}
|
||||
capture.add("onBinary(%s)",stream);
|
||||
capture.offer("onBinary(%s)",stream);
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session sess)
|
||||
{
|
||||
capture.add("onConnect(%s)",sess);
|
||||
capture.offer("onConnect(%s)",sess);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,18 +34,18 @@ public class AnnotatedFramesSocket
|
|||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session sess)
|
||||
{
|
||||
capture.add("onConnect(%s)",sess);
|
||||
capture.offer("onConnect(%s)",sess);
|
||||
}
|
||||
|
||||
@OnWebSocketFrame
|
||||
public void onFrame(Frame frame)
|
||||
{
|
||||
capture.add("onFrame(%s)",frame);
|
||||
capture.offer("onFrame(%s)",frame);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,13 +38,13 @@ public class AnnotatedStreamingSocket
|
|||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session sess)
|
||||
{
|
||||
capture.add("onConnect(%s)",sess);
|
||||
capture.offer("onConnect(%s)",sess);
|
||||
}
|
||||
|
||||
@OnWebSocketFrame
|
||||
|
|
|
@ -34,24 +34,24 @@ public class AnnotatedTextSocket
|
|||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session sess)
|
||||
{
|
||||
capture.add("onConnect(%s)",sess);
|
||||
capture.offer("onConnect(%s)",sess);
|
||||
}
|
||||
|
||||
@OnWebSocketError
|
||||
public void onError(Throwable cause)
|
||||
{
|
||||
capture.add("onError(%s: %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
capture.offer("onError(%s: %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onText(String message)
|
||||
{
|
||||
capture.add("onText(%s)",capture.q(message));
|
||||
capture.offer("onText(%s)",capture.q(message));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,18 +35,18 @@ public class AnnotatedTextStreamSocket
|
|||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@OnWebSocketConnect
|
||||
public void onConnect(Session sess)
|
||||
{
|
||||
capture.add("onConnect(%s)",sess);
|
||||
capture.offer("onConnect(%s)",sess);
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onText(Reader reader)
|
||||
{
|
||||
capture.add("onText(%s)",reader);
|
||||
capture.offer("onText(%s)",reader);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,30 +29,30 @@ public class ListenerBasicSocket implements WebSocketListener
|
|||
@Override
|
||||
public void onWebSocketBinary(byte[] payload, int offset, int len)
|
||||
{
|
||||
capture.add("onWebSocketBinary([%d], %d, %d)",payload.length,offset,len);
|
||||
capture.offer("onWebSocketBinary([%d], %d, %d)",payload.length,offset,len);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session)
|
||||
{
|
||||
capture.add("onWebSocketConnect(%s)",session);
|
||||
capture.offer("onWebSocketConnect(%s)",session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketError(Throwable cause)
|
||||
{
|
||||
capture.add("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
capture.offer("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketText(String message)
|
||||
{
|
||||
capture.add("onWebSocketText(%s)",capture.q(message));
|
||||
capture.offer("onWebSocketText(%s)",capture.q(message));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,24 +30,24 @@ public class ListenerFrameSocket implements WebSocketFrameListener
|
|||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session)
|
||||
{
|
||||
capture.add("onWebSocketConnect(%s)",session);
|
||||
capture.offer("onWebSocketConnect(%s)",session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketError(Throwable cause)
|
||||
{
|
||||
capture.add("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
capture.offer("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketFrame(Frame frame)
|
||||
{
|
||||
capture.add("onWebSocketFrame(%s, %d, %b)", frame.getType(), frame.getPayload().remaining(), frame.isFin());
|
||||
capture.offer("onWebSocketFrame(%s, %d, %b)", frame.getType(), frame.getPayload().remaining(), frame.isFin());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,30 +31,30 @@ public class ListenerPartialSocket implements WebSocketPartialListener
|
|||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session)
|
||||
{
|
||||
capture.add("onWebSocketConnect(%s)",session);
|
||||
capture.offer("onWebSocketConnect(%s)",session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketError(Throwable cause)
|
||||
{
|
||||
capture.add("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
capture.offer("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPartialText(String payload, boolean fin)
|
||||
{
|
||||
capture.add("onWebSocketPartialText('%s', %b)",payload,fin);
|
||||
capture.offer("onWebSocketPartialText('%s', %b)",payload,fin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPartialBinary(ByteBuffer payload, boolean fin)
|
||||
{
|
||||
capture.add("onWebSocketPartialBinary(%s [%d], %b)",payload,payload.remaining(),fin);
|
||||
capture.offer("onWebSocketPartialBinary(%s [%d], %b)",payload,payload.remaining(),fin);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,30 +31,30 @@ public class ListenerPingPongSocket implements WebSocketPingPongListener
|
|||
@Override
|
||||
public void onWebSocketClose(int statusCode, String reason)
|
||||
{
|
||||
capture.add("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
capture.offer("onWebSocketClose(%d, %s)",statusCode,capture.q(reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketConnect(Session session)
|
||||
{
|
||||
capture.add("onWebSocketConnect(%s)",session);
|
||||
capture.offer("onWebSocketConnect(%s)",session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketError(Throwable cause)
|
||||
{
|
||||
capture.add("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
capture.offer("onWebSocketError((%s) %s)",cause.getClass().getSimpleName(),cause.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPing(ByteBuffer payload)
|
||||
{
|
||||
capture.add("onWebSocketPing(%d)",payload.remaining());
|
||||
capture.offer("onWebSocketPing(%d)",payload.remaining());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWebSocketPong(ByteBuffer payload)
|
||||
{
|
||||
capture.add("onWebSocketPong(%d)",payload.remaining());
|
||||
capture.offer("onWebSocketPong(%d)",payload.remaining());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,14 +22,12 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.websocket.api.ProtocolException;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.PingFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.PongFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.UnitGenerator;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
@ -74,9 +72,6 @@ public class TestABCase3
|
|||
return data;
|
||||
}
|
||||
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private WebSocketFrame invalidFrame;
|
||||
|
||||
public TestABCase3(WebSocketFrame invalidFrame)
|
||||
|
|
|
@ -18,53 +18,18 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class EventCapture extends EventQueue<String>
|
||||
public class EventCapture extends LinkedBlockingQueue<String>
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(EventCapture.class);
|
||||
|
||||
public static class Assertable
|
||||
{
|
||||
private final String event;
|
||||
|
||||
public Assertable(String event)
|
||||
{
|
||||
this.event = event;
|
||||
}
|
||||
|
||||
public void assertEventContains(String expected)
|
||||
{
|
||||
Assert.assertThat("Event",event,containsString(expected));
|
||||
}
|
||||
|
||||
public void assertEventRegex(String regex)
|
||||
{
|
||||
Assert.assertTrue("Event: regex:[" + regex + "] in [" + event + "]",Pattern.matches(regex,event));
|
||||
}
|
||||
|
||||
public void assertEventStartsWith(String expected)
|
||||
{
|
||||
Assert.assertThat("Event",event,startsWith(expected));
|
||||
}
|
||||
|
||||
public void assertEvent(String expected)
|
||||
{
|
||||
Assert.assertThat("Event",event,is(expected));
|
||||
}
|
||||
}
|
||||
|
||||
public void add(String format, Object... args)
|
||||
public void offer(String format, Object... args)
|
||||
{
|
||||
String msg = String.format(format,args);
|
||||
if (LOG.isDebugEnabled())
|
||||
|
@ -72,16 +37,6 @@ public class EventCapture extends EventQueue<String>
|
|||
super.offer(msg);
|
||||
}
|
||||
|
||||
public Assertable pop()
|
||||
{
|
||||
return new Assertable(super.poll());
|
||||
}
|
||||
|
||||
public void assertEventCount(int expectedCount)
|
||||
{
|
||||
Assert.assertThat("Event Count",size(),is(expectedCount));
|
||||
}
|
||||
|
||||
public String q(String str)
|
||||
{
|
||||
if (str == null)
|
||||
|
@ -90,4 +45,9 @@ public class EventCapture extends EventQueue<String>
|
|||
}
|
||||
return '"' + str + '"';
|
||||
}
|
||||
|
||||
public String safePoll() throws InterruptedException
|
||||
{
|
||||
return poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import static org.eclipse.jetty.websocket.common.test.MoreMatchers.regex;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
|
@ -80,9 +82,8 @@ public class EventDriverTest
|
|||
conn.open();
|
||||
driver.incomingFrame(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
socket.capture.assertEventCount(2);
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketConnect");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketClose");
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketConnect"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketClose"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -98,10 +99,9 @@ public class EventDriverTest
|
|||
driver.incomingFrame(makeBinaryFrame("Hello World",true));
|
||||
driver.incomingFrame(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
socket.capture.assertEventCount(3);
|
||||
socket.capture.pop().assertEventStartsWith("onConnect");
|
||||
socket.capture.pop().assertEvent("onBinary([11],0,11)");
|
||||
socket.capture.pop().assertEventStartsWith("onClose(1000,");
|
||||
assertThat(socket.capture.safePoll(), startsWith("onConnect"));
|
||||
assertThat(socket.capture.safePoll(), containsString("onBinary([11],0,11)"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onClose(1000,"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,10 +117,9 @@ public class EventDriverTest
|
|||
driver.incomingError(new WebSocketException("oof"));
|
||||
driver.incomingFrame(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
socket.capture.assertEventCount(3);
|
||||
socket.capture.pop().assertEventStartsWith("onConnect");
|
||||
socket.capture.pop().assertEventStartsWith("onError(WebSocketException: oof)");
|
||||
socket.capture.pop().assertEventStartsWith("onClose(1000,");
|
||||
assertThat(socket.capture.safePoll(), startsWith("onConnect"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onError(WebSocketException: oof)"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onClose(1000,"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -138,18 +137,17 @@ public class EventDriverTest
|
|||
driver.incomingFrame(new BinaryFrame().setPayload("Hello Bin"));
|
||||
driver.incomingFrame(new CloseInfo(StatusCode.SHUTDOWN,"testcase").asFrame());
|
||||
|
||||
socket.capture.assertEventCount(6);
|
||||
socket.capture.pop().assertEventStartsWith("onConnect(");
|
||||
socket.capture.pop().assertEventStartsWith("onFrame(PING[");
|
||||
socket.capture.pop().assertEventStartsWith("onFrame(TEXT[");
|
||||
socket.capture.pop().assertEventStartsWith("onFrame(BINARY[");
|
||||
socket.capture.pop().assertEventStartsWith("onFrame(CLOSE[");
|
||||
socket.capture.pop().assertEventStartsWith("onClose(1001,");
|
||||
assertThat(socket.capture.safePoll(), startsWith("onConnect("));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onFrame(PING["));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onFrame(TEXT["));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onFrame(BINARY["));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onFrame(CLOSE["));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onClose(1001,"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnotated_InputStream() throws IOException, TimeoutException, InterruptedException
|
||||
public void testAnnotated_InputStream() throws InterruptedException
|
||||
{
|
||||
AnnotatedBinaryStreamSocket socket = new AnnotatedBinaryStreamSocket();
|
||||
EventDriver driver = wrap(socket);
|
||||
|
@ -160,10 +158,9 @@ public class EventDriverTest
|
|||
driver.incomingFrame(makeBinaryFrame("Hello World",true));
|
||||
driver.incomingFrame(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
socket.capture.assertEventCount(3);
|
||||
socket.capture.pop().assertEventStartsWith("onConnect");
|
||||
socket.capture.pop().assertEventRegex("^onBinary\\(.*InputStream.*");
|
||||
socket.capture.pop().assertEventStartsWith("onClose(1000,");
|
||||
assertThat(socket.capture.safePoll(), startsWith("onConnect"));
|
||||
assertThat(socket.capture.safePoll(), regex("^onBinary\\(.*InputStream.*"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onClose(1000,"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,10 +177,9 @@ public class EventDriverTest
|
|||
driver.incomingFrame(new TextFrame().setPayload("Hello World"));
|
||||
driver.incomingFrame(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
socket.capture.assertEventCount(3);
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketConnect");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketText(\"Hello World\")");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketClose(1000,");
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketConnect"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketText(\"Hello World\")"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketClose(1000,"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,11 +197,10 @@ public class EventDriverTest
|
|||
driver.incomingFrame(new PongFrame().setPayload("PONG"));
|
||||
driver.incomingFrame(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
socket.capture.assertEventCount(4);
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketConnect");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketPing(");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketPong(");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketClose(1000,");
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketConnect"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketPing("));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketPong("));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketClose(1000,"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,11 +218,10 @@ public class EventDriverTest
|
|||
driver.incomingFrame(new PongFrame());
|
||||
driver.incomingFrame(new CloseInfo(StatusCode.NORMAL).asFrame());
|
||||
|
||||
socket.capture.assertEventCount(4);
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketConnect");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketPing(");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketPong(");
|
||||
socket.capture.pop().assertEventStartsWith("onWebSocketClose(1000,");
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketConnect"));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketPing("));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketPong("));
|
||||
assertThat(socket.capture.safePoll(), startsWith("onWebSocketClose(1000,"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,18 +28,13 @@ import java.nio.charset.StandardCharsets;
|
|||
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.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class HttpResponseHeaderParserTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
private void appendUtf8(ByteBuffer buf, String line)
|
||||
{
|
||||
buf.put(ByteBuffer.wrap(StringUtil.getUtf8Bytes(line)));
|
||||
|
|
|
@ -26,7 +26,6 @@ import java.util.Arrays;
|
|||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
|
@ -48,9 +47,6 @@ public class MessageOutputStreamTest
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(MessageOutputStreamTest.class);
|
||||
|
||||
@Rule
|
||||
public TestTracker testtracker = new TestTracker();
|
||||
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ import java.util.Arrays;
|
|||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
|
@ -46,9 +45,6 @@ public class MessageWriterTest
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(MessageWriterTest.class);
|
||||
|
||||
@Rule
|
||||
public TestTracker testtracker = new TestTracker();
|
||||
|
||||
@Rule
|
||||
public TestName testname = new TestName();
|
||||
|
||||
|
|
|
@ -23,9 +23,9 @@ import static org.hamcrest.Matchers.is;
|
|||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -43,8 +43,8 @@ public class TrackingInputStreamSocket
|
|||
public int closeCode = -1;
|
||||
public StringBuilder closeMessage = new StringBuilder();
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
public EventQueue<String> messageQueue = new EventQueue<>();
|
||||
public EventQueue<Throwable> errorQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
|
||||
public LinkedBlockingQueue<Throwable> errorQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
public TrackingInputStreamSocket()
|
||||
{
|
||||
|
|
|
@ -22,10 +22,9 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
|||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
|
@ -45,8 +44,8 @@ public class TrackingSocket extends WebSocketAdapter
|
|||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
public CountDownLatch dataLatch = new CountDownLatch(1);
|
||||
public EventQueue<String> messageQueue = new EventQueue<>();
|
||||
public EventQueue<Throwable> errorQueue = new EventQueue<>();
|
||||
public LinkedBlockingQueue<String> messageQueue = new LinkedBlockingQueue<>();
|
||||
public LinkedBlockingQueue<Throwable> errorQueue = new LinkedBlockingQueue<>();
|
||||
|
||||
public TrackingSocket()
|
||||
{
|
||||
|
@ -102,11 +101,6 @@ public class TrackingSocket extends WebSocketAdapter
|
|||
Assert.assertThat("Was Opened",openLatch.await(30,TimeUnit.SECONDS),is(true));
|
||||
}
|
||||
|
||||
public void awaitMessage(int expectedMessageCount, TimeUnit timeoutUnit, int timeoutDuration) throws TimeoutException, InterruptedException
|
||||
{
|
||||
messageQueue.awaitEventCount(expectedMessageCount,timeoutDuration,timeoutUnit);
|
||||
}
|
||||
|
||||
public void clear()
|
||||
{
|
||||
messageQueue.clear();
|
||||
|
|
|
@ -18,834 +18,67 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.test;
|
||||
|
||||
import static org.hamcrest.Matchers.anyOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.io.EOFException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
|
||||
import org.eclipse.jetty.client.HttpClient;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
|
||||
import org.eclipse.jetty.websocket.api.util.WSURI;
|
||||
import org.eclipse.jetty.websocket.common.AcceptHash;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.ConnectionState;
|
||||
import org.eclipse.jetty.websocket.common.Generator;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
|
||||
import org.eclipse.jetty.websocket.common.io.IOState;
|
||||
import org.eclipse.jetty.websocket.common.io.IOState.ConnectionStateListener;
|
||||
import org.eclipse.jetty.websocket.common.io.http.HttpResponseHeaderParser;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.junit.Assert;
|
||||
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
||||
|
||||
/**
|
||||
* A simple websocket client for performing unit tests with.
|
||||
* <p>
|
||||
* This client will use {@link HttpURLConnection} and {@link HttpsURLConnection} with standard blocking calls to perform websocket requests.
|
||||
* <p>
|
||||
* This client is <u>NOT</u> intended to be performant or follow the websocket spec religiously. In fact, being able to deviate from the websocket spec at will
|
||||
* is desired for this client to operate properly for the unit testing within this module.
|
||||
* <p>
|
||||
* The BlockheadClient should never validate frames or bytes being sent for validity, against any sort of spec, or even sanity. It should, however be honest
|
||||
* with regards to basic IO behavior, a write should work as expected, a read should work as expected, but <u>what</u> byte it sends or reads is not within its
|
||||
* scope.
|
||||
*/
|
||||
public class BlockheadClient implements OutgoingFrames, ConnectionStateListener, AutoCloseable, IBlockheadClient
|
||||
public class BlockheadClient extends HttpClient implements WebSocketContainerScope
|
||||
{
|
||||
private class FrameReadingThread extends Thread implements Runnable, IncomingFrames
|
||||
{
|
||||
public long totalBytes = 0;
|
||||
public long totalReadOps = 0;
|
||||
public long totalParseOps = 0;
|
||||
private WebSocketPolicy policy;
|
||||
private ByteBufferPool bufferPool;
|
||||
private ExtensionFactory extensionFactory;
|
||||
private DecoratedObjectFactory objectFactory;
|
||||
|
||||
public EventQueue<WebSocketFrame> frames = new EventQueue<>();
|
||||
public EventQueue<Throwable> errors = new EventQueue<>();
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
public BlockheadClient()
|
||||
{
|
||||
LOG.debug("Reading frames from server");
|
||||
|
||||
byte buf[] = new byte[BUFFER_SIZE];
|
||||
try
|
||||
{
|
||||
if ((remainingBuffer != null) && (remainingBuffer.remaining() > 0))
|
||||
{
|
||||
LOG.debug("Reading bytes received during response header parse: {}",BufferUtil.toDetailString(remainingBuffer));
|
||||
totalBytes += remainingBuffer.remaining();
|
||||
totalReadOps++;
|
||||
parser.parse(remainingBuffer);
|
||||
super(null);
|
||||
setName("Blockhead-CLIENT");
|
||||
this.policy = new WebSocketPolicy(WebSocketBehavior.CLIENT);
|
||||
this.bufferPool = new MappedByteBufferPool();
|
||||
this.extensionFactory = new WebSocketExtensionFactory(this);
|
||||
this.objectFactory = new DecoratedObjectFactory();
|
||||
}
|
||||
|
||||
int len = 0;
|
||||
int available = 0;
|
||||
while (!eof)
|
||||
public ByteBufferPool getBufferPool()
|
||||
{
|
||||
available = in.available();
|
||||
len = in.read(buf,0,Math.min(available,buf.length));
|
||||
totalReadOps++;
|
||||
if (len < 0)
|
||||
{
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
else if (len > 0)
|
||||
{
|
||||
totalBytes += len;
|
||||
ByteBuffer bbuf = ByteBuffer.wrap(buf,0,len);
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Read {} bytes: {}",len,BufferUtil.toDetailString(bbuf));
|
||||
}
|
||||
totalParseOps++;
|
||||
parser.parse(bbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
return bufferPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
public DecoratedObjectFactory getObjectFactory()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append("FrameReadingThread[");
|
||||
str.append(",frames=" + frames.size());
|
||||
str.append(",errors=" + errors.size());
|
||||
str.append(String.format(",totalBytes=%,d",totalBytes));
|
||||
str.append(String.format(",totalReadOps=%,d",totalReadOps));
|
||||
str.append(String.format(",totalParseOps=%,d",totalParseOps));
|
||||
str.append("]");
|
||||
return str.toString();
|
||||
return objectFactory;
|
||||
}
|
||||
|
||||
public ExtensionFactory getExtensionFactory()
|
||||
{
|
||||
return extensionFactory;
|
||||
}
|
||||
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
public BlockheadClientRequest newWsRequest(URI destURI)
|
||||
{
|
||||
return new BlockheadClientRequest(this, destURI);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void incomingError(Throwable t)
|
||||
{
|
||||
this.errors.add(t);
|
||||
}
|
||||
public void onSessionOpened(WebSocketSession session)
|
||||
{ /* ignored */ }
|
||||
|
||||
@Override
|
||||
public synchronized void incomingFrame(Frame frame)
|
||||
{
|
||||
this.frames.add(WebSocketFrame.copy(frame));
|
||||
}
|
||||
|
||||
public synchronized void clear()
|
||||
{
|
||||
this.frames.clear();
|
||||
this.errors.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private static final String REQUEST_HASH_KEY = "dGhlIHNhbXBsZSBub25jZQ==";
|
||||
private static final int BUFFER_SIZE = 64 * 1024;
|
||||
private static final Logger LOG = Log.getLogger(BlockheadClient.class);
|
||||
private final URI destHttpURI;
|
||||
private final URI destWebsocketURI;
|
||||
private final ByteBufferPool bufferPool;
|
||||
private final Generator generator;
|
||||
private final Parser parser;
|
||||
|
||||
private final WebSocketExtensionFactory extensionFactory;
|
||||
private FrameReadingThread frameReader;
|
||||
|
||||
private ExecutorService executor;
|
||||
private Socket socket;
|
||||
private OutputStream out;
|
||||
private InputStream in;
|
||||
private int version = 13; // default to RFC-6455
|
||||
private String protocols;
|
||||
private List<String> extensions = new ArrayList<>();
|
||||
private List<String> headers = new ArrayList<>();
|
||||
private byte[] clientmask = new byte[] { (byte)0xFF, (byte)0xFF, (byte)0xFF, (byte)0xFF };
|
||||
private int timeout = 1000;
|
||||
private OutgoingFrames outgoing = this;
|
||||
private boolean eof = false;
|
||||
private ExtensionStack extensionStack;
|
||||
private IOState ioState;
|
||||
private CountDownLatch disconnectedLatch = new CountDownLatch(1);
|
||||
private ByteBuffer remainingBuffer;
|
||||
|
||||
private String connectionValue = "Upgrade";
|
||||
|
||||
public BlockheadClient(URI destWebsocketURI) throws URISyntaxException
|
||||
{
|
||||
this(WebSocketPolicy.newClientPolicy(),destWebsocketURI);
|
||||
}
|
||||
|
||||
public BlockheadClient(WebSocketPolicy policy, URI destWebsocketURI) throws URISyntaxException
|
||||
{
|
||||
Assert.assertThat("Websocket URI scheme",destWebsocketURI.getScheme(),anyOf(is("ws"),is("wss")));
|
||||
this.destWebsocketURI = destWebsocketURI;
|
||||
if (destWebsocketURI.getScheme().equals("wss"))
|
||||
{
|
||||
throw new RuntimeException("Sorry, BlockheadClient does not support SSL");
|
||||
}
|
||||
this.destHttpURI = WSURI.toHttp(destWebsocketURI);
|
||||
|
||||
LOG.debug("WebSocket URI: {}",destWebsocketURI);
|
||||
LOG.debug(" HTTP URI: {}",destHttpURI);
|
||||
|
||||
// This is a blockhead client, no point tracking leaks on this object.
|
||||
this.bufferPool = new MappedByteBufferPool(8192);
|
||||
this.generator = new Generator(policy,bufferPool);
|
||||
this.parser = new Parser(policy,bufferPool);
|
||||
|
||||
this.extensionFactory = new WebSocketExtensionFactory(new SimpleContainerScope(policy,bufferPool));
|
||||
this.ioState = new IOState();
|
||||
this.ioState.addListener(this);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#addExtensions(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void addExtensions(String xtension)
|
||||
{
|
||||
this.extensions.add(xtension);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#addHeader(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void addHeader(String header)
|
||||
{
|
||||
this.headers.add(header);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#awaitDisconnect(long, java.util.concurrent.TimeUnit)
|
||||
*/
|
||||
@Override
|
||||
public boolean awaitDisconnect(long timeout, TimeUnit unit) throws InterruptedException
|
||||
{
|
||||
return disconnectedLatch.await(timeout,unit);
|
||||
}
|
||||
|
||||
public void clearCaptured()
|
||||
{
|
||||
frameReader.clear();
|
||||
}
|
||||
|
||||
public void clearExtensions()
|
||||
{
|
||||
extensions.clear();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#close()
|
||||
*/
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
LOG.debug("close()");
|
||||
close(-1,null);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#close(int, java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void close(int statusCode, String message)
|
||||
{
|
||||
LOG.debug("close({},{})",statusCode,message);
|
||||
CloseInfo close = new CloseInfo(statusCode,message);
|
||||
|
||||
if (!ioState.isClosed())
|
||||
{
|
||||
ioState.onCloseLocal(close);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("Not issuing close. ioState = {}",ioState);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#connect()
|
||||
*/
|
||||
@Override
|
||||
public void connect() throws IOException
|
||||
{
|
||||
InetAddress destAddr = InetAddress.getByName(destHttpURI.getHost());
|
||||
int port = destHttpURI.getPort();
|
||||
|
||||
SocketAddress endpoint = new InetSocketAddress(destAddr,port);
|
||||
|
||||
socket = new Socket();
|
||||
socket.setSoTimeout(timeout);
|
||||
socket.connect(endpoint);
|
||||
|
||||
out = socket.getOutputStream();
|
||||
in = socket.getInputStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
LOG.debug("disconnect");
|
||||
IO.close(in);
|
||||
IO.close(out);
|
||||
disconnectedLatch.countDown();
|
||||
if (frameReader != null)
|
||||
{
|
||||
frameReader.interrupt();
|
||||
}
|
||||
if (socket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#expectServerDisconnect()
|
||||
*/
|
||||
@Override
|
||||
public void expectServerDisconnect()
|
||||
{
|
||||
if (eof)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
int len = in.read();
|
||||
if (len == (-1))
|
||||
{
|
||||
// we are disconnected
|
||||
eof = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Assert.assertThat("Expecting no data and proper socket disconnect (issued from server)",len,is(-1));
|
||||
}
|
||||
catch (SocketTimeoutException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
Assert.fail("Expected a server initiated disconnect, instead the read timed out");
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// acceptable path
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#expectUpgradeResponse()
|
||||
*/
|
||||
@Override
|
||||
public HttpResponse expectUpgradeResponse() throws IOException
|
||||
{
|
||||
HttpResponse response = readResponseHeader();
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Response Header: {}{}",'\n',response);
|
||||
}
|
||||
|
||||
Assert.assertThat("Response Status Code",response.getStatusCode(),is(101));
|
||||
Assert.assertThat("Response Status Reason",response.getStatusReason(),is("Switching Protocols"));
|
||||
Assert.assertThat("Response Header[Upgrade]",response.getHeader("Upgrade"),is("WebSocket"));
|
||||
Assert.assertThat("Response Header[Connection]",response.getHeader("Connection"),is("Upgrade"));
|
||||
|
||||
// Validate the Sec-WebSocket-Accept
|
||||
String acceptKey = response.getHeader("Sec-WebSocket-Accept");
|
||||
Assert.assertThat("Response Header[Sec-WebSocket-Accept Exists]",acceptKey,notNullValue());
|
||||
|
||||
String reqKey = REQUEST_HASH_KEY;
|
||||
String expectedHash = AcceptHash.hashKey(reqKey);
|
||||
|
||||
Assert.assertThat("Valid Sec-WebSocket-Accept Hash?",acceptKey,is(expectedHash));
|
||||
|
||||
// collect extensions configured in response header
|
||||
List<ExtensionConfig> configs = getExtensionConfigs(response);
|
||||
extensionStack = new ExtensionStack(this.extensionFactory);
|
||||
extensionStack.negotiate(configs);
|
||||
|
||||
// Setup Frame Reader
|
||||
this.frameReader = new FrameReadingThread();
|
||||
this.frameReader.start();
|
||||
|
||||
// Start with default routing
|
||||
extensionStack.setNextIncoming(frameReader); // the websocket layer
|
||||
extensionStack.setNextOutgoing(outgoing); // the network layer
|
||||
|
||||
// Configure Parser / Generator
|
||||
extensionStack.configure(parser);
|
||||
extensionStack.configure(generator);
|
||||
|
||||
// Start Stack
|
||||
try
|
||||
{
|
||||
extensionStack.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException("Unable to start Extension Stack");
|
||||
}
|
||||
|
||||
// configure parser
|
||||
parser.setIncomingFramesHandler(extensionStack);
|
||||
ioState.onOpened();
|
||||
|
||||
LOG.debug("outgoing = {}",outgoing);
|
||||
LOG.debug("incoming = {}",extensionStack);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public void flush() throws IOException
|
||||
{
|
||||
out.flush();
|
||||
}
|
||||
|
||||
public String getConnectionValue()
|
||||
{
|
||||
return connectionValue;
|
||||
}
|
||||
|
||||
public ExecutorService getExecutor()
|
||||
{
|
||||
if (executor == null)
|
||||
{
|
||||
executor = Executors.newCachedThreadPool();
|
||||
}
|
||||
return executor;
|
||||
}
|
||||
|
||||
private List<ExtensionConfig> getExtensionConfigs(HttpResponse response)
|
||||
{
|
||||
List<ExtensionConfig> configs = new ArrayList<>();
|
||||
|
||||
String econf = response.getHeader("Sec-WebSocket-Extensions");
|
||||
if (econf != null)
|
||||
{
|
||||
LOG.debug("Found Extension Response: {}",econf);
|
||||
ExtensionConfig config = ExtensionConfig.parse(econf);
|
||||
configs.add(config);
|
||||
}
|
||||
return configs;
|
||||
}
|
||||
|
||||
public List<String> getExtensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
public URI getHttpURI()
|
||||
{
|
||||
return destHttpURI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalSocketAddress()
|
||||
{
|
||||
return (InetSocketAddress)socket.getLocalSocketAddress();
|
||||
}
|
||||
|
||||
public IOState getIOState()
|
||||
{
|
||||
return ioState;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#getProtocols()
|
||||
*/
|
||||
@Override
|
||||
public String getProtocols()
|
||||
{
|
||||
return protocols;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteSocketAddress()
|
||||
{
|
||||
return (InetSocketAddress)socket.getRemoteSocketAddress();
|
||||
}
|
||||
|
||||
public String getRequestHost()
|
||||
{
|
||||
if (destHttpURI.getPort() > 0)
|
||||
{
|
||||
return String.format("%s:%d",destHttpURI.getHost(),destHttpURI.getPort());
|
||||
}
|
||||
else
|
||||
{
|
||||
return destHttpURI.getHost();
|
||||
}
|
||||
}
|
||||
|
||||
public String getRequestPath()
|
||||
{
|
||||
StringBuilder path = new StringBuilder();
|
||||
path.append(destHttpURI.getPath());
|
||||
if (StringUtil.isNotBlank(destHttpURI.getQuery()))
|
||||
{
|
||||
path.append('?').append(destHttpURI.getRawQuery());
|
||||
}
|
||||
return path.toString();
|
||||
}
|
||||
|
||||
public String getRequestWebSocketKey()
|
||||
{
|
||||
return REQUEST_HASH_KEY;
|
||||
}
|
||||
|
||||
public String getRequestWebSocketOrigin()
|
||||
{
|
||||
return destWebsocketURI.toASCIIString();
|
||||
}
|
||||
|
||||
public int getVersion()
|
||||
{
|
||||
return version;
|
||||
}
|
||||
|
||||
public URI getWebsocketURI()
|
||||
{
|
||||
return destWebsocketURI;
|
||||
}
|
||||
|
||||
public boolean isConnected()
|
||||
{
|
||||
return (socket != null) && (socket.isConnected());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionStateChange(ConnectionState state)
|
||||
{
|
||||
LOG.debug("CLIENT onConnectionStateChange() - {}",state);
|
||||
switch (state)
|
||||
{
|
||||
case CLOSED:
|
||||
// Per Spec, client should not initiate disconnect on its own
|
||||
// this.disconnect();
|
||||
break;
|
||||
case CLOSING:
|
||||
CloseInfo close = ioState.getCloseInfo();
|
||||
|
||||
WebSocketFrame frame = close.asFrame();
|
||||
LOG.debug("Issuing: {}",frame);
|
||||
try
|
||||
{
|
||||
write(frame);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
|
||||
{
|
||||
ByteBuffer headerBuf = generator.generateHeaderBytes(frame);
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("writing out: {}",BufferUtil.toDetailString(headerBuf));
|
||||
}
|
||||
try
|
||||
{
|
||||
BufferUtil.writeTo(headerBuf,out);
|
||||
BufferUtil.writeTo(frame.getPayload(),out);
|
||||
out.flush();
|
||||
if (callback != null)
|
||||
{
|
||||
callback.writeSuccess();
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
if (callback != null)
|
||||
{
|
||||
callback.writeFailed(e);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
bufferPool.release(headerBuf);
|
||||
}
|
||||
|
||||
if (frame.getOpCode() == OpCode.CLOSE)
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EventQueue<WebSocketFrame> readFrames(int expectedFrameCount, int timeoutDuration, TimeUnit timeoutUnit) throws Exception
|
||||
{
|
||||
frameReader.frames.awaitEventCount(expectedFrameCount,timeoutDuration,timeoutUnit);
|
||||
return frameReader.frames;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#readResponseHeader()
|
||||
*/
|
||||
@Override
|
||||
public HttpResponse readResponseHeader() throws IOException
|
||||
{
|
||||
HttpResponse response = new HttpResponse();
|
||||
HttpResponseHeaderParser respParser = new HttpResponseHeaderParser(response);
|
||||
|
||||
byte buf[] = new byte[512];
|
||||
|
||||
while (!eof)
|
||||
{
|
||||
int available = in.available();
|
||||
int len = in.read(buf,0,Math.min(available,buf.length));
|
||||
if (len < 0)
|
||||
{
|
||||
eof = true;
|
||||
break;
|
||||
}
|
||||
else if (len > 0)
|
||||
{
|
||||
ByteBuffer bbuf = ByteBuffer.wrap(buf,0,len);
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("Read {} bytes: {}",len,BufferUtil.toDetailString(bbuf));
|
||||
}
|
||||
if (respParser.parse(bbuf) != null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remainingBuffer = response.getRemainingBuffer();
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#sendStandardRequest()
|
||||
*/
|
||||
@Override
|
||||
public void sendStandardRequest() throws IOException
|
||||
{
|
||||
StringBuilder req = generateUpgradeRequest();
|
||||
writeRaw(req.toString());
|
||||
}
|
||||
|
||||
public StringBuilder generateUpgradeRequest()
|
||||
{
|
||||
StringBuilder req = new StringBuilder();
|
||||
req.append("GET ").append(getRequestPath()).append(" HTTP/1.1\r\n");
|
||||
req.append("Host: ").append(getRequestHost()).append("\r\n");
|
||||
req.append("Upgrade: websocket\r\n");
|
||||
req.append("User-Agent: BlockheadClient/JettyTests\r\n");
|
||||
req.append("Connection: ").append(connectionValue).append("\r\n");
|
||||
for (String header : headers)
|
||||
{
|
||||
req.append(header);
|
||||
}
|
||||
req.append("Sec-WebSocket-Key: ").append(getRequestWebSocketKey()).append("\r\n");
|
||||
req.append("Sec-WebSocket-Origin: ").append(getRequestWebSocketOrigin()).append("\r\n");
|
||||
if (StringUtil.isNotBlank(protocols))
|
||||
{
|
||||
req.append("Sec-WebSocket-Protocol: ").append(protocols).append("\r\n");
|
||||
}
|
||||
|
||||
for (String xtension : extensions)
|
||||
{
|
||||
req.append("Sec-WebSocket-Extensions: ").append(xtension).append("\r\n");
|
||||
}
|
||||
req.append("Sec-WebSocket-Version: ").append(version).append("\r\n");
|
||||
req.append("\r\n");
|
||||
return req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setConnectionValue(String connectionValue)
|
||||
{
|
||||
this.connectionValue = connectionValue;
|
||||
}
|
||||
|
||||
public void setExecutor(ExecutorService executor)
|
||||
{
|
||||
this.executor = executor;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#setProtocols(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void setProtocols(String protocols)
|
||||
{
|
||||
this.protocols = protocols;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#setTimeout(int, java.util.concurrent.TimeUnit)
|
||||
*/
|
||||
@Override
|
||||
public void setTimeout(int duration, TimeUnit unit)
|
||||
{
|
||||
this.timeout = (int)TimeUnit.MILLISECONDS.convert(duration,unit);
|
||||
}
|
||||
|
||||
public void setVersion(int version)
|
||||
{
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public void skipTo(String string) throws IOException
|
||||
{
|
||||
int state = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
int b = in.read();
|
||||
if (b < 0)
|
||||
{
|
||||
throw new EOFException();
|
||||
}
|
||||
|
||||
if (b == string.charAt(state))
|
||||
{
|
||||
state++;
|
||||
if (state == string.length())
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void sleep(TimeUnit unit, int duration) throws InterruptedException
|
||||
{
|
||||
LOG.info("Sleeping for {} {}",duration,unit);
|
||||
unit.sleep(duration);
|
||||
LOG.info("Waking up from sleep");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#write(org.eclipse.jetty.websocket.common.WebSocketFrame)
|
||||
*/
|
||||
@Override
|
||||
public void write(WebSocketFrame frame) throws IOException
|
||||
{
|
||||
if (!ioState.isOpen())
|
||||
{
|
||||
LOG.debug("IO Not Open / Not Writing: {}",frame);
|
||||
return;
|
||||
}
|
||||
LOG.debug("write(Frame->{}) to {}",frame,outgoing);
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
frame.setMask(new byte[] { 0x00, 0x00, 0x00, 0x00 });
|
||||
}
|
||||
else
|
||||
{
|
||||
frame.setMask(clientmask);
|
||||
}
|
||||
extensionStack.outgoingFrame(frame,null,BatchMode.OFF);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#writeRaw(java.nio.ByteBuffer)
|
||||
*/
|
||||
@Override
|
||||
public void writeRaw(ByteBuffer buf) throws IOException
|
||||
{
|
||||
LOG.debug("write(ByteBuffer) {}",BufferUtil.toDetailString(buf));
|
||||
BufferUtil.writeTo(buf,out);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#writeRaw(java.nio.ByteBuffer, int)
|
||||
*/
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#writeRaw(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
public void writeRaw(String str) throws IOException
|
||||
{
|
||||
LOG.debug("write((String)[{}]){}{})",str.length(),'\n',str);
|
||||
out.write(str.getBytes(StandardCharsets.ISO_8859_1));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadClient#writeRawSlowly(java.nio.ByteBuffer, int)
|
||||
*/
|
||||
@Override
|
||||
public void writeRawSlowly(ByteBuffer buf, int segmentSize) throws IOException
|
||||
{
|
||||
while (buf.remaining() > 0)
|
||||
{
|
||||
writeRaw(buf,segmentSize);
|
||||
flush();
|
||||
}
|
||||
}
|
||||
public void onSessionClosed(WebSocketSession session)
|
||||
{ /* ignored */ }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.common.test;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
|
||||
|
||||
public class BlockheadClientConnection extends BlockheadConnection
|
||||
{
|
||||
public BlockheadClientConnection(WebSocketPolicy policy,
|
||||
ByteBufferPool bufferPool,
|
||||
ExtensionStack extensionStack,
|
||||
CompletableFuture<BlockheadConnection> openFut,
|
||||
EndPoint endp,
|
||||
Executor executor)
|
||||
{
|
||||
super(policy, bufferPool, extensionStack, openFut, endp, executor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(WebSocketFrame frame)
|
||||
{
|
||||
if (frame.getMask() == null)
|
||||
{
|
||||
byte mask[] = new byte[4];
|
||||
ThreadLocalRandom.current().nextBytes(mask);
|
||||
frame.setMask(mask);
|
||||
}
|
||||
super.write(frame);
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.common.test;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
import org.junit.runners.Parameterized.Parameters;
|
||||
|
||||
/**
|
||||
* Gotta test some basic constructors of the BlockheadClient.
|
||||
*/
|
||||
@RunWith(value = Parameterized.class)
|
||||
public class BlockheadClientConstructionTest
|
||||
{
|
||||
@Parameters
|
||||
public static Collection<Object[]> data()
|
||||
{
|
||||
List<Object[]> data = new ArrayList<>();
|
||||
// @formatter:off
|
||||
data.add(new Object[] { "ws://localhost/", "http://localhost/" });
|
||||
data.add(new Object[] { "ws://localhost:8080/", "http://localhost:8080/" });
|
||||
data.add(new Object[] { "ws://webtide.com/", "http://webtide.com/" });
|
||||
data.add(new Object[] { "ws://www.webtide.com/sockets/chat", "http://www.webtide.com/sockets/chat" });
|
||||
// @formatter:on
|
||||
return data;
|
||||
}
|
||||
|
||||
private URI expectedWsUri;
|
||||
private URI expectedHttpUri;
|
||||
|
||||
public BlockheadClientConstructionTest(String wsuri, String httpuri)
|
||||
{
|
||||
this.expectedWsUri = URI.create(wsuri);
|
||||
this.expectedHttpUri = URI.create(httpuri);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testURIs() throws URISyntaxException
|
||||
{
|
||||
@SuppressWarnings("resource")
|
||||
BlockheadClient client = new BlockheadClient(expectedWsUri);
|
||||
Assert.assertThat("Websocket URI",client.getWebsocketURI(),is(expectedWsUri));
|
||||
Assert.assertThat("Websocket URI",client.getHttpURI(),is(expectedHttpUri));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,254 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.common.test;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.client.HttpConversation;
|
||||
import org.eclipse.jetty.client.HttpRequest;
|
||||
import org.eclipse.jetty.client.HttpResponse;
|
||||
import org.eclipse.jetty.client.HttpResponseException;
|
||||
import org.eclipse.jetty.client.api.ContentResponse;
|
||||
import org.eclipse.jetty.client.api.Response;
|
||||
import org.eclipse.jetty.client.api.Result;
|
||||
import org.eclipse.jetty.client.http.HttpConnectionOverHTTP;
|
||||
import org.eclipse.jetty.client.http.HttpConnectionUpgrader;
|
||||
import org.eclipse.jetty.client.util.ByteBufferContentProvider;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.http.HttpMethod;
|
||||
import org.eclipse.jetty.http.HttpStatus;
|
||||
import org.eclipse.jetty.http.HttpVersion;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.B64Code;
|
||||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeException;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.common.AcceptHash;
|
||||
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
|
||||
|
||||
public class BlockheadClientRequest extends HttpRequest implements Response.CompleteListener, HttpConnectionUpgrader
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(BlockheadClientRequest.class);
|
||||
private final BlockheadClient client;
|
||||
private final CompletableFuture<BlockheadConnection> fut;
|
||||
|
||||
protected BlockheadClientRequest(BlockheadClient client, URI uri)
|
||||
{
|
||||
super(client, new HttpConversation(), uri);
|
||||
this.client = client;
|
||||
this.fut = new CompletableFuture<>();
|
||||
}
|
||||
|
||||
public void setInitialBytes(ByteBuffer initialBytes)
|
||||
{
|
||||
content(new RawBytesProvider(initialBytes));
|
||||
}
|
||||
|
||||
private final String genRandomKey()
|
||||
{
|
||||
byte[] bytes = new byte[16];
|
||||
ThreadLocalRandom.current().nextBytes(bytes);
|
||||
return new String(B64Code.encode(bytes));
|
||||
}
|
||||
|
||||
private void initWebSocketHeaders()
|
||||
{
|
||||
method(HttpMethod.GET);
|
||||
version(HttpVersion.HTTP_1_1);
|
||||
|
||||
HttpFields fields = getHeaders();
|
||||
|
||||
// The Upgrade Headers
|
||||
if (!fields.contains(HttpHeader.UPGRADE))
|
||||
header(HttpHeader.UPGRADE, "websocket");
|
||||
if (!fields.contains(HttpHeader.CONNECTION))
|
||||
header(HttpHeader.CONNECTION, "Upgrade");
|
||||
|
||||
// The WebSocket Headers
|
||||
if (!fields.contains(HttpHeader.SEC_WEBSOCKET_KEY))
|
||||
header(HttpHeader.SEC_WEBSOCKET_KEY, genRandomKey());
|
||||
if (!fields.contains(HttpHeader.SEC_WEBSOCKET_VERSION))
|
||||
header(HttpHeader.SEC_WEBSOCKET_VERSION, "13");
|
||||
|
||||
// (Per the hybi list): Add no-cache headers to avoid compatibility issue.
|
||||
// There are some proxies that rewrite "Connection: upgrade"
|
||||
// to "Connection: close" in the response if a request doesn't contain
|
||||
// these headers.
|
||||
if (!fields.contains(HttpHeader.PRAGMA))
|
||||
header(HttpHeader.PRAGMA, "no-cache");
|
||||
if (!fields.contains(HttpHeader.CACHE_CONTROL))
|
||||
header(HttpHeader.CACHE_CONTROL, "no-cache");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContentResponse send() throws InterruptedException, TimeoutException, ExecutionException
|
||||
{
|
||||
throw new RuntimeException("Working with raw ContentResponse is invalid for WebSocket");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void send(final Response.CompleteListener listener)
|
||||
{
|
||||
initWebSocketHeaders();
|
||||
super.send(listener);
|
||||
}
|
||||
|
||||
public CompletableFuture<BlockheadConnection> sendAsync()
|
||||
{
|
||||
send(this);
|
||||
return fut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onComplete(Result result)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("onComplete() - {}", result);
|
||||
}
|
||||
|
||||
URI requestURI = result.getRequest().getURI();
|
||||
Response response = result.getResponse();
|
||||
int responseStatusCode = response.getStatus();
|
||||
String responseLine = responseStatusCode + " " + response.getReason();
|
||||
|
||||
if (result.isFailed())
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
if (result.getFailure() != null)
|
||||
LOG.debug("General Failure", result.getFailure());
|
||||
if (result.getRequestFailure() != null)
|
||||
LOG.debug("Request Failure", result.getRequestFailure());
|
||||
if (result.getResponseFailure() != null)
|
||||
LOG.debug("Response Failure", result.getResponseFailure());
|
||||
}
|
||||
|
||||
Throwable failure = result.getFailure();
|
||||
if ((failure instanceof java.net.ConnectException) || (failure instanceof UpgradeException))
|
||||
{
|
||||
// handle as-is
|
||||
handleException(failure);
|
||||
}
|
||||
else
|
||||
{
|
||||
// wrap in UpgradeException
|
||||
handleException(new UpgradeException(requestURI, responseStatusCode, responseLine, failure));
|
||||
}
|
||||
}
|
||||
|
||||
if (responseStatusCode != HttpStatus.SWITCHING_PROTOCOLS_101)
|
||||
{
|
||||
// Failed to upgrade (other reason)
|
||||
handleException(new UpgradeException(requestURI, responseStatusCode, responseLine));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleException(Throwable failure)
|
||||
{
|
||||
fut.completeExceptionally(failure);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upgrade(HttpResponse response, HttpConnectionOverHTTP oldConn)
|
||||
{
|
||||
if (!this.getHeaders().get(HttpHeader.UPGRADE).equalsIgnoreCase("websocket"))
|
||||
{
|
||||
// Not my upgrade
|
||||
throw new HttpResponseException("Not WebSocket Upgrade", response);
|
||||
}
|
||||
|
||||
// Check the Accept hash
|
||||
String reqKey = this.getHeaders().get(HttpHeader.SEC_WEBSOCKET_KEY);
|
||||
String expectedHash = AcceptHash.hashKey(reqKey);
|
||||
String respHash = response.getHeaders().get(HttpHeader.SEC_WEBSOCKET_ACCEPT);
|
||||
|
||||
if (expectedHash.equalsIgnoreCase(respHash) == false)
|
||||
{
|
||||
throw new HttpResponseException("Invalid Sec-WebSocket-Accept hash", response);
|
||||
}
|
||||
|
||||
// We can upgrade
|
||||
EndPoint endp = oldConn.getEndPoint();
|
||||
|
||||
ExtensionStack extensionStack = new ExtensionStack(client.getExtensionFactory());
|
||||
List<ExtensionConfig> extensions = new ArrayList<>();
|
||||
HttpField extField = response.getHeaders().getField(HttpHeader.SEC_WEBSOCKET_EXTENSIONS);
|
||||
if (extField != null)
|
||||
{
|
||||
String[] extValues = extField.getValues();
|
||||
if (extValues != null)
|
||||
{
|
||||
for (String extVal : extValues)
|
||||
{
|
||||
QuotedStringTokenizer tok = new QuotedStringTokenizer(extVal, ",");
|
||||
while (tok.hasMoreTokens())
|
||||
{
|
||||
extensions.add(ExtensionConfig.parse(tok.nextToken()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
extensionStack.negotiate(extensions);
|
||||
|
||||
BlockheadClientConnection connection = new BlockheadClientConnection(
|
||||
client.getPolicy(),
|
||||
client.getBufferPool(),
|
||||
extensionStack,
|
||||
fut,
|
||||
endp,
|
||||
client.getExecutor());
|
||||
|
||||
endp.setIdleTimeout(client.getIdleTimeout());
|
||||
|
||||
connection.setUpgradeRequestHeaders(this.getHeaders());
|
||||
connection.setUpgradeResponseHeaders(response.getHeaders());
|
||||
|
||||
// Now swap out the connection
|
||||
endp.upgrade(connection);
|
||||
}
|
||||
|
||||
/**
|
||||
* Raw Bytes Content Provider (intentionally without a Content-Type)
|
||||
*/
|
||||
public static class RawBytesProvider extends ByteBufferContentProvider
|
||||
{
|
||||
public RawBytesProvider(ByteBuffer buf)
|
||||
{
|
||||
super(buf);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getContentType()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,414 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.common.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.io.AbstractConnection;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.Connection;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
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.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
|
||||
import org.eclipse.jetty.websocket.common.Generator;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
|
||||
|
||||
public class BlockheadConnection extends AbstractConnection implements Connection.UpgradeTo
|
||||
{
|
||||
private final static int BUFFER_SIZE = 4096;
|
||||
public static final String STATIC_REQUEST_HASH_KEY = "dGhlIHNhbXBsZSBub25jZQ==";
|
||||
private final Logger LOG;
|
||||
private final WebSocketPolicy policy;
|
||||
private final ByteBufferPool bufferPool;
|
||||
private final Parser parser;
|
||||
private final Generator generator;
|
||||
private final ExtensionStack extensionStack;
|
||||
private final OutgoingNetwork networkOutgoing;
|
||||
private final IncomingCapture incomingCapture;
|
||||
private final CompletableFuture<BlockheadConnection> openFuture;
|
||||
private ByteBuffer networkBuffer;
|
||||
private HttpFields upgradeResponseHeaders;
|
||||
private HttpFields upgradeRequestHeaders;
|
||||
|
||||
public BlockheadConnection(WebSocketPolicy policy, ByteBufferPool bufferPool, ExtensionStack extensionStack, CompletableFuture<BlockheadConnection> openFut, EndPoint endp, Executor executor)
|
||||
{
|
||||
super(endp, executor);
|
||||
this.LOG = Log.getLogger(this.getClass());
|
||||
this.policy = policy;
|
||||
this.bufferPool = bufferPool;
|
||||
this.parser = new Parser(policy, bufferPool);
|
||||
this.generator = new Generator(policy, bufferPool, false);
|
||||
this.extensionStack = extensionStack;
|
||||
this.openFuture = openFut;
|
||||
|
||||
this.extensionStack.configure(this.parser);
|
||||
this.extensionStack.configure(this.generator);
|
||||
|
||||
// Wire up incoming frames (network -> extensionStack -> connection)
|
||||
this.parser.setIncomingFramesHandler(extensionStack);
|
||||
this.incomingCapture = new IncomingCapture();
|
||||
this.extensionStack.setNextIncoming(incomingCapture);
|
||||
|
||||
// Wire up outgoing frames (connection -> extensionStack -> network)
|
||||
this.networkOutgoing = new OutgoingNetwork();
|
||||
extensionStack.setNextOutgoing(networkOutgoing);
|
||||
|
||||
try
|
||||
{
|
||||
extensionStack.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new RuntimeException("Unable to start ExtensionStack", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void abort()
|
||||
{
|
||||
EndPoint endPoint = getEndPoint();
|
||||
// We need to gently close first, to allow
|
||||
// SSL close alerts to be sent by Jetty
|
||||
endPoint.shutdownOutput();
|
||||
endPoint.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fillInterested()
|
||||
{
|
||||
// Handle situation where initial/prefill buffer (from upgrade) has created network buffer,
|
||||
// but there is no actual read interest (yet)
|
||||
if (BufferUtil.hasContent(networkBuffer))
|
||||
{
|
||||
fillAndParse();
|
||||
}
|
||||
else
|
||||
{
|
||||
super.fillInterested();
|
||||
}
|
||||
}
|
||||
|
||||
public ByteBufferPool getBufferPool()
|
||||
{
|
||||
return bufferPool;
|
||||
}
|
||||
|
||||
public LinkedBlockingQueue<WebSocketFrame> getFrameQueue()
|
||||
{
|
||||
return incomingCapture.incomingFrames;
|
||||
}
|
||||
|
||||
public Generator getGenerator()
|
||||
{
|
||||
return generator;
|
||||
}
|
||||
|
||||
public InetSocketAddress getLocalSocketAddress()
|
||||
{
|
||||
return getEndPoint().getLocalAddress();
|
||||
}
|
||||
|
||||
public Parser getParser()
|
||||
{
|
||||
return parser;
|
||||
}
|
||||
|
||||
public InetSocketAddress getRemoteSocketAddress()
|
||||
{
|
||||
return getEndPoint().getRemoteAddress();
|
||||
}
|
||||
|
||||
public HttpFields getUpgradeRequestHeaders()
|
||||
{
|
||||
return upgradeRequestHeaders;
|
||||
}
|
||||
|
||||
public HttpFields getUpgradeResponseHeaders()
|
||||
{
|
||||
return upgradeResponseHeaders;
|
||||
}
|
||||
|
||||
public boolean isOpen()
|
||||
{
|
||||
return getEndPoint().isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFillable()
|
||||
{
|
||||
getNetworkBuffer();
|
||||
fillAndParse();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgradeTo(ByteBuffer prefilled)
|
||||
{
|
||||
setInitialBuffer(prefilled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onOpen()
|
||||
{
|
||||
super.onOpen();
|
||||
if(this.openFuture != null)
|
||||
this.openFuture.complete(this);
|
||||
fillInterested();
|
||||
}
|
||||
|
||||
public void processConnectionError(Throwable cause)
|
||||
{
|
||||
LOG.warn("Connection Error", cause);
|
||||
if(this.openFuture != null)
|
||||
this.openFuture.completeExceptionally(cause);
|
||||
}
|
||||
|
||||
public void setUpgradeRequestHeaders(HttpFields upgradeRequestHeaders)
|
||||
{
|
||||
this.upgradeRequestHeaders = new HttpFields(upgradeRequestHeaders);
|
||||
}
|
||||
|
||||
public void setUpgradeResponseHeaders(HttpFields upgradeResponseHeaders)
|
||||
{
|
||||
this.upgradeResponseHeaders = new HttpFields(upgradeResponseHeaders);
|
||||
}
|
||||
|
||||
public void setIncomingFrameConsumer(Consumer<Frame> consumer)
|
||||
{
|
||||
this.incomingCapture.frameConsumer = consumer;
|
||||
}
|
||||
|
||||
public void write(WebSocketFrame frame)
|
||||
{
|
||||
networkOutgoing.outgoingFrame(frame, null, BatchMode.OFF);
|
||||
}
|
||||
|
||||
public void writeRaw(ByteBuffer buf) throws IOException
|
||||
{
|
||||
boolean done = false;
|
||||
while (!done)
|
||||
{
|
||||
done = getEndPoint().flush(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeRaw(ByteBuffer buf, int numBytes) throws IOException
|
||||
{
|
||||
int len = Math.min(numBytes, buf.remaining());
|
||||
ByteBuffer slice = buf.slice();
|
||||
buf.limit(len);
|
||||
try
|
||||
{
|
||||
boolean done = false;
|
||||
while (!done)
|
||||
{
|
||||
done = getEndPoint().flush(slice);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
throw e;
|
||||
}
|
||||
finally
|
||||
{
|
||||
buf.position(buf.position() + len);
|
||||
}
|
||||
}
|
||||
|
||||
public void writeRawSlowly(ByteBuffer buf, int segmentSize) throws IOException
|
||||
{
|
||||
while (buf.remaining() > 0)
|
||||
{
|
||||
writeRaw(buf, segmentSize);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extra bytes from the initial HTTP upgrade that need to
|
||||
* be processed by the websocket parser before starting
|
||||
* to read bytes from the connection
|
||||
*
|
||||
* @param prefilled the bytes of prefilled content encountered during upgrade
|
||||
*/
|
||||
protected void setInitialBuffer(ByteBuffer prefilled)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("set Initial Buffer - {}", BufferUtil.toDetailString(prefilled));
|
||||
}
|
||||
|
||||
if ((prefilled != null) && (prefilled.hasRemaining()))
|
||||
{
|
||||
networkBuffer = bufferPool.acquire(prefilled.remaining(), true);
|
||||
BufferUtil.clearToFill(networkBuffer);
|
||||
BufferUtil.put(prefilled, networkBuffer);
|
||||
BufferUtil.flipToFlush(networkBuffer, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void fillAndParse()
|
||||
{
|
||||
boolean interested = false;
|
||||
|
||||
try
|
||||
{
|
||||
while (getEndPoint().isOpen())
|
||||
{
|
||||
ByteBuffer nBuffer = getNetworkBuffer();
|
||||
|
||||
parser.parse(nBuffer);
|
||||
|
||||
// Shouldn't reach this point if buffer has un-parsed bytes
|
||||
assert (!nBuffer.hasRemaining());
|
||||
|
||||
int filled = getEndPoint().fill(nBuffer);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("endpointFill() filled={}: {}", filled, BufferUtil.toDetailString(nBuffer));
|
||||
|
||||
if (filled < 0)
|
||||
{
|
||||
releaseNetworkBuffer(nBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if (filled == 0)
|
||||
{
|
||||
releaseNetworkBuffer(nBuffer);
|
||||
interested = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
processConnectionError(t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (interested)
|
||||
fillInterested();
|
||||
}
|
||||
}
|
||||
|
||||
private ByteBuffer getNetworkBuffer()
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
if (networkBuffer == null)
|
||||
{
|
||||
networkBuffer = bufferPool.acquire(BUFFER_SIZE, true);
|
||||
}
|
||||
return networkBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
private void releaseNetworkBuffer(ByteBuffer buffer)
|
||||
{
|
||||
synchronized (this)
|
||||
{
|
||||
assert (!buffer.hasRemaining());
|
||||
bufferPool.release(buffer);
|
||||
networkBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public class IncomingCapture implements IncomingFrames
|
||||
{
|
||||
public final LinkedBlockingQueue<WebSocketFrame> incomingFrames = new LinkedBlockingQueue<>();
|
||||
public final LinkedBlockingQueue<Throwable> incomingErrors = new LinkedBlockingQueue<>();
|
||||
public Consumer<Frame> frameConsumer;
|
||||
|
||||
@Override
|
||||
public void incomingError(Throwable cause)
|
||||
{
|
||||
incomingErrors.offer(cause);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
if(frameConsumer != null)
|
||||
frameConsumer.accept(frame);
|
||||
|
||||
incomingFrames.offer(WebSocketFrame.copy(frame));
|
||||
}
|
||||
}
|
||||
|
||||
public class OutgoingNetwork implements OutgoingFrames
|
||||
{
|
||||
/**
|
||||
* Last step for networkOutgoing frames before the network buffer.
|
||||
* <p>
|
||||
* if ExtensionStack is in play, this should be wired up to the output from
|
||||
* the ExtensionStack.
|
||||
* </p>
|
||||
*
|
||||
* @param frame the frame to eventually write to the network layer.
|
||||
* @param callback the callback to notify when the frame is written.
|
||||
* @param batchMode ignored by BlockheadConnections
|
||||
*/
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
|
||||
{
|
||||
ByteBuffer header = generator.generateHeaderBytes(frame);
|
||||
ByteBuffer payload = frame.getPayload();
|
||||
if (payload == null)
|
||||
payload = BufferUtil.EMPTY_BUFFER;
|
||||
|
||||
Callback jettyCallback = asJettyCallback(callback);
|
||||
try
|
||||
{
|
||||
getEndPoint().flush(header, payload);
|
||||
jettyCallback.succeeded();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
jettyCallback.failed(e);
|
||||
}
|
||||
}
|
||||
|
||||
private Callback asJettyCallback(final WriteCallback writeCallback)
|
||||
{
|
||||
if (writeCallback instanceof org.eclipse.jetty.util.Callback)
|
||||
{
|
||||
return (org.eclipse.jetty.util.Callback) writeCallback;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new WriteCallbackDelegate(writeCallback);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,45 +18,116 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.test;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.Socket;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.server.Connector;
|
||||
import org.eclipse.jetty.server.HttpConnection;
|
||||
import org.eclipse.jetty.server.Request;
|
||||
import org.eclipse.jetty.server.Response;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.server.handler.AbstractHandler;
|
||||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.server.handler.HandlerList;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.common.AcceptHash;
|
||||
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
|
||||
import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.eclipse.jetty.websocket.common.scopes.WebSocketContainerScope;
|
||||
|
||||
/**
|
||||
* A overly simplistic websocket server used during testing.
|
||||
* A Server capable of WebSocket upgrade useful for testing.
|
||||
* <p>
|
||||
* This is not meant to be performant or accurate. In fact, having the server misbehave is a useful trait during testing.
|
||||
* This implementation exists to allow for testing of non-standard server behaviors,
|
||||
* especially around the WebSocket Upgrade process.
|
||||
*/
|
||||
public class BlockheadServer
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(BlockheadServer.class);
|
||||
private ServerSocket serverSocket;
|
||||
public static final String SEC_WEBSOCKET_EXTENSIONS = HttpHeader.SEC_WEBSOCKET_EXTENSIONS.toString();
|
||||
|
||||
private final Server server;
|
||||
private final ServerConnector connector;
|
||||
private final BlockheadServerHandler serverHandler;
|
||||
private final WebSocketPolicy policy;
|
||||
private final WebSocketContainerScope websocketContainer;
|
||||
private final WebSocketExtensionFactory extensionFactory;
|
||||
private URI wsUri;
|
||||
|
||||
public IBlockheadServerConnection accept() throws IOException
|
||||
public BlockheadServer()
|
||||
{
|
||||
LOG.debug(".accept()");
|
||||
assertIsStarted();
|
||||
Socket socket = serverSocket.accept();
|
||||
return new BlockheadServerConnection(socket);
|
||||
this.server = new Server();
|
||||
this.connector = new ServerConnector(this.server);
|
||||
this.connector.setPort(0);
|
||||
this.server.addConnector(connector);
|
||||
|
||||
this.policy = new WebSocketPolicy(WebSocketBehavior.SERVER);
|
||||
this.websocketContainer = new SimpleContainerScope(policy);
|
||||
this.extensionFactory = new WebSocketExtensionFactory(websocketContainer);
|
||||
|
||||
HandlerList handlers = new HandlerList();
|
||||
this.serverHandler = new BlockheadServerHandler(websocketContainer, extensionFactory);
|
||||
handlers.addHandler(this.serverHandler);
|
||||
handlers.addHandler(new DefaultHandler());
|
||||
this.server.setHandler(handlers);
|
||||
}
|
||||
|
||||
private void assertIsStarted()
|
||||
public void addConnectFuture(CompletableFuture<BlockheadConnection> serverConnFut)
|
||||
{
|
||||
Assert.assertThat("ServerSocket",serverSocket,notNullValue());
|
||||
Assert.assertThat("ServerSocket.isBound",serverSocket.isBound(),is(true));
|
||||
Assert.assertThat("ServerSocket.isClosed",serverSocket.isClosed(),is(false));
|
||||
this.serverHandler.getWSConnectionFutures().offer(serverConnFut);
|
||||
}
|
||||
|
||||
Assert.assertThat("WsUri",wsUri,notNullValue());
|
||||
public WebSocketExtensionFactory getExtensionFactory()
|
||||
{
|
||||
return extensionFactory;
|
||||
}
|
||||
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
public WebSocketContainerScope getWebsocketContainer()
|
||||
{
|
||||
return websocketContainer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set PRE-Request Handling function.
|
||||
*
|
||||
* @param requestFunction the function to handle the request (before upgrade), do whatever you want.
|
||||
* Note that if you return true, the request will not process into the default Upgrade flow,
|
||||
* false will allow the default Upgrade flow.
|
||||
*/
|
||||
public void setRequestHandling(BiFunction<Request, Response, Boolean> requestFunction)
|
||||
{
|
||||
this.serverHandler.setFunction(requestFunction);
|
||||
}
|
||||
|
||||
public void resetRequestHandling()
|
||||
{
|
||||
this.serverHandler.setFunction(null);
|
||||
}
|
||||
|
||||
public URI getWsUri()
|
||||
|
@ -64,28 +135,142 @@ public class BlockheadServer
|
|||
return wsUri;
|
||||
}
|
||||
|
||||
public void start() throws IOException
|
||||
public void start() throws Exception
|
||||
{
|
||||
InetAddress addr = InetAddress.getByName("localhost");
|
||||
serverSocket = new ServerSocket();
|
||||
InetSocketAddress endpoint = new InetSocketAddress(addr,0);
|
||||
serverSocket.bind(endpoint,1);
|
||||
int port = serverSocket.getLocalPort();
|
||||
String uri = String.format("ws://%s:%d/",addr.getHostAddress(),port);
|
||||
wsUri = URI.create(uri);
|
||||
LOG.debug("Server Started on {} -> {}",endpoint,wsUri);
|
||||
this.server.start();
|
||||
|
||||
wsUri = URI.create("ws://localhost:" + this.connector.getLocalPort() + "/");
|
||||
|
||||
LOG.debug("BlockheadServer available on {}", wsUri);
|
||||
}
|
||||
|
||||
public void stop()
|
||||
public void stop() throws Exception
|
||||
{
|
||||
LOG.debug("Stopping Server");
|
||||
this.server.stop();
|
||||
}
|
||||
|
||||
public static class BlockheadServerHandler extends AbstractHandler
|
||||
{
|
||||
private final WebSocketContainerScope container;
|
||||
private final WebSocketExtensionFactory extensionFactory;
|
||||
private BiFunction<Request, Response, Boolean> requestFunction;
|
||||
private LinkedBlockingQueue<CompletableFuture<BlockheadConnection>> futuresQueue;
|
||||
|
||||
public BlockheadServerHandler(WebSocketContainerScope websocketContainer, WebSocketExtensionFactory extensionFactory)
|
||||
{
|
||||
super();
|
||||
this.container = websocketContainer;
|
||||
this.extensionFactory = extensionFactory;
|
||||
this.futuresQueue = new LinkedBlockingQueue<>();
|
||||
}
|
||||
|
||||
public Queue<CompletableFuture<BlockheadConnection>> getWSConnectionFutures()
|
||||
{
|
||||
return futuresQueue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
|
||||
{
|
||||
Response baseResponse = (Response) response;
|
||||
if(requestFunction != null)
|
||||
{
|
||||
if(requestFunction.apply(baseRequest, baseResponse))
|
||||
{
|
||||
baseRequest.setHandled(true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CompletableFuture<BlockheadConnection> connFut = this.futuresQueue.poll();
|
||||
|
||||
try
|
||||
{
|
||||
serverSocket.close();
|
||||
}
|
||||
catch (IOException ignore)
|
||||
baseRequest.setHandled(true);
|
||||
|
||||
// default/simplified Upgrade flow
|
||||
String key = request.getHeader("Sec-WebSocket-Key");
|
||||
|
||||
if (key == null)
|
||||
{
|
||||
/* ignore */
|
||||
throw new IllegalStateException("Missing request header 'Sec-WebSocket-Key'");
|
||||
}
|
||||
|
||||
// build response
|
||||
response.setHeader("Upgrade", "WebSocket");
|
||||
response.addHeader("Connection", "Upgrade");
|
||||
response.addHeader("Sec-WebSocket-Accept", AcceptHash.hashKey(key));
|
||||
|
||||
response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
|
||||
|
||||
// Initialize / Negotiate Extensions
|
||||
ExtensionStack extensionStack = new ExtensionStack(extensionFactory);
|
||||
|
||||
if (response.containsHeader(SEC_WEBSOCKET_EXTENSIONS))
|
||||
{
|
||||
// Use pre-negotiated extension list from response
|
||||
List<ExtensionConfig> extensionConfigs = new ArrayList<>();
|
||||
response.getHeaders(SEC_WEBSOCKET_EXTENSIONS).forEach(
|
||||
(value) -> extensionConfigs.addAll(ExtensionConfig.parseList(value)));
|
||||
extensionStack.negotiate(extensionConfigs);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use what was given to us
|
||||
Enumeration<String> e = request.getHeaders(SEC_WEBSOCKET_EXTENSIONS);
|
||||
List<ExtensionConfig> extensionConfigs = ExtensionConfig.parseEnum(e);
|
||||
extensionStack.negotiate(extensionConfigs);
|
||||
|
||||
String negotiatedHeaderValue = ExtensionConfig.toHeaderValue(extensionStack.getNegotiatedExtensions());
|
||||
response.setHeader(SEC_WEBSOCKET_EXTENSIONS, negotiatedHeaderValue);
|
||||
}
|
||||
|
||||
WebSocketPolicy policy = this.container.getPolicy().clonePolicy();
|
||||
|
||||
// Get original HTTP connection
|
||||
HttpConnection http = (HttpConnection) request.getAttribute("org.eclipse.jetty.server.HttpConnection");
|
||||
|
||||
EndPoint endp = http.getEndPoint();
|
||||
Connector connector = http.getConnector();
|
||||
Executor executor = connector.getExecutor();
|
||||
ByteBufferPool bufferPool = connector.getByteBufferPool();
|
||||
|
||||
// Setup websocket connection
|
||||
BlockheadServerConnection wsConnection = new BlockheadServerConnection(
|
||||
policy,
|
||||
bufferPool,
|
||||
extensionStack,
|
||||
connFut,
|
||||
endp,
|
||||
executor);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("HttpConnection: {}", http);
|
||||
LOG.debug("BlockheadServerConnection: {}", wsConnection);
|
||||
}
|
||||
|
||||
wsConnection.setUpgradeRequestHeaders(baseRequest.getHttpFields());
|
||||
wsConnection.setUpgradeResponseHeaders(baseResponse.getHttpFields());
|
||||
|
||||
// Tell jetty about the new upgraded connection
|
||||
request.setAttribute(HttpConnection.UPGRADE_CONNECTION_ATTRIBUTE, wsConnection);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Websocket upgrade {} {}", request.getRequestURI(), wsConnection);
|
||||
}
|
||||
catch(Throwable cause)
|
||||
{
|
||||
if(connFut != null)
|
||||
connFut.completeExceptionally(cause);
|
||||
LOG.warn(cause);
|
||||
}
|
||||
}
|
||||
|
||||
public void setFunction(BiFunction<Request, Response, Boolean> function)
|
||||
{
|
||||
this.requestFunction = function;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,618 +18,23 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.test;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.IO;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.io.EndPoint;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.api.extensions.OutgoingFrames;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame.Type;
|
||||
import org.eclipse.jetty.websocket.common.AcceptHash;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.Generator;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
|
||||
import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
|
||||
import org.eclipse.jetty.websocket.common.frames.CloseFrame;
|
||||
import org.eclipse.jetty.websocket.common.scopes.SimpleContainerScope;
|
||||
import org.junit.Assert;
|
||||
|
||||
public class BlockheadServerConnection implements IncomingFrames, OutgoingFrames, Runnable, IBlockheadServerConnection
|
||||
public class BlockheadServerConnection extends BlockheadConnection
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(BlockheadServerConnection.class);
|
||||
|
||||
private final int BUFFER_SIZE = 8192;
|
||||
private final Socket socket;
|
||||
private final ByteBufferPool bufferPool;
|
||||
private final WebSocketPolicy policy;
|
||||
private final IncomingFramesCapture incomingFrames;
|
||||
private final Parser parser;
|
||||
private final Generator generator;
|
||||
private final AtomicInteger parseCount;
|
||||
private final WebSocketExtensionFactory extensionRegistry;
|
||||
private final AtomicBoolean echoing = new AtomicBoolean(false);
|
||||
private Thread echoThread;
|
||||
|
||||
/** Set to true to disable timeouts (for debugging reasons) */
|
||||
private boolean debug = false;
|
||||
private OutputStream out;
|
||||
private InputStream in;
|
||||
|
||||
private Map<String, String> extraResponseHeaders = new HashMap<>();
|
||||
private OutgoingFrames outgoing = this;
|
||||
|
||||
public BlockheadServerConnection(Socket socket)
|
||||
{
|
||||
this.socket = socket;
|
||||
this.incomingFrames = new IncomingFramesCapture();
|
||||
this.policy = WebSocketPolicy.newServerPolicy();
|
||||
this.policy.setMaxBinaryMessageSize(100000);
|
||||
this.policy.setMaxTextMessageSize(100000);
|
||||
// This is a blockhead server connection, no point tracking leaks on this object.
|
||||
this.bufferPool = new MappedByteBufferPool(BUFFER_SIZE);
|
||||
this.parser = new Parser(policy,bufferPool);
|
||||
this.parseCount = new AtomicInteger(0);
|
||||
this.generator = new Generator(policy,bufferPool,false);
|
||||
this.extensionRegistry = new WebSocketExtensionFactory(new SimpleContainerScope(policy,bufferPool));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an extra header for the upgrade response (from the server). No extra work is done to ensure the key and value are sane for http.
|
||||
* @param rawkey the raw key
|
||||
* @param rawvalue the raw value
|
||||
*/
|
||||
@Override
|
||||
public void addResponseHeader(String rawkey, String rawvalue)
|
||||
{
|
||||
extraResponseHeaders.put(rawkey,rawvalue);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection#close()
|
||||
*/
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
write(new CloseFrame());
|
||||
flush();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection#close(int)
|
||||
*/
|
||||
@Override
|
||||
public void close(int statusCode) throws IOException
|
||||
{
|
||||
CloseInfo close = new CloseInfo(statusCode);
|
||||
write(close.asFrame());
|
||||
flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
LOG.debug("disconnect");
|
||||
IO.close(in);
|
||||
IO.close(out);
|
||||
if (socket != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.close();
|
||||
}
|
||||
catch (IOException ignore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void echoMessage(int expectedFrames, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException
|
||||
{
|
||||
LOG.debug("Echo Frames [expecting {}]",expectedFrames);
|
||||
IncomingFramesCapture cap = readFrames(expectedFrames,timeoutDuration,timeoutUnit);
|
||||
// now echo them back.
|
||||
for (Frame frame : cap.getFrames())
|
||||
{
|
||||
write(WebSocketFrame.copy(frame).setMasked(false));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() throws IOException
|
||||
{
|
||||
getOutputStream().flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufferPool getBufferPool()
|
||||
{
|
||||
return bufferPool;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IncomingFramesCapture getIncomingFrames()
|
||||
{
|
||||
return incomingFrames;
|
||||
}
|
||||
|
||||
public InputStream getInputStream() throws IOException
|
||||
{
|
||||
if (in == null)
|
||||
{
|
||||
in = socket.getInputStream();
|
||||
}
|
||||
return in;
|
||||
}
|
||||
|
||||
private OutputStream getOutputStream() throws IOException
|
||||
{
|
||||
if (out == null)
|
||||
{
|
||||
out = socket.getOutputStream();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parser getParser()
|
||||
{
|
||||
return parser;
|
||||
}
|
||||
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
incomingFrames.incomingError(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
LOG.debug("incoming({})",frame);
|
||||
int count = parseCount.incrementAndGet();
|
||||
if ((count % 10) == 0)
|
||||
{
|
||||
LOG.info("Server parsed {} frames",count);
|
||||
}
|
||||
incomingFrames.incomingFrame(WebSocketFrame.copy(frame));
|
||||
|
||||
if (frame.getOpCode() == OpCode.CLOSE)
|
||||
{
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
LOG.debug("Close frame: {}",close);
|
||||
}
|
||||
|
||||
Type type = frame.getType();
|
||||
if (echoing.get() && (type.isData() || type.isContinuation()))
|
||||
{
|
||||
try
|
||||
{
|
||||
write(WebSocketFrame.copy(frame).setMasked(false));
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback, BatchMode batchMode)
|
||||
{
|
||||
ByteBuffer headerBuf = generator.generateHeaderBytes(frame);
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("writing out: {}",BufferUtil.toDetailString(headerBuf));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
BufferUtil.writeTo(headerBuf,out);
|
||||
if (frame.hasPayload())
|
||||
BufferUtil.writeTo(frame.getPayload(),out);
|
||||
out.flush();
|
||||
if (callback != null)
|
||||
{
|
||||
callback.writeSuccess();
|
||||
}
|
||||
|
||||
if (frame.getOpCode() == OpCode.CLOSE)
|
||||
{
|
||||
disconnect();
|
||||
}
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
if (callback != null)
|
||||
{
|
||||
callback.writeFailed(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public List<ExtensionConfig> parseExtensions(List<String> requestLines)
|
||||
{
|
||||
List<ExtensionConfig> extensionConfigs = new ArrayList<>();
|
||||
|
||||
List<String> hits = regexFind(requestLines, "^Sec-WebSocket-Extensions: (.*)$");
|
||||
|
||||
for (String econf : hits)
|
||||
{
|
||||
// found extensions
|
||||
ExtensionConfig config = ExtensionConfig.parse(econf);
|
||||
extensionConfigs.add(config);
|
||||
}
|
||||
|
||||
return extensionConfigs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parseWebSocketKey(List<String> requestLines)
|
||||
{
|
||||
List<String> hits = regexFind(requestLines,"^Sec-WebSocket-Key: (.*)$");
|
||||
if (hits.size() <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Assert.assertThat("Number of Sec-WebSocket-Key headers", hits.size(), is(1));
|
||||
|
||||
String key = hits.get(0);
|
||||
return key;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(ByteBuffer buf) throws IOException
|
||||
{
|
||||
int len = 0;
|
||||
while ((in.available() > 0) && (buf.remaining() > 0))
|
||||
{
|
||||
buf.put((byte)in.read());
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IncomingFramesCapture readFrames(int expectedCount, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException
|
||||
{
|
||||
LOG.debug("Read: waiting for {} frame(s) from client",expectedCount);
|
||||
int startCount = incomingFrames.size();
|
||||
|
||||
ByteBuffer buf = bufferPool.acquire(BUFFER_SIZE,false);
|
||||
BufferUtil.clearToFill(buf);
|
||||
try
|
||||
{
|
||||
long msDur = TimeUnit.MILLISECONDS.convert(timeoutDuration,timeoutUnit);
|
||||
long now = System.currentTimeMillis();
|
||||
long expireOn = now + msDur;
|
||||
LOG.debug("Now: {} - expireOn: {} ({} ms)",now,expireOn,msDur);
|
||||
|
||||
int len = 0;
|
||||
while (incomingFrames.size() < (startCount + expectedCount))
|
||||
{
|
||||
BufferUtil.clearToFill(buf);
|
||||
len = read(buf);
|
||||
if (len > 0)
|
||||
{
|
||||
LOG.debug("Read {} bytes",len);
|
||||
BufferUtil.flipToFlush(buf,0);
|
||||
parser.parse(buf);
|
||||
}
|
||||
try
|
||||
{
|
||||
TimeUnit.MILLISECONDS.sleep(20);
|
||||
}
|
||||
catch (InterruptedException gnore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
if (!debug && (System.currentTimeMillis() > expireOn))
|
||||
{
|
||||
incomingFrames.dump();
|
||||
throw new TimeoutException(String.format("Timeout reading all %d expected frames. (managed to only read %d frame(s))",expectedCount,
|
||||
incomingFrames.size()));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
bufferPool.release(buf);
|
||||
}
|
||||
|
||||
return incomingFrames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String readRequest() throws IOException
|
||||
{
|
||||
LOG.debug("Reading client request");
|
||||
StringBuilder request = new StringBuilder();
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
for (String line = in.readLine(); line != null; line = in.readLine())
|
||||
{
|
||||
if (line.length() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
request.append(line).append("\r\n");
|
||||
LOG.debug("read line: {}",line);
|
||||
}
|
||||
|
||||
LOG.debug("Client Request:{}{}","\n",request);
|
||||
return request.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> readRequestLines() throws IOException
|
||||
{
|
||||
LOG.debug("Reading client request header");
|
||||
List<String> lines = new ArrayList<>();
|
||||
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(getInputStream()));
|
||||
for (String line = in.readLine(); line != null; line = in.readLine())
|
||||
{
|
||||
if (line.length() == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
lines.add(line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> regexFind(List<String> lines, String pattern)
|
||||
{
|
||||
List<String> hits = new ArrayList<>();
|
||||
|
||||
Pattern patKey = Pattern.compile(pattern,Pattern.CASE_INSENSITIVE);
|
||||
|
||||
Matcher mat;
|
||||
for (String line : lines)
|
||||
{
|
||||
mat = patKey.matcher(line);
|
||||
if (mat.matches())
|
||||
{
|
||||
if (mat.groupCount() >= 1)
|
||||
{
|
||||
hits.add(mat.group(1));
|
||||
}
|
||||
else
|
||||
{
|
||||
hits.add(mat.group(0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hits;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void respond(String rawstr) throws IOException
|
||||
{
|
||||
LOG.debug("respond(){}{}","\n",rawstr);
|
||||
getOutputStream().write(rawstr.getBytes());
|
||||
flush();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run()
|
||||
{
|
||||
LOG.debug("Entering echo thread");
|
||||
|
||||
ByteBuffer buf = bufferPool.acquire(BUFFER_SIZE,false);
|
||||
BufferUtil.clearToFill(buf);
|
||||
long readBytes = 0;
|
||||
try
|
||||
{
|
||||
while (echoing.get())
|
||||
{
|
||||
BufferUtil.clearToFill(buf);
|
||||
long len = read(buf);
|
||||
if (len > 0)
|
||||
{
|
||||
readBytes += len;
|
||||
LOG.debug("Read {} bytes",len);
|
||||
BufferUtil.flipToFlush(buf,0);
|
||||
parser.parse(buf);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
TimeUnit.MILLISECONDS.sleep(20);
|
||||
}
|
||||
catch (InterruptedException gnore)
|
||||
{
|
||||
/* ignore */
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.debug("Exception during echo loop",e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
LOG.debug("Read {} bytes",readBytes);
|
||||
bufferPool.release(buf);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSoTimeout(int ms) throws SocketException
|
||||
{
|
||||
socket.setSoTimeout(ms);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startEcho()
|
||||
{
|
||||
if (echoThread != null)
|
||||
{
|
||||
throw new IllegalStateException("Echo thread already declared!");
|
||||
}
|
||||
echoThread = new Thread(this,"BlockheadServer/Echo");
|
||||
echoing.set(true);
|
||||
echoThread.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopEcho()
|
||||
{
|
||||
echoing.set(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> upgrade() throws IOException
|
||||
{
|
||||
List<String> requestLines = readRequestLines();
|
||||
List<ExtensionConfig> extensionConfigs = parseExtensions(requestLines);
|
||||
String key = parseWebSocketKey(requestLines);
|
||||
|
||||
LOG.debug("Client Request Extensions: {}",extensionConfigs);
|
||||
LOG.debug("Client Request Key: {}",key);
|
||||
|
||||
Assert.assertThat("Request: Sec-WebSocket-Key",key,notNullValue());
|
||||
|
||||
// collect extensions configured in response header
|
||||
ExtensionStack extensionStack = new ExtensionStack(extensionRegistry);
|
||||
extensionStack.negotiate(extensionConfigs);
|
||||
|
||||
// Start with default routing
|
||||
extensionStack.setNextIncoming(this);
|
||||
extensionStack.setNextOutgoing(this);
|
||||
|
||||
// Configure Parser / Generator
|
||||
extensionStack.configure(parser);
|
||||
extensionStack.configure(generator);
|
||||
|
||||
// Start Stack
|
||||
try
|
||||
{
|
||||
extensionStack.start();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException("Unable to start Extension Stack");
|
||||
}
|
||||
|
||||
// Configure Parser
|
||||
parser.setIncomingFramesHandler(extensionStack);
|
||||
|
||||
// Setup Response
|
||||
StringBuilder resp = new StringBuilder();
|
||||
resp.append("HTTP/1.1 101 Upgrade\r\n");
|
||||
resp.append("Connection: upgrade\r\n");
|
||||
resp.append("Content-Length: 0\r\n");
|
||||
resp.append("Sec-WebSocket-Accept: ");
|
||||
resp.append(AcceptHash.hashKey(key)).append("\r\n");
|
||||
if (extensionStack.hasNegotiatedExtensions())
|
||||
{
|
||||
// Respond to used extensions
|
||||
resp.append("Sec-WebSocket-Extensions: ");
|
||||
boolean delim = false;
|
||||
for (ExtensionConfig ext : extensionStack.getNegotiatedExtensions())
|
||||
{
|
||||
if (delim)
|
||||
{
|
||||
resp.append(", ");
|
||||
}
|
||||
resp.append(ext.getParameterizedName());
|
||||
delim = true;
|
||||
}
|
||||
resp.append("\r\n");
|
||||
}
|
||||
if (extraResponseHeaders.size() > 0)
|
||||
{
|
||||
for (Map.Entry<String, String> xheader : extraResponseHeaders.entrySet())
|
||||
{
|
||||
resp.append(xheader.getKey());
|
||||
resp.append(": ");
|
||||
resp.append(xheader.getValue());
|
||||
resp.append("\r\n");
|
||||
}
|
||||
}
|
||||
resp.append("\r\n");
|
||||
|
||||
// Write Response
|
||||
LOG.debug("Response: {}",resp.toString());
|
||||
write(resp.toString().getBytes());
|
||||
return requestLines;
|
||||
}
|
||||
|
||||
private void write(byte[] bytes) throws IOException
|
||||
{
|
||||
getOutputStream().write(bytes);
|
||||
}
|
||||
|
||||
public void write(byte[] buf, int offset, int length) throws IOException
|
||||
{
|
||||
getOutputStream().write(buf,offset,length);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.jetty.websocket.common.test.IBlockheadServerConnection#write(org.eclipse.jetty.websocket.api.extensions.Frame)
|
||||
*/
|
||||
@Override
|
||||
public void write(Frame frame) throws IOException
|
||||
{
|
||||
LOG.debug("write(Frame->{}) to {}",frame,outgoing);
|
||||
outgoing.outgoingFrame(frame,null,BatchMode.OFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) throws IOException
|
||||
{
|
||||
getOutputStream().write(b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ByteBuffer buf) throws IOException
|
||||
{
|
||||
byte arr[] = BufferUtil.toArray(buf);
|
||||
if ((arr != null) && (arr.length > 0))
|
||||
{
|
||||
getOutputStream().write(arr);
|
||||
}
|
||||
public BlockheadServerConnection(WebSocketPolicy policy,
|
||||
ByteBufferPool bufferPool,
|
||||
ExtensionStack extensionStack,
|
||||
CompletableFuture<BlockheadConnection> openFut,
|
||||
EndPoint endp,
|
||||
Executor executor)
|
||||
{
|
||||
super(policy, bufferPool, extensionStack, openFut, endp, executor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.common.test;
|
|||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
|
@ -27,19 +28,20 @@ import java.nio.ByteBuffer;
|
|||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
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.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.Generator;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.io.IOState;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
|
@ -47,28 +49,13 @@ import org.junit.Assert;
|
|||
*/
|
||||
public class Fuzzer implements AutoCloseable
|
||||
{
|
||||
public static enum CloseState
|
||||
{
|
||||
OPEN,
|
||||
REMOTE_INITIATED,
|
||||
LOCAL_INITIATED
|
||||
}
|
||||
|
||||
public static enum SendMode
|
||||
public enum SendMode
|
||||
{
|
||||
BULK,
|
||||
PER_FRAME,
|
||||
SLOW
|
||||
}
|
||||
|
||||
public static enum DisconnectMode
|
||||
{
|
||||
/** Disconnect occurred after a proper close handshake */
|
||||
CLEAN,
|
||||
/** Disconnect occurred in a harsh manner, without a close handshake */
|
||||
UNCLEAN
|
||||
}
|
||||
|
||||
private static final int KBYTE = 1024;
|
||||
private static final int MBYTE = KBYTE * KBYTE;
|
||||
|
||||
|
@ -78,24 +65,28 @@ public class Fuzzer implements AutoCloseable
|
|||
protected static final byte[] MASK =
|
||||
{ 0x11, 0x22, 0x33, 0x44 };
|
||||
|
||||
private final Fuzzed testcase;
|
||||
private final BlockheadClient client;
|
||||
private final Generator generator;
|
||||
private final String testname;
|
||||
private BlockheadConnection clientConnection;
|
||||
private SendMode sendMode = SendMode.BULK;
|
||||
private int slowSendSegmentSize = 5;
|
||||
|
||||
public Fuzzer(Fuzzed testcase) throws Exception
|
||||
{
|
||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||
|
||||
this.testcase = testcase;
|
||||
this.client = new BlockheadClient();
|
||||
int bigMessageSize = 20 * MBYTE;
|
||||
|
||||
policy.setMaxTextMessageSize(bigMessageSize);
|
||||
policy.setMaxBinaryMessageSize(bigMessageSize);
|
||||
policy.setIdleTimeout(5000);
|
||||
client.getPolicy().setMaxTextMessageSize(bigMessageSize);
|
||||
client.getPolicy().setMaxBinaryMessageSize(bigMessageSize);
|
||||
client.getPolicy().setIdleTimeout(5000);
|
||||
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
|
||||
client.start();
|
||||
|
||||
this.client = new BlockheadClient(policy,testcase.getServerURI());
|
||||
this.client.setTimeout(2,TimeUnit.SECONDS);
|
||||
this.generator = testcase.getLaxGenerator();
|
||||
this.testname = testcase.getTestMethodName();
|
||||
}
|
||||
|
@ -120,50 +111,81 @@ public class Fuzzer implements AutoCloseable
|
|||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception
|
||||
public void close()
|
||||
{
|
||||
this.client.disconnect();
|
||||
this.clientConnection.close();
|
||||
try
|
||||
{
|
||||
this.client.stop();
|
||||
}
|
||||
catch (Exception ignore)
|
||||
{
|
||||
LOG.ignore(ignore);
|
||||
}
|
||||
}
|
||||
|
||||
public void disconnect()
|
||||
{
|
||||
this.client.disconnect();
|
||||
this.clientConnection.abort();
|
||||
}
|
||||
|
||||
public void connect() throws IOException
|
||||
{
|
||||
if (!client.isConnected())
|
||||
BlockheadClientRequest request = this.client.newWsRequest(testcase.getServerURI());
|
||||
request.idleTimeout(2, TimeUnit.SECONDS);
|
||||
request.header("X-TestCase", testname);
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try
|
||||
{
|
||||
client.connect();
|
||||
client.addHeader("X-TestCase: " + testname + "\r\n");
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
this.clientConnection = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
}
|
||||
catch (InterruptedException e)
|
||||
{
|
||||
throw new IOException("Connect interrupted", e);
|
||||
}
|
||||
catch (ExecutionException e)
|
||||
{
|
||||
throw new IOException("Connect execution failed", e);
|
||||
}
|
||||
catch (TimeoutException e)
|
||||
{
|
||||
throw new IOException("Connect timed out", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void expect(List<WebSocketFrame> expect) throws Exception
|
||||
{
|
||||
expect(expect,10,TimeUnit.SECONDS);
|
||||
expect(expect, Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
}
|
||||
|
||||
public void expect(List<WebSocketFrame> expect, int duration, TimeUnit unit) throws Exception
|
||||
/**
|
||||
* Read the response frames and validate them against the expected frame list
|
||||
*
|
||||
* @param expect the list of expected frames
|
||||
* @param duration the timeout duration to wait for each read frame
|
||||
* @param unit the timeout unit to wait for each read frame
|
||||
* @throws Exception if unable to validate expectations
|
||||
*/
|
||||
public void expect(List<WebSocketFrame> expect, long duration, TimeUnit unit) throws Exception
|
||||
{
|
||||
int expectedCount = expect.size();
|
||||
LOG.debug("expect() {} frame(s)",expect.size());
|
||||
|
||||
// Read frames
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(expect.size(),duration,unit);
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConnection.getFrameQueue();
|
||||
|
||||
String prefix = "";
|
||||
for (int i = 0; i < expectedCount; i++)
|
||||
{
|
||||
WebSocketFrame expected = expect.get(i);
|
||||
WebSocketFrame actual = frames.poll();
|
||||
WebSocketFrame actual = frames.poll(duration,unit);
|
||||
|
||||
prefix = "Frame[" + i + "]";
|
||||
|
||||
LOG.debug("{} {}",prefix,actual);
|
||||
|
||||
Assert.assertThat(prefix, actual, is(notNullValue()));
|
||||
Assert.assertThat(prefix + ".opcode",OpCode.name(actual.getOpCode()),is(OpCode.name(expected.getOpCode())));
|
||||
prefix += "/" + actual.getOpCode();
|
||||
if (expected.getOpCode() == OpCode.CLOSE)
|
||||
|
@ -190,24 +212,6 @@ public class Fuzzer implements AutoCloseable
|
|||
// TODO Should test for no more frames. success if connection closed.
|
||||
}
|
||||
|
||||
public CloseState getCloseState()
|
||||
{
|
||||
IOState ios = client.getIOState();
|
||||
|
||||
if (ios.wasLocalCloseInitiated())
|
||||
{
|
||||
return CloseState.LOCAL_INITIATED;
|
||||
}
|
||||
else if (ios.wasRemoteCloseInitiated())
|
||||
{
|
||||
return CloseState.REMOTE_INITIATED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return CloseState.OPEN;
|
||||
}
|
||||
}
|
||||
|
||||
public SendMode getSendMode()
|
||||
{
|
||||
return sendMode;
|
||||
|
@ -220,27 +224,26 @@ public class Fuzzer implements AutoCloseable
|
|||
|
||||
public void send(ByteBuffer buf) throws IOException
|
||||
{
|
||||
Assert.assertThat("Client connected",client.isConnected(),is(true));
|
||||
Assert.assertThat("Client connected",clientConnection.isOpen(),is(true));
|
||||
LOG.debug("Sending bytes {}",BufferUtil.toDetailString(buf));
|
||||
if (sendMode == SendMode.SLOW)
|
||||
{
|
||||
client.writeRawSlowly(buf,slowSendSegmentSize);
|
||||
clientConnection.writeRawSlowly(buf,slowSendSegmentSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
client.writeRaw(buf);
|
||||
clientConnection.writeRaw(buf);
|
||||
}
|
||||
}
|
||||
|
||||
public void send(ByteBuffer buf, int numBytes) throws IOException
|
||||
{
|
||||
client.writeRaw(buf,numBytes);
|
||||
client.flush();
|
||||
clientConnection.writeRaw(buf, numBytes);
|
||||
}
|
||||
|
||||
public void send(List<WebSocketFrame> send) throws IOException
|
||||
{
|
||||
Assert.assertThat("Client connected",client.isConnected(),is(true));
|
||||
Assert.assertThat("Client connected",clientConnection.isOpen(),is(true));
|
||||
LOG.debug("[{}] Sending {} frames (mode {})",testname,send.size(),sendMode);
|
||||
if ((sendMode == SendMode.BULK) || (sendMode == SendMode.SLOW))
|
||||
{
|
||||
|
@ -267,10 +270,10 @@ public class Fuzzer implements AutoCloseable
|
|||
switch (sendMode)
|
||||
{
|
||||
case BULK:
|
||||
client.writeRaw(buf);
|
||||
clientConnection.writeRaw(buf);
|
||||
break;
|
||||
case SLOW:
|
||||
client.writeRawSlowly(buf,slowSendSegmentSize);
|
||||
clientConnection.writeRawSlowly(buf,slowSendSegmentSize);
|
||||
break;
|
||||
default:
|
||||
throw new RuntimeException("Whoops, unsupported sendMode: " + sendMode);
|
||||
|
@ -286,8 +289,7 @@ public class Fuzzer implements AutoCloseable
|
|||
BufferUtil.clearToFill(fullframe);
|
||||
generator.generateWholeFrame(f,fullframe);
|
||||
BufferUtil.flipToFlush(fullframe,0);
|
||||
client.writeRaw(fullframe);
|
||||
client.flush();
|
||||
clientConnection.writeRaw(fullframe);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,9 @@ package org.eclipse.jetty.websocket.common.test;
|
|||
import java.io.IOException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
|
||||
/**
|
||||
|
@ -56,7 +56,7 @@ public interface IBlockheadClient extends AutoCloseable
|
|||
|
||||
public InetSocketAddress getRemoteSocketAddress();
|
||||
|
||||
public EventQueue<WebSocketFrame> readFrames(int expectedFrameCount, int timeoutDuration, TimeUnit timeoutUnit) throws Exception;
|
||||
public LinkedBlockingQueue<WebSocketFrame> getFrameQueue();
|
||||
|
||||
public HttpResponse readResponseHeader() throws IOException;
|
||||
|
||||
|
|
|
@ -1,68 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.common.test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.SocketException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.Parser;
|
||||
|
||||
public interface IBlockheadServerConnection
|
||||
{
|
||||
public void close() throws IOException;
|
||||
|
||||
public void close(int statusCode) throws IOException;
|
||||
|
||||
public void write(Frame frame) throws IOException;
|
||||
|
||||
public List<String> upgrade() throws IOException;
|
||||
|
||||
public void disconnect();
|
||||
|
||||
public IncomingFramesCapture readFrames(int expectedCount, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException;
|
||||
public void write(ByteBuffer buf) throws IOException;
|
||||
public List<String> readRequestLines() throws IOException;
|
||||
public String parseWebSocketKey(List<String> requestLines);
|
||||
public void respond(String rawstr) throws IOException;
|
||||
public String readRequest() throws IOException;
|
||||
public List<String> regexFind(List<String> lines, String pattern);
|
||||
public void echoMessage(int expectedFrames, int timeoutDuration, TimeUnit timeoutUnit) throws IOException, TimeoutException;
|
||||
public void setSoTimeout(int ms) throws SocketException;
|
||||
public ByteBufferPool getBufferPool();
|
||||
public int read(ByteBuffer buf) throws IOException;
|
||||
public Parser getParser();
|
||||
public IncomingFramesCapture getIncomingFrames();
|
||||
public void flush() throws IOException;
|
||||
public void write(int b) throws IOException;
|
||||
public void startEcho();
|
||||
public void stopEcho();
|
||||
|
||||
/**
|
||||
* Add an extra header for the upgrade response (from the server). No extra work is done to ensure the key and value are sane for http.
|
||||
* @param rawkey the raw key
|
||||
* @param rawvalue the raw value
|
||||
*/
|
||||
public void addResponseHeader(String rawkey, String rawvalue);
|
||||
}
|
|
@ -22,8 +22,8 @@ import static org.hamcrest.Matchers.greaterThanOrEqualTo;
|
|||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
@ -37,8 +37,8 @@ import org.junit.Assert;
|
|||
public class IncomingFramesCapture implements IncomingFrames
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(IncomingFramesCapture.class);
|
||||
private EventQueue<WebSocketFrame> frames = new EventQueue<>();
|
||||
private EventQueue<Throwable> errors = new EventQueue<>();
|
||||
private LinkedBlockingQueue<WebSocketFrame> frames = new LinkedBlockingQueue<>();
|
||||
private LinkedBlockingQueue<Throwable> errors = new LinkedBlockingQueue<>();
|
||||
|
||||
public void assertErrorCount(int expectedCount)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.common.test;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.matchers.RegexMatcher;
|
||||
|
||||
public class MoreMatchers
|
||||
{
|
||||
/**
|
||||
* Create a matcher for {@link String} that matches against a regex pattern.
|
||||
*
|
||||
* <p>
|
||||
* Returns success based on {@code java.util.regex.Pattern.matcher(input).matches();}
|
||||
* </p>
|
||||
*
|
||||
* @param pattern the {@link java.util.regex.Pattern} syntax pattern to match against.
|
||||
* @return the Regex Matcher
|
||||
*/
|
||||
public static org.hamcrest.Matcher<java.lang.String> regex(String pattern)
|
||||
{
|
||||
return new RegexMatcher(pattern);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.common.test;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A central place for all of the various test timeouts within the websocket testing.
|
||||
*/
|
||||
public class Timeouts
|
||||
{
|
||||
// establish a connection timeout
|
||||
public static final long CONNECT = 2;
|
||||
public static final TimeUnit CONNECT_UNIT = TimeUnit.SECONDS;
|
||||
|
||||
// poll for an event timeout
|
||||
public static final long POLL_EVENT = 2;
|
||||
public static final TimeUnit POLL_EVENT_UNIT = TimeUnit.SECONDS;
|
||||
|
||||
// send a message timeout
|
||||
public static final long SEND = 2;
|
||||
public static final TimeUnit SEND_UNIT = TimeUnit.SECONDS;
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2018 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.common.test;
|
||||
|
||||
import org.eclipse.jetty.util.Callback;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
|
||||
public class WriteCallbackDelegate implements Callback
|
||||
{
|
||||
private final WriteCallback delegate;
|
||||
|
||||
public WriteCallbackDelegate(WriteCallback delegate)
|
||||
{
|
||||
this.delegate = delegate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void succeeded()
|
||||
{
|
||||
if (this.delegate != null)
|
||||
this.delegate.writeSuccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void failed(Throwable x)
|
||||
{
|
||||
if (this.delegate != null)
|
||||
this.delegate.writeFailed(x);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.LEVEL=WARN
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.common.test.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.protocol.Parser.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.protocol.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.io.payload.LEVEL=DEBUG
|
||||
|
|
|
@ -20,16 +20,16 @@ package org.eclipse.jetty.websocket.server;
|
|||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
|
@ -38,19 +38,19 @@ import org.eclipse.jetty.websocket.common.Parser;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.examples.echo.BigEchoSocket;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class AnnotatedMaxMessageSizeTest
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tracker = new TestTracker();
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static Server server;
|
||||
private static ServerConnector connector;
|
||||
private static URI serverUri;
|
||||
|
@ -89,59 +89,64 @@ public class AnnotatedMaxMessageSizeTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEchoGood() throws IOException, Exception
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(serverUri);
|
||||
try
|
||||
{
|
||||
client.setProtocols("echo");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEchoGood() throws Exception
|
||||
{
|
||||
BlockheadClientRequest request = client.newWsRequest(serverUri);
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "echo");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Generate text frame
|
||||
String msg = "this is an echo ... cho ... ho ... o";
|
||||
client.write(new TextFrame().setPayload(msg));
|
||||
clientConn.write(new TextFrame().setPayload(msg));
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame.status code",tf.getPayloadAsUTF8(),is(msg));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(timeout=8000)
|
||||
public void testEchoTooBig() throws IOException, Exception
|
||||
public void testEchoTooBig() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(serverUri);
|
||||
try(StacklessLogging logging = new StacklessLogging(Parser.class))
|
||||
{
|
||||
client.setProtocols("echo");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(serverUri);
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "echo");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(Parser.class))
|
||||
{
|
||||
// Generate text frame
|
||||
int size = 120 * 1024;
|
||||
byte buf[] = new byte[size]; // buffer bigger than maxMessageSize
|
||||
Arrays.fill(buf,(byte)'x');
|
||||
client.write(new TextFrame().setPayload(ByteBuffer.wrap(buf)));
|
||||
clientConn.write(new TextFrame().setPayload(ByteBuffer.wrap(buf)));
|
||||
|
||||
// Read frame (hopefully close frame saying its too large)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Frame is close", tf.getOpCode(), is(OpCode.CLOSE));
|
||||
CloseInfo close = new CloseInfo(tf);
|
||||
Assert.assertThat("Close Code", close.getStatusCode(), is(StatusCode.MESSAGE_TOO_LARGE));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,13 +21,19 @@ package org.eclipse.jetty.websocket.server;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.HttpResponse;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.examples.MyEchoServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
|
@ -37,6 +43,7 @@ import org.junit.Test;
|
|||
|
||||
public class ChromeTest
|
||||
{
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
|
||||
@BeforeClass
|
||||
|
@ -52,34 +59,49 @@ public class ChromeTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpgradeWithWebkitDeflateExtension() throws Exception
|
||||
{
|
||||
Assume.assumeTrue("Server has x-webkit-deflate-frame registered",
|
||||
server.getWebSocketServletFactory().getExtensionFactory().isAvailable("x-webkit-deflate-frame"));
|
||||
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
try
|
||||
Assume.assumeTrue("Client has x-webkit-deflate-frame registered",
|
||||
client.getExtensionFactory().isAvailable("x-webkit-deflate-frame"));
|
||||
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, "x-webkit-deflate-frame");
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "chat");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.addExtensions("x-webkit-deflate-frame");
|
||||
client.setProtocols("chat");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
HttpResponse response = client.expectUpgradeResponse();
|
||||
Assert.assertThat("Response",response.getExtensionsHeader(),containsString("x-webkit-deflate-frame"));
|
||||
HttpFields responseFields = clientConn.getUpgradeResponseHeaders();
|
||||
HttpField extensionField = responseFields.getField(HttpHeader.SEC_WEBSOCKET_EXTENSIONS);
|
||||
Assert.assertThat("Response", extensionField.getValue(),containsString("x-webkit-deflate-frame"));
|
||||
|
||||
// Generate text frame
|
||||
String msg = "this is an echo ... cho ... ho ... o";
|
||||
client.write(new TextFrame().setPayload(msg));
|
||||
clientConn.write(new TextFrame().setPayload(msg));
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame.status code",tf.getPayloadAsUTF8(),is(msg));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,18 +24,22 @@ import static org.junit.Assert.assertThat;
|
|||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
import org.eclipse.jetty.util.Decorator;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
|
@ -49,6 +53,7 @@ import org.junit.Test;
|
|||
@Ignore("Unstable - see Issue #1815")
|
||||
public class DecoratorsLegacyTest
|
||||
{
|
||||
|
||||
private static class DecoratorsSocket extends WebSocketAdapter
|
||||
{
|
||||
private final DecoratedObjectFactory objFactory;
|
||||
|
@ -68,10 +73,10 @@ public class DecoratorsLegacyTest
|
|||
{
|
||||
out.printf("Object is a DecoratedObjectFactory%n");
|
||||
List<Decorator> decorators = objFactory.getDecorators();
|
||||
out.printf("Decorators.size = [%d]%n",decorators.size());
|
||||
out.printf("Decorators.size = [%d]%n", decorators.size());
|
||||
for (Decorator decorator : decorators)
|
||||
{
|
||||
out.printf(" decorator[] = %s%n",decorator.getClass().getName());
|
||||
out.printf(" decorator[] = %s%n", decorator.getClass().getName());
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -89,7 +94,7 @@ public class DecoratorsLegacyTest
|
|||
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
|
||||
{
|
||||
ServletContext servletContext = req.getHttpServletRequest().getServletContext();
|
||||
DecoratedObjectFactory objFactory = (DecoratedObjectFactory)servletContext.getAttribute(DecoratedObjectFactory.ATTR);
|
||||
DecoratedObjectFactory objFactory = (DecoratedObjectFactory) servletContext.getAttribute(DecoratedObjectFactory.ATTR);
|
||||
return new DecoratorsSocket(objFactory);
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +131,7 @@ public class DecoratorsLegacyTest
|
|||
}
|
||||
}
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
private static DecoratorsCreator decoratorsCreator;
|
||||
|
||||
|
@ -153,31 +159,39 @@ public class DecoratorsLegacyTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessRequestCookies() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
try
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
clientConn.write(new TextFrame().setPayload("info"));
|
||||
|
||||
client.write(new TextFrame().setPayload("info"));
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
|
||||
WebSocketFrame resp = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame resp = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
String textMsg = resp.getPayloadAsUTF8();
|
||||
|
||||
assertThat("DecoratedObjectFactory", textMsg, containsString("Object is a DecoratedObjectFactory"));
|
||||
assertThat("decorators.size", textMsg, containsString("Decorators.size = [1]"));
|
||||
assertThat("decorator type", textMsg, containsString("decorator[] = " + DummyLegacyDecorator.class.getName()));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,18 +24,22 @@ import static org.junit.Assert.assertThat;
|
|||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.DecoratedObjectFactory;
|
||||
import org.eclipse.jetty.util.Decorator;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
|
@ -43,10 +47,8 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
@Ignore
|
||||
public class DecoratorsTest
|
||||
{
|
||||
private static class DecoratorsSocket extends WebSocketAdapter
|
||||
|
@ -125,6 +127,7 @@ public class DecoratorsTest
|
|||
}
|
||||
}
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
private static DecoratorsCreator decoratorsCreator;
|
||||
|
||||
|
@ -151,31 +154,38 @@ public class DecoratorsTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessRequestCookies() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
|
||||
try
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
clientConn.write(new TextFrame().setPayload("info"));
|
||||
|
||||
client.write(new TextFrame().setPayload("info"));
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
|
||||
WebSocketFrame resp = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame resp = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
String textMsg = resp.getPayloadAsUTF8();
|
||||
|
||||
assertThat("DecoratedObjectFactory", textMsg, containsString("Object is a DecoratedObjectFactory"));
|
||||
assertThat("decorators.size", textMsg, containsString("Decorators.size = [1]"));
|
||||
assertThat("decorator type", textMsg, containsString("decorator[] = " + DummyUtilDecorator.class.getName()));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,15 +18,18 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.examples.MyEchoServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
|
@ -35,39 +38,45 @@ import org.junit.Test;
|
|||
|
||||
public class FirefoxTest
|
||||
{
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
public static void startContainers() throws Exception
|
||||
{
|
||||
server = new SimpleServletServer(new MyEchoServlet());
|
||||
server.start();
|
||||
|
||||
client = new BlockheadClient();
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer()
|
||||
public static void stopContainers() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testConnectionKeepAlive() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
// Odd Connection Header value seen in Firefox
|
||||
client.setConnectionValue("keep-alive, Upgrade");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
|
||||
// Odd Connection Header value seen in older Firefox versions
|
||||
request.header(HttpHeader.CONNECTION, "keep-alive, Upgrade");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try(BlockheadConnection conn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Generate text frame
|
||||
String msg = "this is an echo ... cho ... ho ... o";
|
||||
client.write(new TextFrame().setPayload(msg));
|
||||
conn.write(new TextFrame().setPayload(msg));
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 30, TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = conn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame.status code", tf.getPayloadAsUTF8(), is(msg));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,22 +21,30 @@ package org.eclipse.jetty.websocket.server;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.HttpResponse;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.helper.EchoServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Assume;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
public class FragmentExtensionTest
|
||||
{
|
||||
private static SimpleServletServer server;
|
||||
private static BlockheadClient client;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
|
@ -51,6 +59,20 @@ public class FragmentExtensionTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
private String[] split(String str, int partSize)
|
||||
{
|
||||
int strLength = str.length();
|
||||
|
@ -68,37 +90,39 @@ public class FragmentExtensionTest
|
|||
@Test
|
||||
public void testFragmentExtension() throws Exception
|
||||
{
|
||||
Assume.assumeTrue("Server has fragment registered",
|
||||
server.getWebSocketServletFactory().getExtensionFactory().isAvailable("fragment"));
|
||||
|
||||
Assume.assumeTrue("Client has fragment registered",
|
||||
client.getExtensionFactory().isAvailable("fragment"));
|
||||
|
||||
int fragSize = 4;
|
||||
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.clearExtensions();
|
||||
client.addExtensions("fragment;maxLength=" + fragSize);
|
||||
client.setProtocols("onConnect");
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, "fragment;maxLength=" + fragSize);
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "onConnect");
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
try
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Make sure the read times out if there are problems with the implementation
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
HttpResponse resp = client.expectUpgradeResponse();
|
||||
HttpFields responseHeaders = clientConn.getUpgradeResponseHeaders();
|
||||
HttpField extensionHeader = responseHeaders.getField(HttpHeader.SEC_WEBSOCKET_EXTENSIONS);
|
||||
|
||||
Assert.assertThat("Response",resp.getExtensionsHeader(),containsString("fragment"));
|
||||
Assert.assertThat("Response",extensionHeader.getValue(),containsString("fragment"));
|
||||
|
||||
String msg = "Sent as a long message that should be split";
|
||||
client.write(new TextFrame().setPayload(msg));
|
||||
clientConn.write(new TextFrame().setPayload(msg));
|
||||
|
||||
String parts[] = split(msg,fragSize);
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(parts.length,1000,TimeUnit.MILLISECONDS);
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
for (int i = 0; i < parts.length; i++)
|
||||
{
|
||||
WebSocketFrame frame = frames.poll();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("text[" + i + "].payload",frame.getPayloadAsUTF8(),is(parts[i]));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,13 +21,19 @@ package org.eclipse.jetty.websocket.server;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpField;
|
||||
import org.eclipse.jetty.http.HttpFields;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.HttpResponse;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.helper.EchoServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
|
@ -37,6 +43,7 @@ import org.junit.Test;
|
|||
public class IdentityExtensionTest
|
||||
{
|
||||
private static SimpleServletServer server;
|
||||
private static BlockheadClient client;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
|
@ -51,34 +58,43 @@ public class IdentityExtensionTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIdentityExtension() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.clearExtensions();
|
||||
client.addExtensions("identity;param=0");
|
||||
client.addExtensions("identity;param=1, identity ; param = '2' ; other = ' some = value '");
|
||||
client.setProtocols("onConnect");
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, "identity;param=0");
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_EXTENSIONS, "identity;param=1, identity ; param = '2' ; other = ' some = value '");
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "onConnect");
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
try
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Make sure the read times out if there are problems with the implementation
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
HttpResponse resp = client.expectUpgradeResponse();
|
||||
HttpFields responseHeaders = clientConn.getUpgradeResponseHeaders();
|
||||
HttpField extensionHeader = responseHeaders.getField(HttpHeader.SEC_WEBSOCKET_EXTENSIONS);
|
||||
|
||||
Assert.assertThat("Response",resp.getExtensionsHeader(),containsString("identity"));
|
||||
Assert.assertThat("Response", extensionHeader.getValue(), containsString("identity"));
|
||||
|
||||
client.write(new TextFrame().setPayload("Hello"));
|
||||
clientConn.write(new TextFrame().setPayload("Hello"));
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,1000,TimeUnit.MILLISECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("TEXT.payload",frame.getPayloadAsUTF8(),is("Hello"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,20 @@ package org.eclipse.jetty.websocket.server;
|
|||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.helper.RFCSocket;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
|
@ -40,17 +45,23 @@ import org.junit.Test;
|
|||
|
||||
public class IdleTimeoutTest
|
||||
{
|
||||
|
||||
public static final int IDLE_TIMEOUT_MS_WEBSOCKET_SERVER = 500;
|
||||
public static final int IDLE_TIMEOUT_ON_SERVER = 1000;
|
||||
public static final int IDLE_TIMEOUT_MS_WEBSOCKET_CLIENT = 2500;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public static class TimeoutServlet extends WebSocketServlet
|
||||
{
|
||||
@Override
|
||||
public void configure(WebSocketServletFactory factory)
|
||||
{
|
||||
factory.getPolicy().setIdleTimeout(500);
|
||||
factory.getPolicy().setIdleTimeout(IDLE_TIMEOUT_MS_WEBSOCKET_SERVER);
|
||||
factory.register(RFCSocket.class);
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
|
||||
@BeforeClass
|
||||
|
@ -66,6 +77,20 @@ public class IdleTimeoutTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test IdleTimeout on server.
|
||||
* @throws Exception on test failure
|
||||
|
@ -73,37 +98,32 @@ public class IdleTimeoutTest
|
|||
@Test
|
||||
public void testIdleTimeout() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.setProtocols("onConnect");
|
||||
client.setTimeout(2500,TimeUnit.MILLISECONDS);
|
||||
try
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "onConnect");
|
||||
request.idleTimeout(IDLE_TIMEOUT_MS_WEBSOCKET_CLIENT, TimeUnit.MILLISECONDS);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// This wait should be shorter than client timeout above, but
|
||||
// longer than server timeout configured in TimeoutServlet
|
||||
client.sleep(TimeUnit.MILLISECONDS,1000);
|
||||
TimeUnit.MILLISECONDS.sleep(IDLE_TIMEOUT_ON_SERVER);
|
||||
|
||||
// Write to server
|
||||
// This action is possible, but does nothing.
|
||||
// Server could be in a half-closed state at this point.
|
||||
// Where the server read is closed (due to timeout), but the server write is still open.
|
||||
// The server could not read this frame, if it is in this half closed state
|
||||
client.write(new TextFrame().setPayload("Hello"));
|
||||
clientConn.write(new TextFrame().setPayload("Hello"));
|
||||
|
||||
// Expect server to have closed due to its own timeout
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("frame opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
Assert.assertThat("close code",close.getStatusCode(),is(StatusCode.SHUTDOWN));
|
||||
Assert.assertThat("close reason",close.getReason(),containsString("Timeout"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,21 +18,23 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
|
@ -42,7 +44,9 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.helper.RFCSocket;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
|
@ -51,13 +55,11 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests various close scenarios that should result in Open Session cleanup
|
||||
*/
|
||||
@Ignore
|
||||
public class ManyConnectionsCleanupTest
|
||||
{
|
||||
static class AbstractCloseSocket extends WebSocketAdapter
|
||||
|
@ -219,6 +221,7 @@ public class ManyConnectionsCleanupTest
|
|||
|
||||
private static final Logger LOG = Log.getLogger(ManyConnectionsCleanupTest.class);
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
private static AbstractCloseSocket closeSocket;
|
||||
|
||||
|
@ -235,6 +238,20 @@ public class ManyConnectionsCleanupTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test session open session cleanup (bug #474936)
|
||||
*
|
||||
|
@ -244,53 +261,49 @@ public class ManyConnectionsCleanupTest
|
|||
@Test
|
||||
public void testOpenSessionCleanup() throws Exception
|
||||
{
|
||||
int iterationCount = 100;
|
||||
|
||||
StdErrLog.getLogger(FastFailSocket.class).setLevel(StdErrLog.LEVEL_OFF);
|
||||
|
||||
StdErrLog sessLog = StdErrLog.getLogger(WebSocketSession.class);
|
||||
int oldLevel = sessLog.getLevel();
|
||||
sessLog.setLevel(StdErrLog.LEVEL_OFF);
|
||||
int iterationCount = 20;
|
||||
|
||||
// TODO: consider a SilentLogging alternative class
|
||||
try(StacklessLogging ignore = new StacklessLogging(FastFailSocket.class, WebSocketSession.class))
|
||||
{
|
||||
for (int requests = 0; requests < iterationCount; requests++)
|
||||
{
|
||||
fastFail();
|
||||
fastClose();
|
||||
dropConnection();
|
||||
}
|
||||
}
|
||||
|
||||
sessLog.setLevel(oldLevel);
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "container");
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.setProtocols("container");
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
clientConn.write(new TextFrame().setPayload("calls"));
|
||||
clientConn.write(new TextFrame().setPayload("openSessions"));
|
||||
|
||||
client.write(new TextFrame().setPayload("calls"));
|
||||
client.write(new TextFrame().setPayload("openSessions"));
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(3,6,TimeUnit.SECONDS);
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame;
|
||||
String resp;
|
||||
|
||||
frame = frames.poll();
|
||||
frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("frames[0].opcode",frame.getOpCode(),is(OpCode.TEXT));
|
||||
resp = frame.getPayloadAsUTF8();
|
||||
assertThat("Should only have 1 open session",resp,containsString("calls=" + ((iterationCount * 2) + 1)));
|
||||
|
||||
frame = frames.poll();
|
||||
frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("frames[1].opcode",frame.getOpCode(),is(OpCode.TEXT));
|
||||
resp = frame.getPayloadAsUTF8();
|
||||
assertThat("Should only have 1 open session",resp,containsString("openSessions.size=1\n"));
|
||||
|
||||
frame = frames.poll();
|
||||
frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("frames[2].opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.NORMAL));
|
||||
client.write(close.asFrame()); // respond with close
|
||||
clientConn.write(close.asFrame()); // respond with close
|
||||
|
||||
// ensure server socket got close event
|
||||
assertThat("Open Sessions Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
|
||||
|
@ -301,47 +314,43 @@ public class ManyConnectionsCleanupTest
|
|||
|
||||
private void fastClose() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
client.setProtocols("fastclose");
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "fastclose");
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
client.readFrames(1,1,TimeUnit.SECONDS);
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
|
||||
CloseInfo close = new CloseInfo(StatusCode.NORMAL,"Normal");
|
||||
assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.NORMAL));
|
||||
|
||||
// Notify server of close handshake
|
||||
client.write(close.asFrame()); // respond with close
|
||||
clientConn.write(close.asFrame()); // respond with close
|
||||
|
||||
// ensure server socket got close event
|
||||
assertThat("Fast Close Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
|
||||
assertThat("Fast Close.statusCode",closeSocket.closeStatusCode,is(StatusCode.NORMAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fastFail() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
client.setProtocols("fastfail");
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "fastfail");
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
// client.readFrames(1,2,TimeUnit.SECONDS);
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
CloseInfo close = new CloseInfo(StatusCode.NORMAL,"Normal");
|
||||
client.write(close.asFrame()); // respond with close
|
||||
clientConn.write(close.asFrame()); // respond with close
|
||||
|
||||
// ensure server socket got close event
|
||||
assertThat("Fast Fail Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
|
||||
|
@ -349,21 +358,19 @@ public class ManyConnectionsCleanupTest
|
|||
assertThat("Fast Fail.errors",closeSocket.errors.size(),is(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void dropConnection() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "container");
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
client.setProtocols("container");
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
client.disconnect();
|
||||
}
|
||||
clientConn.abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
|||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.common.util.Sha1Sum;
|
||||
import org.eclipse.jetty.websocket.server.helper.CaptureSocket;
|
||||
import org.eclipse.jetty.websocket.server.helper.EchoServlet;
|
||||
|
@ -166,8 +167,7 @@ public class PerMessageDeflateExtensionTest
|
|||
// Client sends first message
|
||||
session.getRemote().sendBytes(ByteBuffer.wrap(msg));
|
||||
|
||||
clientSocket.messages.awaitEventCount(1,5,TimeUnit.SECONDS);
|
||||
String echoMsg = clientSocket.messages.poll();
|
||||
String echoMsg = clientSocket.messages.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Echo'd Message",echoMsg,is("binary[sha1="+sha1+"]"));
|
||||
}
|
||||
finally
|
||||
|
|
|
@ -26,11 +26,16 @@ import static org.junit.Assert.assertThat;
|
|||
import java.net.HttpCookie;
|
||||
import java.net.URI;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.helper.EchoSocket;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
|
@ -43,6 +48,7 @@ import org.junit.Test;
|
|||
|
||||
public class RequestHeadersTest
|
||||
{
|
||||
|
||||
private static class EchoCreator implements WebSocketCreator
|
||||
{
|
||||
private UpgradeRequest lastRequest;
|
||||
|
@ -86,6 +92,7 @@ public class RequestHeadersTest
|
|||
}
|
||||
}
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
private static EchoCreator echoCreator;
|
||||
|
||||
|
@ -103,19 +110,31 @@ public class RequestHeadersTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessRequestCookies() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
request.header(HttpHeader.COOKIE, "fruit=Pear; type=Anjou");
|
||||
|
||||
try
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection ignore = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.addHeader("Cookie: fruit=Pear; type=Anjou\r\n");
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
|
||||
UpgradeRequest req = echoCreator.getLastRequest();
|
||||
assertThat("Last Request",req,notNullValue());
|
||||
List<HttpCookie> cookies = req.getCookies();
|
||||
|
@ -127,25 +146,19 @@ public class RequestHeadersTest
|
|||
assertThat("Cookie value",cookie.getValue(),anyOf(is("Pear"),is("Anjou")));
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestURI() throws Exception
|
||||
{
|
||||
URI destUri = server.getServerUri().resolve("/?abc=x%20z&breakfast=bacon%26eggs&2*2%3d5=false");
|
||||
BlockheadClient client = new BlockheadClient(destUri);
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
BlockheadClientRequest request = client.newWsRequest(destUri);
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
try
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection ignore = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
|
||||
UpgradeRequest req = echoCreator.getLastRequest();
|
||||
assertThat("Last Request",req,notNullValue());
|
||||
assertThat("Request.host", req.getHost(), is(server.getServerUri().getHost()));
|
||||
|
@ -154,9 +167,5 @@ public class RequestHeadersTest
|
|||
assertThat("Request.uri.rawQuery", req.getRequestURI().getRawQuery(), is("abc=x%20z&breakfast=bacon%26eggs&2*2%3d5=false"));
|
||||
assertThat("Request.uri.query", req.getRequestURI().getQuery(), is("abc=x z&breakfast=bacon&eggs&2*2=5=false"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,9 +21,11 @@ package org.eclipse.jetty.websocket.server;
|
|||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
|
@ -31,6 +33,9 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
|
@ -90,6 +95,7 @@ public class SubProtocolTest
|
|||
}
|
||||
}
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
|
||||
@BeforeClass
|
||||
|
@ -105,6 +111,20 @@ public class SubProtocolTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSingleProtocol() throws Exception
|
||||
{
|
||||
|
@ -119,18 +139,17 @@ public class SubProtocolTest
|
|||
|
||||
private void testSubProtocol(String requestProtocols, String acceptedSubProtocols) throws Exception
|
||||
{
|
||||
try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, requestProtocols);
|
||||
request.idleTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.setTimeout(1, TimeUnit.SECONDS);
|
||||
|
||||
client.connect();
|
||||
client.addHeader("Sec-WebSocket-Protocol: "+ requestProtocols + "\r\n");
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
|
||||
client.write(new TextFrame().setPayload("showme"));
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 30, TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
clientConn.write(new TextFrame().setPayload("showme"));
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
|
||||
assertThat(ProtocolEchoSocket.class.getSimpleName() + ".onMessage()", tf.getPayloadAsUTF8(), is("acceptedSubprotocol=" + acceptedSubProtocols));
|
||||
}
|
||||
|
|
|
@ -21,9 +21,10 @@ package org.eclipse.jetty.websocket.server;
|
|||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.SuspendToken;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
|
@ -33,6 +34,9 @@ import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
|
@ -100,6 +104,7 @@ public class SuspendResumeTest
|
|||
}
|
||||
|
||||
private static SimpleServletServer server;
|
||||
private static BlockheadClient client;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
|
@ -108,6 +113,20 @@ public class SuspendResumeTest
|
|||
server.start();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopServer()
|
||||
{
|
||||
|
@ -117,21 +136,19 @@ public class SuspendResumeTest
|
|||
@Test
|
||||
public void testSuspendResume() throws Exception
|
||||
{
|
||||
try (BlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.setTimeout(1, TimeUnit.SECONDS);
|
||||
clientConn.write(new TextFrame().setPayload("echo1"));
|
||||
clientConn.write(new TextFrame().setPayload("echo2"));
|
||||
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
|
||||
client.write(new TextFrame().setPayload("echo1"));
|
||||
client.write(new TextFrame().setPayload("echo2"));
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(2, 30, TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat(EchoSocket.class.getSimpleName() + ".onMessage()", tf.getPayloadAsUTF8(), is("echo1"));
|
||||
tf = frames.poll();
|
||||
tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat(EchoSocket.class.getSimpleName() + ".onMessage()", tf.getPayloadAsUTF8(), is("echo2"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,22 +23,24 @@ import static org.hamcrest.Matchers.is;
|
|||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.LeakTrackingByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.Generator;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.examples.MyEchoServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -50,6 +52,7 @@ import org.junit.Test;
|
|||
public class TooFastClientTest
|
||||
{
|
||||
private static SimpleServletServer server;
|
||||
private static BlockheadClient client;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
|
@ -64,59 +67,62 @@ public class TooFastClientTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore("RELEASE")
|
||||
public void testUpgradeWithSmallFrames() throws Exception
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
try
|
||||
{
|
||||
client.connect();
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
private ByteBuffer createInitialPacket(String... msgs)
|
||||
{
|
||||
int len = Arrays.stream(msgs).mapToInt((str)->str.length() + Generator.MAX_HEADER_LENGTH).sum();
|
||||
ByteBuffer initialPacket = ByteBuffer.allocate(len);
|
||||
|
||||
// Create ByteBuffer representing the initial opening network packet from the client
|
||||
ByteBuffer initialPacket = ByteBuffer.allocate(4096);
|
||||
BufferUtil.clearToFill(initialPacket);
|
||||
|
||||
// Add upgrade request to packet
|
||||
StringBuilder upgradeRequest = client.generateUpgradeRequest();
|
||||
ByteBuffer upgradeBuffer = BufferUtil.toBuffer(upgradeRequest.toString(),StandardCharsets.UTF_8);
|
||||
initialPacket.put(upgradeBuffer);
|
||||
|
||||
// Add text frames
|
||||
Generator generator = new Generator(WebSocketPolicy.newClientPolicy(),
|
||||
new MappedByteBufferPool());
|
||||
|
||||
for (String msg : msgs)
|
||||
{
|
||||
TextFrame frame = new TextFrame().setPayload(msg);
|
||||
byte mask[] = new byte[]{0x11, 0x22, 0x33, 0x44};
|
||||
frame.setMask(mask);
|
||||
generator.generateWholeFrame(frame, initialPacket);
|
||||
}
|
||||
|
||||
BufferUtil.flipToFlush(initialPacket, 0);
|
||||
return initialPacket;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpgradeWithSmallFrames() throws Exception
|
||||
{
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
|
||||
String msg1 = "Echo 1";
|
||||
String msg2 = "This is also an echooooo!";
|
||||
|
||||
TextFrame frame1 = new TextFrame().setPayload(msg1);
|
||||
TextFrame frame2 = new TextFrame().setPayload(msg2);
|
||||
ByteBuffer initialPacket = createInitialPacket(msg1, msg2);
|
||||
request.setInitialBytes(initialPacket);
|
||||
|
||||
// Need to set frame mask (as these are client frames)
|
||||
byte mask[] = new byte[] { 0x11, 0x22, 0x33, 0x44 };
|
||||
frame1.setMask(mask);
|
||||
frame2.setMask(mask);
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
generator.generateWholeFrame(frame1,initialPacket);
|
||||
generator.generateWholeFrame(frame2,initialPacket);
|
||||
|
||||
// Write packet to network
|
||||
BufferUtil.flipToFlush(initialPacket,0);
|
||||
client.writeRaw(initialPacket);
|
||||
|
||||
// Expect upgrade
|
||||
client.expectUpgradeResponse();
|
||||
|
||||
// Read frames (hopefully text frames)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(2,1,TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
Assert.assertThat("Text Frame/msg1",tf.getPayloadAsUTF8(),is(msg1));
|
||||
tf = frames.poll();
|
||||
Assert.assertThat("Text Frame/msg2",tf.getPayloadAsUTF8(),is(msg2));
|
||||
}
|
||||
finally
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.close();
|
||||
// Read frames (hopefully text frames)
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame/msg1",tf.getPayloadAsUTF8(),is(msg1));
|
||||
tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame/msg2",tf.getPayloadAsUTF8(),is(msg2));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -128,55 +134,26 @@ public class TooFastClientTest
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Ignore("RELEASE")
|
||||
public void testUpgradeWithLargeFrame() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
try
|
||||
{
|
||||
client.connect();
|
||||
|
||||
// Create ByteBuffer representing the initial opening network packet from the client
|
||||
ByteBuffer initialPacket = ByteBuffer.allocate(100 * 1024);
|
||||
BufferUtil.clearToFill(initialPacket);
|
||||
|
||||
// Add upgrade request to packet
|
||||
StringBuilder upgradeRequest = client.generateUpgradeRequest();
|
||||
ByteBuffer upgradeBuffer = BufferUtil.toBuffer(upgradeRequest.toString(),StandardCharsets.UTF_8);
|
||||
initialPacket.put(upgradeBuffer);
|
||||
|
||||
// Add text frames
|
||||
Generator generator = new Generator(WebSocketPolicy.newClientPolicy(),
|
||||
new LeakTrackingByteBufferPool(new MappedByteBufferPool.Tagged()));
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
|
||||
byte bigMsgBytes[] = new byte[64*1024];
|
||||
Arrays.fill(bigMsgBytes,(byte)'x');
|
||||
String bigMsg = new String(bigMsgBytes, StandardCharsets.UTF_8);
|
||||
|
||||
// Need to set frame mask (as these are client frames)
|
||||
byte mask[] = new byte[] { 0x11, 0x22, 0x33, 0x44 };
|
||||
TextFrame frame = new TextFrame().setPayload(bigMsg);
|
||||
frame.setMask(mask);
|
||||
generator.generateWholeFrame(frame,initialPacket);
|
||||
ByteBuffer initialPacket = createInitialPacket(bigMsg);
|
||||
request.setInitialBytes(initialPacket);
|
||||
|
||||
// Write packet to network
|
||||
BufferUtil.flipToFlush(initialPacket,0);
|
||||
client.writeRaw(initialPacket);
|
||||
|
||||
// Expect upgrade
|
||||
client.expectUpgradeResponse();
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Read frames (hopefully text frames)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,1,TimeUnit.SECONDS);
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
|
||||
WebSocketFrame tf = frames.poll();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame/msg1",tf.getPayloadAsUTF8(),is(bigMsg));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -26,9 +26,11 @@ import java.util.ArrayList;
|
|||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
|
@ -41,7 +43,9 @@ import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
|||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.helper.RFCSocket;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
|
@ -50,13 +54,11 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServlet;
|
|||
import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests various close scenarios
|
||||
*/
|
||||
@Ignore
|
||||
public class WebSocketCloseTest
|
||||
{
|
||||
static class AbstractCloseSocket extends WebSocketAdapter
|
||||
|
@ -197,6 +199,7 @@ public class WebSocketCloseTest
|
|||
|
||||
private static final Logger LOG = Log.getLogger(WebSocketCloseTest.class);
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
private static AbstractCloseSocket closeSocket;
|
||||
|
||||
|
@ -213,6 +216,20 @@ public class WebSocketCloseTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test fast close (bug #403817)
|
||||
*
|
||||
|
@ -222,23 +239,23 @@ public class WebSocketCloseTest
|
|||
@Test
|
||||
public void testFastClose() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
client.setProtocols("fastclose");
|
||||
client.setTimeout(5,TimeUnit.SECONDS);
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "fastclose");
|
||||
request.idleTimeout(5,TimeUnit.SECONDS);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Verify that client got close frame
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,5,TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("frames[0].opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.NORMAL));
|
||||
|
||||
// Notify server of close handshake
|
||||
client.write(close.asFrame()); // respond with close
|
||||
clientConn.write(close.asFrame()); // respond with close
|
||||
|
||||
// ensure server socket got close event
|
||||
assertThat("Fast Close Latch",closeSocket.closeLatch.await(5,TimeUnit.SECONDS),is(true));
|
||||
|
@ -255,23 +272,22 @@ public class WebSocketCloseTest
|
|||
@Test
|
||||
public void testFastFail() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
client.setProtocols("fastfail");
|
||||
client.setTimeout(5,TimeUnit.SECONDS);
|
||||
try (StacklessLogging scope = new StacklessLogging(FastFailSocket.class, WebSocketSession.class))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "fastfail");
|
||||
request.idleTimeout(5,TimeUnit.SECONDS);
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,5,TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(FastFailSocket.class, WebSocketSession.class))
|
||||
{
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("frames[0].opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.SERVER_ERROR));
|
||||
|
||||
client.write(close.asFrame()); // respond with close
|
||||
clientConn.write(close.asFrame()); // respond with close
|
||||
|
||||
// ensure server socket got close event
|
||||
assertThat("Fast Fail Latch",closeSocket.closeLatch.await(5,TimeUnit.SECONDS),is(true));
|
||||
|
@ -279,7 +295,6 @@ public class WebSocketCloseTest
|
|||
assertThat("Fast Fail.errors",closeSocket.errors.size(),is(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test session open session cleanup (bug #474936)
|
||||
|
@ -294,30 +309,30 @@ public class WebSocketCloseTest
|
|||
fastClose();
|
||||
dropConnection();
|
||||
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
client.setProtocols("container");
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "container");
|
||||
request.idleTimeout(1,TimeUnit.SECONDS);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
TextFrame text = new TextFrame();
|
||||
text.setPayload("openSessions");
|
||||
client.write(text);
|
||||
clientConn.write(text);
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(2,1,TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("frames[0].opcode",frame.getOpCode(),is(OpCode.TEXT));
|
||||
|
||||
String resp = frame.getPayloadAsUTF8();
|
||||
assertThat("Should only have 1 open session",resp,containsString("openSessions.size=1\n"));
|
||||
|
||||
frame = frames.poll();
|
||||
frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
assertThat("frames[1].opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.NORMAL));
|
||||
client.write(close.asFrame()); // respond with close
|
||||
clientConn.write(close.asFrame()); // respond with close
|
||||
|
||||
// ensure server socket got close event
|
||||
assertThat("Open Sessions Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
|
||||
|
@ -329,47 +344,46 @@ public class WebSocketCloseTest
|
|||
@SuppressWarnings("Duplicates")
|
||||
private void fastClose() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
client.setProtocols("fastclose");
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "fastclose");
|
||||
request.idleTimeout(1,TimeUnit.SECONDS);
|
||||
|
||||
client.readFrames(1,1,TimeUnit.SECONDS);
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame received = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
|
||||
CloseInfo close = new CloseInfo(StatusCode.NORMAL,"Normal");
|
||||
assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.NORMAL));
|
||||
|
||||
// Notify server of close handshake
|
||||
client.write(close.asFrame()); // respond with close
|
||||
clientConn.write(close.asFrame()); // respond with close
|
||||
|
||||
// ensure server socket got close event
|
||||
assertThat("Fast Close Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
|
||||
assertThat("Fast Close.statusCode",closeSocket.closeStatusCode,is(StatusCode.NORMAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fastFail() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
client.setProtocols("fastfail");
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "fastfail");
|
||||
request.idleTimeout(1,TimeUnit.SECONDS);
|
||||
|
||||
client.readFrames(1,1,TimeUnit.SECONDS);
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame received = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
|
||||
CloseInfo close = new CloseInfo(StatusCode.NORMAL,"Normal");
|
||||
client.write(close.asFrame()); // respond with close
|
||||
clientConn.write(close.asFrame()); // respond with close
|
||||
|
||||
// ensure server socket got close event
|
||||
assertThat("Fast Fail Latch",closeSocket.closeLatch.await(1,TimeUnit.SECONDS),is(true));
|
||||
|
@ -377,22 +391,20 @@ public class WebSocketCloseTest
|
|||
assertThat("Fast Fail.errors",closeSocket.errors.size(),is(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
private void dropConnection() throws Exception
|
||||
{
|
||||
try (IBlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "container");
|
||||
request.idleTimeout(1,TimeUnit.SECONDS);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
client.setProtocols("container");
|
||||
client.setTimeout(1,TimeUnit.SECONDS);
|
||||
try (StacklessLogging scope = new StacklessLogging(WebSocketSession.class))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
client.disconnect();
|
||||
}
|
||||
clientConn.abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,18 +19,31 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeException;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.HttpResponse;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.examples.MyEchoServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
|
||||
public class WebSocketInvalidVersionTest
|
||||
{
|
||||
@Rule
|
||||
public ExpectedException expectedException = ExpectedException.none();
|
||||
|
||||
private static BlockheadClient client;
|
||||
private static SimpleServletServer server;
|
||||
|
||||
@BeforeClass
|
||||
|
@ -46,28 +59,40 @@ public class WebSocketInvalidVersionTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the requirement of responding with an http 400 when using a Sec-WebSocket-Version that is unsupported.
|
||||
*
|
||||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
public void testRequestVersion29() throws Exception
|
||||
{
|
||||
@SuppressWarnings("resource")
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
client.setVersion(29); // intentionally bad version
|
||||
try
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
// intentionally bad version
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_VERSION, "29");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
expectedException.expect(ExecutionException.class);
|
||||
expectedException.expectCause(instanceOf(UpgradeException.class));
|
||||
expectedException.expectMessage(containsString("400 Unsupported websocket version specification"));
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
HttpResponse response = client.readResponseHeader();
|
||||
Assert.assertThat("Response Status Code",response.getStatusCode(),is(400));
|
||||
Assert.assertThat("Response Status Reason",response.getStatusReason(),containsString("Unsupported websocket version specification"));
|
||||
Assert.assertThat("Response Versions",response.getHeader("Sec-WebSocket-Version"),is("13"));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,31 +22,27 @@ import static org.hamcrest.Matchers.is;
|
|||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.io.MappedByteBufferPool;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.TestTracker;
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.helper.CaptureSocket;
|
||||
import org.eclipse.jetty.websocket.server.helper.SessionServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class WebSocketOverSSLTest
|
||||
{
|
||||
public static final int CONNECT_TIMEOUT = 15000;
|
||||
public static final int FUTURE_TIMEOUT_SEC = 30;
|
||||
@Rule
|
||||
public TestTracker tracker = new TestTracker();
|
||||
|
||||
public ByteBufferPool bufferPool = new MappedByteBufferPool();
|
||||
|
||||
private static SimpleServletServer server;
|
||||
|
@ -94,9 +90,8 @@ public class WebSocketOverSSLTest
|
|||
remote.flush();
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
clientSocket.messages.awaitEventCount(1,30,TimeUnit.SECONDS);
|
||||
EventQueue<String> captured = clientSocket.messages;
|
||||
Assert.assertThat("Text Message",captured.poll(),is(msg));
|
||||
LinkedBlockingQueue<String> captured = clientSocket.messages;
|
||||
Assert.assertThat("Text Message",captured.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT),is(msg));
|
||||
|
||||
// Shutdown the socket
|
||||
clientSocket.close();
|
||||
|
@ -136,9 +131,8 @@ public class WebSocketOverSSLTest
|
|||
remote.flush();
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
clientSocket.messages.awaitEventCount(1,30,TimeUnit.SECONDS);
|
||||
EventQueue<String> captured = clientSocket.messages;
|
||||
Assert.assertThat("Server.session.isSecure",captured.poll(),is("session.isSecure=true"));
|
||||
LinkedBlockingQueue<String> captured = clientSocket.messages;
|
||||
Assert.assertThat("Server.session.isSecure",captured.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT),is("session.isSecure=true"));
|
||||
|
||||
// Shutdown the socket
|
||||
clientSocket.close();
|
||||
|
@ -178,10 +172,9 @@ public class WebSocketOverSSLTest
|
|||
remote.flush();
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
clientSocket.messages.awaitEventCount(1,30,TimeUnit.SECONDS);
|
||||
EventQueue<String> captured = clientSocket.messages;
|
||||
LinkedBlockingQueue<String> captured = clientSocket.messages;
|
||||
String expected = String.format("session.upgradeRequest.requestURI=%s",requestUri.toASCIIString());
|
||||
Assert.assertThat("session.upgradeRequest.requestURI",captured.poll(),is(expected));
|
||||
Assert.assertThat("session.upgradeRequest.requestURI",captured.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT),is(expected));
|
||||
|
||||
// Shutdown the socket
|
||||
clientSocket.close();
|
||||
|
|
|
@ -21,28 +21,29 @@ package org.eclipse.jetty.websocket.server;
|
|||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.IBlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.server.helper.SessionServlet;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Testing various aspects of the server side support for WebSocket {@link org.eclipse.jetty.websocket.api.Session}
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class WebSocketServerSessionTest
|
||||
{
|
||||
private static SimpleServletServer server;
|
||||
private static BlockheadClient client;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
|
@ -57,19 +58,36 @@ public class WebSocketServerSessionTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisconnect() throws Exception
|
||||
{
|
||||
URI uri = server.getServerUri().resolve("/test/disconnect");
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
clientConn.write(new TextFrame().setPayload("harsh-disconnect"));
|
||||
clientConn.write(new TextFrame().setPayload("this shouldn't be seen by server"));
|
||||
|
||||
client.write(new TextFrame().setPayload("harsh-disconnect"));
|
||||
|
||||
client.awaitDisconnect(1, TimeUnit.SECONDS);
|
||||
TimeUnit.SECONDS.sleep(10);
|
||||
// clientConn.awaitDisconnect(1, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,27 +95,27 @@ public class WebSocketServerSessionTest
|
|||
public void testUpgradeRequestResponse() throws Exception
|
||||
{
|
||||
URI uri = server.getServerUri().resolve("/test?snack=cashews&amount=handful&brand=off");
|
||||
try (IBlockheadClient client = new BlockheadClient(uri))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(uri);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Ask the server socket for specific parameter map info
|
||||
client.write(new TextFrame().setPayload("getParameterMap|snack"));
|
||||
client.write(new TextFrame().setPayload("getParameterMap|amount"));
|
||||
client.write(new TextFrame().setPayload("getParameterMap|brand"));
|
||||
client.write(new TextFrame().setPayload("getParameterMap|cost")); // intentionally invalid
|
||||
clientConn.write(new TextFrame().setPayload("getParameterMap|snack"));
|
||||
clientConn.write(new TextFrame().setPayload("getParameterMap|amount"));
|
||||
clientConn.write(new TextFrame().setPayload("getParameterMap|brand"));
|
||||
clientConn.write(new TextFrame().setPayload("getParameterMap|cost")); // intentionally invalid
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(4,5,TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Parameter Map[snack]", tf.getPayloadAsUTF8(), is("[cashews]"));
|
||||
tf = frames.poll();
|
||||
tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Parameter Map[amount]", tf.getPayloadAsUTF8(), is("[handful]"));
|
||||
tf = frames.poll();
|
||||
tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Parameter Map[brand]", tf.getPayloadAsUTF8(), is("[off]"));
|
||||
tf = frames.poll();
|
||||
tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Parameter Map[cost]", tf.getPayloadAsUTF8(), is("<null>"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,14 +22,15 @@ import static org.hamcrest.Matchers.is;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.http.HttpHeader;
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.util.log.StdErrLog;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
|
@ -42,6 +43,9 @@ import org.eclipse.jetty.websocket.common.frames.BinaryFrame;
|
|||
import org.eclipse.jetty.websocket.common.frames.ContinuationFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.common.test.UnitGenerator;
|
||||
import org.eclipse.jetty.websocket.common.util.Hex;
|
||||
import org.eclipse.jetty.websocket.server.helper.RFCServlet;
|
||||
|
@ -50,16 +54,16 @@ import org.junit.AfterClass;
|
|||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Test various <a href="http://tools.ietf.org/html/rfc6455">RFC 6455</a> specified requirements placed on {@link WebSocketServlet}
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class WebSocketServletRFCTest
|
||||
{
|
||||
private static final String REQUEST_HASH_KEY = "dGhlIHNhbXBsZSBub25jZQ==";
|
||||
private static Generator generator = new UnitGenerator();
|
||||
private static SimpleServletServer server;
|
||||
private static BlockheadClient client;
|
||||
|
||||
@BeforeClass
|
||||
public static void startServer() throws Exception
|
||||
|
@ -74,16 +78,18 @@ public class WebSocketServletRFCTest
|
|||
server.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param clazz the class to enable
|
||||
* @param enabled true to enable the stack traces (or not)
|
||||
* @deprecated use {@link StacklessLogging} in a try-with-resources block instead
|
||||
*/
|
||||
@Deprecated
|
||||
private void enableStacks(Class<?> clazz, boolean enabled)
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
StdErrLog log = StdErrLog.getLogger(clazz);
|
||||
log.setHideStacks(!enabled);
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -93,13 +99,12 @@ public class WebSocketServletRFCTest
|
|||
@Test
|
||||
public void testBinaryAggregate() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
try
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Generate binary frames
|
||||
byte buf1[] = new byte[128];
|
||||
byte buf2[] = new byte[128];
|
||||
|
@ -113,19 +118,19 @@ public class WebSocketServletRFCTest
|
|||
|
||||
bin = new BinaryFrame().setPayload(buf1).setFin(false);
|
||||
|
||||
client.write(bin); // write buf1 (fin=false)
|
||||
clientConn.write(bin); // write buf1 (fin=false)
|
||||
|
||||
bin = new ContinuationFrame().setPayload(buf2).setFin(false);
|
||||
|
||||
client.write(bin); // write buf2 (fin=false)
|
||||
clientConn.write(bin); // write buf2 (fin=false)
|
||||
|
||||
bin = new ContinuationFrame().setPayload(buf3).setFin(true);
|
||||
|
||||
client.write(bin); // write buf3 (fin=true)
|
||||
clientConn.write(bin); // write buf3 (fin=true)
|
||||
|
||||
// Read frame echo'd back (hopefully a single binary frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
Frame binmsg = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
Frame binmsg = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
int expectedSize = buf1.length + buf2.length + buf3.length;
|
||||
Assert.assertThat("BinaryFrame.payloadLength",binmsg.getPayloadLength(),is(expectedSize));
|
||||
|
||||
|
@ -156,10 +161,6 @@ public class WebSocketServletRFCTest
|
|||
Assert.assertThat("Echoed data count for 0xBB",bbCount,is(buf2.length));
|
||||
Assert.assertThat("Echoed data count for 0xCC",ccCount,is(buf3.length));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = NotUtf8Exception.class)
|
||||
|
@ -179,26 +180,21 @@ public class WebSocketServletRFCTest
|
|||
@Test
|
||||
public void testEcho() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
try
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
// Generate text frame
|
||||
String msg = "this is an echo ... cho ... ho ... o";
|
||||
client.write(new TextFrame().setPayload(msg));
|
||||
clientConn.write(new TextFrame().setPayload(msg));
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame.status code",tf.getPayloadAsUTF8(),is(msg));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -209,26 +205,23 @@ public class WebSocketServletRFCTest
|
|||
@Test
|
||||
public void testInternalError() throws Exception
|
||||
{
|
||||
try (BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
StacklessLogging stackless=new StacklessLogging(EventDriver.class))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
|
||||
try (StacklessLogging context = new StacklessLogging(EventDriver.class))
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(EventDriver.class))
|
||||
{
|
||||
// Generate text frame
|
||||
client.write(new TextFrame().setPayload("CRASH"));
|
||||
clientConn.write(new TextFrame().setPayload("CRASH"));
|
||||
|
||||
// Read frame (hopefully close frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
Frame cf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
Frame cf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
CloseInfo close = new CloseInfo(cf);
|
||||
Assert.assertThat("Close Frame.status code",close.getStatusCode(),is(StatusCode.SERVER_ERROR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test http://tools.ietf.org/html/rfc6455#section-4.1 where server side upgrade handling is supposed to be case insensitive.
|
||||
|
@ -239,62 +232,51 @@ public class WebSocketServletRFCTest
|
|||
@Test
|
||||
public void testLowercaseUpgrade() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
try
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header("upgrade", "websocket");
|
||||
request.header("connection", "upgrade");
|
||||
request.header("sec-websocket-key", REQUEST_HASH_KEY);
|
||||
request.header("sec-websocket-origin", server.getServerUri().toASCIIString());
|
||||
request.header("sec-websocket-protocol", "echo");
|
||||
request.header("sec-websocket-version", "13");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
|
||||
StringBuilder req = new StringBuilder();
|
||||
req.append("GET ").append(client.getRequestPath()).append(" HTTP/1.1\r\n");
|
||||
req.append("Host: ").append(client.getRequestHost()).append("\r\n");
|
||||
req.append("Upgrade: websocket\r\n");
|
||||
req.append("connection: upgrade\r\n");
|
||||
req.append("sec-websocket-key: ").append(client.getRequestWebSocketKey()).append("\r\n");
|
||||
req.append("sec-websocket-origin: ").append(client.getRequestWebSocketOrigin()).append("\r\n");
|
||||
req.append("sec-websocket-protocol: echo\r\n");
|
||||
req.append("sec-websocket-version: 13\r\n");
|
||||
req.append("\r\n");
|
||||
client.writeRaw(req.toString());
|
||||
|
||||
client.expectUpgradeResponse();
|
||||
|
||||
// Generate text frame
|
||||
String msg = "this is an echo ... cho ... ho ... o";
|
||||
client.write(new TextFrame().setPayload(msg));
|
||||
clientConn.write(new TextFrame().setPayload(msg));
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame.status code",tf.getPayloadAsUTF8(),is(msg));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTextNotUTF8() throws Exception
|
||||
{
|
||||
try (StacklessLogging stackless=new StacklessLogging(Parser.class);
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri()))
|
||||
{
|
||||
client.setProtocols("other");
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header(HttpHeader.SEC_WEBSOCKET_SUBPROTOCOL, "other");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT);
|
||||
StacklessLogging ignore = new StacklessLogging(Parser.class))
|
||||
{
|
||||
byte buf[] = new byte[]
|
||||
{ (byte)0xC2, (byte)0xC3 };
|
||||
|
||||
WebSocketFrame txt = new TextFrame().setPayload(ByteBuffer.wrap(buf));
|
||||
txt.setMask(Hex.asByteArray("11223344"));
|
||||
ByteBuffer bbHeader = generator.generateHeaderBytes(txt);
|
||||
client.writeRaw(bbHeader);
|
||||
client.writeRaw(txt.getPayload());
|
||||
clientConn.writeRaw(bbHeader);
|
||||
clientConn.writeRaw(txt.getPayload());
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
WebSocketFrame frame = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame frame = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("frames[0].opcode",frame.getOpCode(),is(OpCode.CLOSE));
|
||||
CloseInfo close = new CloseInfo(frame);
|
||||
Assert.assertThat("Close Status Code",close.getStatusCode(),is(StatusCode.BAD_PAYLOAD));
|
||||
|
@ -310,37 +292,26 @@ public class WebSocketServletRFCTest
|
|||
@Test
|
||||
public void testUppercaseUpgrade() throws Exception
|
||||
{
|
||||
BlockheadClient client = new BlockheadClient(server.getServerUri());
|
||||
try
|
||||
BlockheadClientRequest request = client.newWsRequest(server.getServerUri());
|
||||
request.header("UPGRADE", "WEBSOCKET");
|
||||
request.header("CONNECTION", "UPGRADE");
|
||||
request.header("SEC-WEBSOCKET-KEY", REQUEST_HASH_KEY.toUpperCase(Locale.US));
|
||||
request.header("SEC-WEBSOCKET-ORIGIN", server.getServerUri().toASCIIString());
|
||||
request.header("SEC-WEBSOCKET-PROTOCOL", "ECHO");
|
||||
request.header("SEC-WEBSOCKET-VERSION", "13");
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
|
||||
StringBuilder req = new StringBuilder();
|
||||
req.append("GET ").append(client.getRequestPath()).append(" HTTP/1.1\r\n");
|
||||
req.append("HOST: ").append(client.getRequestHost()).append("\r\n");
|
||||
req.append("UPGRADE: WEBSOCKET\r\n");
|
||||
req.append("CONNECTION: UPGRADE\r\n");
|
||||
req.append("SEC-WEBSOCKET-KEY: ").append(client.getRequestWebSocketKey()).append("\r\n");
|
||||
req.append("SEC-WEBSOCKET-ORIGIN: ").append(client.getRequestWebSocketOrigin()).append("\r\n");
|
||||
req.append("SEC-WEBSOCKET-PROTOCOL: ECHO\r\n");
|
||||
req.append("SEC-WEBSOCKET-VERSION: 13\r\n");
|
||||
req.append("\r\n");
|
||||
client.writeRaw(req.toString());
|
||||
|
||||
client.expectUpgradeResponse();
|
||||
|
||||
// Generate text frame
|
||||
String msg = "this is an echo ... cho ... ho ... o";
|
||||
client.write(new TextFrame().setPayload(msg));
|
||||
clientConn.write(new TextFrame().setPayload(msg));
|
||||
|
||||
// Read frame (hopefully text frame)
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1,30,TimeUnit.SECONDS);
|
||||
WebSocketFrame tf = frames.poll();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame tf = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
Assert.assertThat("Text Frame.status code",tf.getPayloadAsUTF8(),is(msg));
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ import java.net.URI;
|
|||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
|
@ -36,19 +38,21 @@ import org.eclipse.jetty.server.Server;
|
|||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClient;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadClientRequest;
|
||||
import org.eclipse.jetty.websocket.common.test.BlockheadConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.Parameterized;
|
||||
|
||||
@Ignore("Unstable - see Issue #1815")
|
||||
@RunWith(Parameterized.class)
|
||||
public class WebSocketUpgradeFilterTest
|
||||
{
|
||||
|
@ -57,6 +61,22 @@ public class WebSocketUpgradeFilterTest
|
|||
Server newServer() throws Exception;
|
||||
}
|
||||
|
||||
private static BlockheadClient client;
|
||||
|
||||
@BeforeClass
|
||||
public static void startClient() throws Exception
|
||||
{
|
||||
client = new BlockheadClient();
|
||||
client.setIdleTimeout(TimeUnit.SECONDS.toMillis(2));
|
||||
client.start();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void stopClient() throws Exception
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
|
||||
private static AtomicInteger uniqTestDirId = new AtomicInteger(0);
|
||||
|
||||
private static File getNewTestDir()
|
||||
|
@ -306,16 +326,17 @@ public class WebSocketUpgradeFilterTest
|
|||
{
|
||||
URI destUri = serverUri.resolve("/info/");
|
||||
|
||||
try (BlockheadClient client = new BlockheadClient(destUri))
|
||||
BlockheadClientRequest request = client.newWsRequest(destUri);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
clientConn.write(new TextFrame().setPayload("hello"));
|
||||
|
||||
client.write(new TextFrame().setPayload("hello"));
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1000, TimeUnit.MILLISECONDS);
|
||||
String payload = frames.poll().getPayloadAsUTF8();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame received = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
String payload = received.getPayloadAsUTF8();
|
||||
|
||||
// If we can connect and send a text message, we know that the endpoint was
|
||||
// added properly, and the response will help us verify the policy configuration too
|
||||
|
@ -328,16 +349,17 @@ public class WebSocketUpgradeFilterTest
|
|||
{
|
||||
URI destUri = serverUri.resolve("/info/");
|
||||
|
||||
try (BlockheadClient client = new BlockheadClient(destUri))
|
||||
BlockheadClientRequest request = client.newWsRequest(destUri);
|
||||
|
||||
Future<BlockheadConnection> connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
clientConn.write(new TextFrame().setPayload("hello 1"));
|
||||
|
||||
client.write(new TextFrame().setPayload("hello 1"));
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1000, TimeUnit.MILLISECONDS);
|
||||
String payload = frames.poll().getPayloadAsUTF8();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame received = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
String payload = received.getPayloadAsUTF8();
|
||||
|
||||
// If we can connect and send a text message, we know that the endpoint was
|
||||
// added properly, and the response will help us verify the policy configuration too
|
||||
|
@ -347,16 +369,17 @@ public class WebSocketUpgradeFilterTest
|
|||
server.getHandler().stop();
|
||||
server.getHandler().start();
|
||||
|
||||
try (BlockheadClient client = new BlockheadClient(destUri))
|
||||
request = client.newWsRequest(destUri);
|
||||
|
||||
connFut = request.sendAsync();
|
||||
|
||||
try (BlockheadConnection clientConn = connFut.get(Timeouts.CONNECT, Timeouts.CONNECT_UNIT))
|
||||
{
|
||||
client.connect();
|
||||
client.sendStandardRequest();
|
||||
client.expectUpgradeResponse();
|
||||
clientConn.write(new TextFrame().setPayload("hello 2"));
|
||||
|
||||
client.write(new TextFrame().setPayload("hello 2"));
|
||||
|
||||
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1000, TimeUnit.MILLISECONDS);
|
||||
String payload = frames.poll().getPayloadAsUTF8();
|
||||
LinkedBlockingQueue<WebSocketFrame> frames = clientConn.getFrameQueue();
|
||||
WebSocketFrame received = frames.poll(Timeouts.POLL_EVENT, Timeouts.POLL_EVENT_UNIT);
|
||||
String payload = received.getPayloadAsUTF8();
|
||||
|
||||
// If we can connect and send a text message, we know that the endpoint was
|
||||
// added properly, and the response will help us verify the policy configuration too
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
|
@ -35,9 +34,7 @@ import org.eclipse.jetty.websocket.common.frames.PingFrame;
|
|||
import org.eclipse.jetty.websocket.common.frames.PongFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.Fuzzer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class TestABCase2 extends AbstractABCase
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.nio.ByteBuffer;
|
|||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.StacklessLogging;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
|
@ -33,12 +32,10 @@ import org.eclipse.jetty.websocket.common.frames.PingFrame;
|
|||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.Fuzzer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Test various bad / forbidden opcodes (per spec)
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class TestABCase4 extends AbstractABCase
|
||||
{
|
||||
/**
|
||||
|
|
|
@ -22,8 +22,6 @@ 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.log.StacklessLogging;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
|
@ -35,12 +33,10 @@ import org.eclipse.jetty.websocket.common.frames.PongFrame;
|
|||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.Fuzzer;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Fragmentation Tests
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class TestABCase5 extends AbstractABCase
|
||||
{
|
||||
/**
|
||||
|
@ -301,7 +297,6 @@ public class TestABCase5 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Slow
|
||||
public void testCase5_19() throws Exception
|
||||
{
|
||||
// phase 1
|
||||
|
|
|
@ -23,8 +23,6 @@ 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.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
|
@ -39,12 +37,10 @@ import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
|||
import org.eclipse.jetty.websocket.common.test.Fuzzer;
|
||||
import org.eclipse.jetty.websocket.common.util.Hex;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* UTF-8 Tests
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class TestABCase6 extends AbstractABCase
|
||||
{
|
||||
/**
|
||||
|
@ -276,7 +272,6 @@ public class TestABCase6 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Slow
|
||||
public void testCase6_4_1() throws Exception
|
||||
{
|
||||
byte part1[] = StringUtil.getUtf8Bytes("\u03BA\u1F79\u03C3\u03BC\u03B5");
|
||||
|
@ -312,7 +307,6 @@ public class TestABCase6 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Slow
|
||||
public void testCase6_4_2() throws Exception
|
||||
{
|
||||
byte part1[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5F4"); // split code point
|
||||
|
@ -340,7 +334,6 @@ public class TestABCase6 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Slow
|
||||
public void testCase6_4_3() throws Exception
|
||||
{
|
||||
// Disable Long Stacks from Parser (we know this test will throw an exception)
|
||||
|
@ -393,7 +386,6 @@ public class TestABCase6 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Slow
|
||||
public void testCase6_4_4() throws Exception
|
||||
{
|
||||
byte invalid[] = Hex.asByteArray("CEBAE1BDB9CF83CEBCCEB5F49080808080656469746564");
|
||||
|
|
|
@ -23,7 +23,6 @@ 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.StacklessLogging;
|
||||
|
@ -39,7 +38,6 @@ import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
|||
import org.eclipse.jetty.websocket.common.io.AbstractWebSocketConnection;
|
||||
import org.eclipse.jetty.websocket.common.test.Fuzzer;
|
||||
import org.eclipse.jetty.websocket.common.util.Hex;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
|
@ -47,9 +45,6 @@ import org.junit.Test;
|
|||
*/
|
||||
public class TestABCase7 extends AbstractABCase
|
||||
{
|
||||
@Rule
|
||||
public TestTracker tt = new TestTracker();
|
||||
|
||||
/**
|
||||
* Basic message then close frame, normal behavior
|
||||
* @throws Exception on test failure
|
||||
|
|
|
@ -24,8 +24,6 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.AdvancedRunner;
|
||||
import org.eclipse.jetty.toolchain.test.annotation.Stress;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
|
@ -36,13 +34,12 @@ import org.eclipse.jetty.websocket.common.frames.ContinuationFrame;
|
|||
import org.eclipse.jetty.websocket.common.frames.DataFrame;
|
||||
import org.eclipse.jetty.websocket.common.frames.TextFrame;
|
||||
import org.eclipse.jetty.websocket.common.test.Fuzzer;
|
||||
import org.eclipse.jetty.websocket.common.test.Timeouts;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
/**
|
||||
* Big frame/message tests
|
||||
*/
|
||||
@RunWith(AdvancedRunner.class)
|
||||
public class TestABCase9 extends AbstractABCase
|
||||
{
|
||||
private static final int KBYTE = 1024;
|
||||
|
@ -74,7 +71,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
int offset = 0;
|
||||
boolean fin;
|
||||
ByteBuffer buf;
|
||||
;
|
||||
byte op = opcode;
|
||||
while (remaining > 0)
|
||||
{
|
||||
|
@ -181,7 +177,7 @@ public class TestABCase9 extends AbstractABCase
|
|||
fuzzer.connect();
|
||||
fuzzer.setSendMode(Fuzzer.SendMode.BULK);
|
||||
fuzzer.send(send);
|
||||
fuzzer.expect(expect);
|
||||
fuzzer.expect(expect, Timeouts.POLL_EVENT*2, Timeouts.POLL_EVENT_UNIT);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -246,7 +242,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_1_5() throws Exception
|
||||
{
|
||||
byte utf[] = new byte[8 * MBYTE];
|
||||
|
@ -275,7 +270,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_1_6() throws Exception
|
||||
{
|
||||
byte utf[] = new byte[16 * MBYTE];
|
||||
|
@ -359,7 +353,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_2_3() throws Exception
|
||||
{
|
||||
byte data[] = new byte[1 * MBYTE];
|
||||
|
@ -388,7 +381,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_2_4() throws Exception
|
||||
{
|
||||
byte data[] = new byte[4 * MBYTE];
|
||||
|
@ -417,7 +409,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_2_5() throws Exception
|
||||
{
|
||||
byte data[] = new byte[8 * MBYTE];
|
||||
|
@ -446,7 +437,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_2_6() throws Exception
|
||||
{
|
||||
byte data[] = new byte[16 * MBYTE];
|
||||
|
@ -475,7 +465,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_1() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,64);
|
||||
|
@ -486,7 +475,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_2() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,256);
|
||||
|
@ -497,7 +485,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_3() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,1 * KBYTE);
|
||||
|
@ -508,7 +495,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_4() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,4 * KBYTE);
|
||||
|
@ -519,7 +505,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_5() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,16 * KBYTE);
|
||||
|
@ -530,7 +515,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_6() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,64 * KBYTE);
|
||||
|
@ -541,7 +525,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_7() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,256 * KBYTE);
|
||||
|
@ -552,7 +535,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_8() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,1 * MBYTE);
|
||||
|
@ -563,7 +545,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_3_9() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.TEXT,4 * MBYTE,4 * MBYTE);
|
||||
|
@ -574,7 +555,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_1() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,64);
|
||||
|
@ -585,7 +565,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_2() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,256);
|
||||
|
@ -596,7 +575,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_3() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,1 * KBYTE);
|
||||
|
@ -607,7 +585,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_4() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,4 * KBYTE);
|
||||
|
@ -618,7 +595,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_5() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,16 * KBYTE);
|
||||
|
@ -629,7 +605,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_6() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,64 * KBYTE);
|
||||
|
@ -640,7 +615,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_7() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,256 * KBYTE);
|
||||
|
@ -651,7 +625,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_8() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,1 * MBYTE);
|
||||
|
@ -662,7 +635,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_4_9() throws Exception
|
||||
{
|
||||
assertMultiFrameEcho(OpCode.BINARY,4 * MBYTE,4 * MBYTE);
|
||||
|
@ -673,7 +645,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_5_1() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,64);
|
||||
|
@ -684,7 +655,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_5_2() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,128);
|
||||
|
@ -695,7 +665,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_5_3() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,256);
|
||||
|
@ -706,7 +675,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_5_4() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,512);
|
||||
|
@ -717,7 +685,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_5_5() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,1024);
|
||||
|
@ -728,7 +695,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_5_6() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.TEXT,1 * MBYTE,2048);
|
||||
|
@ -739,7 +705,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_6_1() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,64);
|
||||
|
@ -750,7 +715,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_6_2() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,128);
|
||||
|
@ -761,7 +725,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_6_3() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,256);
|
||||
|
@ -772,7 +735,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_6_4() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,512);
|
||||
|
@ -783,7 +745,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_6_5() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,1024);
|
||||
|
@ -794,7 +755,6 @@ public class TestABCase9 extends AbstractABCase
|
|||
* @throws Exception on test failure
|
||||
*/
|
||||
@Test
|
||||
@Stress("High I/O use")
|
||||
public void testCase9_6_6() throws Exception
|
||||
{
|
||||
assertSlowFrameEcho(OpCode.BINARY,1 * MBYTE,2048);
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.eclipse.jetty.websocket.server.examples;
|
|||
import java.io.IOException;
|
||||
|
||||
import org.eclipse.jetty.io.RuntimeIOException;
|
||||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.RemoteEndpoint;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
|
||||
|
@ -43,8 +42,6 @@ public class MyEchoSocket extends WebSocketAdapter
|
|||
// echo the data back
|
||||
RemoteEndpoint remote = getRemote();
|
||||
remote.sendString(message);
|
||||
if (remote.getBatchMode() == BatchMode.ON)
|
||||
remote.flush();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue