diff options
author | Anthony Ramine <n.oxyde@gmail.com> | 2017-03-23 17:02:52 +0100 |
---|---|---|
committer | Anthony Ramine <n.oxyde@gmail.com> | 2017-03-24 09:43:14 +0100 |
commit | 0bd54b904bf8b926afb60f4be0554bc37b30464b (patch) | |
tree | 1489467a0fd3fbf41d54fecae20398d0d1f6909f /components/script/dom/websocket.rs | |
parent | bba0be13dd07116d02fd0f2e6d73d1ecb8e952bb (diff) | |
download | servo-0bd54b904bf8b926afb60f4be0554bc37b30464b.tar.gz servo-0bd54b904bf8b926afb60f4be0554bc37b30464b.zip |
Properly follow the spec in WebSocket::Constructor
Diffstat (limited to 'components/script/dom/websocket.rs')
-rw-r--r-- | components/script/dom/websocket.rs | 158 |
1 files changed, 34 insertions, 124 deletions
diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index 296141a6c3a..a08684819e2 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -23,17 +23,13 @@ use dom::globalscope::GlobalScope; use dom::messageevent::MessageEvent; use dom::urlhelper::UrlHelper; use dom_struct::dom_struct; -use hyper; -use hyper_serde::Serde; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use js::jsapi::JSAutoCompartment; use js::jsval::UndefinedValue; use js::typedarray::{ArrayBuffer, CreateWith}; use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent}; -use net_traits::CookieSource::HTTP; -use net_traits::CoreResourceMsg::{SetCookiesForUrl, WebsocketConnect}; +use net_traits::CoreResourceMsg::WebsocketConnect; use net_traits::MessageData; -use net_traits::hosts::replace_hosts; use net_traits::unwrap_websocket_protocol; use script_runtime::CommonScriptMsg; use script_runtime::ScriptThreadEventCategory::WebSocketEvent; @@ -47,7 +43,6 @@ use std::thread; use task_source::TaskSource; use task_source::networking::NetworkingTaskSource; use websocket::header::{Headers, WebSocketProtocol}; -use websocket::ws::util::url::parse_url; #[derive(JSTraceable, PartialEq, Copy, Clone, Debug, HeapSizeOf)] enum WebSocketRequestState { @@ -57,75 +52,6 @@ enum WebSocketRequestState { Closed = 3, } -// list of bad ports according to -// https://fetch.spec.whatwg.org/#port-blocking -const BLOCKED_PORTS_LIST: &'static [u16] = &[ - 1, // tcpmux - 7, // echo - 9, // discard - 11, // systat - 13, // daytime - 15, // netstat - 17, // qotd - 19, // chargen - 20, // ftp-data - 21, // ftp - 22, // ssh - 23, // telnet - 25, // smtp - 37, // time - 42, // name - 43, // nicname - 53, // domain - 77, // priv-rjs - 79, // finger - 87, // ttylink - 95, // supdup - 101, // hostriame - 102, // iso-tsap - 103, // gppitnp - 104, // acr-nema - 109, // pop2 - 110, // pop3 - 111, // sunrpc - 113, // auth - 115, // sftp - 117, // uucp-path - 119, // nntp - 123, // ntp - 135, // loc-srv / epmap - 139, // netbios - 143, // imap2 - 179, // bgp - 389, // ldap - 465, // smtp+ssl - 512, // print / exec - 513, // login - 514, // shell - 515, // printer - 526, // tempo - 530, // courier - 531, // chat - 532, // netnews - 540, // uucp - 556, // remotefs - 563, // nntp+ssl - 587, // smtp - 601, // syslog-conn - 636, // ldap+ssl - 993, // imap+ssl - 995, // pop3+ssl - 2049, // nfs - 3659, // apple-sasl - 4045, // lockd - 6000, // x11 - 6665, // irc (alternate) - 6666, // irc (alternate) - 6667, // irc (default) - 6668, // irc (alternate) - 6669, // irc (alternate) -]; - // Close codes defined in https://tools.ietf.org/html/rfc6455#section-7.4.1 // Names are from https://github.com/mozilla/gecko-dev/blob/master/netwerk/protocol/websocket/nsIWebSocketChannel.idl #[allow(dead_code)] @@ -202,34 +128,36 @@ impl WebSocket { global, WebSocketBinding::Wrap) } + /// https://html.spec.whatwg.org/multipage/#dom-websocket pub fn Constructor(global: &GlobalScope, url: DOMString, protocols: Option<StringOrStringSequence>) -> Fallible<Root<WebSocket>> { - // Step 1. - let resource_url = try!(ServoUrl::parse(&url).map_err(|_| Error::Syntax)); - // Although we do this replace and parse operation again in the resource thread, - // we try here to be able to immediately throw a syntax error on failure. - let _ = try!(parse_url(&replace_hosts(&resource_url).as_url()).map_err(|_| Error::Syntax)); - // Step 2: Disallow https -> ws connections. - - // Step 3: Potentially block access to some ports. - let port: u16 = resource_url.port_or_known_default().unwrap(); + // Steps 1-2. + let url_record = ServoUrl::parse(&url).or(Err(Error::Syntax))?; - if BLOCKED_PORTS_LIST.iter().any(|&p| p == port) { - return Err(Error::Security); + // Step 3. + match url_record.scheme() { + "ws" | "wss" => {}, + _ => return Err(Error::Syntax), } // Step 4. - let protocols = match protocols { - Some(StringOrStringSequence::String(string)) => vec![String::from(string)], - Some(StringOrStringSequence::StringSequence(sequence)) => { - sequence.into_iter().map(String::from).collect() - }, - _ => Vec::new(), - }; + if url_record.fragment().is_some() { + return Err(Error::Syntax); + } // Step 5. + let protocols = protocols.map_or(vec![], |p| { + match p { + StringOrStringSequence::String(string) => vec![string.into()], + StringOrStringSequence::StringSequence(seq) => { + seq.into_iter().map(String::from).collect() + }, + } + }); + + // Step 6. for (i, protocol) in protocols.iter().enumerate() { // https://tools.ietf.org/html/rfc6455#section-4.1 // Handshake requirements, step 10 @@ -244,16 +172,12 @@ impl WebSocket { } } - // Step 6: Origin. - let origin = UrlHelper::Origin(&global.get_url()).0; - - // Step 7. - let ws = WebSocket::new(global, resource_url.clone()); + let ws = WebSocket::new(global, url_record.clone()); let address = Trusted::new(&*ws); let connect_data = WebSocketConnectData { - resource_url: resource_url.clone(), - origin: origin, + resource_url: url_record, + origin: UrlHelper::Origin(&global.get_url()).0, protocols: protocols, }; @@ -270,6 +194,7 @@ impl WebSocket { action_receiver: resource_action_receiver, }; + // Step 8. let _ = global.core_resource_thread().send(WebsocketConnect(connect, connect_data)); *ws.sender.borrow_mut() = Some(dom_action_sender); @@ -279,11 +204,10 @@ impl WebSocket { thread::spawn(move || { while let Ok(event) = dom_event_receiver.recv() { match event { - WebSocketNetworkEvent::ConnectionEstablished(headers, protocols) => { + WebSocketNetworkEvent::ConnectionEstablished(headers) => { let open_thread = box ConnectionEstablishedTask { address: address.clone(), headers: headers, - protocols: protocols, }; task_source.queue_with_wrapper(open_thread, &wrapper).unwrap(); }, @@ -466,45 +390,31 @@ impl WebSocketMethods for WebSocket { /// Task queued when *the WebSocket connection is established*. +/// https://html.spec.whatwg.org/multipage/#feedback-from-the-protocol:concept-websocket-established struct ConnectionEstablishedTask { address: Trusted<WebSocket>, - protocols: Vec<String>, headers: Headers, } impl Runnable for ConnectionEstablishedTask { fn name(&self) -> &'static str { "ConnectionEstablishedTask" } + /// https://html.spec.whatwg.org/multipage/#feedback-from-the-protocol:concept-websocket-established fn handler(self: Box<Self>) { let ws = self.address.root(); - // Step 1: Protocols. - if !self.protocols.is_empty() && self.headers.get::<WebSocketProtocol>().is_none() { - let task_source = ws.global().networking_task_source(); - fail_the_websocket_connection(self.address, &task_source, &ws.global().get_runnable_wrapper()); - return; - } - - // Step 2. + // Step 1. ws.ready_state.set(WebSocketRequestState::Open); - // Step 3: Extensions. - //TODO: Set extensions to extensions in use + // Step 2: 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 { + // Step 3. + if let Some(protocol_name) = unwrap_websocket_protocol(self.headers.get::<WebSocketProtocol>()) { *ws.protocol.borrow_mut() = protocol_name.to_owned(); }; - // Step 5: Cookies. - if let Some(cookies) = self.headers.get::<hyper::header::SetCookie>() { - let cookies = cookies.iter().map(|c| Serde(c.clone())).collect(); - let _ = ws.global().core_resource_thread().send( - SetCookiesForUrl(ws.url.clone(), cookies, HTTP)); - } - - // Step 6. + // Step 4. ws.upcast().fire_event(atom!("open")); } } |