blob: da5c1bae23ef1cabe3d0db02c734a54f823a4a50 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd.
// ------------------------------------------------------------------------
// All rights reserved. This program and the accompanying materials
// are made available under the terms of the Eclipse Public License v1.0
// and Apache License v2.0 which accompanies this distribution.
//
// The Eclipse Public License is available at
// http://www.eclipse.org/legal/epl-v10.html
//
// The Apache License v2.0 is available at
// http://www.opensource.org/licenses/apache2.0.php
//
// You may elect to redistribute this code under either of these licenses.
// ========================================================================
//
package org.eclipse.jetty.websocket.server;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import java.io.File;
import java.net.URI;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import javax.servlet.DispatcherType;
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.servlet.ServletUpgradeRequest;
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class WebSocketUpgradeFilterTest
{
interface ServerProvider
{
Server newServer() throws Exception;
}
private static AtomicInteger uniqTestDirId = new AtomicInteger(0);
private static File getNewTestDir()
{
return MavenTestingUtils.getTargetTestingDir("WSUF-webxml-" + uniqTestDirId.getAndIncrement());
}
@Parameterized.Parameters(name = "{0}")
public static List<Object[]> data()
{
/*
* Case A:
* 1. embedded-jetty WSUF.configureContext() / app-ws configured at ...
* a. during server construction / before server.start (might not be possible with current impl, native SCI not run (yet))
* might require NativeSCI.getDefaultFrom() first
* b. during server construction / after server.start
* c. during server start / via CustomServlet.init()
* 2. embedded-jetty WSUF addFilter / app-ws configured at server construction (before server.start)
* Case B:
* 1. web.xml WSUF / app-ws configured in CustomServlet.init() load-on-start
* Case C:
* 1. embedded-jetty WSUF.configureContext() / app-ws configured via ServletContextListener.contextInitialized
* 2. embedded-jetty WSUF addFilter / app-ws configured via ServletContextListener.contextInitialized
* Case D:
* 1. web.xml WSUF / app-ws configured via ServletContextListener.contextInitialized
*
* Every "app-ws configured" means it should access/set ws policy and add ws mappings
*/
final WebSocketCreator infoCreator = new WebSocketCreator()
{
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
return new InfoSocket();
}
};
List<Object[]> cases = new ArrayList<>();
// Embedded WSUF.configureContext(), directly app-ws configuration
cases.add(new Object[]{"wsuf.configureContext/Direct configure", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
WebSocketUpgradeFilter wsuf = WebSocketUpgradeFilter.configureContext(context);
// direct configuration via WSUF
wsuf.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
wsuf.addMapping("/info/*", infoCreator);
server.start();
return server;
}
}});
// Embedded WSUF.configureContext(), apply app-ws configuration via attribute
cases.add(new Object[]{"wsuf.configureContext/Attribute based configure", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
WebSocketUpgradeFilter.configureContext(context);
// configuration via attribute
NativeWebSocketConfiguration configuration = (NativeWebSocketConfiguration) context.getServletContext().getAttribute(NativeWebSocketConfiguration.class.getName());
assertThat("NativeWebSocketConfiguration", configuration, notNullValue());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
server.start();
return server;
}
}});
// Embedded WSUF, added as filter, apply app-ws configuration via attribute
cases.add(new Object[]{"wsuf/addFilter/Attribute based configure", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
context.addFilter(WebSocketUpgradeFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
context.setAttribute(NativeWebSocketConfiguration.class.getName(), configuration);
server.start();
return server;
}
}});
// Embedded WSUF, added as filter, apply app-ws configuration via wsuf constructor
cases.add(new Object[]{"wsuf/addFilter/WSUF Constructor configure", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
NativeWebSocketConfiguration configuration = new NativeWebSocketConfiguration(context.getServletContext());
configuration.getFactory().getPolicy().setMaxTextMessageSize(10 * 1024 * 1024);
configuration.addMapping("/info/*", infoCreator);
context.addBean(configuration, true);
FilterHolder wsufHolder = new FilterHolder(new WebSocketUpgradeFilter(configuration));
context.addFilter(wsufHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
server.start();
return server;
}
}});
// Embedded WSUF, added as filter, apply app-ws configuration via ServletContextListener
cases.add(new Object[]{"wsuf.configureContext/ServletContextListener configure", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
Server server = new Server();
ServerConnector connector = new ServerConnector(server);
connector.setPort(0);
server.addConnector(connector);
ServletContextHandler context = new ServletContextHandler();
context.setContextPath("/");
server.setHandler(context);
context.addFilter(WebSocketUpgradeFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST));
context.addEventListener(new InfoContextListener());
server.start();
return server;
}
}});
// WSUF from web.xml, SCI active, apply app-ws configuration via ServletContextListener
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/ServletContextListener", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
File testDir = getNewTestDir();
WSServer server = new WSServer(testDir, "/");
server.copyWebInf("wsuf-config-via-listener.xml");
server.copyClass(InfoSocket.class);
server.copyClass(InfoContextAttributeListener.class);
server.start();
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
return server.getServer();
}
}});
// WSUF from web.xml, SCI active, apply app-ws configuration via ServletContextListener with WEB-INF/lib/jetty-http.jar
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/ServletContextListener/jetty-http.jar", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
File testDir = getNewTestDir();
WSServer server = new WSServer(testDir, "/");
server.copyWebInf("wsuf-config-via-listener.xml");
server.copyClass(InfoSocket.class);
server.copyClass(InfoContextAttributeListener.class);
// Add a jetty-http.jar to ensure that the classloader constraints
// and the WebAppClassloader setup is sane and correct
// The odd version string is present to capture bad regex behavior in Jetty
server.copyLib(org.eclipse.jetty.http.pathmap.PathSpec.class, "jetty-http-9.99.999.jar");
server.start();
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
return server.getServer();
}
}});
// WSUF from web.xml, SCI active, apply app-ws configuration via Servlet.init
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/Servlet.init", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
File testDir = getNewTestDir();
WSServer server = new WSServer(testDir, "/");
server.copyWebInf("wsuf-config-via-servlet-init.xml");
server.copyClass(InfoSocket.class);
server.copyClass(InfoServlet.class);
server.start();
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
return server.getServer();
}
}});
// xml based, wsuf, on alternate url-pattern and config attribute location
cases.add(new Object[]{"wsuf/WebAppContext/web.xml/ServletContextListener/alt-config", new ServerProvider()
{
@Override
public Server newServer() throws Exception
{
File testDir = getNewTestDir();
WSServer server = new WSServer(testDir, "/");
server.copyWebInf("wsuf-alt-config-via-listener.xml");
server.copyClass(InfoSocket.class);
server.copyClass(InfoContextAltAttributeListener.class);
server.start();
WebAppContext webapp = server.createWebAppContext();
server.deployWebapp(webapp);
return server.getServer();
}
}});
return cases;
}
private final Server server;
private final URI serverUri;
public WebSocketUpgradeFilterTest(String testId, ServerProvider serverProvider) throws Exception
{
this.server = serverProvider.newServer();
ServerConnector connector = (ServerConnector) server.getConnectors()[0];
// Establish the Server URI
String host = connector.getHost();
if (host == null)
{
host = "localhost";
}
int port = connector.getLocalPort();
serverUri = new URI(String.format("ws://%s:%d/", host, port));
}
@Test
public void testNormalConfiguration() throws Exception
{
URI destUri = serverUri.resolve("/info/");
try (BlockheadClient client = new BlockheadClient(destUri))
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("hello"));
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1000, TimeUnit.MILLISECONDS);
String payload = frames.poll().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
assertThat("payload", payload, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
}
@Test
public void testStopStartOfHandler() throws Exception
{
URI destUri = serverUri.resolve("/info/");
try (BlockheadClient client = new BlockheadClient(destUri))
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("hello 1"));
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1000, TimeUnit.MILLISECONDS);
String payload = frames.poll().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
assertThat("payload", payload, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
server.getHandler().stop();
server.getHandler().start();
try (BlockheadClient client = new BlockheadClient(destUri))
{
client.connect();
client.sendStandardRequest();
client.expectUpgradeResponse();
client.write(new TextFrame().setPayload("hello 2"));
EventQueue<WebSocketFrame> frames = client.readFrames(1, 1000, TimeUnit.MILLISECONDS);
String payload = frames.poll().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
assertThat("payload", payload, containsString("session.maxTextMessageSize=" + (10 * 1024 * 1024)));
}
}
}