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 core::cmp; 15 use core::time::Duration; 16 17 use crate::error::HttpClientError; 18 use crate::util::{proxy, redirect}; 19 20 /// Redirects settings of requests. 21 /// 22 /// # Example 23 /// 24 /// ``` 25 /// use ylong_http_client::Redirect; 26 /// 27 /// // The default maximum number of redirects is 10. 28 /// let redirect = Redirect::default(); 29 /// 30 /// // No redirect. 31 /// let no_redirect = Redirect::none(); 32 /// 33 /// // Custom the number of redirects. 34 /// let max = Redirect::limited(10); 35 /// ``` 36 #[derive(Clone, Debug, Eq, PartialEq, Default)] 37 pub struct Redirect(redirect::Redirect); 38 39 impl Redirect { 40 /// Sets max number of redirects. 41 /// 42 /// # Examples 43 /// 44 /// ``` 45 /// # use ylong_http_client::Redirect; 46 /// 47 /// let redirect = Redirect::limited(10); 48 /// ``` limited(max: usize) -> Self49 pub fn limited(max: usize) -> Self { 50 Self(redirect::Redirect::limited(max)) 51 } 52 53 /// Sets unlimited number of redirects. 54 /// 55 /// # Examples 56 /// 57 /// ``` 58 /// # use ylong_http_client::Redirect; 59 /// 60 /// let redirect = Redirect::no_limit(); 61 /// ``` no_limit() -> Self62 pub fn no_limit() -> Self { 63 Self(redirect::Redirect::limited(usize::MAX)) 64 } 65 66 /// Stops redirects. 67 /// 68 /// # Examples 69 /// 70 /// ``` 71 /// # use ylong_http_client::Redirect; 72 /// 73 /// let redirect = Redirect::none(); 74 /// ``` none() -> Self75 pub fn none() -> Self { 76 Self(redirect::Redirect::none()) 77 } 78 inner(&self) -> &redirect::Redirect79 pub(crate) fn inner(&self) -> &redirect::Redirect { 80 &self.0 81 } 82 } 83 84 /// Retries settings of requests. The default value is `Retry::NEVER`. 85 /// 86 /// # Example 87 /// 88 /// ``` 89 /// use ylong_http_client::Retry; 90 /// 91 /// // Never retry. 92 /// let never = Retry::none(); 93 /// 94 /// // The maximum number of redirects is 3. 95 /// let max = Retry::max(); 96 /// 97 /// // Custom the number of retries. 98 /// let custom = Retry::new(2).unwrap(); 99 /// ``` 100 #[derive(Clone, Debug, Eq, PartialEq)] 101 pub struct Retry(Option<usize>); 102 103 impl Retry { 104 const MAX_RETRIES: usize = 3; 105 106 /// Customizes the number of retries. Returns `Err` if `times` is greater 107 /// than 3. 108 /// 109 /// # Examples 110 /// 111 /// ``` 112 /// use ylong_http_client::Retry; 113 /// 114 /// assert!(Retry::new(1).is_ok()); 115 /// assert!(Retry::new(10).is_err()); 116 /// ``` new(times: usize) -> Result<Self, HttpClientError>117 pub fn new(times: usize) -> Result<Self, HttpClientError> { 118 if times >= Self::MAX_RETRIES { 119 return err_from_msg!(Build, "Invalid params"); 120 } 121 Ok(Self(Some(times))) 122 } 123 124 /// Creates a `Retry` that indicates never retry. 125 /// 126 /// # Examples 127 /// 128 /// ``` 129 /// use ylong_http_client::Retry; 130 /// 131 /// let retry = Retry::none(); 132 /// ``` none() -> Self133 pub fn none() -> Self { 134 Self(None) 135 } 136 137 /// Creates a `Retry` with a max retry times. 138 /// 139 /// The maximum number of redirects is 3. 140 /// 141 /// # Examples 142 /// 143 /// ``` 144 /// use ylong_http_client::Retry; 145 /// 146 /// let retry = Retry::max(); 147 /// ``` max() -> Self148 pub fn max() -> Self { 149 Self(Some(Self::MAX_RETRIES)) 150 } 151 152 /// Get the retry times, returns None if not set. 153 /// 154 /// # Examples 155 /// 156 /// ``` 157 /// use ylong_http_client::Retry; 158 /// 159 /// assert!(Retry::default().times().is_none()); 160 /// ``` times(&self) -> Option<usize>161 pub fn times(&self) -> Option<usize> { 162 self.0 163 } 164 } 165 166 impl Default for Retry { default() -> Self167 fn default() -> Self { 168 Self::none() 169 } 170 } 171 172 /// Timeout settings. 173 /// 174 /// # Examples 175 /// 176 /// ``` 177 /// use ylong_http_client::Timeout; 178 /// 179 /// let timeout = Timeout::none(); 180 /// ``` 181 #[derive(Clone, Debug, Eq, PartialEq)] 182 pub struct Timeout(Option<Duration>); 183 184 impl Timeout { 185 /// Creates a `Timeout` without limiting the timeout. 186 /// 187 /// # Examples 188 /// 189 /// ``` 190 /// use ylong_http_client::Timeout; 191 /// 192 /// let timeout = Timeout::none(); 193 /// ``` none() -> Self194 pub fn none() -> Self { 195 Self(None) 196 } 197 198 /// Creates a new `Timeout` from the specified number of whole seconds. 199 /// 200 /// # Examples 201 /// 202 /// ``` 203 /// use ylong_http_client::Timeout; 204 /// 205 /// let timeout = Timeout::from_secs(9); 206 /// ``` from_secs(secs: u64) -> Self207 pub fn from_secs(secs: u64) -> Self { 208 Self(Some(Duration::from_secs(secs))) 209 } 210 inner(&self) -> Option<Duration>211 pub(crate) fn inner(&self) -> Option<Duration> { 212 self.0 213 } 214 } 215 216 impl Default for Timeout { default() -> Self217 fn default() -> Self { 218 Self::none() 219 } 220 } 221 222 /// Speed limit settings. 223 /// 224 /// # Examples 225 /// 226 /// ``` 227 /// use ylong_http_client::SpeedLimit; 228 /// 229 /// let limit = SpeedLimit::new(); 230 /// ``` 231 pub struct SpeedLimit { 232 min: (u64, Duration), 233 max: u64, 234 } 235 236 impl SpeedLimit { 237 /// Creates a new `SpeedLimit`. 238 /// 239 /// # Examples 240 /// 241 /// ``` 242 /// use ylong_http_client::SpeedLimit; 243 /// 244 /// let limit = SpeedLimit::new(); 245 /// ``` new() -> Self246 pub fn new() -> Self { 247 Self::none() 248 } 249 250 /// Sets the minimum speed and the seconds for which the current speed is 251 /// allowed to be less than this minimum speed. 252 /// 253 /// The unit of speed is bytes per second, and the unit of duration is 254 /// seconds. 255 /// 256 /// The minimum speed cannot exceed the maximum speed that has been set. If 257 /// the set value exceeds the currently set maximum speed, the minimum speed 258 /// will be set to the current maximum speed. 259 /// 260 /// # Examples 261 /// 262 /// ``` 263 /// use ylong_http_client::SpeedLimit; 264 /// 265 /// // Sets minimum speed is 1024B/s, the duration is 10s. 266 /// let limit = SpeedLimit::new().min_speed(1024, 10); 267 /// ``` min_speed(mut self, min: u64, secs: u64) -> Self268 pub fn min_speed(mut self, min: u64, secs: u64) -> Self { 269 self.min = (cmp::min(self.max, min), Duration::from_secs(secs)); 270 self 271 } 272 273 /// Sets the maximum speed. 274 /// 275 /// The unit of speed is bytes per second. 276 /// 277 /// The maximum speed cannot be lower than the minimum speed that has been 278 /// set. If the set value is lower than the currently set minimum speed, the 279 /// maximum speed will be set to the current minimum speed. 280 /// 281 /// # Examples 282 /// 283 /// ``` 284 /// use ylong_http_client::SpeedLimit; 285 /// 286 /// let limit = SpeedLimit::new().max_speed(1024); 287 /// ``` max_speed(mut self, max: u64) -> Self288 pub fn max_speed(mut self, max: u64) -> Self { 289 self.max = cmp::max(self.min.0, max); 290 self 291 } 292 293 /// Creates a `SpeedLimit` without limiting the speed. 294 /// 295 /// # Examples 296 /// 297 /// ``` 298 /// use ylong_http_client::SpeedLimit; 299 /// 300 /// let limit = SpeedLimit::none(); 301 /// ``` none() -> Self302 pub fn none() -> Self { 303 Self { 304 min: (0, Duration::MAX), 305 max: u64::MAX, 306 } 307 } 308 } 309 310 impl Default for SpeedLimit { default() -> Self311 fn default() -> Self { 312 Self::new() 313 } 314 } 315 316 /// Proxy settings. 317 /// 318 /// `Proxy` has functions which is below: 319 /// 320 /// - replace origin uri by proxy uri to link proxy server. 321 /// - set username and password to login proxy server. 322 /// - set no proxy which can keep origin uri not to be replaced by proxy uri. 323 /// 324 /// # Examples 325 /// 326 /// ``` 327 /// # use ylong_http_client::Proxy; 328 /// 329 /// // All http request will be intercepted by `https://www.example.com`, 330 /// // but https request will link to server directly. 331 /// let proxy = Proxy::http("http://www.example.com").build(); 332 /// 333 /// // All https request will be intercepted by `http://www.example.com`, 334 /// // but http request will link to server directly. 335 /// let proxy = Proxy::https("http://www.example.com").build(); 336 /// 337 /// // All https and http request will be intercepted by "http://www.example.com". 338 /// let proxy = Proxy::all("http://www.example.com").build(); 339 /// ``` 340 #[derive(Clone)] 341 pub struct Proxy(proxy::Proxy); 342 343 impl Proxy { 344 /// Passes all HTTP and HTTPS to the proxy URL. 345 /// 346 /// # Examples 347 /// 348 /// ``` 349 /// use ylong_http_client::Proxy; 350 /// 351 /// // All https and http request will be intercepted by `http://example.com`. 352 /// let builder = Proxy::all("http://example.com"); 353 /// ``` all(addr: &str) -> ProxyBuilder354 pub fn all(addr: &str) -> ProxyBuilder { 355 ProxyBuilder { 356 inner: proxy::Proxy::all(addr), 357 } 358 } 359 360 /// Passes HTTP to the proxy URL. 361 /// 362 /// # Examples 363 /// 364 /// ``` 365 /// use ylong_http_client::Proxy; 366 /// 367 /// // All http request will be intercepted by https://example.com, 368 /// // but https request will link to server directly. 369 /// let proxy = Proxy::http("https://example.com"); 370 /// ``` http(addr: &str) -> ProxyBuilder371 pub fn http(addr: &str) -> ProxyBuilder { 372 ProxyBuilder { 373 inner: proxy::Proxy::http(addr), 374 } 375 } 376 377 /// Passes HTTPS to the proxy URL. 378 /// 379 /// # Examples 380 /// 381 /// ``` 382 /// use ylong_http_client::Proxy; 383 /// 384 /// // All https request will be intercepted by http://example.com, 385 /// // but http request will link to server directly. 386 /// let proxy = Proxy::https("http://example.com"); 387 /// ``` https(addr: &str) -> ProxyBuilder388 pub fn https(addr: &str) -> ProxyBuilder { 389 ProxyBuilder { 390 inner: proxy::Proxy::https(addr), 391 } 392 } 393 inner(self) -> proxy::Proxy394 pub(crate) fn inner(self) -> proxy::Proxy { 395 self.0 396 } 397 } 398 399 /// A builder that constructs a `Proxy`. 400 /// 401 /// # Examples 402 /// 403 /// ``` 404 /// use ylong_http_client::Proxy; 405 /// 406 /// let proxy = Proxy::all("http://www.example.com") 407 /// .basic_auth("Aladdin", "open sesame") 408 /// .build(); 409 /// ``` 410 pub struct ProxyBuilder { 411 inner: Result<proxy::Proxy, HttpClientError>, 412 } 413 414 impl ProxyBuilder { 415 /// Pass HTTPS to the proxy URL, but the https uri which is in the no proxy 416 /// list, will not pass the proxy URL. 417 /// 418 /// # Examples 419 /// 420 /// ``` 421 /// use ylong_http_client::Proxy; 422 /// 423 /// let builder = Proxy::https("http://example.com").no_proxy("https://example2.com"); 424 /// ``` no_proxy(mut self, no_proxy: &str) -> Self425 pub fn no_proxy(mut self, no_proxy: &str) -> Self { 426 self.inner = self.inner.map(|mut proxy| { 427 proxy.no_proxy(no_proxy); 428 proxy 429 }); 430 self 431 } 432 433 /// Pass HTTPS to the proxy URL, and set username and password which is 434 /// required by the proxy server. 435 /// 436 /// # Examples 437 /// 438 /// ``` 439 /// use ylong_http_client::Proxy; 440 /// 441 /// let builder = Proxy::https("http://example.com").basic_auth("username", "password"); 442 /// ``` basic_auth(mut self, username: &str, password: &str) -> Self443 pub fn basic_auth(mut self, username: &str, password: &str) -> Self { 444 self.inner = self.inner.map(|mut proxy| { 445 proxy.basic_auth(username, password); 446 proxy 447 }); 448 self 449 } 450 451 /// Constructs a `Proxy`. 452 /// 453 /// # Examples 454 /// 455 /// ``` 456 /// use ylong_http_client::Proxy; 457 /// 458 /// let proxy = Proxy::all("http://proxy.example.com").build(); 459 /// ``` build(self) -> Result<Proxy, HttpClientError>460 pub fn build(self) -> Result<Proxy, HttpClientError> { 461 Ok(Proxy(self.inner?)) 462 } 463 } 464 465 #[cfg(test)] 466 mod ut_settings { 467 use std::time::Duration; 468 469 use ylong_http::request::uri::Uri; 470 471 use crate::{Proxy, Redirect, Retry, SpeedLimit, Timeout}; 472 473 /// UT test cases for `Retry::new`. 474 /// 475 /// # Brief 476 /// 1. Creates a `Retry` by calling `Retry::new`. 477 /// 2. Checks if the results are correct. 478 #[test] ut_retry_new()479 fn ut_retry_new() { 480 let retry = Retry::new(1); 481 assert!(retry.is_ok()); 482 let retry = Retry::new(3); 483 assert!(retry.is_err()); 484 let retry = Retry::new(10); 485 assert!(retry.is_err()); 486 } 487 488 /// UT test cases for `Redirect::default`. 489 /// 490 /// # Brief 491 /// 1. Creates a `Redirect` by calling `Redirect::default`. 492 /// 2. Creates a 10 Redirect. 493 /// 3. Checks if the results are correct. 494 #[test] 495 #[allow(clippy::redundant_clone)] ut_redirect_clone()496 fn ut_redirect_clone() { 497 let redirect = Redirect::default(); 498 let redirect_10 = Redirect::limited(10); 499 assert_eq!(redirect, redirect_10); 500 assert_eq!(redirect.clone(), redirect_10) 501 } 502 503 /// UT test cases for `Retry::clone`. 504 /// 505 /// # Brief 506 /// 1. Creates a `Retry` by calling `Redirect::new`. 507 /// 2. Creates another `Retry` by `Redirect::clone`. 508 /// 3. Checks if the results are correct. 509 #[test] ut_retry_clone()510 fn ut_retry_clone() { 511 let retry = Retry::new(1).unwrap(); 512 assert_eq!(retry.clone(), retry) 513 } 514 515 /// UT test cases for `Retry::default`. 516 /// 517 /// # Brief 518 /// 1. Creates a `Retry` by calling `Redirect::default`. 519 /// 2. Checks if the results are correct. 520 #[test] ut_retry_default()521 fn ut_retry_default() { 522 let retry = Retry::default(); 523 assert_eq!(retry, Retry::none()) 524 } 525 526 /// UT test cases for `Retry::max`. 527 /// 528 /// # Brief 529 /// 1. Creates a `Retry` by calling `Redirect::max`. 530 /// 2. Checks if the results are correct. 531 #[test] ut_retry_max()532 fn ut_retry_max() { 533 let retry = Retry::max(); 534 assert_eq!(retry.times(), Some(3)) 535 } 536 537 /// UT test cases for `Timeout::clone`. 538 /// 539 /// # Brief 540 /// 1. Creates a `Timeout` by calling `Timeout::from_secs`. 541 /// 2. Creates another `Timeout` by `Timeout::clone`. 542 /// 3. Checks if the results are correct. 543 #[test] ut_timeout_clone()544 fn ut_timeout_clone() { 545 let timeout = Timeout::from_secs(5); 546 assert_eq!(timeout.clone(), timeout) 547 } 548 549 /// UT test cases for `Timeout::default`. 550 /// 551 /// # Brief 552 /// 1. Creates a `Timeout` by calling `Timeout::default`. 553 /// 2. Checks if the results are correct. 554 #[test] ut_timeout_default()555 fn ut_timeout_default() { 556 let timeout = Timeout::default(); 557 assert_eq!(timeout, Timeout::none()) 558 } 559 560 /// UT test cases for `SpeedLimit::default`. 561 /// 562 /// # Brief 563 /// 1. Creates a `SpeedLimit` by calling `SpeedLimit::default`. 564 /// 2. Checks if the results are correct. 565 #[test] ut_speed_limit_default()566 fn ut_speed_limit_default() { 567 let speed = SpeedLimit::new(); 568 assert_eq!(speed.max, SpeedLimit::default().max) 569 } 570 571 /// UT test cases for `SpeedLimit::min_speed`. 572 /// 573 /// # Brief 574 /// 1. Creates a `SpeedLimit` by calling `SpeedLimit::new`. 575 /// 2. Sets the max speed of `SpeedLimit`. 576 /// 3. Sets a min speed value that is greater than the max speed value. 577 /// 4. Checks if the results are correct. 578 #[test] ut_speed_limit_min_speed()579 fn ut_speed_limit_min_speed() { 580 let speed = SpeedLimit::new(); 581 let speed = speed.max_speed(1024); 582 let speed = speed.min_speed(2048, 12); 583 assert_eq!(speed.min, (1024, Duration::from_secs(12))) 584 } 585 586 /// UT test cases for `Proxy::clone`. 587 /// 588 /// # Brief 589 /// 1. Creates a `Proxy` by calling `Proxy::all`. 590 /// 2. Creates another `Proxy` by `Timeout::clone`. 591 /// 3. Checks if the results are correct. 592 #[test] ut_proxy_clone()593 fn ut_proxy_clone() { 594 let proxy = Proxy::all("http://127.0.0.1:6789") 595 .no_proxy("127.0.0.1") 596 .basic_auth("user", "password") 597 .build() 598 .unwrap(); 599 let proxy_clone = proxy.clone(); 600 let uri = Uri::from_bytes(b"http://127.0.0.1:3456").unwrap(); 601 assert!(!proxy.inner().is_intercepted(&uri)); 602 assert!(!proxy_clone.inner().is_intercepted(&uri)); 603 } 604 605 /// UT test cases for `Proxy::https`. 606 /// 607 /// # Brief 608 /// 1. Creates a `Proxy` by calling `Proxy::https`. 609 /// 2. Checks if the results are correct. 610 #[test] ut_proxy_https()611 fn ut_proxy_https() { 612 let proxy = Proxy::https("http://127.0.0.1:6789").build().unwrap(); 613 let uri = Uri::from_bytes(b"https://127.0.0.1:3456").unwrap(); 614 assert!(proxy.inner().is_intercepted(&uri)); 615 } 616 } 617