use std::{collections::HashMap, net::SocketAddr, str};
use super::{header::Header, Method};
const HEADERS_COUNT: usize = 32;
#[derive(Clone, Debug)]
pub struct Request {
method: Method,
path: String,
body: Vec<u8>,
headers: Vec<Header>,
peer_addr: Option<SocketAddr>,
pub params: Option<HashMap<String, String>>,
}
impl Request {
pub fn builder() -> Builder {
Builder::new()
}
pub fn method(&self) -> Method {
self.method.clone()
}
pub fn path(&self) -> String {
self.path.clone()
}
pub fn peer_addr(&self) -> Option<SocketAddr> {
self.peer_addr
}
pub fn try_parse_from_bytes(
buffer: &[u8],
peer_addr: Option<SocketAddr>,
) -> Result<Self, ParseRequestError> {
let mut headers = [httparse::EMPTY_HEADER; HEADERS_COUNT];
let mut req = httparse::Request::new(&mut headers);
let mut request = Request::builder().peer_addr(peer_addr);
match req.parse(buffer) {
Ok(httparse::Status::Complete(_)) => {
let method_str = req.method.ok_or(ParseRequestError::MissingMethod)?;
let path = req.path.ok_or(ParseRequestError::MissingPath)?;
let method = Method::from(method_str);
request = request.method(method).path(path);
for header in req.headers.iter() {
let name = header.name.to_string();
let value = str::from_utf8(header.value)?.to_string();
request = request.header(&name, &value);
}
request = request.body(vec![]);
Ok(request.build())
}
Ok(httparse::Status::Partial) => Err(ParseRequestError::Partial),
Err(e) => Err(e.into()),
}
}
}
#[derive(thiserror::Error, Debug)]
pub enum ParseRequestError {
#[error("method is missing")]
MissingMethod,
#[error("path is missing")]
MissingPath,
#[error("header value is invalid utf-8")]
InvalidUtf8HeaderValue(#[from] str::Utf8Error),
#[error("partial request")]
Partial,
#[error(transparent)]
General(#[from] httparse::Error),
}
pub struct Builder {
method: Method,
path: String,
body: Vec<u8>,
headers: Vec<Header>,
peer_addr: Option<SocketAddr>,
params: Option<HashMap<String, String>>,
}
impl Builder {
pub fn new() -> Self {
Builder::default()
}
pub fn method(mut self, method: Method) -> Self {
self.method = method;
self
}
pub fn path(mut self, path: &str) -> Self {
self.path = path.to_string();
self
}
pub fn body(mut self, body: Vec<u8>) -> Self {
self.body = body;
self
}
pub fn header(mut self, key: &str, value: &str) -> Self {
self.headers
.push(Header(key.to_string(), value.to_string()));
self
}
pub fn peer_addr(mut self, peer_addr: Option<SocketAddr>) -> Self {
self.peer_addr = peer_addr;
self
}
pub fn build(&self) -> Request {
Request {
peer_addr: self.peer_addr,
method: self.method.clone(),
path: self.path.clone(),
body: self.body.clone(),
headers: self.headers.clone(),
params: Default::default(),
}
}
}
impl Default for Builder {
fn default() -> Self {
Self {
method: Method::Get,
path: "/".to_string(),
body: vec![],
headers: vec![],
params: Default::default(),
peer_addr: None,
}
}
}