http_net/preface.rs
1//! Detection of the HTTP/2 connection preface (RFC 9113 section 3.4).
2
3/// The 24 bytes an HTTP/2 client sends first when it knows the server
4/// speaks HTTP/2 ("prior knowledge").
5pub(crate) const H2_PREFACE: &[u8; 24] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
6
7/// Whether `input` starts with the HTTP/2 connection preface:
8/// `Some(true)` when the first 24 bytes are the preface, `Some(false)` as
9/// soon as a byte differs from it, and `None` while `input` is a shorter,
10/// so far matching prefix (read more to decide). At most 24 compares.
11///
12/// [`ServerConn`](crate::ServerConn) checks this at the start of every
13/// connection and refuses the preface with
14/// [`HttpError::Http2Preface`](crate::HttpError::Http2Preface); a driver
15/// that accepts prior-knowledge HTTP/2 (behind a trusted proxy only) checks
16/// it first and routes the connection to an HTTP/2 engine.
17///
18/// # Examples
19///
20/// ```
21/// use http_net::is_h2_preface;
22///
23/// assert_eq!(is_h2_preface(b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n\x00\x00"), Some(true));
24/// assert_eq!(is_h2_preface(b"PRI * HTTP/2"), None);
25/// assert_eq!(is_h2_preface(b"GET / HTTP/1.1\r\n"), Some(false));
26/// assert_eq!(is_h2_preface(b""), None);
27/// ```
28#[must_use]
29pub fn is_h2_preface(input: &[u8]) -> Option<bool> {
30 let n = input.len().min(H2_PREFACE.len());
31 if input[..n] != H2_PREFACE[..n] {
32 return Some(false);
33 }
34 if n == H2_PREFACE.len() {
35 Some(true)
36 } else {
37 None
38 }
39}
40
41#[cfg(test)]
42mod tests {
43 use alloc::vec::Vec;
44
45 use super::*;
46
47 #[test]
48 fn test_is_h2_preface_every_prefix_length() {
49 for len in 0..H2_PREFACE.len() {
50 assert_eq!(is_h2_preface(&H2_PREFACE[..len]), None, "{len}");
51 }
52 assert_eq!(is_h2_preface(H2_PREFACE), Some(true));
53 let mut more = H2_PREFACE.to_vec();
54 more.extend_from_slice(b"\x00\x00\x12\x04");
55 assert_eq!(is_h2_preface(&more), Some(true));
56 }
57
58 #[test]
59 fn test_is_h2_preface_any_differing_byte_is_false() {
60 for at in 0..H2_PREFACE.len() {
61 let mut bad: Vec<u8> = H2_PREFACE.to_vec();
62 bad[at] ^= 0x20;
63 assert_eq!(is_h2_preface(&bad), Some(false), "{at}");
64 // Decided as soon as the differing byte is seen.
65 assert_eq!(is_h2_preface(&bad[..=at]), Some(false), "{at}");
66 }
67 assert_eq!(is_h2_preface(b"PRI * HTTP/1.1\r\n\r\n"), Some(false));
68 }
69}