1use super::{HttpParsingError, HttpParsingError::*, parse_headers, parse_version};
2use crate::{Headers, Status};
3
4#[derive(Debug)]
5pub struct Response<'b> {
6 pub http_version: u8,
7 pub status: Status<'b>,
8 pub headers: Headers<'b>,
9 pub buf_offset: usize,
10}
11
12impl<'b> Response<'b> {
13 pub fn parse(buf: &'b [u8]) -> Result<Response<'b>, HttpParsingError> {
14 let start = buf.len();
15 let (http_version, rest) = parse_version(buf)?;
16 let rest = rest.get(1..).ok_or(MalformedStatusLine)?; let (status, rest) = parse_response_status(rest)?;
18 let (headers, rest) = parse_headers(rest)?;
19
20 Ok(Response {
21 http_version,
22 status,
23 headers,
24 buf_offset: start - rest.len(),
25 })
26 }
27}
28
29#[inline]
30fn parse_response_status(buf: &[u8]) -> Result<(Status<'_>, &[u8]), HttpParsingError> {
31 let code = parse_response_status_code(buf)?;
32 if buf.get(3).ok_or(MalformedStatusLine)? != &b' ' {
34 return Err(MalformedStatusLine);
35 }
36
37 let buf = buf.get(4..).ok_or(MalformedStatusLine)?;
38 let mut i = 0;
39 while i + 1 < buf.len() {
40 let c = buf[i];
41 if c == b'\r' && buf[i + 1] == b'\n' {
42 let reason = unsafe { std::str::from_utf8_unchecked(&buf[..i]) };
44 let rest = buf
45 .get(i + 2..) .ok_or(MalformedStatusLine)?;
47 return Ok((Status::borrowed(code, reason), rest));
48 }
49 if !(c == b'\t' || c == b' ' || (0x21..=0x7E).contains(&c)) {
50 return Err(MalformedStatusLine);
52 }
53 i += 1;
54 }
55 Err(MalformedStatusLine)
56}
57
58#[inline]
59fn parse_response_status_code(buf: &[u8]) -> Result<u16, HttpParsingError> {
60 let hundreds = match buf.first().ok_or(MalformedStatusLine)? {
61 x if (*x >= b'0' && *x <= b'9') => *x,
62 _ => return Err(MalformedStatusLine),
63 };
64 let tens = match buf.get(1).ok_or(MalformedStatusLine)? {
65 x if (*x >= b'0' && *x <= b'9') => *x,
66 _ => return Err(MalformedStatusLine),
67 };
68 let ones = match buf.get(2).ok_or(MalformedStatusLine)? {
69 x if (*x >= b'0' && *x <= b'9') => *x,
70 _ => return Err(MalformedStatusLine),
71 };
72
73 Ok((hundreds - b'0') as u16 * 100 + (tens - b'0') as u16 * 10 + (ones - b'0') as u16)
74}