From fd93b3419fde85057cd5df606aa031f35c33e2c1 Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Mon, 25 Jun 2018 21:39:25 -0700 Subject: [PATCH 1/4] pin actix-web harder --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6280d02a..7f8e099c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,7 @@ term-painter = "0.2" url = "1.5" # Below is for the serve cmd actix = "~0.5" -actix-web = "0.6" +actix-web = "~0.6" notify = "4" ws = "0.7" ctrlc = "3" From 17106be497bc84f56e543e5a2cb0f634cb7d792b Mon Sep 17 00:00:00 2001 From: eir Date: Thu, 26 Apr 2018 14:14:37 -0700 Subject: [PATCH 2/4] Send Appropriate Response on Error Users can now place custom error pages in static/error/.html e.g. static/error/404.html If no custom page is found, a default plaintext describing the error is served. --- src/cmd/serve.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 1ae7a01c..85cbe092 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -22,7 +22,7 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. use std::env; -use std::fs::remove_dir_all; +use std::fs::{File, remove_dir_all}; use std::io; use std::path::{Path, PathBuf}; use std::sync::mpsc::channel; @@ -58,6 +58,31 @@ enum ChangeKind { // errors const LIVE_RELOAD: &'static str = include_str!("livereload.js"); +struct ErrCatcher; + +impl AfterMiddleware for ErrCatcher { + + fn catch(&self, _: &mut Request, err: IronError) -> IronResult { + + let err_status = err.response.status.unwrap_or(status::InternalServerError); + + // Search for e.g. "static/error/404.html" + let err_page = File::open( format!("static/error/{}.html", err_status.to_u16()) ); + + if err_page.is_ok() { + let mut err_res = Response::with(( err_status, err_page.unwrap() )); + err_res.headers.set(ContentType::html()); + + return Ok(err_res); + } + + // No custom error page, serve default + let mut err_res = Response::with(( err_status, format!("Error: {}.", err_status) )); + err_res.headers.set(ContentType::plaintext()); + + Ok(err_res) + } +} fn livereload_handler(_: HttpRequest) -> &'static str { LIVE_RELOAD From 7ab22528a53ee13ad0c23706b90ba6877878886f Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Sun, 24 Jun 2018 12:08:33 -0700 Subject: [PATCH 3/4] WIP Custom 404 page. This is a proposed successor to #296 (rewritten for actix-web, rather than iron). --- src/cmd/serve.rs | 49 ++++++++++++++++++++++++++---------------------- 1 file changed, 27 insertions(+), 22 deletions(-) diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index 85cbe092..af22cc7c 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -22,8 +22,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. use std::env; -use std::fs::{File, remove_dir_all}; -use std::io; +use std::fs::{remove_dir_all, File}; +use std::io::{self, Read}; use std::path::{Path, PathBuf}; use std::sync::mpsc::channel; use std::time::{Instant, Duration}; @@ -31,7 +31,8 @@ use std::thread; use chrono::prelude::*; use actix; -use actix_web::{fs, server, App, HttpRequest, HttpResponse, Responder}; +use actix_web::{self, fs, http, server, App, HttpRequest, HttpResponse, Responder}; +use actix_web::middleware::{Middleware, Started, Response}; use notify::{Watcher, RecursiveMode, watcher}; use ws::{WebSocket, Sender, Message}; use ctrlc; @@ -60,27 +61,30 @@ const LIVE_RELOAD: &'static str = include_str!("livereload.js"); struct ErrCatcher; -impl AfterMiddleware for ErrCatcher { +impl Middleware for ErrCatcher { + fn start(&self, _req: &mut HttpRequest) -> actix_web::Result { + Ok(Started::Done) + } - fn catch(&self, _: &mut Request, err: IronError) -> IronResult { - - let err_status = err.response.status.unwrap_or(status::InternalServerError); - - // Search for e.g. "static/error/404.html" - let err_page = File::open( format!("static/error/{}.html", err_status.to_u16()) ); - - if err_page.is_ok() { - let mut err_res = Response::with(( err_status, err_page.unwrap() )); - err_res.headers.set(ContentType::html()); - - return Ok(err_res); + fn response( + &self, + _req: &mut HttpRequest, + mut resp: HttpResponse, + ) -> actix_web::Result { + if http::StatusCode::NOT_FOUND == resp.status() { + let not_found_page = "static/error/404.html"; + if let Ok(mut fh) = File::open(¬_found_page) { + println!("Using {} to handle missing file.", ¬_found_page); + let mut buf: Vec = vec![]; + let _ = fh.read_to_end(&mut buf)?; + resp.replace_body(buf); + resp.headers_mut().insert( + http::header::CONTENT_TYPE, + http::header::HeaderValue::from_static("text/html"), + ); + } } - - // No custom error page, serve default - let mut err_res = Response::with(( err_status, format!("Error: {}.", err_status) )); - err_res.headers.set(ContentType::plaintext()); - - Ok(err_res) + Ok(Response::Done(resp)) } } @@ -180,6 +184,7 @@ pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, conf let sys = actix::System::new("http-server"); server::new(move || { App::new() + .middleware(ErrCatcher) .resource(r"/livereload.js", |r| r.f(livereload_handler)) // Start a webserver that serves the `output_dir` directory .handler(r"/", fs::StaticFiles::new(&static_root) From 8f460dc28b4de29083a318eb8946713a1151b0ef Mon Sep 17 00:00:00 2001 From: Owen Nelson Date: Mon, 25 Jun 2018 23:24:57 -0700 Subject: [PATCH 4/4] Custom 404 page now template driven. Since we are using a builtin template, we can be assured to have the target file in place. Middleware renamed since it is bound directly to the concept of handling 404s. --- components/site/src/lib.rs | 10 ++++++++ components/templates/src/builtins/404.html | 10 ++++++++ components/templates/src/lib.rs | 1 + src/cmd/serve.rs | 27 +++++++++++----------- 4 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 components/templates/src/builtins/404.html diff --git a/components/site/src/lib.rs b/components/site/src/lib.rs index 53ebc9d0..b217795a 100644 --- a/components/site/src/lib.rs +++ b/components/site/src/lib.rs @@ -526,6 +526,7 @@ impl Site { if self.config.generate_rss { self.render_rss_feed()?; } + self.render_404()?; self.render_robots()?; // `render_categories` and `render_tags` will check whether the config allows // them to render or not @@ -660,6 +661,15 @@ impl Site { Ok(()) } + /// Renders 404.html + pub fn render_404(&self) -> Result<()> { + ensure_directory_exists(&self.output_path)?; + create_file( + &self.output_path.join("404.html"), + &render_template("404.html", &self.tera, &Context::new(), &self.config.theme)? + ) + } + /// Renders robots.txt pub fn render_robots(&self) -> Result<()> { ensure_directory_exists(&self.output_path)?; diff --git a/components/templates/src/builtins/404.html b/components/templates/src/builtins/404.html new file mode 100644 index 00000000..f7d50b1a --- /dev/null +++ b/components/templates/src/builtins/404.html @@ -0,0 +1,10 @@ + + + + File Not Found: 404. + + +

Oops!

+

File Not Found: 404.

+ + diff --git a/components/templates/src/lib.rs b/components/templates/src/lib.rs index 1c494038..ce0fe912 100644 --- a/components/templates/src/lib.rs +++ b/components/templates/src/lib.rs @@ -24,6 +24,7 @@ lazy_static! { pub static ref GUTENBERG_TERA: Tera = { let mut tera = Tera::default(); tera.add_raw_templates(vec![ + ("404.html", include_str!("builtins/404.html")), ("rss.xml", include_str!("builtins/rss.xml")), ("sitemap.xml", include_str!("builtins/sitemap.xml")), ("robots.txt", include_str!("builtins/robots.txt")), diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index af22cc7c..a5158e5a 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -59,9 +59,11 @@ enum ChangeKind { // errors const LIVE_RELOAD: &'static str = include_str!("livereload.js"); -struct ErrCatcher; +struct NotFoundHandler { + rendered_template: PathBuf, +} -impl Middleware for ErrCatcher { +impl Middleware for NotFoundHandler { fn start(&self, _req: &mut HttpRequest) -> actix_web::Result { Ok(Started::Done) } @@ -72,17 +74,14 @@ impl Middleware for ErrCatcher { mut resp: HttpResponse, ) -> actix_web::Result { if http::StatusCode::NOT_FOUND == resp.status() { - let not_found_page = "static/error/404.html"; - if let Ok(mut fh) = File::open(¬_found_page) { - println!("Using {} to handle missing file.", ¬_found_page); - let mut buf: Vec = vec![]; - let _ = fh.read_to_end(&mut buf)?; - resp.replace_body(buf); - resp.headers_mut().insert( - http::header::CONTENT_TYPE, - http::header::HeaderValue::from_static("text/html"), - ); - } + let mut fh = File::open(&self.rendered_template)?; + let mut buf: Vec = vec![]; + let _ = fh.read_to_end(&mut buf)?; + resp.replace_body(buf); + resp.headers_mut().insert( + http::header::CONTENT_TYPE, + http::header::HeaderValue::from_static("text/html"), + ); } Ok(Response::Done(resp)) } @@ -184,7 +183,7 @@ pub fn serve(interface: &str, port: &str, output_dir: &str, base_url: &str, conf let sys = actix::System::new("http-server"); server::new(move || { App::new() - .middleware(ErrCatcher) + .middleware(NotFoundHandler { rendered_template: static_root.join("404.html") }) .resource(r"/livereload.js", |r| r.f(livereload_handler)) // Start a webserver that serves the `output_dir` directory .handler(r"/", fs::StaticFiles::new(&static_root)