http_tiny/request_target.rs
1use crate::{
2 error::Result,
3 helpers::{ self, BufReadExt, MatchConfig::Trim }
4};
5use std::{
6 mem, slice, collections::BTreeMap, iter::FromIterator, ops::Deref,
7 io::{ BufRead, Write }
8};
9
10
11/// A request target (see <https://tools.ietf.org/html/rfc7230#section-5.3>)
12///
13/// ## Note
14/// We only support the absolute and the asterisk form.
15///
16/// ## Warning
17/// The path parser is pretty simple and basically follows two rules only:
18/// - the path must either be a wildcard (`*`) or must begin with a slash (`/`)
19/// - empty path components are ignored (i.e. `/`, `//` evaluate to `[]` and `/test//path`, `/test//path/` etc. evaluate
20/// to `["test", "path"]`)
21///
22/// Other potentially dangerous components like `..` are treated like normal components and do __not__ cause an error.
23///
24/// ## Warning
25/// The query parser is also pretty simple and basically parses any `key` or `key=` or `key=value` component without
26/// further validation (with the excepttion that the URI escaping must be valid if present).
27///
28/// The following rules apply:
29/// - the query string must begin with a `?`
30/// - keys don't need a value (e.g. `?key0&key1`)
31/// - keys can have an empty value (e.g. `?key0=&key1=`)
32/// - keys can have a non-empty value (e.g. `?key0=value0&key1=value1`
33/// - empty keys or key-value pairs are ignored (i.e. `?&` evaluates to `[]` or `?key0&&key1` evaluates to
34/// `["key0": "", "key1": ""]` or `?=value0&key1=value1&` evaluates to `["key1": "value1"]`)
35#[derive(Debug, Clone)]
36pub enum RequestTarget {
37 /// The requested path is a wildcard ("*" e.g. for `OPTIONS` requests)
38 Wildcard,
39 /// The requested path
40 Absolute {
41 /// The path components
42 path: RequestTargetPath,
43 /// The query string
44 query: QueryString
45 }
46}
47impl RequestTarget {
48 /// Creates a new wildcard request target
49 pub const fn new_wildcard() -> Self {
50 Self::Wildcard
51 }
52 /// Creates a new request target from the given path and query components
53 pub const fn new_absolute(path: RequestTargetPath, query: QueryString) -> Self {
54 Self::Absolute { path, query }
55 }
56 /// Loads a request target
57 pub fn read<T>(source: &mut T) -> Result<Self> where T: BufRead {
58 // Read the URI
59 let this = match source.peek_one()? {
60 Some(b'/') => {
61 // Read path and query
62 let path = source.read_word("?", [Trim])?;
63 let query = source.read_all([])?;
64
65 // Init self
66 Self::Absolute {
67 path: RequestTargetPath::read(&mut helpers::memreader(path))?,
68 query: QueryString::read(&mut helpers::memreader(query))?
69 }
70 },
71 Some(b'*') => Self::Wildcard,
72 first => return Err(einval!("Invalid request target: {:?}", first))
73 };
74 Ok(this)
75 }
76 /// Writes the request target
77 pub fn write_all<T>(&self, output: &mut T) -> Result where T: Write {
78 match self {
79 Self::Absolute { path, query } => {
80 path.write_all(output)?;
81 query.write_all(output)?;
82 },
83 Self::Wildcard => write!(output, "*")?,
84 }
85 Ok(())
86 }
87}
88
89
90/// An absolute path as request target
91///
92/// ## Warning
93/// The path parser is pretty simple and basically follows two rules only:
94/// - the path must either be a wildcard (`*`) or must begin with a slash (`/`)
95/// - empty path components are ignored (i.e. `/` or `//` etc. evaluate to `[]` and `/test//path` or `/test//path/` etc.
96/// evaluate to `["test", "path"]`)
97///
98/// Other potentially dangerous components like `..` are treated like normal components and __will not__ cause an error.
99#[derive(Debug, Clone, Default)]
100pub struct RequestTargetPath {
101 /// The path components
102 components: Vec<Vec<u8>>
103}
104impl RequestTargetPath {
105 /// Creates a new empty absolute path
106 pub const fn new() -> Self {
107 Self { components: Vec::new() }
108 }
109
110 /// Pushes `component` to `self`
111 pub fn push<T>(&mut self, component: T) where T: Into<Vec<u8>> {
112 self.components.push(component.into());
113 }
114
115 /// Loads an absolute string
116 pub fn read<T>(source: &mut T) -> Result<Self> where T: BufRead {
117 // Create self
118 let mut this = Self { components: Vec::new() };
119
120 // Read the path components
121 let mut component = Vec::new();
122 while source.peek_one()?.is_some() {
123 // Read the next byte
124 let mut next = 0;
125 source.read_exact(slice::from_mut(&mut next))?;
126
127 // Push the next component
128 match next {
129 b'/' if component.is_empty() => (/* no-op */),
130 b'/' => this.components.push(mem::take(&mut component)),
131 other => component.push(other)
132 }
133 }
134 Ok(this)
135 }
136
137 /// Writes the absolute path
138 pub fn write_all<T>(&self, output: &mut T) -> Result where T: Write {
139 // Write a single slash if there are no path components
140 if self.components.is_empty() {
141 output.write_all(b"/")?;
142 return Ok(());
143 }
144
145 // Write the components
146 for component in self.components.iter() {
147 output.write_all(b"/")?;
148 output.write_all(component)?;
149 }
150 Ok(())
151 }
152}
153impl<T> FromIterator<T> for RequestTargetPath where T: Into<Vec<u8>> {
154 fn from_iter<I: IntoIterator<Item = T>>(components: I) -> Self {
155 let components = components.into_iter()
156 .map(|c| c.into())
157 .collect();
158 Self { components }
159 }
160}
161impl IntoIterator for RequestTargetPath {
162 type Item = <Vec<Vec<u8>> as IntoIterator>::Item;
163 type IntoIter = <Vec<Vec<u8>> as IntoIterator>::IntoIter;
164
165 fn into_iter(self) -> Self::IntoIter {
166 self.components.into_iter()
167 }
168}
169
170
171/// A query string
172///
173/// ## Warning
174/// The query parser is pretty simple and basically parses any `key` or `key=` or `key=value` component without further
175/// validation.
176///
177/// The following rules apply:
178/// - the query string _MUST NOT_ begin with a `?` – it's not a bug, it's a feature: this allows the parser to parse query
179/// query strings in the body (e.g. from HTML forms)
180/// - keys don't need a value (i.e. `key0&key1` is valid)
181/// - keys can have an empty value (i.e. `key0=&key1=` is valid)
182/// - keys can have a non-empty value (i.e. `key0=value0&key1=value1` is valid)
183/// - empty keys/key-value pairs are ignored (i.e. `&` evaluates to `[]`, `key0&&key1` evaluates to
184/// `["key0": "", "key1": ""]` and `=value0&key1=value1&` evaluates to `["key1": "value1"]`)
185#[derive(Debug, Clone, Default)]
186pub struct QueryString {
187 /// The key-value fields of the query string
188 fields: BTreeMap<Vec<u8>, Vec<u8>>
189}
190impl QueryString {
191 /// Creates a new header field map
192 pub fn new() -> Self {
193 Self { fields: BTreeMap::new() }
194 }
195
196 /// Gets the value for the field with the given name
197 pub fn get<T>(&self, name: T) -> Option<&[u8]> where T: AsRef<[u8]> {
198 self.fields.get(name.as_ref()).map(|s| s.as_ref())
199 }
200 /// Sets the value for a fiels with the given name
201 pub fn set<A, B>(&mut self, name: A, value: B) where A: Into<Vec<u8>>, B: Into<Vec<u8>> {
202 self.fields.insert(name.into(), value.into());
203 }
204
205 /// Reads a query string
206 pub fn read<T>(source: &mut T) -> Result<Self> where T: BufRead {
207 // Parse the query components
208 let mut fields = BTreeMap::new();
209 while source.peek_one()?.is_some() {
210 // Read split the pair
211 let pair = source.read_word("&", [Trim])?;
212 let mut pair = helpers::memreader(pair);
213
214 // Get key and value
215 let key = pair.read_word("=", [Trim])?;
216 if !key.is_empty() {
217 let value = pair.read_all([])?;
218 fields.insert(key, value);
219 }
220 }
221 Ok(Self { fields })
222 }
223 /// Writes the query string
224 pub fn write_all<T>(&self, output: &mut T) -> Result where T: Write {
225 for (nth_pair, (key, value)) in self.fields.iter().enumerate() {
226 // Write delimiter
227 match nth_pair {
228 0 => output.write_all(b"?")?,
229 _ => output.write_all(b"&")?
230 }
231
232 // Write key and value
233 output.write_all(key)?;
234 if !value.is_empty() {
235 output.write_all(b"=")?;
236 output.write_all(value)?;
237 }
238 }
239 Ok(())
240 }
241}
242impl Deref for QueryString {
243 type Target = BTreeMap<Vec<u8>, Vec<u8>>;
244
245 fn deref(&self) -> &Self::Target {
246 &self.fields
247 }
248}
249impl<K, V> FromIterator<(K, V)> for QueryString where K: Into<Vec<u8>>, V: Into<Vec<u8>> {
250 fn from_iter<T: IntoIterator<Item = (K, V)>>(pairs: T) -> Self {
251 let fields = pairs.into_iter()
252 .map(|(k, v)| (k.into(), v.into()))
253 .collect();
254 Self { fields }
255 }
256}
257impl IntoIterator for QueryString {
258 type Item = <BTreeMap<Vec<u8>, Vec<u8>> as IntoIterator>::Item;
259 type IntoIter = <BTreeMap<Vec<u8>, Vec<u8>> as IntoIterator>::IntoIter;
260
261 fn into_iter(self) -> Self::IntoIter {
262 self.fields.into_iter()
263 }
264}