Skip to main content

zerodds_http2/
preface.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright 2026 ZeroDDS Contributors
3
4//! Connection-Preface — RFC 9113 §3.4.
5//!
6//! Spec §3.5: Client-Preface ist 24 Bytes:
7//! `PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n`.
8
9use crate::error::Http2Error;
10
11/// HTTP/2-Client-Connection-Preface (RFC 9113 §3.4).
12pub const CLIENT_PREFACE: &[u8] = b"PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n";
13
14/// Prueft, ob die ersten 24 Bytes des Inputs der Spec-Preface
15/// entsprechen.
16///
17/// # Errors
18/// `BadPreface` wenn das Praefix nicht passt; `ShortFrameHeader` wenn
19/// weniger als 24 Bytes verfuegbar sind.
20pub fn check_preface(input: &[u8]) -> Result<(), Http2Error> {
21    if input.len() < CLIENT_PREFACE.len() {
22        return Err(Http2Error::ShortFrameHeader);
23    }
24    if &input[..CLIENT_PREFACE.len()] != CLIENT_PREFACE {
25        return Err(Http2Error::BadPreface);
26    }
27    Ok(())
28}
29
30#[cfg(test)]
31#[allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
32mod tests {
33    use super::*;
34
35    #[test]
36    fn correct_preface_passes() {
37        check_preface(CLIENT_PREFACE).unwrap();
38    }
39
40    #[test]
41    fn preface_with_trailing_data_passes() {
42        let mut buf = alloc::vec::Vec::new();
43        buf.extend_from_slice(CLIENT_PREFACE);
44        buf.extend_from_slice(&[0; 100]);
45        check_preface(&buf).unwrap();
46    }
47
48    #[test]
49    fn short_input_rejected() {
50        assert_eq!(check_preface(b"PRI"), Err(Http2Error::ShortFrameHeader));
51    }
52
53    #[test]
54    fn wrong_preface_rejected() {
55        let mut bad = CLIENT_PREFACE.to_vec();
56        bad[0] = b'X';
57        assert_eq!(check_preface(&bad), Err(Http2Error::BadPreface));
58    }
59
60    #[test]
61    fn preface_length_is_24_bytes() {
62        assert_eq!(CLIENT_PREFACE.len(), 24);
63    }
64}