firebolt/structures/server/
request.rs

1use std::collections::HashMap;
2use regex::{Regex};
3use std::fmt::{Display, Formatter};
4use core::fmt;
5use crate::server::firebolt::MAX_PAYLOAD_SIZE;
6use crate::structures::common::header::Header;
7use crate::structures::common::method::Method;
8
9#[derive(Debug)]
10pub struct Request {
11    pub body: Option<String>,
12    pub raw_endpoint: String,
13    pub endpoint: String,
14    pub query_string: Option<HashMap<String, String>>,
15    pub headers: Header,
16    pub method: Option<Method>
17}
18
19fn retrieve_endpoint_with_qs(string: &str) -> String {
20    let regex = Regex::new(r"\s(.+)\s").unwrap();
21
22    let mut raw_endpoint = "";
23
24    match regex.find(string) {
25        Some(e) => raw_endpoint = e.as_str().trim(),
26        None => {}
27    }
28
29    let endpoint = raw_endpoint;
30
31    String::from(endpoint)
32}
33
34fn retrieve_endpoint(string: &str) -> String {
35    let regex = Regex::new(r"(&|\?).+").unwrap();
36
37    let raw_endpoint = regex.replace(string, "");
38
39    String::from(raw_endpoint)
40}
41
42
43fn retrieve_qs(string: &str) -> Option<HashMap<String, String>>  {
44    let regex = Regex::new(r"([&?])([A-z0-9]+)=([A-z0-9]+)").unwrap();
45
46    let matches: Vec<&str> = regex.find_iter(string).into_iter().map(|m| m.as_str()).collect();
47
48    let mut qs : HashMap<String, String> = HashMap::new();
49    let mut has_initial_qs: bool = false;
50
51    for match_idx in 0..matches.len() {
52        let mut qs_match = matches[match_idx].to_owned();
53
54        let starting_qs_regex = Regex::new(r"\?").unwrap();
55        let is_match = starting_qs_regex.is_match(&qs_match);
56
57        if is_match {
58            has_initial_qs = true;
59            let raw_match = starting_qs_regex.replace(&qs_match, "").to_string();
60            qs_match = raw_match;
61        } else {
62            let another_qs_regex = Regex::new(r"&").unwrap();
63            let raw_match = another_qs_regex.replace(&qs_match, "").to_string();
64            qs_match = raw_match;
65        }
66        let split: Vec<&str> = qs_match.split('=').collect();
67
68        if split.len() == 2 {
69            qs.insert(split[0].to_owned(), split[1].to_owned());
70        } else if split.len() == 1 {
71            qs.insert(split[0].to_owned(), String::new());
72        }
73    }
74
75    if has_initial_qs {
76       Some(qs)
77    } else {
78        None
79    }
80}
81
82fn retrieve_headers(raw_headers: Vec<&str>) -> Header {
83    let mut headers: Header = Header::new();
84
85    for header in raw_headers.iter() {
86        let split: Vec<&str> = header.split(":").collect();
87        if split.len() == 2 {
88            headers.insert(split[0].to_string(), split[1].trim_start().to_string());
89        } else if split.len() == 1 {
90            headers.insert(split[0].to_string(), String::new());
91        }
92    }
93
94    headers
95}
96
97impl Request {
98    pub fn new(raw_request: Vec<&str>) -> Self {
99        let request_header = raw_request[0];
100        let method = Method::from_str(request_header);
101        let raw_endpoint_with_qs = retrieve_endpoint_with_qs(raw_request[0]);
102        let endpoint = retrieve_endpoint(raw_endpoint_with_qs.as_str());
103        let qs = retrieve_qs(&raw_endpoint_with_qs);
104        let mut raw_headers: Vec<&str> = Vec::new();
105        if raw_request.len() > 1 {
106            raw_headers = raw_request[1..raw_request.len() - 1].iter().filter_map(|h| -> Option<&str> {
107                if *h != "" {
108                    Some(*h)
109                } else {
110                    None
111                }
112            }).collect();
113        }
114
115        let raw_body = raw_request[raw_request.len() - 1].to_owned();
116        let headers = retrieve_headers(raw_headers.to_vec());
117
118        Self { body: Some(raw_body), headers, raw_endpoint: raw_endpoint_with_qs, query_string: qs, endpoint, method }
119    }
120
121    pub fn get_header(&self, key: &str) -> Option<&String> {
122        self.headers.get(key)
123    }
124
125    pub fn request_size(&self) -> usize {
126        let has_payload = self.body.is_none();
127        match self.get_header("Content-Length") {
128            Some(s) => s.parse().unwrap_or(MAX_PAYLOAD_SIZE + 1),
129            None => {
130                if has_payload {
131                    self.body.as_ref().unwrap().bytes().len()
132                } else {
133                    0
134                }
135            }
136        }
137    }
138}
139
140impl Display for Request {
141    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
142        write!(f, "{:?}\n{:?}\n{:?}\nHeaders: {:?}\nBody: {:?}",  self.method.unwrap(), self.endpoint, self.raw_endpoint, self.headers, self.body)
143    }
144}