http_request_target/
lib.rs1extern crate alloc;
6
7use alloc::string::String;
8use core::str;
9
10mod error;
11
12use crate::error::ParseRequestTarget;
13
14#[derive(Debug, Clone)]
16pub enum RequestTarget {
17 Origin(String),
19
20 Absolute(String),
25
26 Authority(String),
31
32 Asterisk,
39}
40
41impl RequestTarget {
42 pub fn try_from_slice(slice: &[u8]) -> Result<Self, ParseRequestTarget> {
44 if slice.is_empty() {
45 return Err(ParseRequestTarget);
46 }
47
48 if slice == b"*" {
49 return Ok(Self::Asterisk);
50 }
51
52 let mut buf = String::new();
53
54 match () {
55 _ if memchr::memchr(b'/', slice).is_none() => {
56 let authority_form = parse_authority_form(slice, &mut buf)?;
57 Ok(Self::Authority(authority_form))
58 }
59
60 _ => {
61 parse_origin_form(slice, &mut buf).inspect_err(|_err| {
62 eprintln!("so far: {buf}");
63 })?;
64
65 Ok(Self::Origin(buf))
66 }
67 }
68 }
69}
70
71fn parse_origin_form(slice: &[u8], buf: &mut String) -> Result<(), ParseRequestTarget> {
84 eprintln!("parse_origin_form");
85
86 match memchr::memchr(b'?', slice) {
87 Some(query_start) => {
89 eprintln!("parse_origin_form with query");
90 parse_path(&slice[..query_start], buf)?;
91 buf.push('?');
92 parse_query(&slice[query_start + 1..], buf)?;
93 }
94
95 None => {
97 eprintln!("parse_origin_form just path");
98 parse_path(slice, buf)?;
99 }
100 };
101
102 Ok(())
103}
104
105fn parse_path(mut slice: &[u8], buf: &mut String) -> Result<(), ParseRequestTarget> {
106 eprintln!("parse_path");
107
108 if slice.is_empty() {
109 return Err(ParseRequestTarget);
110 }
111
112 while !slice.is_empty() {
113 if !slice.starts_with(b"/") {
114 return Err(ParseRequestTarget);
115 }
116
117 buf.push('/');
118 let seg_len = parse_segment(&slice[1..], buf)?;
119
120 slice = &slice[1 + seg_len..];
122 }
123
124 Ok(())
125}
126
127fn parse_segment(slice: &[u8], buf: &mut String) -> Result<usize, ParseRequestTarget> {
128 eprintln!("parse_segment buf={buf}");
129
130 if slice.is_empty() {
131 return Ok(0);
132 }
133
134 let mut iter = slice.iter().peekable();
135
136 let mut i = 0;
137
138 loop {
139 let Some(b) = iter.next_if(|&&b| b != b'/') else {
140 break;
142 };
143
144 let consumed = match b {
145 b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' | b'-' | b'.' | b'_' | b'~' => 1,
147
148 b'%' => {
150 match iter.next() {
152 Some(b'0'..=b'9' | b'A'..=b'F') => {}
153 Some(&b) => {
154 eprintln!("invalid HEXDIGIT at {i} {}", b as char);
155 return Err(ParseRequestTarget);
156 }
157 None => return Err(ParseRequestTarget),
158 }
159
160 match iter.next() {
162 Some(b'0'..=b'9' | b'A'..=b'F') => {}
163 Some(&b) => {
164 eprintln!("invalid HEXDIGIT at {i} {}", b as char);
165 return Err(ParseRequestTarget);
166 }
167 None => return Err(ParseRequestTarget),
168 }
169
170 3
171 }
172
173 b'!' | b'$' | b'&' | b'\'' | b'(' | b')' | b'*' | b'+' | b',' | b';' | b'=' => 1,
175
176 _ => return Err(ParseRequestTarget),
177 };
178
179 i += consumed;
180 }
181
182 let segment = str::from_utf8(&slice[..i]).map_err(|_err| ParseRequestTarget)?;
183 buf.push_str(segment);
184
185 Ok(i)
186}
187
188fn parse_query(slice: &[u8], buf: &mut String) -> Result<(), ParseRequestTarget> {
189 eprintln!("parse_query");
190
191 let mut iter = slice.iter().peekable();
192
193 loop {
194 let Some(b) = iter.next_if(|&&b| b != b'#') else {
195 break;
197 };
198
199 match b {
200 b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' | b'-' | b'.' | b'_' | b'~' => {}
202
203 b'%' => {
205 match iter.next() {
207 Some(b'0'..=b'9' | b'A'..=b'F') => {}
208 Some(&b) => {
209 eprintln!("invalid HEXDIGIT {}", b as char);
210 return Err(ParseRequestTarget);
211 }
212 None => return Err(ParseRequestTarget),
213 }
214
215 match iter.next() {
217 Some(b'0'..=b'9' | b'A'..=b'F') => {}
218 Some(&b) => {
219 eprintln!("invalid HEXDIGIT {}", b as char);
220 return Err(ParseRequestTarget);
221 }
222 None => return Err(ParseRequestTarget),
223 }
224 }
225
226 b'!' | b'$' | b'&' | b'\'' | b'(' | b')' | b'*' | b'+' | b',' | b';' | b'=' => {}
228
229 b'/' | b'?' => {}
231
232 _ => return Err(ParseRequestTarget),
233 }
234 }
235
236 let query = str::from_utf8(slice).map_err(|_err| ParseRequestTarget)?;
237 buf.push_str(query);
238
239 Ok(())
240}
241
242fn parse_authority_form(_slice: &[u8], _buf: &mut String) -> Result<String, ParseRequestTarget> {
243 todo!()
244}