• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 use crate::{Certificate, HttpClientError, Proxy, Redirect, Request, Timeout, TlsVersion};
17 use reqwest::Response;
18 
19 mod downloader;
20 mod uploader;
21 
22 pub use downloader::{DownloadOperator, Downloader, DownloaderBuilder};
23 pub use uploader::{MultiPart, Part, UploadOperator, Uploader, UploaderBuilder};
24 
25 /// An asynchronous `Client` to make requests with.
26 ///
27 /// The Client has various configuration values to tweak, but the defaults
28 /// are set to what is usually the most commonly desired value. To configure a
29 /// `Client`, use `Client::builder()`.
30 ///
31 /// The `Client` holds a connection pool internally, so it is advised that
32 /// you create one and **reuse** it.
33 ///
34 /// You do **not** have to wrap the `Client` in an [`Rc`] or [`Arc`] to **reuse** it,
35 /// because it already uses an [`Arc`] internally.
36 ///
37 /// [`Rc`]: std::rc::Rc
38 ///
39 /// # Examples
40 ///
41 /// ```no_run
42 /// # use ylong_http_client::async_impl::Client;
43 /// # use ylong_http_client::Request;
44 ///
45 /// # async fn send_request() {
46 /// // Creates a `Client`.
47 /// let client = Client::builder().build().unwrap();
48 ///
49 /// // Constructs your `Request`.
50 /// let request = Request::builder().body("".as_bytes()).unwrap();
51 ///
52 /// // Sends your request through `Client` and gets the response.
53 /// let _response = client.request(request).await;
54 /// # }
55 /// ```
56 #[derive(Clone)]
57 pub struct Client(reqwest::Client);
58 
59 impl Client {
60     /// Creates a `ClientBuilder` to configure a `Client`.
61     ///
62     /// This is the same as `ClientBuilder::new()`.
63     ///
64     /// # Examples
65     ///
66     /// ```
67     /// # use reqwest::Client;
68     ///
69     /// let builder = Client::builder();
70     /// ```
builder() -> ClientBuilder71     pub fn builder() -> ClientBuilder {
72         ClientBuilder::new()
73     }
74 
75     /// Sends a `Request` and gets the `Response`.
76     ///
77     /// A `Request` can be built manually with `Request::new()` or obtained
78     /// from a RequestBuilder with `RequestBuilder::build()`.
79     ///
80     /// # Errors
81     ///
82     /// This method fails if there was an error while sending request,
83     /// redirect loop was detected or redirect limit was exhausted.
84     ///
85     /// # Examples
86     ///
87     /// ```no_run
88     /// # use ylong_http_client::async_impl::Client;
89     /// # use ylong_http_client::Request;
90     ///
91     /// # async fn send_request() {
92     /// // Creates a `Client`.
93     /// let client = Client::builder().build().unwrap();
94     ///
95     /// // Constructs your `Request`.
96     /// let request = Request::builder().body("".as_bytes()).unwrap();
97     ///
98     /// // Sends your request through `Client` and gets the response.
99     /// let _response = client.request(request).await;
100     /// # }
101     /// ```
request<T: Into<reqwest::Body>>( &self, request: Request<T>, ) -> Result<Response, HttpClientError>102     pub async fn request<T: Into<reqwest::Body>>(
103         &self,
104         request: Request<T>,
105     ) -> Result<Response, HttpClientError> {
106         self.0
107             .request(request.inner.method, request.inner.url)
108             .headers(request.inner.headers)
109             .version(request.inner.version)
110             .body(request.body.into())
111             .send()
112             .await
113             .map_err(HttpClientError::from)
114     }
115 }
116 
117 /// A `ClientBuilder` can be used to create a `Client` with custom configuration.
118 ///
119 /// # Examples
120 ///
121 /// ```
122 /// # use ylong_http_client::async_impl::ClientBuilder;
123 ///
124 /// let builder = ClientBuilder::new();
125 /// ```
126 pub struct ClientBuilder(reqwest::ClientBuilder);
127 
128 impl ClientBuilder {
129     /// Creates a `ClientBuilder` to configure a `Client`.
130     ///
131     /// This is the same as `Client::builder()`.
132     ///
133     /// # Examples
134     ///
135     /// ```
136     /// # use ylong_http_client::async_impl::ClientBuilder;
137     ///
138     /// let builder = ClientBuilder::new();
139     /// ```
new() -> Self140     pub fn new() -> Self {
141         Self(reqwest::ClientBuilder::new())
142     }
143 
144     /// Only uses HTTP/1.
145     ///
146     /// # Examples
147     ///
148     /// ```
149     /// # use ylong_http_client::async_impl::ClientBuilder;
150     ///
151     /// let builder = ClientBuilder::new().http1_only();
152     /// ```
http1_only(self) -> Self153     pub fn http1_only(self) -> Self {
154         Self(self.0.http1_only())
155     }
156 
157     /// Only use HTTP/2.
158     ///
159     /// # Examples
160     ///
161     /// ```
162     /// # use ylong_http_client::async_impl::ClientBuilder;
163     ///
164     /// let builder = ClientBuilder::new().http2_prior_knowledge();
165     /// ```
http2_prior_knowledge(self) -> Self166     pub fn http2_prior_knowledge(self) -> Self {
167         Self(self.0.http2_prior_knowledge())
168     }
169 
170     /// Enables a request timeout.
171     ///
172     /// The timeout is applied from when the request starts connecting until the
173     /// response body has finished.
174     ///
175     /// Default is `Timeout::none()`.
176     ///
177     /// # Examples
178     ///
179     /// ```
180     /// # use ylong_http_client::async_impl::ClientBuilder;
181     /// # use ylong_http_client::Timeout;
182     ///
183     /// let builder = ClientBuilder::new()
184     ///     .request_timeout(Timeout::none());
185     /// ```
request_timeout(self, timeout: Timeout) -> Self186     pub fn request_timeout(self, timeout: Timeout) -> Self {
187         match timeout.inner() {
188             Some(duration) => Self(self.0.timeout(duration)),
189             None => self,
190         }
191     }
192 
193     /// Sets a timeout for only the connect phase of a `Client`.
194     ///
195     /// Default is `Timeout::none()`.
196     ///
197     /// # Examples
198     ///
199     /// ```
200     /// # use ylong_http_client::async_impl::ClientBuilder;
201     /// # use ylong_http_client::Timeout;
202     ///
203     /// let builder = ClientBuilder::new()
204     ///     .connect_timeout(Timeout::none());
205     /// ```
connect_timeout(self, timeout: Timeout) -> Self206     pub fn connect_timeout(self, timeout: Timeout) -> Self {
207         match timeout.inner() {
208             Some(duration) => Self(self.0.connect_timeout(duration)),
209             None => self,
210         }
211     }
212 
213     /// Sets a `RedirectPolicy` for this client.
214     ///
215     /// Default will follow redirects up to a maximum of 10.
216     ///
217     /// # Examples
218     ///
219     /// ```
220     /// # use ylong_http_client::async_impl::ClientBuilder;
221     /// # use ylong_http_client::Redirect;
222     ///
223     /// let builder = ClientBuilder::new().redirect(Redirect::none());
224     /// ```
redirect(self, redirect: Redirect) -> Self225     pub fn redirect(self, redirect: Redirect) -> Self {
226         Self(self.0.redirect(redirect.inner()))
227     }
228 
229     /// Adds a `Proxy` to the list of proxies the `Client` will use.
230     ///
231     /// # Note
232     ///
233     /// Adding a proxy will disable the automatic usage of the "system" proxy.
234     ///
235     /// # Examples
236     ///
237     /// ```
238     /// # use ylong_http_client::async_impl::ClientBuilder;
239     /// # use ylong_http_client::Proxy;
240     ///
241     /// let builder = ClientBuilder::new().proxy(Proxy::none());
242     /// ```
proxy(self, proxy: Proxy) -> Self243     pub fn proxy(self, proxy: Proxy) -> Self {
244         match proxy.inner() {
245             Some(proxy) => Self(self.0.proxy(proxy)),
246             None => Self(self.0.no_proxy()),
247         }
248     }
249 
250     /// Sets the maximum allowed TLS version for connections.
251     ///
252     /// By default there's no maximum.
253     ///
254     /// # Note
255     ///
256     /// `tls::Version::TLS_1_3` cannot be set as a maximum.
257     ///
258     /// # Examples
259     ///
260     /// ```
261     /// # use ylong_http_client::async_impl::ClientBuilder;
262     /// # use ylong_http_client::TlsVersion;
263     ///
264     /// let builder = ClientBuilder::new().max_tls_version(TlsVersion::TLS_1_2);
265     /// ```
max_tls_version(self, version: TlsVersion) -> Self266     pub fn max_tls_version(self, version: TlsVersion) -> Self {
267         Self(self.0.max_tls_version(version))
268     }
269 
270     /// Sets the minimum required TLS version for connections.
271     ///
272     /// By default the TLS backend's own default is used.
273     ///
274     /// # Note
275     ///
276     /// `tls::Version::TLS_1_3` cannot be set as a minimum.
277     ///
278     /// # Examples
279     ///
280     /// ```
281     /// # use ylong_http_client::async_impl::ClientBuilder;
282     /// # use ylong_http_client::TlsVersion;
283     ///
284     /// let builder = ClientBuilder::new().min_tls_version(TlsVersion::TLS_1_2);
285     /// ```
min_tls_version(self, version: TlsVersion) -> Self286     pub fn min_tls_version(self, version: TlsVersion) -> Self {
287         Self(self.0.min_tls_version(version))
288     }
289 
290     /// Adds a custom root certificate.
291     ///
292     /// This can be used to connect to a server that has a self-signed
293     /// certificate for example.
294     ///
295     /// # Examples
296     ///
297     /// ```
298     /// # use ylong_http_client::async_impl::ClientBuilder;
299     /// # use ylong_http_client::Certificate;
300     ///
301     /// # fn set_cert(cert: Certificate) {
302     /// let builder = ClientBuilder::new().add_root_certificate(cert);
303     /// # }
304     /// ```
add_root_certificate(mut self, cert: Certificate) -> Self305     pub fn add_root_certificate(mut self, cert: Certificate) -> Self {
306         for cert in cert.into_inner() {
307             self = Self(self.0.add_root_certificate(cert));
308         }
309         self
310     }
311 
312     /// Controls the use of built-in/preloaded certificates during certificate validation.
313     ///
314     /// Defaults to `true` -- built-in system certs will be used.
315     ///
316     /// # Examples
317     ///
318     /// ```
319     /// # use ylong_http_client::async_impl::ClientBuilder;
320     ///
321     /// let builder = ClientBuilder::new().tls_built_in_root_certs(true);
322     /// ```
tls_built_in_root_certs(self, tls_built_in_root_certs: bool) -> ClientBuilder323     pub fn tls_built_in_root_certs(self, tls_built_in_root_certs: bool) -> ClientBuilder {
324         Self(self.0.tls_built_in_root_certs(tls_built_in_root_certs))
325     }
326 
327     /// Controls the use of certificate validation.
328     ///
329     /// Defaults to `false`.
330     ///
331     /// # Warning
332     ///
333     /// You should think very carefully before using this method. If
334     /// invalid certificates are trusted, *any* certificate for *any* site
335     /// will be trusted for use. This includes expired certificates. This
336     /// introduces significant vulnerabilities, and should only be used
337     /// as a last resort.
338     ///
339     /// # Examples
340     ///
341     /// ```
342     /// # use ylong_http_client::async_impl::ClientBuilder;
343     ///
344     /// let builder = ClientBuilder::new().danger_accept_invalid_certs(true);
345     /// ```
danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder346     pub fn danger_accept_invalid_certs(self, accept_invalid_certs: bool) -> ClientBuilder {
347         Self(self.0.danger_accept_invalid_certs(accept_invalid_certs))
348     }
349 
350     /// Returns a `Client` that uses this `ClientBuilder` configuration.
351     ///
352     /// # Errors
353     ///
354     /// This method fails if a TLS backend cannot be initialized, or the resolver
355     /// cannot load the system configuration.
356     ///
357     /// # Examples
358     ///
359     /// ```
360     /// # use ylong_http_client::async_impl::ClientBuilder;
361     /// # use ylong_http_client::{Redirect, TlsVersion};
362     ///
363     /// let client = ClientBuilder::new().build().unwrap();
364     /// ```
build(self) -> Result<Client, HttpClientError>365     pub fn build(self) -> Result<Client, HttpClientError> {
366         self.0.build().map(Client).map_err(HttpClientError::from)
367     }
368 }
369 
370 impl Default for ClientBuilder {
default() -> Self371     fn default() -> Self {
372         Self::new()
373     }
374 }
375