diff --git a/src/http.rs b/src/http.rs index 024b0fa..9678f90 100644 --- a/src/http.rs +++ b/src/http.rs @@ -3,13 +3,20 @@ use std::fs; use std::io::prelude::*; use std::net::TcpStream; +// TODO: +// - we could complement status with a struct that stores the status and the error message. +// - an alternative is to have a status-error_mesage mapper in order to send an error explanation to the client +type Status = u16; +type Body<'a> = Option<&'a str>; + +#[derive(Debug)] pub struct ProcessedResponse { pub data: String, - status: u16, + status: Status, } type QueryParams<'a> = HashMap<&'a str, &'a str>; -type Headers = HashMap; +type Headers<'a> = HashMap<&'a str, &'a str>; #[derive(Debug)] struct HttpRequestQuery<'a> { @@ -27,14 +34,15 @@ struct HttpRequestLine<'a> { #[derive(Debug)] struct HttpRequest<'a> { request: HttpRequestLine<'a>, - headers: Headers, - body: Option, + headers: Headers<'a>, + body: Body<'a>, } -pub fn process_petition(stream: &mut TcpStream) -> std::io::Result { +pub fn process_petition(stream: &mut TcpStream) -> ProcessedResponse { let mut buffer = [0; 1024]; // TODO: manage this size - let _amount = stream.read(&mut buffer)?; + let _amount = stream.read(&mut buffer); let petition = String::from_utf8_lossy(&buffer[..]); + println!("Petition: {:?}", petition); let petition = parse_request(&petition); match petition { @@ -53,38 +61,46 @@ pub fn process_petition(stream: &mut TcpStream) -> std::io::Result { let response: ProcessedResponse = ProcessedResponse { - data: format!("HTTP/1.1 {}\r\nContent-Length: 0\r", error,), + data: format!("HTTP/1.1 {}\r\nContent-Length: 0\r\n\r\n", error), status: error, }; - Ok(response) + response } } } -fn parse_request(request_raw: &str) -> Result { +fn parse_request(request_raw: &str) -> Result { // TODO: study if better to use match if let Some((heading, rest)) = request_raw.split_once("\n") { - // Process heading - // split heading with split_whitespace - // for (i, line) in request_raw.enumerate() { - // } - let request = parse_request_block(heading); - println!("This is a raw request: {:?}", request); - if let Some((headers, body)) = rest.split_once("\n\n") { - // Process headers and body - // split headers over ":" + if let Ok(request) = parse_request_block(heading) { + if let Some((headers, body)) = rest.split_once("\n\r\n") { + if let Ok(headers) = parse_headers(headers) { + let body: Body = { + if body.len() > 0 { + Some(body) + } else { + None + } + }; + return Ok(HttpRequest { + request, + headers, + body, + }); + } + } } } Err(400) } -fn parse_request_block(request_block: &str) -> Result { +fn parse_request_block(request_block: &str) -> Result { let [method, query, version]: [&str; 3] = request_block .split_whitespace() .collect::>() @@ -101,7 +117,7 @@ fn parse_request_block(request_block: &str) -> Result { Err(400) } -fn parse_query(query: &str) -> Result { +fn parse_query(query: &str) -> Result { match query.split_once("?") { Some((path, params)) => { if let Ok(params) = parse_query_params(params) { @@ -118,7 +134,7 @@ fn parse_query(query: &str) -> Result { Err(400) } -fn parse_query_params(query: &str) -> Result { +fn parse_query_params(query: &str) -> Result { let mut param_map: HashMap<&str, &str> = HashMap::new(); let param_list = query.split("&"); @@ -133,3 +149,19 @@ fn parse_query_params(query: &str) -> Result { Ok(param_map) } + +fn parse_headers(headers: &str) -> Result { + let mut header_map: Headers = HashMap::new(); + + let header_list = headers.split("\n"); + + for header in header_list { + if let Some((key, value)) = header.split_once(":") { + header_map.insert(key, value); + } else { + return Err(400); + } + } + + Ok(header_map) +} diff --git a/src/main.rs b/src/main.rs index 0aff297..84a8ab7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,20 +16,8 @@ fn main() { let response = http::process_petition(&mut _stream); // TODO: manage error case - match response { - Ok(data) => { - let _amount = _stream.write(data.data.as_bytes()).unwrap(); - } - Err(e) => { - println!("Error: {:?}", e); - let _amount = _stream - .write( - "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n" - .as_bytes(), - ) - .unwrap(); - } - } + println!("About to responde: {:?}", response); + let _amount = _stream.write(response.data.as_bytes()).unwrap(); _stream.flush().unwrap(); } }