wireforge_app/http/
request.rs1use super::headers::HeaderIter;
4
5#[derive(Debug, Clone)]
7pub struct HttpRequest<'a> {
8 buf: &'a [u8],
9 method_end: usize,
10 uri_end: usize,
11 version_end: usize,
12 headers_start: usize,
13 body_start: usize,
14}
15
16impl<'a> HttpRequest<'a> {
17 pub fn parse(buf: &'a [u8]) -> Option<Self> {
18 let request_line_end = buf.windows(2).position(|w| w == b"\r\n")?;
20 let line = &buf[..request_line_end];
21
22 let sp1 = line.iter().position(|&b| b == b' ')?;
23 let sp2 = line[sp1 + 1..].iter().position(|&b| b == b' ')?;
24 let sp2 = sp1 + 1 + sp2;
25
26 let headers_start = request_line_end + 2;
27 let body_start = find_body_start(&buf[headers_start..]).map(|p| headers_start + p);
28
29 Some(Self {
30 buf,
31 method_end: sp1,
32 uri_end: sp2,
33 version_end: request_line_end,
34 headers_start,
35 body_start: body_start.unwrap_or(buf.len()),
36 })
37 }
38
39 pub fn method(&self) -> &str { core::str::from_utf8(&self.buf[..self.method_end]).unwrap_or("") }
40 pub fn uri(&self) -> &str { core::str::from_utf8(&self.buf[self.method_end + 1..self.uri_end]).unwrap_or("") }
41 pub fn version(&self) -> &str { core::str::from_utf8(&self.buf[self.uri_end + 1..self.version_end]).unwrap_or("") }
42 pub fn headers(&self) -> HeaderIter<'a> { HeaderIter::new(&self.buf[self.headers_start..self.body_start]) }
43 pub fn body(&self) -> &[u8] { &self.buf[self.body_start..] }
44}
45
46fn find_body_start(data: &[u8]) -> Option<usize> {
47 data.windows(4).position(|w| w == b"\r\n\r\n").map(|p| p + 4)
48}