diff --git a/Cargo.toml b/Cargo.toml index 7cc982e..1166ca8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,9 +7,9 @@ authors = ["Alexey Galakhov"] license = "MIT/Apache-2.0" readme = "README.md" homepage = "https://github.com/snapview/tungstenite-rs" -documentation = "https://docs.rs/tungstenite/0.2.3" +documentation = "https://docs.rs/tungstenite/0.2.4" repository = "https://github.com/snapview/tungstenite-rs" -version = "0.2.3" +version = "0.2.4" [features] default = ["tls"] diff --git a/src/client.rs b/src/client.rs index 83e0062..3274ad0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -13,6 +13,7 @@ mod encryption { pub use native_tls::TlsStream; pub use stream::Stream as StreamSwitcher; + /// TCP stream switcher (plain/TLS). pub type AutoStream = StreamSwitcher>; use stream::Mode; @@ -41,6 +42,7 @@ mod encryption { use stream::Mode; use error::{Error, Result}; + /// TLS support is nod compiled in, this is just standard `TcpStream`. pub type AutoStream = TcpStream; pub fn wrap_stream(stream: TcpStream, _domain: &str, mode: Mode) -> Result { @@ -57,7 +59,7 @@ use self::encryption::wrap_stream; use protocol::WebSocket; use handshake::HandshakeError; use handshake::client::{ClientHandshake, Request}; -use stream::Mode; +use stream::{NoDelay, Mode}; use error::{Error, Result}; @@ -73,11 +75,13 @@ use error::{Error, Result}; /// This function uses `native_tls` to do TLS. If you want to use other TLS libraries, /// use `client` instead. There is no need to enable the "tls" feature if you don't call /// `connect` since it's the only function that uses native_tls. -pub fn connect(url: Url) -> Result> { - let mode = url_mode(&url)?; - let addrs = url.to_socket_addrs()?; - let stream = connect_to_some(addrs, &url, mode)?; - client(url.clone(), stream) +pub fn connect<'t, Req: Into>>(request: Req) -> Result> { + let request: Request = request.into(); + let mode = url_mode(&request.url)?; + let addrs = request.url.to_socket_addrs()?; + let mut stream = connect_to_some(addrs, &request.url, mode)?; + NoDelay::set_nodelay(&mut stream, true)?; + client(request, stream) .map_err(|e| match e { HandshakeError::Failure(f) => f, HandshakeError::Interrupted(_) => panic!("Bug: blocking handshake not blocked"), @@ -116,9 +120,10 @@ pub fn url_mode(url: &Url) -> Result { /// Use this function if you need a nonblocking handshake support or if you /// want to use a custom stream like `mio::tcp::TcpStream` or `openssl::ssl::SslStream`. /// Any stream supporting `Read + Write` will do. -pub fn client(url: Url, stream: Stream) +pub fn client<'t, Stream, Req>(request: Req, stream: Stream) -> StdResult, HandshakeError> +where Stream: Read + Write, + Req: Into>, { - let request = Request { url: url, extra_headers: None }; - ClientHandshake::start(stream, request).handshake() + ClientHandshake::start(stream, request.into()).handshake() } diff --git a/src/error.rs b/src/error.rs index 3942d6f..4b027fd 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,9 +15,11 @@ use protocol::frame::CloseFrame; #[cfg(feature="tls")] pub mod tls { + //! TLS error wrapper module, feature-gated. pub use native_tls::Error; } +/// Result type of all Tungstenite library calls. pub type Result = result::Result; /// Possible WebSocket errors diff --git a/src/handshake/client.rs b/src/handshake/client.rs index 157f309..ff07d37 100644 --- a/src/handshake/client.rs +++ b/src/handshake/client.rs @@ -1,3 +1,5 @@ +//! Client handshake machine. + use base64; use rand; use httparse; @@ -14,7 +16,9 @@ use super::machine::{HandshakeMachine, StageResult, TryParse}; /// Client request. pub struct Request<'t> { + /// `ws://` or `wss://` URL to connect to. pub url: Url, + /// Extra HTTP headers to append to the request. pub extra_headers: Option<&'t [(&'t str, &'t str)]>, } @@ -38,6 +42,15 @@ impl<'t> Request<'t> { } } +impl From for Request<'static> { + fn from(value: Url) -> Self { + Request { + url: value, + extra_headers: None, + } + } +} + /// Client handshake role. pub struct ClientHandshake { verify_data: VerifyData, diff --git a/src/handshake/headers.rs b/src/handshake/headers.rs index 260b578..c9e6bee 100644 --- a/src/handshake/headers.rs +++ b/src/handshake/headers.rs @@ -1,3 +1,5 @@ +//! HTTP Request and response header handling. + use std::ascii::AsciiExt; use std::str::from_utf8; use std::slice; @@ -8,7 +10,7 @@ use httparse::Status; use error::Result; use super::machine::TryParse; -// Limit the number of header lines. +/// Limit for the number of header lines. pub const MAX_HEADERS: usize = 124; /// HTTP request or response headers. @@ -70,6 +72,7 @@ impl<'name, 'headers> Iterator for HeadersIter<'name, 'headers> { /// Trait to convert raw objects into HTTP parseables. pub trait FromHttparse: Sized { + /// Convert raw object into parsed HTTP headers. fn from_httparse(raw: T) -> Result; } diff --git a/src/handshake/server.rs b/src/handshake/server.rs index fbd08b6..a3a5fab 100644 --- a/src/handshake/server.rs +++ b/src/handshake/server.rs @@ -1,7 +1,8 @@ +//! Server handshake machine. + use httparse; use httparse::Status; -//use input_buffer::{InputBuffer, MIN_READ}; use error::{Error, Result}; use protocol::{WebSocket, Role}; use super::headers::{Headers, FromHttparse, MAX_HEADERS}; @@ -10,7 +11,9 @@ use super::{MidHandshake, HandshakeRole, ProcessingResult, convert_key}; /// Request from the client. pub struct Request { + /// Path part of the URL. pub path: String, + /// HTTP headers. pub headers: Headers, } diff --git a/src/lib.rs b/src/lib.rs index 60584af..824934c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ //! Lightweight, flexible WebSockets for Rust. #![deny( + missing_docs, missing_copy_implementations, trivial_casts, trivial_numeric_casts, unstable_features, diff --git a/src/protocol/frame/coding.rs b/src/protocol/frame/coding.rs index 97f9fd0..5fde5fb 100644 --- a/src/protocol/frame/coding.rs +++ b/src/protocol/frame/coding.rs @@ -6,7 +6,9 @@ use std::convert::{Into, From}; /// WebSocket message opcode as in RFC 6455. #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum OpCode { + /// Data (text or binary). Data(Data), + /// Control message (close, ping, pong). Control(Control), } diff --git a/src/stream.rs b/src/stream.rs index 2ef7466..ab2c8e2 100644 --- a/src/stream.rs +++ b/src/stream.rs @@ -6,16 +6,44 @@ use std::io::{Read, Write, Result as IoResult}; +use std::net::TcpStream; + +#[cfg(feature="tls")] +use native_tls::TlsStream; + /// Stream mode, either plain TCP or TLS. #[derive(Clone, Copy)] pub enum Mode { + /// Plain mode (`ws://` URL). Plain, + /// TLS mode (`wss://` URL). Tls, } +/// Trait to switch TCP_NODELAY. +pub trait NoDelay { + /// Set the TCP_NODELAY option to the given value. + fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()>; +} + +impl NoDelay for TcpStream { + fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { + TcpStream::set_nodelay(self, nodelay) + } +} + +#[cfg(feature="tls")] +impl NoDelay for TlsStream { + fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { + self.get_mut().set_nodelay(nodelay) + } +} + /// Stream, either plain TCP or TLS. pub enum Stream { + /// Unencrypted socket stream. Plain(S), + /// Encrypted socket stream. Tls(T), } @@ -42,3 +70,12 @@ impl Write for Stream { } } } + +impl NoDelay for Stream { + fn set_nodelay(&mut self, nodelay: bool) -> IoResult<()> { + match *self { + Stream::Plain(ref mut s) => s.set_nodelay(nodelay), + Stream::Tls(ref mut s) => s.set_nodelay(nodelay), + } + } +} diff --git a/src/util.rs b/src/util.rs index 696c0a1..a784f9c 100644 --- a/src/util.rs +++ b/src/util.rs @@ -7,6 +7,7 @@ use error::Error; /// Non-blocking IO handling. pub trait NonBlockingError: Sized { + /// Convert WouldBlock to None and don't touch other errors. fn into_non_blocking(self) -> Option; } @@ -29,8 +30,12 @@ impl NonBlockingError for Error { } /// Non-blocking IO wrapper. +/// +/// This trait is implemented for `Result`. pub trait NonBlockingResult { + /// Type of the converted result: `Result, E>` type Result; + /// Perform the non-block conversion. fn no_block(self) -> Self::Result; }