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.
24#[must_use]
25pub fn is_http_request(buf: &[u8]) -> bool {
26    HTTP_METHODS.iter().any(|m| buf.starts_with(m))
27}
28
29/// Returns `true` if `buf` begins with the HTTP response status-line prefix
30/// `"HTTP/"`.
31#[must_use]
32pub fn is_http_response(buf: &[u8]) -> bool {
33    buf.starts_with(b"HTTP/")
34}
35
36/// Returns `true` if `buf` looks like any HTTP/1.x traffic (request or
37/// response).
38#[must_use]
39pub fn is_http(buf: &[u8]) -> bool {
40    is_http_request(buf) || is_http_response(buf)
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46
47    #[test]
48    fn test_is_http_request_methods() {
49        assert!(is_http_request(b"GET / HTTP/1.1\r\n"));
50        assert!(is_http_request(b"POST /api HTTP/1.1\r\n"));
51        assert!(is_http_request(b"HEAD / HTTP/1.0\r\n"));
52        assert!(is_http_request(b"PUT /resource HTTP/1.1\r\n"));
53        assert!(is_http_request(b"DELETE /res HTTP/1.1\r\n"));
54        assert!(is_http_request(b"OPTIONS * HTTP/1.1\r\n"));
55        assert!(is_http_request(b"PATCH /res HTTP/1.1\r\n"));
56        assert!(is_http_request(b"CONNECT host:443 HTTP/1.1\r\n"));
57        assert!(is_http_request(b"TRACE / HTTP/1.1\r\n"));
58    }
59
60    #[test]
61    fn test_is_http_request_negative() {
62        assert!(!is_http_request(b"HTTP/1.1 200 OK\r\n"));
63        assert!(!is_http_request(b"INVALID method"));
64        assert!(!is_http_request(b""));
65        assert!(!is_http_request(b"SSH-2.0"));
66    }
67
68    #[test]
69    fn test_is_http_response() {
70        assert!(is_http_response(b"HTTP/1.1 200 OK\r\n"));
71        assert!(is_http_response(b"HTTP/1.0 404 Not Found\r\n"));
72        assert!(!is_http_response(b"GET / HTTP/1.1\r\n"));
73        assert!(!is_http_response(b""));
74    }
75
76    #[test]
77    fn test_is_http() {
78        assert!(is_http(b"GET / HTTP/1.1\r\n"));
79        assert!(is_http(b"HTTP/1.1 200 OK\r\n"));
80        assert!(!is_http(b"SSH-2.0-OpenSSH"));
81        assert!(!is_http(b""));
82    }
83}