use std::collections::HashMap; use std::fmt; use std::str::{FromStr, Lines}; use crate::errors::{HandlingError, RequestError}; const HTTP_VERSION: &'static str = "HTTP/1.1"; #[derive(Debug)] pub struct Request { pub method: Method, pub uri: String, pub headers: Vec<(String, String)>, pub body: Option>, } #[derive(Debug)] pub struct Response { pub status: Status, pub headers: Vec<(String, String)>, pub body: String, // make into Option> } #[derive(Debug, Clone, Copy)] pub enum Status { Ok = 200, SeeOther = 303, NotFound = 404, BadRequest = 400, Unauthorized = 401, InternalServerError = 500, } #[derive(Debug)] pub enum Method { Get, Post, Delete, } impl FromStr for Method { type Err = RequestError; fn from_str(s: &str) -> Result { match s { "GET" => Ok(Self::Get), "POST" => Ok(Self::Post), "DELETE" => Ok(Self::Delete), _ => Err(Self::Err::UnusedMethod), } } } impl Status { pub fn message(&self) -> &'static str { match self { Self::Ok => "OK", Self::NotFound => "NOT FOUND", Self::BadRequest => "BAD REQUEST", Self::Unauthorized => "UNAUTHORIZED", Self::InternalServerError => "INTERNAL SERVER ERROR", Self::SeeOther => "SEE OTHER", } } } //impl Request { // pub fn form(&self) -> Result, RequestError> { // let mut hashmap = HashMap::new(); // dbg!(&self.body); // for mut x in self.body.split("&").map(|x| x.split("=")) { // hashmap.insert( // x.next().ok_or(RequestError::NotAForm)?, // decode(x.next().ok_or(RequestError::NotAForm)?)?.into_owned().replace("+", " "), // ); // } // Ok(hashmap) // } //} impl Request { pub fn add_body(&mut self, body: Vec) { self.body = Some(body); } } impl TryFrom> for Request { type Error = RequestError; fn try_from(s: Vec) -> Result { //dbg!(&s); let mut iter = s.iter(); let mut first = iter .next() .ok_or(RequestError::BadRequest)? .split_whitespace(); let method: Method = first.next().ok_or(RequestError::BadRequest)?.parse()?; let uri = first.next().ok_or(RequestError::BadRequest)?.to_string(); let mut headers: Vec<(String, String)> = vec![]; for line in iter { let mut line = line.split(":").take(2); let left = line.next().ok_or(RequestError::BadRequest)?.trim(); let right = line.next().ok_or(RequestError::BadRequest)?.trim(); headers.push((left.to_string(), right.to_string())); } Ok(Self { method, uri, headers, body: None, }) } } impl Response { pub fn new(status: Status, headers: Vec<(&str, &str)>, body: String) -> Self { Self { status, headers: headers .into_iter() .map(|(x, y)| (x.to_owned(), y.to_owned())) .collect(), body, } } } impl fmt::Display for Response { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let headers: String = self .headers .iter() .map(|x| format!("{}:{}\n", x.0, x.1)) .fold(String::from(""), |a, b| format!("{}{}", a, b)); // possibly slow write!( f, "{} {} {}\n{}\n\n{}", HTTP_VERSION, self.status as i32, self.status.message(), headers, self.body, ) } }