awc/client/
mod.rs

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