Skip to main content

wisegate_core/
headers.rs

1//! HTTP header constants for WiseGate.
2//!
3//! This module centralizes all HTTP header names used throughout the codebase,
4//! avoiding magic strings and ensuring consistency.
5
6/// X-Forwarded-For header - contains the originating client IP.
7pub const X_FORWARDED_FOR: &str = "x-forwarded-for";
8
9/// X-Real-IP header - injected by WiseGate for upstream services.
10pub const X_REAL_IP: &str = "x-real-ip";
11
12/// Forwarded header (RFC 7239) - standardized proxy header.
13pub const FORWARDED: &str = "forwarded";
14
15/// Authorization header (for Basic Auth).
16pub const AUTHORIZATION: &str = "authorization";
17
18/// WWW-Authenticate header (for 401 responses).
19pub const WWW_AUTHENTICATE: &str = "www-authenticate";
20
21/// Content-Type header.
22pub const CONTENT_TYPE: &str = "content-type";
23
24/// Host header.
25pub const HOST: &str = "host";
26
27/// Content-Length header.
28pub const CONTENT_LENGTH: &str = "content-length";
29
30/// Connection header (hop-by-hop).
31pub const CONNECTION: &str = "connection";
32
33/// Keep-Alive header (hop-by-hop).
34pub const KEEP_ALIVE: &str = "keep-alive";
35
36/// Proxy-Authenticate header (hop-by-hop).
37pub const PROXY_AUTHENTICATE: &str = "proxy-authenticate";
38
39/// Proxy-Authorization header (hop-by-hop).
40pub const PROXY_AUTHORIZATION: &str = "proxy-authorization";
41
42/// TE header (hop-by-hop).
43pub const TE: &str = "te";
44
45/// Trailers header (hop-by-hop).
46pub const TRAILERS: &str = "trailers";
47
48/// Transfer-Encoding header (hop-by-hop).
49pub const TRANSFER_ENCODING: &str = "transfer-encoding";
50
51/// Upgrade header (hop-by-hop).
52pub const UPGRADE: &str = "upgrade";
53
54/// List of all hop-by-hop headers that should not be forwarded.
55pub const HOP_BY_HOP_HEADERS: &[&str] = &[
56    CONNECTION,
57    KEEP_ALIVE,
58    PROXY_AUTHENTICATE,
59    PROXY_AUTHORIZATION,
60    TE,
61    TRAILERS,
62    TRANSFER_ENCODING,
63    UPGRADE,
64];
65
66/// Check if a header is a hop-by-hop header that shouldn't be forwarded.
67///
68/// Comparison is case-insensitive (ASCII), avoiding allocations from `to_lowercase()`.
69///
70/// # Arguments
71///
72/// * `header_name` - The header name to check.
73///
74/// # Returns
75///
76/// `true` if the header is a hop-by-hop header, `false` otherwise.
77///
78/// # Example
79///
80/// ```
81/// use wisegate_core::headers::is_hop_by_hop;
82///
83/// assert!(is_hop_by_hop("connection"));
84/// assert!(is_hop_by_hop("Transfer-Encoding"));
85/// assert!(!is_hop_by_hop("content-type"));
86/// ```
87pub fn is_hop_by_hop(header_name: &str) -> bool {
88    HOP_BY_HOP_HEADERS
89        .iter()
90        .any(|h| h.eq_ignore_ascii_case(header_name))
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn test_hop_by_hop_headers() {
99        assert!(is_hop_by_hop(CONNECTION));
100        assert!(is_hop_by_hop(KEEP_ALIVE));
101        assert!(is_hop_by_hop(PROXY_AUTHENTICATE));
102        assert!(is_hop_by_hop(PROXY_AUTHORIZATION));
103        assert!(is_hop_by_hop(TE));
104        assert!(is_hop_by_hop(TRAILERS));
105        assert!(is_hop_by_hop(TRANSFER_ENCODING));
106        assert!(is_hop_by_hop(UPGRADE));
107    }
108
109    #[test]
110    fn test_not_hop_by_hop_headers() {
111        assert!(!is_hop_by_hop(CONTENT_TYPE));
112        assert!(!is_hop_by_hop(HOST));
113        assert!(!is_hop_by_hop(CONTENT_LENGTH));
114        assert!(!is_hop_by_hop(X_FORWARDED_FOR));
115        assert!(!is_hop_by_hop(X_REAL_IP));
116        assert!(!is_hop_by_hop(FORWARDED));
117        assert!(!is_hop_by_hop("authorization"));
118        assert!(!is_hop_by_hop("accept"));
119    }
120
121    #[test]
122    fn test_header_constants_lowercase() {
123        // All header constants should be lowercase for consistent matching
124        assert_eq!(X_FORWARDED_FOR, X_FORWARDED_FOR.to_lowercase());
125        assert_eq!(X_REAL_IP, X_REAL_IP.to_lowercase());
126        assert_eq!(FORWARDED, FORWARDED.to_lowercase());
127        assert_eq!(CONTENT_TYPE, CONTENT_TYPE.to_lowercase());
128        assert_eq!(HOST, HOST.to_lowercase());
129        assert_eq!(CONTENT_LENGTH, CONTENT_LENGTH.to_lowercase());
130    }
131}