diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 2ff3d49ce43c..2fb88531318a 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -1084,6 +1084,23 @@ public void addFilter(FilterHolder filter) } } + /** + * 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 * diff --git a/jetty-websocket/websocket-jakarta-server/src/main/java/org/eclipse/jetty/websocket/jakarta/server/config/JakartaWebSocketServletContainerInitializer.java b/jetty-websocket/websocket-jakarta-server/src/main/java/org/eclipse/jetty/websocket/jakarta/server/config/JakartaWebSocketServletContainerInitializer.java index 42398a74a016..c4c2a34d559b 100644 --- a/jetty-websocket/websocket-jakarta-server/src/main/java/org/eclipse/jetty/websocket/jakarta/server/config/JakartaWebSocketServletContainerInitializer.java +++ b/jetty-websocket/websocket-jakarta-server/src/main/java/org/eclipse/jetty/websocket/jakarta/server/config/JakartaWebSocketServletContainerInitializer.java @@ -40,7 +40,7 @@ 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 @@ private static ServerContainer initialize(ServletContextHandler context) { 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()) diff --git a/jetty-websocket/websocket-jakarta-server/src/main/java/org/eclipse/jetty/websocket/jakarta/server/internal/JakartaWebSocketServerContainer.java b/jetty-websocket/websocket-jakarta-server/src/main/java/org/eclipse/jetty/websocket/jakarta/server/internal/JakartaWebSocketServerContainer.java index afae685fa1df..d2a318697d2a 100644 --- a/jetty-websocket/websocket-jakarta-server/src/main/java/org/eclipse/jetty/websocket/jakarta/server/internal/JakartaWebSocketServerContainer.java +++ b/jetty-websocket/websocket-jakarta-server/src/main/java/org/eclipse/jetty/websocket/jakarta/server/internal/JakartaWebSocketServerContainer.java @@ -43,7 +43,7 @@ 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 static JakartaWebSocketServerContainer ensureContainer(ServletContext ser // 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 static JakartaWebSocketServerContainer ensureContainer(ServletContext ser return container; } - private final WebSocketMapping webSocketMapping; + private final WebSocketMappings webSocketMappings; private final JakartaWebSocketServerFrameHandlerFactory frameHandlerFactory; private List> deferredEndpointClasses; private List deferredEndpointConfigs; @@ -118,31 +118,31 @@ public static JakartaWebSocketServerContainer ensureContainer(ServletContext ser /** * 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 coreClientSupplier) + public JakartaWebSocketServerContainer(WebSocketMappings webSocketMappings, WebSocketComponents components, Function coreClientSupplier) { super(components, coreClientSupplier); - this.webSocketMapping = webSocketMapping; + this.webSocketMappings = webSocketMappings; this.frameHandlerFactory = new JakartaWebSocketServerFrameHandlerFactory(this); } @@ -265,7 +265,7 @@ private void addEndpointMapping(ServerEndpointConfig config) throws DeploymentEx 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) { diff --git a/jetty-websocket/websocket-jakarta-tests/src/test/java/org/eclipse/jetty/websocket/jakarta/tests/server/AltFilterTest.java b/jetty-websocket/websocket-jakarta-tests/src/test/java/org/eclipse/jetty/websocket/jakarta/tests/server/AltFilterTest.java index b7882c3a3d32..71139a093077 100644 --- a/jetty-websocket/websocket-jakarta-tests/src/test/java/org/eclipse/jetty/websocket/jakarta/tests/server/AltFilterTest.java +++ b/jetty-websocket/websocket-jakarta-tests/src/test/java/org/eclipse/jetty/websocket/jakarta/tests/server/AltFilterTest.java @@ -61,7 +61,7 @@ public void testEcho() throws Exception { 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"); diff --git a/jetty-websocket/websocket-jakarta-tests/src/test/resources/alt-filter-web.xml b/jetty-websocket/websocket-jakarta-tests/src/test/resources/alt-filter-web.xml index 3803bfc64b38..1fe97201480d 100644 --- a/jetty-websocket/websocket-jakarta-tests/src/test/resources/alt-filter-web.xml +++ b/jetty-websocket/websocket-jakarta-tests/src/test/resources/alt-filter-web.xml @@ -12,16 +12,12 @@ - wsuf-test + org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter - - jetty.websocket.WebSocketMapping - jetty.websocket.defaultMapping - - wsuf-test + org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter /echo/* diff --git a/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java b/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java index a4dc21e9cc5e..202c324c1f7e 100644 --- a/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java +++ b/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServerContainer.java @@ -47,7 +47,7 @@ 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 static JettyWebSocketServerContainer ensureContainer(ServletContext servl // 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 static JettyWebSocketServerContainer ensureContainer(ServletContext servl 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 static JettyWebSocketServerContainer ensureContainer(ServletContext servl /** * 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 static JettyWebSocketServerContainer ensureContainer(ServletContext servl 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); } diff --git a/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServlet.java b/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServlet.java index e0011d8e44de..22ff81044379 100644 --- a/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServlet.java +++ b/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/JettyWebSocketServlet.java @@ -40,14 +40,14 @@ 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. *

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

*

The most basic implementation would be as follows:

@@ -68,11 +68,11 @@ * } * *

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

*

@@ -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 void init() throws ServletException 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 Set getAvailableExtensionNames() @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 void setCreator(JettyWebSocketCreator creator) @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 JettyWebSocketCreator getMapping(String pathSpec) @Override public boolean removeMapping(String pathSpec) { - return mapping.removeMapping(WebSocketMapping.parsePathSpec(pathSpec)); + return mapping.removeMapping(WebSocketMappings.parsePathSpec(pathSpec)); } } diff --git a/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/config/JettyWebSocketServletContainerInitializer.java b/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/config/JettyWebSocketServletContainerInitializer.java index 38230fac151b..fbd1387c321b 100644 --- a/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/config/JettyWebSocketServletContainerInitializer.java +++ b/jetty-websocket/websocket-jetty-server/src/main/java/org/eclipse/jetty/websocket/server/config/JettyWebSocketServletContainerInitializer.java @@ -27,7 +27,7 @@ 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 interface Configurator * 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) diff --git a/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketFilterTest.java b/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketFilterTest.java index 56f8634bce2a..d0c465613359 100644 --- a/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketFilterTest.java +++ b/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketFilterTest.java @@ -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 void start(ServletHolder servletHolder) throws Exception 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 void testWebSocketUpgradeFilter() throws Exception // 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 void testLazyWebSocketUpgradeFilter() throws Exception // 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 void init() // 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 void init() 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 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 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 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 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 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()); + } + } } diff --git a/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketWebApp.java b/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketWebApp.java new file mode 100644 index 000000000000..cbfc6cd119ff --- /dev/null +++ b/jetty-websocket/websocket-jetty-tests/src/test/java/org/eclipse/jetty/websocket/tests/JettyWebSocketWebApp.java @@ -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 = "" + + ""; + + 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()); + } +} diff --git a/jetty-websocket/websocket-jetty-tests/src/test/resources/wsuf-ordering1.xml b/jetty-websocket/websocket-jetty-tests/src/test/resources/wsuf-ordering1.xml new file mode 100644 index 000000000000..b93d673a43b2 --- /dev/null +++ b/jetty-websocket/websocket-jetty-tests/src/test/resources/wsuf-ordering1.xml @@ -0,0 +1,21 @@ + + + + + wsuf-alt + org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter + + idleTimeout + 5999 + + + + wsuf-alt + /* + + diff --git a/jetty-websocket/websocket-jetty-tests/src/test/resources/wsuf-ordering2.xml b/jetty-websocket/websocket-jetty-tests/src/test/resources/wsuf-ordering2.xml new file mode 100644 index 000000000000..a733873a6712 --- /dev/null +++ b/jetty-websocket/websocket-jetty-tests/src/test/resources/wsuf-ordering2.xml @@ -0,0 +1,32 @@ + + + + + + wsuf-alt + org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter + + idleTimeout + 5999 + + + + wsuf-alt + /* + + + + + org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter + org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter + + + org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter + /* + + diff --git a/jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/WebSocketUpgradeFilter.java b/jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/WebSocketUpgradeFilter.java index 76dfa949ffcc..4041ce31e487 100644 --- a/jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/WebSocketUpgradeFilter.java +++ b/jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/WebSocketUpgradeFilter.java @@ -35,12 +35,13 @@ 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 @@ *

* 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}. *

*

* Configuration / Init-Parameters: @@ -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 static FilterHolder ensureFilter(ServletContext servletContext) if (existingFilter != null) return existingFilter; - final String name = "WebSocketUpgradeFilter"; + ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext)); + ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class); + final String pathSpec = "/*"; FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter()); - holder.setName(name); - holder.setInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM, WebSocketMapping.DEFAULT_KEY); - + holder.setName(WebSocketUpgradeFilter.class.getName()); holder.setAsyncSupported(true); - ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext)); - ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class); - servletHandler.addFilterWithMapping(holder, pathSpec, EnumSet.of(DispatcherType.REQUEST)); + + 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 static FilterHolder ensureFilter(ServletContext servletContext) } 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 void dump(Appendable out, String indent) throws IOException @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) diff --git a/jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/internal/WebSocketMapping.java b/jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/internal/WebSocketMappings.java similarity index 88% rename from jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/internal/WebSocketMapping.java rename to jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/internal/WebSocketMappings.java index 1ab74f410b29..1210cc129dbc 100644 --- a/jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/internal/WebSocketMapping.java +++ b/jetty-websocket/websocket-util-server/src/main/java/org/eclipse/jetty/websocket/util/server/internal/WebSocketMappings.java @@ -56,24 +56,14 @@ * wrap that POJO with a {@link FrameHandler} and the customizer is used to configure the resulting * {@link CoreSession}.

*/ -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 WebSocketCreator getMapping(PathSpec pathSpec) 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 @@ else if (rawSpec.startsWith("uri-template|")) throw new IllegalArgumentException("Unrecognized path spec syntax [" + rawSpec + "]"); } - public static final String DEFAULT_KEY = "jetty.websocket.defaultMapping"; - private final PathMappings 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 WebSocketMapping(WebSocketComponents components) 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);