forked from nrabulinski/attic
server: Set a custom header if the cache is public
This can be used as a signal to improve caching. Only done for the Nix Binary Cache APIs for now.
This commit is contained in:
parent
6c4d04da74
commit
05a5e9cca8
7
attic/src/api/binary_cache.rs
Normal file
7
attic/src/api/binary_cache.rs
Normal file
|
@ -0,0 +1,7 @@
|
|||
//! Nix Binary Cache server.
|
||||
//!
|
||||
//! This module contains Attic-specific extensions to the
|
||||
//! Nix Binary Cache API.
|
||||
|
||||
/// Header indicating a cache's visibility.
|
||||
pub const ATTIC_CACHE_VISIBILITY: &str = "X-Attic-Cache-Visibility";
|
|
@ -1 +1,2 @@
|
|||
pub mod binary_cache;
|
||||
pub mod v1;
|
||||
|
|
|
@ -85,6 +85,8 @@ async fn get_nix_cache_info(
|
|||
})
|
||||
.await?;
|
||||
|
||||
req_state.set_public_cache(cache.is_public);
|
||||
|
||||
let info = NixCacheInfo {
|
||||
want_mass_query: true,
|
||||
store_dir: cache.store_dir.into(),
|
||||
|
@ -137,6 +139,8 @@ async fn get_store_path_info(
|
|||
.get_permission_for_cache(&cache_name, cache.is_public);
|
||||
permission.require_pull()?;
|
||||
|
||||
req_state.set_public_cache(cache.is_public);
|
||||
|
||||
let mut narinfo = object.to_nar_info(&nar)?;
|
||||
|
||||
if narinfo.signature().is_none() {
|
||||
|
@ -189,6 +193,8 @@ async fn get_nar(
|
|||
.get_permission_for_cache(&cache_name, cache.is_public);
|
||||
permission.require_pull()?;
|
||||
|
||||
req_state.set_public_cache(cache.is_public);
|
||||
|
||||
database.bump_object_last_accessed(object.id).await?;
|
||||
|
||||
let remote_file = nar.remote_file.0;
|
||||
|
|
|
@ -26,6 +26,7 @@ pub mod oobe;
|
|||
mod storage;
|
||||
|
||||
use std::net::SocketAddr;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
|
@ -46,7 +47,7 @@ use attic::cache::CacheName;
|
|||
use config::{Config, StorageConfig};
|
||||
use database::migration::{Migrator, MigratorTrait};
|
||||
use error::{ErrorKind, ServerError, ServerResult};
|
||||
use middleware::{init_request_state, restrict_host};
|
||||
use middleware::{init_request_state, restrict_host, set_visibility_header};
|
||||
use storage::{LocalBackend, S3Backend, StorageBackend};
|
||||
|
||||
type State = Arc<StateInner>;
|
||||
|
@ -79,6 +80,12 @@ struct RequestStateInner {
|
|||
|
||||
/// Whether the client claims the connection is HTTPS or not.
|
||||
client_claims_https: bool,
|
||||
|
||||
/// Whether the cache the client's interacting with is public.
|
||||
///
|
||||
/// This is purely informational and used to add the `X-Attic-Cache-Visibility`.
|
||||
/// header in responses.
|
||||
public_cache: AtomicBool,
|
||||
}
|
||||
|
||||
impl StateInner {
|
||||
|
@ -167,6 +174,11 @@ impl RequestStateInner {
|
|||
fn substituter_endpoint(&self, cache: CacheName) -> ServerResult<String> {
|
||||
Ok(format!("{}{}", self.api_endpoint()?, cache.as_str()))
|
||||
}
|
||||
|
||||
/// Indicates whether the cache the client is interacting with is public.
|
||||
fn set_public_cache(&self, public: bool) {
|
||||
self.public_cache.store(public, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
|
||||
/// The fallback route.
|
||||
|
@ -192,6 +204,7 @@ pub async fn run_api_server(cli_listen: Option<SocketAddr>, config: Config) -> R
|
|||
.fallback(fallback)
|
||||
// middlewares
|
||||
.layer(axum::middleware::from_fn(apply_auth))
|
||||
.layer(axum::middleware::from_fn(set_visibility_header))
|
||||
.layer(axum::middleware::from_fn(init_request_state))
|
||||
.layer(axum::middleware::from_fn(restrict_host))
|
||||
.layer(Extension(state.clone()))
|
||||
|
|
|
@ -1,15 +1,17 @@
|
|||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use axum::{
|
||||
extract::{Extension, Host},
|
||||
http::Request,
|
||||
http::{HeaderValue, Request},
|
||||
middleware::Next,
|
||||
response::Response,
|
||||
};
|
||||
|
||||
use super::{AuthState, RequestStateInner, State};
|
||||
use super::{AuthState, RequestState, RequestStateInner, State};
|
||||
use crate::error::{ErrorKind, ServerResult};
|
||||
use attic::api::binary_cache::ATTIC_CACHE_VISIBILITY;
|
||||
|
||||
/// Initializes per-request state.
|
||||
pub async fn init_request_state<B>(
|
||||
|
@ -31,6 +33,7 @@ pub async fn init_request_state<B>(
|
|||
api_endpoint: state.config.api_endpoint.to_owned(),
|
||||
host,
|
||||
client_claims_https,
|
||||
public_cache: AtomicBool::new(false),
|
||||
});
|
||||
|
||||
req.extensions_mut().insert(req_state);
|
||||
|
@ -55,3 +58,20 @@ pub async fn restrict_host<B>(
|
|||
|
||||
Ok(next.run(req).await)
|
||||
}
|
||||
|
||||
/// Sets the `X-Attic-Cache-Visibility` header in responses.
|
||||
pub(crate) async fn set_visibility_header<B>(
|
||||
Extension(req_state): Extension<RequestState>,
|
||||
req: Request<B>,
|
||||
next: Next<B>,
|
||||
) -> ServerResult<Response> {
|
||||
let mut response = next.run(req).await;
|
||||
|
||||
if req_state.public_cache.load(Ordering::Relaxed) {
|
||||
response
|
||||
.headers_mut()
|
||||
.append(ATTIC_CACHE_VISIBILITY, HeaderValue::from_static("public"));
|
||||
}
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue