From 6d8e906f7c3d850120f94c7a784690442503aced Mon Sep 17 00:00:00 2001 From: Vika Date: Mon, 26 Aug 2024 21:00:24 +0300 Subject: Explicitly allow caching IndieAuth client metadata This might save a round-trip for clients that know how to cache things. Such as Kittybox's HTTP fetcher. --- src/login.rs | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/src/login.rs b/src/login.rs index e105bcc..646c832 100644 --- a/src/login.rs +++ b/src/login.rs @@ -1,11 +1,12 @@ -use std::borrow::Cow; +use std::{borrow::Cow, str::FromStr}; use futures_util::FutureExt; use axum::{extract::{FromRef, Host, Query, State}, http::HeaderValue, response::IntoResponse, Form}; -use axum_extra::extract::{cookie::{self, Cookie}, SignedCookieJar}; +use axum_extra::{extract::{cookie::{self, Cookie}, SignedCookieJar}, headers::HeaderMapExt, TypedHeader}; use hyper::{header::{CACHE_CONTROL, LOCATION}, StatusCode}; use kittybox_frontend_renderer::{Template, LoginPage, LogoutPage}; use kittybox_indieauth::{AuthorizationResponse, Error, GrantType, PKCEVerifier, Scope, Scopes}; +use sha2::Digest; use crate::database::Storage; @@ -321,7 +322,24 @@ async fn client_metadata( State(storage): State, // XXX: blocked on https://github.com/hyperium/headers/pull/162 //TypedHeader(accept): TypedHeader + cached: Option>, ) -> axum::response::Response { + let etag = { + let mut digest = sha2::Sha256::new(); + digest.update(env!("CARGO_PKG_NAME").as_bytes()); + digest.update(b" "); + digest.update(env!("CARGO_PKG_VERSION").as_bytes()); + digest.update(b" "); + digest.update(crate::OAUTH2_SOFTWARE_ID.as_bytes()); + + let etag = String::from("W/") + &hex::encode(digest.finalize()); + axum_extra::headers::ETag::from_str(&etag).unwrap() + }; + if let Some(cached) = cached { + if cached.precondition_passes(&etag) { + return StatusCode::NOT_MODIFIED.into_response() + } + } let client_uri: url::Url = format!("https://{}/", host).parse().unwrap(); let client_id: url::Url = { let mut url = client_uri.clone(); @@ -345,6 +363,9 @@ async fn client_metadata( let mut response = metadata.into_response(); // Indicate to upstream caches this endpoint does different things depending on the Accept: header. response.headers_mut().append("Vary", HeaderValue::from_static("Accept")); + // Cache this metadata for an hour. + response.headers_mut().append("Cache-Control", HeaderValue::from_static("max-age=600")); + response.headers_mut().typed_insert(etag); response } -- cgit 1.4.1