Skip to main content

rust_web_server/url/path/
mod.rs

1use std::collections::HashMap;
2use std::fmt::{Display, Formatter};
3use crate::symbol::SYMBOL;
4
5#[cfg(test)]
6mod tests;
7
8pub struct UrlPath;
9
10#[derive(Clone, Debug)]
11pub struct Part {
12    pub is_static: bool,
13    pub name: Option<String>,
14    pub value: Option<String>,
15    pub static_pattern: Option<String>
16}
17
18impl Display for Part {
19    fn fmt(&self, _f: &mut Formatter<'_>) -> std::fmt::Result {
20        println!("{:?} {:?} {:?} {:?}", &self.is_static, &self.name, &self.value, &self.static_pattern);
21        Ok(())
22    }
23}
24
25impl UrlPath {
26    pub fn extract_parts_from_pattern(_pattern: &str) -> Result<Vec<Part>, String>{
27        let mut part_list: Vec<Part> = vec![];
28        let mut _buffer: Vec<char> = vec![];
29        let mut previous_char: Option<char> = None;
30        let mut is_opened_token = false;
31
32        for _char in _pattern.chars() {
33            if _char.is_whitespace() || _char.is_control() {
34                return Err("path contains control character or whitespace".to_string())
35            }
36
37            _buffer.push(_char);
38
39            if _char == '[' && previous_char.is_some() && previous_char.unwrap() == '[' {
40                if is_opened_token {
41                    return Err("at least one extra [ char".to_string());
42                }
43                is_opened_token = true;
44                if _buffer.len() != 0 && _buffer.len() >= 2 {
45                    let without_square_brackets = _buffer.len() - 2;
46                    let pattern : String = _buffer[0..without_square_brackets].into_iter().collect();
47                    if pattern.len() > 0 {
48                        let part = Part {
49                            is_static: true,
50                            name: None,
51                            value: None,
52                            static_pattern: Some(pattern),
53                        };
54                        part_list.push(part);
55                    }
56                }
57                _buffer = vec![];
58
59                let previous_part_is_token = part_list.last().is_some() && part_list.last().unwrap().is_static == false;
60                if previous_part_is_token {
61                    return Err("two consecutive tokens one after another".to_string())
62                }
63            }
64
65            if _char == ']' && previous_char.is_some() && previous_char.unwrap() == ']' {
66                is_opened_token = false;
67                let without_square_brackets = _buffer.len() - 2;
68                let key : String = _buffer[0..without_square_brackets].into_iter().collect();
69                let part = Part {
70                    is_static: false,
71                    name: Some(key),
72                    value: None,
73                    static_pattern: None,
74                };
75                part_list.push(part);
76
77                _buffer = vec![];
78
79            }
80
81            previous_char = Some(_char.clone());
82        }
83
84        if _buffer.len() != 0 {
85            let static_ending : String = _buffer.into_iter().collect();
86
87            let part = Part {
88                is_static: true,
89                name: None,
90                value: None,
91                static_pattern: Some(static_ending),
92            };
93            part_list.push(part);
94            _buffer = vec![];
95        }
96
97        Ok(part_list)
98    }
99
100    pub fn is_matching(_path: &str, _pattern: &str) -> Result<bool, String> {
101        let is_matching = true;
102        let is_not_matching = false;
103
104        for char in _path.chars() {
105            if char.is_whitespace() || char.is_control() {
106                return Err("path contains control character or whitespace".to_string());
107            }
108        }
109
110        let boxed_parts = UrlPath::extract_parts_from_pattern(_pattern);
111        if boxed_parts.is_err() {
112            return Err(boxed_parts.err().unwrap());
113        }
114
115        let parts : Vec<Part> = boxed_parts.unwrap();
116        let mut populated_parts : Vec<Part> = vec![];
117
118        let mut url_path = _path.to_string();
119        let number_of_parts = parts.len();
120        println!("number_of_parts, {}", number_of_parts);
121
122        for (index, part) in parts.iter().enumerate() {
123            let part = part;
124            println!("1, {}", part);
125            let is_there_next_part = index < number_of_parts - 1;
126            if part.is_static {
127                let static_pattern = part.static_pattern.clone().unwrap();
128                if !url_path.starts_with(&static_pattern) {
129                    return Ok(is_not_matching)
130                }
131
132                let _part = part.clone();
133                populated_parts.push(_part);
134
135                url_path = url_path.replacen(static_pattern.as_str(), SYMBOL.empty_string, 1);
136            } else {
137                if !is_there_next_part {
138                    let _part = Part {
139                        is_static: false,
140                        name: part.name.clone(),
141                        value: Some(url_path.clone()),
142                        static_pattern: None,
143                    };
144                    let _part = part.clone();
145                    populated_parts.push(_part);
146
147                    println!("2, {}", part);
148
149                } else {
150                    let next_part = parts.get(index + 1).unwrap();
151                    println!("3, {}", part);
152                    let delimiter = next_part.static_pattern.clone().unwrap().chars().next().unwrap();
153                    let occurence = url_path.find(delimiter);
154                    if occurence.is_none() {
155                        return Ok(is_not_matching)
156                    }
157                    let occurence_place = occurence.unwrap();
158                    let token = url_path[..occurence_place].to_string();
159                    let _part = Part {
160                        is_static: false,
161                        name: part.name.clone(),
162                        value: Some(token.clone()),
163                        static_pattern: None,
164                    };
165                    println!("4, {}", part);
166
167                    populated_parts.push(_part.clone());
168
169                    url_path = url_path.chars().skip(occurence_place).collect();
170
171                    println!("123")
172                }
173            }
174        }
175        
176        Ok(is_matching)
177    }
178
179    pub fn extract(_path: &str, _pattern: &str) -> Result<HashMap<String, String>, String> {
180        //TODO
181
182        let boxed_parts = UrlPath::extract_parts_from_pattern(_pattern);
183        if boxed_parts.is_err() {
184            return Err(boxed_parts.err().unwrap());
185        }
186
187        let parts : Vec<Part> = boxed_parts.unwrap();
188        let mut resulting_parts : Vec<Part> = vec![];
189
190        let mut path = _path.to_string();
191        let mut previous_part: Option<Part> = None;
192        let number_of_parts = parts.len();
193        for (index, part) in parts.iter().enumerate() {
194            println!("path: {:?}", path);
195            println!("part: {:?} {:?} {:?}", part.name, part.value, part.static_pattern);
196
197            if part.is_static {
198                if previous_part.is_some() {
199                    let unboxed_previous_part = previous_part.clone().unwrap();
200                    println!("previous_part: {:?} {:?} {:?}", unboxed_previous_part.name, unboxed_previous_part.value, unboxed_previous_part.static_pattern);
201
202                    // read until first char of static pattern
203                    // add to map
204                    let static_pattern = part.static_pattern.clone().unwrap();
205                    let first_char_to_stop = static_pattern.chars().next().unwrap();
206                    let mut buffer = vec![];
207
208                    for char in path.clone().chars() {
209                        if char == first_char_to_stop {
210                            println!("found {:?}", char);
211                            // read the rest of static pattern
212                            break;
213                        } else {
214                            let removed_char = path.remove(0);
215                            buffer.push(removed_char);
216                            println!("removed char: {:?}", removed_char);
217                        }
218                    }
219                    let token : String = buffer.iter().collect();
220                    println!("dynamic part {:?}", token);
221                    let mut processed_part = previous_part.clone().unwrap();
222                    processed_part.value = Some(token);
223                    resulting_parts.push(processed_part.clone());
224                    println!("{:?}", processed_part)
225                } else {
226                    // read the rest of static pattern
227                }
228
229                let static_pattern = part.static_pattern.clone().unwrap();
230                // println!("static pattern {:?}", static_pattern);
231                // println!("path {:?}", path);
232                path = path.strip_prefix(static_pattern.as_str()).unwrap().to_string();
233            } else {
234                // continue, unless the part is last,
235                // if so read to the end of path and add to map
236                if number_of_parts == index + 1 {
237                    // let mut buffer = vec![];
238
239                    // println!("!path {:?}", path);
240                    let mut processed_part = part.clone();
241                    processed_part.value = Some(path.clone());
242                    resulting_parts.push(processed_part.clone());
243                    println!("{:?}", processed_part)
244                }
245
246            }
247
248            previous_part = Some(part.clone());
249        }
250
251        let mut map = HashMap::new();
252        for part in resulting_parts {
253            let key = part.name.unwrap();
254            let value = part.value.unwrap();
255
256            map.insert(key, value);
257        }
258
259        Ok(map)
260    }
261
262    pub fn build(_params: HashMap<String, String>, _pattern: &str) -> Result<String, String> {
263        let boxed_parts = UrlPath::extract_parts_from_pattern(_pattern);
264        if boxed_parts.is_err() {
265            return Err(boxed_parts.err().unwrap());
266        }
267
268        let parts : Vec<Part> = boxed_parts.unwrap();
269
270
271        let mut strings_array = vec![];
272        for part  in parts {
273            if part.is_static {
274                strings_array.push(part.static_pattern.unwrap())
275            } else {
276                let key = part.name.unwrap().to_string();
277                let boxed_value = _params.get(key.as_str());
278                if boxed_value.is_none() {
279                    return Err(format!("specified parameter {} is not found", key))
280                }
281                let value = boxed_value.unwrap();
282                strings_array.push(value.clone());
283            }
284        }
285        let populated_pattern : String = strings_array.join(SYMBOL.empty_string);
286
287        Ok(populated_pattern)
288
289    }
290}