@@ -12,7 +12,9 @@ use std::time::Duration;
1212use web_time:: { SystemTime , UNIX_EPOCH } ;
1313
1414use crate :: cache_policy:: {
15- apply_no_store_private_to_headers, CachePolicy , EdgeCacheHeader , NO_STORE_PRIVATE_CACHE_CONTROL ,
15+ CachePolicy , EdgeCacheHeader , NO_STORE_PRIVATE_CACHE_CONTROL ,
16+ apply_no_store_private_to_headers, cache_control_headers_are_private_or_no_store,
17+ remove_edge_cache_headers,
1618} ;
1719use crate :: constants:: {
1820 HEADER_ACCEPT , HEADER_ACCEPT_ENCODING , HEADER_ACCEPT_LANGUAGE , HEADER_REFERER ,
@@ -125,7 +127,11 @@ impl AssetProxyCachePolicy {
125127 Self :: OriginControlled => { }
126128 Self :: NoStorePrivate => apply_no_store_cache_control ( response) ,
127129 Self :: Normalized ( policy) => {
128- policy. apply_to_headers ( response. headers_mut ( ) , edge_header)
130+ if cache_control_headers_are_private_or_no_store ( response. headers ( ) ) {
131+ remove_edge_cache_headers ( response. headers_mut ( ) ) ;
132+ } else {
133+ policy. apply_to_headers ( response. headers_mut ( ) , edge_header) ;
134+ }
129135 }
130136 }
131137 }
@@ -3751,7 +3757,7 @@ mod tests {
37513757 }
37523758
37533759 #[ test]
3754- fn handle_asset_proxy_request_applies_configured_normalized_cache_policy ( ) {
3760+ fn handle_asset_proxy_request_replaces_third_party_cache_policy_for_rehosted_asset ( ) {
37553761 futures:: executor:: block_on ( async {
37563762 let stub = Arc :: new ( StubHttpClient :: new ( ) ) ;
37573763 stub. push_response_with_headers (
@@ -3801,7 +3807,7 @@ mod tests {
38013807 assert_eq ! (
38023808 response_header( & response, header:: CACHE_CONTROL ) ,
38033809 Some ( "public, max-age=31536000, immutable" ) ,
3804- "core response should apply browser cache policy immediately "
3810+ "configured rehost policy should replace the third-party no-store directive "
38053811 ) ;
38063812 assert ! (
38073813 response. headers( ) . get( "surrogate-control" ) . is_none( ) ,
@@ -3823,6 +3829,43 @@ mod tests {
38233829 } ) ;
38243830 }
38253831
3832+ #[ test]
3833+ fn normalized_asset_policy_preserves_final_private_or_no_store_directives ( ) {
3834+ for cache_control in [ "private, max-age=0" , "no-store" ] {
3835+ let mut response = edge_response_builder ( )
3836+ . header ( header:: CACHE_CONTROL , cache_control)
3837+ . header ( "surrogate-control" , "max-age=31536000" )
3838+ . header ( "cdn-cache-control" , "max-age=31536000" )
3839+ . header ( "cloudflare-cdn-cache-control" , "max-age=31536000" )
3840+ . body ( EdgeBody :: empty ( ) )
3841+ . expect ( "should build asset response" ) ;
3842+
3843+ AssetProxyCachePolicy :: Normalized ( CachePolicy :: public_immutable ( Duration :: from_secs (
3844+ 31_536_000 ,
3845+ ) ) )
3846+ . apply_after_route_finalization ( & mut response, EdgeCacheHeader :: SurrogateControl ) ;
3847+
3848+ assert_eq ! (
3849+ response
3850+ . headers( )
3851+ . get( header:: CACHE_CONTROL )
3852+ . and_then( |value| value. to_str( ) . ok( ) ) ,
3853+ Some ( cache_control) ,
3854+ "final privacy directive should veto normalized cache policy"
3855+ ) ;
3856+ assert ! (
3857+ [
3858+ "surrogate-control" ,
3859+ "cdn-cache-control" ,
3860+ "cloudflare-cdn-cache-control" ,
3861+ ]
3862+ . iter( )
3863+ . all( |name| !response. headers( ) . contains_key( * name) ) ,
3864+ "final privacy directive should remove every edge-cache header"
3865+ ) ;
3866+ }
3867+ }
3868+
38263869 #[ test]
38273870 fn handle_asset_proxy_request_leaves_non_matching_assets_origin_controlled ( ) {
38283871 futures:: executor:: block_on ( async {
0 commit comments