1 use winnow::combinator::seq;
2 use winnow::prelude::*;
3 use winnow::{ascii::line_ending, combinator::repeat, token::take_while};
4 
5 pub type Stream<'i> = &'i [u8];
6 
7 #[rustfmt::skip]
8 #[derive(Debug)]
9 #[allow(dead_code)]
10 pub struct Request<'a> {
11   method:  &'a [u8],
12   uri:     &'a [u8],
13   version: &'a [u8],
14 }
15 
16 #[derive(Debug)]
17 #[allow(dead_code)]
18 pub struct Header<'a> {
19     name: &'a [u8],
20     value: Vec<&'a [u8]>,
21 }
22 
parse(data: &[u8]) -> Option<Vec<(Request<'_>, Vec<Header<'_>>)>>23 pub fn parse(data: &[u8]) -> Option<Vec<(Request<'_>, Vec<Header<'_>>)>> {
24     let mut buf = data;
25     let mut v = Vec::new();
26     loop {
27         match request(&mut buf) {
28             Ok(r) => {
29                 v.push(r);
30 
31                 if buf.is_empty() {
32                     //println!("{}", i);
33                     break;
34                 }
35             }
36             Err(e) => {
37                 println!("error: {:?}", e);
38                 return None;
39             }
40         }
41     }
42 
43     Some(v)
44 }
45 
request<'s>(input: &mut Stream<'s>) -> PResult<(Request<'s>, Vec<Header<'s>>)>46 fn request<'s>(input: &mut Stream<'s>) -> PResult<(Request<'s>, Vec<Header<'s>>)> {
47     let req = request_line(input)?;
48     let h = repeat(1.., message_header).parse_next(input)?;
49     let _ = line_ending.parse_next(input)?;
50 
51     Ok((req, h))
52 }
53 
request_line<'s>(input: &mut Stream<'s>) -> PResult<Request<'s>>54 fn request_line<'s>(input: &mut Stream<'s>) -> PResult<Request<'s>> {
55     seq!( Request {
56         method: take_while(1.., is_token),
57         _: take_while(1.., is_space),
58         uri: take_while(1.., is_not_space),
59         _: take_while(1.., is_space),
60         version: http_version,
61         _: line_ending,
62     })
63     .parse_next(input)
64 }
65 
http_version<'s>(input: &mut Stream<'s>) -> PResult<&'s [u8]>66 fn http_version<'s>(input: &mut Stream<'s>) -> PResult<&'s [u8]> {
67     let _ = "HTTP/".parse_next(input)?;
68     let version = take_while(1.., is_version).parse_next(input)?;
69 
70     Ok(version)
71 }
72 
message_header_value<'s>(input: &mut Stream<'s>) -> PResult<&'s [u8]>73 fn message_header_value<'s>(input: &mut Stream<'s>) -> PResult<&'s [u8]> {
74     let _ = take_while(1.., is_horizontal_space).parse_next(input)?;
75     let data = take_while(1.., till_line_ending).parse_next(input)?;
76     let _ = line_ending.parse_next(input)?;
77 
78     Ok(data)
79 }
80 
message_header<'s>(input: &mut Stream<'s>) -> PResult<Header<'s>>81 fn message_header<'s>(input: &mut Stream<'s>) -> PResult<Header<'s>> {
82     seq!(Header {
83         name: take_while(1.., is_token),
84         _: ':',
85         value: repeat(1.., message_header_value),
86     })
87     .parse_next(input)
88 }
89 
90 #[rustfmt::skip]
91 #[allow(clippy::match_same_arms)]
92 #[allow(clippy::match_like_matches_macro)]
is_token(c: u8) -> bool93 fn is_token(c: u8) -> bool {
94   match c {
95     128..=255 => false,
96     0..=31    => false,
97     b'('      => false,
98     b')'      => false,
99     b'<'      => false,
100     b'>'      => false,
101     b'@'      => false,
102     b','      => false,
103     b';'      => false,
104     b':'      => false,
105     b'\\'     => false,
106     b'"'      => false,
107     b'/'      => false,
108     b'['      => false,
109     b']'      => false,
110     b'?'      => false,
111     b'='      => false,
112     b'{'      => false,
113     b'}'      => false,
114     b' '      => false,
115     _         => true,
116   }
117 }
118 
is_version(c: u8) -> bool119 fn is_version(c: u8) -> bool {
120     c.is_ascii_digit() || c == b'.'
121 }
122 
till_line_ending(c: u8) -> bool123 fn till_line_ending(c: u8) -> bool {
124     c != b'\r' && c != b'\n'
125 }
126 
is_space(c: u8) -> bool127 fn is_space(c: u8) -> bool {
128     c == b' '
129 }
130 
is_not_space(c: u8) -> bool131 fn is_not_space(c: u8) -> bool {
132     c != b' '
133 }
134 
is_horizontal_space(c: u8) -> bool135 fn is_horizontal_space(c: u8) -> bool {
136     c == b' ' || c == b'\t'
137 }
138