Issue #1057 - Improve WebSocketUpgradeFilter performance

+ Tests for WebSocket upgrade now evaluates the request
  from least common feature to most common feature, so as
  minimize the testing of the request object on every request
This commit is contained in:
Joakim Erdfelt 2016-11-02 11:28:56 -07:00
parent 4cc5178944
commit c665106fc5
2 changed files with 73 additions and 61 deletions

View File

@ -188,7 +188,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
catch (URISyntaxException e)
{
throw new IOException("Unable to accept websocket due to mangled URI", e);
}
}
finally
{
Thread.currentThread().setContextClassLoader(old);
@ -340,13 +340,22 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
@Override
public boolean isUpgradeRequest(HttpServletRequest request, HttpServletResponse response)
{
if (!"GET".equalsIgnoreCase(request.getMethod()))
// Tests sorted by least common to most common.
String upgrade = request.getHeader("Upgrade");
if (upgrade == null)
{
// not a "GET" request (not a websocket upgrade)
// no "Upgrade: websocket" header present.
return false;
}
String connection = request.getHeader("connection");
if (!"websocket".equalsIgnoreCase(upgrade))
{
// Not a websocket upgrade
return false;
}
String connection = request.getHeader("Connection");
if (connection == null)
{
// no "Connection: upgrade" header present.
@ -370,17 +379,10 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
{
return false;
}
String upgrade = request.getHeader("Upgrade");
if (upgrade == null)
if (!"GET".equalsIgnoreCase(request.getMethod()))
{
// no "Upgrade: websocket" header present.
return false;
}
if (!"websocket".equalsIgnoreCase(upgrade))
{
LOG.debug("Not a 'Upgrade: WebSocket' (was [Upgrade: " + upgrade + "])");
// not a "GET" request (not a websocket upgrade)
return false;
}

View File

@ -20,6 +20,7 @@ package org.eclipse.jetty.websocket.server;
import java.io.IOException;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
@ -160,17 +161,19 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
chain.doFilter(request,response);
return;
}
if (LOG.isDebugEnabled())
try
{
LOG.debug(".doFilter({}) - {}",fname,chain);
}
if ((request instanceof HttpServletRequest) && (response instanceof HttpServletResponse))
{
HttpServletRequest httpreq = (HttpServletRequest)request;
HttpServletResponse httpresp = (HttpServletResponse)response;
HttpServletRequest httpreq = (HttpServletRequest) request;
HttpServletResponse httpresp = (HttpServletResponse) response;
if (!factory.isUpgradeRequest(httpreq, httpresp))
{
// Not an upgrade request, skip it
chain.doFilter(request, response);
return;
}
// Since this is a filter, we need to be smart about determining the target path
String contextPath = httpreq.getContextPath();
String target = httpreq.getRequestURI();
@ -178,45 +181,52 @@ public class WebSocketUpgradeFilter extends ContainerLifeCycle implements Filter
{
target = target.substring(contextPath.length());
}
if (factory.isUpgradeRequest(httpreq,httpresp))
MappedResource<WebSocketCreator> resource = pathmap.getMatch(target);
if (resource == null)
{
LOG.debug("target = [{}]",target);
MappedResource<WebSocketCreator> resource = pathmap.getMatch(target);
if (resource == null)
if (LOG.isDebugEnabled())
{
if (LOG.isDebugEnabled())
{
LOG.debug("WebSocket Upgrade on {} has no associated endpoint",target);
LOG.debug("PathMappings: {}",pathmap.dump());
}
// no match.
chain.doFilter(request,response);
return;
}
LOG.debug("WebSocket Upgrade detected on {} for endpoint {}",target,resource);
WebSocketCreator creator = resource.getResource();
// Store PathSpec resource mapping as request attribute
httpreq.setAttribute(PathSpec.class.getName(),resource.getPathSpec());
// We have an upgrade request
if (factory.acceptWebSocket(creator,httpreq,httpresp))
{
// We have a socket instance created
return;
}
// If we reach this point, it means we had an incoming request to upgrade
// but it was either not a proper websocket upgrade, or it was possibly rejected
// due to incoming request constraints (controlled by WebSocketCreator)
if (response.isCommitted())
{
// not much we can do at this point.
return;
LOG.debug("WebSocket Upgrade on {} has no associated endpoint", target);
LOG.debug("PathMappings: {}", pathmap.dump());
}
// no match.
chain.doFilter(request, response);
return;
}
if(LOG.isDebugEnabled())
{
LOG.debug("WebSocket Upgrade detected on {} for endpoint {}", target, resource);
}
WebSocketCreator creator = resource.getResource();
// Store PathSpec resource mapping as request attribute
httpreq.setAttribute(PathSpec.class.getName(), resource.getPathSpec());
// We have an upgrade request
if (factory.acceptWebSocket(creator, httpreq, httpresp))
{
// We have a socket instance created
return;
}
// If we reach this point, it means we had an incoming request to upgrade
// but it was either not a proper websocket upgrade, or it was possibly rejected
// due to incoming request constraints (controlled by WebSocketCreator)
if (response.isCommitted())
{
// not much we can do at this point.
return;
}
}
catch (ClassCastException e)
{
// We are in some kind of funky non-http environment.
if (LOG.isDebugEnabled())
{
LOG.debug("Not a HttpServletRequest, skipping WebSocketUpgradeFilter");
}
}