Merged branch 'jetty-10.0.x' into 'jetty-11.0.x'.
This commit is contained in:
commit
8a37363a3f
|
@ -1084,6 +1084,23 @@ public class ServletHandler extends ScopedHandler
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a preconstructed FilterHolder
|
||||
*
|
||||
* @param filter the filter holder
|
||||
*/
|
||||
public void prependFilter(FilterHolder filter)
|
||||
{
|
||||
if (filter == null)
|
||||
return;
|
||||
|
||||
try (AutoLock l = lock())
|
||||
{
|
||||
if (!containsFilterHolder(filter))
|
||||
setFilters(ArrayUtil.prependToArray(filter, getFilters(), FilterHolder.class));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method to add a preconstructed FilterMapping
|
||||
*
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
|||
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
|
||||
import org.eclipse.jetty.websocket.jakarta.server.internal.JakartaWebSocketServerContainer;
|
||||
import org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMappings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -153,7 +153,7 @@ public class JakartaWebSocketServletContainerInitializer implements ServletConta
|
|||
{
|
||||
WebSocketComponents components = WebSocketServerComponents.ensureWebSocketComponents(context.getServer(), context.getServletContext());
|
||||
FilterHolder filterHolder = WebSocketUpgradeFilter.ensureFilter(context.getServletContext());
|
||||
WebSocketMapping mapping = WebSocketMapping.ensureMapping(context.getServletContext(), WebSocketMapping.DEFAULT_KEY);
|
||||
WebSocketMappings mapping = WebSocketMappings.ensureMapping(context.getServletContext());
|
||||
serverContainer = JakartaWebSocketServerContainer.ensureContainer(context.getServletContext());
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
|
|
|
@ -43,7 +43,7 @@ import org.eclipse.jetty.websocket.jakarta.server.config.ContainerDefaultConfigu
|
|||
import org.eclipse.jetty.websocket.jakarta.server.config.JakartaWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.util.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMappings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -99,7 +99,7 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
|
||||
// Create the Jetty ServerContainer implementation
|
||||
container = new JakartaWebSocketServerContainer(
|
||||
WebSocketMapping.ensureMapping(servletContext, WebSocketMapping.DEFAULT_KEY),
|
||||
WebSocketMappings.ensureMapping(servletContext),
|
||||
WebSocketServerComponents.getWebSocketComponents(servletContext),
|
||||
coreClientSupplier);
|
||||
contextHandler.addManaged(container);
|
||||
|
@ -110,7 +110,7 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
return container;
|
||||
}
|
||||
|
||||
private final WebSocketMapping webSocketMapping;
|
||||
private final WebSocketMappings webSocketMappings;
|
||||
private final JakartaWebSocketServerFrameHandlerFactory frameHandlerFactory;
|
||||
private List<Class<?>> deferredEndpointClasses;
|
||||
private List<ServerEndpointConfig> deferredEndpointConfigs;
|
||||
|
@ -118,31 +118,31 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
/**
|
||||
* Main entry point for {@link JakartaWebSocketServletContainerInitializer}.
|
||||
*
|
||||
* @param webSocketMapping the {@link WebSocketMapping} that this container belongs to
|
||||
* @param webSocketMappings the {@link WebSocketMappings} that this container belongs to
|
||||
*/
|
||||
public JakartaWebSocketServerContainer(WebSocketMapping webSocketMapping)
|
||||
public JakartaWebSocketServerContainer(WebSocketMappings webSocketMappings)
|
||||
{
|
||||
this(webSocketMapping, new WebSocketComponents());
|
||||
this(webSocketMappings, new WebSocketComponents());
|
||||
}
|
||||
|
||||
public JakartaWebSocketServerContainer(WebSocketMapping webSocketMapping, WebSocketComponents components)
|
||||
public JakartaWebSocketServerContainer(WebSocketMappings webSocketMappings, WebSocketComponents components)
|
||||
{
|
||||
super(components);
|
||||
this.webSocketMapping = webSocketMapping;
|
||||
this.webSocketMappings = webSocketMappings;
|
||||
this.frameHandlerFactory = new JakartaWebSocketServerFrameHandlerFactory(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main entry point for {@link JakartaWebSocketServletContainerInitializer}.
|
||||
*
|
||||
* @param webSocketMapping the {@link WebSocketMapping} that this container belongs to
|
||||
* @param webSocketMappings the {@link WebSocketMappings} that this container belongs to
|
||||
* @param components the {@link WebSocketComponents} instance to use
|
||||
* @param coreClientSupplier the supplier of the {@link WebSocketCoreClient} instance to use
|
||||
*/
|
||||
public JakartaWebSocketServerContainer(WebSocketMapping webSocketMapping, WebSocketComponents components, Function<WebSocketComponents, WebSocketCoreClient> coreClientSupplier)
|
||||
public JakartaWebSocketServerContainer(WebSocketMappings webSocketMappings, WebSocketComponents components, Function<WebSocketComponents, WebSocketCoreClient> coreClientSupplier)
|
||||
{
|
||||
super(components, coreClientSupplier);
|
||||
this.webSocketMapping = webSocketMapping;
|
||||
this.webSocketMappings = webSocketMappings;
|
||||
this.frameHandlerFactory = new JakartaWebSocketServerFrameHandlerFactory(this);
|
||||
}
|
||||
|
||||
|
@ -265,7 +265,7 @@ public class JakartaWebSocketServerContainer extends JakartaWebSocketClientConta
|
|||
frameHandlerFactory.getMetadata(config.getEndpointClass(), config);
|
||||
JakartaWebSocketCreator creator = new JakartaWebSocketCreator(this, config, getExtensionRegistry());
|
||||
PathSpec pathSpec = new UriTemplatePathSpec(config.getPath());
|
||||
webSocketMapping.addMapping(pathSpec, creator, frameHandlerFactory, defaultCustomizer);
|
||||
webSocketMappings.addMapping(pathSpec, creator, frameHandlerFactory, defaultCustomizer);
|
||||
}
|
||||
catch (InvalidSignatureException e)
|
||||
{
|
||||
|
|
|
@ -61,7 +61,7 @@ public class AltFilterTest
|
|||
{
|
||||
wsb.start();
|
||||
|
||||
FilterHolder filterWebXml = app.getWebAppContext().getServletHandler().getFilter("wsuf-test");
|
||||
FilterHolder filterWebXml = app.getWebAppContext().getServletHandler().getFilter(WebSocketUpgradeFilter.class.getName());
|
||||
assertThat("Filter[wsuf-test]", filterWebXml, notNullValue());
|
||||
|
||||
FilterHolder filterSCI = app.getWebAppContext().getServletHandler().getFilter("Jetty_WebSocketUpgradeFilter");
|
||||
|
|
|
@ -12,16 +12,12 @@
|
|||
</context-param>
|
||||
|
||||
<filter>
|
||||
<filter-name>wsuf-test</filter-name>
|
||||
<filter-name>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-name>
|
||||
<filter-class>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>jetty.websocket.WebSocketMapping</param-name>
|
||||
<param-value>jetty.websocket.defaultMapping</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
|
||||
<filter-mapping>
|
||||
<filter-name>wsuf-test</filter-name>
|
||||
<filter-name>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-name>
|
||||
<url-pattern>/echo/*</url-pattern>
|
||||
</filter-mapping>
|
||||
</web-app>
|
||||
|
|
|
@ -47,7 +47,7 @@ import org.eclipse.jetty.websocket.server.internal.JettyServerFrameHandlerFactor
|
|||
import org.eclipse.jetty.websocket.util.ReflectUtils;
|
||||
import org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.FrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMappings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -77,7 +77,7 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
// Create the Jetty ServerContainer implementation
|
||||
container = new JettyWebSocketServerContainer(
|
||||
contextHandler,
|
||||
WebSocketMapping.ensureMapping(servletContext, WebSocketMapping.DEFAULT_KEY),
|
||||
WebSocketMappings.ensureMapping(servletContext),
|
||||
WebSocketServerComponents.getWebSocketComponents(servletContext), executor);
|
||||
servletContext.setAttribute(JETTY_WEBSOCKET_CONTAINER_ATTRIBUTE, container);
|
||||
contextHandler.addManaged(container);
|
||||
|
@ -90,7 +90,7 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
private static final Logger LOG = LoggerFactory.getLogger(JettyWebSocketServerContainer.class);
|
||||
|
||||
private final ServletContextHandler contextHandler;
|
||||
private final WebSocketMapping webSocketMapping;
|
||||
private final WebSocketMappings webSocketMappings;
|
||||
private final WebSocketComponents components;
|
||||
private final FrameHandlerFactory frameHandlerFactory;
|
||||
private final Executor executor;
|
||||
|
@ -102,14 +102,14 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
/**
|
||||
* Main entry point for {@link JettyWebSocketServletContainerInitializer}.
|
||||
*
|
||||
* @param webSocketMapping the {@link WebSocketMapping} that this container belongs to
|
||||
* @param webSocketMappings the {@link WebSocketMappings} that this container belongs to
|
||||
* @param components the {@link WebSocketComponents} instance to use
|
||||
* @param executor the {@link Executor} to use
|
||||
*/
|
||||
JettyWebSocketServerContainer(ServletContextHandler contextHandler, WebSocketMapping webSocketMapping, WebSocketComponents components, Executor executor)
|
||||
JettyWebSocketServerContainer(ServletContextHandler contextHandler, WebSocketMappings webSocketMappings, WebSocketComponents components, Executor executor)
|
||||
{
|
||||
this.contextHandler = contextHandler;
|
||||
this.webSocketMapping = webSocketMapping;
|
||||
this.webSocketMappings = webSocketMappings;
|
||||
this.executor = executor;
|
||||
this.components = components;
|
||||
|
||||
|
@ -129,12 +129,12 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
|
||||
public void addMapping(String pathSpec, JettyWebSocketCreator creator)
|
||||
{
|
||||
PathSpec ps = WebSocketMapping.parsePathSpec(pathSpec);
|
||||
if (webSocketMapping.getMapping(ps) != null)
|
||||
PathSpec ps = WebSocketMappings.parsePathSpec(pathSpec);
|
||||
if (webSocketMappings.getMapping(ps) != null)
|
||||
throw new WebSocketException("Duplicate WebSocket Mapping for PathSpec");
|
||||
|
||||
WebSocketUpgradeFilter.ensureFilter(contextHandler.getServletContext());
|
||||
webSocketMapping.addMapping(ps,
|
||||
webSocketMappings.addMapping(ps,
|
||||
(req, resp) -> creator.createWebSocket(new DelegatedServerUpgradeRequest(req), new DelegatedServerUpgradeResponse(resp)),
|
||||
frameHandlerFactory, customizer);
|
||||
}
|
||||
|
|
|
@ -40,14 +40,14 @@ import org.eclipse.jetty.websocket.util.server.internal.FrameHandlerFactory;
|
|||
import org.eclipse.jetty.websocket.util.server.internal.ServerUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.ServerUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMappings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Abstract Servlet used to bridge the Servlet API to the WebSocket API.
|
||||
* <p>
|
||||
* To use this servlet, you will be required to register your websockets with the {@link WebSocketMapping} so that it can create your websockets under the
|
||||
* To use this servlet, you will be required to register your websockets with the {@link WebSocketMappings} so that it can create your websockets under the
|
||||
* appropriate conditions.
|
||||
* </p>
|
||||
* <p>The most basic implementation would be as follows:</p>
|
||||
|
@ -68,11 +68,11 @@ import org.slf4j.LoggerFactory;
|
|||
* }
|
||||
* </pre>
|
||||
* <p>
|
||||
* Only request that conforms to a "WebSocket: Upgrade" handshake request will trigger the {@link WebSocketMapping} handling of creating
|
||||
* Only request that conforms to a "WebSocket: Upgrade" handshake request will trigger the {@link WebSocketMappings} handling of creating
|
||||
* WebSockets. All other requests are treated as normal servlet requests. The configuration defined by this servlet init parameters will
|
||||
* be used as the customizer for any mappings created by {@link JettyWebSocketServletFactory#addMapping(String, JettyWebSocketCreator)} during
|
||||
* {@link #configure(JettyWebSocketServletFactory)} calls. The request upgrade may be peformed by this servlet, or is may be performed by a
|
||||
* {@link WebSocketUpgradeFilter} instance that will share the same {@link WebSocketMapping} instance. If the filter is used, then the
|
||||
* {@link WebSocketUpgradeFilter} instance that will share the same {@link WebSocketMappings} instance. If the filter is used, then the
|
||||
* filter configuraton is used as the default configuration prior to this servlets configuration being applied.
|
||||
* </p>
|
||||
* <p>
|
||||
|
@ -99,7 +99,7 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
private static final Logger LOG = LoggerFactory.getLogger(JettyWebSocketServlet.class);
|
||||
private final CustomizedWebSocketServletFactory customizer = new CustomizedWebSocketServletFactory();
|
||||
|
||||
private WebSocketMapping mapping;
|
||||
private WebSocketMappings mapping;
|
||||
private WebSocketComponents components;
|
||||
|
||||
/**
|
||||
|
@ -133,7 +133,7 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
ServletContext servletContext = getServletContext();
|
||||
|
||||
components = WebSocketServerComponents.getWebSocketComponents(servletContext);
|
||||
mapping = new WebSocketMapping(components);
|
||||
mapping = new WebSocketMappings(components);
|
||||
|
||||
String max = getInitParameter("idleTimeout");
|
||||
if (max == null)
|
||||
|
@ -208,7 +208,7 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
@Override
|
||||
public void addMapping(String pathSpec, JettyWebSocketCreator creator)
|
||||
{
|
||||
mapping.addMapping(WebSocketMapping.parsePathSpec(pathSpec), new WrappedJettyCreator(creator), getFactory(), this);
|
||||
mapping.addMapping(WebSocketMappings.parsePathSpec(pathSpec), new WrappedJettyCreator(creator), getFactory(), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -249,7 +249,7 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
@Override
|
||||
public JettyWebSocketCreator getMapping(String pathSpec)
|
||||
{
|
||||
WebSocketCreator creator = mapping.getMapping(WebSocketMapping.parsePathSpec(pathSpec));
|
||||
WebSocketCreator creator = mapping.getMapping(WebSocketMappings.parsePathSpec(pathSpec));
|
||||
if (creator instanceof WrappedJettyCreator)
|
||||
return ((WrappedJettyCreator)creator).getJettyWebSocketCreator();
|
||||
|
||||
|
@ -259,7 +259,7 @@ public abstract class JettyWebSocketServlet extends HttpServlet
|
|||
@Override
|
||||
public boolean removeMapping(String pathSpec)
|
||||
{
|
||||
return mapping.removeMapping(WebSocketMapping.parsePathSpec(pathSpec));
|
||||
return mapping.removeMapping(WebSocketMappings.parsePathSpec(pathSpec));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.eclipse.jetty.servlet.listener.ContainerInitializer;
|
|||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMappings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -48,7 +48,7 @@ public class JettyWebSocketServletContainerInitializer implements ServletContain
|
|||
* during the {@link ServletContext} initialization phase.
|
||||
*
|
||||
* @param context the context to add listener to.
|
||||
* @param configurator a lambda that is called to allow the {@link WebSocketMapping} to
|
||||
* @param configurator a lambda that is called to allow the {@link WebSocketMappings} to
|
||||
* be configured during {@link ServletContext} initialization phase
|
||||
*/
|
||||
public static void configure(ServletContextHandler context, Configurator configurator)
|
||||
|
|
|
@ -18,29 +18,50 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.tests;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import jakarta.servlet.DispatcherType;
|
||||
import jakarta.servlet.FilterConfig;
|
||||
import jakarta.servlet.ServletContextEvent;
|
||||
import jakarta.servlet.ServletContextListener;
|
||||
import jakarta.servlet.ServletException;
|
||||
import jakarta.servlet.annotation.WebListener;
|
||||
import jakarta.servlet.http.HttpServlet;
|
||||
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.servlet.ServletHolder;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.component.AbstractLifeCycle;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketConstants;
|
||||
import org.eclipse.jetty.websocket.server.JettyWebSocketServerContainer;
|
||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketServletContainerInitializer;
|
||||
import org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.instanceOf;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
public class JettyWebSocketFilterTest
|
||||
|
@ -50,6 +71,16 @@ public class JettyWebSocketFilterTest
|
|||
private WebSocketClient client;
|
||||
private ServletContextHandler contextHandler;
|
||||
|
||||
@BeforeEach
|
||||
public void before()
|
||||
{
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
client = new WebSocketClient();
|
||||
}
|
||||
|
||||
public void start(JettyWebSocketServletContainerInitializer.Configurator configurator) throws Exception
|
||||
{
|
||||
start(configurator, null);
|
||||
|
@ -62,20 +93,14 @@ public class JettyWebSocketFilterTest
|
|||
|
||||
public void start(JettyWebSocketServletContainerInitializer.Configurator configurator, ServletHolder servletHolder) throws Exception
|
||||
{
|
||||
server = new Server();
|
||||
connector = new ServerConnector(server);
|
||||
server.addConnector(connector);
|
||||
|
||||
contextHandler = new ServletContextHandler(ServletContextHandler.SESSIONS);
|
||||
contextHandler.setContextPath("/");
|
||||
if (servletHolder != null)
|
||||
contextHandler.addServlet(servletHolder, "/");
|
||||
server.setHandler(contextHandler);
|
||||
|
||||
JettyWebSocketServletContainerInitializer.configure(contextHandler, configurator);
|
||||
server.start();
|
||||
|
||||
client = new WebSocketClient();
|
||||
server.start();
|
||||
client.start();
|
||||
}
|
||||
|
||||
|
@ -93,7 +118,7 @@ public class JettyWebSocketFilterTest
|
|||
|
||||
// After mapping is added we have an UpgradeFilter.
|
||||
assertThat(contextHandler.getServletHandler().getFilters().length, is(1));
|
||||
FilterHolder filterHolder = contextHandler.getServletHandler().getFilter("WebSocketUpgradeFilter");
|
||||
FilterHolder filterHolder = contextHandler.getServletHandler().getFilter(WebSocketUpgradeFilter.class.getName());
|
||||
assertNotNull(filterHolder);
|
||||
assertThat(filterHolder.getState(), is(AbstractLifeCycle.STARTED));
|
||||
assertThat(filterHolder.getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
|
@ -127,7 +152,7 @@ public class JettyWebSocketFilterTest
|
|||
// After mapping is added we have an UpgradeFilter.
|
||||
container.addMapping("/", EchoSocket.class);
|
||||
assertThat(contextHandler.getServletHandler().getFilters().length, is(1));
|
||||
FilterHolder filterHolder = contextHandler.getServletHandler().getFilter("WebSocketUpgradeFilter");
|
||||
FilterHolder filterHolder = contextHandler.getServletHandler().getFilter(WebSocketUpgradeFilter.class.getName());
|
||||
assertNotNull(filterHolder);
|
||||
assertThat(filterHolder.getState(), is(AbstractLifeCycle.STARTED));
|
||||
assertThat(filterHolder.getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
|
@ -164,7 +189,7 @@ public class JettyWebSocketFilterTest
|
|||
|
||||
// After mapping is added we have an UpgradeFilter.
|
||||
assertThat(contextHandler.getServletHandler().getFilters().length, is(1));
|
||||
FilterHolder filterHolder = contextHandler.getServletHandler().getFilter("WebSocketUpgradeFilter");
|
||||
FilterHolder filterHolder = contextHandler.getServletHandler().getFilter(WebSocketUpgradeFilter.class.getName());
|
||||
assertNotNull(filterHolder);
|
||||
assertThat(filterHolder.getState(), is(AbstractLifeCycle.STARTED));
|
||||
assertThat(filterHolder.getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
|
@ -182,4 +207,233 @@ public class JettyWebSocketFilterTest
|
|||
String msg = socket.textMessages.poll();
|
||||
assertThat(msg, is("hello world"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleWebSocketUpgradeFilter() throws Exception
|
||||
{
|
||||
String idleTimeoutFilter1 = "4999";
|
||||
String idleTimeoutFilter2 = "3999";
|
||||
start((context, container) ->
|
||||
{
|
||||
ServletContextHandler contextHandler = Objects.requireNonNull(ServletContextHandler.getServletContextHandler(context));
|
||||
|
||||
// This filter replaces the default filter as we use the pre-defined name.
|
||||
FilterHolder filterHolder = new FilterHolder(WebSocketUpgradeFilter.class);
|
||||
filterHolder.setName(WebSocketUpgradeFilter.class.getName());
|
||||
filterHolder.setInitParameter("idleTimeout", idleTimeoutFilter1);
|
||||
contextHandler.addFilter(filterHolder, "/primaryFilter/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
// This is an additional filter.
|
||||
filterHolder = new FilterHolder(WebSocketUpgradeFilter.class);
|
||||
filterHolder.setName("Secondary Upgrade Filter");
|
||||
filterHolder.setInitParameter("idleTimeout", idleTimeoutFilter2);
|
||||
contextHandler.addFilter(filterHolder, "/secondaryFilter/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
// Add mappings to the server container (same WebSocketMappings is referenced by both upgrade filters).
|
||||
container.addMapping("/echo", EchoSocket.class);
|
||||
container.addMapping("/primaryFilter/echo", LowerCaseEchoSocket.class);
|
||||
container.addMapping("/secondaryFilter/echo", UpperCaseEchoSocket.class);
|
||||
});
|
||||
|
||||
// Verify we have manually added 2 WebSocketUpgrade Filters.
|
||||
List<FilterHolder> upgradeFilters = Arrays.stream(contextHandler.getServletHandler().getFilters())
|
||||
.filter(holder -> holder.getFilter() instanceof WebSocketUpgradeFilter)
|
||||
.collect(Collectors.toList());
|
||||
assertThat(contextHandler.getServletHandler().getFilters().length, is(2));
|
||||
assertThat(upgradeFilters.size(), is(2));
|
||||
for (FilterHolder filterHolder : upgradeFilters)
|
||||
{
|
||||
assertThat(filterHolder.getState(), is(AbstractLifeCycle.STARTED));
|
||||
assertThat(filterHolder.getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
}
|
||||
|
||||
// The /echo path should not match either of the upgrade filters even though it has a valid mapping, we get 404 response.
|
||||
URI firstUri = URI.create("ws://localhost:" + connector.getLocalPort() + "/echo");
|
||||
ExecutionException error = assertThrows(ExecutionException.class, () -> client.connect(new EventSocket(), firstUri).get(5, TimeUnit.SECONDS));
|
||||
assertThat(error.getMessage(), containsString("404 Not Found"));
|
||||
|
||||
// The /primaryFilter/echo path should convert to lower case and have idleTimeout configured on the first upgradeFilter.
|
||||
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/primaryFilter/echo");
|
||||
EventSocket socket = new EventSocket();
|
||||
CompletableFuture<Session> connect = client.connect(socket, uri);
|
||||
try (Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hElLo wOrLd");
|
||||
session.getRemote().sendString("getIdleTimeout");
|
||||
}
|
||||
assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(socket.textMessages.poll(), is("hello world"));
|
||||
assertThat(socket.textMessages.poll(), is(idleTimeoutFilter1));
|
||||
|
||||
// The /secondaryFilter/echo path should convert to upper case and have idleTimeout configured on the second upgradeFilter.
|
||||
uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/secondaryFilter/echo");
|
||||
socket = new EventSocket();
|
||||
connect = client.connect(socket, uri);
|
||||
try (Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hElLo wOrLd");
|
||||
session.getRemote().sendString("getIdleTimeout");
|
||||
}
|
||||
assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(socket.textMessages.poll(), is("HELLO WORLD"));
|
||||
assertThat(socket.textMessages.poll(), is(idleTimeoutFilter2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomUpgradeFilter() throws Exception
|
||||
{
|
||||
start((context, container) ->
|
||||
{
|
||||
ServletContextHandler contextHandler = Objects.requireNonNull(ServletContextHandler.getServletContextHandler(context));
|
||||
|
||||
// This custom filter replaces the default filter as we use the pre-defined name, and adds mapping in init().
|
||||
FilterHolder filterHolder = new FilterHolder(MyUpgradeFilter.class);
|
||||
filterHolder.setName(WebSocketUpgradeFilter.class.getName());
|
||||
contextHandler.addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST));
|
||||
});
|
||||
|
||||
FilterHolder[] holders = contextHandler.getServletHandler().getFilters();
|
||||
assertThat(holders.length, is(1));
|
||||
assertThat(holders[0].getFilter(), instanceOf(MyUpgradeFilter.class));
|
||||
|
||||
// We can reach the echo endpoint and get correct response.
|
||||
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + "/echo");
|
||||
EventSocket socket = new EventSocket();
|
||||
CompletableFuture<Session> connect = client.connect(socket, uri);
|
||||
try (Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hElLo wOrLd");
|
||||
}
|
||||
assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(socket.textMessages.poll(), is("hElLo wOrLd"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultWebSocketUpgradeFilterOrdering() throws Exception
|
||||
{
|
||||
String defaultIdleTimeout = Long.toString(WebSocketConstants.DEFAULT_IDLE_TIMEOUT.toMillis());
|
||||
JettyWebSocketWebApp webApp = new JettyWebSocketWebApp("wsuf-ordering1");
|
||||
Path webXml = MavenTestingUtils.getTestResourcePath("wsuf-ordering1.xml");
|
||||
webApp.copyWebXml(webXml);
|
||||
webApp.copyClass(WebSocketEchoServletContextListener.class);
|
||||
webApp.copyClass(WebSocketEchoServletContextListener.EchoSocket.class);
|
||||
|
||||
server.setHandler(webApp);
|
||||
server.start();
|
||||
client.start();
|
||||
|
||||
// We have both websocket upgrade filters installed.
|
||||
FilterHolder[] filterHolders = webApp.getServletHandler().getFilters();
|
||||
assertThat(filterHolders.length, is(2));
|
||||
assertThat(filterHolders[0].getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
assertThat(filterHolders[1].getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
|
||||
// The custom filter defined in web.xml should be first in line so it will do the upgrade.
|
||||
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + webApp.getContextPath() + "/echo");
|
||||
EventSocket socket = new EventSocket();
|
||||
CompletableFuture<Session> connect = client.connect(socket, uri);
|
||||
try (Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hello world");
|
||||
session.getRemote().sendString("getIdleTimeout");
|
||||
}
|
||||
assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(socket.textMessages.poll(), is("hello world"));
|
||||
assertThat(socket.textMessages.poll(), is(defaultIdleTimeout));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWebSocketUpgradeFilterOrdering() throws Exception
|
||||
{
|
||||
String timeoutFromAltFilter = "5999";
|
||||
JettyWebSocketWebApp webApp = new JettyWebSocketWebApp("wsuf-ordering2");
|
||||
Path webXml = MavenTestingUtils.getTestResourcePath("wsuf-ordering2.xml");
|
||||
webApp.copyWebXml(webXml);
|
||||
webApp.copyClass(WebSocketEchoServletContextListener.class);
|
||||
webApp.copyClass(WebSocketEchoServletContextListener.EchoSocket.class);
|
||||
|
||||
server.setHandler(webApp);
|
||||
server.start();
|
||||
client.start();
|
||||
|
||||
// We have both websocket upgrade filters installed.
|
||||
FilterHolder[] filterHolders = webApp.getServletHandler().getFilters();
|
||||
assertThat(filterHolders.length, is(2));
|
||||
assertThat(filterHolders[0].getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
assertThat(filterHolders[1].getFilter(), instanceOf(WebSocketUpgradeFilter.class));
|
||||
|
||||
// The custom filter defined in web.xml should be first in line so it will do the upgrade.
|
||||
URI uri = URI.create("ws://localhost:" + connector.getLocalPort() + webApp.getContextPath() + "/echo");
|
||||
EventSocket socket = new EventSocket();
|
||||
CompletableFuture<Session> connect = client.connect(socket, uri);
|
||||
try (Session session = connect.get(5, TimeUnit.SECONDS))
|
||||
{
|
||||
session.getRemote().sendString("hello world");
|
||||
session.getRemote().sendString("getIdleTimeout");
|
||||
}
|
||||
assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS));
|
||||
assertThat(socket.textMessages.poll(), is("hello world"));
|
||||
assertThat(socket.textMessages.poll(), is(timeoutFromAltFilter));
|
||||
}
|
||||
|
||||
@WebListener
|
||||
public static class WebSocketEchoServletContextListener implements ServletContextListener
|
||||
{
|
||||
@Override
|
||||
public void contextInitialized(ServletContextEvent sce)
|
||||
{
|
||||
JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(sce.getServletContext());
|
||||
container.addMapping("/echo", EchoSocket.class);
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class EchoSocket
|
||||
{
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(Session session, String message) throws IOException
|
||||
{
|
||||
if ("getIdleTimeout".equals(message))
|
||||
session.getRemote().sendString(Long.toString(session.getIdleTimeout().toMillis()));
|
||||
else
|
||||
session.getRemote().sendString(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class MyUpgradeFilter extends WebSocketUpgradeFilter
|
||||
{
|
||||
@Override
|
||||
public void init(FilterConfig config) throws ServletException
|
||||
{
|
||||
JettyWebSocketServerContainer container = JettyWebSocketServerContainer.getContainer(config.getServletContext());
|
||||
container.addMapping("/echo", EchoSocket.class);
|
||||
super.init(config);
|
||||
}
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class LowerCaseEchoSocket
|
||||
{
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(Session session, String message) throws IOException
|
||||
{
|
||||
if ("getIdleTimeout".equals(message))
|
||||
session.getRemote().sendString(Long.toString(session.getIdleTimeout().toMillis()));
|
||||
else
|
||||
session.getRemote().sendString(message.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@WebSocket
|
||||
public static class UpperCaseEchoSocket
|
||||
{
|
||||
@OnWebSocketMessage
|
||||
public void onMessage(Session session, String message) throws IOException
|
||||
{
|
||||
if ("getIdleTimeout".equals(message))
|
||||
session.getRemote().sendString(Long.toString(session.getIdleTimeout().toMillis()));
|
||||
else
|
||||
session.getRemote().sendString(message.toUpperCase());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under
|
||||
// the terms of the Eclipse Public License 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// This Source Code may also be made available under the following
|
||||
// Secondary Licenses when the conditions for such availability set
|
||||
// forth in the Eclipse Public License, v. 2.0 are satisfied:
|
||||
// the Apache License v2.0 which is available at
|
||||
// https://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.tests;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.FS;
|
||||
import org.eclipse.jetty.toolchain.test.IO;
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.util.TypeUtil;
|
||||
import org.eclipse.jetty.util.resource.PathResource;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.server.config.JettyWebSocketConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
public class JettyWebSocketWebApp extends WebAppContext
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(JettyWebSocketWebApp.class);
|
||||
|
||||
private final Path contextDir;
|
||||
private final Path webInf;
|
||||
private final Path classesDir;
|
||||
|
||||
public JettyWebSocketWebApp(String contextName)
|
||||
{
|
||||
// Ensure context directory.
|
||||
Path testDir = MavenTestingUtils.getTargetTestingPath(JettyWebSocketWebApp.class.getName());
|
||||
contextDir = testDir.resolve(contextName);
|
||||
FS.ensureEmpty(contextDir);
|
||||
|
||||
// Ensure WEB-INF directories.
|
||||
webInf = contextDir.resolve("WEB-INF");
|
||||
FS.ensureDirExists(webInf);
|
||||
classesDir = webInf.resolve("classes");
|
||||
FS.ensureDirExists(classesDir);
|
||||
|
||||
// Configure the WebAppContext.
|
||||
setContextPath("/" + contextName);
|
||||
setBaseResource(new PathResource(contextDir));
|
||||
addConfiguration(new JettyWebSocketConfiguration());
|
||||
}
|
||||
|
||||
public Path getContextDir()
|
||||
{
|
||||
return contextDir;
|
||||
}
|
||||
|
||||
public void createWebXml() throws IOException
|
||||
{
|
||||
String emptyWebXml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" +
|
||||
"<web-app xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://java.sun.com/xml/ns/javaee\" " +
|
||||
"xsi:schemaLocation=\"http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd\" " +
|
||||
"metadata-complete=\"false\" version=\"3.0\"></web-app>";
|
||||
|
||||
Path webXml = webInf.resolve("web.xml");
|
||||
try (FileWriter writer = new FileWriter(webXml.toFile()))
|
||||
{
|
||||
writer.write(emptyWebXml);
|
||||
}
|
||||
}
|
||||
|
||||
public void copyWebXml(Path webXml) throws IOException
|
||||
{
|
||||
IO.copy(webXml.toFile(), webInf.resolve("web.xml").toFile());
|
||||
}
|
||||
|
||||
public void copyClass(Class<?> clazz) throws Exception
|
||||
{
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
String endpointPath = TypeUtil.toClassReference(clazz);
|
||||
URL classUrl = cl.getResource(endpointPath);
|
||||
assertThat("Class URL for: " + clazz, classUrl, notNullValue());
|
||||
Path destFile = classesDir.resolve(endpointPath);
|
||||
FS.ensureDirExists(destFile.getParent());
|
||||
File srcFile = new File(classUrl.toURI());
|
||||
IO.copy(srcFile, destFile.toFile());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app
|
||||
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||
metadata-complete="false"
|
||||
version="4.0">
|
||||
|
||||
<filter>
|
||||
<filter-name>wsuf-alt</filter-name>
|
||||
<filter-class>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>idleTimeout</param-name>
|
||||
<param-value>5999</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>wsuf-alt</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
</web-app>
|
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app
|
||||
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||
metadata-complete="false"
|
||||
version="4.0">
|
||||
|
||||
<!-- Add the custom filter first. -->
|
||||
<filter>
|
||||
<filter-name>wsuf-alt</filter-name>
|
||||
<filter-class>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-class>
|
||||
<init-param>
|
||||
<param-name>idleTimeout</param-name>
|
||||
<param-value>5999</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>wsuf-alt</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
<!-- The default filter is overridden so it is tried after. -->
|
||||
<filter>
|
||||
<filter-name>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-name>
|
||||
<filter-class>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-class>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
</web-app>
|
|
@ -35,12 +35,13 @@ import jakarta.servlet.http.HttpServletRequest;
|
|||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.FilterHolder;
|
||||
import org.eclipse.jetty.servlet.FilterMapping;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.util.component.Dumpable;
|
||||
import org.eclipse.jetty.util.thread.AutoLock;
|
||||
import org.eclipse.jetty.websocket.core.Configuration;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping;
|
||||
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMappings;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
@ -49,7 +50,7 @@ import org.slf4j.LoggerFactory;
|
|||
* <p>
|
||||
* The configuration applied to this filter via init params will be used as the the default
|
||||
* configuration of any websocket upgraded by this filter, prior to the configuration of the
|
||||
* websocket applied by the {@link WebSocketMapping}.
|
||||
* websocket applied by the {@link WebSocketMappings}.
|
||||
* </p>
|
||||
* <p>
|
||||
* <b>Configuration / Init-Parameters:</b>
|
||||
|
@ -78,26 +79,16 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
private static final AutoLock LOCK = new AutoLock();
|
||||
|
||||
/**
|
||||
* The init parameter name used to define {@link ServletContext} attribute used to share the {@link WebSocketMapping}.
|
||||
*/
|
||||
public static final String MAPPING_ATTRIBUTE_INIT_PARAM = "jetty.websocket.WebSocketMapping";
|
||||
|
||||
/**
|
||||
* Return any {@link WebSocketUpgradeFilter} already present on the {@link ServletContext}.
|
||||
* Return the default {@link WebSocketUpgradeFilter} if present on the {@link ServletContext}.
|
||||
*
|
||||
* @param servletContext the {@link ServletContext} to use.
|
||||
* @return the configured default {@link WebSocketUpgradeFilter} instance.
|
||||
*/
|
||||
private static FilterHolder getFilter(ServletContext servletContext)
|
||||
public static FilterHolder getFilter(ServletContext servletContext)
|
||||
{
|
||||
ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext));
|
||||
ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class);
|
||||
for (FilterHolder holder : servletHandler.getFilters())
|
||||
{
|
||||
if (holder.getInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM) != null)
|
||||
return holder;
|
||||
}
|
||||
return null;
|
||||
return servletHandler.getFilter(WebSocketUpgradeFilter.class.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -120,16 +111,23 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
if (existingFilter != null)
|
||||
return existingFilter;
|
||||
|
||||
final String name = "WebSocketUpgradeFilter";
|
||||
final String pathSpec = "/*";
|
||||
FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter());
|
||||
holder.setName(name);
|
||||
holder.setInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM, WebSocketMapping.DEFAULT_KEY);
|
||||
|
||||
holder.setAsyncSupported(true);
|
||||
ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext));
|
||||
ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class);
|
||||
servletHandler.addFilterWithMapping(holder, pathSpec, EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
final String pathSpec = "/*";
|
||||
FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter());
|
||||
holder.setName(WebSocketUpgradeFilter.class.getName());
|
||||
holder.setAsyncSupported(true);
|
||||
|
||||
FilterMapping mapping = new FilterMapping();
|
||||
mapping.setFilterName(holder.getName());
|
||||
mapping.setPathSpec(pathSpec);
|
||||
mapping.setDispatcherTypes(EnumSet.of(DispatcherType.REQUEST));
|
||||
|
||||
// Add the default WebSocketUpgradeFilter as the first filter in the list.
|
||||
servletHandler.prependFilter(holder);
|
||||
servletHandler.prependFilterMapping(mapping);
|
||||
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Adding {} mapped to {} in {}", holder, pathSpec, servletContext);
|
||||
return holder;
|
||||
|
@ -137,7 +135,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
}
|
||||
|
||||
private final Configuration.ConfigurationCustomizer defaultCustomizer = new Configuration.ConfigurationCustomizer();
|
||||
private WebSocketMapping mapping;
|
||||
private WebSocketMappings mapping;
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
|
||||
|
@ -173,12 +171,7 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
|
|||
@Override
|
||||
public void init(FilterConfig config) throws ServletException
|
||||
{
|
||||
final ServletContext context = config.getServletContext();
|
||||
|
||||
String mappingKey = config.getInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM);
|
||||
if (mappingKey == null)
|
||||
throw new ServletException("the WebSocketMapping init param must be set");
|
||||
mapping = WebSocketMapping.ensureMapping(context, mappingKey);
|
||||
mapping = WebSocketMappings.ensureMapping(config.getServletContext());
|
||||
|
||||
String max = config.getInitParameter("idleTimeout");
|
||||
if (max == null)
|
||||
|
|
|
@ -56,24 +56,14 @@ import org.slf4j.LoggerFactory;
|
|||
* wrap that POJO with a {@link FrameHandler} and the customizer is used to configure the resulting
|
||||
* {@link CoreSession}.</p>
|
||||
*/
|
||||
public class WebSocketMapping implements Dumpable, LifeCycle.Listener
|
||||
public class WebSocketMappings implements Dumpable, LifeCycle.Listener
|
||||
{
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebSocketMapping.class);
|
||||
private static final Logger LOG = LoggerFactory.getLogger(WebSocketMappings.class);
|
||||
public static final String WEBSOCKET_MAPPING_ATTRIBUTE = WebSocketMappings.class.getName();
|
||||
|
||||
public static WebSocketMapping getMapping(ServletContext servletContext, String mappingKey)
|
||||
public static WebSocketMappings getMapping(ServletContext servletContext)
|
||||
{
|
||||
Object mappingObject = servletContext.getAttribute(mappingKey);
|
||||
if (mappingObject != null)
|
||||
{
|
||||
if (mappingObject instanceof WebSocketMapping)
|
||||
return (WebSocketMapping)mappingObject;
|
||||
else
|
||||
throw new IllegalStateException(
|
||||
String.format("ContextHandler attribute %s is not of type WebSocketMapping: {%s}",
|
||||
mappingKey, mappingObject.toString()));
|
||||
}
|
||||
|
||||
return null;
|
||||
return (WebSocketMappings)servletContext.getAttribute(WEBSOCKET_MAPPING_ATTRIBUTE);
|
||||
}
|
||||
|
||||
public WebSocketCreator getMapping(PathSpec pathSpec)
|
||||
|
@ -82,13 +72,13 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener
|
|||
return cn == null ? null : cn.getWebSocketCreator();
|
||||
}
|
||||
|
||||
public static WebSocketMapping ensureMapping(ServletContext servletContext, String mappingKey)
|
||||
public static WebSocketMappings ensureMapping(ServletContext servletContext)
|
||||
{
|
||||
WebSocketMapping mapping = getMapping(servletContext, mappingKey);
|
||||
WebSocketMappings mapping = getMapping(servletContext);
|
||||
if (mapping == null)
|
||||
{
|
||||
mapping = new WebSocketMapping(WebSocketServerComponents.getWebSocketComponents(servletContext));
|
||||
servletContext.setAttribute(mappingKey, mapping);
|
||||
mapping = new WebSocketMappings(WebSocketServerComponents.getWebSocketComponents(servletContext));
|
||||
servletContext.setAttribute(WEBSOCKET_MAPPING_ATTRIBUTE, mapping);
|
||||
}
|
||||
|
||||
return mapping;
|
||||
|
@ -133,18 +123,16 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener
|
|||
throw new IllegalArgumentException("Unrecognized path spec syntax [" + rawSpec + "]");
|
||||
}
|
||||
|
||||
public static final String DEFAULT_KEY = "jetty.websocket.defaultMapping";
|
||||
|
||||
private final PathMappings<Negotiator> mappings = new PathMappings<>();
|
||||
private final WebSocketComponents components;
|
||||
private final Handshaker handshaker = Handshaker.newInstance();
|
||||
|
||||
public WebSocketMapping()
|
||||
public WebSocketMappings()
|
||||
{
|
||||
this(new WebSocketComponents());
|
||||
}
|
||||
|
||||
public WebSocketMapping(WebSocketComponents components)
|
||||
public WebSocketMappings(WebSocketComponents components)
|
||||
{
|
||||
this.components = components;
|
||||
}
|
||||
|
@ -153,7 +141,7 @@ public class WebSocketMapping implements Dumpable, LifeCycle.Listener
|
|||
public void lifeCycleStopping(LifeCycle context)
|
||||
{
|
||||
ContextHandler contextHandler = (ContextHandler)context;
|
||||
WebSocketMapping mapping = contextHandler.getBean(WebSocketMapping.class);
|
||||
WebSocketMappings mapping = contextHandler.getBean(WebSocketMappings.class);
|
||||
if (mapping == this)
|
||||
{
|
||||
contextHandler.removeBean(mapping);
|
Loading…
Reference in New Issue