#[cfg(test)]
mod tests;
use std::collections::HashMap;
use crate::header::Header;
use crate::mime_type::MimeType;
use crate::range::Range;
use crate::request::Request;
use crate::response::{Response, STATUS_CODE_REASON_PHRASE};
use crate::url::URL;
pub trait FromRequest: Sized {
fn from_request(request: &Request) -> Result<Self, Response>;
}
#[derive(Debug)]
pub struct Body(pub Vec<u8>);
impl FromRequest for Body {
fn from_request(request: &Request) -> Result<Self, Response> {
Ok(Body(request.body.clone()))
}
}
impl Body {
pub fn into_bytes(self) -> Vec<u8> {
self.0
}
}
#[derive(Debug)]
pub struct BodyText(pub String);
impl FromRequest for BodyText {
fn from_request(request: &Request) -> Result<Self, Response> {
String::from_utf8(request.body.clone())
.map(BodyText)
.map_err(|_| bad_request(request, "request body is not valid UTF-8"))
}
}
impl BodyText {
pub fn as_str(&self) -> &str {
&self.0
}
}
#[derive(Debug)]
pub struct Query(pub HashMap<String, String>);
impl FromRequest for Query {
fn from_request(request: &Request) -> Result<Self, Response> {
let query_str = request.request_uri
.splitn(2, '?')
.nth(1)
.unwrap_or("");
Ok(Query(URL::parse_query(query_str)))
}
}
impl Query {
pub fn get(&self, key: &str) -> Option<&String> {
self.0.get(key)
}
}
#[derive(Debug)]
pub struct RequestHeaders(pub Vec<Header>);
impl FromRequest for RequestHeaders {
fn from_request(request: &Request) -> Result<Self, Response> {
Ok(RequestHeaders(request.headers.clone()))
}
}
impl RequestHeaders {
pub fn get(&self, name: &str) -> Option<&str> {
let lower = name.to_lowercase();
self.0.iter()
.find(|h| h.name.to_lowercase() == lower)
.map(|h| h.value.as_str())
}
}
fn bad_request(request: &Request, msg: &str) -> Response {
let header_list = Header::get_header_list(request);
let cr = Range::get_content_range(msg.as_bytes().to_vec(), MimeType::TEXT_PLAIN.to_string());
Response::get_response(
STATUS_CODE_REASON_PHRASE.n400_bad_request,
Some(header_list),
Some(vec![cr]),
)
}