rocket_governor/limit_error.rs
1//! Errors for governed requests which implement
2//! [Responder](rocket::response::Responder).
3
4use super::{header::Header, Quota};
5use rocket::{
6 response::{self, Responder},
7 Request,
8};
9
10mod catcher;
11
12/// Errors for governed requests which implement
13/// [Responder](rocket::response::Responder).
14#[derive(Clone, Debug)]
15pub enum LimitError {
16 /// Any other undefined LimitError
17 Error,
18
19 // TODO: Check ratelimit headers DRAFT for publication
20 /// Governed request for the next provided seconds.
21 /// Provided `Quota` will be used for setting additional
22 /// HTTP headers defined by
23 /// [draft-ietf-httpapi-ratelimit-headers](https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers).
24 /// These headers could be used in service clients to use the service
25 /// in a more compliant way for its resources.
26 GovernedRequest(u64, Quota),
27
28 /// There is no remote client IP address known in the request. Might be
29 /// a misconfigured server environment.
30 MissingClientIpAddr,
31
32 /// Route is not available which might be only the case in fairings
33 MissingRoute,
34
35 /// There is a route without name and this can not be matched for
36 /// rate limiting
37 MissingRouteName,
38}
39
40/// Implements [Responder] to provide
41/// [Result](rocket::response::Result) possibilities.
42impl<'r, 'o: 'r> Responder<'r, 'o> for &LimitError {
43 fn respond_to(self, request: &'r Request<'_>) -> response::Result<'o> {
44 let mut handler = catcher::too_many_requests_handler(request);
45
46 match self {
47 LimitError::Error => {
48 handler.set_header(Header::XRateLimitError("rate limiter error"));
49 }
50 LimitError::GovernedRequest(wait_time, quota) => {
51 handler.set_header(Header::RetryAfter(*wait_time));
52 // TODO: x-ratelimit-limit can describe the time window of limit
53 // https://datatracker.ietf.org/doc/html/draft-ietf-httpapi-ratelimit-headers#section-5.1
54 handler.set_header(Header::XRateLimitLimit(quota.burst_size().get() as u64));
55 // XRateLimitRemaining makes no sense here in LimitError
56 // because `state.remaining_burst_capacity()` should be
57 // always 0
58 handler.set_header(Header::XRateLimitReset(
59 quota.burst_size_replenished_in().as_secs(),
60 ));
61 }
62 LimitError::MissingClientIpAddr => {
63 handler.set_header(Header::XRateLimitError(
64 "application not retrieving client ip",
65 ));
66 }
67 LimitError::MissingRoute => {
68 handler.set_header(Header::XRateLimitError("routing failure"));
69 }
70 LimitError::MissingRouteName => {
71 handler.set_header(Header::XRateLimitError("route without name"));
72 }
73 };
74
75 Ok(handler)
76 }
77}