Skip to main content

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}