Skip to main content

br_web_server/
url.rs

1use std::collections::HashMap;
2
3#[derive(Debug, Clone)]
4pub struct Url {
5    #[allow(dead_code)]
6    pub url: String,
7    #[allow(dead_code)]
8    pub scheme: String,
9    pub host: String,
10    pub port: u16,
11    pub path_query: String,
12    #[allow(dead_code)]
13    pub path: String,
14    query: String,
15    query_params: HashMap<String, String>,
16}
17
18impl Url {
19    pub fn parse(url: &str) -> Result<Self, String> {
20        let uri = url.to_string();
21
22        let (uri, query) = match uri.find("?") {
23            Some(idx) => (&uri[..idx], &uri[idx + 1..]),
24            None => (uri.as_str(), ""),
25        };
26
27        let scheme = match uri.find(":") {
28            None => return Err("Invalid Scheme Not Found".to_string()),
29            Some(e) => uri[..e].to_string(),
30        };
31
32        let uri = uri
33            .trim_start_matches(scheme.as_str())
34            .trim_start_matches(":")
35            .trim_start_matches("//");
36
37        let (host_port, path) = match uri.find("/") {
38            Some(idx) => (&uri[..idx], &uri[idx..]),
39            None => (uri, "/"),
40        };
41
42        let path_query = if query.is_empty() {
43            path.to_string()
44        } else {
45            format!("{}?{}", path, query)
46        };
47
48        let (host, port) = match host_port.rsplit_once(':') {
49            Some((h, p_str)) if !h.is_empty() && !p_str.is_empty() => {
50                let port: u16 = p_str.parse().unwrap_or_default();
51                (h.to_string(), port)
52            }
53            _ => {
54                let default_port = if scheme == "https" { 443 } else { 80 };
55                (host_port.to_string(), default_port)
56            }
57        };
58
59        let query_params = if !query.is_empty() {
60            let mut query_params = HashMap::new();
61            let r = query.split('&').collect::<Vec<&str>>();
62            for item in r {
63                let t = item.split('=').collect::<Vec<&str>>();
64                query_params.insert(t[0].to_string(), t[1].to_string());
65            }
66            query_params
67        } else {
68            HashMap::new()
69        };
70
71        Ok(Self {
72            url: url.to_string(),
73            scheme,
74            host,
75            port,
76            path_query: path_query.to_string(),
77            path: path.to_string(),
78            query: query.to_string(),
79            query_params,
80        })
81    }
82
83    pub fn set_query(&mut self, param: HashMap<String, String>) {
84        if self.query.is_empty() {
85            self.query_params = param;
86        } else {
87            self.query_params.extend(param);
88        }
89        self.update_query();
90    }
91    fn update_query(&mut self) {
92        self.query = self
93            .query_params
94            .iter()
95            .map(|(key, value)| format!("{}={}", key, value))
96            .collect::<Vec<String>>()
97            .join("&");
98        self.path_query = match self.path_query.find("?") {
99            None => format!("{}?{}", self.path_query, self.query),
100            Some(n) => format!("{}?{}", &self.path_query[..n], self.query),
101        }
102    }
103}
104
105#[test]
106fn test() {
107    let test = Url::parse("http://127.0.0.1:8080/ttt/index.html?ttt=1111").unwrap();
108    println!("scheme: {}", test.scheme);
109    println!("host: {}", test.host);
110    println!("port: {}", test.port);
111    println!("path: {}", test.path);
112    println!("query: {}", test.query);
113    println!("query_params: {:?}", test.query_params);
114
115    let test = Url::parse("http://www.exe.com/ttt/index.html?ttt=1111").unwrap();
116    println!("scheme: {}", test.scheme);
117    println!("host: {}", test.host);
118    println!("port: {}", test.port);
119    println!("path: {}", test.path);
120    println!("query: {}", test.query);
121    println!("query_params: {:?}", test.query_params);
122}