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}