Skip to content

Commit 820b380

Browse files
authored
chore(guard): add metadata to rate limit error (#3292)
1 parent 1db00e7 commit 820b380

File tree

2 files changed

+39
-7
lines changed

2 files changed

+39
-7
lines changed

engine/packages/guard-core/src/errors.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
11
use rivet_error::*;
2+
use rivet_util::Id;
23
use serde::{Deserialize, Serialize};
34

4-
#[derive(RivetError)]
5-
#[error("guard", "rate_limit", "Too many requests. Try again later.")]
6-
pub struct RateLimit;
5+
#[derive(RivetError, Serialize, Deserialize)]
6+
#[error(
7+
"guard",
8+
"rate_limit",
9+
"Too many requests. Try again later.",
10+
"Too many requests to '{method} {path}' (actor_id: {actor_id:?}) from IP {ip}."
11+
)]
12+
pub struct RateLimit {
13+
pub actor_id: Option<Id>,
14+
pub method: String,
15+
pub path: String,
16+
pub ip: String,
17+
}
718

819
#[derive(RivetError, Serialize, Deserialize)]
920
#[error(

engine/packages/guard-core/src/proxy_service.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -722,16 +722,31 @@ impl ProxyService {
722722
None
723723
};
724724

725-
// Extract IP address from remote_addr
726-
let client_ip = self.remote_addr.ip();
725+
// Extract IP address from X-Forwarded-For header or fall back to remote_addr
726+
let client_ip = req
727+
.headers()
728+
.get(X_FORWARDED_FOR)
729+
.and_then(|h| h.to_str().ok())
730+
.and_then(|forwarded| {
731+
// X-Forwarded-For can be a comma-separated list, take the first IP
732+
forwarded.split(',').next().map(|s| s.trim())
733+
})
734+
.and_then(|ip_str| ip_str.parse::<std::net::IpAddr>().ok())
735+
.unwrap_or_else(|| self.remote_addr.ip());
727736

728737
// Apply rate limiting
729738
if !self
730739
.state
731740
.check_rate_limit(client_ip, &actor_id, req.headers())
732741
.await?
733742
{
734-
return Err(errors::RateLimit.build());
743+
return Err(errors::RateLimit {
744+
actor_id,
745+
method: req.method().to_string(),
746+
path: path.clone(),
747+
ip: client_ip.to_string(),
748+
}
749+
.build());
735750
}
736751

737752
// Check in-flight limit
@@ -740,7 +755,13 @@ impl ProxyService {
740755
.acquire_in_flight(client_ip, &actor_id, req.headers())
741756
.await?
742757
{
743-
return Err(errors::RateLimit.build());
758+
return Err(errors::RateLimit {
759+
actor_id,
760+
method: req.method().to_string(),
761+
path: path.clone(),
762+
ip: client_ip.to_string(),
763+
}
764+
.build());
744765
}
745766

746767
// Increment metrics

0 commit comments

Comments
 (0)