Skip to main content

sark_core/http/codec/decode/
request_head.rs

1use std::ops::Range;
2
3#[derive(Clone, Copy, Debug)]
4pub struct ParsedRequestHead<'a> {
5    pub method: &'a [u8],
6    pub target: &'a [u8],
7    pub version: &'a [u8],
8    pub headers_start: usize,
9}
10
11impl ParsedRequestHead<'_> {
12    pub fn parse(buf: &[u8]) -> Option<ParsedRequestHead<'_>> {
13        let start_line_end = memchr::memchr(b'\r', buf)?;
14        if start_line_end + 1 >= buf.len() || buf[start_line_end + 1] != b'\n' {
15            return None;
16        }
17        let line = &buf[..start_line_end];
18        if line.len() < 9 {
19            return None;
20        }
21        let version_start = line.len() - 8;
22        if version_start == 0 || line[version_start - 1] != b' ' {
23            return None;
24        }
25        let method_end = line.iter().position(|&byte| byte == b' ')?;
26        if method_end == 0 || method_end >= version_start - 1 {
27            return None;
28        }
29        let method = &line[..method_end];
30        let target = &line[method_end + 1..version_start - 1];
31        let version = &line[version_start..];
32        if target.is_empty()
33            || (version != b"HTTP/1.1" && version != b"HTTP/1.0")
34            || !crate::http::scan::request_target_is_valid(target)
35        {
36            return None;
37        }
38        Some(ParsedRequestHead {
39            method,
40            target,
41            version,
42            headers_start: start_line_end + 2,
43        })
44    }
45
46    pub fn head_end(bytes: &[u8]) -> Option<Range<usize>> {
47        memchr::memmem::find(bytes, b"\r\n\r\n").map(|s| s..s + 4)
48    }
49}