You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
kchan/src/http.rs

148 lines
3.1 KiB
Rust

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<Vec<u8>>,
}
#[derive(Debug)]
pub struct Response {
pub status: Status,
pub headers: Vec<(String, String)>,
pub body: String, // make into Option<Vec<u8>>
}
#[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<Self, Self::Err> {
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<HashMap<&str, String>, 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<u8>) {
self.body = Some(body);
}
}
impl TryFrom<Vec<String>> for Request {
type Error = RequestError;
fn try_from(s: Vec<String>) -> Result<Self, Self::Error> {
//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,
)
}
}