linode_api_proxy/http_handlers/
fallback_handler.rs1use core::{future::Future, pin::Pin};
2
3use axum::{
4 body::Body,
5 handler::Handler,
6 http::{
7 uri::{Builder as UriBuilder, Parts as UriParts},
8 Request, StatusCode,
9 },
10 response::{IntoResponse as _, Json, Response},
11};
12use linode_api::types::Version;
13
14use crate::context::LinodeApiHttpClient;
15
16#[derive(Debug, Clone)]
18#[non_exhaustive]
19pub struct FallbackHandler {
20 pub linode_api_http_client: LinodeApiHttpClient,
21 pub version: Version,
22}
23
24impl FallbackHandler {
25 pub fn new(linode_api_http_client: LinodeApiHttpClient, version: Version) -> Self {
26 Self {
27 linode_api_http_client,
28 version,
29 }
30 }
31}
32
33impl<T, S> Handler<T, S, Body> for FallbackHandler {
34 type Future = Pin<Box<dyn Future<Output = Response> + Send + 'static>>;
35
36 fn call(self, mut req: Request<Body>, _state: S) -> Self::Future {
37 let req_uri_path = req.uri().path();
38 let req_uri_query = req.uri().query();
39
40 let base_uri = match self.version {
42 Version::V4 => {
43 use linode_api::endpoints::v4::BASE_URI;
44
45 BASE_URI.to_owned()
46 }
47 };
48
49 let req_uri = {
50 let UriParts {
51 scheme,
52 authority,
53 path_and_query,
54 ..
55 } = base_uri.into_parts();
56
57 let mut path_and_query_str = path_and_query
58 .map(|x| x.path().to_owned())
59 .unwrap_or_default();
60
61 if !req_uri_path.starts_with('/') {
62 path_and_query_str.push('/');
63 }
64 path_and_query_str.push_str(req_uri_path);
65
66 if let Some(req_uri_query) = req_uri_query {
67 path_and_query_str.push('?');
68 path_and_query_str.push_str(req_uri_query)
69 }
70
71 let uri_builder = UriBuilder::new();
72 let uri_builder = if let Some(scheme) = scheme {
73 uri_builder.scheme(scheme)
74 } else {
75 uri_builder
76 };
77 let uri_builder = if let Some(authority) = authority {
78 uri_builder.authority(authority)
79 } else {
80 uri_builder
81 };
82 let uri_builder = uri_builder.path_and_query(path_and_query_str);
83
84 match uri_builder.build() {
85 Ok(x) => x,
86 Err(err) => {
87 return Box::pin(async move {
88 let mut resp = match self.version {
89 Version::V4 => {
90 use linode_api::{
91 endpoints::v4::ErrorResponseBody,
92 objects::v4::{Error, ErrorReason},
93 };
94
95 Json(ErrorResponseBody {
96 errors: vec![Error {
97 field: None,
98 reason: ErrorReason::Other(format!(
99 "request uri change failed, err:{err}"
100 )),
101 }],
102 })
103 .into_response()
104 }
105 };
106
107 *resp.status_mut() = StatusCode::from_u16(599).expect("Never");
108 resp
109 })
110 }
111 }
112 };
113
114 *req.uri_mut() = req_uri;
115
116 Box::pin(async move {
117 match axum_request_send::impl_reqwest::send(self.linode_api_http_client.inner(), req)
118 .await
119 {
120 Ok(resp) => resp,
121 Err(err) => match self.version {
122 Version::V4 => {
123 use linode_api::{
124 endpoints::v4::ErrorResponseBody,
125 objects::v4::{Error, ErrorReason},
126 };
127
128 let mut resp = Json(ErrorResponseBody {
129 errors: vec![Error {
130 field: None,
131 reason: ErrorReason::Other(format!("respond failed, err:{err}")),
132 }],
133 })
134 .into_response();
135
136 *resp.status_mut() = StatusCode::from_u16(599).expect("Never");
137 resp
138 }
139 },
140 }
141 })
142 }
143}