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 std::sync::Arc; 15 16 use ylong_http::request::uri::Uri; 17 18 use super::pool::ConnPool; 19 use super::timeout::TimeoutFuture; 20 use super::{conn, Connector, HttpConnector, Request, Response}; 21 use crate::async_impl::dns::{DefaultDnsResolver, Resolver}; 22 use crate::async_impl::request::Message; 23 use crate::error::HttpClientError; 24 use crate::runtime::timeout; 25 #[cfg(feature = "__tls")] 26 use crate::util::c_openssl::verify::PubKeyPins; 27 #[cfg(all(target_os = "linux", feature = "ylong_base", feature = "__tls"))] 28 use crate::util::config::FchownConfig; 29 use crate::util::config::{ 30 ClientConfig, ConnectorConfig, HttpConfig, HttpVersion, Proxy, Redirect, Timeout, 31 }; 32 use crate::util::dispatcher::{Conn, TimeInfoConn}; 33 use crate::util::interceptor::{IdleInterceptor, Interceptor, Interceptors}; 34 use crate::util::normalizer::RequestFormatter; 35 use crate::util::proxy::Proxies; 36 use crate::util::redirect::{RedirectInfo, Trigger}; 37 use crate::util::request::RequestArc; 38 #[cfg(feature = "__tls")] 39 use crate::CertVerifier; 40 use crate::{ErrorKind, Retry}; 41 42 /// HTTP asynchronous client implementation. Users can use `async_impl::Client` 43 /// to send `Request` asynchronously. 44 /// 45 /// `async_impl::Client` depends on a [`async_impl::Connector`] that can be 46 /// customized by the user. 47 /// 48 /// [`async_impl::Connector`]: Connector 49 /// 50 /// # Examples 51 /// 52 /// ```no_run 53 /// use ylong_http_client::async_impl::{Body, Client, Request}; 54 /// use ylong_http_client::HttpClientError; 55 /// 56 /// async fn async_client() -> Result<(), HttpClientError> { 57 /// // Creates a new `Client`. 58 /// let client = Client::new(); 59 /// 60 /// // Creates a new `Request`. 61 /// let request = Request::builder().body(Body::empty())?; 62 /// 63 /// // Sends `Request` and wait for the `Response` to return asynchronously. 64 /// let response = client.request(request).await?; 65 /// 66 /// // Gets the content of `Response`. 67 /// let status = response.status(); 68 /// 69 /// Ok(()) 70 /// } 71 /// ``` 72 pub struct Client<C: Connector> { 73 inner: ConnPool<C, C::Stream>, 74 config: ClientConfig, 75 interceptors: Arc<Interceptors>, 76 } 77 78 impl Client<HttpConnector> { 79 /// Creates a new, default `Client`, which uses 80 /// [`async_impl::HttpConnector`]. 81 /// 82 /// [`async_impl::HttpConnector`]: HttpConnector 83 /// 84 /// # Examples 85 /// 86 /// ``` 87 /// use ylong_http_client::async_impl::Client; 88 /// 89 /// let client = Client::new(); 90 /// ``` new() -> Self91 pub fn new() -> Self { 92 Self::with_connector(HttpConnector::default()) 93 } 94 95 /// Creates a new, default `AsyncClient` with a given dns resolver. 96 /// # Examples 97 /// 98 /// ``` 99 /// use ylong_http_client::async_impl::{Client, DefaultDnsResolver}; 100 /// 101 /// let client = Client::with_dns_resolver(DefaultDnsResolver::default()); 102 /// ``` with_dns_resolver<R>(resolver: R) -> Self where R: Resolver,103 pub fn with_dns_resolver<R>(resolver: R) -> Self 104 where 105 R: Resolver, 106 { 107 Self::with_connector(HttpConnector::with_dns_resolver(resolver)) 108 } 109 110 /// Creates a new, default [`async_impl::ClientBuilder`]. 111 /// 112 /// [`async_impl::ClientBuilder`]: ClientBuilder 113 /// 114 /// # Examples 115 /// 116 /// ``` 117 /// use ylong_http_client::async_impl::Client; 118 /// 119 /// let builder = Client::builder(); 120 /// ``` builder() -> ClientBuilder121 pub fn builder() -> ClientBuilder { 122 ClientBuilder::new() 123 } 124 } 125 126 impl<C: Connector> Client<C> { 127 /// Creates a new, default `Client` with a given connector. 128 /// 129 /// # Examples 130 /// 131 /// ``` 132 /// use ylong_http_client::async_impl::{Client, HttpConnector}; 133 /// 134 /// let client = Client::with_connector(HttpConnector::default()); 135 /// ``` with_connector(connector: C) -> Self136 pub fn with_connector(connector: C) -> Self { 137 Self { 138 inner: ConnPool::new(HttpConfig::default(), connector), 139 config: ClientConfig::default(), 140 interceptors: Arc::new(IdleInterceptor), 141 } 142 } 143 144 /// Sends HTTP `Request` asynchronously. 145 /// 146 /// # Examples 147 /// 148 /// ``` 149 /// use ylong_http_client::async_impl::{Body, Client, Request}; 150 /// use ylong_http_client::HttpClientError; 151 /// 152 /// async fn async_client() -> Result<(), HttpClientError> { 153 /// let client = Client::new(); 154 /// let response = client 155 /// .request(Request::builder().body(Body::empty())?) 156 /// .await?; 157 /// Ok(()) 158 /// } 159 /// ``` request(&self, request: Request) -> Result<Response, HttpClientError>160 pub async fn request(&self, request: Request) -> Result<Response, HttpClientError> { 161 let mut request = RequestArc::new(request); 162 let mut retries = self.config.retry.times().unwrap_or(0); 163 loop { 164 let response = if let Some(timeout) = self.config.total_timeout.inner() { 165 TimeoutFuture::new( 166 self.send_request(request.clone()), 167 timeout, 168 |response, timeout| { 169 response.body_mut().set_total_sleep(timeout); 170 }, 171 ) 172 .await 173 } else { 174 self.send_request(request.clone()).await 175 }; 176 if let Err(ref err) = response { 177 if retries > 0 && request.ref_mut().body_mut().reuse().await.is_ok() { 178 self.interceptors.intercept_retry(err)?; 179 retries -= 1; 180 continue; 181 } 182 } 183 return response; 184 } 185 } 186 187 /// Enables a total timeout. 188 /// 189 /// The timeout is applied from when the request starts connection util the 190 /// response body has finished, and only affects subsequent tasks. 191 /// 192 /// # Examples 193 /// 194 /// ``` 195 /// use ylong_http_client::async_impl::Client; 196 /// use ylong_http_client::{HttpClientError, Timeout}; 197 /// 198 /// let mut client = Client::new(); 199 /// client.total_timeout(Timeout::none()); 200 /// ``` total_timeout(&mut self, timeout: Timeout)201 pub fn total_timeout(&mut self, timeout: Timeout) { 202 self.config.total_timeout = timeout; 203 } 204 } 205 206 impl<C: Connector> Client<C> { send_request(&self, request: RequestArc) -> Result<Response, HttpClientError>207 async fn send_request(&self, request: RequestArc) -> Result<Response, HttpClientError> { 208 let mut response = self.send_unformatted_request(request.clone()).await?; 209 response = self.redirect(response, request.clone()).await?; 210 #[cfg(feature = "http3")] 211 self.inner.set_alt_svcs(request, &response); 212 Ok(response) 213 } 214 send_unformatted_request( &self, mut request: RequestArc, ) -> Result<Response, HttpClientError>215 async fn send_unformatted_request( 216 &self, 217 mut request: RequestArc, 218 ) -> Result<Response, HttpClientError> { 219 RequestFormatter::new(request.ref_mut()).format()?; 220 let mut info_conn = self.connect_to(request.ref_mut().uri()).await?; 221 request 222 .ref_mut() 223 .time_group_mut() 224 .update_transport_conn_time(info_conn.time_group()); 225 let mut conn = info_conn.connection(); 226 self.interceptors.intercept_connection(conn.get_detail())?; 227 self.send_request_on_conn(conn, request).await 228 } 229 connect_to(&self, uri: &Uri) -> Result<TimeInfoConn<C::Stream>, HttpClientError>230 async fn connect_to(&self, uri: &Uri) -> Result<TimeInfoConn<C::Stream>, HttpClientError> { 231 if let Some(dur) = self.config.connect_timeout.inner() { 232 match timeout(dur, self.inner.connect_to(uri)).await { 233 Err(elapsed) => err_from_other!(Timeout, elapsed), 234 Ok(Ok(conn)) => Ok(conn), 235 Ok(Err(e)) => Err(e), 236 } 237 } else { 238 self.inner.connect_to(uri).await 239 } 240 } 241 send_request_on_conn( &self, conn: Conn<C::Stream>, request: RequestArc, ) -> Result<Response, HttpClientError>242 async fn send_request_on_conn( 243 &self, 244 conn: Conn<C::Stream>, 245 request: RequestArc, 246 ) -> Result<Response, HttpClientError> { 247 let message = Message { 248 request, 249 interceptor: Arc::clone(&self.interceptors), 250 }; 251 if let Some(timeout) = self.config.request_timeout.inner() { 252 TimeoutFuture::new( 253 conn::request(conn, message), 254 timeout, 255 |response, timeout| { 256 response.body_mut().set_request_sleep(timeout); 257 }, 258 ) 259 .await 260 } else { 261 conn::request(conn, message).await 262 } 263 } 264 redirect( &self, response: Response, mut request: RequestArc, ) -> Result<Response, HttpClientError>265 async fn redirect( 266 &self, 267 response: Response, 268 mut request: RequestArc, 269 ) -> Result<Response, HttpClientError> { 270 let mut response = response; 271 let mut info = RedirectInfo::new(); 272 loop { 273 match self 274 .config 275 .redirect 276 .inner() 277 .redirect(request.ref_mut(), &response, &mut info)? 278 { 279 Trigger::NextLink => { 280 // Here the body should be reused. 281 request 282 .ref_mut() 283 .body_mut() 284 .reuse() 285 .await 286 .map_err(|e| HttpClientError::from_io_error(ErrorKind::Redirect, e))?; 287 self.interceptors 288 .intercept_redirect_request(request.ref_mut())?; 289 response = self.send_unformatted_request(request.clone()).await?; 290 self.interceptors.intercept_redirect_response(&response)?; 291 } 292 Trigger::Stop => { 293 self.interceptors.intercept_response(&response)?; 294 return Ok(response); 295 } 296 } 297 } 298 } 299 } 300 301 impl Default for Client<HttpConnector> { default() -> Self302 fn default() -> Self { 303 Self::new() 304 } 305 } 306 307 /// A builder which is used to construct `async_impl::Client`. 308 /// 309 /// # Examples 310 /// 311 /// ``` 312 /// use ylong_http_client::async_impl::ClientBuilder; 313 /// 314 /// let client = ClientBuilder::new().build(); 315 /// ``` 316 pub struct ClientBuilder { 317 /// Options and flags that is related to `HTTP`. 318 http: HttpConfig, 319 320 /// Options and flags that is related to `Client`. 321 client: ClientConfig, 322 323 /// Options and flags that is related to `Proxy`. 324 proxies: Proxies, 325 326 #[cfg(all(target_os = "linux", feature = "ylong_base", feature = "__tls"))] 327 /// Fchown configuration. 328 fchown: Option<FchownConfig>, 329 330 /// Interceptor for all stages. 331 interceptors: Arc<Interceptors>, 332 /// Resolver to http DNS. 333 resolver: Arc<dyn Resolver>, 334 335 /// Options and flags that is related to `TLS`. 336 #[cfg(feature = "__tls")] 337 tls: crate::util::TlsConfigBuilder, 338 } 339 340 impl ClientBuilder { 341 /// Creates a new, default `ClientBuilder`. 342 /// 343 /// # Examples 344 /// 345 /// ``` 346 /// use ylong_http_client::async_impl::ClientBuilder; 347 /// 348 /// let builder = ClientBuilder::new(); 349 /// ``` new() -> Self350 pub fn new() -> Self { 351 Self { 352 http: HttpConfig::default(), 353 client: ClientConfig::default(), 354 proxies: Proxies::default(), 355 #[cfg(all(target_os = "linux", feature = "ylong_base", feature = "__tls"))] 356 fchown: None, 357 interceptors: Arc::new(IdleInterceptor), 358 resolver: Arc::new(DefaultDnsResolver::default()), 359 #[cfg(feature = "__tls")] 360 tls: crate::util::TlsConfig::builder(), 361 } 362 } 363 364 /// Only use HTTP/1.x. 365 /// 366 /// # Examples 367 /// 368 /// ``` 369 /// use ylong_http_client::async_impl::ClientBuilder; 370 /// 371 /// let builder = ClientBuilder::new().http1_only(); 372 /// ``` 373 #[cfg(feature = "http1_1")] http1_only(mut self) -> Self374 pub fn http1_only(mut self) -> Self { 375 self.http.version = HttpVersion::Http1; 376 self 377 } 378 379 /// Enables a total timeout. 380 /// 381 /// The timeout is applied from when the request starts connection util the 382 /// response body has finished. 383 /// 384 /// # Examples 385 /// 386 /// ``` 387 /// use ylong_http_client::async_impl::ClientBuilder; 388 /// use ylong_http_client::Timeout; 389 /// 390 /// let builder = ClientBuilder::new().total_timeout(Timeout::none()); 391 /// ``` total_timeout(mut self, timeout: Timeout) -> Self392 pub fn total_timeout(mut self, timeout: Timeout) -> Self { 393 self.client.total_timeout = timeout; 394 self 395 } 396 397 /// Enables a request timeout. 398 /// 399 /// The timeout is applied from when the request is sent util the 400 /// response body has finished. 401 /// 402 /// # Examples 403 /// 404 /// ``` 405 /// use ylong_http_client::async_impl::ClientBuilder; 406 /// use ylong_http_client::Timeout; 407 /// 408 /// let builder = ClientBuilder::new().request_timeout(Timeout::none()); 409 /// ``` request_timeout(mut self, timeout: Timeout) -> Self410 pub fn request_timeout(mut self, timeout: Timeout) -> Self { 411 self.client.request_timeout = timeout; 412 self 413 } 414 415 /// Sets a timeout for only the connect phase of `Client`. 416 /// 417 /// Default is `Timeout::none()`. 418 /// 419 /// # Examples 420 /// 421 /// ``` 422 /// use ylong_http_client::async_impl::ClientBuilder; 423 /// use ylong_http_client::Timeout; 424 /// 425 /// let builder = ClientBuilder::new().connect_timeout(Timeout::none()); 426 /// ``` connect_timeout(mut self, timeout: Timeout) -> Self427 pub fn connect_timeout(mut self, timeout: Timeout) -> Self { 428 self.client.connect_timeout = timeout; 429 self 430 } 431 432 /// Sets a `Redirect` for this client. 433 /// 434 /// Default will follow redirects up to a maximum of 10. 435 /// 436 /// # Examples 437 /// 438 /// ``` 439 /// use ylong_http_client::async_impl::ClientBuilder; 440 /// use ylong_http_client::Redirect; 441 /// 442 /// let builder = ClientBuilder::new().redirect(Redirect::none()); 443 /// ``` redirect(mut self, redirect: Redirect) -> Self444 pub fn redirect(mut self, redirect: Redirect) -> Self { 445 self.client.redirect = redirect; 446 self 447 } 448 449 /// Sets a `Fchown` for this client. 450 /// 451 /// Default will not set the owner of the file descriptor. 452 /// 453 /// # Examples 454 /// 455 /// ``` 456 /// use ylong_http_client::async_impl::ClientBuilder; 457 /// 458 /// let builder = ClientBuilder::new().sockets_owner(1000, 1000); 459 /// ``` 460 #[cfg(all(target_os = "linux", feature = "ylong_base", feature = "__tls"))] sockets_owner(mut self, uid: u32, gid: u32) -> Self461 pub fn sockets_owner(mut self, uid: u32, gid: u32) -> Self { 462 self.fchown = Some(FchownConfig::new(uid, gid)); 463 self 464 } 465 466 /// Sets retry times for this client. 467 /// 468 /// The Retry is the number of times the client will retry the request if 469 /// the response is not obtained correctly. 470 /// 471 /// # Examples 472 /// 473 /// ``` 474 /// use ylong_http_client::async_impl::ClientBuilder; 475 /// use ylong_http_client::Retry; 476 /// 477 /// let builder = ClientBuilder::new().retry(Retry::max()); 478 /// ``` retry(mut self, retry: Retry) -> Self479 pub fn retry(mut self, retry: Retry) -> Self { 480 self.client.retry = retry; 481 self 482 } 483 484 /// Adds a `Proxy` to the list of proxies the `Client` will use. 485 /// 486 /// # Examples 487 /// 488 /// ``` 489 /// # use ylong_http_client::async_impl::ClientBuilder; 490 /// # use ylong_http_client::{HttpClientError, Proxy}; 491 /// 492 /// # fn add_proxy() -> Result<(), HttpClientError> { 493 /// let builder = ClientBuilder::new().proxy(Proxy::http("http://www.example.com").build()?); 494 /// # Ok(()) 495 /// # } 496 /// ``` proxy(mut self, proxy: Proxy) -> Self497 pub fn proxy(mut self, proxy: Proxy) -> Self { 498 self.proxies.add_proxy(proxy.inner()); 499 self 500 } 501 502 /// Sets the maximum number of http1 connections allowed. 503 /// 504 /// By default, the maximum number of http1 connections allowed is 6. 505 /// 506 /// # Examples 507 /// 508 /// ``` 509 /// use ylong_http_client::async_impl::ClientBuilder; 510 /// 511 /// let builder = ClientBuilder::new().max_h1_conn_number(5); 512 /// ``` max_h1_conn_number(mut self, number: usize) -> Self513 pub fn max_h1_conn_number(mut self, number: usize) -> Self { 514 self.http.http1_config.set_max_conn_num(number); 515 self 516 } 517 518 /// Sets the maximum number of bytes per second allowed for data transfer. 519 /// 520 /// By default, there is no limit. 521 /// 522 /// # Examples 523 /// 524 /// ``` 525 /// use ylong_http_client::async_impl::ClientBuilder; 526 /// 527 /// let builder = ClientBuilder::new().max_speed_limit(5); 528 /// ``` max_speed_limit(mut self, rate: u64) -> Self529 pub fn max_speed_limit(mut self, rate: u64) -> Self { 530 self.http.speed_config.set_max_rate(rate); 531 self 532 } 533 534 /// Sets the minimum number of bytes per second allowed for data transfer. 535 /// 536 /// By default, there is no limit. 537 /// 538 /// # Examples 539 /// 540 /// ``` 541 /// use ylong_http_client::async_impl::ClientBuilder; 542 /// 543 /// let builder = ClientBuilder::new().min_speed_limit(5); 544 /// ``` min_speed_limit(mut self, rate: u64) -> Self545 pub fn min_speed_limit(mut self, rate: u64) -> Self { 546 self.http.speed_config.set_min_rate(rate); 547 self 548 } 549 550 /// Sets the maximum time that the speed is allowed to be below 551 /// min_speed_limit, beyond which the abort is executed. 552 /// 553 /// By default, there is no limit. 554 /// 555 /// # Examples 556 /// 557 /// ``` 558 /// use ylong_http_client::async_impl::ClientBuilder; 559 /// 560 /// let builder = ClientBuilder::new().min_speed_limit(5); 561 /// ``` min_speed_interval(mut self, seconds: u64) -> Self562 pub fn min_speed_interval(mut self, seconds: u64) -> Self { 563 self.http.speed_config.set_min_speed_interval(seconds); 564 self 565 } 566 567 /// Adds a `Interceptor` to the `Client`. 568 /// 569 /// # Examples 570 /// 571 /// ``` 572 /// # use ylong_http_client::async_impl::ClientBuilder; 573 /// # use ylong_http_client::{HttpClientError, Interceptor}; 574 /// 575 /// # fn add_interceptor<T>(interceptor: T) 576 /// # where T: Interceptor + Sync + Send + 'static, 577 /// # { 578 /// let builder = ClientBuilder::new().interceptor(interceptor); 579 /// # } 580 /// ``` interceptor<T>(mut self, interceptors: T) -> Self where T: Interceptor + Sync + Send + 'static,581 pub fn interceptor<T>(mut self, interceptors: T) -> Self 582 where 583 T: Interceptor + Sync + Send + 'static, 584 { 585 self.interceptors = Arc::new(interceptors); 586 self 587 } 588 589 /// Adds a dns `Resolver` to the `Client`. 590 /// 591 /// # Example 592 /// 593 /// ``` 594 /// use ylong_http_client::async_impl::{ClientBuilder, DefaultDnsResolver}; 595 /// 596 /// let builder = ClientBuilder::new().dns_resolver(DefaultDnsResolver::default()); 597 /// ``` dns_resolver<R>(mut self, resolver: R) -> Self where R: Resolver,598 pub fn dns_resolver<R>(mut self, resolver: R) -> Self 599 where 600 R: Resolver, 601 { 602 self.resolver = Arc::new(resolver); 603 self 604 } 605 606 /// Constructs a `Client` based on the given settings. 607 /// 608 /// # Examples 609 /// 610 /// ``` 611 /// use ylong_http_client::async_impl::ClientBuilder; 612 /// 613 /// let client = ClientBuilder::new().build(); 614 /// ``` build(self) -> Result<Client<HttpConnector>, HttpClientError>615 pub fn build(self) -> Result<Client<HttpConnector>, HttpClientError> { 616 #[cfg(feature = "__tls")] 617 use crate::util::{AlpnProtocol, AlpnProtocolList}; 618 619 #[cfg(feature = "__tls")] 620 let origin_builder = self.tls; 621 #[cfg(feature = "__tls")] 622 let tls_builder = match self.http.version { 623 HttpVersion::Http1 => origin_builder, 624 #[cfg(feature = "http2")] 625 HttpVersion::Http2 => origin_builder.alpn_protos(AlpnProtocol::H2.wire_format_bytes()), 626 HttpVersion::Negotiate => { 627 let supported = AlpnProtocolList::new(); 628 #[cfg(feature = "http3")] 629 let supported = supported.extend(AlpnProtocol::H3); 630 #[cfg(feature = "http2")] 631 let supported = supported.extend(AlpnProtocol::H2); 632 let supported = supported.extend(AlpnProtocol::HTTP11); 633 origin_builder.alpn_proto_list(supported) 634 } 635 #[cfg(feature = "http3")] 636 HttpVersion::Http3 => origin_builder.alpn_protos(AlpnProtocol::H3.wire_format_bytes()), 637 }; 638 639 let config = ConnectorConfig { 640 proxies: self.proxies, 641 #[cfg(all(target_os = "linux", feature = "ylong_base", feature = "__tls"))] 642 fchown: self.fchown, 643 #[cfg(feature = "__tls")] 644 tls: tls_builder.build()?, 645 timeout: self.client.connect_timeout.clone(), 646 }; 647 648 let connector = HttpConnector::new(config, self.resolver); 649 650 Ok(Client { 651 inner: ConnPool::new(self.http, connector), 652 config: self.client, 653 interceptors: self.interceptors, 654 }) 655 } 656 } 657 658 #[cfg(feature = "http2")] 659 impl ClientBuilder { 660 /// Only use HTTP/2. 661 /// 662 /// # Examples 663 /// 664 /// ``` 665 /// use ylong_http_client::async_impl::ClientBuilder; 666 /// 667 /// let builder = ClientBuilder::new().http2_prior_knowledge(); 668 /// ``` http2_prior_knowledge(mut self) -> Self669 pub fn http2_prior_knowledge(mut self) -> Self { 670 self.http.version = HttpVersion::Http2; 671 self 672 } 673 674 /// Sets allowed max size of local cached frame, By default, 5 frames are 675 /// allowed per stream. 676 /// 677 /// # Examples 678 /// 679 /// ``` 680 /// use ylong_http_client::async_impl::ClientBuilder; 681 /// 682 /// let config = ClientBuilder::new().allowed_cache_frame_size(10); 683 /// ``` allowed_cache_frame_size(mut self, size: usize) -> Self684 pub fn allowed_cache_frame_size(mut self, size: usize) -> Self { 685 self.http.http2_config.set_allowed_cache_frame_size(size); 686 self 687 } 688 689 /// Sets whether to use huffman coding in hpack. The default is true. 690 /// 691 /// # Examples 692 /// 693 /// ``` 694 /// use ylong_http_client::async_impl::ClientBuilder; 695 /// 696 /// let config = ClientBuilder::new().use_huffman_coding(true); 697 /// ``` use_huffman_coding(mut self, use_huffman: bool) -> Self698 pub fn use_huffman_coding(mut self, use_huffman: bool) -> Self { 699 self.http.http2_config.set_use_huffman_coding(use_huffman); 700 self 701 } 702 703 /// Sets the `SETTINGS_MAX_FRAME_SIZE`. 704 /// 705 /// # Examples 706 /// 707 /// ``` 708 /// use ylong_http_client::async_impl::ClientBuilder; 709 /// 710 /// let config = ClientBuilder::new().set_http2_max_frame_size(2 << 13); 711 /// ``` set_http2_max_frame_size(mut self, size: u32) -> Self712 pub fn set_http2_max_frame_size(mut self, size: u32) -> Self { 713 self.http.http2_config.set_max_frame_size(size); 714 self 715 } 716 717 /// Sets the `SETTINGS_MAX_HEADER_LIST_SIZE`. 718 /// 719 /// # Examples 720 /// 721 /// ``` 722 /// use ylong_http_client::async_impl::ClientBuilder; 723 /// 724 /// let config = ClientBuilder::new().set_http2_max_header_list_size(16 << 20); 725 /// ``` set_http2_max_header_list_size(mut self, size: u32) -> Self726 pub fn set_http2_max_header_list_size(mut self, size: u32) -> Self { 727 self.http.http2_config.set_max_header_list_size(size); 728 self 729 } 730 731 /// Sets the `SETTINGS_HEADER_TABLE_SIZE`. 732 /// 733 /// # Examples 734 /// 735 /// ``` 736 /// use ylong_http_client::async_impl::ClientBuilder; 737 /// 738 /// let config = ClientBuilder::new().set_http2_max_header_list_size(4096); 739 /// ``` set_http2_header_table_size(mut self, size: u32) -> Self740 pub fn set_http2_header_table_size(mut self, size: u32) -> Self { 741 self.http.http2_config.set_header_table_size(size); 742 self 743 } 744 745 /// Sets the maximum connection window allowed by the client. 746 /// 747 /// # Examples 748 /// 749 /// ``` 750 /// use ylong_http_client::async_impl::ClientBuilder; 751 /// 752 /// let config = ClientBuilder::new().set_conn_recv_window_size(4096); 753 /// ``` set_conn_recv_window_size(mut self, size: u32) -> Self754 pub fn set_conn_recv_window_size(mut self, size: u32) -> Self { 755 assert!(size <= crate::util::h2::MAX_FLOW_CONTROL_WINDOW); 756 self.http.http2_config.set_conn_window_size(size); 757 self 758 } 759 760 /// Sets the `SETTINGS_INITIAL_WINDOW_SIZE`. 761 /// 762 /// # Examples 763 /// 764 /// ``` 765 /// use ylong_http_client::async_impl::ClientBuilder; 766 /// 767 /// let config = ClientBuilder::new().set_stream_recv_window_size(4096); 768 /// ``` set_stream_recv_window_size(mut self, size: u32) -> Self769 pub fn set_stream_recv_window_size(mut self, size: u32) -> Self { 770 assert!(size <= crate::util::h2::MAX_FLOW_CONTROL_WINDOW); 771 self.http.http2_config.set_stream_window_size(size); 772 self 773 } 774 } 775 776 #[cfg(feature = "http3")] 777 impl ClientBuilder { 778 /// Only use HTTP/3. 779 /// 780 /// # Examples 781 /// 782 /// ``` 783 /// use ylong_http_client::async_impl::ClientBuilder; 784 /// 785 /// let builder = ClientBuilder::new().http3_prior_knowledge(); 786 /// ``` http3_prior_knowledge(mut self) -> Self787 pub fn http3_prior_knowledge(mut self) -> Self { 788 self.http.version = HttpVersion::Http3; 789 self 790 } 791 792 /// Sets the `SETTINGS_MAX_FIELD_SECTION_SIZE` defined in RFC9114 793 /// 794 /// # Examples 795 /// 796 /// ``` 797 /// use ylong_http_client::async_impl::ClientBuilder; 798 /// 799 /// let builder = ClientBuilder::new().set_http3_max_field_section_size(16 * 1024); 800 /// ``` set_http3_max_field_section_size(mut self, size: u64) -> Self801 pub fn set_http3_max_field_section_size(mut self, size: u64) -> Self { 802 self.http.http3_config.set_max_field_section_size(size); 803 self 804 } 805 806 /// Sets the `SETTINGS_QPACK_MAX_TABLE_CAPACITY` defined in RFC9204 807 /// 808 /// # Examples 809 /// 810 /// ``` 811 /// use ylong_http_client::async_impl::ClientBuilder; 812 /// 813 /// let builder = ClientBuilder::new().set_http3_qpack_max_table_capacity(16 * 1024); 814 /// ``` set_http3_qpack_max_table_capacity(mut self, size: u64) -> Self815 pub fn set_http3_qpack_max_table_capacity(mut self, size: u64) -> Self { 816 self.http.http3_config.set_qpack_max_table_capacity(size); 817 self 818 } 819 820 /// Sets the `SETTINGS_QPACK_BLOCKED_STREAMS` defined in RFC9204 821 /// 822 /// # Examples 823 /// 824 /// ``` 825 /// use ylong_http_client::async_impl::ClientBuilder; 826 /// 827 /// let builder = ClientBuilder::new().set_http3_qpack_blocked_streams(10); 828 /// ``` set_http3_qpack_blocked_streams(mut self, size: u64) -> Self829 pub fn set_http3_qpack_blocked_streams(mut self, size: u64) -> Self { 830 self.http.http3_config.set_qpack_blocked_streams(size); 831 self 832 } 833 } 834 835 #[cfg(feature = "__tls")] 836 impl ClientBuilder { 837 /// Sets the maximum allowed TLS version for connections. 838 /// 839 /// By default, there's no maximum. 840 /// 841 /// # Examples 842 /// 843 /// ``` 844 /// use ylong_http_client::async_impl::ClientBuilder; 845 /// use ylong_http_client::TlsVersion; 846 /// 847 /// let builder = ClientBuilder::new().max_tls_version(TlsVersion::TLS_1_2); 848 /// ``` max_tls_version(mut self, version: crate::util::TlsVersion) -> Self849 pub fn max_tls_version(mut self, version: crate::util::TlsVersion) -> Self { 850 self.tls = self.tls.max_proto_version(version); 851 self 852 } 853 854 /// Sets the minimum required TLS version for connections. 855 /// 856 /// By default, the TLS backend's own default is used. 857 /// 858 /// # Examples 859 /// 860 /// ``` 861 /// use ylong_http_client::async_impl::ClientBuilder; 862 /// use ylong_http_client::TlsVersion; 863 /// 864 /// let builder = ClientBuilder::new().min_tls_version(TlsVersion::TLS_1_2); 865 /// ``` min_tls_version(mut self, version: crate::util::TlsVersion) -> Self866 pub fn min_tls_version(mut self, version: crate::util::TlsVersion) -> Self { 867 self.tls = self.tls.min_proto_version(version); 868 self 869 } 870 871 /// Adds a custom root certificate. 872 /// 873 /// This can be used to connect to a server that has a self-signed. 874 /// certificate for example. 875 /// 876 /// # Examples 877 /// 878 /// ``` 879 /// use ylong_http_client::async_impl::ClientBuilder; 880 /// use ylong_http_client::Certificate; 881 /// 882 /// # fn set_cert(cert: Certificate) { 883 /// let builder = ClientBuilder::new().add_root_certificate(cert); 884 /// # } 885 /// ``` add_root_certificate(mut self, certs: crate::util::Certificate) -> Self886 pub fn add_root_certificate(mut self, certs: crate::util::Certificate) -> Self { 887 use crate::c_openssl::adapter::CertificateList; 888 889 match certs.into_inner() { 890 CertificateList::CertList(c) => { 891 self.tls = self.tls.add_root_certificates(c); 892 } 893 CertificateList::PathList(p) => { 894 self.tls = self.tls.add_path_certificates(p); 895 } 896 } 897 self 898 } 899 900 /// Adds user pinned Public Key. 901 /// 902 /// Used to avoid man-in-the-middle attacks. 903 /// 904 /// # Examples 905 /// 906 /// ``` 907 /// use ylong_http_client::async_impl::ClientBuilder; 908 /// use ylong_http_client::PubKeyPins; 909 /// 910 /// let pinned_key = PubKeyPins::builder() 911 /// .add("https://example.com:443", 912 /// "sha256//YhKJKSzoTt2b5FP18fvpHo7fJYqQCjAa3HWY3tvRMwE=;sha256//t62CeU2tQiqkexU74Gxa2eg7fRbEgoChTociMee9wno=") 913 /// .build() 914 /// .unwrap(); 915 /// let builder = ClientBuilder::new().add_public_key_pins(pinned_key); 916 /// ``` add_public_key_pins(mut self, pin: PubKeyPins) -> Self917 pub fn add_public_key_pins(mut self, pin: PubKeyPins) -> Self { 918 self.tls = self.tls.pinning_public_key(pin); 919 self 920 } 921 922 /// Loads trusted root certificates from a file. The file should contain a 923 /// sequence of PEM-formatted CA certificates. 924 /// 925 /// # Examples 926 /// 927 /// ``` 928 /// use ylong_http_client::async_impl::ClientBuilder; 929 /// 930 /// let builder = ClientBuilder::new().tls_ca_file("ca.crt"); 931 /// ``` tls_ca_file(mut self, path: &str) -> Self932 pub fn tls_ca_file(mut self, path: &str) -> Self { 933 self.tls = self.tls.ca_file(path); 934 self 935 } 936 937 /// Sets the list of supported ciphers for protocols before `TLSv1.3`. 938 /// 939 /// See [`ciphers`] for details on the format. 940 /// 941 /// [`ciphers`]: https://www.openssl.org/docs/man1.1.0/apps/ciphers.html 942 /// 943 /// # Examples 944 /// 945 /// ``` 946 /// use ylong_http_client::async_impl::ClientBuilder; 947 /// 948 /// let builder = ClientBuilder::new() 949 /// .tls_cipher_list("DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK"); 950 /// ``` tls_cipher_list(mut self, list: &str) -> Self951 pub fn tls_cipher_list(mut self, list: &str) -> Self { 952 self.tls = self.tls.cipher_list(list); 953 self 954 } 955 956 /// Controls the use of built-in system certificates during certificate 957 /// validation. Default to `true` -- uses built-in system certs. 958 /// 959 /// # Examples 960 /// 961 /// ``` 962 /// use ylong_http_client::async_impl::ClientBuilder; 963 /// 964 /// let builder = ClientBuilder::new().tls_built_in_root_certs(false); 965 /// ``` tls_built_in_root_certs(mut self, is_use: bool) -> Self966 pub fn tls_built_in_root_certs(mut self, is_use: bool) -> Self { 967 self.tls = self.tls.build_in_root_certs(is_use); 968 self 969 } 970 971 /// Controls the use of certificates verification. 972 /// 973 /// Defaults to `false` -- verify certificates. 974 /// 975 /// # Warning 976 /// 977 /// When sets `true`, any certificate for any site will be trusted for use. 978 /// 979 /// # Examples 980 /// 981 /// ``` 982 /// use ylong_http_client::async_impl::ClientBuilder; 983 /// 984 /// let builder = ClientBuilder::new().danger_accept_invalid_certs(true); 985 /// ``` danger_accept_invalid_certs(mut self, is_invalid: bool) -> Self986 pub fn danger_accept_invalid_certs(mut self, is_invalid: bool) -> Self { 987 self.tls = self.tls.danger_accept_invalid_certs(is_invalid); 988 self 989 } 990 991 /// Controls the use of hostname verification. 992 /// 993 /// Defaults to `false` -- verify hostname. 994 /// 995 /// # Warning 996 /// 997 /// When sets `true`, any valid certificate for any site will be trusted for 998 /// use from any other. 999 /// 1000 /// # Examples 1001 /// 1002 /// ``` 1003 /// use ylong_http_client::async_impl::ClientBuilder; 1004 /// 1005 /// let builder = ClientBuilder::new().danger_accept_invalid_hostnames(true); 1006 /// ``` danger_accept_invalid_hostnames(mut self, is_invalid: bool) -> Self1007 pub fn danger_accept_invalid_hostnames(mut self, is_invalid: bool) -> Self { 1008 self.tls = self.tls.danger_accept_invalid_hostnames(is_invalid); 1009 self 1010 } 1011 1012 /// Controls the use of TLS server name indication. 1013 /// 1014 /// Defaults to `true` -- sets sni. 1015 /// 1016 /// # Examples 1017 /// 1018 /// ``` 1019 /// use ylong_http_client::async_impl::ClientBuilder; 1020 /// 1021 /// let builder = ClientBuilder::new().tls_sni(true); 1022 /// ``` tls_sni(mut self, is_set_sni: bool) -> Self1023 pub fn tls_sni(mut self, is_set_sni: bool) -> Self { 1024 self.tls = self.tls.sni(is_set_sni); 1025 self 1026 } 1027 1028 /// Controls the use of TLS certs verifier. 1029 /// 1030 /// Defaults to `None` -- sets cert_verifier. 1031 /// 1032 /// # Example 1033 /// 1034 /// ``` 1035 /// use ylong_http_client::async_impl::ClientBuilder; 1036 /// use ylong_http_client::{CertVerifier, ServerCerts}; 1037 /// 1038 /// pub struct CallbackTest { 1039 /// inner: String, 1040 /// } 1041 /// 1042 /// impl CallbackTest { 1043 /// pub(crate) fn new() -> Self { 1044 /// Self { 1045 /// inner: "Test".to_string(), 1046 /// } 1047 /// } 1048 /// } 1049 /// 1050 /// impl CertVerifier for CallbackTest { 1051 /// fn verify(&self, certs: &ServerCerts) -> bool { 1052 /// true 1053 /// } 1054 /// } 1055 /// 1056 /// let verifier = CallbackTest::new(); 1057 /// let builder = ClientBuilder::new().cert_verifier(verifier); 1058 /// ``` cert_verifier<T: CertVerifier + Send + Sync + 'static>(mut self, verifier: T) -> Self1059 pub fn cert_verifier<T: CertVerifier + Send + Sync + 'static>(mut self, verifier: T) -> Self { 1060 use crate::util::config::tls::DefaultCertVerifier; 1061 1062 self.tls = self 1063 .tls 1064 .cert_verifier(Arc::new(DefaultCertVerifier::new(verifier))); 1065 self 1066 } 1067 } 1068 1069 impl Default for ClientBuilder { default() -> Self1070 fn default() -> Self { 1071 Self::new() 1072 } 1073 } 1074 1075 #[cfg(test)] 1076 mod ut_async_impl_client { 1077 #[cfg(feature = "ylong_base")] 1078 use ylong_runtime::io::AsyncWriteExt; 1079 1080 #[cfg(feature = "ylong_base")] 1081 use crate::async_impl::{Body, Request, Response}; 1082 use crate::async_impl::{Client, HttpConnector}; 1083 #[cfg(feature = "ylong_base")] 1084 use crate::util::test_utils::{format_header_str, TcpHandle}; 1085 #[cfg(feature = "ylong_base")] 1086 use crate::{build_client_request, start_tcp_server, Retry}; 1087 #[cfg(all(feature = "__tls", feature = "ylong_base"))] 1088 use crate::{CertVerifier, ServerCerts}; 1089 #[cfg(feature = "__tls")] 1090 use crate::{Certificate, TlsVersion}; 1091 use crate::{Proxy, Timeout}; 1092 1093 #[cfg(all(feature = "__tls", feature = "ylong_base"))] 1094 struct Verifier; 1095 1096 #[cfg(feature = "ylong_base")] client_request_redirect()1097 async fn client_request_redirect() { 1098 use std::sync::Arc; 1099 1100 use ylong_http::h1::ResponseDecoder; 1101 use ylong_http::response::Response as HttpResponse; 1102 1103 use crate::async_impl::{ClientBuilder, HttpBody}; 1104 use crate::util::interceptor::IdleInterceptor; 1105 use crate::util::normalizer::BodyLength; 1106 use crate::util::request::RequestArc; 1107 use crate::util::Redirect; 1108 1109 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(); 1110 let mut decoder = ResponseDecoder::new(); 1111 let result = decoder.decode(response_str).unwrap().unwrap(); 1112 1113 let box_stream = Box::new("hello world".as_bytes()); 1114 let content_bytes = ""; 1115 let until_close = HttpBody::new( 1116 Arc::new(IdleInterceptor), 1117 BodyLength::UntilClose, 1118 box_stream, 1119 content_bytes.as_bytes(), 1120 ) 1121 .unwrap(); 1122 let response = HttpResponse::from_raw_parts(result.0, until_close); 1123 let response = Response::new(response); 1124 let request = Request::builder() 1125 .url("http://example1.com:80/foo?a=1") 1126 .body(Body::slice("this is a body")) 1127 .unwrap(); 1128 let request = RequestArc::new(request); 1129 1130 let client = ClientBuilder::default() 1131 .redirect(Redirect::limited(2)) 1132 .connect_timeout(Timeout::from_secs(2)) 1133 .build() 1134 .unwrap(); 1135 let res = client.redirect(response, request.clone()).await; 1136 assert!(res.is_ok()) 1137 } 1138 1139 #[cfg(feature = "ylong_base")] client_request_version_1_0()1140 async fn client_request_version_1_0() { 1141 let request = Request::builder() 1142 .url("http://example1.com:80/foo?a=1") 1143 .method("CONNECT") 1144 .version("HTTP/1.0") 1145 .body(Body::empty()) 1146 .unwrap(); 1147 1148 let client = Client::builder().http1_only().build().unwrap(); 1149 let res = client.request(request).await; 1150 assert!(res 1151 .map_err(|e| { 1152 assert_eq!(format!("{e}"), "Request Error: Unknown METHOD in HTTP/1.0"); 1153 e 1154 }) 1155 .is_err()); 1156 } 1157 1158 #[cfg(all(feature = "__tls", feature = "ylong_base"))] 1159 impl CertVerifier for Verifier { verify(&self, certs: &ServerCerts) -> bool1160 fn verify(&self, certs: &ServerCerts) -> bool { 1161 // get version 1162 let _v = certs.version().unwrap(); 1163 // get issuer 1164 let _i = certs.issuer().unwrap(); 1165 // get name 1166 let _n = certs.cert_name().unwrap(); 1167 // cmp cert file 1168 let cert_pem = r#"-----BEGIN CERTIFICATE----- 1169 MIIDGzCCAgMCCQCHcfe97pgvpTANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB 1170 VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 1171 cyBQdHkgTHRkMB4XDTE2MDgxNDE3MDAwM1oXDTI2MDgxMjE3MDAwM1owWjELMAkG 1172 A1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0 1173 IFdpZGdpdHMgUHR5IEx0ZDETMBEGA1UEAwwKZm9vYmFyLmNvbTCCASIwDQYJKoZI 1174 hvcNAQEBBQADggEPADCCAQoCggEBAKj0JYxEsxejUIX+I5GH0Hg2G0kX/y1H0+Ub 1175 3mw2/Ja5BD/yN96/7zMSumXF8uS3SkmpyiJkbyD01TSRTqjlP7/VCBlyUIChlpLQ 1176 mrGaijZiT/VCyPXqmcwFzXS5IOTpX1olJfW8rA41U1LCIcDUyFf6LtZ/v8rSeKr6 1177 TuE6SGV4WRaBm1SrjWBeHVV866CRrtSS1ieT2asFsAyOZqWhk2fakwwBDFWDhOGI 1178 ubfO+5aq9cBJbNRlzsgB3UZs3gC0O6GzbnZ6oT0TiJMeTsXXjABLUlaq/rrqFF4Y 1179 euZkkbHTFBMz288PUc3m3ZTcpN+E7+ZOUBRZXKD20K07NugqCzUCAwEAATANBgkq 1180 hkiG9w0BAQsFAAOCAQEASvYHuIl5C0NHBELPpVHNuLbQsDQNKVj3a54+9q1JkiMM 1181 6taEJYfw7K1Xjm4RoiFSHpQBh+PWZS3hToToL2Zx8JfMR5MuAirdPAy1Sia/J/qE 1182 wQdJccqmvuLkLTSlsGbEJ/LUUgOAgrgHOZM5lUgIhCneA0/dWJ3PsN0zvn69/faY 1183 oo1iiolWiIHWWBUSdr3jM2AJaVAsTmLh00cKaDNk37JB940xConBGSl98JPrNrf9 1184 dUAiT0iIBngDBdHnn/yTj+InVEFyZSKrNtiDSObFHxPcxGteHNrCPJdP1e+GqkHp 1185 HJMRZVCQpSMzvHlofHSNgzWV1MX5h1CP4SGZdBDTfA== 1186 -----END CERTIFICATE-----"#; 1187 let _c = certs.cmp_pem_cert(cert_pem.as_bytes()).unwrap(); 1188 false 1189 } 1190 } 1191 1192 #[cfg(all(feature = "__tls", feature = "ylong_base"))] client_request_verify()1193 async fn client_request_verify() { 1194 // Creates a `async_impl::Client` 1195 let client = Client::builder() 1196 .cert_verifier(Verifier) 1197 .connect_timeout(Timeout::from_secs(10)) 1198 .build() 1199 .unwrap(); 1200 // Creates a `Request`. 1201 let request = Request::builder() 1202 .url("https://www.example.com") 1203 .body(Body::empty()) 1204 .unwrap(); 1205 // Sends request and receives a `Response`. 1206 let response = client.request(request).await; 1207 assert!(response.is_err()) 1208 } 1209 1210 /// UT test cases for `Client::builder`. 1211 /// 1212 /// # Brief 1213 /// 1. Creates a ClientBuilder by calling `Client::Builder`. 1214 /// 2. Calls `http_config`, `client_config`, `build` on the builder 1215 /// respectively. 1216 /// 3. Checks if the result is as expected. 1217 #[cfg(feature = "http1_1")] 1218 #[test] ut_client_builder()1219 fn ut_client_builder() { 1220 let builder = Client::builder().http1_only().build(); 1221 assert!(builder.is_ok()); 1222 let builder_proxy = Client::builder() 1223 .proxy(Proxy::http("http://www.example.com").build().unwrap()) 1224 .build(); 1225 assert!(builder_proxy.is_ok()); 1226 } 1227 1228 /// UT test cases for `Client::with_connector`. 1229 /// 1230 /// # Brief 1231 /// 1. Creates a Client by calling `Client::with_connector`. 1232 /// 2. Checks if the result is as expected. 1233 #[test] ut_client_with_connector()1234 fn ut_client_with_connector() { 1235 let client = Client::with_connector(HttpConnector::default()); 1236 assert_eq!(client.config.connect_timeout, Timeout::none()) 1237 } 1238 1239 /// UT test cases for `Client::new`. 1240 /// 1241 /// # Brief 1242 /// 1. Creates a Client by calling `Client::new`. 1243 /// 2. Checks if the result is as expected. 1244 #[test] ut_client_new()1245 fn ut_client_new() { 1246 let client = Client::new(); 1247 assert_eq!(client.config.connect_timeout, Timeout::none()) 1248 } 1249 1250 /// UT test cases for `Client::default`. 1251 /// 1252 /// # Brief 1253 /// 1. Creates a Client by calling `Client::default`. 1254 /// 2. Checks if the result is as expected. 1255 #[test] ut_client_default()1256 fn ut_client_default() { 1257 let client = Client::default(); 1258 assert_eq!(client.config.connect_timeout, Timeout::none()) 1259 } 1260 1261 /// UT test cases for `ClientBuilder::build`. 1262 /// 1263 /// # Brief 1264 /// 1. Creates a ClientBuilder by calling `Client::Builder`. 1265 /// 2. Checks if the result is as expected. 1266 #[cfg(feature = "__tls")] 1267 #[test] ut_client_build_tls()1268 fn ut_client_build_tls() { 1269 let client = Client::builder() 1270 .max_tls_version(TlsVersion::TLS_1_3) 1271 .min_tls_version(TlsVersion::TLS_1_0) 1272 .add_root_certificate(Certificate::from_pem(b"cert").unwrap()) 1273 .tls_ca_file("ca.crt") 1274 .tls_cipher_list( 1275 "DEFAULT:!aNULL:!eNULL:!MD5:!3DES:!DES:!RC4:!IDEA:!SEED:!aDSS:!SRP:!PSK", 1276 ) 1277 .tls_built_in_root_certs(false) 1278 .danger_accept_invalid_certs(false) 1279 .danger_accept_invalid_hostnames(false) 1280 .tls_sni(false) 1281 .build(); 1282 1283 assert!(client.is_err()); 1284 } 1285 1286 /// UT test cases for `ClientBuilder::build`. 1287 /// 1288 /// # Brief 1289 /// 1. Creates a ClientBuilder by calling `Client::Builder`. 1290 /// 2. Checks if the result is as expected. 1291 #[cfg(feature = "__tls")] 1292 #[test] ut_client_build_tls_pubkey_pinning()1293 fn ut_client_build_tls_pubkey_pinning() { 1294 use crate::PubKeyPins; 1295 1296 let client = Client::builder() 1297 .tls_built_in_root_certs(true) // not use root certs 1298 .danger_accept_invalid_certs(true) // not verify certs 1299 .max_tls_version(TlsVersion::TLS_1_2) 1300 .min_tls_version(TlsVersion::TLS_1_2) 1301 .add_public_key_pins( 1302 PubKeyPins::builder() 1303 .add( 1304 "https://7.249.243.101:6789", 1305 "sha256//VHQAbNl67nmkZJNESeTKvTxb5bQmd1maWnMKG/tjcAY=", 1306 ) 1307 .build() 1308 .unwrap(), 1309 ) 1310 .build(); 1311 assert!(client.is_ok()) 1312 } 1313 1314 /// UT test cases for `ClientBuilder::default`. 1315 /// 1316 /// # Brief 1317 /// 1. Creates a `ClientBuilder` by calling `ClientBuilder::default`. 1318 /// 2. Calls `http_config`, `client_config`, `tls_config` and `build` 1319 /// respectively. 1320 /// 3. Checks if the result is as expected. 1321 #[test] ut_client_builder_default()1322 fn ut_client_builder_default() { 1323 use crate::async_impl::ClientBuilder; 1324 use crate::util::{Redirect, Timeout}; 1325 1326 let builder = ClientBuilder::default() 1327 .redirect(Redirect::none()) 1328 .connect_timeout(Timeout::from_secs(9)) 1329 .build(); 1330 assert!(builder.is_ok()) 1331 } 1332 1333 /// UT test cases for `ClientBuilder::default`. 1334 /// 1335 /// # Brief 1336 /// 1. Creates a `ClientBuilder` by calling `ClientBuilder::default`. 1337 /// 2. Set redirect for client and call `Client::redirect_request`. 1338 /// 3. Checks if the result is as expected. 1339 #[cfg(feature = "ylong_base")] 1340 #[test] ut_client_request_redirect()1341 fn ut_client_request_redirect() { 1342 let handle = ylong_runtime::spawn(async move { 1343 client_request_redirect().await; 1344 }); 1345 ylong_runtime::block_on(handle).unwrap(); 1346 } 1347 1348 /// UT test cases for `Client::request`. 1349 /// 1350 /// # Brief 1351 /// 1. Creates a `Client` by calling `Client::builder()`. 1352 /// 2. Set version HTTP/1.0 for client and call `Client::request`. 1353 /// 3. Checks if the result is as expected. 1354 #[cfg(feature = "ylong_base")] 1355 #[test] ut_client_connect_http1_0()1356 fn ut_client_connect_http1_0() { 1357 let handle = ylong_runtime::spawn(async move { 1358 client_request_version_1_0().await; 1359 }); 1360 ylong_runtime::block_on(handle).unwrap(); 1361 } 1362 1363 /// UT test cases for retry of `Client::request`. 1364 /// 1365 /// # Brief 1366 /// 1. Creates a `Client` by calling `Client::builder()`. 1367 /// 2. Set version HTTP/1.0 for client and call `Client::request`. 1368 /// 3. Checks if the result is as expected. 1369 #[cfg(feature = "ylong_base")] 1370 #[test] ut_client_request_http1_0_retry()1371 fn ut_client_request_http1_0_retry() { 1372 let request = Request::builder() 1373 .url("http://example1.com:80/foo?a=1") 1374 .method("CONNECT") 1375 .version("HTTP/1.0") 1376 .body(Body::empty()) 1377 .unwrap(); 1378 1379 let retry_times = Retry::new(1).unwrap(); 1380 let client = Client::builder() 1381 .retry(retry_times) 1382 .http1_only() 1383 .build() 1384 .unwrap(); 1385 1386 let handle = ylong_runtime::spawn(async move { 1387 let res = client.request(request).await; 1388 assert!(res 1389 .map_err(|e| { 1390 assert_eq!(format!("{e}"), "Request Error: Unknown METHOD in HTTP/1.0"); 1391 e 1392 }) 1393 .is_err()); 1394 }); 1395 ylong_runtime::block_on(handle).unwrap(); 1396 } 1397 1398 /// UT test cases for certificate verify of `Client::request`. 1399 /// 1400 /// # Brief 1401 /// 1. Creates a `Client` by calling `Client::builder()`. 1402 /// 2. implement `CertVerifier` for struct `Verifier`. 1403 /// 3. Sets `CertVerifier` for this client. 1404 /// 4. Checks if the result is as expected. 1405 #[cfg(all(feature = "__tls", feature = "ylong_base"))] 1406 #[test] ut_client_request_verify()1407 fn ut_client_request_verify() { 1408 let handle = ylong_runtime::spawn(async move { 1409 client_request_verify().await; 1410 }); 1411 ylong_runtime::block_on(handle).unwrap(); 1412 } 1413 1414 /// UT test cases for certificate verify of `Client::send_request`. 1415 /// 1416 /// # Brief 1417 /// 1. Creates a `Client` by calling `Client::builder()`. 1418 /// 2. Sends a `Request` by `Client::send_request`. 1419 /// 4. Checks if the result is as expected. 1420 #[cfg(feature = "ylong_base")] 1421 #[test] ut_client_send_request()1422 fn ut_client_send_request() { 1423 let mut handles = vec![]; 1424 start_tcp_server!( 1425 Handles: handles, 1426 Response: { 1427 Status: 201, 1428 Version: "HTTP/1.1", 1429 Header: "Content-Length", "11", 1430 Body: "METHOD GET!", 1431 }, 1432 ); 1433 let handle = handles.pop().expect("No more handles !"); 1434 1435 let request = build_client_request!( 1436 Request: { 1437 Method: "GET", 1438 Path: "/data", 1439 Addr: handle.addr.as_str(), 1440 Header: "Content-Length", "5", 1441 Body: Body::slice("HELLO".as_bytes()), 1442 }, 1443 ); 1444 let client = Client::builder() 1445 .connect_timeout(Timeout::from_secs(2)) 1446 .max_h1_conn_number(10) 1447 .http1_only() 1448 .build() 1449 .unwrap(); 1450 1451 let handle = ylong_runtime::spawn(async move { 1452 let resp = client.request(request).await; 1453 assert!(resp.is_ok()); 1454 let body = resp.unwrap().text().await; 1455 assert!(body.is_ok()); 1456 handle 1457 .server_shutdown 1458 .recv() 1459 .expect("server send order failed !"); 1460 }); 1461 ylong_runtime::block_on(handle).unwrap(); 1462 } 1463 1464 /// UT test cases for retry of `Client::connect_to`. 1465 /// 1466 /// # Brief 1467 /// 1. Creates a `Client` by calling `Client::builder()`. 1468 /// 2. Sets connect timeout for this client. 1469 /// 3. Checks if the result is as expected. 1470 #[cfg(feature = "ylong_base")] 1471 #[test] ut_client_connect_to()1472 fn ut_client_connect_to() { 1473 let client = Client::builder() 1474 .connect_timeout(Timeout::from_secs(1)) 1475 .http1_only() 1476 .build() 1477 .unwrap(); 1478 1479 let request = build_client_request!( 1480 Request: { 1481 Path: "", 1482 Addr: "198.18.0.25:80", 1483 Body: Body::empty(), 1484 }, 1485 ); 1486 let handle = ylong_runtime::spawn(async move { 1487 let res = client.request(request).await; 1488 assert!(res.is_err()); 1489 }); 1490 ylong_runtime::block_on(handle).unwrap(); 1491 } 1492 1493 /// UT test cases for certificate verify of `Client::redirect`. 1494 /// 1495 /// # Brief 1496 /// 1. Creates a `Client` by calling `Client::builder()`. 1497 /// 2. Sends a `Request` by `Client::redirect`. 1498 /// 3. Checks if the result is as expected. 1499 #[cfg(feature = "ylong_base")] 1500 #[test] ut_client_redirect()1501 fn ut_client_redirect() { 1502 let mut handles = vec![]; 1503 start_tcp_server!( 1504 Handles: handles, 1505 Response: { 1506 Status: 302, 1507 Version: "HTTP/1.1", 1508 Header: "Content-Length", "11", 1509 Header: "Location", "http://ylong_http.com:80", 1510 Body: "METHOD GET!", 1511 }, 1512 ); 1513 let handle = handles.pop().expect("No more handles !"); 1514 1515 let request = build_client_request!( 1516 Request: { 1517 Method: "GET", 1518 Path: "/data", 1519 Addr: handle.addr.as_str(), 1520 Header: "Content-Length", "5", 1521 Body: Body::slice("HELLO".as_bytes()), 1522 }, 1523 ); 1524 let client = Client::builder() 1525 .request_timeout(Timeout::from_secs(2)) 1526 .http1_only() 1527 .build() 1528 .unwrap(); 1529 1530 let handle = ylong_runtime::spawn(async move { 1531 let resp = client.request(request).await; 1532 assert!(resp.is_err()); 1533 handle 1534 .server_shutdown 1535 .recv() 1536 .expect("server send order failed !"); 1537 }); 1538 ylong_runtime::block_on(handle).unwrap(); 1539 } 1540 1541 /// UT test cases for proxy of `Client::request`. 1542 /// 1543 /// # Brief 1544 /// 1. Creates a `Client` by calling `Client::builder()`. 1545 /// 2. Sends a `Request` by `Client::request`. 1546 /// 3. Checks if the result is as expected. 1547 #[cfg(feature = "ylong_base")] 1548 #[test] ut_client_http_proxy()1549 fn ut_client_http_proxy() { 1550 let mut handles = vec![]; 1551 start_tcp_server!( 1552 Handles: handles, 1553 Response: { 1554 Status: 201, 1555 Version: "HTTP/1.1", 1556 Header: "Content-Length", "11", 1557 Body: "METHOD GET!", 1558 }, 1559 ); 1560 let handle = handles.pop().expect("No more handles !"); 1561 1562 let request = build_client_request!( 1563 Request: { 1564 Method: "GET", 1565 Path: "/data", 1566 Addr: "ylong_http.com", 1567 Header: "Content-Length", "5", 1568 Body: Body::slice("HELLO".as_bytes()), 1569 }, 1570 ); 1571 let client = Client::builder() 1572 .proxy( 1573 Proxy::http(format!("http://{}{}", handle.addr.as_str(), "/data").as_str()) 1574 .build() 1575 .expect("Http proxy build failed"), 1576 ) 1577 .build() 1578 .expect("Client build failed!"); 1579 1580 let handle = ylong_runtime::spawn(async move { 1581 let resp = client.request(request).await; 1582 assert!(resp.is_ok()); 1583 handle 1584 .server_shutdown 1585 .recv() 1586 .expect("server send order failed !"); 1587 }); 1588 ylong_runtime::block_on(handle).unwrap(); 1589 } 1590 1591 /// UT test cases for sends chunk body of `Client::request`. 1592 /// 1593 /// # Brief 1594 /// 1. Creates a `Client` by calling `Client::builder()`. 1595 /// 2. Sends a `Request` by `Client::request`. 1596 /// 3. Checks if the result is as expected. 1597 #[cfg(feature = "ylong_base")] 1598 #[test] ut_client_send_trunk_body()1599 fn ut_client_send_trunk_body() { 1600 let mut handles = vec![]; 1601 start_tcp_server!( 1602 Handles: handles, 1603 Response: { 1604 Status: 201, 1605 Version: "HTTP/1.1", 1606 Header: "Content-Length", "11", 1607 Body: "METHOD GET!", 1608 }, 1609 ); 1610 let handle = handles.pop().expect("No more handles !"); 1611 1612 let request = build_client_request!( 1613 Request: { 1614 Method: "GET", 1615 Path: "/data", 1616 Addr: handle.addr.as_str(), 1617 Header: "Transfer-Encoding", "chunked", 1618 Body: Body::slice("aaaaa bbbbb ccccc ddddd".as_bytes()), 1619 }, 1620 ); 1621 let client = Client::builder().http1_only().build().unwrap(); 1622 1623 let handle = ylong_runtime::spawn(async move { 1624 let resp = client.request(request).await; 1625 assert!(resp.is_ok()); 1626 handle 1627 .server_shutdown 1628 .recv() 1629 .expect("server send order failed !"); 1630 }); 1631 ylong_runtime::block_on(handle).unwrap(); 1632 } 1633 1634 /// UT test cases for sends no headers request of `Client::request`. 1635 /// 1636 /// # Brief 1637 /// 1. Creates a `Client` by calling `Client::builder()`. 1638 /// 2. Sends a `Request` by `Client::request`. 1639 /// 3. Checks if the result is as expected. 1640 #[cfg(feature = "ylong_base")] 1641 #[test] ut_client_send_unknown_size()1642 fn ut_client_send_unknown_size() { 1643 let mut handles = vec![]; 1644 start_tcp_server!( 1645 Handles: handles, 1646 Response: { 1647 Status: 201, 1648 Version: "HTTP/1.1", 1649 Header: "Content-Length", "11", 1650 Body: "METHOD GET!", 1651 }, 1652 ); 1653 let handle = handles.pop().expect("No more handles !"); 1654 1655 let request = build_client_request!( 1656 Request: { 1657 Method: "GET", 1658 Path: "/data", 1659 Addr: handle.addr.as_str(), 1660 Body: Body::empty(), 1661 }, 1662 ); 1663 let client = Client::builder().http1_only().build().unwrap(); 1664 1665 let handle = ylong_runtime::spawn(async move { 1666 let resp = client.request(request).await; 1667 assert!(resp.is_ok()); 1668 handle 1669 .server_shutdown 1670 .recv() 1671 .expect("server send order failed !"); 1672 }); 1673 ylong_runtime::block_on(handle).unwrap(); 1674 } 1675 1676 /// UT test cases for receive `Connection` header response of 1677 /// `Client::request`. 1678 /// 1679 /// # Brief 1680 /// 1. Creates a `Client` by calling `Client::builder()`. 1681 /// 2. Sends a `Request` by `Client::request`. 1682 /// 3. Checks if the result is as expected. 1683 #[cfg(feature = "ylong_base")] 1684 #[test] ut_client_recv_conn_close()1685 fn ut_client_recv_conn_close() { 1686 let mut handles = vec![]; 1687 start_tcp_server!( 1688 Handles: handles, 1689 Response: { 1690 Status: 201, 1691 Version: "HTTP/1.1", 1692 Header: "Content-Length", "11", 1693 Header: "Connection", "close", 1694 Body: "METHOD GET!", 1695 }, 1696 ); 1697 let handle = handles.pop().expect("No more handles !"); 1698 1699 let request = build_client_request!( 1700 Request: { 1701 Method: "GET", 1702 Path: "/data", 1703 Addr: handle.addr.as_str(), 1704 Header: "Content-Length", "5", 1705 Body: Body::slice("HELLO".as_bytes()), 1706 }, 1707 ); 1708 let client = Client::builder().http1_only().build().unwrap(); 1709 1710 let handle = ylong_runtime::spawn(async move { 1711 let resp = client.request(request).await; 1712 assert!(resp.is_ok()); 1713 handle 1714 .server_shutdown 1715 .recv() 1716 .expect("server send order failed !"); 1717 }); 1718 ylong_runtime::block_on(handle).unwrap(); 1719 } 1720 1721 /// UT test cases for receive HTTP/1.0 response with invalid header of 1722 /// `Client::request`. 1723 /// 1724 /// # Brief 1725 /// 1. Creates a `Client` by calling `Client::builder()`. 1726 /// 2. Sends a `Request` by `Client::request`. 1727 /// 3. Checks if the result is as expected. 1728 #[cfg(feature = "ylong_base")] 1729 #[test] ut_client_recv_http1_0_resp()1730 fn ut_client_recv_http1_0_resp() { 1731 let mut handles = vec![]; 1732 start_tcp_server!( 1733 Handles: handles, 1734 Response: { 1735 Status: 201, 1736 Version: "HTTP/1.0", 1737 Header: "Content-Length", "11", 1738 Header: "Connection", "close", 1739 Body: "METHOD GET!", 1740 }, 1741 ); 1742 let handle = handles.pop().expect("No more handles !"); 1743 1744 let request = build_client_request!( 1745 Request: { 1746 Method: "GET", 1747 Version: "HTTP/1.0", 1748 Path: "/data", 1749 Addr: handle.addr.as_str(), 1750 Header: "Content-Length", "5", 1751 Body: Body::slice("HELLO".as_bytes()), 1752 }, 1753 ); 1754 let client = Client::builder().http1_only().build().unwrap(); 1755 1756 let handle = ylong_runtime::spawn(async move { 1757 let resp = client.request(request).await; 1758 assert!(resp.is_ok()); 1759 handle 1760 .server_shutdown 1761 .recv() 1762 .expect("server send order failed !"); 1763 }); 1764 ylong_runtime::block_on(handle).unwrap(); 1765 } 1766 1767 /// UT test cases for receive HTTP/1.0 response with transfer-encoding 1768 /// header of `Client::request`. 1769 /// 1770 /// # Brief 1771 /// 1. Creates a `Client` by calling `Client::builder()`. 1772 /// 2. Sends a `Request` by `Client::request`. 1773 /// 3. Checks if the result is as expected. 1774 #[cfg(feature = "ylong_base")] 1775 #[test] ut_client_recv_invalid_http1_0_resp()1776 fn ut_client_recv_invalid_http1_0_resp() { 1777 let mut handles = vec![]; 1778 start_tcp_server!( 1779 Handles: handles, 1780 Response: { 1781 Status: 201, 1782 Version: "HTTP/1.0", 1783 Header: "Transfer-Encoding", "chunked", 1784 Body: "0\r\n\r\n", 1785 }, 1786 ); 1787 let handle = handles.pop().expect("No more handles !"); 1788 1789 let request = build_client_request!( 1790 Request: { 1791 Method: "GET", 1792 Version: "HTTP/1.0", 1793 Path: "/data", 1794 Addr: handle.addr.as_str(), 1795 Header: "Content-Length", "5", 1796 Body: Body::slice("HELLO".as_bytes()), 1797 }, 1798 ); 1799 let client = Client::builder().http1_only().build().unwrap(); 1800 1801 let handle = ylong_runtime::spawn(async move { 1802 let resp = client.request(request).await; 1803 assert!(resp.is_err()); 1804 handle 1805 .server_shutdown 1806 .recv() 1807 .expect("server send order failed !"); 1808 }); 1809 ylong_runtime::block_on(handle).unwrap(); 1810 } 1811 1812 /// UT test cases for receive response when server is shutdown of 1813 /// `Client::request`. 1814 /// 1815 /// # Brief 1816 /// 1. Creates a `Client` by calling `Client::builder()`. 1817 /// 2. Sends a `Request` by `Client::request`. 1818 /// 3. Checks if the result is as expected. 1819 #[cfg(feature = "ylong_base")] 1820 #[test] ut_client_recv_when_server_shutdown()1821 fn ut_client_recv_when_server_shutdown() { 1822 let mut handles = vec![]; 1823 start_tcp_server!(Handles: handles, Shutdown: std::net::Shutdown::Both,); 1824 let handle = handles.pop().expect("No more handles !"); 1825 1826 let request = build_client_request!( 1827 Request: { 1828 Method: "GET", 1829 Path: "/data", 1830 Addr: handle.addr.as_str(), 1831 Header: "Content-Length", "5", 1832 Body: Body::slice("HELLO".as_bytes()), 1833 }, 1834 ); 1835 let client = Client::builder().http1_only().build().unwrap(); 1836 1837 let handle = ylong_runtime::spawn(async move { 1838 let resp = client.request(request).await; 1839 assert!(resp.is_err()); 1840 handle 1841 .server_shutdown 1842 .recv() 1843 .expect("server send order failed !"); 1844 }); 1845 ylong_runtime::block_on(handle).unwrap(); 1846 } 1847 1848 /// UT test cases for receive response status in error of `Client::request`. 1849 /// 1850 /// # Brief 1851 /// 1. Creates a `Client` by calling `Client::builder()`. 1852 /// 2. Sends a `Request` by `Client::request`. 1853 /// 3. Checks if the result is as expected. 1854 #[cfg(feature = "ylong_base")] 1855 #[test] ut_client_recv_error_resp_status()1856 fn ut_client_recv_error_resp_status() { 1857 let mut handles = vec![]; 1858 start_tcp_server!( 1859 Handles: handles, 1860 Response: { 1861 Status: 2023, 1862 Version: "HTTP/1.1", 1863 Header: "Content-Length", "11", 1864 Header: "Connection", "close", 1865 Body: "METHOD GET!", 1866 }, 1867 ); 1868 let handle = handles.pop().expect("No more handles !"); 1869 1870 let request = build_client_request!( 1871 Request: { 1872 Method: "GET", 1873 Path: "/data", 1874 Addr: handle.addr.as_str(), 1875 Header: "Content-Length", "5", 1876 Body: Body::slice("HELLO".as_bytes()), 1877 }, 1878 ); 1879 let client = Client::builder().http1_only().build().unwrap(); 1880 1881 let handle = ylong_runtime::spawn(async move { 1882 let resp = client.request(request).await; 1883 assert!(resp.is_err()); 1884 handle 1885 .server_shutdown 1886 .recv() 1887 .expect("server send order failed !"); 1888 }); 1889 ylong_runtime::block_on(handle).unwrap(); 1890 } 1891 } 1892