Radish alpha
h
Radicle Heartwood Protocol & Stack
Radicle
Git (anonymous pull)
Log in to clone via SSH
httpd: Mark immutable response as such with Cache-Control header
◌ CI pending Thomas Scholtes committed 2 years ago
commit 1846e592ca3ce28125df1ea94d41042b13c46c20
parent a48081f2717f069d456ec09f31d9e639b232dbed
1 passed 1 pending (2 total) View logs
2 files changed +25 -10
modified radicle-httpd/src/api/v1/projects.rs
@@ -28,7 +28,7 @@ use radicle_surf::{diff, Glob, Oid, Repository};
use crate::api::error::Error;
use crate::api::project::Info;
use crate::api::{self, announce_refs, CobsQuery, Context, PaginationQuery, ProjectQuery};
-
use crate::axum_extra::{Path, Query};
+
use crate::axum_extra::{immutable_response, Path, Query};

const CACHE_1_HOUR: &str = "public, max-age=3600, must-revalidate";
const MAX_BODY_LIMIT: usize = 4_194_304;
@@ -195,6 +195,7 @@ async fn history_handler(
        per_page,
    } = qs;

+
    let is_immutable = parent.is_some();
    let sha = match parent {
        Some(commit) => commit,
        None => {
@@ -258,7 +259,11 @@ async fn history_handler(
        "stats":  repo.stats_from(&sha)?,
    });

-
    Ok::<_, Error>((StatusCode::OK, Json(response)))
+
    if is_immutable {
+
        Ok::<_, Error>(immutable_response(response).into_response())
+
    } else {
+
        Ok::<_, Error>(Json(response).into_response())
+
    }
}

/// Get project commit.
@@ -318,13 +323,13 @@ async fn commit_handler(
        }
    });

-
    let response = json!({
+
    let response: serde_json::Value = json!({
      "commit": api::json::commit(&commit),
      "diff": diff,
      "files": files,
      "branches": branches
    });
-
    Ok::<_, Error>(Json(response))
+
    Ok::<_, Error>(immutable_response(response))
}

/// Get diff between two commits
@@ -391,7 +396,7 @@ async fn diff_handler(

    let response = json!({ "diff": diff, "files": files, "commits": commits });

-
    Ok::<_, Error>(Json(response))
+
    Ok::<_, Error>(immutable_response(response))
}

/// Get project activity for the past year.
@@ -439,7 +444,7 @@ async fn tree_handler(
    if let Some(ref cache) = ctx.cache {
        let cache = &mut cache.tree.lock().await;
        if let Some(response) = cache.get(&(project, sha, path.clone())) {
-
            return Ok::<_, Error>(Json(response.clone()));
+
            return Ok::<_, Error>(immutable_response(response.clone()));
        }
    }

@@ -447,14 +452,14 @@ async fn tree_handler(
    let repo = Repository::open(paths::repository(storage, &project))?;
    let tree = repo.tree(sha, &path)?;
    let stats = repo.stats_from(&sha)?;
-
    let response = api::json::tree(&tree, &path, &stats);
+
    let response: serde_json::Value = api::json::tree(&tree, &path, &stats);

    if let Some(cache) = ctx.cache {
        let cache = &mut cache.tree.lock().await;
        cache.put((project, sha, path.clone()), response.clone());
    }

-
    Ok::<_, Error>(Json(response))
+
    Ok::<_, Error>(immutable_response(response))
}

/// Get all project remotes.
@@ -566,7 +571,7 @@ async fn readme_handler(
    {
        if let Ok(blob) = repo.blob(sha, &path) {
            let response = api::json::blob(&blob, &path);
-
            return Ok::<_, Error>(Json(response));
+
            return Ok::<_, Error>(immutable_response(response));
        }
    }

modified radicle-httpd/src/axum_extra.rs
@@ -2,7 +2,8 @@ use axum::extract::path::ErrorKind;
use axum::extract::rejection::{PathRejection, QueryRejection};
use axum::extract::FromRequestParts;
use axum::http::request::Parts;
-
use axum::http::StatusCode;
+
use axum::http::{header, StatusCode};
+
use axum::response::IntoResponse;
use axum::{async_trait, Json};

use serde::de::DeserializeOwned;
@@ -87,3 +88,12 @@ pub struct Error {
    success: bool,
    error: String,
}
+

+
/// Add a Cache-Control header that marks the response as immutable and instructs clients to cache
+
/// the response for 7 days.
+
pub fn immutable_response(data: impl serde::Serialize) -> impl IntoResponse {
+
    (
+
        [(header::CACHE_CONTROL, "public, max-age=604800, immutable")],
+
        Json(data),
+
    )
+
}