diff --git a/examples/srv_accept_unmasked_frames.rs b/examples/srv_accept_unmasked_frames.rs new file mode 100644 index 0000000..04acbfc --- /dev/null +++ b/examples/srv_accept_unmasked_frames.rs @@ -0,0 +1,50 @@ +use std::{net::TcpListener, thread::spawn}; +use tungstenite::{ + handshake::server::{Request, Response}, + protocol::WebSocketConfig, + server::accept_hdr_with_config, +}; + +fn main() { + env_logger::init(); + let server = TcpListener::bind("127.0.0.1:3012").unwrap(); + for stream in server.incoming() { + spawn(move || { + let callback = |req: &Request, mut response: Response| { + println!("Received a new ws handshake"); + println!("The request's path is: {}", req.uri().path()); + println!("The request's headers are:"); + for (ref header, _value) in req.headers() { + println!("* {}", header); + } + + // Let's add an additional header to our response to the client. + let headers = response.headers_mut(); + headers.append("MyCustomHeader", ":)".parse().unwrap()); + headers.append("SOME_TUNGSTENITE_HEADER", "header_value".parse().unwrap()); + + Ok(response) + }; + + let config = Some(WebSocketConfig { + max_send_queue: None, + max_message_size: None, + max_frame_size: None, + // This setting allows to accept client frames which are not masked + // This is not in compliance with RFC 6455 but might be handy in some + // rare cases where it is necessary to integrate with existing/legacy + // clients which are sending unmasked frames + server_allow_unmasked: Some(true), + }); + + let mut websocket = accept_hdr_with_config(stream.unwrap(), callback, config).unwrap(); + + loop { + let msg = websocket.read_message().unwrap(); + if msg.is_binary() || msg.is_text() { + println!("received message {}", msg); + } + } + }); + } +} diff --git a/src/protocol/mod.rs b/src/protocol/mod.rs index 72485e9..6714005 100644 --- a/src/protocol/mod.rs +++ b/src/protocol/mod.rs @@ -50,6 +50,11 @@ pub struct WebSocketConfig { /// be reasonably big for all normal use-cases but small enough to prevent memory eating /// by a malicious user. pub max_frame_size: Option, + /// If set to true it will allow the websocket server to accept unmasked frames from client. + /// Even though this behaviour is not in compliance with RFC 6455 (which requires the server + /// to close the connection when unmasked frame from client is received) it might be handy in some cases + /// as there are existing applications sending unmasked client frames. + pub server_allow_unmasked: Option, } impl Default for WebSocketConfig { @@ -58,6 +63,7 @@ impl Default for WebSocketConfig { max_send_queue: None, max_message_size: Some(64 << 20), max_frame_size: Some(16 << 20), + server_allow_unmasked: None, } } } @@ -449,9 +455,22 @@ impl WebSocketContext { } 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(), - )); + // The only exception here is if the user explicitly accepts given + // stream (by tungstenite::server::accept_with_config or tungstenite::server::accept_hdr_with_config) + // with WebSocketConfig.server_allow_unmasked set to Some(true) + if let Some(server_allow_unmasked_val) = + self.get_config().server_allow_unmasked + { + if server_allow_unmasked_val == false { + return Err(Error::Protocol( + "Received an unmasked frame from client".into(), + )); + } + } else { + return Err(Error::Protocol( + "Received an unmasked frame from client".into(), + )); + } } } Role::Client => {