use std::collections::HashMap;
use std::env;
use std::io::{self, Read};
use crate::error::{CgiError, CgiErrorKind};
pub enum Method {
GET,
HEAD,
OPTIONS,
TRACE,
PUT,
DELETE,
POST,
PATCH,
CONNECT,
OTHER(&'static str)
}
pub struct Request {
pub method: Method,
pub path: &'static str,
pub body: Option<String>,
pub headers: HashMap<String, String>
}
pub fn new_request() -> Result<Request, CgiError> {
let method = {
let method_str = env::var("REQUEST_METHOD");
if method_str.is_err() {
return Err(CgiError::new("REQUEST_METHOD enviroment variable was not found", CgiErrorKind::RequestMethodNodFound))
}
match method_str.unwrap().leak() as &'static str {
"GET" => Method::GET,
"HEAD" => Method::HEAD,
"OPTIONS" => Method::OPTIONS,
"TRACE" => Method::TRACE,
"PUT" => Method::PUT,
"DELETE" => Method::DELETE,
"POST" => Method::POST,
"PATCH" => Method::PATCH,
"CONNECT" => Method::CONNECT,
other => {
if other.is_empty() {
return Err(CgiError::new("method is empty", CgiErrorKind::EmptyContent))
} else {
Method::OTHER(other)
}
}
}
};
let path = env::var("PATH_INFO");
if path.is_err() {
return Err(CgiError::new("PATH_INFO enviroment variable was not found", CgiErrorKind::PathInfoNotFound));
}
let path = path.unwrap().leak();
if path.is_empty() {
return Err(CgiError::new("path is empty", CgiErrorKind::EmptyContent))
}
let body_len_str = env::var("CONTENT_LENGTH");
let body_len: u64;
match body_len_str {
Ok(body_len_str) => {
body_len = body_len_str.parse().unwrap();
}
Err(_) => return Err(CgiError::new("CONTENT_LENGTH enviroment variable was not found", CgiErrorKind::ContentLengthNotFound))
}
let body = {
let mut body_buffer = String::new();
let io_result = io::stdin()
.take(body_len)
.read_to_string(&mut body_buffer);
if io_result.is_err() {
return Err(CgiError::new("failed to read body input", CgiErrorKind::InputBodyFail))
}
drop(io_result);
if body_buffer.is_empty() {
None
} else {
Some(body_buffer)
}
};
let mut headers = HashMap::new();
for (key, value) in env::vars() {
if key.starts_with("HTTP_") && key.len() >= 5 {
headers.insert(key, value);
}
}
Ok(Request {
method: method,
path: path,
body: body,
headers: headers
})
}