tokio_tungstenite/
connect.rs

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