redfish_axum/
serial_interface.rs1pub struct DefaultPrivileges;
5impl redfish_core::privilege::OperationPrivilegeMapping for DefaultPrivileges {
6 type Get = redfish_core::privilege::Login;
7 type Head = redfish_core::privilege::Login;
8 type Post = redfish_core::privilege::ConfigureManager;
9 type Put = redfish_core::privilege::ConfigureManager;
10 type Patch = redfish_core::privilege::ConfigureManager;
11 type Delete = redfish_core::privilege::ConfigureManager;
12}
13
14pub struct SerialInterface<S, P>
19where
20 S: Clone,
21{
22 router: axum::routing::MethodRouter<S>,
23 privilege_marker: std::marker::PhantomData<fn() -> P>,
24 allowed_methods: Vec<axum::http::method::Method>,
25}
26
27impl<S> Default for SerialInterface<S, DefaultPrivileges>
28where
29 S: Clone,
30{
31 fn default() -> Self {
32 Self {
33 router: Default::default(),
34 privilege_marker: Default::default(),
35 allowed_methods: Vec::new(),
36 }
37 }
38}
39
40impl<S, P> SerialInterface<S, P>
41where
42 S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
43 P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
44 <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
45 <P as redfish_core::privilege::OperationPrivilegeMapping>::Put: Send,
46 <P as redfish_core::privilege::OperationPrivilegeMapping>::Patch: Send,
47{
48 pub fn get<H, T>(mut self, handler: H) -> Self
49 where
50 H: axum::handler::Handler<T, S, axum::body::Body>,
51 T: 'static,
52 {
53 let operation = axum::routing::get(
54 |auth: redfish_core::extract::RedfishAuth<P::Get>,
55 axum::extract::State(state): axum::extract::State<S>,
56 mut request: axum::http::Request<axum::body::Body>| async {
57 request.extensions_mut().insert(auth.user);
58 handler.call(request, state).await
59 },
60 );
61 self.router = self.router.get(operation);
62 self.allowed_methods.push(axum::http::method::Method::GET);
63 self
64 }
65
66 pub fn put<H, T>(mut self, handler: H) -> Self
67 where
68 H: axum::handler::Handler<T, S, axum::body::Body>,
69 T: 'static,
70 {
71 let operation = axum::routing::put(
72 |auth: redfish_core::extract::RedfishAuth<P::Put>,
73 axum::extract::State(state): axum::extract::State<S>,
74 mut request: axum::http::Request<axum::body::Body>| async {
75 request.extensions_mut().insert(auth.user);
76 handler.call(request, state).await
77 },
78 );
79 self.router = self.router.put(operation);
80 self.allowed_methods.push(axum::http::method::Method::PUT);
81 self
82 }
83
84 pub fn patch<H, T>(mut self, handler: H) -> Self
85 where
86 H: axum::handler::Handler<T, S, axum::body::Body>,
87 T: 'static,
88 {
89 let operation = axum::routing::patch(
90 |auth: redfish_core::extract::RedfishAuth<P::Patch>,
91 axum::extract::State(state): axum::extract::State<S>,
92 mut request: axum::http::Request<axum::body::Body>| async {
93 request.extensions_mut().insert(auth.user);
94 handler.call(request, state).await
95 },
96 );
97 self.router = self.router.patch(operation);
98 self.allowed_methods.push(axum::http::method::Method::PATCH);
99 self
100 }
101
102 pub fn into_router(self) -> axum::Router<S> {
103 let Self {
104 router,
105 mut allowed_methods,
106 ..
107 } = self;
108 let result = axum::Router::default();
109 allowed_methods.dedup();
110 let allow_header = allowed_methods
111 .into_iter()
112 .map(|method| method.to_string())
113 .reduce(|one, two| one + "," + &two)
114 .unwrap();
115 result.route(
116 "/",
117 router.fallback(|| async {
118 (
119 axum::http::StatusCode::METHOD_NOT_ALLOWED,
120 axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
121 )
122 })
123 .route_layer(axum::middleware::from_fn_with_state(
124 allow_header,
125 |axum::extract::State(allow_header): axum::extract::State<String>,
126 request: axum::http::Request<axum::body::Body>,
127 next: axum::middleware::Next<axum::body::Body>| async move {
128 let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
129 let mut response = next.run(request).await;
130 if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
131 response.headers_mut().insert(
132 axum::http::header::ALLOW,
133 axum::http::HeaderValue::from_str(&allow_header).unwrap(),
134 );
135 }
136 response
137 },
138 )),
139 )
140 }
141}