Issue #3458 - jetty websocket upgrades with only websocket-server
websocket-servlet exposes core classes as it is used by the jetty and javax sides, so this introduces a way to add websocket mappings with jetty-server which does not depend on websocket-servlet to set websocket mappings through the JettyWebSocketServerContainer you now need to use the JettyWebSocketCreator which abstracts away the core classes from use with the jetty websocket api Signed-off-by: Lachlan Roberts <lachlan@webtide.com>
This commit is contained in:
parent
86675422a6
commit
f60534a8ac
|
@ -0,0 +1,310 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.net.HttpCookie;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.net.URI;
|
||||
import java.security.Principal;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.common.JettyExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.core.server.Negotiation;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeRequest;
|
||||
|
||||
public class JettyServerUpgradeRequest
|
||||
{
|
||||
private ServletUpgradeRequest upgradeRequest;
|
||||
|
||||
public JettyServerUpgradeRequest(ServletUpgradeRequest request)
|
||||
{
|
||||
upgradeRequest = request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The {@link X509Certificate} instance at request attribute "javax.servlet.request.X509Certificate" or null.
|
||||
*/
|
||||
public X509Certificate[] getCertificates()
|
||||
{
|
||||
return upgradeRequest.getCertificates();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see HttpServletRequest#getCookies()
|
||||
* @return Request cookies
|
||||
*/
|
||||
public List<HttpCookie> getCookies()
|
||||
{
|
||||
return upgradeRequest.getCookies();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The extensions offered
|
||||
* @see Negotiation#getOfferedExtensions()
|
||||
*/
|
||||
public List<ExtensionConfig> getExtensions()
|
||||
{
|
||||
return upgradeRequest.getExtensions().stream().map(JettyExtensionConfig::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Header name
|
||||
* @return Header value or null
|
||||
* @see HttpServletRequest#getHeader(String)
|
||||
*/
|
||||
public String getHeader(String name)
|
||||
{
|
||||
return upgradeRequest.getHeader(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Header name
|
||||
* @return Header value as integer or -1
|
||||
* @see HttpServletRequest#getHeader(String)
|
||||
*/
|
||||
public int getHeaderInt(String name)
|
||||
{
|
||||
return upgradeRequest.getHeaderInt(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Map of headers
|
||||
*/
|
||||
public Map<String, List<String>> getHeadersMap()
|
||||
{
|
||||
return upgradeRequest.getHeadersMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Header name
|
||||
* @return List of header values or null
|
||||
*/
|
||||
public List<String> getHeaders(String name)
|
||||
{
|
||||
return upgradeRequest.getHeaders(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The requested host
|
||||
* @see HttpServletRequest#getRequestURL()
|
||||
*/
|
||||
public String getHost()
|
||||
{
|
||||
return upgradeRequest.getHost();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Immutable version of {@link HttpServletRequest}
|
||||
*/
|
||||
public HttpServletRequest getHttpServletRequest()
|
||||
{
|
||||
return upgradeRequest.getHttpServletRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The HTTP protocol version
|
||||
* @see HttpServletRequest#getProtocol()
|
||||
*/
|
||||
public String getHttpVersion()
|
||||
{
|
||||
return upgradeRequest.getHttpVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The requested Locale
|
||||
* @see HttpServletRequest#getLocale()
|
||||
*/
|
||||
public Locale getLocale()
|
||||
{
|
||||
return upgradeRequest.getLocale();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The requested Locales
|
||||
* @see HttpServletRequest#getLocales()
|
||||
*/
|
||||
public Enumeration<Locale> getLocales()
|
||||
{
|
||||
return upgradeRequest.getLocales();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The local requested address, which is typically an {@link InetSocketAddress}, but may be another derivation of {@link SocketAddress}
|
||||
* @see ServletRequest#getLocalAddr()
|
||||
* @see ServletRequest#getLocalPort()
|
||||
*/
|
||||
public SocketAddress getLocalSocketAddress()
|
||||
{
|
||||
return upgradeRequest.getLocalSocketAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The requested method
|
||||
* @see HttpServletRequest#getMethod()
|
||||
*/
|
||||
public String getMethod()
|
||||
{
|
||||
return upgradeRequest.getMethod();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The origin header value
|
||||
*/
|
||||
public String getOrigin()
|
||||
{
|
||||
return upgradeRequest.getOrigin();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The request parameter map
|
||||
* @see ServletRequest#getParameterMap()
|
||||
*/
|
||||
public Map<String, List<String>> getParameterMap()
|
||||
{
|
||||
return upgradeRequest.getParameterMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WebSocket protocol version from "Sec-WebSocket-Version" header
|
||||
*/
|
||||
public String getProtocolVersion()
|
||||
{
|
||||
return upgradeRequest.getProtocolVersion();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The request query string
|
||||
* @see HttpServletRequest#getQueryString()
|
||||
*/
|
||||
public String getQueryString()
|
||||
{
|
||||
return upgradeRequest.getQueryString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The remote request address, which is typically an {@link InetSocketAddress}, but may be another derivation of {@link SocketAddress}
|
||||
* @see ServletRequest#getRemoteAddr()
|
||||
* @see ServletRequest#getRemotePort()
|
||||
*/
|
||||
public SocketAddress getRemoteSocketAddress()
|
||||
{
|
||||
return upgradeRequest.getRemoteSocketAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The request URI path within the context
|
||||
*/
|
||||
public String getRequestPath()
|
||||
{
|
||||
return upgradeRequest.getRequestPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The request URI
|
||||
* @see HttpServletRequest#getRequestURL()
|
||||
*/
|
||||
public URI getRequestURI()
|
||||
{
|
||||
return upgradeRequest.getRequestURI();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Attribute name
|
||||
* @return Attribute value or null
|
||||
* @see ServletRequest#getAttribute(String)
|
||||
*/
|
||||
public Object getServletAttribute(String name)
|
||||
{
|
||||
return upgradeRequest.getServletAttribute(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Request attribute map
|
||||
*/
|
||||
public Map<String, Object> getServletAttributes()
|
||||
{
|
||||
return upgradeRequest.getServletAttributes();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Request parameters
|
||||
* @see ServletRequest#getParameterMap()
|
||||
*/
|
||||
public Map<String, List<String>> getServletParameters()
|
||||
{
|
||||
return upgradeRequest.getServletParameters();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The HttpSession, which may be null or invalidated
|
||||
* @see HttpServletRequest#getSession(boolean)
|
||||
*/
|
||||
public HttpSession getSession()
|
||||
{
|
||||
return upgradeRequest.getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Get WebSocket negotiation offered sub protocols
|
||||
*/
|
||||
public List<String> getSubProtocols()
|
||||
{
|
||||
return upgradeRequest.getSubProtocols();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The User's {@link Principal} or null
|
||||
* @see HttpServletRequest#getUserPrincipal()
|
||||
*/
|
||||
public Principal getUserPrincipal()
|
||||
{
|
||||
return upgradeRequest.getUserPrincipal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param subprotocol A sub protocol name
|
||||
* @return True if the sub protocol was offered
|
||||
*/
|
||||
public boolean hasSubProtocol(String subprotocol)
|
||||
{
|
||||
return upgradeRequest.hasSubProtocol(subprotocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if the request is secure
|
||||
* @see ServletRequest#isSecure()
|
||||
*/
|
||||
public boolean isSecure()
|
||||
{
|
||||
return upgradeRequest.isSecure();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param role The user role
|
||||
* @return True if the requests user has the role
|
||||
* @see HttpServletRequest#isUserInRole(String)
|
||||
*/
|
||||
public boolean isUserInRole(String role)
|
||||
{
|
||||
return upgradeRequest.isUserInRole(role);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Attribute name
|
||||
* @param value Attribute value to set
|
||||
* @see ServletRequest#setAttribute(String, Object)
|
||||
*/
|
||||
public void setServletAttribute(String name, Object value)
|
||||
{
|
||||
upgradeRequest.setServletAttribute(name, value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.common.JettyExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.servlet.ServletUpgradeResponse;
|
||||
|
||||
public class JettyServerUpgradeResponse
|
||||
{
|
||||
private ServletUpgradeResponse upgradeResponse;
|
||||
|
||||
public JettyServerUpgradeResponse(ServletUpgradeResponse response)
|
||||
{
|
||||
upgradeResponse = response;
|
||||
}
|
||||
|
||||
public void addHeader(String name, String value)
|
||||
{
|
||||
upgradeResponse.addHeader(name, value);
|
||||
}
|
||||
|
||||
public void setHeader(String name, String value)
|
||||
{
|
||||
upgradeResponse.setHeader(name, value);
|
||||
}
|
||||
|
||||
public void setHeader(String name, List<String> values)
|
||||
{
|
||||
upgradeResponse.setHeader(name, values);
|
||||
}
|
||||
|
||||
public String getAcceptedSubProtocol()
|
||||
{
|
||||
return upgradeResponse.getAcceptedSubProtocol();
|
||||
}
|
||||
|
||||
public List<ExtensionConfig> getExtensions()
|
||||
{
|
||||
return upgradeResponse.getExtensions().stream().map(JettyExtensionConfig::new).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String getHeader(String name)
|
||||
{
|
||||
return upgradeResponse.getHeader(name);
|
||||
}
|
||||
|
||||
public Set<String> getHeaderNames()
|
||||
{
|
||||
return upgradeResponse.getHeaderNames();
|
||||
}
|
||||
|
||||
public Map<String, List<String>> getHeadersMap()
|
||||
{
|
||||
return upgradeResponse.getHeadersMap();
|
||||
}
|
||||
|
||||
public List<String> getHeaders(String name)
|
||||
{
|
||||
return upgradeResponse.getHeaders(name);
|
||||
}
|
||||
|
||||
public int getStatusCode()
|
||||
{
|
||||
return upgradeResponse.getStatusCode();
|
||||
}
|
||||
|
||||
public boolean isCommitted()
|
||||
{
|
||||
return upgradeResponse.isCommitted();
|
||||
}
|
||||
|
||||
public void sendError(int statusCode, String message) throws IOException
|
||||
{
|
||||
upgradeResponse.sendError(statusCode, message);
|
||||
}
|
||||
|
||||
public void sendForbidden(String message) throws IOException
|
||||
{
|
||||
upgradeResponse.sendForbidden(message);
|
||||
}
|
||||
|
||||
public void setAcceptedSubProtocol(String protocol)
|
||||
{
|
||||
upgradeResponse.setAcceptedSubProtocol(protocol);
|
||||
}
|
||||
|
||||
public void setExtensions(List<ExtensionConfig> configs)
|
||||
{
|
||||
upgradeResponse.setExtensions(configs.stream()
|
||||
.map(c->new org.eclipse.jetty.websocket.core.ExtensionConfig(c.getName(), c.getParameters()))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
public void setStatusCode(int statusCode)
|
||||
{
|
||||
upgradeResponse.setStatusCode(statusCode);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package org.eclipse.jetty.websocket.server;
|
||||
|
||||
|
||||
/**
|
||||
* Abstract WebSocket creator interface.
|
||||
* <p>
|
||||
* Should you desire filtering of the WebSocket object creation due to criteria such as origin or sub-protocol, then you will be required to implement a custom
|
||||
* WebSocketCreator implementation.
|
||||
* </p>
|
||||
*/
|
||||
public interface JettyWebSocketCreator
|
||||
{
|
||||
/**
|
||||
* Create a websocket from the incoming request.
|
||||
*
|
||||
* @param req the request details
|
||||
* @param resp the response details
|
||||
* @return a websocket object to use, or null if no websocket should be created from this request.
|
||||
*/
|
||||
Object createWebSocket(JettyServerUpgradeRequest req, JettyServerUpgradeResponse resp);
|
||||
}
|
|
@ -28,7 +28,6 @@ import java.util.function.Consumer;
|
|||
import javax.servlet.ServletContext;
|
||||
|
||||
import org.eclipse.jetty.http.pathmap.PathSpec;
|
||||
import org.eclipse.jetty.server.handler.ContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
import org.eclipse.jetty.util.component.LifeCycle;
|
||||
|
@ -44,7 +43,6 @@ import org.eclipse.jetty.websocket.core.FrameHandler;
|
|||
import org.eclipse.jetty.websocket.core.WebSocketComponents;
|
||||
import org.eclipse.jetty.websocket.core.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.servlet.FrameHandlerFactory;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketCreator;
|
||||
import org.eclipse.jetty.websocket.servlet.WebSocketMapping;
|
||||
|
||||
public class JettyWebSocketServerContainer extends ContainerLifeCycle implements WebSocketContainer, WebSocketPolicy, LifeCycle.Listener
|
||||
|
@ -114,13 +112,15 @@ public class JettyWebSocketServerContainer extends ContainerLifeCycle implements
|
|||
addSessionListener(sessionTracker);
|
||||
}
|
||||
|
||||
public void addMapping(String pathSpec, WebSocketCreator creator)
|
||||
public void addMapping(String pathSpec, JettyWebSocketCreator creator)
|
||||
{
|
||||
PathSpec ps = WebSocketMapping.parsePathSpec(pathSpec);
|
||||
if (webSocketMapping.getMapping(ps) != null)
|
||||
throw new WebSocketException("Duplicate WebSocket Mapping for PathSpec");
|
||||
|
||||
webSocketMapping.addMapping(ps, creator, frameHandlerFactory, customizer);
|
||||
webSocketMapping.addMapping(ps,
|
||||
(req, resp)-> creator.createWebSocket(new JettyServerUpgradeRequest(req), new JettyServerUpgradeResponse(resp)),
|
||||
frameHandlerFactory, customizer);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue