• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2023 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 //     http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13 
14 use ylong_http::body::{ChunkBody, TextBody};
15 use ylong_http::response::Response;
16 
17 use super::{conn, Body, ConnPool, Connector, HttpBody, HttpConnector};
18 use crate::async_impl::timeout::TimeoutFuture;
19 #[cfg(feature = "__tls")]
20 use crate::c_openssl::adapter::CertificateList;
21 use crate::util::normalizer::{format_host_value, RequestFormatter, UriFormatter};
22 use crate::util::proxy::Proxies;
23 use crate::util::redirect::TriggerKind;
24 use crate::util::{ClientConfig, ConnectorConfig, HttpConfig, HttpVersion, Redirect};
25 #[cfg(feature = "http2")]
26 use crate::H2Config;
27 use crate::{sleep, timeout, ErrorKind, HttpClientError, Proxy, Request, Timeout, Uri};
28 
29 /// HTTP asynchronous client implementation. Users can use `async_impl::Client`
30 /// to send `Request` asynchronously. `async_impl::Client` depends on a
31 /// [`async_impl::Connector`] that can be customized by the user.
32 ///
33 /// [`async_impl::Connector`]: Connector
34 ///
35 /// # Examples
36 ///
37 /// ```
38 /// use ylong_http_client::async_impl::Client;
39 /// use ylong_http_client::{EmptyBody, Request};
40 ///
41 /// async fn async_client() {
42 ///     // Creates a new `Client`.
43 ///     let client = Client::new();
44 ///
45 ///     // Creates a new `Request`.
46 ///     let request = Request::new(EmptyBody);
47 ///
48 ///     // Sends `Request` and wait for the `Response` to return asynchronously.
49 ///     let response = client.request(request).await.unwrap();
50 ///
51 ///     // Gets the content of `Response`.
52 ///     let status = response.status();
53 /// }
54 /// ```
55 pub struct Client<C: Connector> {
56     inner: ConnPool<C, C::Stream>,
57     client_config: ClientConfig,
58     http_config: HttpConfig,
59 }
60 
61 impl Client<HttpConnector> {
62     /// Creates a new, default `AsyncClient`, which uses
63     /// [`async_impl::HttpConnector`].
64     ///
65     /// [`async_impl::HttpConnector`]: HttpConnector
66     ///
67     /// # Examples
68     ///
69     /// ```
70     /// use ylong_http_client::async_impl::Client;
71     ///
72     /// let client = Client::new();
73     /// ```
new() -> Self74     pub fn new() -> Self {
75         Self::with_connector(HttpConnector::default())
76     }
77 
78     /// Creates a new, default [`async_impl::ClientBuilder`].
79     ///
80     /// [`async_impl::ClientBuilder`]: ClientBuilder
81     ///
82     /// # Examples
83     ///
84     /// ```
85     /// use ylong_http_client::async_impl::Client;
86     ///
87     /// let builder = Client::builder();
88     /// ```
builder() -> ClientBuilder89     pub fn builder() -> ClientBuilder {
90         ClientBuilder::new()
91     }
92 }
93 
94 impl<C: Connector> Client<C> {
95     /// Creates a new, default `AsyncClient` with a given connector.
with_connector(connector: C) -> Self96     pub fn with_connector(connector: C) -> Self {
97         let http_config = HttpConfig::default();
98         Self {
99             inner: ConnPool::new(http_config.clone(), connector),
100             client_config: ClientConfig::default(),
101             http_config,
102         }
103     }
104 
105     /// Sends HTTP `Request` asynchronously.
106     ///
107     /// # Examples
108     ///
109     /// ```
110     /// use ylong_http_client::async_impl::Client;
111     /// use ylong_http_client::{EmptyBody, Request};
112     ///
113     /// async fn async_client() {
114     ///     let client = Client::new();
115     ///     let response = client.request(Request::new(EmptyBody)).await;
116     /// }
117     /// ```
118     // TODO: change result to `Response<HttpBody>` later.
request<T: Body>( &self, request: Request<T>, ) -> Result<super::Response, HttpClientError>119     pub async fn request<T: Body>(
120         &self,
121         request: Request<T>,
122     ) -> Result<super::Response, HttpClientError> {
123         let (part, body) = request.into_parts();
124 
125         let content_length = part
126             .headers
127             .get("Content-Length")
128             .and_then(|v| v.to_str().ok())
129             .and_then(|v| v.parse::<u64>().ok())
130             .is_some();
131 
132         let transfer_encoding = part
133             .headers
134             .get("Transfer-Encoding")
135             .and_then(|v| v.to_str().ok())
136             .map(|v| v.contains("chunked"))
137             .unwrap_or(false);
138 
139         let response = match (content_length, transfer_encoding) {
140             (_, true) => {
141                 let request = Request::from_raw_parts(part, ChunkBody::from_async_body(body));
142                 self.retry_send_request(request).await
143             }
144             (true, false) => {
145                 let request = Request::from_raw_parts(part, TextBody::from_async_body(body));
146                 self.retry_send_request(request).await
147             }
148             (false, false) => {
149                 let request = Request::from_raw_parts(part, body);
150                 self.retry_send_request(request).await
151             }
152         };
153         response.map(super::Response::new)
154     }
155 
retry_send_request<T: Body>( &self, mut request: Request<T>, ) -> Result<Response<HttpBody>, HttpClientError>156     async fn retry_send_request<T: Body>(
157         &self,
158         mut request: Request<T>,
159     ) -> Result<Response<HttpBody>, HttpClientError> {
160         let mut retries = self.client_config.retry.times().unwrap_or(0);
161         loop {
162             let response = self.send_request_retryable(&mut request).await;
163             if response.is_ok() || retries == 0 {
164                 return response;
165             }
166             retries -= 1;
167         }
168     }
169 
send_request_retryable<T: Body>( &self, request: &mut Request<T>, ) -> Result<Response<HttpBody>, HttpClientError>170     async fn send_request_retryable<T: Body>(
171         &self,
172         request: &mut Request<T>,
173     ) -> Result<Response<HttpBody>, HttpClientError> {
174         let response = self
175             .send_request_with_uri(request.uri().clone(), request)
176             .await?;
177         self.redirect_request(response, request).await
178     }
179 
redirect_request<T: Body>( &self, mut response: Response<HttpBody>, request: &mut Request<T>, ) -> Result<Response<HttpBody>, HttpClientError>180     async fn redirect_request<T: Body>(
181         &self,
182         mut response: Response<HttpBody>,
183         request: &mut Request<T>,
184     ) -> Result<Response<HttpBody>, HttpClientError> {
185         let mut redirected_list = vec![];
186         let mut dst_uri = Uri::default();
187         loop {
188             if Redirect::is_redirect(response.status().clone(), request) {
189                 redirected_list.push(request.uri().clone());
190                 let trigger = Redirect::get_redirect(
191                     &mut dst_uri,
192                     &self.client_config.redirect,
193                     &redirected_list,
194                     &response,
195                     request,
196                 )?;
197 
198                 UriFormatter::new().format(&mut dst_uri)?;
199                 let _ = request
200                     .headers_mut()
201                     .insert("Host", format_host_value(&dst_uri)?.as_bytes());
202                 match trigger {
203                     TriggerKind::NextLink => {
204                         response = self.send_request_with_uri(dst_uri.clone(), request).await?;
205                         continue;
206                     }
207                     TriggerKind::Stop => {
208                         return Ok(response);
209                     }
210                 }
211             } else {
212                 return Ok(response);
213             }
214         }
215     }
216 
send_request_with_uri<T: Body>( &self, mut uri: Uri, request: &mut Request<T>, ) -> Result<Response<HttpBody>, HttpClientError>217     async fn send_request_with_uri<T: Body>(
218         &self,
219         mut uri: Uri,
220         request: &mut Request<T>,
221     ) -> Result<Response<HttpBody>, HttpClientError> {
222         UriFormatter::new().format(&mut uri)?;
223         RequestFormatter::new(request).normalize()?;
224 
225         match self.http_config.version {
226             #[cfg(feature = "http2")]
227             HttpVersion::Http2PriorKnowledge => self.http2_request(uri, request).await,
228             HttpVersion::Http11 => {
229                 let conn = if let Some(dur) = self.client_config.connect_timeout.inner() {
230                     match timeout(dur, self.inner.connect_to(uri)).await {
231                         Err(_elapsed) => {
232                             return Err(HttpClientError::new_with_message(
233                                 ErrorKind::Timeout,
234                                 "Connect timeout",
235                             ))
236                         }
237                         Ok(Ok(conn)) => conn,
238                         Ok(Err(e)) => return Err(e),
239                     }
240                 } else {
241                     self.inner.connect_to(uri).await?
242                 };
243 
244                 let mut retryable = Retryable::default();
245                 if let Some(timeout) = self.client_config.request_timeout.inner() {
246                     TimeoutFuture {
247                         timeout: Some(Box::pin(sleep(timeout))),
248                         future: Box::pin(conn::request(conn, request, &mut retryable)),
249                     }
250                     .await
251                 } else {
252                     conn::request(conn, request, &mut retryable).await
253                 }
254             }
255         }
256     }
257 
258     #[cfg(feature = "http2")]
http2_request<T: Body>( &self, uri: Uri, request: &mut Request<T>, ) -> Result<Response<HttpBody>, HttpClientError>259     async fn http2_request<T: Body>(
260         &self,
261         uri: Uri,
262         request: &mut Request<T>,
263     ) -> Result<Response<HttpBody>, HttpClientError> {
264         let mut retryable = Retryable::default();
265 
266         const RETRY: usize = 1;
267         let mut times = 0;
268         loop {
269             retryable.set_retry(false);
270             let conn = self.inner.connect_to(uri.clone()).await?;
271             let response = conn::request(conn, request, &mut retryable).await;
272             if retryable.retry() && times < RETRY {
273                 times += 1;
274                 continue;
275             }
276             return response;
277         }
278     }
279 }
280 
281 impl Default for Client<HttpConnector> {
default() -> Self282     fn default() -> Self {
283         Self::new()
284     }
285 }
286 
287 #[derive(Default)]
288 pub(crate) struct Retryable {
289     #[cfg(feature = "http2")]
290     retry: bool,
291 }
292 
293 #[cfg(feature = "http2")]
294 impl Retryable {
set_retry(&mut self, retryable: bool)295     pub(crate) fn set_retry(&mut self, retryable: bool) {
296         self.retry = retryable
297     }
298 
retry(&self) -> bool299     pub(crate) fn retry(&self) -> bool {
300         self.retry
301     }
302 }
303 
304 /// A builder which is used to construct `async_impl::Client`.
305 ///
306 /// # Examples
307 ///
308 /// ```
309 /// use ylong_http_client::async_impl::ClientBuilder;
310 ///
311 /// let client = ClientBuilder::new().build();
312 /// ```
313 pub struct ClientBuilder {
314     /// Options and flags that is related to `HTTP`.
315     http: HttpConfig,
316 
317     /// Options and flags that is related to `Client`.
318     client: ClientConfig,
319 
320     /// Options and flags that is related to `Proxy`.
321     proxies: Proxies,
322 
323     /// Options and flags that is related to `TLS`.
324     #[cfg(feature = "__tls")]
325     tls: crate::util::TlsConfigBuilder,
326 }
327 
328 impl ClientBuilder {
329     /// Creates a new, default `ClientBuilder`.
330     ///
331     /// # Examples
332     ///
333     /// ```
334     /// use ylong_http_client::async_impl::ClientBuilder;
335     ///
336     /// let builder = ClientBuilder::new();
337     /// ```
new() -> Self338     pub fn new() -> Self {
339         Self {
340             http: HttpConfig::default(),
341             client: ClientConfig::default(),
342             proxies: Proxies::default(),
343 
344             #[cfg(feature = "__tls")]
345             tls: crate::util::TlsConfig::builder(),
346         }
347     }
348 
349     /// Only use HTTP/1.
350     ///
351     /// # Examples
352     ///
353     /// ```
354     /// use ylong_http_client::async_impl::ClientBuilder;
355     ///
356     /// let builder = ClientBuilder::new().http1_only();
357     /// ```
http1_only(mut self) -> Self358     pub fn http1_only(mut self) -> Self {
359         self.http.version = HttpVersion::Http11;
360         self
361     }
362 
363     /// Only use HTTP/2.
364     ///
365     /// # Examples
366     ///
367     /// ```
368     /// use ylong_http_client::async_impl::ClientBuilder;
369     ///
370     /// let builder = ClientBuilder::new().http2_prior_knowledge();
371     /// ```
372     #[cfg(feature = "http2")]
http2_prior_knowledge(mut self) -> Self373     pub fn http2_prior_knowledge(mut self) -> Self {
374         self.http.version = HttpVersion::Http2PriorKnowledge;
375         self
376     }
377 
378     /// HTTP/2 settings.
379     ///
380     /// # Examples
381     ///
382     /// ```
383     /// use ylong_http_client::async_impl::ClientBuilder;
384     /// use ylong_http_client::H2Config;
385     ///
386     /// let builder = ClientBuilder::new().http2_settings(H2Config::default());
387     /// ```
388     #[cfg(feature = "http2")]
http2_settings(mut self, config: H2Config) -> Self389     pub fn http2_settings(mut self, config: H2Config) -> Self {
390         self.http.http2_config = config;
391         self
392     }
393 
394     /// Enables a request timeout.
395     ///
396     /// The timeout is applied from when the request starts connection util the
397     /// response body has finished.
398     ///
399     /// # Examples
400     ///
401     /// ```
402     /// use ylong_http_client::async_impl::ClientBuilder;
403     /// use ylong_http_client::Timeout;
404     ///
405     /// let builder = ClientBuilder::new().request_timeout(Timeout::none());
406     /// ```
request_timeout(mut self, timeout: Timeout) -> Self407     pub fn request_timeout(mut self, timeout: Timeout) -> Self {
408         self.client.request_timeout = timeout;
409         self
410     }
411 
412     /// Sets a timeout for only the connect phase of `Client`.
413     ///
414     /// Default is `Timeout::none()`.
415     ///
416     /// # Examples
417     ///
418     /// ```
419     /// use ylong_http_client::async_impl::ClientBuilder;
420     /// use ylong_http_client::Timeout;
421     ///
422     /// let builder = ClientBuilder::new().connect_timeout(Timeout::none());
423     /// ```
connect_timeout(mut self, timeout: Timeout) -> Self424     pub fn connect_timeout(mut self, timeout: Timeout) -> Self {
425         self.client.connect_timeout = timeout;
426         self
427     }
428 
429     /// Sets a `Redirect` for this client.
430     ///
431     /// Default will follow redirects up to a maximum of 10.
432     ///
433     /// # Examples
434     ///
435     /// ```
436     /// use ylong_http_client::async_impl::ClientBuilder;
437     /// use ylong_http_client::Redirect;
438     ///
439     /// let builder = ClientBuilder::new().redirect(Redirect::none());
440     /// ```
redirect(mut self, redirect: Redirect) -> Self441     pub fn redirect(mut self, redirect: Redirect) -> Self {
442         self.client.redirect = redirect;
443         self
444     }
445 
446     /// Adds a `Proxy` to the list of proxies the `Client` will use.
447     ///
448     /// # Examples
449     ///
450     /// ```
451     /// # use ylong_http_client::async_impl::ClientBuilder;
452     /// # use ylong_http_client::{HttpClientError, Proxy};
453     ///
454     /// # fn add_proxy() -> Result<(), HttpClientError> {
455     /// let builder = ClientBuilder::new().proxy(Proxy::http("http://www.example.com").build()?);
456     /// # Ok(())
457     /// # }
458     /// ```
proxy(mut self, proxy: Proxy) -> Self459     pub fn proxy(mut self, proxy: Proxy) -> Self {
460         self.proxies.add_proxy(proxy.inner());
461         self
462     }
463 
464     /// Constructs a `Client` based on the given settings.
465     ///
466     /// # Examples
467     ///
468     /// ```
469     /// use ylong_http_client::async_impl::ClientBuilder;
470     ///
471     /// let client = ClientBuilder::new().build();
472     /// ```
build(self) -> Result<Client<HttpConnector>, HttpClientError>473     pub fn build(self) -> Result<Client<HttpConnector>, HttpClientError> {
474         let config = ConnectorConfig {
475             proxies: self.proxies,
476             #[cfg(feature = "__tls")]
477             tls: self.tls.build()?,
478         };
479 
480         let connector = HttpConnector::new(config);
481 
482         Ok(Client {
483             inner: ConnPool::new(self.http.clone(), connector),
484             client_config: self.client,
485             http_config: self.http,
486         })
487     }
488 }
489 
490 #[cfg(feature = "__tls")]
491 impl ClientBuilder {
492     /// Sets the maximum allowed TLS version for connections.
493     ///
494     /// By default there's no maximum.
495     ///
496     /// # Examples
497     ///
498     /// ```
499     /// use ylong_http_client::async_impl::ClientBuilder;
500     /// use ylong_http_client::TlsVersion;
501     ///
502     /// let builder = ClientBuilder::new().max_tls_version(TlsVersion::TLS_1_2);
503     /// ```
max_tls_version(mut self, version: crate::util::TlsVersion) -> Self504     pub fn max_tls_version(mut self, version: crate::util::TlsVersion) -> Self {
505         self.tls = self.tls.max_proto_version(version);
506         self
507     }
508 
509     /// Sets the minimum required TLS version for connections.
510     ///
511     /// By default the TLS backend's own default is used.
512     ///
513     /// # Examples
514     ///
515     /// ```
516     /// use ylong_http_client::async_impl::ClientBuilder;
517     /// use ylong_http_client::TlsVersion;
518     ///
519     /// let builder = ClientBuilder::new().min_tls_version(TlsVersion::TLS_1_2);
520     /// ```
min_tls_version(mut self, version: crate::util::TlsVersion) -> Self521     pub fn min_tls_version(mut self, version: crate::util::TlsVersion) -> Self {
522         self.tls = self.tls.min_proto_version(version);
523         self
524     }
525 
526     /// Adds a custom root certificate.
527     ///
528     /// This can be used to connect to a server that has a self-signed.
529     /// certificate for example.
530     ///
531     /// # Examples
532     ///
533     /// ```
534     /// use ylong_http_client::async_impl::ClientBuilder;
535     /// use ylong_http_client::Certificate;
536     ///
537     /// # fn set_cert(cert: Certificate) {
538     /// let builder = ClientBuilder::new().add_root_certificate(cert);
539     /// # }
540     /// ```
add_root_certificate(mut self, certs: crate::util::Certificate) -> Self541     pub fn add_root_certificate(mut self, certs: crate::util::Certificate) -> Self {
542         match certs.into_inner() {
543             CertificateList::CertList(c) => {
544                 self.tls = self.tls.add_root_certificates(c);
545             }
546             #[cfg(feature = "c_openssl_3_0")]
547             CertificateList::PathList(p) => {
548                 self.tls = self.tls.add_path_certificates(p);
549             }
550         }
551         self
552     }
553 
554     /// Loads trusted root certificates from a file. The file should contain a
555     /// sequence of PEM-formatted CA certificates.
556     ///
557     /// # Examples
558     ///
559     /// ```
560     /// use ylong_http_client::async_impl::ClientBuilder;
561     ///
562     /// let builder = ClientBuilder::new().tls_ca_file("ca.crt");
563     /// ```
tls_ca_file(mut self, path: &str) -> Self564     pub fn tls_ca_file(mut self, path: &str) -> Self {
565         self.tls = self.tls.ca_file(path);
566         self
567     }
568 
569     /// Sets the list of supported ciphers for protocols before `TLSv1.3`.
570     ///
571     /// See [`ciphers`] for details on the format.
572     ///
573     /// [`ciphers`]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html
574     ///
575     /// # Examples
576     ///
577     /// ```
578     /// use ylong_http_client::async_impl::ClientBuilder;
579     ///
580     /// let builder = ClientBuilder::new()
581     ///     .tls_cipher_list("DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK");
582     /// ```
tls_cipher_list(mut self, list: &str) -> Self583     pub fn tls_cipher_list(mut self, list: &str) -> Self {
584         self.tls = self.tls.cipher_list(list);
585         self
586     }
587 
588     /// Sets the list of supported ciphers for the `TLSv1.3` protocol.
589     ///
590     /// The format consists of TLSv1.3 cipher suite names separated by `:`
591     /// characters in order of preference.
592     ///
593     /// Requires `OpenSSL 1.1.1` or `LibreSSL 3.4.0` or newer.
594     ///
595     /// # Examples
596     ///
597     /// ```
598     /// use ylong_http_client::async_impl::ClientBuilder;
599     ///
600     /// let builder = ClientBuilder::new().tls_cipher_suites(
601     ///     "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK",
602     /// );
603     /// ```
tls_cipher_suites(mut self, list: &str) -> Self604     pub fn tls_cipher_suites(mut self, list: &str) -> Self {
605         self.tls = self.tls.cipher_suites(list);
606         self
607     }
608 
609     /// Controls the use of built-in system certificates during certificate
610     /// validation. Default to `true` -- uses built-in system certs.
611     ///
612     /// # Examples
613     ///
614     /// ```
615     /// use ylong_http_client::async_impl::ClientBuilder;
616     ///
617     /// let builder = ClientBuilder::new().tls_built_in_root_certs(false);
618     /// ```
tls_built_in_root_certs(mut self, is_use: bool) -> Self619     pub fn tls_built_in_root_certs(mut self, is_use: bool) -> Self {
620         self.tls = self.tls.build_in_root_certs(is_use);
621         self
622     }
623 
624     /// Controls the use of certificates verification.
625     ///
626     /// Defaults to `false` -- verify certificates.
627     ///
628     /// # Warning
629     ///
630     /// When sets `true`, any certificate for any site will be trusted for use.
631     ///
632     /// # Examples
633     ///
634     /// ```
635     /// use ylong_http_client::async_impl::ClientBuilder;
636     ///
637     /// let builder = ClientBuilder::new().danger_accept_invalid_certs(true);
638     /// ```
danger_accept_invalid_certs(mut self, is_invalid: bool) -> Self639     pub fn danger_accept_invalid_certs(mut self, is_invalid: bool) -> Self {
640         self.tls = self.tls.danger_accept_invalid_certs(is_invalid);
641         self
642     }
643 
644     /// Controls the use of hostname verification.
645     ///
646     /// Defaults to `false` -- verify hostname.
647     ///
648     /// # Warning
649     ///
650     /// When sets `true`, any valid certificate for any site will be trusted for
651     /// use from any other.
652     ///
653     /// # Examples
654     ///
655     /// ```
656     /// use ylong_http_client::async_impl::ClientBuilder;
657     ///
658     /// let builder = ClientBuilder::new().danger_accept_invalid_hostnames(true);
659     /// ```
danger_accept_invalid_hostnames(mut self, is_invalid: bool) -> Self660     pub fn danger_accept_invalid_hostnames(mut self, is_invalid: bool) -> Self {
661         self.tls = self.tls.danger_accept_invalid_hostnames(is_invalid);
662         self
663     }
664 
665     /// Controls the use of TLS server name indication.
666     ///
667     /// Defaults to `true` -- sets sni.
668     ///
669     /// # Examples
670     ///
671     /// ```
672     /// use ylong_http_client::async_impl::ClientBuilder;
673     ///
674     /// let builder = ClientBuilder::new().tls_sni(true);
675     /// ```
tls_sni(mut self, is_set_sni: bool) -> Self676     pub fn tls_sni(mut self, is_set_sni: bool) -> Self {
677         self.tls = self.tls.sni(is_set_sni);
678         self
679     }
680 }
681 
682 impl Default for ClientBuilder {
default() -> Self683     fn default() -> Self {
684         Self::new()
685     }
686 }
687 
688 #[cfg(test)]
689 mod ut_async_impl_client {
690     use crate::async_impl::Client;
691     use crate::Proxy;
692 
693     /// UT test cases for `Client::builder`.
694     ///
695     /// # Brief
696     /// 1. Creates a ClientBuilder by calling `Client::Builder`.
697     /// 2. Calls `http_config`, `client_config`, `build` on the builder
698     ///    respectively.
699     /// 3. Checks if the result is as expected.
700     #[test]
ut_client_builder()701     fn ut_client_builder() {
702         let builder = Client::builder().http1_only().build();
703         assert!(builder.is_ok());
704         let builder_proxy = Client::builder()
705             .proxy(Proxy::http("http://www.example.com").build().unwrap())
706             .build();
707         assert!(builder_proxy.is_ok());
708     }
709 
710     /// UT test cases for `ClientBuilder::default`.
711     ///
712     /// # Brief
713     /// 1. Creates a `ClientBuilder` by calling `ClientBuilder::default`.
714     /// 2. Calls `http_config`, `client_config`, `tls_config` and `build`
715     ///    respectively.
716     /// 3. Checks if the result is as expected.
717     #[cfg(feature = "__tls")]
718     #[test]
ut_client_builder_default()719     fn ut_client_builder_default() {
720         use crate::async_impl::ClientBuilder;
721         use crate::util::{Redirect, Timeout};
722 
723         let builder = ClientBuilder::default()
724             .redirect(Redirect::none())
725             .connect_timeout(Timeout::from_secs(9))
726             .build();
727         assert!(builder.is_ok())
728     }
729 
730     /// UT test cases for `ClientBuilder::default`.
731     ///
732     /// # Brief
733     /// 1. Creates a `ClientBuilder` by calling `ClientBuilder::default`.
734     /// 2. Set redirect for client and call `Client::redirect_request`.
735     /// 3. Checks if the result is as expected.
736     #[cfg(all(feature = "__tls", feature = "ylong_base"))]
737     #[test]
ut_client_request_redirect()738     fn ut_client_request_redirect() {
739         let handle = ylong_runtime::spawn(async move {
740             client_request_redirect().await;
741         });
742         ylong_runtime::block_on(handle).unwrap();
743     }
744 
745     #[cfg(all(feature = "__tls", feature = "ylong_base"))]
client_request_redirect()746     async fn client_request_redirect() {
747         use ylong_http::h1::ResponseDecoder;
748         use ylong_http::request::uri::Uri;
749         use ylong_http::request::Request;
750         use ylong_http::response::Response;
751 
752         use crate::async_impl::{ClientBuilder, HttpBody};
753         use crate::util::normalizer::BodyLength;
754         use crate::util::{Redirect, Timeout};
755 
756         let response_str = "HTTP/1.1 304 \r\nAge: \t 270646 \t \t\r\nLocation: \t http://example3.com:80/foo?a=1 \t \t\r\nDate: \t Mon, 19 Dec 2022 01:46:59 GMT \t \t\r\nEtag:\t \"3147526947+gzip\" \t \t\r\n\r\n".as_bytes();
757         let mut decoder = ResponseDecoder::new();
758         let result = decoder.decode(response_str).unwrap().unwrap();
759 
760         let box_stream = Box::new("hello world".as_bytes());
761         let content_bytes = "";
762         let until_close =
763             HttpBody::new(BodyLength::UntilClose, box_stream, content_bytes.as_bytes()).unwrap();
764         let response = Response::from_raw_parts(result.0, until_close);
765         let mut request = Request::new("this is a body");
766         let request_uri = request.uri_mut();
767         *request_uri = Uri::from_bytes(b"http://example1.com:80/foo?a=1").unwrap();
768 
769         let client = ClientBuilder::default()
770             .redirect(Redirect::limited(2))
771             .connect_timeout(Timeout::from_secs(2))
772             .build()
773             .unwrap();
774         let res = client.redirect_request(response, &mut request).await;
775         assert!(res.is_ok())
776     }
777 }
778