use axum::body::Body;
use axum::http::{HeaderValue, Request, StatusCode};
use tower::ServiceExt;
use super::*;
#[tokio::test]
async fn forwarded_for_from_an_untrusted_peer_does_not_pick_the_bucket() {
let ctx = test_ctx(1);
for (forwarded_for, expected) in [
("9.9.9.1", StatusCode::OK),
("9.9.9.2", StatusCode::TOO_MANY_REQUESTS),
] {
let req = header_request("203.0.113.7", "x-forwarded-for", forwarded_for);
let resp = test_app(ctx.clone()).oneshot(req).await.unwrap();
assert_eq!(resp.status(), expected, "x-forwarded-for {forwarded_for}");
}
}
#[tokio::test]
async fn x_real_ip_from_an_untrusted_peer_does_not_pick_the_bucket() {
let ctx = test_ctx(1);
for (real_ip, expected) in [
("192.168.1.1", StatusCode::OK),
("192.168.1.2", StatusCode::TOO_MANY_REQUESTS),
] {
let req = header_request("203.0.113.7", "x-real-ip", real_ip);
let resp = test_app(ctx.clone()).oneshot(req).await.unwrap();
assert_eq!(resp.status(), expected, "x-real-ip {real_ip}");
}
}
#[tokio::test]
async fn trusted_proxy_forwards_each_client_to_its_own_bucket() {
let mut ctx = test_ctx(1);
ctx.trusted_proxies = "10.0.0.0/8".parse().unwrap();
for (forwarded_for, expected) in [
("198.51.100.1", StatusCode::OK),
("198.51.100.2", StatusCode::OK),
("198.51.100.1", StatusCode::TOO_MANY_REQUESTS),
] {
let req = header_request("10.0.0.2", "x-forwarded-for", forwarded_for);
let resp = test_app(ctx.clone()).oneshot(req).await.unwrap();
assert_eq!(resp.status(), expected, "x-forwarded-for {forwarded_for}");
}
}
#[tokio::test]
async fn hops_forged_before_the_trusted_proxy_are_ignored() {
let mut ctx = test_ctx(1);
ctx.trusted_proxies = "10.0.0.0/8".parse().unwrap();
for (forwarded_for, expected) in [
("9.9.9.1, 198.51.100.1", StatusCode::OK),
("9.9.9.2, 198.51.100.1", StatusCode::TOO_MANY_REQUESTS),
] {
let req = header_request("10.0.0.2", "x-forwarded-for", forwarded_for);
let resp = test_app(ctx.clone()).oneshot(req).await.unwrap();
assert_eq!(resp.status(), expected, "x-forwarded-for {forwarded_for}");
}
}
#[tokio::test]
async fn x_real_ip_header_mode_reads_x_real_ip() {
let mut ctx = test_ctx(1);
ctx.trusted_proxies = "10.0.0.2"
.parse::<TrustedProxies>()
.unwrap()
.with_header(ClientIpHeader::XRealIp);
for (real_ip, expected) in [
("198.51.100.1", StatusCode::OK),
("198.51.100.2", StatusCode::OK),
("198.51.100.1", StatusCode::TOO_MANY_REQUESTS),
] {
let req = header_request("10.0.0.2", "x-real-ip", real_ip);
let resp = test_app(ctx.clone()).oneshot(req).await.unwrap();
assert_eq!(resp.status(), expected, "x-real-ip {real_ip}");
}
let req = with_peer(
Request::builder()
.uri("/test")
.header("x-real-ip", "198.51.100.3")
.header("x-forwarded-for", "198.51.100.1")
.body(Body::empty())
.unwrap(),
"10.0.0.2",
);
let resp = test_app(ctx).oneshot(req).await.unwrap();
assert_eq!(resp.status(), StatusCode::OK);
}
#[tokio::test]
async fn x_real_ip_is_not_a_fallback_for_x_forwarded_for() {
let mut ctx = test_ctx(1);
ctx.trusted_proxies = "10.0.0.0/8".parse().unwrap();
for (real_ip, expected) in [
("198.51.100.1", StatusCode::OK),
("198.51.100.2", StatusCode::TOO_MANY_REQUESTS),
] {
let req = header_request("10.0.0.2", "x-real-ip", real_ip);
let resp = test_app(ctx.clone()).oneshot(req).await.unwrap();
assert_eq!(resp.status(), expected, "x-real-ip {real_ip}");
}
}
#[tokio::test]
async fn requests_without_peer_do_not_share_one_bucket() {
let ctx = test_ctx(1);
for forwarded_for in ["9.9.9.1", "9.9.9.2"] {
let value = HeaderValue::from_static(forwarded_for);
let mut req = no_peer_request();
req.headers_mut().insert("x-forwarded-for", value);
let resp = test_app(ctx.clone()).oneshot(req).await.unwrap();
assert_eq!(
resp.status(),
StatusCode::OK,
"x-forwarded-for {forwarded_for}"
);
assert!(!resp.headers().contains_key("x-ratelimit-limit"));
}
}