1 /* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 use crate::{ErrorKind, HttpClientError}; 17 use std::cmp; 18 use std::error::Error; 19 use std::fmt::{Debug, Display, Formatter}; 20 use std::time::Duration; 21 22 /// Timeout settings. 23 /// 24 /// # Examples 25 /// 26 /// ``` 27 /// # use ylong_http_client::Timeout; 28 /// 29 /// let timeout = Timeout::none(); 30 /// ``` 31 pub struct Timeout(Option<Duration>); 32 33 impl Timeout { 34 /// Creates a `Timeout` without limiting the timeout. 35 /// 36 /// # Examples 37 /// 38 /// ``` 39 /// # use ylong_http_client::Timeout; 40 /// 41 /// let timeout = Timeout::none(); 42 /// ``` none() -> Self43 pub fn none() -> Self { 44 Self(None) 45 } 46 47 /// Creates a `Timeout` from the specified number of seconds. 48 /// 49 /// # Examples 50 /// 51 /// ``` 52 /// # use ylong_http_client::Timeout; 53 /// 54 /// let timeout = Timeout::from_secs(9); 55 /// ``` from_secs(secs: u64) -> Self56 pub fn from_secs(secs: u64) -> Self { 57 Self(Some(Duration::from_secs(secs))) 58 } 59 inner(&self) -> Option<Duration>60 pub(crate) fn inner(&self) -> Option<Duration> { 61 self.0 62 } 63 } 64 65 /// Speed limit settings. 66 /// 67 /// # Examples 68 /// 69 /// ``` 70 /// # use ylong_http_client::SpeedLimit; 71 /// 72 /// let limit = SpeedLimit::none(); 73 /// ``` 74 pub struct SpeedLimit { 75 min: (u64, Duration), 76 max: u64, 77 } 78 79 impl SpeedLimit { 80 /// Creates a `SpeedLimit` without limiting the speed. 81 /// 82 /// # Examples 83 /// 84 /// ``` 85 /// # use ylong_http_client::SpeedLimit; 86 /// 87 /// let limit = SpeedLimit::none(); 88 /// ``` new() -> Self89 pub fn new() -> Self { 90 Self::none() 91 } 92 93 /// Sets the minimum speed and the seconds for which the current speed is 94 /// allowed to be less than this minimum speed. 95 /// 96 /// The unit of speed is bytes per second, and the unit of duration is seconds. 97 /// 98 /// The minimum speed cannot exceed the maximum speed that has been set. If 99 /// the set value exceeds the currently set maximum speed, the minimum speed 100 /// will be set to the current maximum speed. 101 /// 102 /// # Examples 103 /// 104 /// ``` 105 /// # use ylong_http_client::SpeedLimit; 106 /// 107 /// // Sets minimum speed is 1024B/s, the duration is 10s. 108 /// let limit = SpeedLimit::new().min_speed(1024, 10); 109 /// ``` min_speed(mut self, min: u64, duration: u64) -> Self110 pub fn min_speed(mut self, min: u64, duration: u64) -> Self { 111 self.min = (cmp::min(self.max, min), Duration::from_secs(duration)); 112 self 113 } 114 115 /// Sets the maximum speed. 116 /// 117 /// The unit of speed is bytes per second. 118 /// 119 /// The maximum speed cannot be lower than the minimum speed that has been 120 /// set. If the set value is lower than the currently set minimum speed, the 121 /// maximum speed will be set to the current minimum speed. 122 /// 123 /// # Examples 124 /// 125 /// ``` 126 /// # use ylong_http_client::SpeedLimit; 127 /// 128 /// let limit = SpeedLimit::new().max_speed(1024); 129 /// ``` max_speed(mut self, max: u64) -> Self130 pub fn max_speed(mut self, max: u64) -> Self { 131 self.max = cmp::max(self.min.0, max); 132 self 133 } 134 135 /// Creates a `SpeedLimit` without limiting the speed. 136 /// 137 /// # Examples 138 /// 139 /// ``` 140 /// # use ylong_http_client::SpeedLimit; 141 /// 142 /// let limit = SpeedLimit::none(); 143 /// ``` none() -> Self144 pub fn none() -> Self { 145 Self { 146 min: (0, Duration::MAX), 147 max: u64::MAX, 148 } 149 } 150 } 151 152 impl Default for SpeedLimit { default() -> Self153 fn default() -> Self { 154 Self::new() 155 } 156 } 157 158 /// Redirect settings. 159 /// 160 /// # Examples 161 /// 162 /// ``` 163 /// # use ylong_http_client::Redirect; 164 /// 165 /// let redirect = Redirect::none(); 166 /// ``` 167 #[derive(Default)] 168 pub struct Redirect(reqwest::redirect::Policy); 169 170 impl Redirect { 171 /// Creates a `Redirect` without redirection. 172 /// 173 /// # Examples 174 /// 175 /// ``` 176 /// # use ylong_http_client::Redirect; 177 /// 178 /// let redirect = Redirect::none(); 179 /// ``` none() -> Self180 pub fn none() -> Self { 181 Self(reqwest::redirect::Policy::none()) 182 } 183 184 /// Creates a `Redirect` from the specified times. 185 /// 186 /// # Examples 187 /// 188 /// ``` 189 /// # use ylong_http_client::Redirect; 190 /// 191 /// let redirect = Redirect::limited(10); 192 /// ``` limited(max: usize) -> Self193 pub fn limited(max: usize) -> Self { 194 Self(reqwest::redirect::Policy::limited(max)) 195 } 196 inner(self) -> reqwest::redirect::Policy197 pub(crate) fn inner(self) -> reqwest::redirect::Policy { 198 self.0 199 } 200 } 201 202 /// Proxy settings. 203 /// 204 /// # Examples 205 /// 206 /// ``` 207 /// # use ylong_http_client::Proxy; 208 /// 209 /// let proxy = Proxy::none(); 210 /// ``` 211 pub struct Proxy(Option<reqwest::Proxy>); 212 213 impl Proxy { 214 /// Creates a `Proxy` without any proxies. 215 /// 216 /// # Examples 217 /// 218 /// ``` 219 /// # use ylong_http_client::Proxy; 220 /// 221 /// let proxy = Proxy::none(); 222 /// ``` none() -> Self223 pub fn none() -> Self { 224 Self(None) 225 } 226 227 /// Creates a `ProxyBuilder`. This builder can help you construct a proxy 228 /// that proxy all HTTP traffic to the passed URL. 229 /// 230 /// # Examples 231 /// 232 /// ``` 233 /// # use ylong_http_client::Proxy; 234 /// 235 /// let proxy = Proxy::http("http://proxy.example.com"); 236 /// ``` http(url: &str) -> ProxyBuilder237 pub fn http(url: &str) -> ProxyBuilder { 238 ProxyBuilder( 239 reqwest::Proxy::http(url) 240 .map_err(|e| HttpClientError::new_with_cause(ErrorKind::Build, Some(e))), 241 ) 242 } 243 244 /// Creates a `ProxyBuilder`. This builder can help you construct a proxy 245 /// that proxy all HTTPS traffic to the passed URL. 246 /// 247 /// # Examples 248 /// 249 /// ``` 250 /// # use ylong_http_client::Proxy; 251 /// 252 /// let proxy = Proxy::https("https://proxy.example.com"); 253 /// ``` https(url: &str) -> ProxyBuilder254 pub fn https(url: &str) -> ProxyBuilder { 255 ProxyBuilder( 256 reqwest::Proxy::https(url) 257 .map_err(|e| HttpClientError::new_with_cause(ErrorKind::Build, Some(e))), 258 ) 259 } 260 261 /// Creates a `ProxyBuilder`. This builder can help you construct a proxy 262 /// that proxy **all** traffic to the passed URL. 263 /// 264 /// # Examples 265 /// 266 /// ``` 267 /// # use ylong_http_client::Proxy; 268 /// 269 /// let proxy = Proxy::all("http://proxy.example.com"); 270 /// ``` all(url: &str) -> ProxyBuilder271 pub fn all(url: &str) -> ProxyBuilder { 272 ProxyBuilder( 273 reqwest::Proxy::all(url) 274 .map_err(|e| HttpClientError::new_with_cause(ErrorKind::Build, Some(e))), 275 ) 276 } 277 inner(self) -> Option<reqwest::Proxy>278 pub(crate) fn inner(self) -> Option<reqwest::Proxy> { 279 self.0 280 } 281 } 282 283 /// A builder that constructs a `Proxy`. 284 /// 285 /// # Examples 286 /// 287 /// ``` 288 /// # use ylong_http_client::Proxy; 289 /// 290 /// let proxy = Proxy::all("http://proxy.example.com") 291 /// .basic_auth("Aladdin", "open sesame") 292 /// .build(); 293 /// ``` 294 pub struct ProxyBuilder(Result<reqwest::Proxy, HttpClientError>); 295 296 impl ProxyBuilder { 297 /// Sets the `Proxy-Authorization` header using Basic auth. 298 /// 299 /// # Examples 300 /// 301 /// ``` 302 /// # use ylong_http_client::Proxy; 303 /// 304 /// let builder = Proxy::all("http://proxy.example.com") 305 /// .basic_auth("Aladdin", "open sesame"); 306 /// ``` basic_auth(mut self, username: &str, password: &str) -> Self307 pub fn basic_auth(mut self, username: &str, password: &str) -> Self { 308 self.0 = self.0.map(|mut p| { 309 p = p.basic_auth(username, password); 310 p 311 }); 312 self 313 } 314 315 /// Constructs a `Proxy`. 316 /// 317 /// # Examples 318 /// 319 /// ``` 320 /// # use ylong_http_client::Proxy; 321 /// 322 /// let proxy = Proxy::all("http://proxy.example.com").build(); 323 /// ``` build(self) -> Result<Proxy, HttpClientError>324 pub fn build(self) -> Result<Proxy, HttpClientError> { 325 Ok(Proxy(Some(self.0?))) 326 } 327 } 328 329 /// Represents a server X509 certificates. 330 /// 331 /// You can use `from_pem` to parse a `&[u8]` into a list of certificates. 332 /// 333 /// # Examples 334 /// 335 /// ``` 336 /// use ylong_http_client::Certificate; 337 /// 338 /// fn from_pem(pem: &[u8]) { 339 /// let certs = Certificate::from_pem(pem); 340 /// } 341 /// ``` 342 pub struct Certificate { 343 inner: Vec<reqwest::Certificate>, 344 } 345 346 impl Certificate { 347 /// Creates a `Certificate` from a PEM encoded certificate. 348 /// 349 /// Return `InvalidCertificate` if we cannot parse the given slice. 350 /// 351 /// # Examples 352 /// 353 /// ```no_run 354 /// # use ylong_http_client::Certificate; 355 /// 356 /// # fn cert() { 357 /// let file = std::fs::read("./cert.pem").unwrap(); 358 /// let cert = reqwest::Certificate::from_pem(&file); 359 /// # } 360 /// ``` from_pem(pem: &[u8]) -> Result<Certificate, HttpClientError>361 pub fn from_pem(pem: &[u8]) -> Result<Certificate, HttpClientError> { 362 const CERT_BEGIN: &str = "-----BEGIN CERTIFICATE-----"; 363 const CERT_END: &str = "-----END CERTIFICATE-----"; 364 365 let mut inner = Vec::new(); 366 let str = std::str::from_utf8(pem).map_err(|_| { 367 HttpClientError::new_with_cause(ErrorKind::Build, Some(InvalidCertificate)) 368 })?; 369 let mut pos = 0; 370 while pos < str.len() { 371 let st = match str[pos..].find(CERT_BEGIN) { 372 Some(size) => size, 373 None => break, 374 }; 375 376 let ed = match str[pos + st..].find(CERT_END) { 377 Some(size) => size, 378 None => break, 379 }; 380 381 let slice = str[pos + st..pos + st + ed + CERT_END.len()].as_bytes(); 382 let cert = reqwest::Certificate::from_pem(slice) 383 .map_err(|e| HttpClientError::new_with_cause(ErrorKind::Build, Some(e)))?; 384 inner.push(cert); 385 pos += st + ed + CERT_END.len(); 386 } 387 388 if inner.is_empty() { 389 return Err(HttpClientError::new_with_cause( 390 ErrorKind::Build, 391 Some(InvalidCertificate), 392 )); 393 } 394 395 Ok(Self { inner }) 396 } 397 into_inner(self) -> Vec<reqwest::Certificate>398 pub(crate) fn into_inner(self) -> Vec<reqwest::Certificate> { 399 self.inner 400 } 401 } 402 403 struct InvalidCertificate; 404 405 impl Debug for InvalidCertificate { fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result406 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 407 f.debug_struct("InvalidCertificate").finish() 408 } 409 } 410 411 impl Display for InvalidCertificate { fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result412 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 413 f.write_str("InvalidCertificate") 414 } 415 } 416 417 impl Error for InvalidCertificate {} 418