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: Vec, // make into Option> } #[derive(Debug, Clone, Copy)] pub enum Status { Ok = 200, SeeOther = 303, NotFound = 404, BadRequest = 400, Unauthorized = 401, InternalServerError = 500, } #[derive(Debug, PartialEq)] 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: Vec) -> Self { Self { status, headers: headers .into_iter() .map(|(x, y)| (x.to_owned(), y.to_owned())) .collect(), body, } } pub fn respond(&self) -> Vec { let mut res = vec![]; res.extend_from_slice(HTTP_VERSION.as_bytes()); res.extend_from_slice(b" "); res.extend_from_slice(&(self.status as i32).to_string().as_bytes()); // network endianness res.extend_from_slice(b" "); res.extend_from_slice(self.status.message().as_bytes()); res.extend_from_slice(b"\r\n"); for (i, j) in self.headers.iter() { res.extend_from_slice(i.as_bytes()); res.extend_from_slice(b":"); res.extend_from_slice(j.as_bytes()); res.extend_from_slice(b"\r\n"); } res.extend_from_slice(b"\r\n"); res.extend_from_slice(&self.body); res } }