aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjmr0 <jrosello720@gmail.com>2016-01-03 11:51:25 -0500
committerjmr0 <jrosello720@gmail.com>2016-01-24 18:31:21 -0500
commit3846cf52f28bffaea5c98ca825679ffc5275d86e (patch)
treec414af8a61ad0850b89ef066c303c4e0e962d5b5
parent5b2d2c0ed88e8b635f91c3421b472c804dd1afe4 (diff)
downloadservo-3846cf52f28bffaea5c98ca825679ffc5275d86e.tar.gz
servo-3846cf52f28bffaea5c98ca825679ffc5275d86e.zip
fix websocket header validation, ensure it meets token requirements, add
testing
-rw-r--r--components/script/dom/bindings/str.rs31
-rw-r--r--components/script/dom/websocket.rs11
-rw-r--r--components/util/str.rs34
-rw-r--r--tests/wpt/metadata/MANIFEST.json17
-rw-r--r--tests/wpt/web-platform-tests/websockets/Create-asciiSep-protocol-string.htm21
-rw-r--r--tests/wpt/web-platform-tests/websockets/Create-protocols-repeated-case-insensitive.htm18
-rw-r--r--tests/wpt/web-platform-tests/websockets/websocket.js13
7 files changed, 108 insertions, 37 deletions
diff --git a/components/script/dom/bindings/str.rs b/components/script/dom/bindings/str.rs
index b9b1090e082..df69bc77fd0 100644
--- a/components/script/dom/bindings/str.rs
+++ b/components/script/dom/bindings/str.rs
@@ -11,6 +11,7 @@ use std::ops;
use std::str;
use std::str::FromStr;
use util::mem::HeapSizeOf;
+use util::str::is_token;
/// Encapsulates the IDL `ByteString` type.
#[derive(JSTraceable, Clone, Eq, PartialEq, HeapSizeOf)]
@@ -49,35 +50,7 @@ impl ByteString {
/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
pub fn is_token(&self) -> bool {
let ByteString(ref vec) = *self;
- if vec.is_empty() {
- return false; // A token must be at least a single character
- }
- vec.iter().all(|&x| {
- // http://tools.ietf.org/html/rfc2616#section-2.2
- match x {
- 0...31 | 127 => false, // CTLs
- 40 |
- 41 |
- 60 |
- 62 |
- 64 |
- 44 |
- 59 |
- 58 |
- 92 |
- 34 |
- 47 |
- 91 |
- 93 |
- 63 |
- 61 |
- 123 |
- 125 |
- 32 => false, // separators
- x if x > 127 => false, // non-CHARs
- _ => true,
- }
- })
+ is_token(vec)
}
/// Returns whether `self` is a `field-value`, as defined by
diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs
index 36456cd02ff..5828d1c069d 100644
--- a/components/script/dom/websocket.rs
+++ b/components/script/dom/websocket.rs
@@ -34,11 +34,12 @@ use net_traits::unwrap_websocket_protocol;
use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
use script_thread::ScriptThreadEventCategory::WebSocketEvent;
use script_thread::{CommonScriptMsg, Runnable, ScriptChan};
+use std::ascii::AsciiExt;
use std::borrow::ToOwned;
use std::cell::Cell;
use std::ptr;
use std::thread;
-use util::str::DOMString;
+use util::str::{DOMString, is_token};
use websocket::client::request::Url;
use websocket::header::{Headers, WebSocketProtocol};
use websocket::ws::util::url::parse_url;
@@ -218,17 +219,13 @@ impl WebSocket {
for (i, protocol) in protocols.iter().enumerate() {
// https://tools.ietf.org/html/rfc6455#section-4.1
// Handshake requirements, step 10
- if protocol.is_empty() {
- return Err(Error::Syntax);
- }
- if protocols[i + 1..].iter().any(|p| p == protocol) {
+ if protocols[i + 1..].iter().any(|p| p.eq_ignore_ascii_case(protocol)) {
return Err(Error::Syntax);
}
- // TODO: also check that no separator characters are used
// https://tools.ietf.org/html/rfc6455#section-4.1
- if protocol.chars().any(|c| c < '\u{0021}' || c > '\u{007E}') {
+ if !is_token(protocol.as_bytes()) {
return Err(Error::Syntax);
}
}
diff --git a/components/util/str.rs b/components/util/str.rs
index 0b1e863a8de..dc3b8df1762 100644
--- a/components/util/str.rs
+++ b/components/util/str.rs
@@ -565,3 +565,37 @@ pub fn search_index(index: usize, indices: CharIndices) -> isize {
}
character_count
}
+
+/// Returns whether `s` is a `token`, as defined by
+/// [RFC 2616](http://tools.ietf.org/html/rfc2616#page-17).
+pub fn is_token(s: &[u8]) -> bool {
+ if s.is_empty() {
+ return false; // A token must be at least a single character
+ }
+ s.iter().all(|&x| {
+ // http://tools.ietf.org/html/rfc2616#section-2.2
+ match x {
+ 0...31 | 127 => false, // CTLs
+ 40 |
+ 41 |
+ 60 |
+ 62 |
+ 64 |
+ 44 |
+ 59 |
+ 58 |
+ 92 |
+ 34 |
+ 47 |
+ 91 |
+ 93 |
+ 63 |
+ 61 |
+ 123 |
+ 125 |
+ 32 => false, // separators
+ x if x > 127 => false, // non-CHARs
+ _ => true,
+ }
+ })
+}
diff --git a/tests/wpt/metadata/MANIFEST.json b/tests/wpt/metadata/MANIFEST.json
index 12e5be2479a..c655596b8d7 100644
--- a/tests/wpt/metadata/MANIFEST.json
+++ b/tests/wpt/metadata/MANIFEST.json
@@ -33212,7 +33212,22 @@
},
"local_changes": {
"deleted": [],
- "items": {},
+ "items": {
+ "testharness": {
+ "websockets/Create-asciiSep-protocol-string.htm": [
+ {
+ "path": "websockets/Create-asciiSep-protocol-string.htm",
+ "url": "/websockets/Create-asciiSep-protocol-string.htm"
+ }
+ ],
+ "websockets/Create-protocols-repeated-case-insensitive.htm": [
+ {
+ "path": "websockets/Create-protocols-repeated-case-insensitive.htm",
+ "url": "/websockets/Create-protocols-repeated-case-insensitive.htm"
+ }
+ ]
+ }
+ },
"reftest_nodes": {}
},
"reftest_nodes": {
diff --git a/tests/wpt/web-platform-tests/websockets/Create-asciiSep-protocol-string.htm b/tests/wpt/web-platform-tests/websockets/Create-asciiSep-protocol-string.htm
new file mode 100644
index 00000000000..7309009d052
--- /dev/null
+++ b/tests/wpt/web-platform-tests/websockets/Create-asciiSep-protocol-string.htm
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>W3C WebSocket API - Create WebSocket - ascii protocol string with separator</title>
+ <script type="text/javascript" src="/resources/testharness.js"></script>
+ <script type="text/javascript" src="/resources/testharnessreport.js"></script>
+ <script type="text/javascript" src="websocket.js?pipe=sub"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <script type="text/javascript">
+ if(window.WebSocket) {
+ test(function () {
+ var asciiWithSep = "/echo";
+ var wsocket;
+ assert_throws("SYNTAX_ERR", function () { wsocket = CreateWebSocketWithAsciiSep(asciiWithSep) });
+ }, "W3C WebSocket API - Create WebSocket - Pass a valid URL and a protocol string with an ascii separator character - SYNTAX_ERR is thrown")
+ }
+ </script>
+</body>
+</html>
diff --git a/tests/wpt/web-platform-tests/websockets/Create-protocols-repeated-case-insensitive.htm b/tests/wpt/web-platform-tests/websockets/Create-protocols-repeated-case-insensitive.htm
new file mode 100644
index 00000000000..f32ce5bfd58
--- /dev/null
+++ b/tests/wpt/web-platform-tests/websockets/Create-protocols-repeated-case-insensitive.htm
@@ -0,0 +1,18 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>W3C WebSocket API - Create WebSocket - repeated protocols with different case</title>
+ <script type="text/javascript" src="/resources/testharness.js"></script>
+ <script type="text/javascript" src="/resources/testharnessreport.js"></script>
+ <script type="text/javascript" src="websocket.js?pipe=sub"></script>
+</head>
+<body>
+ <div id="log"></div>
+ <script type="text/javascript">
+ test(function () {
+ var wsocket;
+ assert_throws("SYNTAX_ERR", function () { wsocket = CreateWebSocketWithRepeatedProtocolsCaseInsensitive() });
+ }, "W3C WebSocket API - Create WebSocket - Pass a valid URL and an array of protocol strings with repeated values but different case - SYNTAX_ERR is thrown")
+ </script>
+</body>
+</html>
diff --git a/tests/wpt/web-platform-tests/websockets/websocket.js b/tests/wpt/web-platform-tests/websockets/websocket.js
index 2d2697a1170..79b7bd59c58 100644
--- a/tests/wpt/web-platform-tests/websockets/websocket.js
+++ b/tests/wpt/web-platform-tests/websockets/websocket.js
@@ -8,6 +8,7 @@ var __CONTROLPATH = "control";
var __PROTOCOL = "echo";
var __PROTOCOLS = ["echo", "chat"];
var __REPEATED__PROTOCOLS = ["echo", "echo"];
+var __REPEATED__PROTOCOLS_CASE_INSENSITIVE = ["echo", "eCho"];
var __URL;
var __IS__WEBSOCKET;
var __PASS = "Pass";
@@ -47,6 +48,12 @@ function CreateWebSocketNonAsciiProtocol(nonAsciiProtocol) {
wsocket = new WebSocket(__URL, nonAsciiProtocol);
}
+function CreateWebSocketWithAsciiSep(asciiWithSep) {
+ IsWebSocket();
+ __URL = "ws://" + __SERVER__NAME + ":" + __PORT + "/" + __PATH;
+ wsocket = new WebSocket(__URL, asciiWithSep);
+}
+
function CreateWebSocketWithBlockedPort(blockedPort) {
IsWebSocket();
__URL = "wss://" + __SERVER__NAME + ":" + blockedPort + "/" + __PATH;
@@ -71,6 +78,12 @@ function CreateWebSocketWithRepeatedProtocols() {
wsocket = new WebSocket(__URL, __REPEATED__PROTOCOLS);
}
+function CreateWebSocketWithRepeatedProtocolsCaseInsensitive() {
+ IsWebSocket();
+ __URL = "ws://" + __SERVER__NAME + ":" + __PORT + "/" + __PATH;
+ wsocket = new WebSocket(__URL, __REPEATED__PROTOCOLS_CASE_INSENSITIVE);
+}
+
function CreateWebSocket(isSecure, isProtocol, isProtocols) {
IsWebSocket();
if (isSecure) {