- do not select duplicate extensions in javax default Configurator - correctly copy payload for ping frames in jetty & javax frame handlers - add ByteBuffer to javadoc for onMessage in jetty api - cleaned up some test logging for EventSocket - add autoFragment and maxFrameSize settings to WebSocketPolicy - fix early validation for multiple extensions in setExtensions Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
2310196532
commit
d0f74c5532
|
@ -545,13 +545,7 @@ public class JavaxWebSocketFrameHandler implements FrameHandler
|
|||
|
||||
public void onPing(Frame frame, Callback callback)
|
||||
{
|
||||
ByteBuffer payload = BufferUtil.EMPTY_BUFFER;
|
||||
|
||||
if (frame.hasPayload())
|
||||
{
|
||||
payload = ByteBuffer.allocate(frame.getPayloadLength());
|
||||
BufferUtil.put(frame.getPayload(), payload);
|
||||
}
|
||||
ByteBuffer payload = BufferUtil.copy(frame.getPayload());
|
||||
coreSession.sendFrame(new Frame(OpCode.PONG).setPayload(payload), Callback.NOOP, false);
|
||||
callback.succeeded();
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.javax.server.config;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.ServiceLoader;
|
||||
import javax.websocket.Extension;
|
||||
|
@ -28,6 +29,7 @@ import javax.websocket.server.ServerEndpointConfig.Configurator;
|
|||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.core.ExtensionConfig;
|
||||
|
||||
/**
|
||||
* The "Container Default Configurator" per the JSR-356 spec.
|
||||
|
@ -78,7 +80,16 @@ public final class ContainerDefaultConfigurator extends Configurator
|
|||
@Override
|
||||
public List<Extension> getNegotiatedExtensions(List<Extension> installed, List<Extension> requested)
|
||||
{
|
||||
return requested;
|
||||
List<Extension> negotiatedExtensions = new ArrayList<>();
|
||||
for (Extension ext : requested)
|
||||
{
|
||||
// Only choose the first extension if multiple with the same name.
|
||||
long matches = negotiatedExtensions.stream().filter(e -> e.getName().equals(ext.getName())).count();
|
||||
if (matches == 0)
|
||||
negotiatedExtensions.add(ext);
|
||||
}
|
||||
|
||||
return negotiatedExtensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"options": {
|
||||
"failByDrop": false
|
||||
},
|
||||
"outdir": "./target/reports/servers",
|
||||
"servers": [
|
||||
{
|
||||
"agent": "Jetty-10.0.0-SNAPSHOT",
|
||||
"url": "ws://127.0.0.1:9001",
|
||||
"options": {
|
||||
"version": 18
|
||||
}
|
||||
}
|
||||
],
|
||||
"cases": ["*"],
|
||||
"exclude-cases": [],
|
||||
"exclude-agent-cases": {}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"options": {
|
||||
"failByDrop": false
|
||||
},
|
||||
"url": "ws://127.0.0.1:9001",
|
||||
"outdir": "./target/reports/clients",
|
||||
"cases": ["*"],
|
||||
"exclude-cases": [],
|
||||
"exclude-agent-cases": {}
|
||||
}
|
|
@ -52,28 +52,32 @@ public class EventSocket
|
|||
public void onOpen(Session session)
|
||||
{
|
||||
this.session = session;
|
||||
LOG.info("{} onOpen(): {}", toString(), session);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onOpen(): {}", toString(), session);
|
||||
openLatch.countDown();
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onMessage(String message) throws IOException
|
||||
{
|
||||
LOG.info("{} onMessage(): {}", toString(), message);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onMessage(): {}", toString(), message);
|
||||
messageQueue.offer(message);
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose(CloseReason reason)
|
||||
{
|
||||
LOG.info("{} onClose(): {}", toString(), reason);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onClose(): {}", toString(), reason);
|
||||
closeLatch.countDown();
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Throwable cause)
|
||||
{
|
||||
LOG.info("{} onError(): {}", toString(), cause);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onError(): {}", toString(), cause);
|
||||
error = cause;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,200 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 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.javax.tests.autobahn;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import javax.websocket.CloseReason;
|
||||
|
||||
import org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.UrlEncoded;
|
||||
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.javax.client.JavaxWebSocketClientContainer;
|
||||
import org.eclipse.jetty.websocket.javax.tests.EventSocket;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* WebSocket Client for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||
* <p>
|
||||
* Installing Autobahn:
|
||||
* </p>
|
||||
* <pre>
|
||||
* # For Debian / Ubuntu
|
||||
* $ sudo apt-get install python python-dev python-twisted
|
||||
* $ sudo apt-get install python-pip
|
||||
* $ sudo pip install autobahntestsuite
|
||||
*
|
||||
* # For Fedora / Redhat
|
||||
* $ sudo yum install python python-dev python-pip twisted
|
||||
* $ sudo yum install libffi-devel
|
||||
* $ sudo pip install autobahntestsuite
|
||||
* </pre>
|
||||
* <p>
|
||||
* Upgrading an existing installation of autobahntestsuite
|
||||
* </p>
|
||||
* <pre>
|
||||
* $ sudo pip install -U autobahntestsuite
|
||||
* </pre>
|
||||
* <p>
|
||||
* Running Autobahn Fuzzing Server (which you run this client implementation against):
|
||||
* </p>
|
||||
* <pre>
|
||||
* # Change to javax-websocket-tests directory first.
|
||||
* $ cd jetty-websocket/javax-websocket-tests/
|
||||
* $ wstest --mode=fuzzingserver --spec=fuzzingserver.json
|
||||
*
|
||||
* # Report output is configured (in the fuzzingserver.json) at location:
|
||||
* $ ls target/reports/clients/
|
||||
* </pre>
|
||||
*/
|
||||
public class JavaxAutobahnClient
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
String hostname = "localhost";
|
||||
int port = 9001;
|
||||
|
||||
if (args.length > 0)
|
||||
hostname = args[0];
|
||||
if (args.length > 1)
|
||||
port = Integer.parseInt(args[1]);
|
||||
|
||||
// Optional case numbers
|
||||
// NOTE: these are url query parameter case numbers (whole integers, eg "6"), not the case ids (eg "7.3.1")
|
||||
int[] caseNumbers = null;
|
||||
if (args.length > 2)
|
||||
{
|
||||
int offset = 2;
|
||||
caseNumbers = new int[args.length - offset];
|
||||
for (int i = offset; i < args.length; i++)
|
||||
{
|
||||
caseNumbers[i - offset] = Integer.parseInt(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
JavaxAutobahnClient client = null;
|
||||
try
|
||||
{
|
||||
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
|
||||
client = new JavaxAutobahnClient(hostname, port, userAgent);
|
||||
|
||||
LOG.info("Running test suite...");
|
||||
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
|
||||
LOG.info("User Agent: {}", userAgent);
|
||||
|
||||
if (caseNumbers == null)
|
||||
{
|
||||
int caseCount = client.getCaseCount();
|
||||
LOG.info("Will run all {} cases ...", caseCount);
|
||||
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
|
||||
{
|
||||
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
|
||||
client.runCaseByNumber(caseNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Will run %d cases ...", caseNumbers.length);
|
||||
for (int caseNum : caseNumbers)
|
||||
{
|
||||
client.runCaseByNumber(caseNum);
|
||||
}
|
||||
}
|
||||
LOG.info("All test cases executed.");
|
||||
client.updateReports();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn("Test Failed", t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (client != null)
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Log.getLogger(JavaxAutobahnClient.class);
|
||||
private URI baseWebsocketUri;
|
||||
private JavaxWebSocketClientContainer clientContainer;
|
||||
private String userAgent;
|
||||
|
||||
public JavaxAutobahnClient(String hostname, int port, String userAgent) throws Exception
|
||||
{
|
||||
this.userAgent = userAgent;
|
||||
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
|
||||
this.clientContainer = new JavaxWebSocketClientContainer();
|
||||
clientContainer.start();
|
||||
}
|
||||
|
||||
public void stop()
|
||||
{
|
||||
LifeCycle.stop(clientContainer);
|
||||
}
|
||||
|
||||
public int getCaseCount()
|
||||
{
|
||||
URI wsUri = baseWebsocketUri.resolve("/getCaseCount");
|
||||
EventSocket onCaseCount = new EventSocket();
|
||||
|
||||
try
|
||||
{
|
||||
clientContainer.connectToServer(onCaseCount, wsUri);
|
||||
String msg = onCaseCount.messageQueue.poll(10, TimeUnit.SECONDS);
|
||||
onCaseCount.session.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, null));
|
||||
assertTrue(onCaseCount.closeLatch.await(2, TimeUnit.SECONDS));
|
||||
assertNotNull(msg);
|
||||
return Integer.decode(msg);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
throw new IllegalStateException("Unable to get Case Count", t);
|
||||
}
|
||||
}
|
||||
|
||||
public void runCaseByNumber(int caseNumber) throws Exception
|
||||
{
|
||||
URI wsUri = baseWebsocketUri.resolve("/runCase?case=" + caseNumber + "&agent=" + UrlEncoded.encodeString(userAgent));
|
||||
LOG.info("test uri: {}", wsUri);
|
||||
|
||||
JavaxAutobahnSocket echoHandler = new JavaxAutobahnSocket();
|
||||
clientContainer.connectToServer(echoHandler, wsUri);
|
||||
|
||||
// Wait up to 5 min as some of the tests can take a while
|
||||
if (!echoHandler.closeLatch.await(5, TimeUnit.MINUTES))
|
||||
{
|
||||
LOG.warn("could not close {}, closing session", echoHandler);
|
||||
echoHandler.session.close(new CloseReason(CloseReason.CloseCodes.GOING_AWAY, null));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateReports() throws Exception
|
||||
{
|
||||
URI wsUri = baseWebsocketUri.resolve("/updateReports?agent=" + UrlEncoded.encodeString(userAgent));
|
||||
EventSocket onUpdateReports = new EventSocket();
|
||||
clientContainer.connectToServer(onUpdateReports, wsUri);
|
||||
assertTrue(onUpdateReports.closeLatch.await(15, TimeUnit.SECONDS));
|
||||
LOG.info("Reports updated.");
|
||||
LOG.info("Test suite finished!");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 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.javax.tests.autobahn;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.javax.server.config.JavaxWebSocketServletContainerInitializer;
|
||||
|
||||
/**
|
||||
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||
* <p>
|
||||
* Installing Autobahn:
|
||||
* </p>
|
||||
* <pre>
|
||||
* # For Debian / Ubuntu
|
||||
* $ sudo apt-get install python python-dev python-twisted
|
||||
* $ sudo apt-get install python-pip
|
||||
* $ sudo pip install autobahntestsuite
|
||||
*
|
||||
* # For Fedora / Redhat
|
||||
* $ sudo yum install python python-dev python-pip twisted
|
||||
* $ sudo yum install libffi-devel
|
||||
* $ sudo pip install autobahntestsuite
|
||||
* </pre>
|
||||
* <p>
|
||||
* Upgrading an existing installation of autobahntestsuite
|
||||
* </p>
|
||||
* <pre>
|
||||
* $ sudo pip install -U autobahntestsuite
|
||||
* </pre>
|
||||
* <p>
|
||||
* Running Autobahn Fuzzing Client (against this server implementation):
|
||||
* </p>
|
||||
* <pre>
|
||||
* # Change to javax-websocket-tests directory first.
|
||||
* $ cd jetty-websocket/javax-websocket-tests/
|
||||
* $ wstest --mode=fuzzingclient --spec=fuzzingclient.json
|
||||
*
|
||||
* # Report output is configured (in the fuzzingclient.json) at location:
|
||||
* $ ls target/reports/servers/
|
||||
* </pre>
|
||||
*/
|
||||
public class JavaxAutobahnServer
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
int port = 9001; // same port as found in fuzzing-client.json
|
||||
if (args != null && args.length > 0)
|
||||
port = Integer.parseInt(args[0]);
|
||||
|
||||
Server server = new Server(port);
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setIdleTimeout(10000);
|
||||
server.addConnector(connector);
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.setContextPath("/");
|
||||
server.setHandler(context);
|
||||
|
||||
JavaxWebSocketServletContainerInitializer.configure(context, (servletContext, container)->
|
||||
container.addEndpoint(JavaxAutobahnSocket.class));
|
||||
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 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.javax.tests.autobahn;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
@ClientEndpoint
|
||||
@ServerEndpoint("/")
|
||||
public class JavaxAutobahnSocket
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JavaxAutobahnSocket.class);
|
||||
|
||||
public Session session;
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
|
||||
@OnOpen
|
||||
public void onConnect(Session session)
|
||||
{
|
||||
this.session = session;
|
||||
session.setMaxTextMessageBufferSize(Integer.MAX_VALUE);
|
||||
session.setMaxBinaryMessageBufferSize(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onText(String message) throws IOException
|
||||
{
|
||||
session.getBasicRemote().sendText(message);
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public void onBinary(ByteBuffer message) throws IOException
|
||||
{
|
||||
session.getBasicRemote().sendBinary(message);
|
||||
}
|
||||
|
||||
@OnError
|
||||
public void onError(Throwable t)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("onError()", t);
|
||||
}
|
||||
|
||||
@OnClose
|
||||
public void onClose()
|
||||
{
|
||||
closeLatch.countDown();
|
||||
}
|
||||
}
|
|
@ -84,6 +84,20 @@ public interface WebSocketPolicy
|
|||
*/
|
||||
long getMaxTextMessageSize();
|
||||
|
||||
/**
|
||||
* The maximum payload size of any WebSocket Frame which can be received.
|
||||
*
|
||||
* @return the maximum size of a WebSocket Frame.
|
||||
*/
|
||||
long getMaxFrameSize();
|
||||
|
||||
/**
|
||||
* If true, frames are automatically fragmented to respect the maximum frame size.
|
||||
*
|
||||
* @return whether to automatically fragment incoming WebSocket Frames.
|
||||
*/
|
||||
boolean isAutoFragment();
|
||||
|
||||
/**
|
||||
* The duration that a websocket may be idle before being closed by the implementation
|
||||
*
|
||||
|
@ -123,4 +137,21 @@ public interface WebSocketPolicy
|
|||
* @param size the maximum allowed size of a text message.
|
||||
*/
|
||||
void setMaxTextMessageSize(long size);
|
||||
|
||||
/**
|
||||
* The maximum payload size of any WebSocket Frame which can be received.
|
||||
* <p>
|
||||
* WebSocket Frames over this maximum will result in a close code 1009 {@link StatusCode#MESSAGE_TOO_LARGE}
|
||||
* </p>
|
||||
*
|
||||
* @param maxFrameSize the maximum allowed size of a WebSocket Frame.
|
||||
*/
|
||||
void setMaxFrameSize(long maxFrameSize);
|
||||
|
||||
/**
|
||||
* If set to true, frames are automatically fragmented to respect the maximum frame size.
|
||||
*
|
||||
* @param autoFragment whether to automatically fragment incoming WebSocket Frames.
|
||||
*/
|
||||
void setAutoFragment(boolean autoFragment);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,8 @@ import org.eclipse.jetty.websocket.api.Session;
|
|||
* <p>
|
||||
* <u>Binary Message Versions</u>
|
||||
* <ol>
|
||||
* <li>{@code public void methodName(ByteBuffer message)}</li>
|
||||
* <li><code>public void methodName({@link Session} session, ByteBuffer message)</code></li>
|
||||
* <li>{@code public void methodName(byte buf[], int offset, int length)}</li>
|
||||
* <li><code>public void methodName({@link Session} session, byte buf[], int offset, int length)</code></li>
|
||||
* <li>{@code public void methodName(InputStream stream)}</li>
|
||||
|
|
|
@ -237,6 +237,18 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketPoli
|
|||
return configurationCustomizer.getMaxTextMessageSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxFrameSize()
|
||||
{
|
||||
return configurationCustomizer.getMaxFrameSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoFragment()
|
||||
{
|
||||
return configurationCustomizer.isAutoFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdleTimeout(Duration duration)
|
||||
{
|
||||
|
@ -268,6 +280,18 @@ public class WebSocketClient extends ContainerLifeCycle implements WebSocketPoli
|
|||
configurationCustomizer.setMaxTextMessageSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFrameSize(long maxFrameSize)
|
||||
{
|
||||
configurationCustomizer.setMaxFrameSize(maxFrameSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoFragment(boolean autoFragment)
|
||||
{
|
||||
configurationCustomizer.setAutoFragment(autoFragment);
|
||||
}
|
||||
|
||||
public SocketAddress getBindAddress()
|
||||
{
|
||||
return getHttpClient().getBindAddress();
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.websocket.api.BatchMode;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.common.invoke.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.core.BadPayloadException;
|
||||
import org.eclipse.jetty.websocket.core.CloseException;
|
||||
|
@ -359,10 +360,8 @@ public class JettyWebSocketFrameHandler implements FrameHandler
|
|||
else
|
||||
{
|
||||
// Automatically respond
|
||||
Frame pong = new Frame(OpCode.PONG);
|
||||
if (frame.hasPayload())
|
||||
pong.setPayload(frame.getPayload());
|
||||
getSession().getRemote().getCoreSession().sendFrame(pong, Callback.NOOP, false);
|
||||
ByteBuffer payload = BufferUtil.copy(frame.getPayload());
|
||||
getSession().getRemote().sendPong(payload, WriteCallback.NOOP);
|
||||
}
|
||||
callback.succeeded();
|
||||
}
|
||||
|
|
|
@ -117,6 +117,18 @@ public class WebSocketSession extends AbstractLifeCycle implements Session, Susp
|
|||
return coreSession.getMaxTextMessageSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxFrameSize()
|
||||
{
|
||||
return coreSession.getMaxFrameSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoFragment()
|
||||
{
|
||||
return coreSession.isAutoFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdleTimeout(Duration duration)
|
||||
{
|
||||
|
@ -147,6 +159,18 @@ public class WebSocketSession extends AbstractLifeCycle implements Session, Susp
|
|||
coreSession.setMaxTextMessageSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFrameSize(long maxFrameSize)
|
||||
{
|
||||
coreSession.setMaxFrameSize(maxFrameSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoFragment(boolean autoFragment)
|
||||
{
|
||||
coreSession.setAutoFragment(autoFragment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProtocolVersion()
|
||||
{
|
||||
|
|
|
@ -295,6 +295,18 @@ public class OutgoingMessageCapture extends FrameHandler.CoreSession.Empty imple
|
|||
return maxMessageSize;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxFrameSize()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoFragment()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdleTimeout(Duration duration)
|
||||
{
|
||||
|
@ -319,6 +331,16 @@ public class OutgoingMessageCapture extends FrameHandler.CoreSession.Empty imple
|
|||
public void setMaxTextMessageSize(long size)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFrameSize(long maxFrameSize)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoFragment(boolean autoFragment)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,6 +206,18 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
return customizer.getMaxTextMessageSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxFrameSize()
|
||||
{
|
||||
return customizer.getMaxFrameSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAutoFragment()
|
||||
{
|
||||
return customizer.isAutoFragment();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIdleTimeout(Duration duration)
|
||||
{
|
||||
|
@ -235,4 +247,16 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
{
|
||||
customizer.setMaxTextMessageSize(size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxFrameSize(long maxFrameSize)
|
||||
{
|
||||
customizer.setMaxFrameSize(maxFrameSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAutoFragment(boolean autoFragment)
|
||||
{
|
||||
customizer.setAutoFragment(autoFragment);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import java.time.Duration;
|
|||
import java.util.Set;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
|
@ -50,44 +49,25 @@ public class JettyWebSocketServletFactory implements WebSocketPolicy
|
|||
return WebSocketBehavior.SERVER;
|
||||
}
|
||||
|
||||
/**
|
||||
* If true, frames are automatically fragmented to respect the maximum frame size.
|
||||
*
|
||||
* @return whether to automatically fragment incoming WebSocket Frames.
|
||||
*/
|
||||
@Override
|
||||
public boolean isAutoFragment()
|
||||
{
|
||||
return factory.isAutoFragment();
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to true, frames are automatically fragmented to respect the maximum frame size.
|
||||
*
|
||||
* @param autoFragment whether to automatically fragment incoming WebSocket Frames.
|
||||
*/
|
||||
@Override
|
||||
public void setAutoFragment(boolean autoFragment)
|
||||
{
|
||||
factory.setAutoFragment(autoFragment);
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum payload size of any WebSocket Frame which can be received.
|
||||
*
|
||||
* @return the maximum size of a WebSocket Frame.
|
||||
*/
|
||||
@Override
|
||||
public long getMaxFrameSize()
|
||||
{
|
||||
return factory.getMaxFrameSize();
|
||||
}
|
||||
|
||||
/**
|
||||
* The maximum payload size of any WebSocket Frame which can be received.
|
||||
* <p>
|
||||
* WebSocket Frames over this maximum will result in a close code 1009 {@link StatusCode#MESSAGE_TOO_LARGE}
|
||||
* </p>
|
||||
*
|
||||
* @param maxFrameSize the maximum allowed size of a WebSocket Frame.
|
||||
*/
|
||||
@Override
|
||||
public void setMaxFrameSize(long maxFrameSize)
|
||||
{
|
||||
factory.setMaxFrameSize(maxFrameSize);
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"options": {
|
||||
"failByDrop": false
|
||||
},
|
||||
"outdir": "./target/reports/servers",
|
||||
"servers": [
|
||||
{
|
||||
"agent": "Jetty-10.0.0-SNAPSHOT",
|
||||
"url": "ws://127.0.0.1:9001",
|
||||
"options": {
|
||||
"version": 18
|
||||
}
|
||||
}
|
||||
],
|
||||
"cases": ["*"],
|
||||
"exclude-cases": [],
|
||||
"exclude-agent-cases": {}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"options": {
|
||||
"failByDrop": false
|
||||
},
|
||||
"url": "ws://127.0.0.1:9001",
|
||||
"outdir": "./target/reports/clients",
|
||||
"cases": ["*"],
|
||||
"exclude-cases": [],
|
||||
"exclude-agent-cases": {}
|
||||
}
|
|
@ -57,14 +57,16 @@ public class EventSocket
|
|||
{
|
||||
this.session = session;
|
||||
behavior = session.getPolicy().getBehavior().name();
|
||||
LOG.info("{} onOpen(): {}", toString(), session);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onOpen(): {}", toString(), session);
|
||||
openLatch.countDown();
|
||||
}
|
||||
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(String message) throws IOException
|
||||
{
|
||||
LOG.info("{} onMessage(): {}", toString(), message);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onMessage(): {}", toString(), message);
|
||||
messageQueue.offer(message);
|
||||
}
|
||||
|
||||
|
@ -72,14 +74,16 @@ public class EventSocket
|
|||
public void onMessage(byte buf[], int offset, int len)
|
||||
{
|
||||
ByteBuffer message = ByteBuffer.wrap(buf, offset, len);
|
||||
LOG.info("{} onMessage(): {}", toString(), message);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onMessage(): {}", toString(), message);
|
||||
binaryMessageQueue.offer(message);
|
||||
}
|
||||
|
||||
@OnWebSocketClose
|
||||
public void onClose(int statusCode, String reason)
|
||||
{
|
||||
LOG.info("{} onClose(): {}:{}", toString(), statusCode, reason);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onClose(): {}:{}", toString(), statusCode, reason);
|
||||
this.statusCode = statusCode;
|
||||
this.reason = reason;
|
||||
closeLatch.countDown();
|
||||
|
@ -88,7 +92,8 @@ public class EventSocket
|
|||
@OnWebSocketError
|
||||
public void onError(Throwable cause)
|
||||
{
|
||||
LOG.info("{} onError(): {}", toString(), cause);
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("{} onError(): {}", toString(), cause);
|
||||
error = cause;
|
||||
errorLatch.countDown();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,227 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 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.tests.autobahn;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
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 org.eclipse.jetty.util.Jetty;
|
||||
import org.eclipse.jetty.util.UrlEncoded;
|
||||
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.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.tests.EchoSocket;
|
||||
import org.eclipse.jetty.websocket.tests.EventSocket;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* WebSocket Client for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||
* <p>
|
||||
* Installing Autobahn:
|
||||
* </p>
|
||||
* <pre>
|
||||
* # For Debian / Ubuntu
|
||||
* $ sudo apt-get install python python-dev python-twisted
|
||||
* $ sudo apt-get install python-pip
|
||||
* $ sudo pip install autobahntestsuite
|
||||
*
|
||||
* # For Fedora / Redhat
|
||||
* $ sudo yum install python python-dev python-pip twisted
|
||||
* $ sudo yum install libffi-devel
|
||||
* $ sudo pip install autobahntestsuite
|
||||
* </pre>
|
||||
* <p>
|
||||
* Upgrading an existing installation of autobahntestsuite
|
||||
* </p>
|
||||
* <pre>
|
||||
* $ sudo pip install -U autobahntestsuite
|
||||
* </pre>
|
||||
* <p>
|
||||
* Running Autobahn Fuzzing Server (which you run this client implementation against):
|
||||
* </p>
|
||||
* <pre>
|
||||
* # Change to jetty-websocket-tests directory first.
|
||||
* $ cd jetty-websocket/jetty-websocket-tests/
|
||||
* $ wstest --mode=fuzzingserver --spec=fuzzingserver.json
|
||||
*
|
||||
* # Report output is configured (in the fuzzingserver.json) at location:
|
||||
* $ ls target/reports/clients/
|
||||
* </pre>
|
||||
*/
|
||||
public class JettyAutobahnClient
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
String hostname = "localhost";
|
||||
int port = 9001;
|
||||
|
||||
if (args.length > 0)
|
||||
hostname = args[0];
|
||||
if (args.length > 1)
|
||||
port = Integer.parseInt(args[1]);
|
||||
|
||||
// Optional case numbers
|
||||
// NOTE: these are url query parameter case numbers (whole integers, eg "6"), not the case ids (eg "7.3.1")
|
||||
int[] caseNumbers = null;
|
||||
if (args.length > 2)
|
||||
{
|
||||
int offset = 2;
|
||||
caseNumbers = new int[args.length - offset];
|
||||
for (int i = offset; i < args.length; i++)
|
||||
{
|
||||
caseNumbers[i - offset] = Integer.parseInt(args[i]);
|
||||
}
|
||||
}
|
||||
|
||||
JettyAutobahnClient client = null;
|
||||
try
|
||||
{
|
||||
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
|
||||
client = new JettyAutobahnClient(hostname, port, userAgent);
|
||||
|
||||
LOG.info("Running test suite...");
|
||||
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
|
||||
LOG.info("User Agent: {}", userAgent);
|
||||
|
||||
if (caseNumbers == null)
|
||||
{
|
||||
int caseCount = client.getCaseCount();
|
||||
LOG.info("Will run all {} cases ...", caseCount);
|
||||
for (int caseNum = 1; caseNum <= caseCount; caseNum++)
|
||||
{
|
||||
LOG.info("Running case {} (of {}) ...", caseNum, caseCount);
|
||||
client.runCaseByNumber(caseNum);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.info("Will run %d cases ...", caseNumbers.length);
|
||||
for (int caseNum : caseNumbers)
|
||||
{
|
||||
client.runCaseByNumber(caseNum);
|
||||
}
|
||||
}
|
||||
LOG.info("All test cases executed.");
|
||||
client.updateReports();
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn("Test Failed", t);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (client != null)
|
||||
client.shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Log.getLogger(JettyAutobahnClient.class);
|
||||
private URI baseWebsocketUri;
|
||||
private WebSocketClient client;
|
||||
private String userAgent;
|
||||
|
||||
public JettyAutobahnClient(String hostname, int port, String userAgent) throws Exception
|
||||
{
|
||||
this.userAgent = userAgent;
|
||||
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
|
||||
this.client = new WebSocketClient();
|
||||
this.client.start();
|
||||
}
|
||||
|
||||
public int getCaseCount() throws IOException, InterruptedException
|
||||
{
|
||||
URI wsUri = baseWebsocketUri.resolve("/getCaseCount");
|
||||
EventSocket onCaseCount = new EventSocket();
|
||||
CompletableFuture<Session> response = client.connect(onCaseCount, wsUri);
|
||||
|
||||
if (waitForUpgrade(wsUri, response))
|
||||
{
|
||||
String msg = onCaseCount.messageQueue.poll(10, TimeUnit.SECONDS);
|
||||
onCaseCount.session.close(StatusCode.SHUTDOWN, null);
|
||||
assertTrue(onCaseCount.closeLatch.await(2, TimeUnit.SECONDS));
|
||||
assertNotNull(msg);
|
||||
return Integer.decode(msg);
|
||||
}
|
||||
throw new IllegalStateException("Unable to get Case Count");
|
||||
}
|
||||
|
||||
public void runCaseByNumber(int caseNumber) throws IOException, InterruptedException
|
||||
{
|
||||
URI wsUri = baseWebsocketUri.resolve("/runCase?case=" + caseNumber + "&agent=" + UrlEncoded.encodeString(userAgent));
|
||||
LOG.info("test uri: {}", wsUri);
|
||||
|
||||
EchoSocket echoHandler = new JettyAutobahnSocket();
|
||||
Future<Session> response = client.connect(echoHandler, wsUri);
|
||||
if (waitForUpgrade(wsUri, response))
|
||||
{
|
||||
// Wait up to 5 min as some of the tests can take a while
|
||||
if (!echoHandler.closeLatch.await(5, TimeUnit.MINUTES))
|
||||
{
|
||||
LOG.warn("could not close {}, aborting session", echoHandler);
|
||||
echoHandler.session.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown()
|
||||
{
|
||||
try
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOG.warn("Unable to stop WebSocketClient", e);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateReports() throws IOException, InterruptedException, ExecutionException, TimeoutException
|
||||
{
|
||||
URI wsUri = baseWebsocketUri.resolve("/updateReports?agent=" + UrlEncoded.encodeString(userAgent));
|
||||
EventSocket onUpdateReports = new EventSocket();
|
||||
Future<Session> response = client.connect(onUpdateReports, wsUri);
|
||||
response.get(5, TimeUnit.SECONDS);
|
||||
assertTrue(onUpdateReports.closeLatch.await(15, TimeUnit.SECONDS));
|
||||
LOG.info("Reports updated.");
|
||||
LOG.info("Test suite finished!");
|
||||
}
|
||||
|
||||
private boolean waitForUpgrade(URI wsUri, Future<Session> response)
|
||||
{
|
||||
try
|
||||
{
|
||||
response.get(10, TimeUnit.SECONDS);
|
||||
return true;
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn("Unable to connect to: " + wsUri, t);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 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.tests.autobahn;
|
||||
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.server.ServerConnector;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||
|
||||
/**
|
||||
* WebSocket Server for use with <a href="https://github.com/crossbario/autobahn-testsuite">autobahn websocket testsuite</a> (wstest).
|
||||
* <p>
|
||||
* Installing Autobahn:
|
||||
* </p>
|
||||
* <pre>
|
||||
* # For Debian / Ubuntu
|
||||
* $ sudo apt-get install python python-dev python-twisted
|
||||
* $ sudo apt-get install python-pip
|
||||
* $ sudo pip install autobahntestsuite
|
||||
*
|
||||
* # For Fedora / Redhat
|
||||
* $ sudo yum install python python-dev python-pip twisted
|
||||
* $ sudo yum install libffi-devel
|
||||
* $ sudo pip install autobahntestsuite
|
||||
* </pre>
|
||||
* <p>
|
||||
* Upgrading an existing installation of autobahntestsuite
|
||||
* </p>
|
||||
* <pre>
|
||||
* $ sudo pip install -U autobahntestsuite
|
||||
* </pre>
|
||||
* <p>
|
||||
* Running Autobahn Fuzzing Client (against this server implementation):
|
||||
* </p>
|
||||
* <pre>
|
||||
* # Change to jetty-websocket-tests directory first.
|
||||
* $ cd jetty-websocket/jetty-websocket-tests/
|
||||
* $ wstest --mode=fuzzingclient --spec=fuzzingclient.json
|
||||
*
|
||||
* # Report output is configured (in the fuzzingclient.json) at location:
|
||||
* $ ls target/reports/servers/
|
||||
* </pre>
|
||||
*/
|
||||
public class JettyAutobahnServer
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
||||
int port = 9001; // same port as found in fuzzing-client.json
|
||||
if (args != null && args.length > 0)
|
||||
port = Integer.parseInt(args[0]);
|
||||
|
||||
Server server = new Server(port);
|
||||
ServerConnector connector = new ServerConnector(server);
|
||||
connector.setIdleTimeout(10000);
|
||||
server.addConnector(connector);
|
||||
ServletContextHandler context = new ServletContextHandler();
|
||||
context.setContextPath("/");
|
||||
server.setHandler(context);
|
||||
|
||||
JettyWebSocketServletContainerInitializer.configure(context, (servletContext, container)->
|
||||
container.addMapping("/", (req, resp) -> new JettyAutobahnSocket()));
|
||||
|
||||
server.start();
|
||||
server.join();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2019 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.tests.autobahn;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.tests.EchoSocket;
|
||||
|
||||
@WebSocket
|
||||
public class JettyAutobahnSocket extends EchoSocket
|
||||
{
|
||||
@Override
|
||||
public void onOpen(Session session)
|
||||
{
|
||||
super.onOpen(session);
|
||||
session.setMaxTextMessageSize(Long.MAX_VALUE);
|
||||
session.setMaxBinaryMessageSize(Long.MAX_VALUE);
|
||||
session.setMaxFrameSize(WebSocketConstants.DEFAULT_MAX_FRAME_SIZE*2);
|
||||
}
|
||||
}
|
|
@ -141,7 +141,7 @@
|
|||
</goals>
|
||||
<configuration>
|
||||
<!-- The class that contains a main method which accepts the port as a parameter to start the server. -->
|
||||
<mainClass>org.eclipse.jetty.websocket.core.autobahn.AutobahnWebSocketServer</mainClass>
|
||||
<mainClass>org.eclipse.jetty.websocket.core.autobahn.CoreAutobahnServer</mainClass>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
|
|
@ -48,6 +48,7 @@ import org.junit.jupiter.api.Test;
|
|||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
@ -104,6 +105,7 @@ public class WebSocketNegotiationTest extends WebSocketTester
|
|||
break;
|
||||
|
||||
case "test":
|
||||
case "testExtensionThatDoesNotExist":
|
||||
case "testInvalidExtensionParameter":
|
||||
case "testAcceptTwoExtensionsOfSameName":
|
||||
case "testInvalidUpgradeRequest":
|
||||
|
@ -239,6 +241,23 @@ public class WebSocketNegotiationTest extends WebSocketTester
|
|||
assertNull(extensionHeader.get(5, TimeUnit.SECONDS));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExtensionThatDoesNotExist() throws Exception
|
||||
{
|
||||
Socket client = new Socket();
|
||||
client.connect(new InetSocketAddress("127.0.0.1", server.getLocalPort()));
|
||||
|
||||
HttpFields httpFields = newUpgradeRequest("nonExistentExtensionName");
|
||||
String upgradeRequest = "GET / HTTP/1.1\r\n" + httpFields;
|
||||
client.getOutputStream().write(upgradeRequest.getBytes(StandardCharsets.ISO_8859_1));
|
||||
String response = getUpgradeResponse(client.getInputStream());
|
||||
|
||||
assertThat(response, startsWith("HTTP/1.1 101 Switching Protocols"));
|
||||
assertThat(response, containsString("Sec-WebSocket-Protocol: test"));
|
||||
assertThat(response, containsString("Sec-WebSocket-Accept: +WahVcVmeMLKQUMm0fvPrjSjwzI="));
|
||||
assertThat(response, not(containsString(HttpHeader.SEC_WEBSOCKET_EXTENSIONS.asString())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAcceptTwoExtensionsOfSameName() throws Exception
|
||||
{
|
||||
|
|
|
@ -62,7 +62,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
* Running Autobahn Fuzzing Server (which you run this client implementation against):
|
||||
* </p>
|
||||
* <pre>
|
||||
* # Change to websocket-core
|
||||
* # Change to websocket-core first
|
||||
* $ cd jetty-websocket/websocket-core
|
||||
* $ wstest --mode=fuzzingserver --spec=fuzzingserver.json
|
||||
*
|
||||
|
@ -70,7 +70,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
* $ ls target/reports/clients/
|
||||
* </pre>
|
||||
*/
|
||||
public class AutobahnWebSocketClient
|
||||
public class CoreAutobahnClient
|
||||
{
|
||||
public static void main(String[] args)
|
||||
{
|
||||
|
@ -95,11 +95,11 @@ public class AutobahnWebSocketClient
|
|||
}
|
||||
}
|
||||
|
||||
AutobahnWebSocketClient client = null;
|
||||
CoreAutobahnClient client = null;
|
||||
try
|
||||
{
|
||||
String userAgent = "JettyWebsocketClient/" + Jetty.VERSION;
|
||||
client = new AutobahnWebSocketClient(hostname, port, userAgent);
|
||||
client = new CoreAutobahnClient(hostname, port, userAgent);
|
||||
|
||||
LOG.info("Running test suite...");
|
||||
LOG.info("Using Fuzzing Server: {}:{}", hostname, port);
|
||||
|
@ -137,12 +137,12 @@ public class AutobahnWebSocketClient
|
|||
}
|
||||
}
|
||||
|
||||
private static final Logger LOG = Log.getLogger(AutobahnWebSocketClient.class);
|
||||
private static final Logger LOG = Log.getLogger(CoreAutobahnClient.class);
|
||||
private URI baseWebsocketUri;
|
||||
private WebSocketCoreClient client;
|
||||
private String userAgent;
|
||||
|
||||
public AutobahnWebSocketClient(String hostname, int port, String userAgent) throws Exception
|
||||
public CoreAutobahnClient(String hostname, int port, String userAgent) throws Exception
|
||||
{
|
||||
this.userAgent = userAgent;
|
||||
this.baseWebsocketUri = new URI("ws://" + hostname + ":" + port);
|
|
@ -57,7 +57,7 @@ import org.eclipse.jetty.websocket.core.server.WebSocketUpgradeHandler;
|
|||
* $ ls target/reports/servers/
|
||||
* </pre>
|
||||
*/
|
||||
public class AutobahnWebSocketServer
|
||||
public class CoreAutobahnServer
|
||||
{
|
||||
public static void main(String[] args) throws Exception
|
||||
{
|
|
@ -176,7 +176,7 @@ public class ServletUpgradeResponse
|
|||
if (matches < 1)
|
||||
throw new IllegalArgumentException("Extension not a requested extension");
|
||||
|
||||
matches = negotiation.getNegotiatedExtensions().stream().filter(e -> e.getName().equals(config.getName())).count();
|
||||
matches = configs.stream().filter(e -> e.getName().equals(config.getName())).count();
|
||||
if (matches > 1)
|
||||
throw new IllegalArgumentException("Multiple extensions of the same name");
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue