From dbc8bd7b71f103191b158953ae8d0a4ebcbc314f Mon Sep 17 00:00:00 2001 From: Daniel Abramov Date: Wed, 7 Aug 2019 18:56:40 +0200 Subject: [PATCH] Fix issue with hanging server connection --- src/protocol/mod.rs | 4 +-- tests/connection_reset.rs | 62 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 tests/connection_reset.rs diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 50ea169..1406e84 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -567,8 +567,8 @@ impl WebSocketState { /// Check if the state is active, return error if not. fn check_active(&self) -> Result<()> { match self { - WebSocketState::Terminated - => Err(Error::AlreadyClosed), + WebSocketState::CloseAcknowledged => Err(Error::ConnectionClosed), + WebSocketState::Terminated => Err(Error::AlreadyClosed), _ => Ok(()), } } diff --git a/tests/connection_reset.rs b/tests/connection_reset.rs new file mode 100644 index 0000000..47a0740 --- /dev/null +++ b/tests/connection_reset.rs @@ -0,0 +1,62 @@ +//! Verifies that the server returns a `ConnectionClosed` error when the connection +//! is closedd from the server's point of view and drop the underlying tcp socket. + +extern crate env_logger; +extern crate tungstenite; +extern crate url; + +use std::net::TcpListener; +use std::process::exit; +use std::thread::{spawn, sleep}; +use std::time::Duration; + +use tungstenite::{accept, connect, Error, Message}; +use url::Url; + +#[test] +fn test_close() { + env_logger::init(); + + spawn(|| { + sleep(Duration::from_secs(5)); + println!("Unit test executed too long, perhaps stuck on WOULDBLOCK..."); + exit(1); + }); + + let server = TcpListener::bind("127.0.0.1:3012").unwrap(); + + let client_thread = spawn(move || { + let (mut client, _) = connect(Url::parse("ws://localhost:3012/socket").unwrap()).unwrap(); + + client.write_message(Message::Text("Hello WebSocket".into())).unwrap(); + + let message = client.read_message().unwrap(); // receive close from server + assert!(message.is_close()); + + let err = client.read_message().unwrap_err(); // now we should get ConnectionClosed + match err { + Error::ConnectionClosed => { }, + _ => panic!("unexpected error"), + } + }); + + let client_handler = server.incoming().next().unwrap(); + let mut client_handler = accept(client_handler.unwrap()).unwrap(); + + let message = client_handler.read_message().unwrap(); + assert_eq!(message.into_data(), b"Hello WebSocket"); + + client_handler.close(None).unwrap(); // send close to client + + assert!(client_handler.read_message().unwrap().is_close()); // receive acknowledgement + + let err = client_handler.read_message().unwrap_err(); // now we should get ConnectionClosed + match err { + Error::ConnectionClosed => { }, + _ => panic!("unexpected error"), + } + + drop(client_handler); + + client_thread.join().unwrap(); +}