es_htmlform/
value.rs

1use std::fmt;
2use std::str::FromStr;
3use std::error::Error;
4use std::ops::Deref;
5use std::collections::HashMap;
6
7use crate::ValidationError;
8
9/// Error to denote `urldecode()` fails.
10#[derive(Debug, PartialEq)]
11pub struct UrlDecodingError<'a> {
12    message: &'a str,
13}
14
15impl <'a> UrlDecodingError<'a> {
16    pub fn new(message: &'a str) -> UrlDecodingError {
17        UrlDecodingError {
18            message,
19        }
20    }
21}
22
23impl <'a> fmt::Display for UrlDecodingError<'a> {
24    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25        write!(f, "{}", self.message)
26    }
27}
28
29impl <'a> Error for UrlDecodingError<'a> {
30    fn description(&self) -> &str {
31        &self.message
32    }
33}
34
35impl <'a> From<std::str::Utf8Error> for UrlDecodingError<'a> {
36    fn from(_e: std::str::Utf8Error) -> UrlDecodingError<'a> {
37        UrlDecodingError {
38            message: "invalid encoding error sequence",
39        }
40    }
41}
42
43impl <'a> From<hex::FromHexError> for UrlDecodingError<'a> {
44    fn from(_e: hex::FromHexError) -> UrlDecodingError<'a> {
45        UrlDecodingError {
46            message: "invalid encoding sequence",
47        }
48    }
49}
50
51impl <'a> From<std::num::ParseIntError> for UrlDecodingError<'a> {
52    fn from(_e: std::num::ParseIntError) -> UrlDecodingError<'a> {
53        UrlDecodingError {
54            message: "invalid encoding character",
55        }
56    }
57}
58
59/// Decode url-encoded bytes to a UTF-8 `String`.
60pub fn urldecode(input: &[u8]) -> Result<String, UrlDecodingError<'static>> {
61    let plus: u8 = 43;
62    let percent: u8 = 37;
63    let mut out: Vec<u8> = Vec::new();
64    let mut i = 0;
65    while i < input.len() {
66        let chr: u8 = input[i];
67        let charcode: u8;
68        i += 1;
69        if chr == percent {
70            if input.len() < i + 2 {
71                return Err(
72                    UrlDecodingError::new("unexpected end of input"));
73            }
74            // we now have 2 ascii chars (u8), which should be numbers,
75            // depicting 2 character a hexdecimal number when combined,
76            // which form the ascii value of 1 char (so another u8, unicode
77            // is encoded as multiple u8s in a row, each with a separate %,
78            // so if we handle the chars 1 at a time, we should end up with
79            // a valid utf-8 sequence, assuming the character encoding is
80            // utf-8 (XXX and what if it isn't? or is it always?))
81            // XXX this is rather ugly... :|
82            charcode = hex::decode(
83                &format!(
84                    "{}{}", input[i] as char, input[i + 1] as char))?[0];
85            i += 2;
86        } else if chr == plus {
87            // stupid + signs in GET to replace spaces
88            charcode = 32 // space
89        } else {
90            charcode = chr;
91        }
92        out.push(charcode);
93    }
94    Ok(std::str::from_utf8(&out)?.to_string())
95}
96
97/// A set of form values. Note that values are always stored as lists of
98/// strings, similar to how urlencoded form data is treated (no type
99/// information, any field may appear more than once and there doesn't need
100/// to be a value).
101#[derive(Debug, PartialEq, Clone)]
102pub struct ValueMap {
103    values: HashMap<String, Vec<Value>>,
104}
105
106impl ValueMap {
107    pub fn new(values: HashMap<String, Vec<Value>>) -> ValueMap {
108        ValueMap {
109            values,
110        }
111    }
112
113    pub fn from_vec(vec: Vec<(&str, Vec<&str>)>) -> ValueMap {
114        let mut values: HashMap<String, Vec<Value>> = HashMap::new();
115        for (name, strvalues) in vec {
116            values.insert(
117                String::from(name),
118                strvalues.iter().map(|v| Value::new(v)).collect());
119        }
120        ValueMap {
121            values,
122        }
123    }
124
125    pub fn values(&self, name: &str) -> Option<&Vec<Value>> {
126        self.values.get(name)
127    }
128
129    pub fn from_urlencoded(input: &[u8]) ->
130            Result<ValueMap, UrlDecodingError> {
131        let mut values: HashMap<String, Vec<Value>> = HashMap::new();
132        let eq: u8 = 61;
133        let amp: u8 = 38;
134        let mut bkey = vec![];
135        let mut bvalue = vec![];
136        let mut in_value = false;
137        for chr in input {
138            let chr = chr.clone();
139            if chr == eq {
140                if !in_value {
141                    in_value = true;
142                } else {
143                    return Err(
144                        UrlDecodingError::new("unexpected = character"));
145                }
146            } else if chr == amp {
147                let key = urldecode(&bkey)?;
148                let value = urldecode(&bvalue)?;
149                if !bvalue.is_empty() {
150                    if values.contains_key(&key) {
151                        let keyvalues = values.get_mut(&key).unwrap();
152                        keyvalues.push(Value::new(&value));
153                    } else {
154                        values.insert(key, vec![Value::new(&value)]);
155                    }
156                } else {
157                    values.insert(key, vec![]);
158                }
159                bkey.truncate(0);
160                bvalue.truncate(0);
161                in_value = false;
162            } else if in_value {
163                bvalue.push(chr);
164            } else {
165                bkey.push(chr);
166            }
167        }
168        // there should now be 1 key (or pair) left in the buffers
169        if !bkey.is_empty() {
170            let key = urldecode(&bkey)?;
171            let value = urldecode(&bvalue)?;
172            if !bvalue.is_empty() {
173                if values.contains_key(&key) {
174                    let keyvalues = values.get_mut(&key).unwrap();
175                    keyvalues.push(Value::new(&value));
176                } else {
177                    values.insert(key, vec![Value::new(&value)]);
178                }
179            } else {
180                values.insert(key, vec![]);
181            }
182        }
183        let map = ValueMap {
184            values,
185        };
186        Ok(map)
187    }
188}
189
190impl Deref for ValueMap {
191    type Target = HashMap<String, Vec<Value>>;
192
193    fn deref(&self) -> &Self::Target {
194        &self.values
195    }
196}
197
198/// A single form value, stored as `String`. May be empty in some cases,
199/// which results in the value being ignored in validation.
200#[derive(Debug, PartialEq, Clone)]
201pub struct Value(String);
202
203impl Value {
204    pub fn new(value: &str) -> Value {
205        Value(value.to_string())
206    }
207
208    pub fn as_string(&self) -> String {
209        self.0.clone()
210    }
211
212    pub fn parse<T>(&self) -> Result<T, ValidationError>
213            where T: FromStr {
214        match self.0.parse() {
215            Ok(value) => Ok(value),
216            Err(_) => Err(ValidationError::new(
217                &format!("cannot convert {:?}", self.0))),
218        }
219    }
220}
221
222// Deref
223impl Deref for Value {
224    type Target = String;
225
226    fn deref(&self) -> &Self::Target {
227        &self.0
228    }
229}