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