|
|
|
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: String,
|
|
|
|
pub uri: String,
|
|
|
|
pub headers: Vec<(String, String)>,
|
|
|
|
pub body: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Response {
|
|
|
|
pub status: Status,
|
|
|
|
pub headers: Vec<(String, String)>,
|
|
|
|
pub body: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub enum Status {
|
|
|
|
Ok = 200,
|
|
|
|
NotFound = 404,
|
|
|
|
BadRequest = 400,
|
|
|
|
Unauthorized = 401,
|
|
|
|
InternalServerError = 500,
|
|
|
|
}
|
|
|
|
|
|
|
|
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",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Request {
|
|
|
|
pub fn form(&self) -> Result<HashMap<&str, &str>, RequestError> {
|
|
|
|
let mut hashmap = HashMap::new();
|
|
|
|
for mut x in self.body.split("&").map(|x| x.split("=")) {
|
|
|
|
hashmap.insert(
|
|
|
|
x.next().ok_or(RequestError::NotAForm)?,
|
|
|
|
x.next().ok_or(RequestError::NotAForm)?,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
Ok(hashmap)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FromStr for Request {
|
|
|
|
type Err = RequestError;
|
|
|
|
|
|
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
|
|
//dbg!(&s);
|
|
|
|
let mut iter = s.lines();
|
|
|
|
let mut first = iter
|
|
|
|
.next()
|
|
|
|
.ok_or(RequestError::BadRequest)?
|
|
|
|
.split_whitespace();
|
|
|
|
let method = first.next().ok_or(RequestError::BadRequest)?;
|
|
|
|
let uri = first.next().ok_or(RequestError::BadRequest)?;
|
|
|
|
let mut headers: Vec<(String, String)> = vec![];
|
|
|
|
|
|
|
|
for line in &mut iter {
|
|
|
|
if line.is_empty() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
let line: Vec<&str> = line.split(":").take(2).collect();
|
|
|
|
headers.push((line[0].into(), line[1].into()));
|
|
|
|
}
|
|
|
|
let body: String = iter.fold(String::new(), |a, b| format!("{}{}", a, b));
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
|
method: method.to_string(),
|
|
|
|
uri: uri.to_string(),
|
|
|
|
headers: headers,
|
|
|
|
body: body.to_string(),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Response {
|
|
|
|
pub fn new(status: Status, headers: Vec<(String, String)>, body: String) -> Self {
|
|
|
|
Self {
|
|
|
|
status,
|
|
|
|
headers,
|
|
|
|
body,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<HandlingError> for Response {
|
|
|
|
fn from(err: HandlingError) -> Self {
|
|
|
|
todo!();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for Response {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
let headers: String = self
|
|
|
|
.headers
|
|
|
|
.iter()
|
|
|
|
.map(|x| format!("{}:{}", x.0, x.1))
|
|
|
|
.fold(String::from(""), |a, b| format!("{}\n{}", a, b)); // possibly slow
|
|
|
|
|
|
|
|
write!(
|
|
|
|
f,
|
|
|
|
"{} {} {}\n{}\n\n{}",
|
|
|
|
HTTP_VERSION,
|
|
|
|
self.status as i32,
|
|
|
|
self.status.message(),
|
|
|
|
headers,
|
|
|
|
self.body,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|