From fc6d26e821889023c31434bbdacbe777d9b15940 Mon Sep 17 00:00:00 2001 From: nazeh Date: Thu, 17 Oct 2024 21:26:29 +0300 Subject: [PATCH] feat(homeserver): support if-modified-since header in HEAD requests --- pubky-homeserver/src/routes/public.rs | 72 ++++++++++++++++++--------- 1 file changed, 49 insertions(+), 23 deletions(-) diff --git a/pubky-homeserver/src/routes/public.rs b/pubky-homeserver/src/routes/public.rs index d55c0c5..43e120e 100644 --- a/pubky-homeserver/src/routes/public.rs +++ b/pubky-homeserver/src/routes/public.rs @@ -1,5 +1,6 @@ use axum::{ body::Body, + debug_handler, extract::State, http::{header, HeaderMap, HeaderValue, Response, StatusCode}, response::IntoResponse, @@ -45,6 +46,7 @@ pub async fn put( Ok(()) } +#[debug_handler] pub async fn get( State(state): State, headers: HeaderMap, @@ -107,7 +109,38 @@ pub async fn get( Ok(()) }); - if let Some(entry) = entry_rx.recv_async().await? { + get_entry( + headers, + entry_rx.recv_async().await?, + Some(Body::from_stream(chunks_rx.into_stream())), + ) +} + +pub async fn head( + State(state): State, + headers: HeaderMap, + pubky: Pubky, + path: EntryPath, +) -> Result { + verify(path.as_str())?; + + let rtxn = state.db.env.read_txn()?; + + get_entry( + headers, + state + .db + .get_entry(&rtxn, pubky.public_key(), path.as_str())?, + None, + ) +} + +pub fn get_entry( + headers: HeaderMap, + entry: Option, + body: Option, +) -> Result> { + if let Some(entry) = entry { // TODO: Enable seek API (range requests) // TODO: Gzip? or brotli? @@ -124,8 +157,10 @@ pub async fn get( if condition_http_date >= entry_http_date { *response.status_mut() = StatusCode::NOT_MODIFIED; } - } else { - *response.body_mut() = Body::from_stream(chunks_rx.into_stream()); + }; + + if let Some(body) = body { + *response.body_mut() = body; }; Ok(response) @@ -134,26 +169,6 @@ pub async fn get( } } -pub async fn head( - State(state): State, - pubky: Pubky, - path: EntryPath, -) -> Result { - verify(path.as_str())?; - - let rtxn = state.db.env.read_txn()?; - - match state - .db - .get_entry(&rtxn, pubky.public_key(), path.as_str())? - .as_ref() - .map(HeaderMap::from) - { - Some(headers) => Ok(headers), - None => Err(Error::with_status(StatusCode::NOT_FOUND)), - } -} - pub async fn delete( State(mut state): State, pubky: Pubky, @@ -287,6 +302,17 @@ mod tests { assert_eq!(response.status(), StatusCode::NOT_MODIFIED); + let response = client + .request(Method::HEAD, &url) + .header( + header::IF_MODIFIED_SINCE, + response.headers().get(header::LAST_MODIFIED).unwrap(), + ) + .send() + .await?; + + assert_eq!(response.status(), StatusCode::NOT_MODIFIED); + Ok(()) } }