sark_core/http/codec/decode/
request_head.rs1use 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::simd::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}