Skip to main content

stackforge_core/layer/http/
detection.rs

1//! HTTP traffic detection utilities.
2//!
3//! Provides functions to quickly determine whether a byte slice looks like
4//! HTTP/1.x request or response data, without full parsing.
5
6/// All standard HTTP/1.x request methods, each with a trailing space so a
7/// simple `starts_with` check is unambiguous.
8const HTTP_METHODS: &[&[u8]] = &[
9    b"GET ",
10    b"POST ",
11    b"HEAD ",
12    b"PUT ",
13    b"DELETE ",
14    b"OPTIONS ",
15    b"PATCH ",
16    b"CONNECT ",
17    b"TRACE ",
18];
19
20/// Returns `true` if `buf` begins with a recognised HTTP request method token.
21///
22/// The check is a fast `starts_with` on the first few bytes and does **not**
23/// validate the rest of the request line.
24pub fn is_http_request(buf: &[u8]) -> bool {
25    HTTP_METHODS.iter().any(|m| buf.starts_with(m))
26}
27
28/// Returns `true` if `buf` begins with the HTTP response status-line prefix
29/// `"HTTP/"`.
30pub fn is_http_response(buf: &[u8]) -> bool {
31    buf.starts_with(b"HTTP/")
32}
33
34/// Returns `true` if `buf` looks like any HTTP/1.x traffic (request or
35/// response).
36pub fn is_http(buf: &[u8]) -> bool {
37    is_http_request(buf) || is_http_response(buf)
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn test_is_http_request_methods() {
46        assert!(is_http_request(b"GET / HTTP/1.1\r\n"));
47        assert!(is_http_request(b"POST /api HTTP/1.1\r\n"));
48        assert!(is_http_request(b"HEAD / HTTP/1.0\r\n"));
49        assert!(is_http_request(b"PUT /resource HTTP/1.1\r\n"));
50        assert!(is_http_request(b"DELETE /res HTTP/1.1\r\n"));
51        assert!(is_http_request(b"OPTIONS * HTTP/1.1\r\n"));
52        assert!(is_http_request(b"PATCH /res HTTP/1.1\r\n"));
53        assert!(is_http_request(b"CONNECT host:443 HTTP/1.1\r\n"));
54        assert!(is_http_request(b"TRACE / HTTP/1.1\r\n"));
55    }
56
57    #[test]
58    fn test_is_http_request_negative() {
59        assert!(!is_http_request(b"HTTP/1.1 200 OK\r\n"));
60        assert!(!is_http_request(b"INVALID method"));
61        assert!(!is_http_request(b""));
62        assert!(!is_http_request(b"SSH-2.0"));
63    }
64
65    #[test]
66    fn test_is_http_response() {
67        assert!(is_http_response(b"HTTP/1.1 200 OK\r\n"));
68        assert!(is_http_response(b"HTTP/1.0 404 Not Found\r\n"));
69        assert!(!is_http_response(b"GET / HTTP/1.1\r\n"));
70        assert!(!is_http_response(b""));
71    }
72
73    #[test]
74    fn test_is_http() {
75        assert!(is_http(b"GET / HTTP/1.1\r\n"));
76        assert!(is_http(b"HTTP/1.1 200 OK\r\n"));
77        assert!(!is_http(b"SSH-2.0-OpenSSH"));
78        assert!(!is_http(b""));
79    }
80}