Skip to main content

arminius_lib_component/
request_source.rs

1// SPDX-FileCopyrightText: 2025 BWI GmbH
2//
3// SPDX-License-Identifier: Apache-2.0
4
5//! Module containing an Axum extractor for extracting IP addresses
6
7mod tests;
8
9use std::net::IpAddr;
10
11use crate::error::{InternalServerError, ResultExt as _};
12
13/// The source of a HTTP request, parsed from the X-Forwarded-For header
14#[derive(Debug)]
15pub struct RequestSource(pub Option<IpAddr>);
16
17impl<S> axum::extract::FromRequestParts<S> for RequestSource
18where
19	S: Send + Sync,
20{
21	/// Anything that can go wrong here, is the fault of the server
22	/// administrator, so the user shouldn't get any information about how the
23	/// server is set up if the sysadmin messes up. If the sysadmin wants to
24	/// troubleshoot their reverse proxy, *they* can just look at the logs.
25	type Rejection = InternalServerError;
26
27	async fn from_request_parts(
28		parts: &mut axum::http::request::Parts,
29		_: &S,
30	) -> Result<Self, InternalServerError> {
31		let Some(forwarded_for) = parts.headers.get("X-Forwarded-For") else {
32			return Ok(Self(None));
33		};
34		let addr: IpAddr = forwarded_for
35			.to_str()
36			.unrecoverable_error("Could not parse X-Forwarded-For header as ASCII")?
37			.parse()
38			.unrecoverable_error("Could not parse X-Forwarded-For header as address")?;
39		Ok(Self(Some(addr)))
40	}
41}