Skip to main content

chio_http_core/
method.rs

1//! HTTP method enumeration for Chio request evaluation.
2
3use serde::{Deserialize, Serialize};
4
5/// HTTP method. Used to determine default policy (GET = session-scoped allow,
6/// POST/PUT/PATCH/DELETE = deny without capability).
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
8#[serde(rename_all = "UPPERCASE")]
9pub enum HttpMethod {
10    Get,
11    Post,
12    Put,
13    Patch,
14    Delete,
15    Head,
16    Options,
17}
18
19impl HttpMethod {
20    /// Whether this method is considered side-effect-free by default.
21    /// Side-effect-free methods get session-scoped allow; others require
22    /// explicit capability grants.
23    #[must_use]
24    pub fn is_safe(&self) -> bool {
25        matches!(self, Self::Get | Self::Head | Self::Options)
26    }
27
28    /// Whether this method requires an explicit capability grant by default.
29    #[must_use]
30    pub fn requires_capability(&self) -> bool {
31        !self.is_safe()
32    }
33}
34
35impl std::fmt::Display for HttpMethod {
36    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37        match self {
38            Self::Get => write!(f, "GET"),
39            Self::Post => write!(f, "POST"),
40            Self::Put => write!(f, "PUT"),
41            Self::Patch => write!(f, "PATCH"),
42            Self::Delete => write!(f, "DELETE"),
43            Self::Head => write!(f, "HEAD"),
44            Self::Options => write!(f, "OPTIONS"),
45        }
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    #[test]
54    fn safe_methods() {
55        assert!(HttpMethod::Get.is_safe());
56        assert!(HttpMethod::Head.is_safe());
57        assert!(HttpMethod::Options.is_safe());
58    }
59
60    #[test]
61    fn unsafe_methods_require_capability() {
62        assert!(HttpMethod::Post.requires_capability());
63        assert!(HttpMethod::Put.requires_capability());
64        assert!(HttpMethod::Patch.requires_capability());
65        assert!(HttpMethod::Delete.requires_capability());
66    }
67
68    #[test]
69    fn display_uppercase() {
70        assert_eq!(HttpMethod::Get.to_string(), "GET");
71        assert_eq!(HttpMethod::Delete.to_string(), "DELETE");
72    }
73
74    #[test]
75    fn serde_roundtrip() {
76        let method = HttpMethod::Post;
77        let json = serde_json::to_string(&method).unwrap();
78        assert_eq!(json, "\"POST\"");
79        let back: HttpMethod = serde_json::from_str(&json).unwrap();
80        assert_eq!(back, method);
81    }
82}