1use crate::{AverList, Header, HttpResponse};
2
3pub fn get(url: &str) -> Result<HttpResponse, String> {
4 simple_request("GET", url)
5}
6
7pub fn head(url: &str) -> Result<HttpResponse, String> {
8 simple_request("HEAD", url)
9}
10
11pub fn delete(url: &str) -> Result<HttpResponse, String> {
12 simple_request("DELETE", url)
13}
14
15pub fn post(
16 url: &str,
17 body: &str,
18 content_type: &str,
19 headers: &AverList<Header>,
20) -> Result<HttpResponse, String> {
21 body_request("POST", url, body, content_type, headers)
22}
23
24pub fn put(
25 url: &str,
26 body: &str,
27 content_type: &str,
28 headers: &AverList<Header>,
29) -> Result<HttpResponse, String> {
30 body_request("PUT", url, body, content_type, headers)
31}
32
33pub fn patch(
34 url: &str,
35 body: &str,
36 content_type: &str,
37 headers: &AverList<Header>,
38) -> Result<HttpResponse, String> {
39 body_request("PATCH", url, body, content_type, headers)
40}
41
42fn simple_request(method: &str, url: &str) -> Result<HttpResponse, String> {
43 let result = ureq::request(method, url)
44 .timeout(std::time::Duration::from_secs(10))
45 .call();
46 response_value(result)
47}
48
49fn body_request(
50 method: &str,
51 url: &str,
52 body: &str,
53 content_type: &str,
54 headers: &AverList<Header>,
55) -> Result<HttpResponse, String> {
56 let mut req = ureq::request(method, url)
57 .timeout(std::time::Duration::from_secs(10))
58 .set("Content-Type", content_type);
59 for h in headers {
60 req = req.set(&h.name, &h.value);
61 }
62 response_value(req.send_string(body))
63}
64
65fn response_value(result: Result<ureq::Response, ureq::Error>) -> Result<HttpResponse, String> {
66 match result {
67 Ok(resp) => build_response(resp),
68 Err(ureq::Error::Status(_, resp)) => build_response(resp),
69 Err(ureq::Error::Transport(e)) => Err(e.to_string()),
70 }
71}
72
73fn build_response(resp: ureq::Response) -> Result<HttpResponse, String> {
74 use std::io::Read;
75
76 const BODY_LIMIT: u64 = 10 * 1024 * 1024;
77
78 let status = resp.status() as i64;
79 let header_names = resp.headers_names();
80 let headers: Vec<Header> = header_names
81 .iter()
82 .map(|name| Header {
83 name: name.clone(),
84 value: resp.header(name).unwrap_or("").to_string(),
85 })
86 .collect();
87
88 let mut buf = Vec::new();
89 let bytes_read = resp
90 .into_reader()
91 .take(BODY_LIMIT + 1)
92 .read_to_end(&mut buf)
93 .map_err(|e| format!("Http: failed to read response body: {}", e))?;
94 if bytes_read as u64 > BODY_LIMIT {
95 return Err("Http: response body exceeds 10 MB limit".to_string());
96 }
97 let body = String::from_utf8_lossy(&buf).into_owned();
98 Ok(HttpResponse {
99 status,
100 body,
101 headers: AverList::from_vec(headers),
102 })
103}