You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by vi...@apache.org on 2014/09/13 18:08:30 UTC
svn commit: r1624760 - in /tomcat/tc7.0.x/trunk: ./
java/org/apache/tomcat/websocket/LocalStrings.properties
java/org/apache/tomcat/websocket/Util.java
test/org/apache/tomcat/websocket/TestUtil.java
Author: violetagg
Date: Sat Sep 13 16:08:30 2014
New Revision: 1624760
URL: http://svn.apache.org/r1624760
Log:
Merged revisions 1604781, 1604788 from tomcat/trunk:
- Add support for parsing the extension header
- Strengthen WebSocket extension parameter validation
Modified:
tomcat/tc7.0.x/trunk/ (props changed)
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties
tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Util.java
tomcat/tc7.0.x/trunk/test/org/apache/tomcat/websocket/TestUtil.java
Propchange: tomcat/tc7.0.x/trunk/
------------------------------------------------------------------------------
Merged /tomcat/trunk:r1604781,1604788
Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties?rev=1624760&r1=1624759&r2=1624760&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/LocalStrings.properties Sat Sep 13 16:08:30 2014
@@ -28,6 +28,7 @@ asyncChannelWrapperSecure.wrongStateWrit
backgroundProcessManager.processFailed=A background process failed
+util.notToken=An illegal extension parameter was specified with name [{0}] and value [{1}]
util.invalidMessageHandler=The message handler provided does not have an onMessage(Object) method
util.invalidType=Unable to coerce value [{0}] to type [{1}]. That type is not supported.
util.unknownDecoderType=The Decoder type [{0}] is not recognized
Modified: tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Util.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Util.java?rev=1624760&r1=1624759&r2=1624760&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Util.java (original)
+++ tomcat/tc7.0.x/trunk/java/org/apache/tomcat/websocket/Util.java Sat Sep 13 16:08:30 2014
@@ -43,6 +43,7 @@ import javax.websocket.Decoder.TextStrea
import javax.websocket.DeploymentException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
+import javax.websocket.Extension;
import javax.websocket.MessageHandler;
import javax.websocket.PongMessage;
import javax.websocket.Session;
@@ -352,7 +353,6 @@ public class Util {
}
-
public static Set<MessageHandlerResult> getMessageHandlers(
MessageHandler listener, EndpointConfig endpointConfig,
Session session) {
@@ -448,6 +448,85 @@ public class Util {
}
+ public static void parseExtensionHeader(List<Extension> extensions,
+ String header) {
+ // The relevant ABNF for the Sec-WebSocket-Extensions is as follows:
+ // extension-list = 1#extension
+ // extension = extension-token *( ";" extension-param )
+ // extension-token = registered-token
+ // registered-token = token
+ // extension-param = token [ "=" (token | quoted-string) ]
+ // ; When using the quoted-string syntax variant, the value
+ // ; after quoted-string unescaping MUST conform to the
+ // ; 'token' ABNF.
+ //
+ // The limiting of parameter values to tokens or "quoted tokens" makes
+ // the parsing of the header significantly simpler and allows a number
+ // of short-cuts to be taken.
+
+ // Step one, split the header into individual extensions using ',' as a
+ // separator
+ String unparsedExtensions[] = header.split(",");
+ for (String unparsedExtension : unparsedExtensions) {
+ // Step two, split the extension into the registered name and
+ // parameter/value pairs using ';' as a separator
+ String unparsedParameters[] = unparsedExtension.split(";");
+ WsExtension extension = new WsExtension(unparsedParameters[0].trim());
+
+ for (int i = 1; i < unparsedParameters.length; i++) {
+ int equalsPos = unparsedParameters[i].indexOf('=');
+ String name;
+ String value;
+ if (equalsPos == -1) {
+ name = unparsedParameters[i].trim();
+ value = null;
+ } else {
+ name = unparsedParameters[i].substring(0, equalsPos).trim();
+ value = unparsedParameters[i].substring(equalsPos + 1).trim();
+ int len = value.length();
+ if (len > 1) {
+ if (value.charAt(0) == '\"' && value.charAt(len - 1) == '\"') {
+ value = value.substring(1, value.length() - 1);
+ }
+ }
+ }
+ // Make sure value doesn't contain any of the delimiters since
+ // that would indicate something went wrong
+ if (containsDelims(name) || containsDelims(value)) {
+ throw new IllegalArgumentException(sm.getString(
+ "util.notToken", name, value));
+ }
+ if (value != null &&
+ (value.indexOf(',') > -1 || value.indexOf(';') > -1 ||
+ value.indexOf('\"') > -1 || value.indexOf('=') > -1)) {
+ throw new IllegalArgumentException(sm.getString("", value));
+ }
+ extension.addParameter(new WsExtensionParameter(name, value));
+ }
+ extensions.add(extension);
+ }
+ }
+
+
+ private static boolean containsDelims(String input) {
+ if (input == null || input.length() == 0) {
+ return false;
+ }
+ for (char c : input.toCharArray()) {
+ switch (c) {
+ case ',':
+ case ';':
+ case '\"':
+ case '=':
+ return true;
+ default:
+ // NO_OP
+ }
+
+ }
+ return false;
+ }
+
private static Method getOnMessageMethod(MessageHandler listener) {
try {
return listener.getClass().getMethod("onMessage", Object.class);
@@ -460,6 +539,7 @@ public class Util {
}
}
+
public static class DecoderMatch {
private final List<Class<? extends Decoder>> textDecoders =
Modified: tomcat/tc7.0.x/trunk/test/org/apache/tomcat/websocket/TestUtil.java
URL: http://svn.apache.org/viewvc/tomcat/tc7.0.x/trunk/test/org/apache/tomcat/websocket/TestUtil.java?rev=1624760&r1=1624759&r2=1624760&view=diff
==============================================================================
--- tomcat/tc7.0.x/trunk/test/org/apache/tomcat/websocket/TestUtil.java (original)
+++ tomcat/tc7.0.x/trunk/test/org/apache/tomcat/websocket/TestUtil.java Sat Sep 13 16:08:30 2014
@@ -16,11 +16,14 @@
*/
package org.apache.tomcat.websocket;
+import java.util.ArrayList;
import java.util.List;
import javax.websocket.EncodeException;
import javax.websocket.Encoder;
import javax.websocket.EndpointConfig;
+import javax.websocket.Extension;
+import javax.websocket.Extension.Parameter;
import javax.websocket.MessageHandler;
import org.junit.Assert;
@@ -370,4 +373,101 @@ public class TestUtil {
return null;
}
}
+
+
+ @Test
+ public void testParseExtensionHeaderSimple01() {
+ doTestParseExtensionHeaderSimple("ext;a=1;b=2");
+ }
+
+ @Test
+ public void testParseExtensionHeaderSimple02() {
+ doTestParseExtensionHeaderSimple("ext;a=\"1\";b=2");
+ }
+
+ @Test
+ public void testParseExtensionHeaderSimple03() {
+ doTestParseExtensionHeaderSimple("ext;a=1;b=\"2\"");
+ }
+
+ @Test
+ public void testParseExtensionHeaderSimple04() {
+ doTestParseExtensionHeaderSimple(" ext ; a = 1 ; b = 2 ");
+ }
+
+ private void doTestParseExtensionHeaderSimple(String header) {
+ // Simple test
+ List<Extension> result = new ArrayList<Extension>();
+ Util.parseExtensionHeader(result, header);
+
+ Assert.assertEquals(1, result.size());
+
+ Extension ext = result.get(0);
+ Assert.assertEquals("ext", ext.getName());
+ List<Parameter> params = ext.getParameters();
+ Assert.assertEquals(2, params.size());
+ Parameter paramA = params.get(0);
+ Assert.assertEquals("a", paramA.getName());
+ Assert.assertEquals("1", paramA.getValue());
+ Parameter paramB = params.get(1);
+ Assert.assertEquals("b", paramB.getName());
+ Assert.assertEquals("2", paramB.getValue());
+ }
+
+
+ @Test
+ public void testParseExtensionHeaderMultiple01() {
+ doTestParseExtensionHeaderMultiple("ext;a=1;b=2,ext2;c;d=xyz,ext3");
+ }
+
+ @Test
+ public void testParseExtensionHeaderMultiple02() {
+ doTestParseExtensionHeaderMultiple(
+ " ext ; a = 1 ; b = 2 , ext2 ; c ; d = xyz , ext3 ");
+ }
+
+ private void doTestParseExtensionHeaderMultiple(String header) {
+ // Simple test
+ List<Extension> result = new ArrayList<Extension>();
+ Util.parseExtensionHeader(result, header);
+
+ Assert.assertEquals(3, result.size());
+
+ Extension ext = result.get(0);
+ Assert.assertEquals("ext", ext.getName());
+ List<Parameter> params = ext.getParameters();
+ Assert.assertEquals(2, params.size());
+ Parameter paramA = params.get(0);
+ Assert.assertEquals("a", paramA.getName());
+ Assert.assertEquals("1", paramA.getValue());
+ Parameter paramB = params.get(1);
+ Assert.assertEquals("b", paramB.getName());
+ Assert.assertEquals("2", paramB.getValue());
+
+ Extension ext2 = result.get(1);
+ Assert.assertEquals("ext2", ext2.getName());
+ List<Parameter> params2 = ext2.getParameters();
+ Assert.assertEquals(2, params2.size());
+ Parameter paramC = params2.get(0);
+ Assert.assertEquals("c", paramC.getName());
+ Assert.assertNull(paramC.getValue());
+ Parameter paramD = params2.get(1);
+ Assert.assertEquals("d", paramD.getName());
+ Assert.assertEquals("xyz", paramD.getValue());
+
+ Extension ext3 = result.get(2);
+ Assert.assertEquals("ext3", ext3.getName());
+ List<Parameter> params3 = ext3.getParameters();
+ Assert.assertEquals(0, params3.size());
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testParseExtensionHeaderInvalid01() {
+ Util.parseExtensionHeader(new ArrayList<Extension>(), "ext;a=\"1;b=2");
+ }
+
+ @Test(expected=IllegalArgumentException.class)
+ public void testParseExtensionHeaderInvalid02() {
+ Util.parseExtensionHeader(new ArrayList<Extension>(), "ext;a=1\";b=2");
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org