Skip to content

Commit aacfbb9

Browse files
committed
packages/ak-axum/extract/scheme: init (#21322)
Squashed commit of the following: commit adac0e4 Merge: f2dea0e 2e5cfb2 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:47:53 2026 +0200 Merge branch 'rust-axum-extract-client-ip' into rust-axum-extract-scheme commit 2e5cfb2 Merge: d51d860 a6d543b Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:47:43 2026 +0200 Merge branch 'rust-axum-extract-trusted-proxy' into rust-axum-extract-client-ip commit a6d543b Merge: da38234 a522b8b Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:47:33 2026 +0200 Merge branch 'rust-axum-acceptor-proxy' into rust-axum-extract-trusted-proxy commit a522b8b Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:46:57 2026 +0200 fmt Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit f2dea0e Merge: 6b7d139 d51d860 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:16:56 2026 +0200 Merge branch 'rust-axum-extract-client-ip' into rust-axum-extract-scheme commit d51d860 Merge: f74e533 da38234 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:16:50 2026 +0200 Merge branch 'rust-axum-extract-trusted-proxy' into rust-axum-extract-client-ip Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit da38234 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:16:30 2026 +0200 add doc Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 6b7d139 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:15:25 2026 +0200 wip Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 19c6cf0 Merge: 1173406 f74e533 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:13:12 2026 +0200 Merge branch 'rust-axum-extract-client-ip' into rust-axum-extract-scheme commit f74e533 Merge: 4c84c53 703d5af Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:13:03 2026 +0200 Merge branch 'rust-axum-extract-trusted-proxy' into rust-axum-extract-client-ip commit 703d5af Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:12:58 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 1173406 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:12:24 2026 +0200 wip Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 4c84c53 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:10:10 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 356c487 Merge: c2bd441 81f314c Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:09:58 2026 +0200 Merge branch 'rust-axum-extract-trusted-proxy' into rust-axum-extract-client-ip commit 81f314c Merge: 544f662 5b13d5b Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:09:51 2026 +0200 Merge branch 'rust-axum-trace' into rust-axum-extract-trusted-proxy commit 5b13d5b Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:09:43 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit c2bd441 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:09:25 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit d350e94 Merge: b42fb09 544f662 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:09:10 2026 +0200 Merge branch 'rust-axum-extract-trusted-proxy' into rust-axum-extract-client-ip commit 544f662 Merge: 267336f 5e03610 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:08:55 2026 +0200 Merge branch 'rust-axum-trace' into rust-axum-extract-trusted-proxy commit 5e03610 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:08:20 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit b42fb09 Merge: a30b345 267336f Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:06:28 2026 +0200 Merge branch 'rust-axum-extract-trusted-proxy' into rust-axum-extract-client-ip Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 267336f Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:05:50 2026 +0200 fix layer order Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit a30b345 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:05:32 2026 +0200 wip Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit e2ab302 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 19:00:34 2026 +0200 add docs Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 89fbf0d Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 18:56:17 2026 +0200 packages/ak-axum/extract/trusted_proxy: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 279610b Merge: 2917970 5c937d7 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 18:54:49 2026 +0200 Merge branch 'rust-axum-trace' into rust-axum-extract-trusted-proxy Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 2917970 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 18:40:31 2026 +0200 packages/ak-axum/accept/proxy_protocol: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit d999d80 Merge: 65f33d6 365de9d Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 18:38:50 2026 +0200 Merge branch 'rust-lib-proxy-protocol' into rust-axum-acceptor-proxy Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 65f33d6 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 18:35:12 2026 +0200 packages/ak-axum/accept/tls: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 116e601 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 18:28:43 2026 +0200 packages/ak-axum/server: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 5c937d7 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:40:46 2026 +0200 packages/ak-axum/tracing: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 67ed0dc Merge: b4f06d6 095d38c Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:17:40 2026 +0200 Merge branch 'rust-config' into rust-axum Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 365de9d Merge: ab239bf 0079984 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:15:04 2026 +0200 Merge branch 'rust-lib-rename' into rust-lib-proxy-protocol Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 095d38c Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:11:52 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 7eb07d5 Merge: cb1f86b 507eb2f Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:11:08 2026 +0200 Merge branch 'rust-arbiter' into rust-config commit 507eb2f Merge: 6968d59 0079984 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:10:37 2026 +0200 Merge branch 'rust-lib-rename' into rust-arbiter Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 0079984 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:08:07 2026 +0200 packages/ak-common: rename from ak-lib Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit b4f06d6 Merge: c08e2a3 cb1f86b Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:05:36 2026 +0200 wip Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit c08e2a3 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 17:05:01 2026 +0200 wip Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 75622e9 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 16:57:45 2026 +0200 packages/ak-axum: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit cb1f86b Merge: c8fa1b8 a3fea5d Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 16:53:19 2026 +0200 Merge branch 'fix-rustfmt-config' into rust-config commit 6968d59 Merge: 341c9cc a3fea5d Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 16:52:55 2026 +0200 Merge branch 'fix-rustfmt-config' into rust-arbiter commit ab239bf Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 16:39:44 2026 +0200 fix import Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit a3fea5d Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 16:32:16 2026 +0200 root: fix rustfmt config Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 3ef0080 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Wed Apr 1 16:29:35 2026 +0200 packages/ak-lib/tokio/proxy_procotol: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit c8fa1b8 Merge: 48c833c 341c9cc Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Tue Mar 31 13:56:39 2026 +0200 Merge branch 'rust-arbiter' into rust-config commit 341c9cc Merge: a1cf0a7 55e555c Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Tue Mar 31 13:55:28 2026 +0200 Merge branch 'main' into rust-arbiter Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 48c833c Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 20:31:04 2026 +0200 lint Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 681117d Merge: 4c54511 a1cf0a7 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 20:03:49 2026 +0200 Merge branch 'rust-arbiter' into rust-config Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit a1cf0a7 Merge: 1ee6f11 524b788 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 20:03:01 2026 +0200 Merge branch 'rust-lib' into rust-arbiter Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 524b788 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:57:51 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit dc65ab1 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 16:33:49 2026 +0200 packages/ak-lib: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 4c54511 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:52:55 2026 +0200 move into lib crate Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit d7141df Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:48:34 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 2bab7ed Merge: 2bc79f1 1ee6f11 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:43:24 2026 +0200 Merge branch 'rust-arbiter' into rust-config commit 1ee6f11 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:43:21 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 2bc79f1 Merge: e7d3704 27ff039 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:42:58 2026 +0200 Merge branch 'rust-arbiter' into rust-config Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 27ff039 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:40:37 2026 +0200 rename to ak-lib Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit e7d3704 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:32:59 2026 +0200 packages/ak-config: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 1e5cb4b Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 19:32:18 2026 +0200 sort out package versions Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 64b9391 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 17:49:16 2026 +0200 lint Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 57edeec Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 17:48:51 2026 +0200 add tests Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit 5294f8a Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 16:38:11 2026 +0200 fixup Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> commit f1257d2 Author: Marc 'risson' Schmitt <marc.schmitt@risson.space> Date: Mon Mar 30 16:33:49 2026 +0200 packages/ak-arbiter: init Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space> Signed-off-by: Marc 'risson' Schmitt <marc.schmitt@risson.space>
1 parent 4e4ca82 commit aacfbb9

File tree

7 files changed

+263
-2
lines changed

7 files changed

+263
-2
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ console-subscriber = "= 0.5.0"
3434
dotenvy = "= 0.15.7"
3535
durstr = "= 0.5.1"
3636
eyre = "= 0.6.12"
37+
forwarded-header-value = "= 0.1.1"
3738
futures = "= 0.3.32"
3839
glob = "= 0.3.3"
3940
ipnet = { version = "= 2.12.0", features = ["serde"] }

packages/ak-axum/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ axum.workspace = true
1616
client-ip.workspace = true
1717
durstr.workspace = true
1818
eyre.workspace = true
19+
forwarded-header-value.workspace = true
1920
futures.workspace = true
2021
tokio-rustls.workspace = true
2122
tokio.workspace = true
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
//! axum extractors to get information about a request.
22
33
pub mod client_ip;
4+
pub mod scheme;
45
pub mod trusted_proxy;
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
//! axum extractor and middleware to get the request scheme.
2+
3+
use axum::{
4+
Extension, RequestPartsExt as _,
5+
extract::{FromRequestParts, Request},
6+
http::{self, header::FORWARDED, request::Parts},
7+
middleware::Next,
8+
response::Response,
9+
};
10+
use forwarded_header_value::{ForwardedHeaderValue, Protocol};
11+
use tracing::{Span, instrument};
12+
13+
use crate::{
14+
accept::{proxy_protocol::ProxyProtocolState, tls::TlsState},
15+
extract::trusted_proxy::TrustedProxy,
16+
};
17+
18+
const X_FORWARDED_PROTO: &str = "X-Forwarded-Proto";
19+
const X_FORWARDED_SCHEME: &str = "X-Forwarded-Scheme";
20+
21+
/// Request scheme.
22+
///
23+
/// The [`scheme_middleware`] must be added to the router before using this extractor,
24+
/// otherwise this will result in requests erroring.
25+
#[derive(Clone, Debug)]
26+
pub struct Scheme(pub http::uri::Scheme);
27+
28+
impl<S> FromRequestParts<S> for Scheme
29+
where
30+
S: Send + Sync,
31+
{
32+
type Rejection = <Extension<Self> as FromRequestParts<S>>::Rejection;
33+
34+
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
35+
Extension::<Self>::from_request_parts(parts, state)
36+
.await
37+
.map(|Extension(scheme)| scheme)
38+
}
39+
}
40+
41+
/// Get the scheme from the request.
42+
#[instrument(skip_all)]
43+
async fn extract_scheme(parts: &mut Parts) -> http::uri::Scheme {
44+
let is_trusted = parts
45+
.extract::<TrustedProxy>()
46+
.await
47+
.unwrap_or(TrustedProxy(false))
48+
.0;
49+
50+
if is_trusted {
51+
if let Some(proto) = parts.headers.get(X_FORWARDED_PROTO)
52+
&& let Ok(proto) = proto.to_str()
53+
&& let Ok(scheme) = proto.to_lowercase().as_str().try_into()
54+
{
55+
return scheme;
56+
}
57+
58+
if let Some(proto) = parts.headers.get(X_FORWARDED_SCHEME)
59+
&& let Ok(proto) = proto.to_str()
60+
&& let Ok(scheme) = proto.to_lowercase().as_str().try_into()
61+
{
62+
return scheme;
63+
}
64+
65+
if let Some(forwarded) = parts.headers.get(FORWARDED)
66+
&& let Ok(forwarded) = forwarded.to_str()
67+
&& let Ok(forwarded) = ForwardedHeaderValue::from_forwarded(forwarded)
68+
{
69+
for stanza in forwarded.iter() {
70+
if let Some(forwarded_proto) = &stanza.forwarded_proto {
71+
let scheme = match forwarded_proto {
72+
Protocol::Http => http::uri::Scheme::HTTP,
73+
Protocol::Https => http::uri::Scheme::HTTPS,
74+
};
75+
return scheme;
76+
}
77+
}
78+
}
79+
80+
if let Ok(Extension(proxy_protocol_state)) =
81+
parts.extract::<Extension<ProxyProtocolState>>().await
82+
&& let Some(header) = &proxy_protocol_state.header
83+
&& header.ssl().is_some()
84+
{
85+
return http::uri::Scheme::HTTPS;
86+
}
87+
}
88+
89+
if parts.extract::<Extension<TlsState>>().await.is_ok() {
90+
http::uri::Scheme::HTTPS
91+
} else {
92+
http::uri::Scheme::HTTP
93+
}
94+
}
95+
96+
/// Middleware required by the [`Scheme`] extractor.
97+
///
98+
/// Use with [`axum::middleware::from_fn`].
99+
pub async fn scheme_middleware(request: Request, next: Next) -> Response {
100+
let (mut parts, body) = request.into_parts();
101+
102+
let scheme = extract_scheme(&mut parts).await;
103+
Span::current().record("scheme", scheme.to_string());
104+
parts.extensions.insert::<Scheme>(Scheme(scheme));
105+
106+
let request = Request::from_parts(parts, body);
107+
108+
next.run(request).await
109+
}
110+
111+
#[cfg(test)]
112+
mod tests {
113+
use axum::{body::Body, http::Request};
114+
115+
use super::*;
116+
117+
#[tokio::test]
118+
async fn x_forwarded_proto_trusted() {
119+
let (mut parts, _) = Request::builder()
120+
.uri("http://example.com/path")
121+
.header("x-forwarded-proto", "https")
122+
.extension(TrustedProxy(true))
123+
.body(Body::empty())
124+
.expect("failed to create request")
125+
.into_parts();
126+
127+
let scheme = extract_scheme(&mut parts).await;
128+
129+
assert_eq!(scheme, http::uri::Scheme::HTTPS,);
130+
}
131+
132+
#[tokio::test]
133+
async fn x_forwarded_scheme_trusted() {
134+
let (mut parts, _) = Request::builder()
135+
.uri("http://example.com/path")
136+
.header("x-forwarded-scheme", "https")
137+
.extension(TrustedProxy(true))
138+
.body(Body::empty())
139+
.expect("Failed to create request")
140+
.into_parts();
141+
142+
let scheme = extract_scheme(&mut parts).await;
143+
144+
assert_eq!(scheme, http::uri::Scheme::HTTPS,);
145+
}
146+
147+
#[tokio::test]
148+
async fn forwarded_header_trusted() {
149+
let (mut parts, _) = Request::builder()
150+
.uri("http://example.com/path")
151+
.header("forwarded", "proto=https")
152+
.extension(TrustedProxy(true))
153+
.body(Body::empty())
154+
.expect("Failed to create request")
155+
.into_parts();
156+
157+
let scheme = extract_scheme(&mut parts).await;
158+
159+
assert_eq!(scheme, http::uri::Scheme::HTTPS,);
160+
}
161+
162+
#[tokio::test]
163+
async fn x_forwarded_proto_untrusted() {
164+
let (mut parts, _) = Request::builder()
165+
.uri("http://example.com/path")
166+
.header("x-forwarded-proto", "https")
167+
.extension(TrustedProxy(false))
168+
.body(Body::empty())
169+
.expect("Failed to create request")
170+
.into_parts();
171+
172+
let scheme = extract_scheme(&mut parts).await;
173+
174+
assert_eq!(scheme, http::uri::Scheme::HTTP,);
175+
}
176+
177+
#[tokio::test]
178+
async fn scheme_from_tls_state() {
179+
let (mut parts, _) = Request::builder()
180+
.uri("http://example.com/path")
181+
.extension(TlsState {
182+
peer_certificates: None,
183+
})
184+
.body(Body::empty())
185+
.expect("Failed to create request")
186+
.into_parts();
187+
188+
let scheme = extract_scheme(&mut parts).await;
189+
190+
assert_eq!(scheme, http::uri::Scheme::HTTPS,);
191+
}
192+
193+
#[tokio::test]
194+
async fn scheme_defaults_to_http() {
195+
let (mut parts, _) = Request::builder()
196+
.uri("http://example.com/path")
197+
.body(Body::empty())
198+
.expect("Failed to create request")
199+
.into_parts();
200+
201+
let scheme = extract_scheme(&mut parts).await;
202+
203+
assert_eq!(scheme, http::uri::Scheme::HTTP,);
204+
}
205+
206+
#[tokio::test]
207+
async fn priority_order() {
208+
let (mut parts, _) = Request::builder()
209+
.uri("http://example.com/path")
210+
.header("x-forwarded-proto", "http")
211+
.header("x-forwarded-scheme", "https")
212+
.header("forwarded", "proto=https")
213+
.extension(TrustedProxy(true))
214+
.body(Body::empty())
215+
.expect("Failed to create request")
216+
.into_parts();
217+
218+
let scheme = extract_scheme(&mut parts).await;
219+
220+
assert_eq!(scheme, http::uri::Scheme::HTTP,);
221+
}
222+
223+
#[tokio::test]
224+
async fn multiple_forwarded_stanzas() {
225+
let (mut parts, _) = Request::builder()
226+
.uri("http://example.com/path")
227+
.header("forwarded", "proto=http, proto=https")
228+
.extension(TrustedProxy(true))
229+
.body(Body::empty())
230+
.expect("Failed to create request")
231+
.into_parts();
232+
233+
let scheme = extract_scheme(&mut parts).await;
234+
235+
assert_eq!(scheme, http::uri::Scheme::HTTP,);
236+
}
237+
238+
#[tokio::test]
239+
async fn test_scheme_case_insensitive() {
240+
let (mut parts, _) = Request::builder()
241+
.uri("http://example.com/path")
242+
.header("x-forwarded-proto", "HTTPS")
243+
.extension(TrustedProxy(true))
244+
.body(Body::empty())
245+
.expect("Failed to create request")
246+
.into_parts();
247+
248+
let scheme = extract_scheme(&mut parts).await;
249+
250+
assert_eq!(scheme, http::uri::Scheme::HTTPS,);
251+
}
252+
}

packages/ak-axum/src/router.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ use tower::ServiceBuilder;
66
use tower_http::timeout::TimeoutLayer;
77

88
use crate::{
9-
extract::{client_ip::client_ip_middleware, trusted_proxy::trusted_proxy_middleware},
9+
extract::{
10+
client_ip::client_ip_middleware, scheme::scheme_middleware,
11+
trusted_proxy::trusted_proxy_middleware,
12+
},
1013
tracing::{span_middleware, tracing_middleware},
1114
};
1215

@@ -28,7 +31,8 @@ pub fn wrap_router(router: Router, with_tracing: bool) -> Router {
2831
))
2932
.layer(from_fn(span_middleware))
3033
.layer(from_fn(trusted_proxy_middleware))
31-
.layer(from_fn(client_ip_middleware));
34+
.layer(from_fn(client_ip_middleware))
35+
.layer(from_fn(scheme_middleware));
3236
if with_tracing {
3337
router.layer(service_builder.layer(from_fn(tracing_middleware)))
3438
} else {

packages/ak-axum/src/tracing.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub(crate) async fn span_middleware(request: Request, next: Next) -> Response {
2828
path = %request.uri(),
2929
method = %request.method(),
3030
remote = field::Empty,
31+
scheme = field::Empty,
3132
http_headers = ?http_headers,
3233
);
3334
next.run(request).instrument(span).await

0 commit comments

Comments
 (0)