azure_identity/
oauth2_http_client.rs
1use azure_core::{
5 error::{Error, ErrorKind, ResultExt},
6 HttpClient, Request,
7};
8use std::{collections::HashMap, str::FromStr, sync::Arc};
9use tracing::warn;
10
11pub(crate) struct Oauth2HttpClient {
12 http_client: Arc<dyn HttpClient>,
13}
14
15impl Oauth2HttpClient {
16 pub fn new(http_client: Arc<dyn HttpClient>) -> Self {
18 Self { http_client }
19 }
20
21 pub(crate) async fn request(
22 &self,
23 oauth2_request: oauth2::HttpRequest,
24 ) -> Result<oauth2::HttpResponse, azure_core::error::Error> {
25 let method = try_from_method(&oauth2_request.method)?;
26 let mut request = Request::new(oauth2_request.url, method);
27 for (name, value) in to_headers(&oauth2_request.headers) {
28 request.insert_header(name, value);
29 }
30 request.set_body(oauth2_request.body);
31 let response = self.http_client.execute_request(&request).await?;
32 let status_code = try_from_status(response.status())?;
33 let headers = try_from_headers(response.headers())?;
34 let body = response.into_body().collect().await?.to_vec();
35 Ok(oauth2::HttpResponse {
36 status_code,
37 headers,
38 body,
39 })
40 }
41}
42
43fn try_from_method(method: &oauth2::http::Method) -> azure_core::Result<azure_core::Method> {
44 match *method {
45 oauth2::http::Method::GET => Ok(azure_core::Method::Get),
46 oauth2::http::Method::POST => Ok(azure_core::Method::Post),
47 oauth2::http::Method::PUT => Ok(azure_core::Method::Put),
48 oauth2::http::Method::DELETE => Ok(azure_core::Method::Delete),
49 oauth2::http::Method::HEAD => Ok(azure_core::Method::Head),
50 oauth2::http::Method::OPTIONS => Ok(azure_core::Method::Options),
51 oauth2::http::Method::CONNECT => Ok(azure_core::Method::Connect),
52 oauth2::http::Method::PATCH => Ok(azure_core::Method::Patch),
53 oauth2::http::Method::TRACE => Ok(azure_core::Method::Trace),
54 _ => Err(Error::with_message(ErrorKind::DataConversion, || {
55 format!("unsupported oauth2::http::Method {method}")
56 })),
57 }
58}
59
60fn try_from_headers(
61 headers: &azure_core::headers::Headers,
62) -> azure_core::Result<oauth2::http::HeaderMap> {
63 let mut header_map = oauth2::http::HeaderMap::new();
64 for (name, value) in headers.iter() {
65 let name = name.as_str();
66 let header_name = oauth2::http::header::HeaderName::from_str(name)
67 .with_context(ErrorKind::DataConversion, || {
68 format!("unable to convert http header name '{name}'")
69 })?;
70 let value = value.as_str().to_owned();
71 header_map.append(
72 header_name,
73 oauth2::http::HeaderValue::from_str(&value)
74 .with_context(ErrorKind::DataConversion, || {
75 format!("unable to convert http header value for '{name}'")
76 })?,
77 );
78 }
79 Ok(header_map)
80}
81
82fn try_from_status(status: azure_core::StatusCode) -> azure_core::Result<oauth2::http::StatusCode> {
83 oauth2::http::StatusCode::from_u16(status as u16).map_kind(ErrorKind::DataConversion)
84}
85
86fn to_headers(map: &oauth2::http::header::HeaderMap) -> azure_core::headers::Headers {
87 let map = map
88 .iter()
89 .filter_map(|(k, v)| {
90 let key = k.as_str();
91 if let Ok(value) = v.to_str() {
92 Some((
93 azure_core::headers::HeaderName::from(key.to_owned()),
94 azure_core::headers::HeaderValue::from(value.to_owned()),
95 ))
96 } else {
97 warn!("header value for `{key}` is not utf8");
98 None
99 }
100 })
101 .collect::<HashMap<_, _>>();
102 azure_core::headers::Headers::from(map)
103}