diff --git a/assets/404.html.tera b/assets/404.html.tera
new file mode 100644
index 0000000..060efa2
--- /dev/null
+++ b/assets/404.html.tera
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ brevo
+
+
+
+
+
+
+
+
diff --git a/src/handlers.rs b/src/handlers.rs
index e18861a..e3848da 100644
--- a/src/handlers.rs
+++ b/src/handlers.rs
@@ -1,17 +1,17 @@
-use crate::util::gen_id;
-use crate::util::make_link;
-use crate::util::render_reject;
+use crate::util::{gen_id, make_link, render_reject};
use serde::{Deserialize, Serialize};
use sqlx::Row;
-use std::sync::Arc;
+use std::{convert::Infallible, sync::Arc};
use tera::Context;
use url::Url;
-use warp::http::uri::InvalidUri;
-use warp::redirect;
use warp::{
- http::Uri,
+ body::BodyDeserializeError,
+ http::{uri::InvalidUri, Uri},
+ redirect,
reject::{self, Reject},
- reply, Rejection, Reply,
+ reply,
+ Rejection,
+ Reply,
};
use crate::{sqlargs, util::sql_reject, Brevo};
@@ -19,7 +19,7 @@ use crate::{sqlargs, util::sql_reject, Brevo};
pub async fn index(brevo: Arc) -> Result, Rejection> {
let rendered = brevo.tera.render("index.html", &Context::new());
match rendered {
- Err(_) => Err(reject::custom(BrevoReject::RenderFail)),
+ Err(e) => Err(reject::custom(BrevoReject::RenderFail(e))),
Ok(r) => Ok(Box::new(reply::html(r))),
}
}
@@ -103,6 +103,68 @@ pub async fn submit(form_data: SubmitForm, brevo: Arc) -> Result,
+ err: Rejection,
+) -> Result, Infallible> {
+ match try_handle_reject(brevo, err).await {
+ Ok(x) => Ok(x),
+ Err(e) => {
+ log::error!("Unrecoverable reply error occured! {:?}", e);
+ Ok(Box::new(reply::html("ERROR!! see logs")))
+ },
+ }
+}
+
+pub async fn try_handle_reject(
+ brevo: Arc,
+ err: Rejection,
+) -> Result, Rejection> {
+ if err.is_not_found() {
+ let rendered = brevo
+ .tera
+ .render("404.html", &Context::new())
+ .map_err(render_reject)?;
+
+ return Ok(Box::new(reply::html(rendered)));
+ }
+
+ if let Some(rej) = err.find::() {
+ return match rej {
+ BrevoReject::SqlError(err) => {
+ log::error!("SQL error: {:?}", err);
+ Ok(Box::new(reply::html("SQL error! see logs.")))
+ },
+
+ BrevoReject::RenderFail(err) => {
+ log::error!("Template error: {:?}", err);
+ Ok(Box::new(reply::html(
+ "Failed to render template! see logs.",
+ )))
+ },
+
+ BrevoReject::UrlParseError(err) => {
+ log::error!("URL parse error: {:?}", err);
+ Ok(Box::new(reply::html("Not a valid URL!")))
+ },
+
+ BrevoReject::UriParseError(err) => {
+ log::error!("URI parse error: {:?}", err);
+ Ok(Box::new(reply::html("Not a valid URI!")))
+ },
+ };
+ }
+
+ if err.find::().is_some() {
+ return Ok(Box::new(reply::html(
+ "Invalid data! Did you enter a valid URI?",
+ )));
+ }
+
+ log::error!("unknown rejection: {:?}", err);
+ Ok(Box::new(reply::html("Found unknown rejection! see logs")))
+}
+
async fn make_table(brevo: Arc) -> Result<(), Rejection> {
// can't parameterize VARCHAR len, but this should be safe
sqlx::query(&format!(
@@ -133,7 +195,7 @@ pub struct SubmitForm {
// TODO: implement reject handerls
#[derive(Debug)]
pub enum BrevoReject {
- RenderFail,
+ RenderFail(tera::Error),
SqlError(sqlx::Error),
UrlParseError(url::ParseError),
UriParseError(InvalidUri),
diff --git a/src/main.rs b/src/main.rs
index b9803f4..9a74bb2 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,4 +1,3 @@
-use tokio::sync::Mutex;
use crate::config::Config;
use anyhow::Context;
use rand::{rngs::StdRng, SeedableRng};
@@ -6,6 +5,7 @@ use sqlx::MySqlPool;
use std::sync::Arc;
use structopt::StructOpt;
use tera::Tera;
+use tokio::sync::Mutex;
use warp::Filter;
mod config;
@@ -35,6 +35,7 @@ async fn main() -> anyhow::Result<()> {
tera.add_raw_templates(vec![
("index.html", include_str!("../assets/index.html.tera")),
("success.html", include_str!("../assets/success.html.tera")),
+ ("404.html", include_str!("../assets/404.html.tera")),
])
.context("error adding templates to tera")?;
@@ -47,6 +48,7 @@ async fn main() -> anyhow::Result<()> {
let brevo_idx = Arc::clone(&brevo);
let brevo_submit = Arc::clone(&brevo);
let brevo_srv = Arc::clone(&brevo);
+ let brevo_reject = Arc::clone(&brevo);
let routes = warp::get()
.and(
@@ -59,7 +61,8 @@ async fn main() -> anyhow::Result<()> {
.or(warp::post()
.and(warp::body::content_length_limit(1024 * 16))
.and(warp::body::form())
- .and_then(move |form_data| handlers::submit(form_data, Arc::clone(&brevo_submit))));
+ .and_then(move |form_data| handlers::submit(form_data, Arc::clone(&brevo_submit))))
+ .recover(move |err| handlers::handle_reject(Arc::clone(&brevo_reject), err));
warp::serve(routes).run(brevo_srv.config.bind_addr).await;
diff --git a/src/util.rs b/src/util.rs
index 4ff530c..2068f66 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -1,10 +1,8 @@
use std::sync::Arc;
-use crate::handlers::BrevoReject;
-use crate::Brevo;
+use crate::{handlers::BrevoReject, Brevo};
use rand::seq::IteratorRandom;
-use warp::reject;
-use warp::Rejection;
+use warp::{reject, Rejection};
#[macro_export]
macro_rules! sqlargs {
@@ -22,8 +20,8 @@ pub fn sql_reject(e: sqlx::Error) -> Rejection {
reject::custom(BrevoReject::SqlError(e))
}
-pub fn render_reject(_: T) -> Rejection {
- reject::custom(BrevoReject::RenderFail)
+pub fn render_reject(err: tera::Error) -> Rejection {
+ reject::custom(BrevoReject::RenderFail(err))
}
pub fn make_link(brevo: Arc, id: &str) -> Result {