aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--components/net/websocket_loader.rs35
-rw-r--r--components/net_traits/lib.rs9
-rw-r--r--components/script/dom/webidls/WebSocket.webidl2
-rw-r--r--components/script/dom/websocket.rs40
-rw-r--r--tests/wpt/metadata/html/dom/interfaces.html.ini3
-rw-r--r--tests/wpt/metadata/websockets/Create-Secure-valid-url-array-protocols.htm.ini (renamed from tests/wpt/metadata/websockets/Create-Secure-valid-url-protocol-setCorrectly.htm.ini)10
-rw-r--r--tests/wpt/metadata/websockets/Create-valid-url-array-protocols.htm.ini9
-rw-r--r--tests/wpt/metadata/websockets/Create-valid-url-protocol-empty.htm.ini5
-rw-r--r--tests/wpt/metadata/websockets/constructor/009.html.ini6
-rw-r--r--tests/wpt/metadata/websockets/constructor/012.html.ini6
-rw-r--r--tests/wpt/metadata/websockets/interfaces.html.ini6
-rw-r--r--tests/wpt/metadata/websockets/interfaces/WebSocket/protocol/protocol-initial.html.ini5
12 files changed, 87 insertions, 49 deletions
diff --git a/components/net/websocket_loader.rs b/components/net/websocket_loader.rs
index 2ae54dc8eb2..05665077845 100644
--- a/components/net/websocket_loader.rs
+++ b/components/net/websocket_loader.rs
@@ -5,16 +5,18 @@
use hyper::header::Host;
use net_traits::MessageData;
use net_traits::hosts::replace_hosts;
+use net_traits::unwrap_websocket_protocol;
use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
+use std::ascii::AsciiExt;
use std::sync::{Arc, Mutex};
use std::thread;
use util::task::spawn_named;
use websocket::client::receiver::Receiver;
use websocket::client::request::Url;
use websocket::client::sender::Sender;
-use websocket::header::Origin;
+use websocket::header::{Headers, Origin, WebSocketProtocol};
use websocket::message::Type;
-use websocket::result::WebSocketResult;
+use websocket::result::{WebSocketError, WebSocketResult};
use websocket::stream::WebSocketStream;
use websocket::ws::receiver::Receiver as WSReceiver;
use websocket::ws::sender::Sender as Sender_Object;
@@ -23,8 +25,8 @@ use websocket::{Client, Message};
/// *Establish a WebSocket Connection* as defined in RFC 6455.
fn establish_a_websocket_connection(resource_url: &Url, net_url: (Host, String, bool),
- origin: String)
- -> WebSocketResult<(Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
+ origin: String, protocols: Vec<String>)
+ -> WebSocketResult<(Headers, Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
let host = Host {
hostname: resource_url.serialize_host().unwrap(),
@@ -34,11 +36,26 @@ fn establish_a_websocket_connection(resource_url: &Url, net_url: (Host, String,
let mut request = try!(Client::connect(net_url));
request.headers.set(Origin(origin));
request.headers.set(host);
+ if !protocols.is_empty() {
+ request.headers.set(WebSocketProtocol(protocols.clone()));
+ };
let response = try!(request.send());
try!(response.validate());
- Ok(response.begin().split())
+ {
+ let protocol_in_use = unwrap_websocket_protocol(response.protocol());
+ if let Some(protocol_name) = protocol_in_use {
+ if !protocols.is_empty() && !protocols.iter().any(|p| p.eq_ignore_ascii_case(protocol_name)) {
+ return Err(WebSocketError::ProtocolError("Protocol in Use not in client-supplied protocol list"));
+ };
+ };
+ }
+
+ let headers = response.headers.clone();
+ let (sender, receiver) = response.begin().split();
+ Ok((headers, sender, receiver))
+
}
pub fn init(connect: WebSocketCommunicate, connect_data: WebSocketConnectData) {
@@ -60,10 +77,12 @@ pub fn init(connect: WebSocketCommunicate, connect_data: WebSocketConnectData) {
};
let channel = establish_a_websocket_connection(&connect_data.resource_url,
net_url,
- connect_data.origin);
- let (ws_sender, mut receiver) = match channel {
+ connect_data.origin,
+ connect_data.protocols.clone());
+ let (_, ws_sender, mut receiver) = match channel {
Ok(channel) => {
- let _ = connect.event_sender.send(WebSocketNetworkEvent::ConnectionEstablished);
+ let _ = connect.event_sender.send(WebSocketNetworkEvent::ConnectionEstablished(channel.0.clone(),
+ connect_data.protocols));
channel
},
Err(e) => {
diff --git a/components/net_traits/lib.rs b/components/net_traits/lib.rs
index fbf1b5e810a..64bfb89f62b 100644
--- a/components/net_traits/lib.rs
+++ b/components/net_traits/lib.rs
@@ -37,6 +37,7 @@ use std::rc::Rc;
use std::thread;
use url::Url;
use util::mem::HeapSizeOf;
+use websocket::header;
pub mod hosts;
pub mod image_cache_task;
@@ -239,7 +240,7 @@ pub enum WebSocketDomAction {
#[derive(Deserialize, Serialize)]
pub enum WebSocketNetworkEvent {
- ConnectionEstablished,
+ ConnectionEstablished(header::Headers, Vec<String>),
MessageReceived(MessageData),
Close,
}
@@ -254,6 +255,7 @@ pub struct WebSocketCommunicate {
pub struct WebSocketConnectData {
pub resource_url: Url,
pub origin: String,
+ pub protocols: Vec<String>,
}
#[derive(Deserialize, Serialize)]
@@ -429,6 +431,11 @@ pub fn load_whole_resource(resource_task: &ResourceTask, url: Url, pipeline_id:
}
}
+/// Defensively unwraps the protocol string from the response object's protocol
+pub fn unwrap_websocket_protocol(wsp: Option<&header::WebSocketProtocol>) -> Option<&str> {
+ wsp.and_then(|protocol_list| protocol_list.get(0).map(|protocol| protocol.as_ref()))
+}
+
/// An unique identifier to keep track of each load message in the resource handler
#[derive(Clone, PartialEq, Eq, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct ResourceId(pub u32);
diff --git a/components/script/dom/webidls/WebSocket.webidl b/components/script/dom/webidls/WebSocket.webidl
index e18b2536743..8a07e0496eb 100644
--- a/components/script/dom/webidls/WebSocket.webidl
+++ b/components/script/dom/webidls/WebSocket.webidl
@@ -22,7 +22,7 @@ interface WebSocket : EventTarget {
attribute EventHandler onerror;
attribute EventHandler onclose;
//readonly attribute DOMString extensions;
- //readonly attribute DOMString protocol;
+ readonly attribute DOMString protocol;
[Throws] void close([Clamp] optional unsigned short code, optional USVString reason);
//messaging
diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs
index 8d7e5ebd6c6..392b8258b5c 100644
--- a/components/script/dom/websocket.rs
+++ b/components/script/dom/websocket.rs
@@ -29,6 +29,7 @@ use libc::{uint32_t, uint8_t};
use net_traits::ControlMsg::WebsocketConnect;
use net_traits::MessageData;
use net_traits::hosts::replace_hosts;
+use net_traits::unwrap_websocket_protocol;
use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
use ref_slice::ref_slice;
use script_task::ScriptTaskEventCategory::WebSocketEvent;
@@ -39,6 +40,7 @@ use std::ptr;
use std::thread;
use util::str::DOMString;
use websocket::client::request::Url;
+use websocket::header::{Headers, WebSocketProtocol};
use websocket::ws::util::url::parse_url;
#[derive(JSTraceable, PartialEq, Copy, Clone, Debug, HeapSizeOf)]
@@ -146,6 +148,7 @@ pub struct WebSocket {
code: Cell<u16>, //Closing code
reason: DOMRefCell<String>, //Closing reason
binary_type: Cell<BinaryType>,
+ protocol: DOMRefCell<String>, //Subprotocol selected by server
}
impl WebSocket {
@@ -164,6 +167,7 @@ impl WebSocket {
code: Cell::new(0),
reason: DOMRefCell::new("".to_owned()),
binary_type: Cell::new(BinaryType::Blob),
+ protocol: DOMRefCell::new("".to_owned()),
}
}
@@ -208,6 +212,8 @@ impl WebSocket {
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}') {
return Err(Error::Syntax);
}
@@ -220,10 +226,12 @@ impl WebSocket {
let address = Trusted::new(global.get_cx(), ws.r(), global.networking_task_source());
let origin = global.get_url().serialize();
+ let protocols: Vec<String> = protocols.iter().map(|x| String::from(x.clone())).collect();
let connect_data = WebSocketConnectData {
resource_url: resource_url.clone(),
origin: origin,
+ protocols: protocols,
};
// Create the interface for communication with the resource task
@@ -246,13 +254,14 @@ impl WebSocket {
let moved_address = address.clone();
let sender = global.networking_task_source();
-
thread::spawn(move || {
while let Ok(event) = dom_event_receiver.recv() {
match event {
- WebSocketNetworkEvent::ConnectionEstablished => {
+ WebSocketNetworkEvent::ConnectionEstablished(headers, protocols) => {
let open_task = box ConnectionEstablishedTask {
addr: moved_address.clone(),
+ headers: headers,
+ protocols: protocols,
};
sender.send(CommonScriptMsg::RunnableMsg(WebSocketEvent, open_task)).unwrap();
},
@@ -358,6 +367,11 @@ impl WebSocketMethods for WebSocket {
self.binary_type.set(btype)
}
+ // https://html.spec.whatwg.org/multipage/#dom-websocket-protocol
+ fn Protocol(&self) -> DOMString {
+ DOMString::from(self.protocol.borrow().clone())
+ }
+
// https://html.spec.whatwg.org/multipage/#dom-websocket-send
fn Send(&self, data: USVString) -> Fallible<()> {
@@ -448,22 +462,42 @@ impl WebSocketMethods for WebSocket {
/// Task queued when *the WebSocket connection is established*.
struct ConnectionEstablishedTask {
addr: Trusted<WebSocket>,
+ protocols: Vec<String>,
+ headers: Headers,
}
impl Runnable for ConnectionEstablishedTask {
fn handler(self: Box<Self>) {
let ws = self.addr.root();
+ let global = ws.global.root();
+
// Step 1: Protocols.
+ if !self.protocols.is_empty() && self.headers.get::<WebSocketProtocol>().is_none() {
+ ws.failed.set(true);
+ ws.ready_state.set(WebSocketRequestState::Closing);
+ let task = box CloseTask {
+ addr: self.addr,
+ };
+ let sender = global.r().networking_task_source();
+ sender.send(CommonScriptMsg::RunnableMsg(WebSocketEvent, task)).unwrap();
+ return;
+ }
// Step 2.
ws.ready_state.set(WebSocketRequestState::Open);
// Step 3: Extensions.
+ //TODO: Set extensions to extensions in use
+
// Step 4: Protocols.
+ let protocol_in_use = unwrap_websocket_protocol(self.headers.get::<WebSocketProtocol>());
+ if let Some(protocol_name) = protocol_in_use {
+ *ws.protocol.borrow_mut() = protocol_name.to_owned();
+ };
+
// Step 5: Cookies.
// Step 6.
- let global = ws.global.root();
let event = Event::new(global.r(), atom!("open"),
EventBubbles::DoesNotBubble,
EventCancelable::NotCancelable);
diff --git a/tests/wpt/metadata/html/dom/interfaces.html.ini b/tests/wpt/metadata/html/dom/interfaces.html.ini
index 7ca1add1408..735d9196bf5 100644
--- a/tests/wpt/metadata/html/dom/interfaces.html.ini
+++ b/tests/wpt/metadata/html/dom/interfaces.html.ini
@@ -7845,9 +7845,6 @@
[WebSocket interface: attribute extensions]
expected: FAIL
- [WebSocket interface: attribute protocol]
- expected: FAIL
-
[CloseEvent interface: existence and properties of interface object]
expected: FAIL
diff --git a/tests/wpt/metadata/websockets/Create-Secure-valid-url-protocol-setCorrectly.htm.ini b/tests/wpt/metadata/websockets/Create-Secure-valid-url-array-protocols.htm.ini
index a76a4bc2c74..f1617ea3c85 100644
--- a/tests/wpt/metadata/websockets/Create-Secure-valid-url-protocol-setCorrectly.htm.ini
+++ b/tests/wpt/metadata/websockets/Create-Secure-valid-url-array-protocols.htm.ini
@@ -1,9 +1,9 @@
-[Create-Secure-valid-url-protocol-setCorrectly.htm]
+[Create-Secure-valid-url-array-protocols.htm]
type: testharness
expected: TIMEOUT
- [W3C WebSocket API - Create Secure WebSocket - Pass a valid URL and protocol string - protocol should be set correctly - Connection should be opened]
- expected: FAIL
-
- [W3C WebSocket API - Create Secure WebSocket - Pass a valid URL and protocol string - Connection should be closed]
+ [W3C WebSocket API - Create Secure WebSocket - Pass a valid URL and array of protocol strings - Connection should be opened]
expected: NOTRUN
+ [W3C WebSocket API - Create Secure WebSocket - Pass a valid URL and array of protocol strings - Connection should be closed]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/websockets/Create-valid-url-array-protocols.htm.ini b/tests/wpt/metadata/websockets/Create-valid-url-array-protocols.htm.ini
new file mode 100644
index 00000000000..dccba045ceb
--- /dev/null
+++ b/tests/wpt/metadata/websockets/Create-valid-url-array-protocols.htm.ini
@@ -0,0 +1,9 @@
+[Create-valid-url-array-protocols.htm]
+ type: testharness
+ expected: TIMEOUT
+ [W3C WebSocket API - Create WebSocket - Pass a valid URL and array of protocol strings - Connection should be opened]
+ expected: NOTRUN
+
+ [W3C WebSocket API - Create WebSocket - Pass a valid URL and array of protocol strings - Connection should be closed]
+ expected: FAIL
+
diff --git a/tests/wpt/metadata/websockets/Create-valid-url-protocol-empty.htm.ini b/tests/wpt/metadata/websockets/Create-valid-url-protocol-empty.htm.ini
deleted file mode 100644
index e39be950b89..00000000000
--- a/tests/wpt/metadata/websockets/Create-valid-url-protocol-empty.htm.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[Create-valid-url-protocol-empty.htm]
- type: testharness
- [W3C WebSocket API - Create WebSocket - wsocket.protocol should be empty before connection is established]
- expected: FAIL
-
diff --git a/tests/wpt/metadata/websockets/constructor/009.html.ini b/tests/wpt/metadata/websockets/constructor/009.html.ini
deleted file mode 100644
index db8502371ba..00000000000
--- a/tests/wpt/metadata/websockets/constructor/009.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[009.html]
- type: testharness
- expected: TIMEOUT
- [WebSockets: protocol]
- expected: TIMEOUT
-
diff --git a/tests/wpt/metadata/websockets/constructor/012.html.ini b/tests/wpt/metadata/websockets/constructor/012.html.ini
deleted file mode 100644
index 3c79462be91..00000000000
--- a/tests/wpt/metadata/websockets/constructor/012.html.ini
+++ /dev/null
@@ -1,6 +0,0 @@
-[012.html]
- type: testharness
- expected: TIMEOUT
- [WebSockets: no protocol in response]
- expected: TIMEOUT
-
diff --git a/tests/wpt/metadata/websockets/interfaces.html.ini b/tests/wpt/metadata/websockets/interfaces.html.ini
index d8c25bdc068..d5eaa3f58dc 100644
--- a/tests/wpt/metadata/websockets/interfaces.html.ini
+++ b/tests/wpt/metadata/websockets/interfaces.html.ini
@@ -9,18 +9,12 @@
[WebSocket interface: attribute extensions]
expected: FAIL
- [WebSocket interface: attribute protocol]
- expected: FAIL
-
[Stringification of new WebSocket("ws://foo")]
expected: FAIL
[WebSocket interface: new WebSocket("ws://foo") must inherit property "extensions" with the proper type (10)]
expected: FAIL
- [WebSocket interface: new WebSocket("ws://foo") must inherit property "protocol" with the proper type (11)]
- expected: FAIL
-
[CloseEvent interface: existence and properties of interface object]
expected: FAIL
diff --git a/tests/wpt/metadata/websockets/interfaces/WebSocket/protocol/protocol-initial.html.ini b/tests/wpt/metadata/websockets/interfaces/WebSocket/protocol/protocol-initial.html.ini
deleted file mode 100644
index 1c6ba352e3b..00000000000
--- a/tests/wpt/metadata/websockets/interfaces/WebSocket/protocol/protocol-initial.html.ini
+++ /dev/null
@@ -1,5 +0,0 @@
-[protocol-initial.html]
- type: testharness
- [WebSockets: getting protocol in connecting]
- expected: FAIL
-