use crate::ast::AnyRes;
use http_body_util::{combinators::BoxBody, BodyExt, Empty, Full};
use hyper::{
body::{Body, Bytes, Frame},
service::service_fn,
Method, Request, Response, StatusCode,
};
use hyper_util::{
rt::{TokioExecutor, TokioIo},
server::conn,
};
use std::net::SocketAddr;
use tokio::net::TcpListener;
async fn serve(
req: Request<hyper::body::Incoming>,
) -> Result<Response<BoxBody<Bytes, hyper::Error>>, hyper::Error> {
match (req.method(), req.uri().path()) {
(&Method::GET, "/") => Ok(Response::new(full("Try POSTing data to /echo"))),
(&Method::GET, "/hello") => Ok(Response::new(full(Bytes::from("Hello, World!")))),
(&Method::POST, "/echo") => Ok(Response::new(req.into_body().boxed())),
(&Method::POST, "/echo/uppercase") => {
let frame_stream = req.into_body().map_frame(|frame| {
let frame = if let Ok(data) = frame.into_data() {
data.iter()
.map(|byte| byte.to_ascii_uppercase())
.collect::<Bytes>()
} else {
Bytes::new()
};
Frame::data(frame)
});
Ok(Response::new(frame_stream.boxed()))
}
(&Method::POST, "/echo/reversed") => {
let upper = req.body().size_hint().upper().unwrap_or(u64::MAX);
if upper > 1024 * 64 {
let mut resp = Response::new(full("Body too big"));
*resp.status_mut() = hyper::StatusCode::PAYLOAD_TOO_LARGE;
return Ok(resp);
}
let whole_body = req.collect().await?.to_bytes();
let reversed_body = whole_body.iter().rev().cloned().collect::<Vec<u8>>();
Ok(Response::new(full(reversed_body)))
}
_ => {
let mut not_found = Response::new(empty());
*not_found.status_mut() = StatusCode::NOT_FOUND;
Ok(not_found)
}
}
}
fn empty() -> BoxBody<Bytes, hyper::Error> {
Empty::<Bytes>::new()
.map_err(|never| match never {})
.boxed()
}
fn full<T: Into<Bytes>>(chunk: T) -> BoxBody<Bytes, hyper::Error> {
Full::new(chunk.into())
.map_err(|never| match never {})
.boxed()
}
pub async fn main() -> AnyRes {
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
let listener = TcpListener::bind(addr).await?;
loop {
let (stream, _) = listener.accept().await?;
let io = TokioIo::new(stream);
tokio::task::spawn(async move {
if let Err(err) = conn::auto::Builder::new(TokioExecutor::new())
.serve_connection(io, service_fn(serve))
.await
{
eprintln!("Error serving connection: {:?}", err);
}
});
}
}