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