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