use crate::infrastructure::http::method::Method;
use crate::infrastructure::http::request::request::Request;
use std::collections::HashMap;
use std::io::{BufRead, BufReader, Read};
use std::net::TcpStream;
pub fn parse_request(buffer: &[u8]) -> Result<Request, Box<dyn std::error::Error>> {
let request_str = std::str::from_utf8(buffer)?;
let mut lines = request_str.lines();
let first_line = lines.next().ok_or("No request line")?;
let mut parts = first_line.split_whitespace();
let method_str = parts.next().ok_or("No method")?;
let path_qs = parts.next().ok_or("No path")?;
let _version = parts.next().ok_or("No version")?;
let method = Method::from_str(method_str).ok_or("Invalid method")?;
let (path, query_string) = if let Some(pos) = path_qs.find('?') {
(path_qs[..pos].to_string(), Some(path_qs[pos + 1..].to_string()))
} else {
(path_qs.to_string(), None)
};
let mut query_params = HashMap::new();
if let Some(qs) = &query_string {
for pair in qs.split('&') {
if let Some(eq_pos) = pair.find('=') {
let key = urlencoding::decode(&pair[..eq_pos])?.to_string();
let value = urlencoding::decode(&pair[eq_pos + 1..])?.to_string();
query_params.insert(key, value);
}
}
}
let mut headers = HashMap::new();
for line in lines.by_ref() {
if line.is_empty() {
break;
}
if let Some(colon_pos) = line.find(':') {
let key = line[..colon_pos].trim().to_string();
let value = line[colon_pos + 1..].trim().to_string();
headers.insert(key, value);
}
}
let body_start = request_str.find("\r\n\r\n").map(|p| p + 4).unwrap_or(request_str.len());
let content_length = headers.get("Content-Length")
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(0);
let body = buffer[body_start..body_start + content_length].to_vec();
let params = HashMap::new();
let mut request = Request::new(method, path);
request.headers = headers;
request.body = body;
request.params = params;
request.query_params = query_params;
request.query_string = query_string;
Ok(request)
}
pub fn parse_request_dynamic(stream: &mut TcpStream) -> Result<Request, Box<dyn std::error::Error>> {
let mut reader = BufReader::new(stream);
let mut first_line = String::new();
reader.read_line(&mut first_line)?;
let first_line = first_line.trim();
let mut parts = first_line.split_whitespace();
let method_str = parts.next().ok_or("No method")?;
let path_qs = parts.next().ok_or("No path")?;
let _version = parts.next().ok_or("No version")?;
let method = Method::from_str(method_str).ok_or("Invalid method")?;
let (path, query_string) = if let Some(pos) = path_qs.find('?') {
(path_qs[..pos].to_string(), Some(path_qs[pos + 1..].to_string()))
} else {
(path_qs.to_string(), None)
};
let mut query_params = HashMap::new();
if let Some(qs) = &query_string {
for pair in qs.split('&') {
if let Some(eq_pos) = pair.find('=') {
let key = urlencoding::decode(&pair[..eq_pos])?.to_string();
let value = urlencoding::decode(&pair[eq_pos + 1..])?.to_string();
query_params.insert(key, value);
}
}
}
let mut headers = HashMap::new();
loop {
let mut line = String::new();
reader.read_line(&mut line)?;
let line = line.trim();
if line.is_empty() {
break;
}
if let Some(colon_pos) = line.find(':') {
let key = line[..colon_pos].trim().to_string();
let value = line[colon_pos + 1..].trim().to_string();
headers.insert(key, value);
}
}
let content_length = headers.get("Content-Length")
.and_then(|s| s.parse::<usize>().ok())
.unwrap_or(0);
let mut body = vec![0; content_length];
reader.read_exact(&mut body)?;
let params = HashMap::new();
let mut request = Request::new(method, path);
request.headers = headers;
request.body = body;
request.params = params;
request.query_params = query_params;
request.query_string = query_string;
Ok(request)
}