|
|
|
@ -8,13 +8,13 @@ pub use self::message::Message; |
|
|
|
|
pub use self::frame::CloseFrame; |
|
|
|
|
|
|
|
|
|
use std::collections::VecDeque; |
|
|
|
|
use std::io::{Read, Write, ErrorKind as IoErrorKind}; |
|
|
|
|
use std::io::{ErrorKind as IoErrorKind, Read, Write}; |
|
|
|
|
use std::mem::replace; |
|
|
|
|
|
|
|
|
|
use error::{Error, Result}; |
|
|
|
|
use self::message::{IncompleteMessage, IncompleteMessageType}; |
|
|
|
|
use self::frame::{Frame, FrameSocket}; |
|
|
|
|
use self::frame::coding::{OpCode, Data as OpData, Control as OpCtl, CloseCode}; |
|
|
|
|
use self::frame::coding::{CloseCode, Control as OpCtl, Data as OpData, OpCode}; |
|
|
|
|
use util::NonBlockingResult; |
|
|
|
|
|
|
|
|
|
/// Indicates a Client or Server role of the websocket
|
|
|
|
@ -30,6 +30,7 @@ pub enum Role { |
|
|
|
|
///
|
|
|
|
|
/// This is THE structure you want to create to be able to speak the WebSocket protocol.
|
|
|
|
|
/// It may be created by calling `connect`, `accept` or `client` functions.
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
pub struct WebSocket<Stream> { |
|
|
|
|
/// Server or client?
|
|
|
|
|
role: Role, |
|
|
|
@ -93,7 +94,7 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
let res = self.read_message_frame(); |
|
|
|
|
if let Some(message) = self.translate_close(res)? { |
|
|
|
|
trace!("Received message {}", message); |
|
|
|
|
return Ok(message) |
|
|
|
|
return Ok(message); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -108,16 +109,12 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
/// most recent pong frame is sent if multiple pong frames are queued up.
|
|
|
|
|
pub fn write_message(&mut self, message: Message) -> Result<()> { |
|
|
|
|
let frame = match message { |
|
|
|
|
Message::Text(data) => { |
|
|
|
|
Frame::message(data.into(), OpCode::Data(OpData::Text), true) |
|
|
|
|
} |
|
|
|
|
Message::Binary(data) => { |
|
|
|
|
Frame::message(data, OpCode::Data(OpData::Binary), true) |
|
|
|
|
} |
|
|
|
|
Message::Text(data) => Frame::message(data.into(), OpCode::Data(OpData::Text), true), |
|
|
|
|
Message::Binary(data) => Frame::message(data, OpCode::Data(OpData::Binary), true), |
|
|
|
|
Message::Ping(data) => Frame::ping(data), |
|
|
|
|
Message::Pong(data) => { |
|
|
|
|
self.pong = Some(Frame::pong(data)); |
|
|
|
|
return self.write_pending() |
|
|
|
|
return self.write_pending(); |
|
|
|
|
} |
|
|
|
|
}; |
|
|
|
|
self.send_queue.push_back(frame); |
|
|
|
@ -182,14 +179,13 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
/// Try to decode one message frame. May return None.
|
|
|
|
|
fn read_message_frame(&mut self) -> Result<Option<Message>> { |
|
|
|
|
if let Some(mut frame) = self.socket.read_frame()? { |
|
|
|
|
|
|
|
|
|
// MUST be 0 unless an extension is negotiated that defines meanings
|
|
|
|
|
// for non-zero values. If a nonzero value is received and none of
|
|
|
|
|
// the negotiated extensions defines the meaning of such a nonzero
|
|
|
|
|
// value, the receiving endpoint MUST _Fail the WebSocket
|
|
|
|
|
// Connection_.
|
|
|
|
|
if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() { |
|
|
|
|
return Err(Error::Protocol("Reserved bits are non-zero".into())) |
|
|
|
|
return Err(Error::Protocol("Reserved bits are non-zero".into())); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
match self.role { |
|
|
|
@ -201,19 +197,22 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
} else { |
|
|
|
|
// The server MUST close the connection upon receiving a
|
|
|
|
|
// frame that is not masked. (RFC 6455)
|
|
|
|
|
return Err(Error::Protocol("Received an unmasked frame from client".into())) |
|
|
|
|
return Err(Error::Protocol( |
|
|
|
|
"Received an unmasked frame from client".into(), |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
Role::Client => { |
|
|
|
|
if frame.is_masked() { |
|
|
|
|
// A client MUST close a connection if it detects a masked frame. (RFC 6455)
|
|
|
|
|
return Err(Error::Protocol("Received a masked frame from server".into())) |
|
|
|
|
return Err(Error::Protocol( |
|
|
|
|
"Received a masked frame from server".into(), |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
match frame.opcode() { |
|
|
|
|
|
|
|
|
|
OpCode::Control(ctl) => { |
|
|
|
|
match ctl { |
|
|
|
|
// All control frames MUST have a payload length of 125 bytes or less
|
|
|
|
@ -224,12 +223,10 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
_ if frame.payload().len() > 125 => { |
|
|
|
|
Err(Error::Protocol("Control frame too big".into())) |
|
|
|
|
} |
|
|
|
|
OpCtl::Close => { |
|
|
|
|
self.do_close(frame.into_close()?).map(|_| None) |
|
|
|
|
} |
|
|
|
|
OpCtl::Reserved(i) => { |
|
|
|
|
Err(Error::Protocol(format!("Unknown control frame type {}", i).into())) |
|
|
|
|
} |
|
|
|
|
OpCtl::Close => self.do_close(frame.into_close()?).map(|_| None), |
|
|
|
|
OpCtl::Reserved(i) => Err(Error::Protocol( |
|
|
|
|
format!("Unknown control frame type {}", i).into(), |
|
|
|
|
)), |
|
|
|
|
OpCtl::Ping | OpCtl::Pong if !self.state.is_active() => { |
|
|
|
|
// No ping processing while closing.
|
|
|
|
|
Ok(None) |
|
|
|
@ -239,9 +236,7 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
self.pong = Some(Frame::pong(data.clone())); |
|
|
|
|
Ok(Some(Message::Ping(data))) |
|
|
|
|
} |
|
|
|
|
OpCtl::Pong => { |
|
|
|
|
Ok(Some(Message::Pong(frame.into_data()))) |
|
|
|
|
} |
|
|
|
|
OpCtl::Pong => Ok(Some(Message::Pong(frame.into_data()))), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -258,19 +253,21 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
// TODO if msg too big
|
|
|
|
|
msg.extend(frame.into_data())?; |
|
|
|
|
} else { |
|
|
|
|
return Err(Error::Protocol("Continue frame but nothing to continue".into())) |
|
|
|
|
return Err(Error::Protocol( |
|
|
|
|
"Continue frame but nothing to continue".into(), |
|
|
|
|
)); |
|
|
|
|
} |
|
|
|
|
if fin { |
|
|
|
|
Ok(Some(replace(&mut self.incomplete, None).unwrap().complete()?)) |
|
|
|
|
Ok(Some(replace(&mut self.incomplete, None) |
|
|
|
|
.unwrap() |
|
|
|
|
.complete()?)) |
|
|
|
|
} else { |
|
|
|
|
Ok(None) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
c if self.incomplete.is_some() => { |
|
|
|
|
Err(Error::Protocol( |
|
|
|
|
format!("Received {} while waiting for more fragments", c).into() |
|
|
|
|
)) |
|
|
|
|
} |
|
|
|
|
c if self.incomplete.is_some() => Err(Error::Protocol( |
|
|
|
|
format!("Received {} while waiting for more fragments", c).into(), |
|
|
|
|
)), |
|
|
|
|
OpData::Text | OpData::Binary => { |
|
|
|
|
let msg = { |
|
|
|
|
let message_type = match data { |
|
|
|
@ -289,22 +286,20 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
Ok(None) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
OpData::Reserved(i) => { |
|
|
|
|
Err(Error::Protocol(format!("Unknown data frame type {}", i).into())) |
|
|
|
|
} |
|
|
|
|
OpData::Reserved(i) => Err(Error::Protocol( |
|
|
|
|
format!("Unknown data frame type {}", i).into(), |
|
|
|
|
)), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} // match opcode
|
|
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
match replace(&mut self.state, WebSocketState::Terminated) { |
|
|
|
|
WebSocketState::CloseAcknowledged(close) | WebSocketState::ClosedByPeer(close) => { |
|
|
|
|
Err(Error::ConnectionClosed(close)) |
|
|
|
|
} |
|
|
|
|
_ => { |
|
|
|
|
Err(Error::Protocol("Connection reset without closing handshake".into())) |
|
|
|
|
} |
|
|
|
|
_ => Err(Error::Protocol( |
|
|
|
|
"Connection reset without closing handshake".into(), |
|
|
|
|
)), |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -325,7 +320,7 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
} else { |
|
|
|
|
Frame::close(Some(CloseFrame { |
|
|
|
|
code: CloseCode::Protocol, |
|
|
|
|
reason: "Protocol violation".into() |
|
|
|
|
reason: "Protocol violation".into(), |
|
|
|
|
})) |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
@ -361,8 +356,7 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
/// Send a single pending frame.
|
|
|
|
|
fn send_one_frame(&mut self, mut frame: Frame) -> Result<()> { |
|
|
|
|
match self.role { |
|
|
|
|
Role::Server => { |
|
|
|
|
} |
|
|
|
|
Role::Server => {} |
|
|
|
|
Role::Client => { |
|
|
|
|
// 5. If the data is being sent by the client, the frame(s) MUST be
|
|
|
|
|
// masked as defined in Section 5.3. (RFC 6455)
|
|
|
|
@ -379,10 +373,12 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
Err(Error::Io(err)) => Err({ |
|
|
|
|
if err.kind() == IoErrorKind::ConnectionReset { |
|
|
|
|
match self.state { |
|
|
|
|
WebSocketState::ClosedByPeer(ref mut frame) => |
|
|
|
|
Error::ConnectionClosed(replace(frame, None)), |
|
|
|
|
WebSocketState::CloseAcknowledged(ref mut frame) => |
|
|
|
|
Error::ConnectionClosed(replace(frame, None)), |
|
|
|
|
WebSocketState::ClosedByPeer(ref mut frame) => { |
|
|
|
|
Error::ConnectionClosed(replace(frame, None)) |
|
|
|
|
} |
|
|
|
|
WebSocketState::CloseAcknowledged(ref mut frame) => { |
|
|
|
|
Error::ConnectionClosed(replace(frame, None)) |
|
|
|
|
} |
|
|
|
|
_ => Error::Io(err), |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
@ -392,10 +388,10 @@ impl<Stream: Read + Write> WebSocket<Stream> { |
|
|
|
|
x => x, |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// The current connection state.
|
|
|
|
|
#[derive(Debug)] |
|
|
|
|
enum WebSocketState { |
|
|
|
|
/// The connection is active.
|
|
|
|
|
Active, |
|
|
|
@ -421,7 +417,7 @@ impl WebSocketState { |
|
|
|
|
|
|
|
|
|
#[cfg(test)] |
|
|
|
|
mod tests { |
|
|
|
|
use super::{WebSocket, Role, Message}; |
|
|
|
|
use super::{Message, Role, WebSocket}; |
|
|
|
|
|
|
|
|
|
use std::io; |
|
|
|
|
use std::io::Cursor; |
|
|
|
@ -443,24 +439,24 @@ mod tests { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#[test] |
|
|
|
|
fn receive_messages() { |
|
|
|
|
let incoming = Cursor::new(vec![ |
|
|
|
|
0x89, 0x02, 0x01, 0x02, |
|
|
|
|
0x8a, 0x01, 0x03, |
|
|
|
|
0x01, 0x07, |
|
|
|
|
0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x2c, 0x20, |
|
|
|
|
0x80, 0x06, |
|
|
|
|
0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, |
|
|
|
|
0x82, 0x03, |
|
|
|
|
0x01, 0x02, 0x03, |
|
|
|
|
0x89, 0x02, 0x01, 0x02, 0x8a, 0x01, 0x03, 0x01, 0x07, 0x48, 0x65, 0x6c, 0x6c, 0x6f, |
|
|
|
|
0x2c, 0x20, 0x80, 0x06, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x21, 0x82, 0x03, 0x01, 0x02, |
|
|
|
|
0x03, |
|
|
|
|
]); |
|
|
|
|
let mut socket = WebSocket::from_raw_socket(WriteMoc(incoming), Role::Client); |
|
|
|
|
assert_eq!(socket.read_message().unwrap(), Message::Ping(vec![1, 2])); |
|
|
|
|
assert_eq!(socket.read_message().unwrap(), Message::Pong(vec![3])); |
|
|
|
|
assert_eq!(socket.read_message().unwrap(), Message::Text("Hello, World!".into())); |
|
|
|
|
assert_eq!(socket.read_message().unwrap(), Message::Binary(vec![0x01, 0x02, 0x03])); |
|
|
|
|
assert_eq!( |
|
|
|
|
socket.read_message().unwrap(), |
|
|
|
|
Message::Text("Hello, World!".into()) |
|
|
|
|
); |
|
|
|
|
assert_eq!( |
|
|
|
|
socket.read_message().unwrap(), |
|
|
|
|
Message::Binary(vec![0x01, 0x02, 0x03]) |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|