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

94 lines
1.8 KiB
Rust

use std::fmt;
use std::str::{FromStr, Lines};
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,
}
impl Status {
pub fn message(&self) -> &'static str {
match self {
Self::Ok => "OK",
Self::NotFound => "NOT FOUND",
}
}
}
// TODO proper errors
impl FromStr for Request {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut iter = s.lines();
let mut first = iter.next().unwrap().split_whitespace();
let method = first.next().unwrap();
let uri = first.next().unwrap();
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 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,
)
}
}