lexa_framework/extract/
context.rs

1// ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
2// ┃ Copyright: (c) 2023, Mike 'PhiSyX' S. (https://github.com/PhiSyX)         ┃
3// ┃ SPDX-License-Identifier: MPL-2.0                                          ┃
4// ┃ ╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌ ┃
5// ┃                                                                           ┃
6// ┃  This Source Code Form is subject to the terms of the Mozilla Public      ┃
7// ┃  License, v. 2.0. If a copy of the MPL was not distributed with this      ┃
8// ┃  file, You can obtain one at https://mozilla.org/MPL/2.0/.                ┃
9// ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
10
11use axum::http;
12
13use crate::http::{HttpContext, HttpContextInterface};
14use crate::state::State;
15
16// ----------- //
17// Énumération //
18// ----------- //
19
20#[derive(Debug)]
21#[derive(thiserror::Error)]
22#[error("\n\t{}: {0}", std::any::type_name::<Self>())]
23pub enum HttpContextError {
24	Extension(#[from] axum::extract::rejection::ExtensionRejection),
25	Infaillible(#[from] std::convert::Infallible),
26	MissingExtension,
27}
28
29// -------------- //
30// Implémentation // -> Interface
31// -------------- //
32
33#[axum::async_trait]
34impl<C, S> axum::extract::FromRequestParts<State<S>> for HttpContext<C>
35where
36	C: 'static,
37	C: HttpContextInterface,
38	S: 'static,
39	S: Send + Sync,
40	<C as HttpContextInterface>::State: Send + Sync,
41	<C as HttpContextInterface>::State: axum::extract::FromRef<State<S>>,
42{
43	type Rejection = HttpContextError;
44
45	async fn from_request_parts(
46		parts: &mut axum::http::request::Parts,
47		state: &State<S>,
48	) -> Result<Self, Self::Rejection> {
49		// Context
50		let axum::extract::State(extracts) = axum::extract::State::<
51			<C as HttpContextInterface>::State,
52		>::from_request_parts(parts, state)
53		.await?;
54
55		let context = C::new(&parts.extensions, extracts)
56			.await
57			.ok_or(HttpContextError::MissingExtension)?
58			.shared();
59
60		// Request
61		let axum::extract::ConnectInfo(ip) =
62			axum::extract::ConnectInfo::from_request_parts(parts, state)
63				.await?;
64		let method = parts.method.clone();
65		let axum::extract::OriginalUri(uri) =
66			axum::extract::OriginalUri::from_request_parts(parts, state)
67				.await?;
68		let axum::extract::RawQuery(raw_query) =
69			axum::extract::RawQuery::from_request_parts(parts, state).await?;
70		let referer =
71			axum::TypedHeader::<axum::headers::Referer>::from_request_parts(
72				parts, state,
73			)
74			.await
75			.map(|ext| ext.0)
76			.ok();
77		let request = crate::http::HttpRequest {
78			context: context.clone(),
79			ip,
80			method,
81			uri,
82			raw_query,
83			referer,
84		};
85
86		// Response
87		let response = crate::http::HttpResponse {
88			context: context.clone(),
89		};
90
91		// Cookies
92		#[cfg(feature = "cookies")]
93		{
94			let cookie_key = state.cookie_key.as_ref().unwrap().clone();
95			let cookies_manager =
96				tower_cookies::Cookies::from_request_parts(parts, state)
97					.await
98					.expect("Cookies Manager");
99			let cookies =
100				crate::http::cookies::Cookies::new(cookies_manager, cookie_key);
101
102			let session = parts
103				.extensions
104				.get::<axum_sessions::SessionHandle>()
105				.cloned()
106				.map(|session_handle| {
107					crate::http::session::Session {
108						handle: session_handle,
109					}
110				})
111				.expect("Impossible d'extraire la session");
112
113			Ok(Self {
114				context,
115				request,
116				response,
117				cookies,
118				session,
119			})
120		}
121
122		#[cfg(not(feature = "cookies"))]
123		{
124			Ok(Self {
125				context,
126				request,
127				response,
128			})
129		}
130	}
131}
132
133impl axum::response::IntoResponse for HttpContextError {
134	fn into_response(self) -> axum::response::Response {
135		let err_status = http::StatusCode::INTERNAL_SERVER_ERROR;
136		let err_body = self.to_string();
137		(err_status, err_body).into_response()
138	}
139}