diff --git a/assets/favicon.png b/assets/favicon.png new file mode 100644 index 0000000..217fd72 Binary files /dev/null and b/assets/favicon.png differ diff --git a/src/startup.rs b/src/startup.rs index 607e965..875551f 100644 --- a/src/startup.rs +++ b/src/startup.rs @@ -1,12 +1,15 @@ use crate::{configuration::Settings, email_client::EmailClient, routes::require_auth, routes::*}; use axum::{ Router, + body::Bytes, extract::MatchedPath, http::Request, middleware, + response::{IntoResponse, Response}, routing::{get, post}, }; use axum_server::tls_rustls::RustlsConfig; +use reqwest::{StatusCode, header}; use secrecy::ExposeSecret; use sqlx::{PgPool, postgres::PgPoolOptions}; use std::{net::TcpListener, sync::Arc, time::Duration}; @@ -124,7 +127,6 @@ pub fn app( .route("/logout", post(logout)) .layer(middleware::from_fn(require_auth)); Router::new() - .nest_service("/assets", ServeDir::new("assets")) .route("/", get(home)) .route("/login", get(get_login).post(post_login)) .route("/health_check", get(health_check)) @@ -134,7 +136,9 @@ pub fn app( .route("/unsubscribe/confirm", get(unsubscribe_confirm)) .route("/posts", get(list_posts)) .route("/posts/{post_id}", get(see_post)) + .route("/favicon.ico", get(favicon)) .nest("/admin", admin_routes) + .nest_service("/assets", ServeDir::new("assets")) .layer( TraceLayer::new_for_http().make_span_with(|request: &Request<_>| { let matched_path = request @@ -156,3 +160,22 @@ pub fn app( .fallback(not_found) .with_state(app_state) } + +pub async fn favicon() -> Response { + match tokio::fs::read("assets/favicon.png").await { + Ok(content) => { + let bytes = Bytes::from(content); + let body = bytes.into(); + Response::builder() + .status(StatusCode::OK) + .header(header::CONTENT_TYPE, "image/x-icon") + .header(header::CACHE_CONTROL, "public, max-age=86400") + .body(body) + .unwrap() + } + Err(e) => { + tracing::error!("Error while reading favicon.ico: {}", e); + StatusCode::NOT_FOUND.into_response() + } + } +}