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}