razer_ws/
lib.rs

1//! Lightweight, event-driven WebSockets for Rust.
2#![allow(deprecated)]
3#![deny(missing_copy_implementations, trivial_casts, trivial_numeric_casts, unstable_features,
4        unused_import_braces)]
5
6extern crate byteorder;
7extern crate bytes;
8extern crate httparse;
9extern crate mio;
10extern crate mio_extras;
11#[cfg(feature = "ssl")]
12extern crate openssl;
13#[cfg(feature = "nativetls")]
14extern crate native_tls;
15extern crate rand;
16extern crate sha1;
17extern crate slab;
18extern crate url;
19#[macro_use]
20extern crate log;
21
22mod communication;
23mod connection;
24mod factory;
25mod frame;
26mod handler;
27mod handshake;
28mod io;
29mod message;
30mod protocol;
31mod result;
32mod stream;
33
34#[cfg(feature = "permessage-deflate")]
35pub mod deflate;
36
37pub mod util;
38
39pub use factory::Factory;
40pub use handler::Handler;
41
42pub use communication::Sender;
43pub use frame::Frame;
44pub use handshake::{Handshake, Request, Response};
45pub use message::Message;
46pub use protocol::{CloseCode, OpCode};
47pub use result::Kind as ErrorKind;
48pub use result::{Error, Result};
49
50use std::borrow::Borrow;
51use std::default::Default;
52use std::fmt;
53use std::net::{SocketAddr, ToSocketAddrs};
54
55use mio::Poll;
56
57/// A utility function for setting up a WebSocket server.
58///
59/// # Safety
60///
61/// This function blocks until the event loop finishes running. Avoid calling this method within
62/// another WebSocket handler.
63///
64/// # Examples
65///
66/// ```no_run
67/// use ws::listen;
68///
69/// listen("127.0.0.1:3012", |out| {
70///     move |msg| {
71///        out.send(msg)
72///    }
73/// }).unwrap()
74/// ```
75///
76pub fn listen<A, F, H>(addr: A, factory: F) -> Result<()>
77where
78    A: ToSocketAddrs + fmt::Debug,
79    F: FnMut(Sender) -> H,
80    H: Handler,
81{
82    let ws = WebSocket::new(factory)?;
83    ws.listen(addr)?;
84    Ok(())
85}
86
87/// A utility function for setting up a WebSocket client.
88///
89/// # Safety
90///
91/// This function blocks until the event loop finishes running. Avoid calling this method within
92/// another WebSocket handler. If you need to establish a connection from inside of a handler,
93/// use the `connect` method on the Sender.
94///
95/// # Examples
96///
97/// ```no_run
98/// use ws::{connect, CloseCode};
99///
100/// connect("ws://127.0.0.1:3012", |out| {
101///     out.send("Hello WebSocket").unwrap();
102///
103///     move |msg| {
104///         println!("Got message: {}", msg);
105///         out.close(CloseCode::Normal)
106///     }
107/// }).unwrap()
108/// ```
109///
110pub fn connect<U, F, H>(url: U, factory: F) -> Result<()>
111where
112    U: Borrow<str>,
113    F: FnMut(Sender) -> H,
114    H: Handler,
115{
116    let mut ws = WebSocket::new(factory)?;
117    let parsed = url::Url::parse(url.borrow()).map_err(|err| {
118        Error::new(
119            ErrorKind::Internal,
120            format!("Unable to parse {} as url due to {:?}", url.borrow(), err),
121        )
122    })?;
123    ws.connect(parsed)?;
124    ws.run()?;
125    Ok(())
126}
127
128/// WebSocket settings
129#[derive(Debug, Clone, Copy)]
130pub struct Settings {
131    /// The maximum number of connections that this WebSocket will support.
132    /// The default setting is low and should be increased when expecting more
133    /// connections because this is a hard limit and no new connections beyond
134    /// this limit can be made until an old connection is dropped.
135    /// Default: 100
136    pub max_connections: usize,
137    /// The number of events anticipated per connection. The event loop queue size will
138    /// be `queue_size` * `max_connections`. In order to avoid an overflow error,
139    /// `queue_size` * `max_connections` must be less than or equal to `usize::max_value()`.
140    /// The queue is shared between connections, which means that a connection may schedule
141    /// more events than `queue_size` provided that another connection is using less than
142    /// `queue_size`. However, if the queue is maxed out a Queue error will occur.
143    /// Default: 5
144    pub queue_size: usize,
145    /// Whether to panic when unable to establish a new TCP connection.
146    /// Default: false
147    pub panic_on_new_connection: bool,
148    /// Whether to panic when a shutdown of the WebSocket is requested.
149    /// Default: false
150    pub panic_on_shutdown: bool,
151    /// The maximum number of fragments the connection can handle without reallocating.
152    /// Default: 10
153    pub fragments_capacity: usize,
154    /// Whether to reallocate when `fragments_capacity` is reached. If this is false,
155    /// a Capacity error will be triggered instead.
156    /// Default: true
157    pub fragments_grow: bool,
158    /// The maximum length of outgoing frames. Messages longer than this will be fragmented.
159    /// Default: 65,535
160    pub fragment_size: usize,
161    /// The maximum length of acceptable incoming frames. Messages longer than this will be rejected.
162    /// Default: unlimited
163    pub max_fragment_size: usize,
164    /// The size of the incoming buffer. A larger buffer uses more memory but will allow for fewer
165    /// reallocations.
166    /// Default: 2048
167    pub in_buffer_capacity: usize,
168    /// Whether to reallocate the incoming buffer when `in_buffer_capacity` is reached. If this is
169    /// false, a Capacity error will be triggered instead.
170    /// Default: true
171    pub in_buffer_grow: bool,
172    /// The size of the outgoing buffer. A larger buffer uses more memory but will allow for fewer
173    /// reallocations.
174    /// Default: 2048
175    pub out_buffer_capacity: usize,
176    /// Whether to reallocate the incoming buffer when `out_buffer_capacity` is reached. If this is
177    /// false, a Capacity error will be triggered instead.
178    /// Default: true
179    pub out_buffer_grow: bool,
180    /// Whether to panic when an Internal error is encountered. Internal errors should generally
181    /// not occur, so this setting defaults to true as a debug measure, whereas production
182    /// applications should consider setting it to false.
183    /// Default: true
184    pub panic_on_internal: bool,
185    /// Whether to panic when a Capacity error is encountered.
186    /// Default: false
187    pub panic_on_capacity: bool,
188    /// Whether to panic when a Protocol error is encountered.
189    /// Default: false
190    pub panic_on_protocol: bool,
191    /// Whether to panic when an Encoding error is encountered.
192    /// Default: false
193    pub panic_on_encoding: bool,
194    /// Whether to panic when a Queue error is encountered.
195    /// Default: false
196    pub panic_on_queue: bool,
197    /// Whether to panic when an Io error is encountered.
198    /// Default: false
199    pub panic_on_io: bool,
200    /// Whether to panic when a Timer error is encountered.
201    /// Default: false
202    pub panic_on_timeout: bool,
203    /// Whether to shutdown the eventloop when an interrupt is received.
204    /// Default: true
205    pub shutdown_on_interrupt: bool,
206    /// The WebSocket protocol requires frames sent from client endpoints to be masked as a
207    /// security and sanity precaution. Enforcing this requirement, which may be removed at some
208    /// point may cause incompatibilities. If you need the extra security, set this to true.
209    /// Default: false
210    pub masking_strict: bool,
211    /// The WebSocket protocol requires clients to verify the key returned by a server to ensure
212    /// that the server and all intermediaries can perform the protocol. Verifying the key will
213    /// consume processing time and other resources with the benefit that we can fail the
214    /// connection early. The default in WS-RS is to accept any key from the server and instead
215    /// fail late if a protocol error occurs. Change this setting to enable key verification.
216    /// Default: false
217    pub key_strict: bool,
218    /// The WebSocket protocol requires clients to perform an opening handshake using the HTTP
219    /// GET method for the request. However, since only WebSockets are supported on the connection,
220    /// verifying the method of handshake requests is not always necessary. To enforce the
221    /// requirement that handshakes begin with a GET method, set this to true.
222    /// Default: false
223    pub method_strict: bool,
224    /// Indicate whether server connections should use ssl encryption when accepting connections.
225    /// Setting this to true means that clients should use the `wss` scheme to connect to this
226    /// server. Note that using this flag will in general necessitate overriding the
227    /// `Handler::upgrade_ssl_server` method in order to provide the details of the ssl context. It may be
228    /// simpler for most users to use a reverse proxy such as nginx to provide server side
229    /// encryption.
230    ///
231    /// Default: false
232    pub encrypt_server: bool,
233    /// Disables Nagle's algorithm.
234    /// Usually tcp socket tries to accumulate packets to send them all together (every 200ms).
235    /// When enabled socket will try to send packet as fast as possible.
236    ///
237    /// Default: false
238    pub tcp_nodelay: bool,
239}
240
241impl Default for Settings {
242    fn default() -> Settings {
243        Settings {
244            max_connections: 100,
245            queue_size: 5,
246            panic_on_new_connection: false,
247            panic_on_shutdown: false,
248            fragments_capacity: 10,
249            fragments_grow: true,
250            fragment_size: u16::max_value() as usize,
251            max_fragment_size: usize::max_value(),
252            in_buffer_capacity: 2048,
253            in_buffer_grow: true,
254            out_buffer_capacity: 2048,
255            out_buffer_grow: true,
256            panic_on_internal: true,
257            panic_on_capacity: false,
258            panic_on_protocol: false,
259            panic_on_encoding: false,
260            panic_on_queue: false,
261            panic_on_io: false,
262            panic_on_timeout: false,
263            shutdown_on_interrupt: true,
264            masking_strict: false,
265            key_strict: false,
266            method_strict: false,
267            encrypt_server: false,
268            tcp_nodelay: false,
269        }
270    }
271}
272
273/// The WebSocket struct. A WebSocket can support multiple incoming and outgoing connections.
274pub struct WebSocket<F>
275where
276    F: Factory,
277{
278    poll: Poll,
279    handler: io::Handler<F>,
280}
281
282impl<F> WebSocket<F>
283where
284    F: Factory,
285{
286    /// Create a new WebSocket using the given Factory to create handlers.
287    pub fn new(factory: F) -> Result<WebSocket<F>> {
288        Builder::new().build(factory)
289    }
290
291    /// Consume the WebSocket and bind to the specified address.
292    /// If the `addr_spec` yields multiple addresses this will return after the
293    /// first successful bind. `local_addr` can be called to determine which
294    /// address it ended up binding to.
295    /// After the server is successfully bound you should start it using `run`.
296    pub fn bind<A>(mut self, addr_spec: A) -> Result<WebSocket<F>>
297    where
298        A: ToSocketAddrs,
299    {
300        let mut last_error = Error::new(ErrorKind::Internal, "No address given");
301
302        for addr in addr_spec.to_socket_addrs()? {
303            if let Err(e) = self.handler.listen(&mut self.poll, &addr) {
304                error!("Unable to listen on {}", addr);
305                last_error = e;
306            } else {
307                let actual_addr = self.handler.local_addr().unwrap_or(addr);
308                info!("Listening for new connections on {}.", actual_addr);
309                return Ok(self);
310            }
311        }
312
313        Err(last_error)
314    }
315
316    /// Consume the WebSocket and listen for new connections on the specified address.
317    ///
318    /// # Safety
319    ///
320    /// This method will block until the event loop finishes running.
321    pub fn listen<A>(self, addr_spec: A) -> Result<WebSocket<F>>
322    where
323        A: ToSocketAddrs,
324    {
325        self.bind(addr_spec).and_then(|server| server.run())
326    }
327
328    /// Queue an outgoing connection on this WebSocket. This method may be called multiple times,
329    /// but the actual connections will not be established until `run` is called.
330    pub fn connect(&mut self, url: url::Url) -> Result<&mut WebSocket<F>> {
331        let sender = self.handler.sender();
332        info!("Queuing connection to {}", url);
333        sender.connect(url)?;
334        Ok(self)
335    }
336
337    /// Run the WebSocket. This will run the encapsulated event loop blocking the calling thread until
338    /// the WebSocket is shutdown.
339    pub fn run(mut self) -> Result<WebSocket<F>> {
340        self.handler.run(&mut self.poll)?;
341        Ok(self)
342    }
343
344    /// Get a Sender that can be used to send messages on all connections.
345    /// Calling `send` on this Sender is equivalent to calling `broadcast`.
346    /// Calling `shutdown` on this Sender will shutdown the WebSocket even if no connections have
347    /// been established.
348    #[inline]
349    pub fn broadcaster(&self) -> Sender {
350        self.handler.sender()
351    }
352
353    /// Get the local socket address this socket is bound to. Will return an error
354    /// if the backend returns an error. Will return a `NotFound` error if
355    /// this WebSocket is not a listening socket.
356    pub fn local_addr(&self) -> ::std::io::Result<SocketAddr> {
357        self.handler.local_addr()
358    }
359}
360
361/// Utility for constructing a WebSocket from various settings.
362#[derive(Debug, Default, Clone, Copy)]
363pub struct Builder {
364    settings: Settings,
365}
366
367// TODO: add convenience methods for each setting
368impl Builder {
369    /// Create a new Builder with default settings.
370    pub fn new() -> Builder {
371        Builder::default()
372    }
373
374    /// Build a WebSocket using this builder and a factory.
375    /// It is possible to use the same builder to create multiple WebSockets.
376    pub fn build<F>(&self, factory: F) -> Result<WebSocket<F>>
377    where
378        F: Factory,
379    {
380        Ok(WebSocket {
381            poll: Poll::new()?,
382            handler: io::Handler::new(factory, self.settings),
383        })
384    }
385
386    /// Set the WebSocket settings to use.
387    pub fn with_settings(&mut self, settings: Settings) -> &mut Builder {
388        self.settings = settings;
389        self
390    }
391}