diff --git a/src/http/requests.rs b/src/http/requests.rs index 6111a3e..6dc91c3 100644 --- a/src/http/requests.rs +++ b/src/http/requests.rs @@ -1,38 +1,81 @@ -use std::collections::HashMap; +use std::{ + collections::HashMap, + io::{prelude::*, BufReader}, + net::TcpStream, +}; -pub struct URL<'a> { - pub raw: &'a str, - pub path: &'a str, - pub query: HashMap<&'a str, &'a str>, +pub struct URL { + raw: String, + pub path: String, + pub query: HashMap, } -impl<'a> URL<'a> { - pub fn new(url: &'a str) -> Option { +impl URL { + pub fn new(url: String) -> Option { let raw = url; + let mut split = raw.split('?'); // Query string parsing let mut query = HashMap::new(); - let mut split = url.split('?'); - let path = split.nth(0)?; + let path = split.next()?.to_string(); let query_string = split.next(); for pair in query_string.unwrap_or("").split('&') { let mut key_value = pair.split('='); let key = match key_value.next() { - Some(key) => key, + Some(key) => key.to_string(), None => continue, }; - let value = key_value.next().unwrap_or(""); + let value = key_value.next().unwrap_or("").to_string(); query.insert(key, value); } // Drop trailing slash but not for root path let path = if path.ends_with("/") && path.len() > 1 { - &path[..path.len() - 1] + path[..path.len() - 1].to_string() } else { path }; - Some(URL { raw, path, query }) + Some(URL { path, query, raw }) + } +} + +pub struct Request { + stream: TcpStream, + pub method: String, + pub url: URL, +} + +pub enum RequestStatus { + Ok(Request), + MalformedHTTP, +} + +impl<'a> Request { + pub fn parse_stream(stream: TcpStream) -> RequestStatus { + let reader = BufReader::new(&stream); + let mut lines = reader.lines(); + + let request_line = match lines.next() { + Some(Ok(line)) => line, + _ => return RequestStatus::MalformedHTTP, + }; + + let request_line_parts = request_line.split(" ").collect::>(); + if request_line_parts.len() != 3 { + return RequestStatus::MalformedHTTP; + } + + let (method, url_str) = ( + request_line_parts[0].to_string().clone(), + request_line_parts[1].to_string().clone(), + ); + let url = match URL::new(url_str) { + Some(path) => path, + None => return RequestStatus::MalformedHTTP, + }; + + RequestStatus::Ok(Request { stream, method, url }) } }