Add proper error handling

This commit is contained in:
Tristan Daniël Maat 2022-09-06 15:14:42 +01:00
parent 98d71f0311
commit ab405fc1f8
Signed by: tlater
GPG key ID: 49670FD774E43268
4 changed files with 107 additions and 19 deletions

View file

@ -1,10 +1,17 @@
#![allow(dead_code)]
use std::net::SocketAddr;
use std::path::PathBuf;
use actix_files::NamedFile;
use actix_web::http::StatusCode;
use actix_web::middleware::ErrorHandlers;
use actix_web::{get, web, App, HttpRequest, HttpResponse, HttpServer, Responder};
use clap::Parser;
use handlebars::Handlebars;
use std::path::PathBuf;
mod errors;
use errors::{generic_error, UserError};
#[derive(Parser, Debug, Clone)]
struct Config {
@ -21,16 +28,17 @@ struct Config {
dev_mode: bool,
}
#[derive(Debug)]
struct SharedData<'a> {
handlebars: Handlebars<'a>,
config: Config,
}
#[get("/{filename:.*.html}")]
#[get(r"/{filename:.*\.html}")]
async fn template(
shared: web::Data<SharedData<'_>>,
req: HttpRequest,
) -> Result<impl Responder, Box<dyn std::error::Error>> {
) -> actix_web::Result<impl Responder> {
let path = req
.match_info()
.query("filename")
@ -38,22 +46,21 @@ async fn template(
.expect("only paths with this suffix should get here");
if shared.handlebars.has_template(path) {
let body = shared.handlebars.render(path, &())?;
Ok(HttpResponse::Ok().body(body))
} else {
let body = shared
.handlebars
.render("404", &())
.expect("404 template not found");
Ok(HttpResponse::NotFound().body(body))
.render(path, &())
.map_err(|_| UserError::InternalError)?;
Ok(HttpResponse::Ok().body(body))
} else {
Err(UserError::NotFound)?
}
}
#[get("/{filename:.*}")]
#[get("/{filename:.*[^/]+}")]
async fn static_file(
shared: web::Data<SharedData<'_>>,
req: HttpRequest,
) -> Result<impl Responder, Box<dyn std::error::Error>> {
) -> actix_web::Result<impl Responder> {
let requested = req.match_info().query("filename");
match shared
@ -67,17 +74,13 @@ async fn static_file(
//
// i.e., don't serve up /etc/passwd
Ok(path) if path.starts_with(&shared.config.template_directory) => {
let file = NamedFile::open_async(path).await?;
let file = NamedFile::open_async(path)
.await
.map_err(|_| UserError::NotFound)?;
Ok(file.use_last_modified(false).respond_to(&req))
}
// Any other cases should 404
_ => {
let body = shared
.handlebars
.render("404", &())
.expect("404 template not found");
Ok(HttpResponse::NotFound().body(body))
}
_ => Err(UserError::NotFound)?,
}
}
@ -101,6 +104,11 @@ async fn main() -> Result<(), std::io::Error> {
HttpServer::new(move || {
App::new()
.wrap(
ErrorHandlers::new()
.handler(StatusCode::NOT_FOUND, generic_error)
.handler(StatusCode::INTERNAL_SERVER_ERROR, generic_error),
)
.app_data(shared_data.clone())
.service(template)
.service(static_file)