Use actix-web 4.2.1 features to clean up resource handling

pull/8/head
Tristan Daniël Maat 2022-09-16 17:16:12 +01:00
parent 9035cf5419
commit a960bf4b27
Signed by: tlater
GPG Key ID: 49670FD774E43268
6 changed files with 42 additions and 84 deletions

13
Cargo.lock generated
View File

@ -44,9 +44,9 @@ dependencies = [
[[package]]
name = "actix-http"
version = "3.2.1"
version = "3.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6f9ffb6db08c1c3a1f4aef540f1a63193adc73c4fbd40b75a95fc8c5258f6e51"
checksum = "0c83abf9903e1f0ad9973cc4f7b9767fd5a03a583f51a5b7a339e07987cd2724"
dependencies = [
"actix-codec",
"actix-rt",
@ -154,9 +154,9 @@ dependencies = [
[[package]]
name = "actix-web"
version = "4.1.0"
version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27e8fe9ba4ae613c21f677c2cfaf0696c3744030c6f485b34634e502d6bb379"
checksum = "d48f7b6534e06c7bfc72ee91db7917d4af6afe23e7d223b51e68fffbb21e96b9"
dependencies = [
"actix-codec",
"actix-http",
@ -176,6 +176,7 @@ dependencies = [
"encoding_rs",
"futures-core",
"futures-util",
"http",
"itoa",
"language-tags",
"log",
@ -194,9 +195,9 @@ dependencies = [
[[package]]
name = "actix-web-codegen"
version = "4.0.1"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f270541caec49c15673b0af0e9a00143421ad4f118d2df7edcb68b627632f56"
checksum = "1fa9362663c8643d67b2d5eafba49e4cb2c8a053a29ed00a0bea121f17c76b13"
dependencies = [
"actix-router",
"proc-macro2",

View File

@ -5,7 +5,7 @@ edition = "2021"
[dependencies]
actix-files = "0.6.2"
actix-web = "4.1.0"
actix-web = { version = "4.2.1", features = ["macros"] }
clap = { version = "3.2.17", features = ["derive"] }
derive_more = "0.99.17"
env_logger = "0.9.0"

View File

@ -7,7 +7,7 @@ use actix_web::{web, HttpResponse, ResponseError};
use derive_more::{Display, Error};
use super::SharedData;
use crate::template_utils::{ErrorMessage, TemplateArgs};
use crate::template_utils::{render_template, ErrorMessage, TemplateArgs};
#[derive(Debug, Display, Error)]
pub enum UserError {
@ -56,8 +56,7 @@ pub fn generic_error<B>(
.error_page(ErrorMessage::new(message, status_code.as_u16()))
.build();
let body = handlebars
.render("error", &args)
let body = render_template(handlebars, "error", &args)
.map_err(|_| UserError::InternalError)?;
HttpResponse::build(res.status())

View File

@ -2,6 +2,7 @@
use std::net::SocketAddr;
use std::path::PathBuf;
use actix_files::Files;
use actix_web::{
http::{Method, StatusCode},
middleware::{self, ErrorHandlers},
@ -15,7 +16,7 @@ mod main_pages;
mod template_utils;
use errors::generic_error;
use main_pages::{mail_post, static_file, template, template_index};
use main_pages::{mail_post, template};
#[derive(Parser, Debug, Clone)]
struct Config {
@ -66,9 +67,8 @@ async fn main() -> std::io::Result<()> {
)
.app_data(shared_data.clone())
.service(template)
.service(static_file)
.service(template_index)
.service(mail_post)
.service(Files::new("/", &config.template_directory))
.default_service(web::route().method(Method::GET))
})
.bind(config.address)?

View File

@ -1,11 +1,8 @@
use actix_files::NamedFile;
use actix_web::{get, post, web, HttpRequest, HttpResponse, Responder};
use actix_web::{post, routes, web, HttpRequest, HttpResponse, Responder};
use log::info;
use serde::Deserialize;
use crate::errors::UserError;
use crate::template_utils::TemplateArgs;
use crate::template_utils::{Flash, FlashType};
use crate::template_utils::{render_template, Flash, FlashType, TemplateArgs};
use crate::SharedData;
#[derive(Clone, Debug, Deserialize)]
@ -15,69 +12,22 @@ pub(crate) struct Mail {
message: String,
}
#[routes]
#[get(r"/")]
pub(crate) async fn template_index(
shared: web::Data<SharedData<'_>>,
) -> actix_web::Result<impl Responder> {
if shared.handlebars.has_template("index") {
let body = shared
.handlebars
.render("index", &())
.map_err(|_| UserError::InternalError)?;
Ok(HttpResponse::Ok().body(body))
} else {
Err(UserError::NotFound)?
}
}
#[get(r"/{filename:.*\.html}")]
pub(crate) async fn template(
shared: web::Data<SharedData<'_>>,
req: HttpRequest,
) -> actix_web::Result<impl Responder> {
let path = req
.match_info()
.query("filename")
.strip_suffix(".html")
.expect("only paths with this suffix should get here");
let path = match req.match_info().query("filename") {
"" => "index",
other => other
.strip_suffix(".html")
.expect("only paths with this suffix should get here"),
};
if shared.handlebars.has_template(path) {
let body = shared
.handlebars
.render(path, &())
.map_err(|_| UserError::InternalError)?;
Ok(HttpResponse::Ok().body(body))
} else {
Err(UserError::NotFound)?
}
}
#[get("/{filename:.*[^/]+}")]
pub(crate) async fn static_file(
shared: web::Data<SharedData<'_>>,
req: HttpRequest,
) -> actix_web::Result<impl Responder> {
let requested = req.match_info().query("filename");
match shared
.config
.template_directory
.join(requested)
.canonicalize()
{
// We only want to serve paths that are both valid *and* in
// the template directory.
//
// 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
.map_err(|_| UserError::NotFound)?;
Ok(file.use_last_modified(false).respond_to(&req))
}
// Any other cases should 404
_ => Err(UserError::NotFound)?,
}
render_template(&shared.handlebars, path, &TemplateArgs::default())
.map(|body| HttpResponse::Ok().body(body))
}
#[post("/mail.html")]
@ -91,13 +41,5 @@ pub(crate) async fn mail_post(
.flash(Flash::new("Mail successfully sent!", FlashType::Success))
.build();
if shared.handlebars.has_template("mail") {
let body = shared
.handlebars
.render("mail", &args)
.map_err(|_| UserError::InternalError)?;
Ok(HttpResponse::Ok().body(body))
} else {
Err(UserError::InternalError)?
}
render_template(&shared.handlebars, "mail", &args).map(|body| HttpResponse::Ok().body(body))
}

View File

@ -1,7 +1,23 @@
use serde::Serialize;
use crate::errors::UserError;
pub fn render_template(
handlebars: &handlebars::Handlebars,
name: &str,
args: &TemplateArgs,
) -> actix_web::Result<String> {
if handlebars.has_template(name) {
Ok(handlebars
.render(name, args)
.map_err(|_| UserError::InternalError)?)
} else {
Err(UserError::NotFound)?
}
}
/** All arguments that can be given to a template. */
#[derive(Serialize)]
#[derive(Default, Serialize)]
pub struct TemplateArgs {
flash: Option<Flash>,
error: Option<ErrorMessage>,