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