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::{ErrorKind, HttpClientError};
17 use std::cmp;
18 use std::error::Error;
19 use std::fmt::{Debug, Display, Formatter};
20 use std::time::Duration;
21 
22 /// Timeout settings.
23 ///
24 /// # Examples
25 ///
26 /// ```
27 /// # use ylong_http_client::Timeout;
28 ///
29 /// let timeout = Timeout::none();
30 /// ```
31 pub struct Timeout(Option<Duration>);
32 
33 impl Timeout {
34     /// Creates a `Timeout` without limiting the timeout.
35     ///
36     /// # Examples
37     ///
38     /// ```
39     /// # use ylong_http_client::Timeout;
40     ///
41     /// let timeout = Timeout::none();
42     /// ```
none() -> Self43     pub fn none() -> Self {
44         Self(None)
45     }
46 
47     /// Creates a `Timeout` from the specified number of seconds.
48     ///
49     /// # Examples
50     ///
51     /// ```
52     /// # use ylong_http_client::Timeout;
53     ///
54     /// let timeout = Timeout::from_secs(9);
55     /// ```
from_secs(secs: u64) -> Self56     pub fn from_secs(secs: u64) -> Self {
57         Self(Some(Duration::from_secs(secs)))
58     }
59 
inner(&self) -> Option<Duration>60     pub(crate) fn inner(&self) -> Option<Duration> {
61         self.0
62     }
63 }
64 
65 /// Speed limit settings.
66 ///
67 /// # Examples
68 ///
69 /// ```
70 /// # use ylong_http_client::SpeedLimit;
71 ///
72 /// let limit = SpeedLimit::none();
73 /// ```
74 pub struct SpeedLimit {
75     min: (u64, Duration),
76     max: u64,
77 }
78 
79 impl SpeedLimit {
80     /// Creates a `SpeedLimit` without limiting the speed.
81     ///
82     /// # Examples
83     ///
84     /// ```
85     /// # use ylong_http_client::SpeedLimit;
86     ///
87     /// let limit = SpeedLimit::none();
88     /// ```
new() -> Self89     pub fn new() -> Self {
90         Self::none()
91     }
92 
93     /// Sets the minimum speed and the seconds for which the current speed is
94     /// allowed to be less than this minimum speed.
95     ///
96     /// The unit of speed is bytes per second, and the unit of duration is seconds.
97     ///
98     /// The minimum speed cannot exceed the maximum speed that has been set. If
99     /// the set value exceeds the currently set maximum speed, the minimum speed
100     /// will be set to the current maximum speed.
101     ///
102     /// # Examples
103     ///
104     /// ```
105     /// # use ylong_http_client::SpeedLimit;
106     ///
107     /// // Sets minimum speed is 1024B/s, the duration is 10s.
108     /// let limit = SpeedLimit::new().min_speed(1024, 10);
109     /// ```
min_speed(mut self, min: u64, duration: u64) -> Self110     pub fn min_speed(mut self, min: u64, duration: u64) -> Self {
111         self.min = (cmp::min(self.max, min), Duration::from_secs(duration));
112         self
113     }
114 
115     /// Sets the maximum speed.
116     ///
117     /// The unit of speed is bytes per second.
118     ///
119     /// The maximum speed cannot be lower than the minimum speed that has been
120     /// set. If the set value is lower than the currently set minimum speed, the
121     /// maximum speed will be set to the current minimum speed.
122     ///
123     /// # Examples
124     ///
125     /// ```
126     /// # use ylong_http_client::SpeedLimit;
127     ///
128     /// let limit = SpeedLimit::new().max_speed(1024);
129     /// ```
max_speed(mut self, max: u64) -> Self130     pub fn max_speed(mut self, max: u64) -> Self {
131         self.max = cmp::max(self.min.0, max);
132         self
133     }
134 
135     /// Creates a `SpeedLimit` without limiting the speed.
136     ///
137     /// # Examples
138     ///
139     /// ```
140     /// # use ylong_http_client::SpeedLimit;
141     ///
142     /// let limit = SpeedLimit::none();
143     /// ```
none() -> Self144     pub fn none() -> Self {
145         Self {
146             min: (0, Duration::MAX),
147             max: u64::MAX,
148         }
149     }
150 }
151 
152 impl Default for SpeedLimit {
default() -> Self153     fn default() -> Self {
154         Self::new()
155     }
156 }
157 
158 /// Redirect settings.
159 ///
160 /// # Examples
161 ///
162 /// ```
163 /// # use ylong_http_client::Redirect;
164 ///
165 /// let redirect = Redirect::none();
166 /// ```
167 #[derive(Default)]
168 pub struct Redirect(reqwest::redirect::Policy);
169 
170 impl Redirect {
171     /// Creates a `Redirect` without redirection.
172     ///
173     /// # Examples
174     ///
175     /// ```
176     /// # use ylong_http_client::Redirect;
177     ///
178     /// let redirect = Redirect::none();
179     /// ```
none() -> Self180     pub fn none() -> Self {
181         Self(reqwest::redirect::Policy::none())
182     }
183 
184     /// Creates a `Redirect` from the specified times.
185     ///
186     /// # Examples
187     ///
188     /// ```
189     /// # use ylong_http_client::Redirect;
190     ///
191     /// let redirect = Redirect::limited(10);
192     /// ```
limited(max: usize) -> Self193     pub fn limited(max: usize) -> Self {
194         Self(reqwest::redirect::Policy::limited(max))
195     }
196 
inner(self) -> reqwest::redirect::Policy197     pub(crate) fn inner(self) -> reqwest::redirect::Policy {
198         self.0
199     }
200 }
201 
202 /// Proxy settings.
203 ///
204 /// # Examples
205 ///
206 /// ```
207 /// # use ylong_http_client::Proxy;
208 ///
209 /// let proxy = Proxy::none();
210 /// ```
211 pub struct Proxy(Option<reqwest::Proxy>);
212 
213 impl Proxy {
214     /// Creates a `Proxy` without any proxies.
215     ///
216     /// # Examples
217     ///
218     /// ```
219     /// # use ylong_http_client::Proxy;
220     ///
221     /// let proxy = Proxy::none();
222     /// ```
none() -> Self223     pub fn none() -> Self {
224         Self(None)
225     }
226 
227     /// Creates a `ProxyBuilder`. This builder can help you construct a proxy
228     /// that proxy all HTTP traffic to the passed URL.
229     ///
230     /// # Examples
231     ///
232     /// ```
233     /// # use ylong_http_client::Proxy;
234     ///
235     /// let proxy = Proxy::http("http://proxy.example.com");
236     /// ```
http(url: &str) -> ProxyBuilder237     pub fn http(url: &str) -> ProxyBuilder {
238         ProxyBuilder(
239             reqwest::Proxy::http(url)
240                 .map_err(|e| HttpClientError::new_with_cause(ErrorKind::Build, Some(e))),
241         )
242     }
243 
244     /// Creates a `ProxyBuilder`. This builder can help you construct a proxy
245     /// that proxy all HTTPS traffic to the passed URL.
246     ///
247     /// # Examples
248     ///
249     /// ```
250     /// # use ylong_http_client::Proxy;
251     ///
252     /// let proxy = Proxy::https("https://proxy.example.com");
253     /// ```
https(url: &str) -> ProxyBuilder254     pub fn https(url: &str) -> ProxyBuilder {
255         ProxyBuilder(
256             reqwest::Proxy::https(url)
257                 .map_err(|e| HttpClientError::new_with_cause(ErrorKind::Build, Some(e))),
258         )
259     }
260 
261     /// Creates a `ProxyBuilder`. This builder can help you construct a proxy
262     /// that proxy **all** traffic to the passed URL.
263     ///
264     /// # Examples
265     ///
266     /// ```
267     /// # use ylong_http_client::Proxy;
268     ///
269     /// let proxy = Proxy::all("http://proxy.example.com");
270     /// ```
all(url: &str) -> ProxyBuilder271     pub fn all(url: &str) -> ProxyBuilder {
272         ProxyBuilder(
273             reqwest::Proxy::all(url)
274                 .map_err(|e| HttpClientError::new_with_cause(ErrorKind::Build, Some(e))),
275         )
276     }
277 
inner(self) -> Option<reqwest::Proxy>278     pub(crate) fn inner(self) -> Option<reqwest::Proxy> {
279         self.0
280     }
281 }
282 
283 /// A builder that constructs a `Proxy`.
284 ///
285 /// # Examples
286 ///
287 /// ```
288 /// # use ylong_http_client::Proxy;
289 ///
290 /// let proxy = Proxy::all("http://proxy.example.com")
291 ///     .basic_auth("Aladdin", "open sesame")
292 ///     .build();
293 /// ```
294 pub struct ProxyBuilder(Result<reqwest::Proxy, HttpClientError>);
295 
296 impl ProxyBuilder {
297     /// Sets the `Proxy-Authorization` header using Basic auth.
298     ///
299     /// # Examples
300     ///
301     /// ```
302     /// # use ylong_http_client::Proxy;
303     ///
304     /// let builder = Proxy::all("http://proxy.example.com")
305     ///     .basic_auth("Aladdin", "open sesame");
306     /// ```
basic_auth(mut self, username: &str, password: &str) -> Self307     pub fn basic_auth(mut self, username: &str, password: &str) -> Self {
308         self.0 = self.0.map(|mut p| {
309             p = p.basic_auth(username, password);
310             p
311         });
312         self
313     }
314 
315     /// Constructs a `Proxy`.
316     ///
317     /// # Examples
318     ///
319     /// ```
320     /// # use ylong_http_client::Proxy;
321     ///
322     /// let proxy = Proxy::all("http://proxy.example.com").build();
323     /// ```
build(self) -> Result<Proxy, HttpClientError>324     pub fn build(self) -> Result<Proxy, HttpClientError> {
325         Ok(Proxy(Some(self.0?)))
326     }
327 }
328 
329 /// Represents a server X509 certificates.
330 ///
331 /// You can use `from_pem` to parse a `&[u8]` into a list of certificates.
332 ///
333 /// # Examples
334 ///
335 /// ```
336 /// use ylong_http_client::Certificate;
337 ///
338 /// fn from_pem(pem: &[u8]) {
339 ///     let certs = Certificate::from_pem(pem);
340 /// }
341 /// ```
342 pub struct Certificate {
343     inner: Vec<reqwest::Certificate>,
344 }
345 
346 impl Certificate {
347     /// Creates a `Certificate` from a PEM encoded certificate.
348     ///
349     /// Return `InvalidCertificate` if we cannot parse the given slice.
350     ///
351     /// # Examples
352     ///
353     /// ```no_run
354     /// # use ylong_http_client::Certificate;
355     ///
356     /// # fn cert() {
357     /// let file = std::fs::read("./cert.pem").unwrap();
358     /// let cert = reqwest::Certificate::from_pem(&file);
359     /// # }
360     /// ```
from_pem(pem: &[u8]) -> Result<Certificate, HttpClientError>361     pub fn from_pem(pem: &[u8]) -> Result<Certificate, HttpClientError> {
362         const CERT_BEGIN: &str = "-----BEGIN CERTIFICATE-----";
363         const CERT_END: &str = "-----END CERTIFICATE-----";
364 
365         let mut inner = Vec::new();
366         let str = std::str::from_utf8(pem).map_err(|_| {
367             HttpClientError::new_with_cause(ErrorKind::Build, Some(InvalidCertificate))
368         })?;
369         let mut pos = 0;
370         while pos < str.len() {
371             let st = match str[pos..].find(CERT_BEGIN) {
372                 Some(size) => size,
373                 None => break,
374             };
375 
376             let ed = match str[pos + st..].find(CERT_END) {
377                 Some(size) => size,
378                 None => break,
379             };
380 
381             let slice = str[pos + st..pos + st + ed + CERT_END.len()].as_bytes();
382             let cert = reqwest::Certificate::from_pem(slice)
383                 .map_err(|e| HttpClientError::new_with_cause(ErrorKind::Build, Some(e)))?;
384             inner.push(cert);
385             pos += st + ed + CERT_END.len();
386         }
387 
388         if inner.is_empty() {
389             return Err(HttpClientError::new_with_cause(
390                 ErrorKind::Build,
391                 Some(InvalidCertificate),
392             ));
393         }
394 
395         Ok(Self { inner })
396     }
397 
into_inner(self) -> Vec<reqwest::Certificate>398     pub(crate) fn into_inner(self) -> Vec<reqwest::Certificate> {
399         self.inner
400     }
401 }
402 
403 struct InvalidCertificate;
404 
405 impl Debug for InvalidCertificate {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result406     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
407         f.debug_struct("InvalidCertificate").finish()
408     }
409 }
410 
411 impl Display for InvalidCertificate {
fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result412     fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
413         f.write_str("InvalidCertificate")
414     }
415 }
416 
417 impl Error for InvalidCertificate {}
418