1 use log::Level::Error as ErrorLevel; 2 #[cfg(feature = "nativetls")] 3 use native_tls::{TlsConnector, TlsStream as SslStream}; 4 #[cfg(feature = "ssl")] 5 use openssl::ssl::{SslConnector, SslMethod, SslStream}; 6 use url; 7 8 use frame::Frame; 9 use handshake::{Handshake, Request, Response}; 10 use message::Message; 11 use protocol::CloseCode; 12 use result::{Error, Kind, Result}; 13 use util::{Timeout, Token}; 14 15 #[cfg(any(feature = "ssl", feature = "nativetls"))] 16 use util::TcpStream; 17 18 /// The core trait of this library. 19 /// Implementing this trait provides the business logic of the WebSocket application. 20 pub trait Handler { 21 // general 22 23 /// Called when a request to shutdown all connections has been received. 24 #[inline] on_shutdown(&mut self)25 fn on_shutdown(&mut self) { 26 debug!("Handler received WebSocket shutdown request."); 27 } 28 29 // WebSocket events 30 31 /// Called when the WebSocket handshake is successful and the connection is open for sending 32 /// and receiving messages. on_open(&mut self, shake: Handshake) -> Result<()>33 fn on_open(&mut self, shake: Handshake) -> Result<()> { 34 if let Some(addr) = shake.remote_addr()? { 35 debug!("Connection with {} now open", addr); 36 } 37 Ok(()) 38 } 39 40 /// Called on incoming messages. on_message(&mut self, msg: Message) -> Result<()>41 fn on_message(&mut self, msg: Message) -> Result<()> { 42 debug!("Received message {:?}", msg); 43 Ok(()) 44 } 45 46 /// Called any time this endpoint receives a close control frame. 47 /// This may be because the other endpoint is initiating a closing handshake, 48 /// or it may be the other endpoint confirming the handshake initiated by this endpoint. on_close(&mut self, code: CloseCode, reason: &str)49 fn on_close(&mut self, code: CloseCode, reason: &str) { 50 debug!("Connection closing due to ({:?}) {}", code, reason); 51 } 52 53 /// Called when an error occurs on the WebSocket. on_error(&mut self, err: Error)54 fn on_error(&mut self, err: Error) { 55 // Ignore connection reset errors by default, but allow library clients to see them by 56 // overriding this method if they want 57 if let Kind::Io(ref err) = err.kind { 58 if let Some(104) = err.raw_os_error() { 59 return; 60 } 61 } 62 63 error!("{:?}", err); 64 if !log_enabled!(ErrorLevel) { 65 println!( 66 "Encountered an error: {}\nEnable a logger to see more information.", 67 err 68 ); 69 } 70 } 71 72 // handshake events 73 74 /// A method for handling the low-level workings of the request portion of the WebSocket 75 /// handshake. 76 /// 77 /// Implementors should select a WebSocket protocol and extensions where they are supported. 78 /// 79 /// Implementors can inspect the Request and must return a Response or an error 80 /// indicating that the handshake failed. The default implementation provides conformance with 81 /// the WebSocket protocol, and implementors should use the `Response::from_request` method and 82 /// then modify the resulting response as necessary in order to maintain conformance. 83 /// 84 /// This method will not be called when the handler represents a client endpoint. Use 85 /// `build_request` to provide an initial handshake request. 86 /// 87 /// # Examples 88 /// 89 /// ```ignore 90 /// let mut res = try!(Response::from_request(req)); 91 /// if try!(req.extensions()).iter().find(|&&ext| ext.contains("myextension-name")).is_some() { 92 /// res.add_extension("myextension-name") 93 /// } 94 /// Ok(res) 95 /// ``` 96 #[inline] on_request(&mut self, req: &Request) -> Result<Response>97 fn on_request(&mut self, req: &Request) -> Result<Response> { 98 debug!("Handler received request:\n{}", req); 99 Response::from_request(req) 100 } 101 102 /// A method for handling the low-level workings of the response portion of the WebSocket 103 /// handshake. 104 /// 105 /// Implementors can inspect the Response and choose to fail the connection by 106 /// returning an error. This method will not be called when the handler represents a server 107 /// endpoint. The response should indicate which WebSocket protocol and extensions the server 108 /// has agreed to if any. 109 #[inline] on_response(&mut self, res: &Response) -> Result<()>110 fn on_response(&mut self, res: &Response) -> Result<()> { 111 debug!("Handler received response:\n{}", res); 112 Ok(()) 113 } 114 115 // timeout events 116 117 /// Called when a timeout is triggered. 118 /// 119 /// This method will be called when the eventloop encounters a timeout on the specified 120 /// token. To schedule a timeout with your specific token use the `Sender::timeout` method. 121 /// 122 /// # Examples 123 /// 124 /// ```ignore 125 /// const GRATI: Token = Token(1); 126 /// 127 /// ... Handler 128 /// 129 /// fn on_open(&mut self, _: Handshake) -> Result<()> { 130 /// // schedule a timeout to send a gratuitous pong every 5 seconds 131 /// self.ws.timeout(5_000, GRATI) 132 /// } 133 /// 134 /// fn on_timeout(&mut self, event: Token) -> Result<()> { 135 /// if event == GRATI { 136 /// // send gratuitous pong 137 /// try!(self.ws.pong(vec![])) 138 /// // reschedule the timeout 139 /// self.ws.timeout(5_000, GRATI) 140 /// } else { 141 /// Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!")) 142 /// } 143 /// } 144 /// ``` 145 #[inline] on_timeout(&mut self, event: Token) -> Result<()>146 fn on_timeout(&mut self, event: Token) -> Result<()> { 147 debug!("Handler received timeout token: {:?}", event); 148 Ok(()) 149 } 150 151 /// Called when a timeout has been scheduled on the eventloop. 152 /// 153 /// This method is the hook for obtaining a Timeout object that may be used to cancel a 154 /// timeout. This is a noop by default. 155 /// 156 /// # Examples 157 /// 158 /// ```ignore 159 /// const PING: Token = Token(1); 160 /// const EXPIRE: Token = Token(2); 161 /// 162 /// ... Handler 163 /// 164 /// fn on_open(&mut self, _: Handshake) -> Result<()> { 165 /// // schedule a timeout to send a ping every 5 seconds 166 /// try!(self.ws.timeout(5_000, PING)); 167 /// // schedule a timeout to close the connection if there is no activity for 30 seconds 168 /// self.ws.timeout(30_000, EXPIRE) 169 /// } 170 /// 171 /// fn on_timeout(&mut self, event: Token) -> Result<()> { 172 /// match event { 173 /// PING => { 174 /// self.ws.ping(vec![]); 175 /// self.ws.timeout(5_000, PING) 176 /// } 177 /// EXPIRE => self.ws.close(CloseCode::Away), 178 /// _ => Err(Error::new(ErrorKind::Internal, "Invalid timeout token encountered!")), 179 /// } 180 /// } 181 /// 182 /// fn on_new_timeout(&mut self, event: Token, timeout: Timeout) -> Result<()> { 183 /// if event == EXPIRE { 184 /// if let Some(t) = self.timeout.take() { 185 /// try!(self.ws.cancel(t)) 186 /// } 187 /// self.timeout = Some(timeout) 188 /// } 189 /// Ok(()) 190 /// } 191 /// 192 /// fn on_frame(&mut self, frame: Frame) -> Result<Option<Frame>> { 193 /// // some activity has occurred, let's reset the expiration 194 /// try!(self.ws.timeout(30_000, EXPIRE)); 195 /// Ok(Some(frame)) 196 /// } 197 /// ``` 198 #[inline] on_new_timeout(&mut self, _: Token, _: Timeout) -> Result<()>199 fn on_new_timeout(&mut self, _: Token, _: Timeout) -> Result<()> { 200 // default implementation discards the timeout handle 201 Ok(()) 202 } 203 204 // frame events 205 206 /// A method for handling incoming frames. 207 /// 208 /// This method provides very low-level access to the details of the WebSocket protocol. It may 209 /// be necessary to implement this method in order to provide a particular extension, but 210 /// incorrect implementation may cause the other endpoint to fail the connection. 211 /// 212 /// Returning `Ok(None)` will cause the connection to forget about a particular frame. This is 213 /// useful if you want ot filter out a frame or if you don't want any of the default handler 214 /// methods to run. 215 /// 216 /// By default this method simply ensures that no reserved bits are set. 217 #[inline] on_frame(&mut self, frame: Frame) -> Result<Option<Frame>>218 fn on_frame(&mut self, frame: Frame) -> Result<Option<Frame>> { 219 debug!("Handler received: {}", frame); 220 // default implementation doesn't allow for reserved bits to be set 221 if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() { 222 Err(Error::new( 223 Kind::Protocol, 224 "Encountered frame with reserved bits set.", 225 )) 226 } else { 227 Ok(Some(frame)) 228 } 229 } 230 231 /// A method for handling outgoing frames. 232 /// 233 /// This method provides very low-level access to the details of the WebSocket protocol. It may 234 /// be necessary to implement this method in order to provide a particular extension, but 235 /// incorrect implementation may cause the other endpoint to fail the connection. 236 /// 237 /// Returning `Ok(None)` will cause the connection to forget about a particular frame, meaning 238 /// that it will not be sent. You can use this approach to merge multiple frames into a single 239 /// frame before sending the message. 240 /// 241 /// For messages, this method will be called with a single complete, final frame before any 242 /// fragmentation is performed. Automatic fragmentation will be performed on the returned 243 /// frame, if any, based on the `fragment_size` setting. 244 /// 245 /// By default this method simply ensures that no reserved bits are set. 246 #[inline] on_send_frame(&mut self, frame: Frame) -> Result<Option<Frame>>247 fn on_send_frame(&mut self, frame: Frame) -> Result<Option<Frame>> { 248 trace!("Handler will send: {}", frame); 249 // default implementation doesn't allow for reserved bits to be set 250 if frame.has_rsv1() || frame.has_rsv2() || frame.has_rsv3() { 251 Err(Error::new( 252 Kind::Protocol, 253 "Encountered frame with reserved bits set.", 254 )) 255 } else { 256 Ok(Some(frame)) 257 } 258 } 259 260 // constructors 261 262 /// A method for creating the initial handshake request for WebSocket clients. 263 /// 264 /// The default implementation provides conformance with the WebSocket protocol, but this 265 /// method may be overridden. In order to facilitate conformance, 266 /// implementors should use the `Request::from_url` method and then modify the resulting 267 /// request as necessary. 268 /// 269 /// Implementors should indicate any available WebSocket extensions here. 270 /// 271 /// # Examples 272 /// ```ignore 273 /// let mut req = try!(Request::from_url(url)); 274 /// req.add_extension("permessage-deflate; client_max_window_bits"); 275 /// Ok(req) 276 /// ``` 277 #[inline] build_request(&mut self, url: &url::Url) -> Result<Request>278 fn build_request(&mut self, url: &url::Url) -> Result<Request> { 279 trace!("Handler is building request to {}.", url); 280 Request::from_url(url) 281 } 282 283 /// A method for wrapping a client TcpStream with Ssl Authentication machinery 284 /// 285 /// Override this method to customize how the connection is encrypted. By default 286 /// this will use the Server Name Indication extension in conformance with RFC6455. 287 #[inline] 288 #[cfg(feature = "ssl")] upgrade_ssl_client( &mut self, stream: TcpStream, url: &url::Url, ) -> Result<SslStream<TcpStream>>289 fn upgrade_ssl_client( 290 &mut self, 291 stream: TcpStream, 292 url: &url::Url, 293 ) -> Result<SslStream<TcpStream>> { 294 let domain = url.domain().ok_or(Error::new( 295 Kind::Protocol, 296 format!("Unable to parse domain from {}. Needed for SSL.", url), 297 ))?; 298 let connector = SslConnector::builder(SslMethod::tls()) 299 .map_err(|e| { 300 Error::new( 301 Kind::Internal, 302 format!("Failed to upgrade client to SSL: {}", e), 303 ) 304 })? 305 .build(); 306 connector.connect(domain, stream).map_err(Error::from) 307 } 308 309 #[inline] 310 #[cfg(feature = "nativetls")] upgrade_ssl_client( &mut self, stream: TcpStream, url: &url::Url, ) -> Result<SslStream<TcpStream>>311 fn upgrade_ssl_client( 312 &mut self, 313 stream: TcpStream, 314 url: &url::Url, 315 ) -> Result<SslStream<TcpStream>> { 316 let domain = url.domain().ok_or(Error::new( 317 Kind::Protocol, 318 format!("Unable to parse domain from {}. Needed for SSL.", url), 319 ))?; 320 321 let connector = TlsConnector::new().map_err(|e| { 322 Error::new( 323 Kind::Internal, 324 format!("Failed to upgrade client to SSL: {}", e), 325 ) 326 })?; 327 328 connector.connect(domain, stream).map_err(Error::from) 329 } 330 /// A method for wrapping a server TcpStream with Ssl Authentication machinery 331 /// 332 /// Override this method to customize how the connection is encrypted. By default 333 /// this method is not implemented. 334 #[inline] 335 #[cfg(any(feature = "ssl", feature = "nativetls"))] upgrade_ssl_server(&mut self, _: TcpStream) -> Result<SslStream<TcpStream>>336 fn upgrade_ssl_server(&mut self, _: TcpStream) -> Result<SslStream<TcpStream>> { 337 unimplemented!() 338 } 339 } 340 341 impl<F> Handler for F 342 where 343 F: Fn(Message) -> Result<()>, 344 { on_message(&mut self, msg: Message) -> Result<()>345 fn on_message(&mut self, msg: Message) -> Result<()> { 346 self(msg) 347 } 348 } 349 350 mod test { 351 #![allow(unused_imports, unused_variables, dead_code)] 352 use super::*; 353 use frame; 354 use handshake::{Handshake, Request, Response}; 355 use message; 356 use mio; 357 use protocol::CloseCode; 358 use result::Result; 359 use url; 360 361 #[derive(Debug, Eq, PartialEq)] 362 struct M; 363 impl Handler for M { on_message(&mut self, _: message::Message) -> Result<()>364 fn on_message(&mut self, _: message::Message) -> Result<()> { 365 println!("test"); 366 Ok(()) 367 } 368 on_frame(&mut self, f: frame::Frame) -> Result<Option<frame::Frame>>369 fn on_frame(&mut self, f: frame::Frame) -> Result<Option<frame::Frame>> { 370 Ok(None) 371 } 372 } 373 374 #[test] handler()375 fn handler() { 376 struct H; 377 378 impl Handler for H { 379 fn on_open(&mut self, shake: Handshake) -> Result<()> { 380 assert!(shake.request.key().is_ok()); 381 assert!(shake.response.key().is_ok()); 382 Ok(()) 383 } 384 385 fn on_message(&mut self, msg: message::Message) -> Result<()> { 386 Ok(assert_eq!( 387 msg, 388 message::Message::Text(String::from("testme")) 389 )) 390 } 391 392 fn on_close(&mut self, code: CloseCode, _: &str) { 393 assert_eq!(code, CloseCode::Normal) 394 } 395 } 396 397 let mut h = H; 398 let url = url::Url::parse("wss://127.0.0.1:3012").unwrap(); 399 let req = Request::from_url(&url).unwrap(); 400 let res = Response::from_request(&req).unwrap(); 401 h.on_open(Handshake { 402 request: req, 403 response: res, 404 peer_addr: None, 405 local_addr: None, 406 }).unwrap(); 407 h.on_message(message::Message::Text("testme".to_owned())) 408 .unwrap(); 409 h.on_close(CloseCode::Normal, ""); 410 } 411 412 #[test] closure_handler()413 fn closure_handler() { 414 let mut close = |msg| { 415 assert_eq!(msg, message::Message::Binary(vec![1, 2, 3])); 416 Ok(()) 417 }; 418 419 close 420 .on_message(message::Message::Binary(vec![1, 2, 3])) 421 .unwrap(); 422 } 423 } 424