blaze 0.1.6

blazing fast http framework
Documentation
use crate::{pkg::error::Error, types::http::*};

use http::header::{HeaderMap, HeaderName, HeaderValue};
use std::collections::HashMap;

pub fn parse_query_string(query: &str) -> HashMap<String, String> {
    query
        .split('&')
        .filter(|s| !s.is_empty())
        .filter_map(|s| {
            let mut parts = s.splitn(2, '=');
            Some((parts.next()?.to_string(), parts.next().unwrap_or("").to_string()))
        })
        .collect()
}

pub fn extract_params(request_path: &str, route_path: &str) -> HashMap<String, String> {
    let mut params = HashMap::new();
    let req_segments: Vec<&str> = request_path.split('/').collect();
    let route_segments: Vec<&str> = route_path.split('/').collect();

    for (req_seg, route_seg) in req_segments.iter().zip(route_segments.iter()) {
        if route_seg.starts_with('{') && route_seg.ends_with('}') {
            let param_name = &route_seg[1..route_seg.len() - 1];
            params.insert(param_name.to_string(), req_seg.to_string());
        }
    }

    params
}

pub fn paths_match(request_path: &str, route_path: &str) -> bool {
    let req_segments: Vec<&str> = request_path.split('/').collect();
    let route_segments: Vec<&str> = route_path.split('/').collect();

    if req_segments.len() != route_segments.len() {
        return false;
    }

    for (req_seg, route_seg) in req_segments.iter().zip(route_segments.iter()) {
        if !route_seg.starts_with('{') && req_seg != route_seg {
            return false;
        }
    }

    true
}

pub fn parse_headers<'a, I>(lines: I) -> Result<HeaderMap, Error>
where
    I: Iterator<Item = &'a str>,
{
    let mut headers = HeaderMap::new();
    for line in lines {
        if line.is_empty() {
            break;
        }
        if let Some((key, value)) = line.split_once(':') {
            let header_name = HeaderName::from_bytes(key.trim().as_bytes()).map_err(|e| Error(format!("Invalid header name: {}", e)))?;
            let header_value = HeaderValue::from_str(value.trim()).map_err(|e| Error(format!("Invalid header value: {}", e)))?;
            headers.insert(header_name, header_value);
        }
    }
    Ok(headers)
}

pub fn parse_request(buffer: &[u8]) -> Result<Request, Error> {
    let request_str = String::from_utf8_lossy(buffer);
    let mut parts = request_str.splitn(2, "\r\n\r\n");

    let headers_part = parts.next().ok_or_else(|| Error("Invalid request".into()))?;
    let body_part = parts.next().unwrap_or("");

    let mut lines = headers_part.lines();
    let first_line = lines.next().ok_or_else(|| Error("Invalid request".into()))?;
    let mut parts = first_line.split_whitespace();

    let method = match parts.next() {
        Some("GET") => Method::GET,
        Some("POST") => Method::POST,
        Some("PUT") => Method::PUT,
        Some("DELETE") => Method::DELETE,
        _ => return Err(Error("Invalid method".into())),
    };

    let full_path = parts.next().ok_or_else(|| Error("Invalid path".into()))?;
    let (path, query) = full_path.split_once('?').unwrap_or((full_path, ""));
    let query_params = parse_query_string(query);

    let headers = parse_headers(lines)?;
    let body = body_part.as_bytes().to_vec();

    Ok(Request {
        method,
        headers,
        query: query_params,
        body,
        params: HashMap::new(),
        path: path.to_string(),
    })
}