Skip to main content

awc/client/
mod.rs

1//! HTTP client.
2
3use std::{rc::Rc, time::Duration};
4
5use actix_http::{error::HttpError, header::HeaderMap, Method, RequestHead, Uri};
6use actix_rt::net::TcpStream;
7use actix_service::Service;
8pub use actix_tls::connect::{
9    ConnectError as TcpConnectError, ConnectInfo, Connection as TcpConnection,
10};
11
12use crate::{ws, BoxConnectorService, ClientBuilder, ClientRequest};
13
14mod config;
15mod connection;
16mod connector;
17mod error;
18mod h1proto;
19mod h2proto;
20mod pool;
21
22pub use self::{
23    connection::{Connection, ConnectionIo},
24    connector::{Connector, ConnectorService},
25    error::{ConnectError, FreezeRequestError, InvalidUrl, SendRequestError},
26};
27
28#[derive(Clone)]
29pub struct Connect {
30    pub uri: Uri,
31    pub addr: Option<std::net::SocketAddr>,
32}
33
34/// An asynchronous HTTP and WebSocket client.
35///
36/// You should take care to create, at most, one `Client` per thread. Otherwise, expect higher CPU
37/// and memory usage.
38///
39/// # Examples
40/// ```
41/// use awc::Client;
42///
43/// #[actix_rt::main]
44/// async fn main() {
45///     let mut client = Client::default();
46///
47///     let res = client.get("http://www.rust-lang.org")
48///         .insert_header(("User-Agent", "my-app/1.2"))
49///         .send()
50///         .await;
51///
52///      println!("Response: {:?}", res);
53/// }
54/// ```
55#[derive(Clone)]
56pub struct Client(pub(crate) ClientConfig);
57
58#[derive(Clone)]
59pub(crate) struct ClientConfig {
60    pub(crate) connector: BoxConnectorService,
61    pub(crate) default_headers: Rc<HeaderMap>,
62    pub(crate) timeout: Option<Duration>,
63}
64
65impl Default for Client {
66    fn default() -> Self {
67        ClientBuilder::new().finish()
68    }
69}
70
71impl Client {
72    /// Constructs new client instance with default settings.
73    pub fn new() -> Client {
74        Client::default()
75    }
76
77    /// Constructs new `Client` builder.
78    ///
79    /// This function is equivalent of `ClientBuilder::new()`.
80    pub fn builder() -> ClientBuilder<
81        impl Service<
82                ConnectInfo<Uri>,
83                Response = TcpConnection<Uri, TcpStream>,
84                Error = TcpConnectError,
85            > + Clone,
86    > {
87        ClientBuilder::new()
88    }
89
90    /// Construct HTTP request.
91    pub fn request<U>(&self, method: Method, url: U) -> ClientRequest
92    where
93        Uri: TryFrom<U>,
94        <Uri as TryFrom<U>>::Error: Into<HttpError>,
95    {
96        let mut req = ClientRequest::new(method, url, self.0.clone());
97
98        for header in self.0.default_headers.iter() {
99            req = req.append_header(header);
100        }
101
102        req
103    }
104
105    /// Create `ClientRequest` from `RequestHead`
106    ///
107    /// It is useful for proxy requests. This implementation
108    /// copies all headers and the method.
109    pub fn request_from<U>(&self, url: U, head: &RequestHead) -> ClientRequest
110    where
111        Uri: TryFrom<U>,
112        <Uri as TryFrom<U>>::Error: Into<HttpError>,
113    {
114        let mut req = self.request(head.method.clone(), url);
115        for header in head.headers.iter() {
116            req = req.insert_header_if_none(header);
117        }
118        req
119    }
120
121    /// Construct HTTP *GET* request.
122    pub fn get<U>(&self, url: U) -> ClientRequest
123    where
124        Uri: TryFrom<U>,
125        <Uri as TryFrom<U>>::Error: Into<HttpError>,
126    {
127        self.request(Method::GET, url)
128    }
129
130    /// Construct HTTP *HEAD* request.
131    pub fn head<U>(&self, url: U) -> ClientRequest
132    where
133        Uri: TryFrom<U>,
134        <Uri as TryFrom<U>>::Error: Into<HttpError>,
135    {
136        self.request(Method::HEAD, url)
137    }
138
139    /// Construct HTTP *PUT* request.
140    pub fn put<U>(&self, url: U) -> ClientRequest
141    where
142        Uri: TryFrom<U>,
143        <Uri as TryFrom<U>>::Error: Into<HttpError>,
144    {
145        self.request(Method::PUT, url)
146    }
147
148    /// Construct HTTP *POST* request.
149    pub fn post<U>(&self, url: U) -> ClientRequest
150    where
151        Uri: TryFrom<U>,
152        <Uri as TryFrom<U>>::Error: Into<HttpError>,
153    {
154        self.request(Method::POST, url)
155    }
156
157    /// Construct HTTP *PATCH* request.
158    pub fn patch<U>(&self, url: U) -> ClientRequest
159    where
160        Uri: TryFrom<U>,
161        <Uri as TryFrom<U>>::Error: Into<HttpError>,
162    {
163        self.request(Method::PATCH, url)
164    }
165
166    /// Construct HTTP *DELETE* request.
167    pub fn delete<U>(&self, url: U) -> ClientRequest
168    where
169        Uri: TryFrom<U>,
170        <Uri as TryFrom<U>>::Error: Into<HttpError>,
171    {
172        self.request(Method::DELETE, url)
173    }
174
175    /// Construct HTTP *OPTIONS* request.
176    pub fn options<U>(&self, url: U) -> ClientRequest
177    where
178        Uri: TryFrom<U>,
179        <Uri as TryFrom<U>>::Error: Into<HttpError>,
180    {
181        self.request(Method::OPTIONS, url)
182    }
183
184    /// Initialize a WebSocket connection.
185    /// Returns a WebSocket connection builder.
186    pub fn ws<U>(&self, url: U) -> ws::WebsocketsRequest
187    where
188        Uri: TryFrom<U>,
189        <Uri as TryFrom<U>>::Error: Into<HttpError>,
190    {
191        let mut req = ws::WebsocketsRequest::new(url, self.0.clone());
192        for (key, value) in self.0.default_headers.iter() {
193            req.head.headers.insert(key.clone(), value.clone());
194        }
195        req
196    }
197
198    /// Get default HeaderMap of Client.
199    ///
200    /// Returns Some(&mut HeaderMap) when Client object is unique
201    /// (No other clone of client exists at the same time).
202    pub fn headers(&mut self) -> Option<&mut HeaderMap> {
203        Rc::get_mut(&mut self.0.default_headers)
204    }
205}