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