Skip to main content

rightkit_daemon/contract/
status.rs

1use crate::error::*;
2use crate::ServiceError;
3
4/// Error code -> HTTP-style status, for transports that carry one. Local transport ignores it
5/// and sends the [`ServiceError`] as is. Unknown codes are 500, or 503 when retryable.
6pub const STATUS_TABLE: &[(&str, u16)] = &[
7    ("bad_request", 400),
8    (ERROR_UNAUTHENTICATED, 401),
9    (ERROR_RATE_LIMITED, 429),
10    (ERROR_FORBIDDEN, 403),
11    (ERROR_NOT_ALLOWED, 403),
12    (ERROR_REVISION_CONFLICT, 409),
13    (ERROR_RESPONSE_TOO_LARGE, 502),
14    (ERROR_REQUEST_TOO_LARGE, 413),
15    (ERROR_BAD_CHUNK, 400),
16    (ERROR_CONNECTION_CLOSED, 502),
17    (ERROR_HOST_HANDOFF, 503),
18    (ERROR_UNAVAILABLE, 503),
19    (ERROR_TIMEOUT, 504),
20    (ERROR_HOST_IDENTITY, 502),
21    (ERROR_SUITE_UNRESOLVED, 500),
22];
23
24/// Status for a code; `None` when the table does not know it.
25pub fn status_for_code(code: &str) -> Option<u16> {
26    STATUS_TABLE
27        .iter()
28        .find(|(c, _)| *c == code)
29        .map(|(_, s)| *s)
30}
31
32/// Status for an error: the table, else 503 when retryable, else 500.
33pub fn status_for_error(e: &ServiceError) -> u16 {
34    status_for_code(&e.code).unwrap_or(if e.retryable { 503 } else { 500 })
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40
41    #[test]
42    fn known_codes_map_and_unknown_fall_back() {
43        assert_eq!(status_for_code("unauthenticated"), Some(401));
44        assert_eq!(status_for_code("forbidden"), Some(403));
45        assert_eq!(status_for_code("revision_conflict"), Some(409));
46        assert_eq!(status_for_code(ERROR_NOT_ALLOWED), Some(403));
47        assert_eq!(status_for_code(ERROR_REQUEST_TOO_LARGE), Some(413));
48        assert_eq!(status_for_code(ERROR_BAD_CHUNK), Some(400));
49        assert_eq!(status_for_code("nope"), None);
50        assert_eq!(status_for_error(&ServiceError::new("nope", "x")), 500);
51        assert_eq!(status_for_error(&ServiceError::retryable("nope", "x")), 503);
52        assert_eq!(status_for_error(&ServiceError::handoff()), 503);
53    }
54
55    #[test]
56    fn codes_are_unique() {
57        let mut seen = std::collections::BTreeSet::new();
58        for (c, _) in STATUS_TABLE {
59            assert!(seen.insert(*c), "duplicate {c}");
60        }
61    }
62}