servo: Merge #10382 - stop client websocket close echoing server close (from bobthekingofegypt:fix-websocket-close); r=metajack
authorBob <bobthekingofegypt@googlemail.com>
Fri, 10 Jun 2016 08:49:53 -0500
changeset 339059 6878828310df2ecfbe70be08728bfdd7887d373e
parent 339058 261172d1f7037d80f247732a93355ade4bcb3db5
child 339060 1e9fee765f5fbe2a974fedc607bfbd42b6c5018e
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmetajack
servo: Merge #10382 - stop client websocket close echoing server close (from bobthekingofegypt:fix-websocket-close); r=metajack Client initiated close requests should send a close message to the server that the server will echo back to complete the process. Servo should not then echo the servers close request back again to the server, this guard stops servo from echoing a server close request if the process was initiated by the client. Tracked in https://github.com/servo/servo/issues/9803#issuecomment-196424406 Source-Repo: https://github.com/servo/servo Source-Revision: 96f34049286076c20ff91b260eb6a9651c0eecd6
servo/components/net/websocket_loader.rs
--- a/servo/components/net/websocket_loader.rs
+++ b/servo/components/net/websocket_loader.rs
@@ -5,16 +5,17 @@
 use cookie_storage::CookieStorage;
 use http_loader;
 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::atomic::{AtomicBool, Ordering};
 use std::sync::{Arc, Mutex, RwLock};
 use std::thread;
 use util::thread::spawn_named;
 use websocket::client::request::Url;
 use websocket::header::{Headers, Origin, WebSocketProtocol};
 use websocket::message::Type;
 use websocket::receiver::Receiver;
 use websocket::result::{WebSocketError, WebSocketResult};
@@ -93,18 +94,20 @@ pub fn init(connect: WebSocketCommunicat
             Err(e) => {
                 debug!("Failed to establish a WebSocket connection: {:?}", e);
                 let _ = connect.event_sender.send(WebSocketNetworkEvent::Fail);
                 return;
             }
 
         };
 
+        let initiated_close = Arc::new(AtomicBool::new(false));
         let ws_sender = Arc::new(Mutex::new(ws_sender));
 
+        let initiated_close_incoming = initiated_close.clone();
         let ws_sender_incoming = ws_sender.clone();
         let resource_event_sender = connect.event_sender;
         thread::spawn(move || {
             for message in receiver.incoming_messages() {
                 let message: Message = match message {
                     Ok(m) => m,
                     Err(e) => {
                         debug!("Error receiving incoming WebSocket message: {:?}", e);
@@ -117,42 +120,47 @@ pub fn init(connect: WebSocketCommunicat
                     Type::Binary => MessageData::Binary(message.payload.into_owned()),
                     Type::Ping => {
                         let pong = Message::pong(message.payload);
                         ws_sender_incoming.lock().unwrap().send_message(&pong).unwrap();
                         continue;
                     },
                     Type::Pong => continue,
                     Type::Close => {
-                        ws_sender_incoming.lock().unwrap().send_message(&message).unwrap();
+                        if !initiated_close_incoming.fetch_or(true, Ordering::SeqCst) {
+                            ws_sender_incoming.lock().unwrap().send_message(&message).unwrap();
+                        }
                         let code = message.cd_status_code;
                         let reason = String::from_utf8_lossy(&message.payload).into_owned();
                         let _ = resource_event_sender.send(WebSocketNetworkEvent::Close(code, reason));
                         break;
                     },
                 };
                 let _ = resource_event_sender.send(WebSocketNetworkEvent::MessageReceived(message));
             }
         });
 
+        let initiated_close_outgoing = initiated_close.clone();
         let ws_sender_outgoing = ws_sender.clone();
         let resource_action_receiver = connect.action_receiver;
         thread::spawn(move || {
             while let Ok(dom_action) = resource_action_receiver.recv() {
                 match dom_action {
                     WebSocketDomAction::SendMessage(MessageData::Text(data)) => {
                         ws_sender_outgoing.lock().unwrap().send_message(&Message::text(data)).unwrap();
                     },
                     WebSocketDomAction::SendMessage(MessageData::Binary(data)) => {
                         ws_sender_outgoing.lock().unwrap().send_message(&Message::binary(data)).unwrap();
                     },
                     WebSocketDomAction::Close(code, reason) => {
-                        let message = match code {
-                            Some(code) => Message::close_because(code, reason.unwrap_or("".to_owned())),
-                            None => Message::close()
-                        };
-                        ws_sender_outgoing.lock().unwrap().send_message(&message).unwrap();
+                        if !initiated_close_outgoing.fetch_or(true, Ordering::SeqCst) {
+                            let message = match code {
+                                Some(code) => Message::close_because(code, reason.unwrap_or("".to_owned())),
+                                None => Message::close()
+                            };
+                            ws_sender_outgoing.lock().unwrap().send_message(&message).unwrap();
+                        }
                     },
                 }
             }
         });
     });
 }