diff --git a/jetty-core/jetty-websocket/jetty-websocket-core-common/src/main/java/org/eclipse/jetty/websocket/core/Frame.java b/jetty-core/jetty-websocket/jetty-websocket-core-common/src/main/java/org/eclipse/jetty/websocket/core/Frame.java
index 9feffe21a0b2..2b5d8ac21277 100644
--- a/jetty-core/jetty-websocket/jetty-websocket-core-common/src/main/java/org/eclipse/jetty/websocket/core/Frame.java
+++ b/jetty-core/jetty-websocket/jetty-websocket-core-common/src/main/java/org/eclipse/jetty/websocket/core/Frame.java
@@ -18,7 +18,6 @@
import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.StringUtil;
-import org.eclipse.jetty.util.TypeUtil;
/**
* A Base Frame as seen in RFC 6455. Sec 5.2
@@ -412,7 +411,7 @@ public String toString()
b.append(((finRsvOp & 0x40) != 0) ? '1' : '0');
b.append(((finRsvOp & 0x20) != 0) ? '1' : '0');
b.append(((finRsvOp & 0x10) != 0) ? '1' : '0');
- b.append(",m=").append(mask == null ? "null" : TypeUtil.toHexString(mask));
+ b.append(",m=").append(mask == null ? "null" : StringUtil.toHexString(mask));
b.append(']');
if (payload != null)
b.append(BufferUtil.toDetailString(payload));
diff --git a/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/ServerUpgradeRequest.java b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/ServerUpgradeRequest.java
index 224072aef7ce..d438b4150f2c 100644
--- a/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/ServerUpgradeRequest.java
+++ b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/ServerUpgradeRequest.java
@@ -14,131 +14,23 @@
package org.eclipse.jetty.websocket.core.server;
import java.util.List;
-import java.util.Set;
-import org.eclipse.jetty.http.BadMessageException;
-import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.util.Attributes;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
import org.eclipse.jetty.websocket.core.WebSocketComponents;
-import org.eclipse.jetty.websocket.core.WebSocketConstants;
-import org.eclipse.jetty.websocket.core.server.internal.WebSocketNegotiation;
-/**
- * Upgrade request used for websocket negotiation.
- * Provides getters for things like the requested extensions and subprotocols so that the headers don't have to be parsed manually.
- */
-public class ServerUpgradeRequest extends Request.Wrapper
+public interface ServerUpgradeRequest extends Request
{
- private final Request request;
- private final WebSocketNegotiation negotiation;
- private final Attributes attributes = new Attributes.Lazy();
- private boolean upgraded = false;
+ WebSocketComponents getWebSocketComponents();
- public ServerUpgradeRequest(WebSocketNegotiation negotiation, Request baseRequest) throws BadMessageException
- {
- super(baseRequest);
- this.negotiation = negotiation;
- this.request = baseRequest;
- }
+ void upgrade(Attributes attributes);
- public WebSocketComponents getWebSocketComponents()
- {
- return negotiation.getWebSocketComponents();
- }
+ List getExtensions();
- public void upgrade(Attributes attributes)
- {
- this.attributes.clearAttributes();
- for (String name : attributes.getAttributeNameSet())
- {
- this.attributes.setAttribute(name, attributes.getAttribute(name));
- }
- upgraded = true;
- }
+ String getProtocolVersion();
- @Override
- public Object removeAttribute(String name)
- {
- if (upgraded)
- return attributes.removeAttribute(name);
- return super.removeAttribute(name);
- }
+ List getSubProtocols();
- @Override
- public Object setAttribute(String name, Object attribute)
- {
- if (upgraded)
- return attributes.setAttribute(name, attribute);
- return super.setAttribute(name, attribute);
- }
-
- @Override
- public Object getAttribute(String name)
- {
- if (upgraded)
- return attributes.getAttribute(name);
- return super.getAttribute(name);
- }
-
- @Override
- public Set getAttributeNameSet()
- {
- if (upgraded)
- return attributes.getAttributeNameSet();
- return super.getAttributeNameSet();
- }
-
- @Override
- public void clearAttributes()
- {
- if (upgraded)
- attributes.clearAttributes();
- else
- super.clearAttributes();
- }
-
- /**
- * @return The extensions offered
- */
- public List getExtensions()
- {
- return negotiation.getOfferedExtensions();
- }
-
- /**
- * @return WebSocket protocol version from "Sec-WebSocket-Version" header
- */
- public String getProtocolVersion()
- {
- String version = request.getHeaders().get(HttpHeader.SEC_WEBSOCKET_VERSION.asString());
- if (version == null)
- {
- return Integer.toString(WebSocketConstants.SPEC_VERSION);
- }
- return version;
- }
-
- /**
- * @return Get WebSocket negotiation offered sub protocols
- */
- public List getSubProtocols()
- {
- return negotiation.getOfferedSubprotocols();
- }
-
- /**
- * @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(subprotocol))
- return true;
- }
- return false;
- }
+ boolean hasSubProtocol(String subprotocol);
}
diff --git a/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/ServerUpgradeResponse.java b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/ServerUpgradeResponse.java
index 856fc1714ba7..6cb897aab451 100644
--- a/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/ServerUpgradeResponse.java
+++ b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/ServerUpgradeResponse.java
@@ -13,84 +13,20 @@
package org.eclipse.jetty.websocket.core.server;
-import java.util.ArrayList;
import java.util.List;
-import org.eclipse.jetty.http.HttpFields;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.websocket.core.ExtensionConfig;
-import org.eclipse.jetty.websocket.core.server.internal.WebSocketHttpFieldsWrapper;
-import org.eclipse.jetty.websocket.core.server.internal.WebSocketNegotiation;
-/**
- * Upgrade response used for websocket negotiation.
- * Allows setting of extensions and subprotocol without using headers directly.
- */
-public class ServerUpgradeResponse extends Response.Wrapper
+public interface ServerUpgradeResponse extends Response
{
- private final Response response;
- private final WebSocketNegotiation negotiation;
- private final HttpFields.Mutable fields;
+ String getAcceptedSubProtocol();
- public ServerUpgradeResponse(WebSocketNegotiation negotiation, Response baseResponse)
- {
- super(baseResponse.getRequest(), baseResponse);
- this.negotiation = negotiation;
- this.response = baseResponse;
- this.fields = new WebSocketHttpFieldsWrapper(response.getHeaders(), this, negotiation);
- }
+ void setAcceptedSubProtocol(String protocol);
- @Override
- public HttpFields.Mutable getHeaders()
- {
- return fields;
- }
+ List getExtensions();
- public String getAcceptedSubProtocol()
- {
- return negotiation.getSubprotocol();
- }
+ void addExtensions(List configs);
- public void setAcceptedSubProtocol(String protocol)
- {
- negotiation.setSubprotocol(protocol);
- }
-
- public List getExtensions()
- {
- return negotiation.getNegotiatedExtensions();
- }
-
- public void addExtensions(List configs)
- {
- ArrayList combinedConfig = new ArrayList<>();
- combinedConfig.addAll(getExtensions());
- combinedConfig.addAll(configs);
- setExtensions(combinedConfig);
- }
-
- public void setExtensions(List configs)
- {
- // This validation is also done later in RFC6455Handshaker but it is better to fail earlier
- for (ExtensionConfig config : configs)
- {
- if (config.getName().startsWith("@"))
- continue;
-
- long matches = negotiation.getOfferedExtensions().stream().filter(e -> e.getName().equals(config.getName())).count();
- if (matches < 1)
- throw new IllegalArgumentException("Extension not a requested extension");
-
- matches = configs.stream().filter(e -> e.getName().equals(config.getName())).count();
- if (matches > 1)
- throw new IllegalArgumentException("Multiple extensions of the same name");
- }
-
- negotiation.setNegotiatedExtensions(configs);
- }
-
- public String toString()
- {
- return String.format("UpgradeResponse=%s", response);
- }
+ void setExtensions(List configs);
}
diff --git a/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/ServerUpgradeRequestImpl.java b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/ServerUpgradeRequestImpl.java
new file mode 100644
index 000000000000..4227e11c8ba9
--- /dev/null
+++ b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/ServerUpgradeRequestImpl.java
@@ -0,0 +1,150 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+// ========================================================================
+//
+
+package org.eclipse.jetty.websocket.core.server.internal;
+
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jetty.http.BadMessageException;
+import org.eclipse.jetty.http.HttpHeader;
+import org.eclipse.jetty.server.Request;
+import org.eclipse.jetty.util.Attributes;
+import org.eclipse.jetty.websocket.core.ExtensionConfig;
+import org.eclipse.jetty.websocket.core.WebSocketComponents;
+import org.eclipse.jetty.websocket.core.WebSocketConstants;
+import org.eclipse.jetty.websocket.core.server.ServerUpgradeRequest;
+
+/**
+ * Upgrade request used for websocket negotiation.
+ * Provides getters for things like the requested extensions and subprotocols so that the headers don't have to be parsed manually.
+ */
+public class ServerUpgradeRequestImpl extends Request.Wrapper implements ServerUpgradeRequest
+{
+ private final Request request;
+ private final WebSocketNegotiation negotiation;
+ private final Attributes attributes = new Attributes.Lazy();
+ private boolean upgraded = false;
+
+ public ServerUpgradeRequestImpl(WebSocketNegotiation negotiation, Request baseRequest) throws BadMessageException
+ {
+ super(baseRequest);
+ this.negotiation = negotiation;
+ this.request = baseRequest;
+ }
+
+ @Override
+ public WebSocketComponents getWebSocketComponents()
+ {
+ return negotiation.getWebSocketComponents();
+ }
+
+ @Override
+ public void upgrade(Attributes attributes)
+ {
+ this.attributes.clearAttributes();
+ for (String name : attributes.getAttributeNameSet())
+ {
+ this.attributes.setAttribute(name, attributes.getAttribute(name));
+ }
+ upgraded = true;
+ }
+
+ @Override
+ public Object removeAttribute(String name)
+ {
+ if (upgraded)
+ return attributes.removeAttribute(name);
+ return super.removeAttribute(name);
+ }
+
+ @Override
+ public Object setAttribute(String name, Object attribute)
+ {
+ if (upgraded)
+ return attributes.setAttribute(name, attribute);
+ return super.setAttribute(name, attribute);
+ }
+
+ @Override
+ public Object getAttribute(String name)
+ {
+ if (upgraded)
+ return attributes.getAttribute(name);
+ return super.getAttribute(name);
+ }
+
+ @Override
+ public Set getAttributeNameSet()
+ {
+ if (upgraded)
+ return attributes.getAttributeNameSet();
+ return super.getAttributeNameSet();
+ }
+
+ @Override
+ public void clearAttributes()
+ {
+ if (upgraded)
+ attributes.clearAttributes();
+ else
+ super.clearAttributes();
+ }
+
+ /**
+ * @return The extensions offered
+ */
+ @Override
+ public List getExtensions()
+ {
+ return negotiation.getOfferedExtensions();
+ }
+
+ /**
+ * @return WebSocket protocol version from "Sec-WebSocket-Version" header
+ */
+ @Override
+ public String getProtocolVersion()
+ {
+ String version = request.getHeaders().get(HttpHeader.SEC_WEBSOCKET_VERSION.asString());
+ if (version == null)
+ {
+ return Integer.toString(WebSocketConstants.SPEC_VERSION);
+ }
+ return version;
+ }
+
+ /**
+ * @return Get WebSocket negotiation offered sub protocols
+ */
+ @Override
+ public List getSubProtocols()
+ {
+ return negotiation.getOfferedSubprotocols();
+ }
+
+ /**
+ * @param subprotocol A sub protocol name
+ * @return True if the sub protocol was offered
+ */
+ @Override
+ public boolean hasSubProtocol(String subprotocol)
+ {
+ for (String protocol : getSubProtocols())
+ {
+ if (protocol.equalsIgnoreCase(subprotocol))
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/ServerUpgradeResponseImpl.java b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/ServerUpgradeResponseImpl.java
new file mode 100644
index 000000000000..264f6e749743
--- /dev/null
+++ b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/ServerUpgradeResponseImpl.java
@@ -0,0 +1,100 @@
+//
+// ========================================================================
+// Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
+//
+// This program and the accompanying materials are made available under the
+// terms of the Eclipse Public License v. 2.0 which is available at
+// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
+// which is available at https://www.apache.org/licenses/LICENSE-2.0.
+//
+// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
+// ========================================================================
+//
+
+package org.eclipse.jetty.websocket.core.server.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jetty.http.HttpFields;
+import org.eclipse.jetty.server.Response;
+import org.eclipse.jetty.websocket.core.ExtensionConfig;
+import org.eclipse.jetty.websocket.core.server.ServerUpgradeResponse;
+
+/**
+ * Upgrade response used for websocket negotiation.
+ * Allows setting of extensions and subprotocol without using headers directly.
+ */
+public class ServerUpgradeResponseImpl extends Response.Wrapper implements ServerUpgradeResponse
+{
+ private final Response response;
+ private final WebSocketNegotiation negotiation;
+ private final HttpFields.Mutable fields;
+
+ public ServerUpgradeResponseImpl(WebSocketNegotiation negotiation, Response baseResponse)
+ {
+ super(baseResponse.getRequest(), baseResponse);
+ this.negotiation = negotiation;
+ this.response = baseResponse;
+ this.fields = new WebSocketHttpFieldsWrapper(response.getHeaders(), this, negotiation);
+ }
+
+ @Override
+ public HttpFields.Mutable getHeaders()
+ {
+ return fields;
+ }
+
+ @Override
+ public String getAcceptedSubProtocol()
+ {
+ return negotiation.getSubprotocol();
+ }
+
+ @Override
+ public void setAcceptedSubProtocol(String protocol)
+ {
+ negotiation.setSubprotocol(protocol);
+ }
+
+ @Override
+ public List getExtensions()
+ {
+ return negotiation.getNegotiatedExtensions();
+ }
+
+ @Override
+ public void addExtensions(List configs)
+ {
+ ArrayList combinedConfig = new ArrayList<>();
+ combinedConfig.addAll(getExtensions());
+ combinedConfig.addAll(configs);
+ setExtensions(combinedConfig);
+ }
+
+ @Override
+ public void setExtensions(List configs)
+ {
+ // This validation is also done later in RFC6455Handshaker but it is better to fail earlier
+ for (ExtensionConfig config : configs)
+ {
+ if (config.getName().startsWith("@"))
+ continue;
+
+ long matches = negotiation.getOfferedExtensions().stream().filter(e -> e.getName().equals(config.getName())).count();
+ if (matches < 1)
+ throw new IllegalArgumentException("Extension not a requested extension");
+
+ matches = configs.stream().filter(e -> e.getName().equals(config.getName())).count();
+ if (matches > 1)
+ throw new IllegalArgumentException("Multiple extensions of the same name");
+ }
+
+ negotiation.setNegotiatedExtensions(configs);
+ }
+
+ public String toString()
+ {
+ return String.format("UpgradeResponse=%s", response);
+ }
+}
diff --git a/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/WebSocketNegotiation.java b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/WebSocketNegotiation.java
index 5a2b516cc998..c11b18bb924b 100644
--- a/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/WebSocketNegotiation.java
+++ b/jetty-core/jetty-websocket/jetty-websocket-core-server/src/main/java/org/eclipse/jetty/websocket/core/server/internal/WebSocketNegotiation.java
@@ -45,8 +45,8 @@ public abstract class WebSocketNegotiation
public WebSocketNegotiation(Request request, Response response, Callback callback, WebSocketComponents webSocketComponents)
{
- this.request = new ServerUpgradeRequest(this, request);
- this.response = new ServerUpgradeResponse(this, response);
+ this.request = new ServerUpgradeRequestImpl(this, request);
+ this.response = new ServerUpgradeResponseImpl(this, response);
this.callback = callback;
this.components = webSocketComponents;
}