diff --git a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
index 38bb2f5a1b7..5864f928389 100644
--- a/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
+++ b/examples/embedded/src/main/java/org/eclipse/jetty/embedded/WebSocketJsrServer.java
@@ -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();
diff --git a/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-13.mod b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-13.mod
new file mode 100644
index 00000000000..689601a4197
--- /dev/null
+++ b/jetty-alpn/jetty-alpn-server/src/main/config/modules/alpn-impl/alpn-13.mod
@@ -0,0 +1,4 @@
+DO NOT EDIT - See: https://www.eclipse.org/jetty/documentation/current/startup-modules.html
+
+[depend]
+alpn-impl/alpn-9
diff --git a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java
index ad44afff3e7..5322c215657 100644
--- a/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java
+++ b/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java
@@ -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,
diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java
index 5436006635f..49d1b3542b0 100644
--- a/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java
+++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ProxyConnectionFactory.java
@@ -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()
{
diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java
index e71555ef7cd..5ecf8e6cbda 100644
--- a/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java
+++ b/jetty-util/src/main/java/org/eclipse/jetty/util/component/Dumpable.java
@@ -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","|");
diff --git a/jetty-websocket/jetty-websocket-server/pom.xml b/jetty-websocket/jetty-websocket-server/pom.xml
index 8a9be182b40..a63620025b1 100644
--- a/jetty-websocket/jetty-websocket-server/pom.xml
+++ b/jetty-websocket/jetty-websocket-server/pom.xml
@@ -32,6 +32,12 @@
jetty-server
${project.version}
+
+ org.eclipse.jetty
+ jetty-jmx
+ ${project.version}
+ provided
+
org.eclipse.jetty.websocket
jetty-websocket-api
diff --git a/jetty-websocket/jetty-websocket-server/src/main/java/module-info.java b/jetty-websocket/jetty-websocket-server/src/main/java/module-info.java
index ada32d8c283..745cff9d63a 100644
--- a/jetty-websocket/jetty-websocket-server/src/main/java/module-info.java
+++ b/jetty-websocket/jetty-websocket-server/src/main/java/module-info.java
@@ -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;
diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/AbstractExtension.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/AbstractExtension.java
index b034d47abdc..35a71b3209f 100644
--- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/AbstractExtension.java
+++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/AbstractExtension.java
@@ -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)
{
diff --git a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/internal/ExtensionStack.java b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/internal/ExtensionStack.java
index 30d385490b2..eff21089020 100644
--- a/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/internal/ExtensionStack.java
+++ b/jetty-websocket/websocket-core/src/main/java/org/eclipse/jetty/websocket/core/internal/ExtensionStack.java
@@ -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()
{
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/FrameHandlerFactory.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/FrameHandlerFactory.java
index 2a781fe88ab..395b06af06c 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/FrameHandlerFactory.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/FrameHandlerFactory.java
@@ -20,7 +20,9 @@ package org.eclipse.jetty.websocket.servlet;
import org.eclipse.jetty.websocket.core.FrameHandler;
-
+/**
+ * Factory for FrameHandler instances
+ */
public interface FrameHandlerFactory
{
/**
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java
index 81715bb2d8e..b073df0ef18 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java
@@ -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 getCookies()
{
if (cookies == null)
@@ -95,16 +106,30 @@ public class ServletUpgradeRequest
return cookies;
}
+ /**
+ * @return The extensions offered
+ * @see Negotiation#getOfferedExtensions()
+ */
public List 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> getHeadersMap()
{
return request.getHeaders();
}
+ /**
+ * @param name Header name
+ * @return List of header values or null
+ * @see UpgradeHttpServletRequest#getHeaders()
+ */
public List 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 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> 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 getServletAttributes()
{
return request.getAttributes();
}
+ /**
+ * @return Request parameters
+ * @see ServletRequest#getParameterMap()
+ */
public Map> 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 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);
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java
index 394688689f3..47dfb5c8c33 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServlet.java
@@ -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()
{
diff --git a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
index 8b839beae6b..04d5528d677 100644
--- a/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
+++ b/jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/WebSocketServletFactory.java
@@ -24,6 +24,7 @@ import java.time.Duration;
public interface WebSocketServletFactory
{
+
Duration getDefaultIdleTimeout();
void setDefaultIdleTimeout(Duration duration);