aboutsummaryrefslogtreecommitdiffstats
path: root/components/net/websocket_loader.rs
diff options
context:
space:
mode:
authorAnthony Ramine <n.oxyde@gmail.com>2017-03-23 17:02:52 +0100
committerAnthony Ramine <n.oxyde@gmail.com>2017-03-24 09:43:14 +0100
commit0bd54b904bf8b926afb60f4be0554bc37b30464b (patch)
tree1489467a0fd3fbf41d54fecae20398d0d1f6909f /components/net/websocket_loader.rs
parentbba0be13dd07116d02fd0f2e6d73d1ecb8e952bb (diff)
downloadservo-0bd54b904bf8b926afb60f4be0554bc37b30464b.tar.gz
servo-0bd54b904bf8b926afb60f4be0554bc37b30464b.zip
Properly follow the spec in WebSocket::Constructor
Diffstat (limited to 'components/net/websocket_loader.rs')
-rw-r--r--components/net/websocket_loader.rs108
1 files changed, 64 insertions, 44 deletions
diff --git a/components/net/websocket_loader.rs b/components/net/websocket_loader.rs
index 186909c9314..6c0392ab65a 100644
--- a/components/net/websocket_loader.rs
+++ b/components/net/websocket_loader.rs
@@ -2,11 +2,13 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+use cookie::Cookie;
use cookie_storage::CookieStorage;
+use fetch::methods::should_be_blocked_due_to_bad_port;
use http_loader;
-use hyper::header::Host;
-use net_traits::{WebSocketCommunicate, WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
-use net_traits::MessageData;
+use hyper::header::{Host, SetCookie};
+use net_traits::{CookieSource, MessageData, WebSocketCommunicate};
+use net_traits::{WebSocketConnectData, WebSocketDomAction, WebSocketNetworkEvent};
use net_traits::hosts::replace_hosts;
use net_traits::unwrap_websocket_protocol;
use servo_url::ServoUrl;
@@ -23,72 +25,90 @@ use websocket::sender::Sender;
use websocket::stream::WebSocketStream;
use websocket::ws::receiver::Receiver as WSReceiver;
use websocket::ws::sender::Sender as Sender_Object;
-use websocket::ws::util::url::parse_url;
-/// *Establish a WebSocket Connection* as defined in RFC 6455.
-fn establish_a_websocket_connection(resource_url: &ServoUrl, net_url: (Host, String, bool),
- origin: String, protocols: Vec<String>,
+// https://fetch.spec.whatwg.org/#concept-websocket-establish
+fn establish_a_websocket_connection(resource_url: &ServoUrl,
+ origin: String,
+ protocols: Vec<String>,
cookie_jar: Arc<RwLock<CookieStorage>>)
- -> WebSocketResult<(Headers, Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
- let host = Host {
+ -> WebSocketResult<(Headers, Sender<WebSocketStream>, Receiver<WebSocketStream>)> {
+ // Steps 1-2 are not really applicable here, given we don't exactly go
+ // through the same infrastructure as the Fetch spec.
+
+ if should_be_blocked_due_to_bad_port(resource_url) {
+ // Subset of steps 11-12, we inline the bad port check here from the
+ // main fetch algorithm for the same reason steps 1-2 are not
+ // applicable.
+ return Err(WebSocketError::RequestError("Request should be blocked due to bad port."));
+ }
+
+ // Steps 3-7.
+ let net_url = replace_hosts(resource_url);
+ let mut request = try!(Client::connect(net_url.as_url()));
+
+ // Client::connect sets the Host header to the host of the URL that is
+ // passed to it, so we need to reset it afterwards to the correct one.
+ request.headers.set(Host {
hostname: resource_url.host_str().unwrap().to_owned(),
- port: resource_url.port_or_known_default(),
- };
+ port: resource_url.port(),
+ });
- let mut request = try!(Client::connect(net_url));
- request.headers.set(Origin(origin));
- request.headers.set(host);
+ // Step 8.
if !protocols.is_empty() {
request.headers.set(WebSocketProtocol(protocols.clone()));
- };
+ }
+
+ // Steps 9-10.
+ // TODO: support for permessage-deflate extension.
+ // Subset of step 11.
+ // See step 2 of https://fetch.spec.whatwg.org/#concept-fetch.
+ request.headers.set(Origin(origin));
+
+ // Transitive subset of step 11.
+ // See step 17.1 of https://fetch.spec.whatwg.org/#concept-http-network-or-cache-fetch.
http_loader::set_request_cookies(&resource_url, &mut request.headers, &cookie_jar);
+ // Step 11, somewhat.
let response = try!(request.send());
+
+ // Step 12, 14.
try!(response.validate());
- {
- 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"));
- };
+ // Step 13 and transitive subset of step 14.
+ // See step 6 of http://tools.ietf.org/html/rfc6455#section-4.1.
+ if let Some(protocol_name) = unwrap_websocket_protocol(response.protocol()) {
+ 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"));
};
+ };
+
+ // Transitive subset of step 11.
+ // See step 15 of https://fetch.spec.whatwg.org/#http-network-fetch.
+ if let Some(cookies) = response.headers.get::<SetCookie>() {
+ let mut jar = cookie_jar.write().unwrap();
+ for cookie in &**cookies {
+ if let Some(cookie) = Cookie::new_wrapped(cookie.clone(), resource_url, CookieSource::HTTP) {
+ jar.push(cookie, resource_url, CookieSource::HTTP);
+ }
+ }
}
let headers = response.headers.clone();
let (sender, receiver) = response.begin().split();
Ok((headers, sender, receiver))
-
}
pub fn init(connect: WebSocketCommunicate, connect_data: WebSocketConnectData, cookie_jar: Arc<RwLock<CookieStorage>>) {
thread::Builder::new().name(format!("WebSocket connection to {}", connect_data.resource_url)).spawn(move || {
- // Step 8: Protocols.
-
- // Step 9.
-
- // URL that we actually fetch from the network, after applying the replacements
- // specified in the hosts file.
- let net_url_result = parse_url(replace_hosts(&connect_data.resource_url).as_url());
- let net_url = match net_url_result {
- Ok(net_url) => net_url,
- Err(e) => {
- debug!("Failed to establish a WebSocket connection: {:?}", e);
- let _ = connect.event_sender.send(WebSocketNetworkEvent::Fail);
- return;
- }
- };
let channel = establish_a_websocket_connection(&connect_data.resource_url,
- net_url,
connect_data.origin,
- connect_data.protocols.clone(),
+ connect_data.protocols,
cookie_jar);
- let (_, ws_sender, mut receiver) = match channel {
- Ok(channel) => {
- let _ = connect.event_sender.send(WebSocketNetworkEvent::ConnectionEstablished(channel.0.clone(),
- connect_data.protocols));
- channel
+ let (ws_sender, mut receiver) = match channel {
+ Ok((headers, sender, receiver)) => {
+ let _ = connect.event_sender.send(WebSocketNetworkEvent::ConnectionEstablished(headers));
+ (sender, receiver)
},
Err(e) => {
debug!("Failed to establish a WebSocket connection: {:?}", e);