mirror of
https://codeberg.org/Toasterson/ips.git
synced 2026-04-10 13:20:42 +00:00
Add content-type handling for JSON catalog artifacts and weak ETag for manifests
- Ensured correct `Content-Type` header for catalog artifacts (`catalog.attrs` and `catalog.*`) in HTTP responses. - Added SHA-1 based weak ETag generation for manifest responses to improve caching and legacy compatibility. - Updated `integration_tests` to validate content-type and ETag correctness. - Added new dependency `sha1` for hashing support.
This commit is contained in:
parent
e87d1a3166
commit
cff3d5d960
5 changed files with 38 additions and 3 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -2120,6 +2120,7 @@ dependencies = [
|
|||
"rustls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha1",
|
||||
"socket2",
|
||||
"tempfile",
|
||||
"thiserror 2.0.17",
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ serde = { version = "1.0", features = ["derive"] }
|
|||
serde_json = "1.0"
|
||||
dirs = "6"
|
||||
nix = { version = "0.30", features = ["signal", "process", "user", "fs"] }
|
||||
sha1 = "0.10"
|
||||
|
||||
# Telemetry
|
||||
tracing = "0.1"
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ use crate::repo::DepotRepo;
|
|||
use crate::errors::DepotError;
|
||||
use tower_http::services::ServeFile;
|
||||
use tower::ServiceExt;
|
||||
use axum::http::header;
|
||||
|
||||
pub async fn get_catalog_v1(
|
||||
State(repo): State<Arc<DepotRepo>>,
|
||||
|
|
@ -19,7 +20,14 @@ pub async fn get_catalog_v1(
|
|||
let result = service.oneshot(req).await;
|
||||
|
||||
match result {
|
||||
Ok(res) => Ok(res.into_response()),
|
||||
Ok(mut res) => {
|
||||
// Ensure correct content-type for JSON catalog artifacts regardless of file extension
|
||||
let is_catalog_json = filename == "catalog.attrs" || filename.starts_with("catalog.");
|
||||
if is_catalog_json {
|
||||
res.headers_mut().insert(header::CONTENT_TYPE, header::HeaderValue::from_static("application/json"));
|
||||
}
|
||||
Ok(res.into_response())
|
||||
},
|
||||
Err(e) => Err(DepotError::Server(e.to_string())),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use crate::repo::DepotRepo;
|
|||
use crate::errors::DepotError;
|
||||
use libips::fmri::Fmri;
|
||||
use std::str::FromStr;
|
||||
use sha1::Digest as _;
|
||||
|
||||
pub async fn get_manifest(
|
||||
State(repo): State<Arc<DepotRepo>>,
|
||||
|
|
@ -16,9 +17,16 @@ pub async fn get_manifest(
|
|||
let fmri = Fmri::from_str(&fmri_str).map_err(|e| DepotError::Repo(libips::repository::RepositoryError::Other(e.to_string())))?;
|
||||
|
||||
let content = repo.get_manifest_text(&publisher, &fmri)?;
|
||||
// Compute weak ETag from SHA-1 of manifest content (legacy friendly)
|
||||
let mut hasher = sha1::Sha1::new();
|
||||
hasher.update(content.as_bytes());
|
||||
let etag = format!("\"{}\"", format!("{:x}", hasher.finalize()));
|
||||
|
||||
Ok((
|
||||
[(header::CONTENT_TYPE, "text/plain")],
|
||||
content
|
||||
[
|
||||
(header::CONTENT_TYPE, "text/plain"),
|
||||
(header::ETAG, etag.as_str()),
|
||||
],
|
||||
content,
|
||||
).into_response())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -230,4 +230,21 @@ async fn test_ini_only_repo_serving_catalog() {
|
|||
let body = resp.text().await.unwrap();
|
||||
assert!(body.contains("package-count"));
|
||||
assert!(body.contains("parts"));
|
||||
|
||||
// Also fetch individual catalog parts
|
||||
for part in ["catalog.base.C", "catalog.dependency.C", "catalog.summary.C"].iter() {
|
||||
let url = format!("{}/{}/catalog/1/{}", base_url, publisher, part);
|
||||
let resp = client.get(&url).send().await.unwrap();
|
||||
assert!(resp.status().is_success(), "{} status: {:?}", part, resp.status());
|
||||
let ct = resp.headers().get("content-type").unwrap().to_str().unwrap().to_string();
|
||||
assert!(ct.contains("application/json"), "content-type for {} was {}", part, ct);
|
||||
let txt = resp.text().await.unwrap();
|
||||
assert!(!txt.is_empty(), "{} should not be empty", part);
|
||||
if *part == "catalog.base.C" {
|
||||
assert!(txt.contains(&publisher) && txt.contains("version"), "base part should contain publisher and version");
|
||||
} else {
|
||||
// dependency/summary may be empty for this test package; at least ensure signature is present
|
||||
assert!(txt.contains("_SIGNATURE"), "{} should contain a signature field", part);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue