openid_client/
http_client.rs

1//! Default Http Client
2
3use std::time::Duration;
4
5use reqwest::{
6    header::{CONTENT_TYPE, WWW_AUTHENTICATE},
7    ClientBuilder, Method, Response,
8};
9
10use crate::types::http_client::{HttpMethod, HttpRequest, HttpResponse, OidcHttpClient};
11
12/// The default HttpClient
13pub struct DefaultHttpClient;
14
15impl DefaultHttpClient {
16    async fn to_response(response: Response) -> HttpResponse {
17        let status_code = response.status().as_u16();
18        let response_headers = response.headers().clone();
19
20        let mut content_type = None;
21
22        if let Some(Ok(ct)) = response_headers
23            .get(CONTENT_TYPE)
24            .map(|ct| ct.to_str().map(|s| s.to_string()))
25        {
26            content_type = Some(ct);
27        };
28
29        let mut www_authenticate = None;
30
31        if let Some(Ok(www)) = response_headers
32            .get(WWW_AUTHENTICATE)
33            .map(|www| www.to_str().map(|s| s.to_string()))
34        {
35            www_authenticate = Some(www);
36        };
37
38        let mut dpop_nonce = None;
39
40        if let Some(Ok(dn)) = response_headers
41            .get("dpop-nonce")
42            .map(|dn| dn.to_str().map(|s| s.to_string()))
43        {
44            dpop_nonce = Some(dn);
45        };
46
47        let body_result = response.text().await;
48        let mut body: Option<String> = None;
49        if let Ok(body_string) = body_result {
50            if !body_string.is_empty() {
51                body = Some(body_string);
52            }
53        }
54
55        HttpResponse {
56            body,
57            status_code,
58            content_type,
59            www_authenticate,
60            dpop_nonce,
61        }
62    }
63}
64
65impl OidcHttpClient for DefaultHttpClient {
66    async fn request(&self, req: HttpRequest) -> Result<HttpResponse, String> {
67        let client = ClientBuilder::new()
68            .connect_timeout(Duration::from_secs(10))
69            .build()
70            .map_err(|e| format!("{e}"))?;
71
72        let method = match req.method {
73            HttpMethod::GET => Method::GET,
74            HttpMethod::POST => Method::POST,
75            HttpMethod::PUT => Method::PUT,
76            HttpMethod::PATCH => Method::PATCH,
77            HttpMethod::DELETE => Method::DELETE,
78            HttpMethod::HEAD => Method::HEAD,
79            HttpMethod::OPTIONS => Method::OPTIONS,
80            HttpMethod::TRACE => Method::TRACE,
81            HttpMethod::CONNECT => Method::CONNECT,
82        };
83
84        let mut req_builder = client.request(method, req.url);
85
86        if let Some(body) = req.body {
87            req_builder = req_builder.body(body);
88        }
89
90        for (name, values) in req.headers {
91            for value in values {
92                req_builder = req_builder.header(name.clone(), value);
93            }
94        }
95
96        req_builder = req_builder.header(
97            "User-Agent",
98            "openid-client (https://github.com/sathyajithps/openid-client)",
99        );
100
101        match req_builder.send().await {
102            Ok(res) => Ok(Self::to_response(res).await),
103            Err(e) => Err(format!("{e}")),
104        }
105    }
106}