#![warn(rust_2018_idioms)]
use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::net::SocketAddr;
use std::time::{Duration, Instant};
pub use http::{header, HeaderMap, Method, Request, Response, StatusCode, Version};
pub type ResponseResult<Error> = Result<Response<Body>, Error>;
pub type HttpResult = ResponseResult<http::Error>;
pub type BoxError = Box<dyn Error + Send>;
pub type HandlerResult = Result<Response<Body>, BoxError>;
pub struct StartInstant(Instant);
impl StartInstant {
pub fn now() -> Self {
Self(Instant::now())
}
}
pub enum Body {
Static(&'static [u8]),
Owned(Vec<u8>),
File(File),
}
impl Body {
pub fn empty() -> Self {
Self::from_static(b"")
}
pub fn from_static(bytes: &'static [u8]) -> Self {
Self::Static(bytes)
}
pub fn from_vec(bytes: Vec<u8>) -> Self {
Self::Owned(bytes)
}
}
pub fn box_error<E: Error + Send + 'static>(error: E) -> BoxError {
Box::new(error)
}
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Scheme {
Http,
Https,
}
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Host<'a> {
Name(&'a str),
Socket(SocketAddr),
}
pub type Extensions = http::Extensions;
pub trait RequestExt {
fn elapsed(&self) -> Duration {
self.extensions().get::<StartInstant>().unwrap().0.elapsed()
}
fn http_version(&self) -> Version;
fn method(&self) -> &Method;
fn scheme(&self) -> Scheme;
fn host(&self) -> Host<'_>;
fn virtual_root(&self) -> Option<&str>;
fn path(&self) -> &str;
fn path_mut(&mut self) -> &mut String;
fn query_string(&self) -> Option<&str>;
fn remote_addr(&self) -> SocketAddr;
fn content_length(&self) -> Option<u64>;
fn headers(&self) -> &HeaderMap;
fn body(&mut self) -> &mut dyn Read;
fn extensions(&self) -> &Extensions;
fn mut_extensions(&mut self) -> &mut Extensions;
}
pub trait Handler: Sync + Send + 'static {
fn call(&self, request: &mut dyn RequestExt) -> HandlerResult;
}
impl<F, E> Handler for F
where
F: Fn(&mut dyn RequestExt) -> ResponseResult<E> + Sync + Send + 'static,
E: Error + Send + 'static,
{
fn call(&self, request: &mut dyn RequestExt) -> HandlerResult {
(*self)(request).map_err(box_error)
}
}