Merge branch 'jetty-10.0.x-3167-websocket-mapping' into jetty-10.0.x-3167-2175-websocket-close

This commit is contained in:
Greg Wilkins 2019-01-15 13:38:19 +11:00
commit 878e51032d
13 changed files with 226 additions and 16 deletions

View File

@ -24,6 +24,8 @@ import javax.websocket.server.ServerContainer;
import javax.websocket.server.ServerEndpoint; import javax.websocket.server.ServerEndpoint;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServerContainerInitializer; import org.eclipse.jetty.websocket.javax.server.JavaxWebSocketServerContainerInitializer;
@ -49,10 +51,12 @@ public class WebSocketJsrServer
{ {
Server server = new Server(8080); Server server = new Server(8080);
HandlerList handlers = new HandlerList();
ServletContextHandler context = new ServletContextHandler( ServletContextHandler context = new ServletContextHandler(
ServletContextHandler.SESSIONS); ServletContextHandler.SESSIONS);
context.setContextPath("/"); context.setContextPath("/");
server.setHandler(context); handlers.addHandler(context);
// Enable javax.websocket configuration for the context // Enable javax.websocket configuration for the context
ServerContainer wsContainer = JavaxWebSocketServerContainerInitializer ServerContainer wsContainer = JavaxWebSocketServerContainerInitializer
@ -61,6 +65,9 @@ public class WebSocketJsrServer
// Add your websockets to the container // Add your websockets to the container
wsContainer.addEndpoint(EchoJsrSocket.class); wsContainer.addEndpoint(EchoJsrSocket.class);
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start(); server.start();
context.dumpStdErr(); context.dumpStdErr();
server.join(); server.join();

View File

@ -0,0 +1,4 @@
DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
[depend]
alpn-impl/alpn-9

View File

@ -549,7 +549,7 @@ public abstract class AbstractProxyServlet extends HttpServlet
} }
builder.append(System.lineSeparator()); builder.append(System.lineSeparator());
_log.debug("{} proxying to upstream:{}{}{}{}", _log.debug("{} proxying to upstream:{}{}{}{}{}",
getRequestId(clientRequest), getRequestId(clientRequest),
System.lineSeparator(), System.lineSeparator(),
builder, builder,

View File

@ -620,6 +620,16 @@ public class ProxyConnectionFactory extends AbstractConnectionFactory
return _remote; return _remote;
} }
@Override
public String toString() {
return String.format("%s@%x[remote=%s,local=%s,endpoint=%s]",
getClass().getSimpleName(),
hashCode(),
_remote,
_local,
_endp);
}
@Override @Override
public boolean isOpen() public boolean isOpen()
{ {

View File

@ -69,6 +69,15 @@ public interface Dumpable
return b.toString(); return b.toString();
} }
/**
* The description of this/self found in the dump.
* Allows for alternative representation of Object other then .toString()
* where the long form output of toString() is represented in a cleaner way
* within the dump infrastructure.
*
* @return the representation of self
*/
default String dumpSelf() { return toString(); }
/** /**
* Dump just an Object (but not it's contained items) to an Appendable. * Dump just an Object (but not it's contained items) to an Appendable.
@ -89,6 +98,8 @@ public interface Dumpable
s = String.format("%s@%x[size=%d]",o.getClass().getComponentType(),o.hashCode(), Array.getLength(o)); s = String.format("%s@%x[size=%d]",o.getClass().getComponentType(),o.hashCode(), Array.getLength(o));
else if (o instanceof Map) else if (o instanceof Map)
s = String.format("%s@%x{size=%d}",o.getClass().getName(),o.hashCode(),((Map<?,?>)o).size()); s = String.format("%s@%x{size=%d}",o.getClass().getName(),o.hashCode(),((Map<?,?>)o).size());
else if (o instanceof Dumpable)
s = ((Dumpable)o).dumpSelf().replace("\r\n","|").replace("\n","|");
else else
s = String.valueOf(o).replace("\r\n","|").replace("\n","|"); s = String.valueOf(o).replace("\r\n","|").replace("\n","|");

View File

@ -32,6 +32,12 @@
<artifactId>jetty-server</artifactId> <artifactId>jetty-server</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>org.eclipse.jetty.websocket</groupId> <groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>jetty-websocket-api</artifactId> <artifactId>jetty-websocket-api</artifactId>

View File

@ -30,6 +30,7 @@ module org.eclipse.jetty.websocket.jetty.server
requires org.eclipse.jetty.util; requires org.eclipse.jetty.util;
requires org.eclipse.jetty.http; requires org.eclipse.jetty.http;
requires org.eclipse.jetty.server; requires org.eclipse.jetty.server;
requires static org.eclipse.jetty.jmx;
requires org.eclipse.jetty.servlet; requires org.eclipse.jetty.servlet;
requires org.eclipse.jetty.webapp; requires org.eclipse.jetty.webapp;
requires org.eclipse.jetty.websocket.jetty.api; requires org.eclipse.jetty.websocket.jetty.api;

View File

@ -18,16 +18,19 @@
package org.eclipse.jetty.websocket.core; package org.eclipse.jetty.websocket.core;
import java.io.IOException;
import org.eclipse.jetty.io.ByteBufferPool; import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.Callback; import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.annotation.ManagedAttribute; import org.eclipse.jetty.util.annotation.ManagedAttribute;
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.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel; import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
@ManagedObject("Abstract Extension") @ManagedObject("Abstract Extension")
public abstract class AbstractExtension implements Extension public abstract class AbstractExtension implements Extension, Dumpable
{ {
private final Logger log; private final Logger log;
private ByteBufferPool bufferPool; private ByteBufferPool bufferPool;
@ -41,6 +44,27 @@ public abstract class AbstractExtension implements Extension
log = Log.getLogger(this.getClass()); log = Log.getLogger(this.getClass());
} }
@Override
public String dump()
{
return Dumpable.dump(this);
}
@Override
public void dump(Appendable out, String indent) throws IOException
{
// incoming
dumpWithHeading(out, indent, "incoming", this.nextIncoming);
dumpWithHeading(out, indent, "outgoing", this.nextOutgoing);
}
protected void dumpWithHeading(Appendable out, String indent, String heading, Object bean) throws IOException
{
out.append(indent).append(" +- ");
out.append(heading).append(" : ");
out.append(bean.toString());
}
@Override @Override
public void init(ExtensionConfig config, ByteBufferPool bufferPool) public void init(ExtensionConfig config, ByteBufferPool bufferPool)
{ {

View File

@ -232,6 +232,12 @@ public class ExtensionStack implements IncomingFrames, OutgoingFrames, Dumpable
Dumpable.dumpObjects(out, indent, this, extensions == null?Collections.emptyList():extensions); Dumpable.dumpObjects(out, indent, this, extensions == null?Collections.emptyList():extensions);
} }
@Override
public String dumpSelf()
{
return String.format("%s@%x[size=%d,queueSize=%d]", getClass().getSimpleName(), hashCode(), extensions.size(), getQueueSize());
}
@Override @Override
public String toString() public String toString()
{ {

View File

@ -20,7 +20,9 @@ package org.eclipse.jetty.websocket.servlet;
import org.eclipse.jetty.websocket.core.FrameHandler; import org.eclipse.jetty.websocket.core.FrameHandler;
/**
* Factory for FrameHandler instances
*/
public interface FrameHandlerFactory public interface FrameHandlerFactory
{ {
/** /**

View File

@ -18,15 +18,6 @@
package org.eclipse.jetty.websocket.servlet; package org.eclipse.jetty.websocket.servlet;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.WebSocketConstants;
import org.eclipse.jetty.websocket.core.server.Negotiation;
import org.eclipse.jetty.websocket.servlet.internal.UpgradeHttpServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.net.HttpCookie; import java.net.HttpCookie;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.SocketAddress; import java.net.SocketAddress;
@ -42,8 +33,19 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.WebSocketConstants;
import org.eclipse.jetty.websocket.core.server.Negotiation;
import org.eclipse.jetty.websocket.servlet.internal.UpgradeHttpServletRequest;
/** /**
* Servlet specific Upgrade Request implementation. * Holder of request data for a WebSocket upgrade request.
*/ */
public class ServletUpgradeRequest public class ServletUpgradeRequest
{ {
@ -62,7 +64,9 @@ public class ServletUpgradeRequest
this.queryString = httpRequest.getQueryString(); this.queryString = httpRequest.getQueryString();
this.secure = httpRequest.isSecure(); this.secure = httpRequest.isSecure();
// TODO why is this URL and not URI?
StringBuffer uri = httpRequest.getRequestURL(); StringBuffer uri = httpRequest.getRequestURL();
// WHY?
if (this.queryString != null) if (this.queryString != null)
uri.append("?").append(this.queryString); uri.append("?").append(this.queryString);
uri.replace(0, uri.indexOf(":"), secure?"wss":"ws"); uri.replace(0, uri.indexOf(":"), secure?"wss":"ws");
@ -70,11 +74,18 @@ public class ServletUpgradeRequest
this.request = new UpgradeHttpServletRequest(httpRequest); this.request = new UpgradeHttpServletRequest(httpRequest);
} }
/**
* @return The {@link X509Certificate} instance at request attribute "javax.servlet.request.X509Certificate" or null.
*/
public X509Certificate[] getCertificates() public X509Certificate[] getCertificates()
{ {
return (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate"); return (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
} }
/**
* @see HttpServletRequest#getCookies()
* @return Request cookies
*/
public List<HttpCookie> getCookies() public List<HttpCookie> getCookies()
{ {
if (cookies == null) if (cookies == null)
@ -95,16 +106,30 @@ public class ServletUpgradeRequest
return cookies; return cookies;
} }
/**
* @return The extensions offered
* @see Negotiation#getOfferedExtensions()
*/
public List<ExtensionConfig> getExtensions() public List<ExtensionConfig> getExtensions()
{ {
return negotiation.getOfferedExtensions(); return negotiation.getOfferedExtensions();
} }
/**
* @param name Header name
* @return Header value or null
* @see HttpServletRequest#getHeader(String)
*/
public String getHeader(String name) public String getHeader(String name)
{ {
return request.getHeader(name); return request.getHeader(name);
} }
/**
* @param name Header name
* @return Header value as integer or -1
* @see HttpServletRequest#getHeader(String)
*/
public int getHeaderInt(String name) public int getHeaderInt(String name)
{ {
String val = request.getHeader(name); String val = request.getHeader(name);
@ -115,57 +140,102 @@ public class ServletUpgradeRequest
return Integer.parseInt(val); return Integer.parseInt(val);
} }
/**
* @return Map of headers
* @see UpgradeHttpServletRequest#getHeaders()
*/
public Map<String, List<String>> getHeadersMap() public Map<String, List<String>> getHeadersMap()
{ {
return request.getHeaders(); return request.getHeaders();
} }
/**
* @param name Header name
* @return List of header values or null
* @see UpgradeHttpServletRequest#getHeaders()
*/
public List<String> getHeaders(String name) public List<String> getHeaders(String name)
{ {
return request.getHeaders().get(name); return request.getHeaders().get(name);
} }
/**
* @return The requested host
* @see HttpServletRequest#getRequestURL()
*/
public String getHost() public String getHost()
{ {
// TODO why is this not HttpServletRequest#getHost ?
return requestURI.getHost(); return requestURI.getHost();
} }
/**
* @return Immutable version of {@link HttpServletRequest}
*/
public HttpServletRequest getHttpServletRequest() public HttpServletRequest getHttpServletRequest()
{ {
return request; return request;
} }
/**
* @return The HTTP protocol version
* @see HttpServletRequest#getProtocol()
*/
public String getHttpVersion() public String getHttpVersion()
{ {
return request.getProtocol(); return request.getProtocol();
} }
/**
* @return The requested Locale
* @see HttpServletRequest#getLocale()
*/
public Locale getLocale() public Locale getLocale()
{ {
return request.getLocale(); return request.getLocale();
} }
/**
* @return The requested Locales
* @see HttpServletRequest#getLocales()
*/
public Enumeration<Locale> getLocales() public Enumeration<Locale> getLocales()
{ {
return request.getLocales(); return request.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() public SocketAddress getLocalSocketAddress()
{ {
// TODO: fix when HttpServletRequest can use Unix Socket stuff // TODO: fix when HttpServletRequest can use Unix Socket stuff
return new InetSocketAddress(request.getLocalAddr(), request.getLocalPort()); return new InetSocketAddress(request.getLocalAddr(), request.getLocalPort());
} }
/**
* @return The requested method
* @see HttpServletRequest#getMethod()
*/
public String getMethod() public String getMethod()
{ {
return request.getMethod(); return request.getMethod();
} }
/**
* @return The origin header value
*/
public String getOrigin() public String getOrigin()
{ {
return getHeader("Origin"); return getHeader("Origin");
} }
/**
* @return The request parameter map
* @see ServletRequest#getParameterMap()
*/
public Map<String, List<String>> getParameterMap() public Map<String, List<String>> getParameterMap()
{ {
if (parameterMap == null) if (parameterMap == null)
@ -181,6 +251,9 @@ public class ServletUpgradeRequest
return parameterMap; return parameterMap;
} }
/**
* @return WebSocket protocol version from "Sec-WebSocket-Version" header
*/
public String getProtocolVersion() public String getProtocolVersion()
{ {
String version = request.getHeader(HttpHeader.SEC_WEBSOCKET_VERSION.asString()); String version = request.getHeader(HttpHeader.SEC_WEBSOCKET_VERSION.asString());
@ -191,19 +264,32 @@ public class ServletUpgradeRequest
return version; return version;
} }
/**
* @return The request query string
* @see HttpServletRequest#getQueryString()
*/
public String getQueryString() public String getQueryString()
{ {
return this.queryString; return this.queryString;
} }
/**
* @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() public SocketAddress getRemoteSocketAddress()
{ {
return new InetSocketAddress(request.getRemoteAddr(), request.getRemotePort()); return new InetSocketAddress(request.getRemoteAddr(), request.getRemotePort());
} }
/**
* @return The request URI path within the context
*/
public String getRequestPath() public String getRequestPath()
{ {
// Since this can be called from a filter, we need to be smart about determining the target request path. // Since this can be called from a filter, we need to be smart about determining the target request path.
// TODO probably better adding servletPath and pathInfo
String contextPath = request.getContextPath(); String contextPath = request.getContextPath();
String requestPath = request.getRequestURI(); String requestPath = request.getRequestURI();
if (requestPath.startsWith(contextPath)) if (requestPath.startsWith(contextPath))
@ -211,46 +297,78 @@ public class ServletUpgradeRequest
return requestPath; return requestPath;
} }
/**
* @return The request URI
* @see HttpServletRequest#getRequestURL()
*/
public URI getRequestURI() public URI getRequestURI()
{ {
return requestURI; return requestURI;
} }
/**
* @param name Attribute name
* @return Attribute value or null
* @see ServletRequest#getAttribute(String)
*/
public Object getServletAttribute(String name) public Object getServletAttribute(String name)
{ {
return request.getAttribute(name); return request.getAttribute(name);
} }
/**
* @return Request attribute map
* @see UpgradeHttpServletRequest#getAttributes()
*/
public Map<String, Object> getServletAttributes() public Map<String, Object> getServletAttributes()
{ {
return request.getAttributes(); return request.getAttributes();
} }
/**
* @return Request parameters
* @see ServletRequest#getParameterMap()
*/
public Map<String, List<String>> getServletParameters() public Map<String, List<String>> getServletParameters()
{ {
return getParameterMap(); return getParameterMap();
} }
/**
* @return The HttpSession, which may be null or invalidated
* @see HttpServletRequest#getSession(boolean)
*/
public HttpSession getSession() public HttpSession getSession()
{ {
return request.getSession(false); return request.getSession(false);
} }
/**
* @return Get WebSocket negotiation offered sub protocols
*/
public List<String> getSubProtocols() public List<String> getSubProtocols()
{ {
return negotiation.getOfferedSubprotocols(); return negotiation.getOfferedSubprotocols();
} }
/**
* @return The User's {@link Principal} or null
* @see HttpServletRequest#getUserPrincipal()
*/
public Principal getUserPrincipal() public Principal getUserPrincipal()
{ {
return request.getUserPrincipal(); return request.getUserPrincipal();
} }
public boolean hasSubProtocol(String test) /**
* @param subprotocol A sub protocol name
* @return True if the sub protocol was offered
*/
public boolean hasSubProtocol(String subprotocol)
{ {
for (String protocol : getSubProtocols()) for (String protocol : getSubProtocols())
{ {
if (protocol.equalsIgnoreCase(test)) if (protocol.equalsIgnoreCase(subprotocol))
{ {
return true; return true;
} }
@ -258,16 +376,30 @@ public class ServletUpgradeRequest
return false; return false;
} }
/**
* @return True if the request is secure
* @see ServletRequest#isSecure()
*/
public boolean isSecure() public boolean isSecure()
{ {
return this.secure; return this.secure;
} }
/**
* @param role The user role
* @return True if the requests user has the role
* @see HttpServletRequest#isUserInRole(String)
*/
public boolean isUserInRole(String role) public boolean isUserInRole(String role)
{ {
return request.isUserInRole(role); return request.isUserInRole(role);
} }
/**
* @param name Attribute name
* @param value Attribute value to set
* @see ServletRequest#setAttribute(String, Object)
*/
public void setServletAttribute(String name, Object value) public void setServletAttribute(String name, Object value)
{ {
request.setAttribute(name, value); request.setAttribute(name, value);

View File

@ -33,6 +33,7 @@ import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.websocket.core.FrameHandler; import org.eclipse.jetty.websocket.core.FrameHandler;
import org.eclipse.jetty.websocket.core.WebSocketExtensionRegistry;
/** /**
* Abstract Servlet used to bridge the Servlet API to the WebSocket API. * Abstract Servlet used to bridge the Servlet API to the WebSocket API.
@ -173,6 +174,11 @@ public abstract class WebSocketServlet extends HttpServlet
private class CustomizedWebSocketServletFactory extends FrameHandler.ConfigurationCustomizer implements WebSocketServletFactory private class CustomizedWebSocketServletFactory extends FrameHandler.ConfigurationCustomizer implements WebSocketServletFactory
{ {
public WebSocketExtensionRegistry getExtensionRegistry()
{
return mapping.getExtensionRegistry();
}
@Override @Override
public Duration getDefaultIdleTimeout() public Duration getDefaultIdleTimeout()
{ {

View File

@ -24,6 +24,7 @@ import java.time.Duration;
public interface WebSocketServletFactory public interface WebSocketServletFactory
{ {
Duration getDefaultIdleTimeout(); Duration getDefaultIdleTimeout();
void setDefaultIdleTimeout(Duration duration); void setDefaultIdleTimeout(Duration duration);