1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use anyhow::{Context, Error};
use async_trait::async_trait;
use remote_settings_client::client::net::{
Headers as RsHeaders, Method as RsMethod, Requester as RsRequester, Response as RsResponse,
Url as RsUrl,
};
use reqwest::{header::CONTENT_TYPE, Method, Response};
use std::time::Duration;
#[derive(Debug)]
pub struct ReqwestClient {
reqwest_client: reqwest::Client,
}
impl ReqwestClient {
pub fn try_new(
http_request_timeout: Duration,
http_connect_timeout: Duration,
) -> Result<ReqwestClient, Error> {
let reqwest_client = reqwest::Client::builder()
.pool_max_idle_per_host(0)
.connect_timeout(http_connect_timeout)
.timeout(http_request_timeout)
.build()?;
Ok(Self { reqwest_client })
}
}
#[async_trait]
impl RsRequester for ReqwestClient {
async fn get(&self, url: RsUrl) -> Result<RsResponse, ()> {
self.request_json(RsMethod::GET, url, vec![], RsHeaders::default())
.await
}
async fn request_json(
&self,
method: RsMethod,
url: RsUrl,
data: Vec<u8>,
headers: RsHeaders,
) -> Result<RsResponse, ()> {
let method = match method {
RsMethod::GET => Method::GET,
RsMethod::PATCH => Method::PATCH,
RsMethod::POST => Method::POST,
RsMethod::PUT => Method::PUT,
RsMethod::DELETE => Method::DELETE,
};
let headers = (&headers).try_into().map_err(|e| {
tracing::error!(
r#type = "adm.remote-settings.reqwest.headers-conversion-failed",
"ReqwestClient - unable to try_into headers. {:#?}",
e
);
})?;
match self
.reqwest_client
.request(method.clone(), url.clone())
.header(CONTENT_TYPE, "application/json")
.headers(headers)
.body(data)
.send()
.await
.and_then(Response::error_for_status)
.context(format!(
"Performing HTTP request for Remote Settings: {}",
url
)) {
Err(e) => {
tracing::error!(
r#type = "adm.remote-settings.reqwest.get-failed",
"ReqwestClient - unable to submit {} request. {:#?}",
method,
e
);
Err(())
}
Ok(response) => {
let status = response.status().as_u16();
let mut headers: RsHeaders = RsHeaders::new();
for h in response.headers() {
headers
.entry(h.0.to_string())
.or_insert_with(|| h.1.to_str().unwrap_or_default().to_string());
}
let body = response.bytes().await.map_err(|err| {
tracing::error!(
r#type = "adm.remote-settings.reqwest.parsing-failed",
"ReqwestClient - unable to parse response body. {:#?}",
err
);
})?;
Ok(RsResponse {
status,
body: body.to_vec(),
headers,
})
}
}
}
}