br-web-server 0.5.17

This is an WEB SERVER
Documentation
use std::collections::HashMap;

#[derive(Debug, Clone)]
pub struct Url {
    #[allow(dead_code)]
    pub url: String,
    #[allow(dead_code)]
    pub scheme: String,
    pub host: String,
    pub port: u16,
    pub path_query: String,
    #[allow(dead_code)]
    pub path: String,
    query: String,
    query_params: HashMap<String, String>,
}

impl Url {
    pub fn parse(url: &str) -> Result<Self, String> {
        let uri = url.to_string();

        let (uri, query) = match uri.find("?") {
            Some(idx) => (&uri[..idx], &uri[idx + 1..]),
            None => (uri.as_str(), ""),
        };

        let scheme = match uri.find(":") {
            None => return Err("Invalid Scheme Not Found".to_string()),
            Some(e) => uri[..e].to_string(),
        };

        let uri = uri
            .trim_start_matches(scheme.as_str())
            .trim_start_matches(":")
            .trim_start_matches("//");

        let (host_port, path) = match uri.find("/") {
            Some(idx) => (&uri[..idx], &uri[idx..]),
            None => (uri, "/"),
        };

        let path_query = if query.is_empty() {
            path.to_string()
        } else {
            format!("{}?{}", path, query)
        };

        let (host, port) = match host_port.rsplit_once(':') {
            Some((h, p_str)) if !h.is_empty() && !p_str.is_empty() => {
                let port: u16 = p_str.parse().unwrap_or_default();
                (h.to_string(), port)
            }
            _ => {
                let default_port = if scheme == "https" { 443 } else { 80 };
                (host_port.to_string(), default_port)
            }
        };

        let query_params = if !query.is_empty() {
            let mut query_params = HashMap::new();
            let r = query.split('&').collect::<Vec<&str>>();
            for item in r {
                let t = item.split('=').collect::<Vec<&str>>();
                query_params.insert(t[0].to_string(), t[1].to_string());
            }
            query_params
        } else {
            HashMap::new()
        };

        Ok(Self {
            url: url.to_string(),
            scheme,
            host,
            port,
            path_query: path_query.to_string(),
            path: path.to_string(),
            query: query.to_string(),
            query_params,
        })
    }

    pub fn set_query(&mut self, param: HashMap<String, String>) {
        if self.query.is_empty() {
            self.query_params = param;
        } else {
            self.query_params.extend(param);
        }
        self.update_query();
    }
    fn update_query(&mut self) {
        self.query = self
            .query_params
            .iter()
            .map(|(key, value)| format!("{}={}", key, value))
            .collect::<Vec<String>>()
            .join("&");
        self.path_query = match self.path_query.find("?") {
            None => format!("{}?{}", self.path_query, self.query),
            Some(n) => format!("{}?{}", &self.path_query[..n], self.query),
        }
    }
}

#[test]
fn test() {
    let test = Url::parse("http://127.0.0.1:8080/ttt/index.html?ttt=1111").unwrap();
    println!("scheme: {}", test.scheme);
    println!("host: {}", test.host);
    println!("port: {}", test.port);
    println!("path: {}", test.path);
    println!("query: {}", test.query);
    println!("query_params: {:?}", test.query_params);

    let test = Url::parse("http://www.exe.com/ttt/index.html?ttt=1111").unwrap();
    println!("scheme: {}", test.scheme);
    println!("host: {}", test.host);
    println!("port: {}", test.port);
    println!("path: {}", test.path);
    println!("query: {}", test.query);
    println!("query_params: {:?}", test.query_params);
}