Skip to content

Commit

Permalink
Add text/plain extension
Browse files Browse the repository at this point in the history
  • Loading branch information
brson committed Nov 16, 2019
1 parent f6bd95a commit 17e2213
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 18 deletions.
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -30,6 +30,9 @@ useful for developing documentation locally. Those extensions are:

- Listing directories when no "index.html" file is found.

- Serving common source code types and files as "text/plain" so they are
rendered in the browser.

This makes `basic-http-server` useful for the following scenarios:

- Previewing markdown content. Draft your `README.md` changes and view them
Expand Down
96 changes: 81 additions & 15 deletions src/ext.rs
Expand Up @@ -39,26 +39,27 @@ pub async fn serve(
return Ok(md_path_to_html(&path).await?);
}

// If the requested file was not found, then try doing a directory listing.
if let Err(e) = resp {
match e {
super::Error::Io(e) => {
if e.kind() == io::ErrorKind::NotFound {
let list_dir_resp = maybe_list_dir(&config.root_dir, &path).await?;
trace!("using directory list extension");
if let Some(f) = list_dir_resp {
Ok(f)
} else {
Err(super::Error::from(e))
}
match resp {
Ok(mut resp) => {
// Serve source code as plain text to render them in the browser
maybe_convert_mime_type_to_text(&req, &mut resp);
Ok(resp)
}
Err(super::Error::Io(e)) => {
// If the requested file was not found, then try doing a directory listing.
if e.kind() == io::ErrorKind::NotFound {
let list_dir_resp = maybe_list_dir(&config.root_dir, &path).await?;
trace!("using directory list extension");
if let Some(f) = list_dir_resp {
Ok(f)
} else {
Err(super::Error::from(e))
}
} else {
Err(super::Error::from(e))
}
_ => Err(e),
}
} else {
resp
r => r,
}
}

Expand Down Expand Up @@ -92,6 +93,71 @@ async fn md_path_to_html(path: &Path) -> Result<Response<Body>> {
.map_err(Error::from)
}

fn maybe_convert_mime_type_to_text(req: &Request<Body>, resp: &mut Response<Body>) {
let path = req.uri().path();
let file_name = path.rsplit('/').next();
if let Some(file_name) = file_name {
let mut do_convert = false;

let ext = file_name.rsplit('.').next();
if let Some(ext) = ext {
if TEXT_EXTENSIONS.contains(&ext) {
do_convert = true;
}
}

if TEXT_FILES.contains(&file_name) {
do_convert = true;
}

if do_convert {
use http::header::HeaderValue;
let val =
HeaderValue::from_str(mime::TEXT_PLAIN.as_ref()).expect("mime is valid header");
resp.headers_mut().insert(header::CONTENT_TYPE, val);
}
}
}

#[rustfmt::skip]
static TEXT_EXTENSIONS: &[&'static str] = &[
"c",
"cc",
"cpp",
"csv",
"fst",
"h",
"java",
"md",
"mk",
"proto",
"py",
"rb",
"rs",
"rst",
"sh",
"toml",
"yml",
];

#[rustfmt::skip]
static TEXT_FILES: &[&'static str] = &[
".gitattributes",
".gitignore",
".mailmap",
"AUTHORS",
"CODE_OF_CONDUCT",
"CONTRIBUTING",
"COPYING",
"COPYRIGHT",
"Cargo.lock",
"LICENSE",
"LICENSE-APACHE",
"LICENSE-MIT",
"Makefile",
"rust-toolchain",
];

/// Try to treat the path as a directory and list the contents as HTML.
async fn maybe_list_dir(root_dir: &Path, path: &Path) -> Result<Option<Response<Body>>> {
let meta = tokio::fs::metadata(path).await?;
Expand Down
5 changes: 2 additions & 3 deletions todo.md
@@ -1,6 +1,5 @@
- mime types
- teach ext to serve various types as "text/plain"
- teach ext to do syntax highlighting
- what happens if content-type ends up incorrect?
- teach ext to do syntax highlighting
- production-readiness
- benchmark with ab / h2load
- consider behavior under resource exhastion
Expand Down

0 comments on commit 17e2213

Please sign in to comment.