mod common;
use common::{
png_bytes, send_public_get_request, send_public_get_request_with_headers,
send_transform_request, signed_target, spawn_server, split_response, temp_dir,
};
use std::collections::BTreeMap;
use std::fs;
use truss::{MediaType, RawArtifact, ServerConfig, sniff_artifact};
#[test]
fn serve_once_private_transform_sets_no_store_and_safety_headers() {
let storage_root = temp_dir("private-headers");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let (addr, handle) = spawn_server(ServerConfig::new(storage_root, Some("secret".to_string())));
let response = send_transform_request(
addr,
r#"{"source":{"kind":"path","path":"/image.png"},"options":{"format":"jpeg"}}"#,
Some("secret"),
);
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (header, content_type, body) = split_response(&response);
let artifact = sniff_artifact(RawArtifact::new(body, None)).expect("sniff transformed output");
assert!(header.starts_with("HTTP/1.1 200 OK"));
assert_eq!(content_type, "image/jpeg");
assert!(header.lines().any(|line| line == "Cache-Control: no-store"));
assert!(header.contains("ETag: \"sha256-"));
assert!(
header
.lines()
.any(|line| line == "X-Content-Type-Options: nosniff")
);
assert!(
header
.lines()
.any(|line| line == "Content-Disposition: inline; filename=\"truss.jpeg\"")
);
assert_eq!(artifact.media_type, MediaType::Jpeg);
}
#[test]
fn serve_once_public_get_negotiates_accept_and_sets_cache_headers() {
let storage_root = temp_dir("public-negotiate");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let (addr, handle) = spawn_server(
ServerConfig::new(storage_root, Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value"),
);
let target = signed_target(
"/images/by-path",
BTreeMap::from([
("path".to_string(), "/image.png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
]),
"cdn.example.com",
"secret-value",
);
let response = send_public_get_request_with_headers(
addr,
&target,
"cdn.example.com",
&[("Accept", "image/avif,image/webp;q=0.8")],
);
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (header, content_type, body) = split_response(&response);
let artifact = sniff_artifact(RawArtifact::new(body, None)).expect("sniff transformed output");
assert!(header.starts_with("HTTP/1.1 200 OK"));
assert_eq!(content_type, "image/avif");
assert!(
header.lines().any(|line| {
line == "Cache-Control: public, max-age=3600, stale-while-revalidate=60"
})
);
assert!(header.contains("ETag: \"sha256-"));
assert!(header.lines().any(|line| line == "Vary: Accept"));
assert!(
header
.lines()
.any(|line| line == "X-Content-Type-Options: nosniff")
);
assert!(
header
.lines()
.any(|line| line == "Content-Disposition: inline; filename=\"truss.avif\"")
);
assert_eq!(artifact.media_type, MediaType::Avif);
}
#[test]
fn serve_once_public_get_reports_vary_accept_when_the_request_omits_accept() {
let storage_root = temp_dir("public-no-accept");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let (addr, handle) = spawn_server(
ServerConfig::new(storage_root, Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value"),
);
let target = signed_target(
"/images/by-path",
BTreeMap::from([
("path".to_string(), "/image.png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
]),
"cdn.example.com",
"secret-value",
);
let response = send_public_get_request(addr, &target, "cdn.example.com");
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (header, content_type, _) = split_response(&response);
assert!(header.starts_with("HTTP/1.1 200 OK"), "got: {header}");
assert_eq!(content_type, "image/png");
assert!(
header.lines().any(|line| line == "Vary: Accept"),
"a negotiable URL must report Vary: Accept even when the request sent no Accept: {header}"
);
}
#[test]
fn serve_once_public_get_omits_vary_accept_when_the_format_is_explicit() {
let storage_root = temp_dir("public-explicit-format");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let (addr, handle) = spawn_server(
ServerConfig::new(storage_root, Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value"),
);
let target = signed_target(
"/images/by-path",
BTreeMap::from([
("path".to_string(), "/image.png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
("format".to_string(), "jpeg".to_string()),
]),
"cdn.example.com",
"secret-value",
);
let response = send_public_get_request_with_headers(
addr,
&target,
"cdn.example.com",
&[("Accept", "image/avif,image/webp")],
);
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (header, content_type, _) = split_response(&response);
assert!(header.starts_with("HTTP/1.1 200 OK"), "got: {header}");
assert_eq!(content_type, "image/jpeg");
assert!(
!header.lines().any(|line| line == "Vary: Accept"),
"an explicitly formatted URL does not vary on Accept: {header}"
);
}
#[test]
fn serve_once_public_get_reports_vary_accept_on_not_acceptable() {
let storage_root = temp_dir("public-not-acceptable");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let (addr, handle) = spawn_server(
ServerConfig::new(storage_root, Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value"),
);
let target = signed_target(
"/images/by-path",
BTreeMap::from([
("path".to_string(), "/image.png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
]),
"cdn.example.com",
"secret-value",
);
let response = send_public_get_request_with_headers(
addr,
&target,
"cdn.example.com",
&[("Accept", "text/html")],
);
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (header, _, _) = split_response(&response);
assert!(
header.starts_with("HTTP/1.1 406"),
"expected 406, got: {header}"
);
assert!(
header.lines().any(|line| line == "Vary: Accept"),
"the 406 was selected by Accept and must say so: {header}"
);
}
#[test]
fn serve_once_public_get_returns_not_modified_for_matching_etag() {
let storage_root = temp_dir("public-etag");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let config = ServerConfig::new(storage_root.clone(), Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value");
let target = signed_target(
"/images/by-path",
BTreeMap::from([
("path".to_string(), "/image.png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
("format".to_string(), "jpeg".to_string()),
]),
"cdn.example.com",
"secret-value",
);
let (addr, handle) = spawn_server(config.clone());
let first_response = send_public_get_request(addr, &target, "cdn.example.com");
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (first_header, _, _) = split_response(&first_response);
let etag = first_header
.lines()
.find_map(|line| line.strip_prefix("ETag: "))
.expect("etag header")
.to_string();
let (addr, handle) = spawn_server(config);
let second_response = send_public_get_request_with_headers(
addr,
&target,
"cdn.example.com",
&[("If-None-Match", &etag)],
);
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (header, content_type, body) = split_response(&second_response);
assert!(header.starts_with("HTTP/1.1 304 Not Modified"));
assert!(content_type.is_empty());
assert!(body.is_empty());
assert!(header.contains("ETag: "));
assert!(
header.lines().any(|line| {
line == "Cache-Control: public, max-age=3600, stale-while-revalidate=60"
})
);
}
#[test]
fn serve_once_shares_one_cache_entry_across_equivalent_accept_headers() {
let storage_root = temp_dir("accept-cache-sharing");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let cache_root = temp_dir("accept-cache-sharing-cache");
let config = ServerConfig::new(storage_root, Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value")
.with_cache_root(cache_root.clone());
let target = signed_target(
"/images/by-path",
BTreeMap::from([
("path".to_string(), "/image.png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
]),
"cdn.example.com",
"secret-value",
);
let (addr, handle) = spawn_server(config.clone());
let first = send_public_get_request_with_headers(
addr,
&target,
"cdn.example.com",
&[("Accept", "image/webp")],
);
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (first_header, first_content_type, first_body) = split_response(&first);
assert!(first_header.contains("Cache-Status: \"truss\"; fwd=miss"));
let (addr, handle) = spawn_server(config);
let second = send_public_get_request_with_headers(
addr,
&target,
"cdn.example.com",
&[("Accept", "image/webp,image/png;q=0.5")],
);
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (second_header, second_content_type, second_body) = split_response(&second);
assert_eq!(first_content_type, second_content_type);
assert_eq!(first_body, second_body);
assert!(
second_header.contains("Cache-Status: \"truss\"; hit"),
"the second request should hit the entry the first wrote: {second_header}"
);
assert!(second_header.lines().any(|line| line == "Vary: Accept"));
let entries = walk_files(&cache_root);
assert_eq!(
entries, 1,
"two equivalent Accept headers wrote {entries} cache entries"
);
}
fn walk_files(root: &std::path::Path) -> usize {
let Ok(entries) = fs::read_dir(root) else {
return 0;
};
entries
.flatten()
.map(|entry| {
let path = entry.path();
if path.is_dir() { walk_files(&path) } else { 1 }
})
.sum()
}
#[test]
fn serve_once_carries_transform_warnings_as_headers_on_miss_and_hit() {
let storage_root = temp_dir("warning-header");
fs::write(
storage_root.join("tagged.jpg"),
include_bytes!("../integration/fixtures/exif-rotated.jpg"),
)
.expect("write source fixture");
let cache_root = temp_dir("warning-header-cache");
let config = ServerConfig::new(storage_root, Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value")
.with_cache_root(cache_root);
let params = |auto_orient: Option<&str>| {
let mut params = BTreeMap::from([
("path".to_string(), "/tagged.jpg".to_string()),
("format".to_string(), "png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
]);
if let Some(value) = auto_orient {
params.insert("autoOrient".to_string(), value.to_string());
}
signed_target("/images/by-path", params, "cdn.example.com", "secret-value")
};
let warning_lines = |header: &str| -> Vec<String> {
header
.lines()
.filter(|line| line.starts_with("Truss-Warning: "))
.map(str::to_string)
.collect()
};
let dropped = params(Some("false"));
let (addr, handle) = spawn_server(config.clone());
let first = send_public_get_request(addr, &dropped, "cdn.example.com");
handle.join().expect("join").expect("serve");
let (first_header, _, _) = split_response(&first);
assert!(first_header.contains("Cache-Status: \"truss\"; fwd=miss"));
let first_warnings = warning_lines(&first_header);
assert_eq!(first_warnings.len(), 1, "{first_header}");
assert!(
first_warnings[0].contains("EXIF orientation 6"),
"{first_warnings:?}"
);
let (addr, handle) = spawn_server(config.clone());
let second = send_public_get_request(addr, &dropped, "cdn.example.com");
handle.join().expect("join").expect("serve");
let (second_header, _, _) = split_response(&second);
assert!(
second_header.contains("Cache-Status: \"truss\"; hit"),
"{second_header}"
);
assert_eq!(
warning_lines(&second_header),
first_warnings,
"the hit should repeat the warning the miss produced"
);
let (addr, handle) = spawn_server(config);
let applied = send_public_get_request(addr, ¶ms(None), "cdn.example.com");
handle.join().expect("join").expect("serve");
let (applied_header, _, _) = split_response(&applied);
assert!(
applied_header.starts_with("HTTP/1.1 200"),
"{applied_header}"
);
assert!(
warning_lines(&applied_header).is_empty(),
"nothing to warn about: {applied_header}"
);
}
#[test]
fn serve_once_public_get_refuses_fit_without_both_dimensions_on_a_warm_cache() {
let storage_root = temp_dir("fit-without-dimensions");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let cache_root = temp_dir("fit-without-dimensions-cache");
let config = ServerConfig::new(storage_root, Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value")
.with_cache_root(cache_root);
let valid_query = BTreeMap::from([
("path".to_string(), "/image.png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
("format".to_string(), "png".to_string()),
]);
let mut invalid_query = valid_query.clone();
invalid_query.insert("fit".to_string(), "cover".to_string());
let warm_target = signed_target(
"/images/by-path",
valid_query,
"cdn.example.com",
"secret-value",
);
let invalid_target = signed_target(
"/images/by-path",
invalid_query,
"cdn.example.com",
"secret-value",
);
let (addr, handle) = spawn_server(config.clone());
let warm_up = send_public_get_request(addr, &warm_target, "cdn.example.com");
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (warm_header, _, _) = split_response(&warm_up);
assert!(
warm_header.starts_with("HTTP/1.1 200 OK"),
"the warm-up request must write a cache entry: {warm_header}"
);
let (addr, handle) = spawn_server(config);
let response = send_public_get_request(addr, &invalid_target, "cdn.example.com");
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (header, _, body) = split_response(&response);
let body = String::from_utf8_lossy(&body);
assert!(
header.starts_with("HTTP/1.1 400 Bad Request"),
"fit without both dimensions is refused whatever the cache holds: {header}\n{body}"
);
assert!(
body.contains("fit requires both width and height"),
"the refusal names the rule the caller broke: {body}"
);
}
#[test]
fn serve_once_public_get_refuses_position_without_both_dimensions_on_a_warm_cache() {
let storage_root = temp_dir("position-without-dimensions");
fs::write(storage_root.join("image.png"), png_bytes()).expect("write source fixture");
let cache_root = temp_dir("position-without-dimensions-cache");
let config = ServerConfig::new(storage_root, Some("secret".to_string()))
.with_signed_url_credentials("public-dev", "secret-value")
.with_cache_root(cache_root);
let valid_query = BTreeMap::from([
("path".to_string(), "/image.png".to_string()),
("keyId".to_string(), "public-dev".to_string()),
("expires".to_string(), "4102444800".to_string()),
("format".to_string(), "png".to_string()),
]);
let mut invalid_query = valid_query.clone();
invalid_query.insert("position".to_string(), "center".to_string());
let warm_target = signed_target(
"/images/by-path",
valid_query,
"cdn.example.com",
"secret-value",
);
let invalid_target = signed_target(
"/images/by-path",
invalid_query,
"cdn.example.com",
"secret-value",
);
let (addr, handle) = spawn_server(config.clone());
let _ = send_public_get_request(addr, &warm_target, "cdn.example.com");
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (addr, handle) = spawn_server(config);
let response = send_public_get_request(addr, &invalid_target, "cdn.example.com");
handle
.join()
.expect("join server thread")
.expect("serve one request");
let (header, _, body) = split_response(&response);
let body = String::from_utf8_lossy(&body);
assert!(
header.starts_with("HTTP/1.1 400 Bad Request"),
"position without both dimensions is refused whatever the cache holds: {header}\n{body}"
);
assert!(
body.contains("position requires both width and height"),
"the refusal names the rule the caller broke: {body}"
);
}