1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
//! Connection helper.
use tokio::net::TcpStream;
use tungstenite::{
error::{Error, UrlError},
handshake::client::{Request, Response},
protocol::WebSocketConfig,
};
use crate::{domain, stream::MaybeTlsStream, Connector, IntoClientRequest, WebSocketStream};
/// Connect to a given URL.
///
/// Accepts any request that implements [`IntoClientRequest`], which is often just `&str`, but can
/// be a variety of types such as `httparse::Request` or [`tungstenite::http::Request`] for more
/// complex uses.
///
/// ```no_run
/// # use tungstenite::client::IntoClientRequest;
///
/// # async fn test() {
/// use tungstenite::http::{Method, Request};
/// use tokio_tungstenite::connect_async;
///
/// let mut request = "wss://api.example.com".into_client_request().unwrap();
/// request.headers_mut().insert("api-key", "42".parse().unwrap());
///
/// let (stream, response) = connect_async(request).await.unwrap();
/// # }
/// ```
pub async fn connect_async<R>(
request: R,
) -> Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response), Error>
where
R: IntoClientRequest + Unpin,
{
connect_async_with_config(request, None, false).await
}
/// The same as `connect_async()` but the one can specify a websocket configuration.
/// Please refer to `connect_async()` for more details. `disable_nagle` specifies if
/// the Nagle's algorithm must be disabled, i.e. `set_nodelay(true)`. If you don't know
/// what the Nagle's algorithm is, better leave it set to `false`.
pub async fn connect_async_with_config<R>(
request: R,
config: Option<WebSocketConfig>,
disable_nagle: bool,
) -> Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response), Error>
where
R: IntoClientRequest + Unpin,
{
connect(request.into_client_request()?, config, disable_nagle, None).await
}
/// The same as `connect_async()` but the one can specify a websocket configuration,
/// and a TLS connector to use. Please refer to `connect_async()` for more details.
/// `disable_nagle` specifies if the Nagle's algorithm must be disabled, i.e.
/// `set_nodelay(true)`. If you don't know what the Nagle's algorithm is, better
/// leave it to `false`.
#[cfg(any(feature = "native-tls", feature = "__rustls-tls"))]
pub async fn connect_async_tls_with_config<R>(
request: R,
config: Option<WebSocketConfig>,
disable_nagle: bool,
connector: Option<Connector>,
) -> Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response), Error>
where
R: IntoClientRequest + Unpin,
{
connect(request.into_client_request()?, config, disable_nagle, connector).await
}
async fn connect(
request: Request,
config: Option<WebSocketConfig>,
disable_nagle: bool,
connector: Option<Connector>,
) -> Result<(WebSocketStream<MaybeTlsStream<TcpStream>>, Response), Error> {
let domain = domain(&request)?;
let port = request
.uri()
.port_u16()
.or_else(|| match request.uri().scheme_str() {
Some("wss") => Some(443),
Some("ws") => Some(80),
_ => None,
})
.ok_or(Error::Url(UrlError::UnsupportedUrlScheme))?;
let addr = format!("{domain}:{port}");
let socket = TcpStream::connect(addr).await.map_err(Error::Io)?;
if disable_nagle {
socket.set_nodelay(true)?;
}
crate::tls::client_async_tls_with_config(request, socket, config, connector).await
}