Issue #5378 - guard against concurrent requests lazily initializing the filter

Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
Lachlan Roberts 2020-10-08 08:45:38 +11:00
parent 2a4d672fc1
commit 7003b3c42e
1 changed files with 24 additions and 15 deletions

View File

@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.util.server;
import java.io.IOException; import java.io.IOException;
import java.time.Duration; import java.time.Duration;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.Objects;
import javax.servlet.DispatcherType; import javax.servlet.DispatcherType;
import javax.servlet.Filter; import javax.servlet.Filter;
import javax.servlet.FilterChain; import javax.servlet.FilterChain;
@ -37,6 +38,7 @@ import org.eclipse.jetty.servlet.FilterHolder;
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;
import org.eclipse.jetty.util.thread.AutoLock;
import org.eclipse.jetty.websocket.core.Configuration; import org.eclipse.jetty.websocket.core.Configuration;
import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents; import org.eclipse.jetty.websocket.core.server.WebSocketServerComponents;
import org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping; import org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping;
@ -74,10 +76,12 @@ import org.slf4j.LoggerFactory;
public class WebSocketUpgradeFilter implements Filter, Dumpable public class WebSocketUpgradeFilter implements Filter, Dumpable
{ {
private static final Logger LOG = LoggerFactory.getLogger(WebSocketUpgradeFilter.class); private static final Logger LOG = LoggerFactory.getLogger(WebSocketUpgradeFilter.class);
private static final AutoLock LOCK = new AutoLock();
private static FilterHolder getFilter(ServletContext servletContext) private static FilterHolder getFilter(ServletContext servletContext)
{ {
ServletHandler servletHandler = ContextHandler.getContextHandler(servletContext).getChildHandlerByClass(ServletHandler.class); ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext));
ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class);
for (FilterHolder holder : servletHandler.getFilters()) for (FilterHolder holder : servletHandler.getFilters())
{ {
@ -104,6 +108,9 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
* @return the configured default {@link WebSocketUpgradeFilter} instance * @return the configured default {@link WebSocketUpgradeFilter} instance
*/ */
public static FilterHolder ensureFilter(ServletContext servletContext) public static FilterHolder ensureFilter(ServletContext servletContext)
{
// Lock in case two concurrent requests are initializing the filter lazily.
try (AutoLock l = LOCK.lock())
{ {
FilterHolder existingFilter = WebSocketUpgradeFilter.getFilter(servletContext); FilterHolder existingFilter = WebSocketUpgradeFilter.getFilter(servletContext);
if (existingFilter != null) if (existingFilter != null)
@ -116,12 +123,14 @@ public class WebSocketUpgradeFilter implements Filter, Dumpable
holder.setInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM, WebSocketMapping.DEFAULT_KEY); holder.setInitParameter(MAPPING_ATTRIBUTE_INIT_PARAM, WebSocketMapping.DEFAULT_KEY);
holder.setAsyncSupported(true); holder.setAsyncSupported(true);
ServletHandler servletHandler = ContextHandler.getContextHandler(servletContext).getChildHandlerByClass(ServletHandler.class); ContextHandler contextHandler = Objects.requireNonNull(ContextHandler.getContextHandler(servletContext));
ServletHandler servletHandler = contextHandler.getChildHandlerByClass(ServletHandler.class);
servletHandler.addFilterWithMapping(holder, pathSpec, EnumSet.of(DispatcherType.REQUEST)); servletHandler.addFilterWithMapping(holder, pathSpec, EnumSet.of(DispatcherType.REQUEST));
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;
} }
}
public static final String MAPPING_ATTRIBUTE_INIT_PARAM = "org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping.key"; public static final String MAPPING_ATTRIBUTE_INIT_PARAM = "org.eclipse.jetty.websocket.util.server.internal.WebSocketMapping.key";