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 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.websocket.javax.server.JavaxWebSocketServerContainerInitializer;
@ -49,10 +51,12 @@ public class WebSocketJsrServer
{
Server server = new Server(8080);
HandlerList handlers = new HandlerList();
ServletContextHandler context = new ServletContextHandler(
ServletContextHandler.SESSIONS);
context.setContextPath("/");
server.setHandler(context);
handlers.addHandler(context);
// Enable javax.websocket configuration for the context
ServerContainer wsContainer = JavaxWebSocketServerContainerInitializer
@ -61,6 +65,9 @@ public class WebSocketJsrServer
// Add your websockets to the container
wsContainer.addEndpoint(EchoJsrSocket.class);
handlers.addHandler(new DefaultHandler());
server.setHandler(handlers);
server.start();
context.dumpStdErr();
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());
_log.debug("{} proxying to upstream:{}{}{}{}",
_log.debug("{} proxying to upstream:{}{}{}{}{}",
getRequestId(clientRequest),
System.lineSeparator(),
builder,

View File

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

View File

@ -69,6 +69,15 @@ public interface Dumpable
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.
@ -89,6 +98,8 @@ public interface Dumpable
s = String.format("%s@%x[size=%d]",o.getClass().getComponentType(),o.hashCode(), Array.getLength(o));
else if (o instanceof Map)
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
s = String.valueOf(o).replace("\r\n","|").replace("\n","|");

View File

@ -32,6 +32,12 @@
<artifactId>jetty-server</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-jmx</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<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.http;
requires org.eclipse.jetty.server;
requires static org.eclipse.jetty.jmx;
requires org.eclipse.jetty.servlet;
requires org.eclipse.jetty.webapp;
requires org.eclipse.jetty.websocket.jetty.api;

View File

@ -18,16 +18,19 @@
package org.eclipse.jetty.websocket.core;
import java.io.IOException;
import org.eclipse.jetty.io.ByteBufferPool;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.annotation.ManagedAttribute;
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.Logger;
import org.eclipse.jetty.websocket.core.internal.WebSocketChannel;
@ManagedObject("Abstract Extension")
public abstract class AbstractExtension implements Extension
public abstract class AbstractExtension implements Extension, Dumpable
{
private final Logger log;
private ByteBufferPool bufferPool;
@ -41,6 +44,27 @@ public abstract class AbstractExtension implements Extension
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
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);
}
@Override
public String dumpSelf()
{
return String.format("%s@%x[size=%d,queueSize=%d]", getClass().getSimpleName(), hashCode(), extensions.size(), getQueueSize());
}
@Override
public String toString()
{

View File

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

View File

@ -18,15 +18,6 @@
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.InetSocketAddress;
import java.net.SocketAddress;
@ -42,8 +33,19 @@ import java.util.List;
import java.util.Locale;
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
{
@ -62,7 +64,9 @@ public class ServletUpgradeRequest
this.queryString = httpRequest.getQueryString();
this.secure = httpRequest.isSecure();
// TODO why is this URL and not URI?
StringBuffer uri = httpRequest.getRequestURL();
// WHY?
if (this.queryString != null)
uri.append("?").append(this.queryString);
uri.replace(0, uri.indexOf(":"), secure?"wss":"ws");
@ -70,11 +74,18 @@ public class ServletUpgradeRequest
this.request = new UpgradeHttpServletRequest(httpRequest);
}
/**
* @return The {@link X509Certificate} instance at request attribute "javax.servlet.request.X509Certificate" or null.
*/
public X509Certificate[] getCertificates()
{
return (X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
}
/**
* @see HttpServletRequest#getCookies()
* @return Request cookies
*/
public List<HttpCookie> getCookies()
{
if (cookies == null)
@ -95,16 +106,30 @@ public class ServletUpgradeRequest
return cookies;
}
/**
* @return The extensions offered
* @see Negotiation#getOfferedExtensions()
*/
public List<ExtensionConfig> getExtensions()
{
return negotiation.getOfferedExtensions();
}
/**
* @param name Header name
* @return Header value or null
* @see HttpServletRequest#getHeader(String)
*/
public String getHeader(String 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)
{
String val = request.getHeader(name);
@ -115,57 +140,102 @@ public class ServletUpgradeRequest
return Integer.parseInt(val);
}
/**
* @return Map of headers
* @see UpgradeHttpServletRequest#getHeaders()
*/
public Map<String, List<String>> getHeadersMap()
{
return request.getHeaders();
}
/**
* @param name Header name
* @return List of header values or null
* @see UpgradeHttpServletRequest#getHeaders()
*/
public List<String> getHeaders(String name)
{
return request.getHeaders().get(name);
}
/**
* @return The requested host
* @see HttpServletRequest#getRequestURL()
*/
public String getHost()
{
// TODO why is this not HttpServletRequest#getHost ?
return requestURI.getHost();
}
/**
* @return Immutable version of {@link HttpServletRequest}
*/
public HttpServletRequest getHttpServletRequest()
{
return request;
}
/**
* @return The HTTP protocol version
* @see HttpServletRequest#getProtocol()
*/
public String getHttpVersion()
{
return request.getProtocol();
}
/**
* @return The requested Locale
* @see HttpServletRequest#getLocale()
*/
public Locale getLocale()
{
return request.getLocale();
}
/**
* @return The requested Locales
* @see HttpServletRequest#getLocales()
*/
public Enumeration<Locale> 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()
{
// TODO: fix when HttpServletRequest can use Unix Socket stuff
return new InetSocketAddress(request.getLocalAddr(), request.getLocalPort());
}
/**
* @return The requested method
* @see HttpServletRequest#getMethod()
*/
public String getMethod()
{
return request.getMethod();
}
/**
* @return The origin header value
*/
public String getOrigin()
{
return getHeader("Origin");
}
/**
* @return The request parameter map
* @see ServletRequest#getParameterMap()
*/
public Map<String, List<String>> getParameterMap()
{
if (parameterMap == null)
@ -181,6 +251,9 @@ public class ServletUpgradeRequest
return parameterMap;
}
/**
* @return WebSocket protocol version from "Sec-WebSocket-Version" header
*/
public String getProtocolVersion()
{
String version = request.getHeader(HttpHeader.SEC_WEBSOCKET_VERSION.asString());
@ -191,19 +264,32 @@ public class ServletUpgradeRequest
return version;
}
/**
* @return The request query string
* @see HttpServletRequest#getQueryString()
*/
public String getQueryString()
{
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()
{
return new InetSocketAddress(request.getRemoteAddr(), request.getRemotePort());
}
/**
* @return The request URI path within the context
*/
public String getRequestPath()
{
// 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 requestPath = request.getRequestURI();
if (requestPath.startsWith(contextPath))
@ -211,46 +297,78 @@ public class ServletUpgradeRequest
return requestPath;
}
/**
* @return The request URI
* @see HttpServletRequest#getRequestURL()
*/
public URI getRequestURI()
{
return requestURI;
}
/**
* @param name Attribute name
* @return Attribute value or null
* @see ServletRequest#getAttribute(String)
*/
public Object getServletAttribute(String name)
{
return request.getAttribute(name);
}
/**
* @return Request attribute map
* @see UpgradeHttpServletRequest#getAttributes()
*/
public Map<String, Object> getServletAttributes()
{
return request.getAttributes();
}
/**
* @return Request parameters
* @see ServletRequest#getParameterMap()
*/
public Map<String, List<String>> getServletParameters()
{
return getParameterMap();
}
/**
* @return The HttpSession, which may be null or invalidated
* @see HttpServletRequest#getSession(boolean)
*/
public HttpSession getSession()
{
return request.getSession(false);
}
/**
* @return Get WebSocket negotiation offered sub protocols
*/
public List<String> getSubProtocols()
{
return negotiation.getOfferedSubprotocols();
}
/**
* @return The User's {@link Principal} or null
* @see HttpServletRequest#getUserPrincipal()
*/
public Principal 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())
{
if (protocol.equalsIgnoreCase(test))
if (protocol.equalsIgnoreCase(subprotocol))
{
return true;
}
@ -258,16 +376,30 @@ public class ServletUpgradeRequest
return false;
}
/**
* @return True if the request is secure
* @see ServletRequest#isSecure()
*/
public boolean isSecure()
{
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)
{
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)
{
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.Logger;
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.
@ -173,6 +174,11 @@ public abstract class WebSocketServlet extends HttpServlet
private class CustomizedWebSocketServletFactory extends FrameHandler.ConfigurationCustomizer implements WebSocketServletFactory
{
public WebSocketExtensionRegistry getExtensionRegistry()
{
return mapping.getExtensionRegistry();
}
@Override
public Duration getDefaultIdleTimeout()
{

View File

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