Last active
August 4, 2019 22:56
-
-
Save wegry/d1bbb515fe754d80feb68de29df37551 to your computer and use it in GitHub Desktop.
Basic Rust 2018 Static File Server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use colored::*; | |
use futures::{future, Future}; | |
use hyper::header::{HeaderName, HeaderValue}; | |
use hyper::service::service_fn; | |
use hyper::{Body, Request, Response, Server}; | |
use hyper::{Method, StatusCode}; | |
use lazy_static::lazy_static; | |
use maplit::btreemap; | |
use std::collections::BTreeMap; | |
use std::path::Path; | |
lazy_static! { | |
static ref MIME_BY_EXTENSION: BTreeMap<String, String> = { | |
let owned_version = btreemap![ | |
"css" => "text/css", | |
"js" => "text/javascript", | |
"wasm" => "application/wasm", | |
"woff2" => "font/woff2" | |
]; | |
owned_version | |
.iter() | |
.map(|(key, val)| (String::from(*key), String::from(*val))) | |
.collect() | |
}; | |
} | |
// Just a simple type alias | |
type BoxFut = Box<Future<Item = Response<Body>, Error = hyper::Error> + Send>; | |
fn poor_mans_static_server(req: Request<Body>) -> BoxFut { | |
let mut response = Response::new(Body::empty()); | |
match (req.method(), req.uri().path()) { | |
(&Method::GET, path) => { | |
// first, we serve static files | |
let fs_path = match path { | |
"" | "/" => String::from("index.html"), | |
_ => format!(".{}", path), | |
}; | |
// Cribbed from https://github.com/sparkles-web/sparkles/blob/e3e10dc2e684f4b6c9749b784f34ff788cf379d2/src/server.rs#L144-L172 | |
// ... you trying to do something bad? | |
// TODO: Disallow current dir too... | |
if fs_path.contains("../") { | |
*response.status_mut() = StatusCode::NOT_FOUND; | |
// GET OUT | |
return Box::new(future::ok(response)); | |
} | |
// Set content type here... | |
let path_creator = fs_path.clone(); | |
let as_path = Path::new(&path_creator); | |
if as_path.is_file() { | |
let text = vec![std::fs::read(fs_path).unwrap()]; | |
if let Some(extension) = as_path.extension() { | |
if let Some(non_html_mime) = MIME_BY_EXTENSION.get(extension.to_str().unwrap()) | |
{ | |
(*response.headers_mut()).insert( | |
HeaderName::from_static("content-type"), | |
HeaderValue::from_static(non_html_mime), | |
); | |
}; | |
} else { | |
eprintln!("Content type unset for {:?}", as_path); | |
} | |
*response.body_mut() = | |
Body::wrap_stream(futures::stream::iter_ok::<_, ::std::io::Error>(text)); | |
} | |
} | |
_ => { | |
*response.status_mut() = StatusCode::NOT_FOUND; | |
} | |
}; | |
Box::new(future::ok(response)) | |
} | |
pub fn static_files() { | |
// This is our socket address... | |
let addr = ([127, 0, 0, 1], 3000).into(); | |
let server = Server::bind(&addr) | |
.serve(|| service_fn(poor_mans_static_server)) | |
.map_err(|e| eprintln!("server error: {}", e)); | |
println!( | |
"{}", | |
format!("🚀 Listening at http://{}", addr).bright_blue() | |
); | |
hyper::rt::run(server) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment