razer_ws/
handler.rs

1use log::Level::Error as ErrorLevel;
2#[cfg(feature = "nativetls")]
3use native_tls::{TlsConnector, TlsStream as SslStream};
4#[cfg(feature = "ssl")]
5use openssl::ssl::{SslConnector, SslMethod, SslStream};
6use url;
7
8use frame::Frame;
9use handshake::{Handshake, Request, Response};
10use message::Message;
11use protocol::CloseCode;
12use result::{Error, Kind, Result};
13use util::{Timeout, Token};
14
15#[cfg(any(feature = "ssl", feature = "nativetls"))]
16use util::TcpStream;
17
18/// The core trait of this library.
19/// Implementing this trait provides the business logic of the WebSocket application.
20pub trait Handler {
21    // general
22
23    /// Called when a request to shutdown all connections has been received.
24    #[inline]
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.
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.
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.
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.
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]
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]
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]
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]
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]
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]
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]
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")]
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")]
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"))]
336    fn upgrade_ssl_server(&mut self, _: TcpStream) -> Result<SslStream<TcpStream>> {
337        unimplemented!()
338    }
339}
340
341impl<F> Handler for F
342where
343    F: Fn(Message) -> Result<()>,
344{
345    fn on_message(&mut self, msg: Message) -> Result<()> {
346        self(msg)
347    }
348}
349
350mod 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 {
364        fn on_message(&mut self, _: message::Message) -> Result<()> {
365            println!("test");
366            Ok(())
367        }
368
369        fn on_frame(&mut self, f: frame::Frame) -> Result<Option<frame::Frame>> {
370            Ok(None)
371        }
372    }
373
374    #[test]
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]
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}