use super::*; use crate::cache::RangeSelection; use http::HeaderValue; fn settings() -> Settings { Settings { enabled: true, static_ignore_cookies: true, static_extensions: vec!["css".into()], ..Default::default() } } #[test] fn disabled_cache_retains_reason_without_matching_force_rules_or_reparsing_headers() { let settings = settings(); let mut headers = HeaderMap::new(); headers.insert("authorization", HeaderValue::from_static("private")); headers.insert( "cache-control", HeaderValue::from_static("max-age=not-a-number"), ); for reason in [ "cache_disabled", "route_disabled", "admin_control_plane", "basic_auth", "tinyauth", "authelia", "authentik", "sticky_cookie", "request_upgrade", ] { let plan = CachePlan::new(Some(reason), &settings, "/style.css", || { panic!("disabled cache must not match force-cache rules") }); assert!(!plan.force_cache()); assert!(!plan.ignore_cookie()); let policy = plan.request_policy(&Method::GET, &headers, true, "/style.css", false, &settings); assert_eq!(policy, RequestPolicy::Bypass(reason)); assert_eq!( combine_policy(policy, || panic!( "disabled cache must not parse post-rule policy" )), policy ); } } #[test] fn cache_on_keeps_all_existing_request_policy_outcomes() { let settings = settings(); for forced in [false, true] { let plan = CachePlan::new(None, &settings, "/style.css", || forced); for (name, value) in [ ("x-irrelevant", "yes"), ("cache-control", "no-store"), ("cache-control", "no-cache"), ("cache-control", "max-age=0"), ("cache-control", "min-fresh=broken"), ("authorization", "private"), ("cookie", "session=private"), ("range", "bytes=0-2"), ("range", "bytes=0-2,4-5"), ("if-range", "\"etag\""), ("if-match", "\"etag\""), ("upgrade", "websocket"), ] { let mut headers = HeaderMap::new(); headers.insert( http::HeaderName::from_bytes(name.as_bytes()).unwrap(), value.parse().unwrap(), ); for method in [Method::GET, Method::HEAD, Method::POST] { for body_empty in [false, true] { let expected = if forced { crate::cache::forced_request_policy(&method, &headers, body_empty) } else { crate::cache::request_policy( &method, &headers, body_empty, "/style.css", false, &settings, ) }; assert_eq!( plan.request_policy( &method, &headers, body_empty, "/style.css", false, &settings ), expected ); } } } } } #[test] fn request_header_rules_cannot_relax_bypass_or_revalidation() { let cases = [ RequestPolicy::Use, RequestPolicy::Revalidate("request_no_cache"), RequestPolicy::Revalidate("request_max_age"), RequestPolicy::Bypass("request_authorization"), RequestPolicy::Bypass("request_no_store"), ]; for original in cases { for rewritten in cases { let expected = match (original, rewritten) { (RequestPolicy::Bypass(reason), _) | (_, RequestPolicy::Bypass(reason)) => { RequestPolicy::Bypass(reason) } (RequestPolicy::Revalidate(reason), _) | (_, RequestPolicy::Revalidate(reason)) => { RequestPolicy::Revalidate(reason) } _ => RequestPolicy::Use, }; assert_eq!(combine_policy(original, || rewritten), expected); } } } #[test] fn cache_off_still_blocks_range_transformation_and_preserves_origin_headers() { for method in [Method::GET, Method::HEAD, Method::POST] { for range in [ None, Some("bytes=0-2"), Some("bytes=0-2,4-5"), Some("broken"), Some("bytes=99-"), ] { let mut headers = HeaderMap::new(); if let Some(range) = range { headers.insert("range", range.parse().unwrap()); } headers.insert("if-range", HeaderValue::from_static("\"same-validator\"")); headers.insert( "if-none-match", HeaderValue::from_static("\"client-validator\""), ); let original = headers.clone(); let baseline = crate::cache::request_range(&method, &headers); assert_eq!(range_selection(true, &method, &headers), baseline); assert_eq!( matches!( range_selection(false, &method, &headers), RangeSelection::None ), matches!(baseline, RangeSelection::None) ); assert_eq!( headers, original, "origin must receive the original Range/conditional fields" ); } } } #[test] fn force_cache_keeps_cookie_variants_and_disabled_cookie_matching_has_no_effect() { let settings = settings(); let ordinary = CachePlan::new(None, &settings, "/style.css", || false); assert!(ordinary.ignore_cookie()); let forced = CachePlan::new(None, &settings, "/style.css", || true); assert!(forced.force_cache()); assert!(!forced.ignore_cookie()); let disabled = CachePlan::new(Some("route_disabled"), &settings, "/style.css", || true); assert!(!disabled.force_cache()); assert!(!disabled.ignore_cookie()); }