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