diff options
-rw-r--r-- | src/error.rs | 3 | ||||
-rw-r--r-- | src/get_routes.rs | 59 | ||||
-rw-r--r-- | src/main.rs | 7 |
3 files changed, 41 insertions, 28 deletions
diff --git a/src/error.rs b/src/error.rs index 8460376..0a36476 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,6 +2,7 @@ use sputnik::hyper_body::FormError; use sputnik::request::QueryError; use std::str::Utf8Error; +/// For convenience this enum also contains nonerroneous variants. pub enum Error { /// A 400 bad request error. BadRequest(String), @@ -13,6 +14,8 @@ pub enum Error { NotFound(String), /// A 500 internal server error. Internal(String), + /// A 304 response. + NotModified, /// A 302 redirect to the given path. Redirect(String), diff --git a/src/get_routes.rs b/src/get_routes.rs index 57d7e56..cde88c3 100644 --- a/src/get_routes.rs +++ b/src/get_routes.rs @@ -8,8 +8,6 @@ use git2::Tree; use git2::TreeEntry; use hyper::header; use hyper::http::request::Parts; -use hyper::http::response::Builder; -use hyper::StatusCode; use serde::Deserialize; use sputnik::html_escape; use sputnik::request::SputnikParts; @@ -310,11 +308,9 @@ fn diff_blob<C: Controller>( Ok(page.into()) } -fn raw_blob<C: Controller>( +fn build_raw_response( entr: TreeEntry, - _params: ActionParam, - _controller: &C, - ctx: Context, + ctx: &Context, parts: &Parts, ) -> Result<HyperResponse, Error> { if let Some(etag) = parts @@ -323,11 +319,7 @@ fn raw_blob<C: Controller>( .and_then(|v| v.to_str().ok()) { if etag.trim_matches('"') == entr.id().to_string() { - return Ok(Builder::new() - .status(StatusCode::NOT_MODIFIED) - .body("".into()) - .unwrap() - .into()); + return Err(Error::NotModified); } } @@ -338,25 +330,36 @@ fn raw_blob<C: Controller>( .insert(header::ETAG, format!("\"{}\"", entr.id()).parse().unwrap()); resp.headers_mut() .insert(header::CACHE_CONTROL, "no-cache".parse().unwrap()); + Ok(resp) +} - if let Some(mime) = mime_guess::from_path(&ctx.path).first() { - if mime.type_() == "text" { - // workaround for Firefox, which downloads non-plain text subtypes - // instead of displaying them (https://bugzilla.mozilla.org/1319262) - resp.headers_mut() - .insert(header::CONTENT_TYPE, "text/plain".parse().unwrap()); - } else { - resp.headers_mut() - .insert(header::CONTENT_TYPE, mime.to_string().parse().unwrap()); +fn raw_blob<C: Controller>( + entr: TreeEntry, + _params: ActionParam, + _controller: &C, + ctx: Context, + parts: &Parts, +) -> Result<HyperResponse, Error> { + build_raw_response(entr, &ctx, parts).map(|mut resp| { + if let Some(mime) = mime_guess::from_path(&ctx.path).first() { + if mime.type_() == "text" { + // workaround for Firefox, which downloads non-plain text subtypes + // instead of displaying them (https://bugzilla.mozilla.org/1319262) + resp.headers_mut() + .insert(header::CONTENT_TYPE, "text/plain".parse().unwrap()); + } else { + resp.headers_mut() + .insert(header::CONTENT_TYPE, mime.to_string().parse().unwrap()); + } } - } - Ok(resp) + resp + }) } fn run_blob<C: Controller>( entr: TreeEntry, - params: ActionParam, - controller: &C, + _params: ActionParam, + _controller: &C, ctx: Context, parts: &Parts, ) -> Result<HyperResponse, Error> { @@ -365,18 +368,18 @@ fn run_blob<C: Controller>( "run action only available for .html files".into(), )); } - raw_blob(entr, params, controller, ctx, parts).map(|mut r| { - r.headers_mut() + build_raw_response(entr, &ctx, parts).map(|mut resp| { + resp.headers_mut() .insert(header::CONTENT_TYPE, "text/html".parse().unwrap()); // We want users to be able to view .html applications of other users // without having to worry about the application accessing their private // files. So we set the CSP: sandbox header which makes browsers treat // the page as a unique origin as per the same-origin policy. - r.headers_mut().insert( + resp.headers_mut().insert( header::CONTENT_SECURITY_POLICY, "sandbox allow-scripts;".parse().unwrap(), ); - r + resp }) } diff --git a/src/main.rs b/src/main.rs index 58431a2..d3c88f6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,6 +21,7 @@ use serde::Deserialize; use sputnik::html_escape; use sputnik::mime; use sputnik::request::SputnikParts; +use sputnik::response::EmptyBuilder; use sputnik::response::SputnikBuilder; use std::convert::Infallible; use std::env; @@ -241,6 +242,12 @@ async fn service<C: Controller>( Error::Forbidden(msg) => (403, msg), Error::NotFound(msg) => (404, msg), Error::Internal(msg) => (500, msg), + Error::NotModified => { + return Builder::new() + .status(StatusCode::NOT_MODIFIED) + .empty() + .unwrap(); + } Error::MissingTrailingSlash(path) => { return Builder::new() .status(StatusCode::FOUND) |