Always add the default WebSocketUpgradeFilter as the first filter.

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2020-11-18 21:27:25 +11:00
parent aba2c93eae
commit 6a83a261e1
6 changed files with 73 additions and 28 deletions

View File

@ -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 * Convenience method to add a preconstructed FilterMapping
* *

View File

@ -311,7 +311,7 @@ public class JettyWebSocketFilterTest
@Test @Test
public void testDefaultWebSocketUpgradeFilterOrdering() throws Exception public void testDefaultWebSocketUpgradeFilterOrdering() throws Exception
{ {
String timeoutFromAltFilter = "5999"; String defaultIdleTimeout = Long.toString(WebSocketConstants.DEFAULT_IDLE_TIMEOUT.toMillis());
JettyWebSocketWebApp webApp = new JettyWebSocketWebApp("wsuf-ordering1"); JettyWebSocketWebApp webApp = new JettyWebSocketWebApp("wsuf-ordering1");
Path webXml = MavenTestingUtils.getTestResourcePath("wsuf-ordering1.xml"); Path webXml = MavenTestingUtils.getTestResourcePath("wsuf-ordering1.xml");
webApp.copyWebXml(webXml); webApp.copyWebXml(webXml);
@ -339,13 +339,13 @@ public class JettyWebSocketFilterTest
} }
assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS)); assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(socket.textMessages.poll(), is("hello world")); assertThat(socket.textMessages.poll(), is("hello world"));
assertThat(socket.textMessages.poll(), is(timeoutFromAltFilter)); assertThat(socket.textMessages.poll(), is(defaultIdleTimeout));
} }
@Test @Test
public void testWebSocketUpgradeFilterOrdering() throws Exception public void testWebSocketUpgradeFilterOrdering() throws Exception
{ {
String defaultIdleTimeout = Long.toString(WebSocketConstants.DEFAULT_IDLE_TIMEOUT.toMillis()); String timeoutFromAltFilter = "5999";
JettyWebSocketWebApp webApp = new JettyWebSocketWebApp("wsuf-ordering2"); JettyWebSocketWebApp webApp = new JettyWebSocketWebApp("wsuf-ordering2");
Path webXml = MavenTestingUtils.getTestResourcePath("wsuf-ordering2.xml"); Path webXml = MavenTestingUtils.getTestResourcePath("wsuf-ordering2.xml");
webApp.copyWebXml(webXml); webApp.copyWebXml(webXml);
@ -373,7 +373,7 @@ public class JettyWebSocketFilterTest
} }
assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS)); assertTrue(socket.closeLatch.await(5, TimeUnit.SECONDS));
assertThat(socket.textMessages.poll(), is("hello world")); assertThat(socket.textMessages.poll(), is("hello world"));
assertThat(socket.textMessages.poll(), is(defaultIdleTimeout)); assertThat(socket.textMessages.poll(), is(timeoutFromAltFilter));
} }
@WebListener @WebListener

View File

@ -1,3 +1,21 @@
//
// ========================================================================
// 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; package org.eclipse.jetty.websocket.tests;
import java.io.File; import java.io.File;

View File

@ -2,9 +2,9 @@
<web-app <web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" metadata-complete="false"
version="3.1"> version="4.0">
<filter> <filter>
<filter-name>wsuf-alt</filter-name> <filter-name>wsuf-alt</filter-name>

View File

@ -2,21 +2,11 @@
<web-app <web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" metadata-complete="false"
version="3.1"> version="4.0">
<!-- Make sure the default filter is first. --> <!-- Add the custom filter first. -->
<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>
<!-- The custom filter is then tried after. -->
<filter> <filter>
<filter-name>wsuf-alt</filter-name> <filter-name>wsuf-alt</filter-name>
<filter-class>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-class> <filter-class>org.eclipse.jetty.websocket.util.server.WebSocketUpgradeFilter</filter-class>
@ -29,4 +19,14 @@
<filter-name>wsuf-alt</filter-name> <filter-name>wsuf-alt</filter-name>
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping> </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> </web-app>

View File

@ -35,6 +35,7 @@ import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletHandler; import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.util.annotation.ManagedObject; import org.eclipse.jetty.util.annotation.ManagedObject;
import org.eclipse.jetty.util.component.Dumpable; import org.eclipse.jetty.util.component.Dumpable;
@ -78,12 +79,12 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
private static final AutoLock LOCK = new AutoLock(); private static final AutoLock LOCK = new AutoLock();
/** /**
* 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. * @param servletContext the {@link ServletContext} to use.
* @return the configured default {@link WebSocketUpgradeFilter} instance. * @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)); ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext));
ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class); ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class);
@ -111,14 +112,23 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
if (existingFilter != null) if (existingFilter != null)
return existingFilter; return existingFilter;
ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext));
ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class);
final String pathSpec = "/*"; final String pathSpec = "/*";
FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter()); FilterHolder holder = new FilterHolder(new WebSocketUpgradeFilter());
holder.setName(WebSocketUpgradeFilter.class.getName()); holder.setName(WebSocketUpgradeFilter.class.getName());
holder.setAsyncSupported(true); holder.setAsyncSupported(true);
ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext));
ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class); FilterMapping mapping = new FilterMapping();
servletHandler.addFilterWithMapping(holder, pathSpec, EnumSet.of(DispatcherType.REQUEST)); 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()) if (LOG.isDebugEnabled())
LOG.debug("Adding {} mapped to {} in {}", holder, pathSpec, servletContext); LOG.debug("Adding {} mapped to {} in {}", holder, pathSpec, servletContext);
return holder; return holder;