use super::header::HTTPRequestHeaders;
#[derive(Debug)]
pub struct HTTPRequestParsingError;
impl std::error::Error for HTTPRequestParsingError {}
impl std::fmt::Display for HTTPRequestParsingError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
write!(f, "error parsing HTTP request")
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum HTTPMethod {
Get,
Post,
Head,
Delete,
Put,
Connect,
Options,
Trace,
Patch,
}
impl std::fmt::Display for HTTPMethod {
fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
let string = match self {
HTTPMethod::Get => String::from("GET"),
HTTPMethod::Post => String::from("POST"),
HTTPMethod::Head => String::from("HEAD"),
HTTPMethod::Delete => String::from("DELETE"),
HTTPMethod::Put => String::from("PUT"),
HTTPMethod::Connect => String::from("CONNECT"),
HTTPMethod::Options => String::from("OPTIONS"),
HTTPMethod::Trace => String::from("TRACE"),
HTTPMethod::Patch => String::from("PATCH"),
};
write!(f, "{}", string)
}
}
#[derive(Clone, Debug)]
pub struct HTTPRequest {
method: HTTPMethod,
path: String,
header: Vec<HTTPRequestHeaders>,
body: Option<String>,
}
impl HTTPRequest {
pub fn new(
method: HTTPMethod,
path: String,
header: Vec<HTTPRequestHeaders>,
body: Option<String>,
) -> HTTPRequest {
HTTPRequest {
method,
path,
body,
header,
}
}
pub fn from_string(req_string: String) -> Result<HTTPRequest, HTTPRequestParsingError> {
let mut lines = req_string.lines();
let line1: String = match lines.next() {
Some(n) => n.to_string(),
None => {
return Err(HTTPRequestParsingError);
}
};
let mut line1_iter = line1.split_whitespace();
let method: &str = match line1_iter.next() {
Some(n) => n,
None => {
return Err(HTTPRequestParsingError);
}
};
let path: &str = match line1_iter.next() {
Some(n) => n,
None => {
return Err(HTTPRequestParsingError);
}
};
let method: HTTPMethod = match method {
"GET" => HTTPMethod::Get,
"POST" => HTTPMethod::Post,
"HEAD" => HTTPMethod::Head,
"DELETE" => HTTPMethod::Delete,
"PUT" => HTTPMethod::Put,
"CONNECT" => HTTPMethod::Connect,
"OPTIONS" => HTTPMethod::Options,
"TRACE" => HTTPMethod::Trace,
"PATCH" => HTTPMethod::Patch,
_ => {
return Err(HTTPRequestParsingError);
}
};
let out_headers: Vec<HTTPRequestHeaders> = req_string
.split("\r\n\r\n")
.nth(0)
.unwrap_or(&String::new())
.lines()
.skip(1)
.filter(|x| HTTPRequestHeaders::from_string(x.to_string()).is_some())
.map(|x| HTTPRequestHeaders::from_string(x.to_string()).unwrap())
.collect();
let body: Option<String> = match req_string.split("\r\n\r\n").nth(1) {
Some(n) => Some(n.to_string()),
None => None,
};
Ok(HTTPRequest::new(
method,
path.to_string(),
out_headers,
body,
))
}
pub fn get_path(&self) -> &str {
&self.path
}
pub fn get_method(&self) -> HTTPMethod {
self.method
}
pub fn get_header(&self) -> &Vec<HTTPRequestHeaders> {
&self.header
}
pub fn get_body(&self) -> &Option<String> {
&self.body
}
}