sfo_http/
http_util.rs

1#![allow(unused)]
2
3mod json {
4    pub use json::*;
5}
6
7pub use reqwest::*;
8use std::collections::HashMap;
9use std::fmt::{Debug, Formatter};
10use std::net::SocketAddr;
11use std::sync::Arc;
12use std::time::Duration;
13use ::json::JsonValue;
14use serde::{Deserialize, Serialize};
15use crate::errors::{HttpError, ErrorCode, HttpResult};
16use reqwest::dns::Resolve;
17use reqwest::header::{CONTENT_TYPE, HeaderMap, HeaderName, HeaderValue};
18
19pub async fn http_post_request(url: &str, param: Vec<u8>, content_type: Option<&str>) -> HttpResult<(Vec<u8>, Option<String>)> {
20    let mut request_builder = reqwest::Client::builder().no_proxy().build().unwrap().post(url);
21    if content_type.is_some() {
22        request_builder = request_builder.header(CONTENT_TYPE, content_type.unwrap());
23    }
24    // req.set_body(param);
25    let mut resp = request_builder.body(param).send().await.map_err(|err| {
26        let msg = format!("http connect error! host={}, err={}", url, err);
27        log::error!("{}", msg.as_str());
28        HttpError::new(ErrorCode::ConnectFailed, msg)
29    })?;
30
31    let header = resp.headers().get(CONTENT_TYPE);
32    let header = if header.is_some() {
33        Some(header.unwrap().to_str().map_err(|err| {
34            let msg = format!("invalid content-type {}", err);
35            log::error!("{}", msg.as_str());
36            HttpError::new(ErrorCode::InvalidParam, msg)
37        })?.to_string())
38    } else {
39        None
40    };
41    let data = resp.bytes().await.map_err(|err| {
42        let msg = format!("recv body error! err={}", err);
43        log::error!("{}", msg.as_str());
44        HttpError::new(ErrorCode::InvalidData, msg)
45    })?;
46    Ok((data.to_vec(), header))
47}
48
49pub async fn http_post_request2<T: for<'de> Deserialize<'de>>(url: &str, param: Vec<u8>, content_type: Option<&str>) -> HttpResult<T> {
50    let mut request_builder = reqwest::Client::builder().no_proxy().build().unwrap().post(url);
51    if content_type.is_some() {
52        request_builder = request_builder.header(CONTENT_TYPE, content_type.unwrap());
53    }
54    // req.set_body(param);
55    let mut resp = request_builder.body(param).send().await.map_err(|err| {
56        let msg = format!("http connect error! host={}, err={}", url, err);
57        log::error!("{}", msg.as_str());
58        HttpError::new(ErrorCode::ConnectFailed, msg)
59    })?;
60
61    let data = resp.json().await.map_err(|err| {
62        let msg = format!("recv body error! err={}", err);
63        log::error!("{}", msg.as_str());
64        HttpError::new(ErrorCode::InvalidData, msg)
65    })?;
66    Ok(data)
67}
68
69pub async fn http_post_request3<T: for<'de> Deserialize<'de>, P: Serialize>(url: &str, param: &P) -> HttpResult<T> {
70    let mut resp = reqwest::Client::builder().no_proxy().build().unwrap().post(url).json(param).send().await.map_err(|err| {
71        let msg = format!("http connect error! host={}, err={}", url, err);
72        log::error!("{}", msg.as_str());
73        HttpError::new(ErrorCode::ConnectFailed, msg)
74    })?;
75
76    resp.json().await.map_err(|err| {
77        let msg = format!("recv error! err={}", err);
78        log::error!("{}", msg.as_str());
79        HttpError::new(ErrorCode::InvalidData, msg)
80    })
81}
82
83pub async fn http_get_request2<T: for<'de> Deserialize<'de>>(url: &str) -> HttpResult<T> {
84    let resp = reqwest::Client::builder().no_proxy().build().unwrap().get(url).send().await.map_err(|err| {
85        let msg = format!("http connect error! host={}, err={}", url, err);
86        log::error!("{}", msg.as_str());
87        HttpError::new(ErrorCode::ConnectFailed, msg)
88    })?;
89
90    resp.json().await.map_err(|err| {
91        let msg = format!("recv error! err={}", err);
92        log::error!("{}", msg.as_str());
93        HttpError::new(ErrorCode::InvalidData, msg)
94    })
95}
96
97
98pub async fn http_get_request(url: &str) -> HttpResult<(Vec<u8>, Option<String>)> {
99    let resp = reqwest::Client::builder().no_proxy().build().unwrap().get(url).send().await.map_err(|err| {
100        let msg = format!("http connect error! host={}, err={}", url, err);
101        log::error!("{}", msg.as_str());
102        HttpError::new(ErrorCode::ConnectFailed, msg)
103    })?;
104
105    let header = resp.headers().get(CONTENT_TYPE);
106    let header = if header.is_some() {
107        Some(header.unwrap().to_str().map_err(|err| {
108            let msg = format!("invalid content-type {}", err);
109            log::error!("{}", msg.as_str());
110            HttpError::new(ErrorCode::InvalidParam, msg)
111        })?.to_string())
112    } else {
113        None
114    };
115    let data = resp.bytes().await.map_err(|err| {
116        let msg = format!("recv body error! err={}", err);
117        log::error!("{}", msg.as_str());
118        HttpError::new(ErrorCode::InvalidData, msg)
119    })?;
120    Ok((data.to_vec(), header))
121}
122
123pub async fn http_get_request3(url: &str) -> HttpResult<Response> {
124    reqwest::Client::builder().no_proxy().build().unwrap().get(url).send().await.map_err(|err| {
125        let msg = format!("http connect error! host={}, err={}", url, err);
126        log::error!("{}", msg.as_str());
127        HttpError::new(ErrorCode::ConnectFailed, msg)
128    })
129}
130
131pub async fn http_request(req: Request) -> HttpResult<Response> {
132    let url = req.url().to_string();
133    reqwest::Client::builder().no_proxy().build().unwrap().execute(req).await.map_err(|err| {
134        let msg = format!("http connect error! url={} err={}", url, err);
135        log::error!("{}", msg.as_str());
136        HttpError::new(ErrorCode::ConnectFailed, msg)
137    })
138}
139
140pub async fn http_post_json(url: &str, param: JsonValue) -> HttpResult<JsonValue> {
141    let resp = reqwest::Client::builder().no_proxy().build().unwrap()
142        .post(url)
143        .header(CONTENT_TYPE, "application/json")
144        .body(param.to_string())
145        .send().await.map_err(|err| {
146        let msg = format!("http connect error! url={} err={}", url, err);
147        log::error!("{}", msg.as_str());
148        HttpError::new(ErrorCode::ConnectFailed, msg)
149    })?;
150
151    let resp_str = resp.text().await.map_err(|err| {
152        let msg = format!("recv error! err={}", err);
153        log::error!("{}", msg.as_str());
154        HttpError::new(ErrorCode::InvalidData, msg)
155    })?;
156    json::parse(resp_str.as_str()).map_err(|err| {
157        let msg = format!("parse {} error! err={}", resp_str.as_str(), err);
158        log::error!("{}", msg.as_str());
159        HttpError::new(ErrorCode::InvalidData, msg)
160    })
161}
162
163
164pub async fn http_post_json2<T: for<'de> Deserialize<'de>>(url: &str, param: JsonValue) -> HttpResult<T> {
165    let resp = reqwest::Client::builder().no_proxy().build().unwrap().post(url)
166        .header(CONTENT_TYPE, "application/json")
167        .body(param.to_string())
168        .send().await.map_err(|err| {
169        let msg = format!("http connect error! url={} err={}", url, err);
170        log::error!("{}", msg.as_str());
171        HttpError::new(ErrorCode::ConnectFailed, msg)
172    })?;
173
174    resp.json().await.map_err(|err| {
175        let msg = format!("recv error! err={}", err);
176        log::error!("{}", msg.as_str());
177        HttpError::new(ErrorCode::InvalidData, msg)
178    })
179}
180
181#[derive(Clone)]
182pub struct HttpClient {
183    client: reqwest::Client,
184    base_url: Option<String>,
185}
186
187impl Debug for HttpClient {
188    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
189        write!(f, "HttpClient")
190    }
191}
192
193impl HttpClient {
194    pub fn new(max_connections: usize, base_url: Option<&str>) -> Self {
195        let client = reqwest::ClientBuilder::new()
196            .connect_timeout(Duration::from_secs(30))
197            .http2_keep_alive_while_idle(true)
198            .pool_max_idle_per_host(max_connections)
199            .no_proxy()
200            .build().unwrap();
201
202        let base_url = if base_url.is_some() {
203            let base_url = base_url.unwrap();
204            let base_url = if base_url.ends_with("/") {
205                base_url.to_string()
206            } else {
207                format!("{}/", base_url)
208            };
209            Some(base_url)
210        } else {
211            base_url.map(|v| v.to_string())
212        };
213
214        Self {
215            client,
216            base_url,
217        }
218    }
219
220    pub fn new_with_no_cert_verify(max_connections: usize, base_url: Option<&str>) -> Self {
221        let client = reqwest::ClientBuilder::new()
222            .connect_timeout(Duration::from_secs(30))
223            .http2_keep_alive_while_idle(true)
224            .use_rustls_tls()
225            .pool_max_idle_per_host(max_connections)
226            .danger_accept_invalid_certs(true)
227            .no_proxy()
228            .build().unwrap();
229
230        let base_url = if base_url.is_some() {
231            let base_url = base_url.unwrap();
232            let base_url = if base_url.ends_with("/") {
233                base_url.to_string()
234            } else {
235                format!("{}/", base_url)
236            };
237            Some(base_url)
238        } else {
239            base_url.map(|v| v.to_string())
240        };
241
242        Self {
243            client,
244            base_url,
245        }
246    }
247
248    fn get_url(&self, uri: &str) -> String {
249        if self.base_url.is_some() {
250            let base_url = self.base_url.as_ref().unwrap().as_str();
251            if base_url.ends_with("/") {
252                if uri.starts_with("/") {
253                    format!("{}{}", base_url, &uri[1..])
254                } else {
255                    format!("{}{}", base_url, uri)
256                }
257            } else {
258                if uri.starts_with("/") {
259                    format!("{}{}", base_url, uri)
260                } else {
261                    format!("{}/{}", base_url, uri)
262                }
263            }
264        } else {
265            uri.to_string()
266        }
267    }
268
269    pub async fn get_json<T: for<'de> Deserialize<'de>>(&self, uri: &str) -> HttpResult<T> {
270        let mut resp = self.client.get(self.get_url(uri).as_str()).send().await.map_err(|err| {
271            let msg = format!("http connect error! url={}, err={}", self.get_url(uri), err);
272            log::error!("{}", msg.as_str());
273            HttpError::new(ErrorCode::ConnectFailed, msg)
274        })?;
275
276        resp.json().await.map_err(|err| {
277            let msg = format!("recv error! err={}", err);
278            log::error!("{}", msg.as_str());
279            HttpError::new(ErrorCode::InvalidData, msg)
280        })
281    }
282
283    pub async fn get(&self, uri: &str) -> HttpResult<(Vec<u8>, Option<String>)> {
284        let mut resp = self.client.get(self.get_url(uri).as_str()).send().await.map_err(|err| {
285            let msg = format!("http connect error! url={}, err={}", self.get_url(uri), err);
286            log::error!("{}", msg.as_str());
287            HttpError::new(ErrorCode::ConnectFailed, msg)
288        })?;
289
290        let header = resp.headers().get(CONTENT_TYPE);
291        let header = if header.is_some() {
292            Some(header.unwrap().to_str().map_err(|err| {
293                let msg = format!("invalid content-type {}", err);
294                log::error!("{}", msg.as_str());
295                HttpError::new(ErrorCode::InvalidParam, msg)
296            })?.to_string())
297        } else {
298            None
299        };
300        let data = resp.bytes().await.map_err(|err| {
301            let msg = format!("recv body error! err={}", err);
302            log::error!("{}", msg.as_str());
303            HttpError::new(ErrorCode::InvalidData, msg)
304        })?;
305        Ok((data.to_vec(), header))
306    }
307
308    pub async fn post_json<T: for<'de> Deserialize<'de>, P: Serialize>(&self, uri: &str, param: &P) -> HttpResult<T> {
309        let mut resp = self.client.post(self.get_url(uri)).json(param).send().await.map_err(|err| {
310            let msg = format!("http connect error! url={}, err={}", self.get_url(uri), err);
311            log::error!("{}", msg.as_str());
312            HttpError::new(ErrorCode::ConnectFailed, msg)
313        })?;
314
315        resp.json().await.map_err(|err| {
316            let msg = format!("recv error! err={}", err);
317            log::error!("{}", msg.as_str());
318            HttpError::new(ErrorCode::InvalidData, msg)
319        })
320    }
321
322    pub async fn post(&self, uri: &str, param: Vec<u8>, content_type: Option<&str>) -> HttpResult<(Vec<u8>, Option<String>)> {
323        let mut request_builder = self.client.post(self.get_url(uri));
324        if content_type.is_some() {
325            request_builder = request_builder.header(CONTENT_TYPE, content_type.unwrap());
326        }
327        // req.set_body(param);
328        let mut resp = request_builder.body(param).send().await.map_err(|err| {
329            let msg = format!("http connect error! host={}, err={}", self.get_url(uri), err);
330            log::error!("{}", msg.as_str());
331            HttpError::new(ErrorCode::ConnectFailed, msg)
332        })?;
333
334        let header = resp.headers().get(CONTENT_TYPE);
335        let header = if header.is_some() {
336            Some(header.unwrap().to_str().map_err(|err| {
337                let msg = format!("invalid content-type {}", err);
338                log::error!("{}", msg.as_str());
339                HttpError::new(ErrorCode::InvalidParam, msg)
340            })?.to_string())
341        } else {
342            None
343        };
344
345        let data = resp.bytes().await.map_err(|err| {
346            let msg = format!("recv body error! err={}", err);
347            log::error!("{}", msg.as_str());
348            HttpError::new(ErrorCode::InvalidData, msg)
349        })?;
350        Ok((data.to_vec(), header))
351    }
352
353    pub async fn execute(&self, req: Request) -> HttpResult<Response> {
354        let url = req.url().to_string();
355        self.client.execute(req).await.map_err(|err| {
356            let msg = format!("http connect error! url={} err={}", url, err);
357            log::error!("{}", msg.as_str());
358            HttpError::new(ErrorCode::ConnectFailed, msg)
359        })
360    }
361}
362
363pub struct HttpClientBuilder {
364    base_url: Option<String>,
365    builder: ClientBuilder,
366    headers: HeaderMap,
367}
368
369impl Default for HttpClientBuilder {
370    fn default() -> Self {
371        Self {
372            base_url: None,
373            builder: ClientBuilder::new(),
374            headers: Default::default(),
375        }
376    }
377}
378
379impl HttpClientBuilder {
380    pub fn set_base_url(mut self, base_url: &str) -> Self {
381        let base_url = if base_url.ends_with("/") {
382            base_url.to_string()
383        } else {
384            format!("{}/", base_url)
385        };
386        self.base_url = Some(base_url);
387        self
388    }
389    pub fn add_header(
390        mut self,
391        name: impl Into<HeaderName>,
392        value: impl Into<HeaderValue>,
393    ) -> HttpResult<Self> {
394        self.headers
395            .insert(name.into(), value.into());
396        Ok(self)
397    }
398
399    pub fn set_http_keep_alive(mut self, keep_alive: bool) -> Self {
400        self.builder = self.builder.http2_keep_alive_while_idle(keep_alive);
401        self
402    }
403
404    pub fn set_tcp_no_delay(mut self, no_delay: bool) -> Self {
405        self.builder = self.builder.tcp_nodelay(no_delay);
406        self
407    }
408
409    pub fn set_timeout(mut self, timeout: Duration) -> Self {
410        self.builder = self.builder.connect_timeout(timeout);
411        self
412    }
413
414    pub fn set_max_connections_per_host(mut self, max_connections_per_host: usize) -> Self {
415        self.builder = self.builder.pool_max_idle_per_host(max_connections_per_host);
416        self
417    }
418
419    pub fn set_verify_tls(mut self, verify_tls: bool) -> Self {
420        self.builder = self.builder.danger_accept_invalid_certs(!verify_tls);
421        self
422    }
423
424    pub fn set_auto_sys_proxy(mut self, proxy: bool) -> Self {
425        if !proxy {
426            self.builder = self.builder.no_proxy();
427        }
428        self
429    }
430
431    pub fn add_root_certificate(mut self, cert: Certificate) -> Self {
432        self.builder = self.builder.add_root_certificate(cert);
433        self
434    }
435
436    pub fn tls_built_in_root_certs(mut self, tls_built_in_root_certs: bool) -> Self {
437        self.builder = self.builder.tls_built_in_root_certs(tls_built_in_root_certs);
438        self
439    }
440
441    pub fn identity(mut self, identity: Identity) -> Self {
442        self.builder = self.builder.identity(identity);
443        self
444    }
445
446    pub fn tls_sni(mut self, tls_sni: bool) -> Self {
447        self.builder = self.builder.tls_sni(tls_sni);
448        self
449    }
450
451    pub fn min_tls_version(mut self, version: tls::Version) -> Self {
452        self.builder = self.builder.min_tls_version(version);
453        self
454    }
455
456    pub fn max_tls_version(mut self, version: tls::Version) -> Self {
457        self.builder = self.builder.max_tls_version(version);
458        self
459    }
460
461    pub fn https_only(mut self, enabled: bool) -> Self {
462        self.builder = self.builder.https_only(enabled);
463        self
464    }
465
466    pub fn resolve(mut self, domain: &str, addr: SocketAddr) -> Self {
467        self.builder = self.builder.resolve(domain, addr);
468        self
469    }
470
471    pub fn resolve_to_addrs(mut self, domain: &str, addrs: &[SocketAddr]) -> Self {
472        self.builder = self.builder.resolve_to_addrs(domain, addrs);
473        self
474    }
475
476    pub fn dns_resolver<R: Resolve + 'static>(mut self, resolver: Arc<R>) -> Self {
477        self.builder = self.builder.dns_resolver(resolver);
478        self
479    }
480
481    pub fn proxy(mut self, proxy: Proxy) -> Self {
482        self.builder = self.builder.proxy(proxy);
483        self
484    }
485
486    pub fn build(mut self) -> HttpClient {
487        let mut config = self.builder.default_headers(self.headers);
488
489        HttpClient {
490            client: config.build().unwrap(),
491            base_url: self.base_url,
492        }
493    }
494}