use bytes::Bytes;
use futures_util::future;
use http::{
header::{self, HeaderMap, HeaderValue},
Request, Response,
};
use http_serve::ChunkedReadFile;
use hyper::service::{make_service_fn, service_fn};
use hyper::Body;
struct Context {
path: std::ffi::OsString,
}
type BoxedError = Box<dyn std::error::Error + Send + Sync>;
async fn serve(ctx: &'static Context, req: Request<Body>) -> Result<Response<Body>, BoxedError> {
let f = tokio::task::block_in_place::<_, Result<ChunkedReadFile<Bytes, BoxedError>, BoxedError>>(
move || {
let f = std::fs::File::open(&ctx.path)?;
let mut headers = HeaderMap::new();
headers.insert(
header::CONTENT_TYPE,
HeaderValue::from_static("application/octet-stream"),
);
Ok(ChunkedReadFile::new(f, headers)?)
},
)?;
Ok(http_serve::serve(f, &req))
}
#[tokio::main]
async fn main() -> Result<(), BoxedError> {
let mut args = std::env::args_os();
if args.len() != 2 {
eprintln!("Expected serve [FILENAME]");
std::process::exit(1);
}
let path = args.nth(1).unwrap();
let ctx: &'static Context = Box::leak(Box::new(Context { path: path }));
env_logger::init();
let addr = ([127, 0, 0, 1], 1337).into();
let make_svc = make_service_fn(move |_conn| {
future::ok::<_, std::convert::Infallible>(service_fn(move |req| serve(ctx, req)))
});
let server = hyper::Server::bind(&addr).serve(make_svc);
println!(
"Serving {} on http://{} with 1 thread.",
ctx.path.to_string_lossy(),
server.local_addr()
);
server.await?;
Ok(())
}