Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java11
-rw-r--r--jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java146
-rw-r--r--jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java39
-rw-r--r--jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java18
-rw-r--r--jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java5
-rw-r--r--jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties2
-rw-r--r--jetty-websocket/websocket-servlet/src/main/java/org/eclipse/jetty/websocket/servlet/ServletUpgradeRequest.java13
7 files changed, 185 insertions, 49 deletions
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java
index 8729131d34..f72359982b 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/UpgradeRequest.java
@@ -187,7 +187,7 @@ public class UpgradeRequest
{
return Collections.unmodifiableMap(parameters);
}
-
+
public String getProtocolVersion()
{
String version = getHeader("Sec-WebSocket-Version");
@@ -265,6 +265,15 @@ public class UpgradeRequest
this.cookies = cookies;
}
+ public void setExtensions(List<ExtensionConfig> configs)
+ {
+ this.extensions.clear();
+ if (configs != null)
+ {
+ this.extensions.addAll(configs);
+ }
+ }
+
public void setHeader(String name, List<String> values)
{
headers.put(name,values);
diff --git a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java
index 329dbea81c..d7ade452aa 100644
--- a/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java
+++ b/jetty-websocket/websocket-api/src/main/java/org/eclipse/jetty/websocket/api/extensions/ExtensionConfig.java
@@ -18,8 +18,11 @@
package org.eclipse.jetty.websocket.api.extensions;
+import java.util.ArrayList;
+import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -30,39 +33,99 @@ import org.eclipse.jetty.websocket.api.util.QuoteUtil;
*/
public class ExtensionConfig
{
+ /**
+ * Parse a single parameterized name.
+ *
+ * @param parameterizedName
+ * the parameterized name
+ * @return the ExtensionConfig
+ */
public static ExtensionConfig parse(String parameterizedName)
{
- Iterator<String> extListIter = QuoteUtil.splitAt(parameterizedName,";");
- String extToken = extListIter.next();
+ return new ExtensionConfig(parameterizedName);
+ }
- ExtensionConfig ext = new ExtensionConfig(extToken);
+ /**
+ * Parse enumeration of <code>Sec-WebSocket-Extensions</code> header values into a {@link ExtensionConfig} list
+ *
+ * @param valuesEnum
+ * the raw header values enum
+ * @return the list of extension configs
+ */
+ public static List<ExtensionConfig> parseEnum(Enumeration<String> valuesEnum)
+ {
+ List<ExtensionConfig> configs = new ArrayList<>();
- // now for parameters
- while (extListIter.hasNext())
+ if (valuesEnum != null)
{
- String extParam = extListIter.next();
- Iterator<String> extParamIter = QuoteUtil.splitAt(extParam,"=");
- String key = extParamIter.next().trim();
- String value = null;
- if (extParamIter.hasNext())
+ while (valuesEnum.hasMoreElements())
{
- value = extParamIter.next();
+ Iterator<String> extTokenIter = QuoteUtil.splitAt(valuesEnum.nextElement(),",");
+ while (extTokenIter.hasNext())
+ {
+ String extToken = extTokenIter.next();
+ configs.add(ExtensionConfig.parse(extToken));
+ }
}
- ext.setParameter(key,value);
}
- return ext;
+ return configs;
}
- private final String name;
- private Map<String, String> parameters;
+ /**
+ * Parse 1 or more raw <code>Sec-WebSocket-Extensions</code> header values into a {@link ExtensionConfig} list
+ *
+ * @param rawSecWebSocketExtensions
+ * the raw header values
+ * @return the list of extension configs
+ */
+ public static List<ExtensionConfig> parseList(String... rawSecWebSocketExtensions)
+ {
+ List<ExtensionConfig> configs = new ArrayList<>();
+
+ for (String rawValue : rawSecWebSocketExtensions)
+ {
+ Iterator<String> extTokenIter = QuoteUtil.splitAt(rawValue,",");
+ while (extTokenIter.hasNext())
+ {
+ String extToken = extTokenIter.next();
+ configs.add(ExtensionConfig.parse(extToken));
+ }
+ }
+
+ return configs;
+ }
- public ExtensionConfig(String name)
+ /**
+ * Convert a list of {@link ExtensionConfig} to a header value
+ *
+ * @param configs
+ * the list of extension configs
+ * @return the header value (null if no configs present)
+ */
+ public static String toHeaderValue(List<ExtensionConfig> configs)
{
- this.name = name;
- this.parameters = new HashMap<>();
+ if ((configs == null) || (configs.isEmpty()))
+ {
+ return null;
+ }
+ StringBuilder parameters = new StringBuilder();
+ boolean needsDelim = false;
+ for (ExtensionConfig ext : configs)
+ {
+ if (needsDelim)
+ {
+ parameters.append(", ");
+ }
+ parameters.append(ext.getParameterizedName());
+ needsDelim = true;
+ }
+ return parameters.toString();
}
+ private final String name;
+ private final Map<String, String> parameters;
+
/**
* Copy constructor
*/
@@ -73,12 +136,33 @@ public class ExtensionConfig
this.parameters.putAll(copy.parameters);
}
+ public ExtensionConfig(String parameterizedName)
+ {
+ Iterator<String> extListIter = QuoteUtil.splitAt(parameterizedName,";");
+ this.name = extListIter.next();
+ this.parameters = new HashMap<>();
+
+ // now for parameters
+ while (extListIter.hasNext())
+ {
+ String extParam = extListIter.next();
+ Iterator<String> extParamIter = QuoteUtil.splitAt(extParam,"=");
+ String key = extParamIter.next().trim();
+ String value = null;
+ if (extParamIter.hasNext())
+ {
+ value = extParamIter.next();
+ }
+ parameters.put(key,value);
+ }
+ }
+
public String getName()
{
return name;
}
- public int getParameter(String key, int defValue)
+ public final int getParameter(String key, int defValue)
{
String val = parameters.get(key);
if (val == null)
@@ -88,7 +172,7 @@ public class ExtensionConfig
return Integer.valueOf(val);
}
- public String getParameter(String key, String defValue)
+ public final String getParameter(String key, String defValue)
{
String val = parameters.get(key);
if (val == null)
@@ -98,7 +182,7 @@ public class ExtensionConfig
return val;
}
- public String getParameterizedName()
+ public final String getParameterizedName()
{
StringBuilder str = new StringBuilder();
str.append(name);
@@ -116,7 +200,7 @@ public class ExtensionConfig
return str.toString();
}
- public Set<String> getParameterKeys()
+ public final Set<String> getParameterKeys()
{
return parameters.keySet();
}
@@ -126,7 +210,7 @@ public class ExtensionConfig
*
* @return the parameter map
*/
- public Map<String, String> getParameters()
+ public final Map<String, String> getParameters()
{
return parameters;
}
@@ -137,25 +221,25 @@ public class ExtensionConfig
* @param other
* the other configuration.
*/
- public void init(ExtensionConfig other)
+ public final void init(ExtensionConfig other)
{
this.parameters.clear();
this.parameters.putAll(other.parameters);
}
- public void setParameter(String key, int value)
+ public final void setParameter(String key)
{
- parameters.put(key,Integer.toString(value));
+ parameters.put(key,null);
}
- public void setParameter(String key, String value)
+ public final void setParameter(String key, int value)
{
- parameters.put(key,value);
+ parameters.put(key,Integer.toString(value));
}
-
- public void setParameter(String key)
+
+ public final void setParameter(String key, String value)
{
- parameters.put(key,null);
+ parameters.put(key,value);
}
@Override
diff --git a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java
index ef39b3394d..b0344550da 100644
--- a/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java
+++ b/jetty-websocket/websocket-common/src/main/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStack.java
@@ -46,6 +46,7 @@ import org.eclipse.jetty.websocket.common.Parser;
public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames, OutgoingFrames
{
private static final Logger LOG = Log.getLogger(ExtensionStack.class);
+
private final ExtensionFactory factory;
private List<Extension> extensions;
private IncomingFrames nextIncoming;
@@ -215,6 +216,9 @@ public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames
{
LOG.debug("Extension Configs={}",configs);
this.extensions = new ArrayList<>();
+
+ String rsvClaims[] = new String[3];
+
for (ExtensionConfig config : configs)
{
Extension ext = factory.newInstance(config);
@@ -223,8 +227,41 @@ public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames
// Extension not present on this side
continue;
}
+
+ // Check RSV
+ if (ext.isRsv1User() && (rsvClaims[0] != null))
+ {
+ LOG.debug("Not adding extension {}. Extension {} already claimed RSV1",config,rsvClaims[0]);
+ continue;
+ }
+ if (ext.isRsv2User() && (rsvClaims[1] != null))
+ {
+ LOG.debug("Not adding extension {}. Extension {} already claimed RSV2",config,rsvClaims[1]);
+ continue;
+ }
+ if (ext.isRsv3User() && (rsvClaims[2] != null))
+ {
+ LOG.debug("Not adding extension {}. Extension {} already claimed RSV3",config,rsvClaims[2]);
+ continue;
+ }
+
+ // Add Extension
extensions.add(ext);
- LOG.debug("Adding Extension: {}",ext);
+ LOG.debug("Adding Extension: {}",config);
+
+ // Record RSV Claims
+ if (ext.isRsv1User())
+ {
+ rsvClaims[0] = ext.getName();
+ }
+ if (ext.isRsv2User())
+ {
+ rsvClaims[1] = ext.getName();
+ }
+ if (ext.isRsv3User())
+ {
+ rsvClaims[2] = ext.getName();
+ }
}
addBean(extensions);
diff --git a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java
index 0f9a6aedd9..28b2b5f257 100644
--- a/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java
+++ b/jetty-websocket/websocket-common/src/test/java/org/eclipse/jetty/websocket/common/extensions/ExtensionStackTest.java
@@ -18,7 +18,7 @@
package org.eclipse.jetty.websocket.common.extensions;
-import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.*;
import java.util.ArrayList;
import java.util.List;
@@ -168,4 +168,20 @@ public class ExtensionStackTest
// Shouldn't cause a NPE.
LOG.debug("Shouldn't cause a NPE: {}",stack.toString());
}
+
+ @Test
+ public void testNegotiateChrome32()
+ {
+ ExtensionStack stack = createExtensionStack();
+
+ String chromeRequest = "permessage-deflate; client_max_window_bits, x-webkit-deflate-frame";
+ List<ExtensionConfig> requestedConfigs = ExtensionConfig.parseList(chromeRequest);
+ stack.negotiate(requestedConfigs);
+
+ List<ExtensionConfig> negotiated = stack.getNegotiatedExtensions();
+ String response = ExtensionConfig.toHeaderValue(negotiated);
+
+ Assert.assertThat("Negotiated Extensions", response, is("permessage-deflate"));
+ LOG.debug("Shouldn't cause a NPE: {}",stack.toString());
+ }
}
diff --git a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java
index aee3a73aa1..85fde179e8 100644
--- a/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java
+++ b/jetty-websocket/websocket-server/src/main/java/org/eclipse/jetty/websocket/server/HandshakeRFC6455.java
@@ -57,9 +57,10 @@ public class HandshakeRFC6455 implements WebSocketHandshake
if (response.getExtensions() != null)
{
- for (ExtensionConfig ext : response.getExtensions())
+ String value = ExtensionConfig.toHeaderValue(response.getExtensions());
+ if (value != null)
{
- response.addHeader("Sec-WebSocket-Extensions",ext.getParameterizedName());
+ response.addHeader("Sec-WebSocket-Extensions",value);
}
}
diff --git a/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties b/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
index 644823c1ba..994503cc1b 100644
--- a/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
+++ b/jetty-websocket/websocket-server/src/test/resources/jetty-logging.properties
@@ -3,7 +3,7 @@ org.eclipse.jetty.LEVEL=WARN
# org.eclipse.jetty.io.WriteFlusher.LEVEL=DEBUG
# org.eclipse.jetty.websocket.LEVEL=DEBUG
-org.eclipse.jetty.websocket.LEVEL=INFO
+# org.eclipse.jetty.websocket.LEVEL=INFO
# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG
# org.eclipse.jetty.websocket.server.ab.LEVEL=DEBUG
# org.eclipse.jetty.websocket.common.Parser.LEVEL=DEBUG
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 8a908a7860..fa87d1099a 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
@@ -28,7 +28,6 @@ import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
-import java.util.Iterator;
import java.util.List;
import java.util.Map;
@@ -37,7 +36,6 @@ import javax.servlet.http.HttpServletRequest;
import org.eclipse.jetty.websocket.api.UpgradeRequest;
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
-import org.eclipse.jetty.websocket.api.util.QuoteUtil;
import org.eclipse.jetty.websocket.api.util.WSURI;
/**
@@ -106,16 +104,7 @@ public class ServletUpgradeRequest extends UpgradeRequest
// Parse Extension Configurations
Enumeration<String> e = request.getHeaders("Sec-WebSocket-Extensions");
- while (e.hasMoreElements())
- {
- Iterator<String> extTokenIter = QuoteUtil.splitAt(e.nextElement(),",");
- while (extTokenIter.hasNext())
- {
- String extToken = extTokenIter.next();
- ExtensionConfig config = ExtensionConfig.parse(extToken);
- addExtensions(config);
- }
- }
+ setExtensions(ExtensionConfig.parseEnum(e));
}
public X509Certificate[] getCertificates()

Back to the top