diff options
author | jmr0 <jrosello720@gmail.com> | 2015-12-03 13:58:30 -0500 |
---|---|---|
committer | jmr0 <jrosello720@gmail.com> | 2015-12-17 09:17:15 -0500 |
commit | 7d0bede8ba5a451a103cafa5ad18586f5a889b79 (patch) | |
tree | 7eb162e5ac050f46d190fec010d166095c93b06f /components/script/dom/websocket.rs | |
parent | 99fd946130c9f06433b47c7f60241d5f7ad14a5b (diff) | |
download | servo-7d0bede8ba5a451a103cafa5ad18586f5a889b79.tar.gz servo-7d0bede8ba5a451a103cafa5ad18586f5a889b79.zip |
adding initial support for websocket subprotocol negotation
Diffstat (limited to 'components/script/dom/websocket.rs')
-rw-r--r-- | components/script/dom/websocket.rs | 40 |
1 files changed, 37 insertions, 3 deletions
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); |