@@ -496,7 +496,10 @@ impl S3SigV4AuthConfig {
496496#[ derive( Debug , Clone , Deserialize , Serialize ) ]
497497pub struct AssetImageOptimizerConfig {
498498 /// Enables Image Optimizer for this route when the table is present.
499- #[ serde( default = "default_asset_image_optimizer_enabled" ) ]
499+ #[ serde(
500+ default = "default_asset_image_optimizer_enabled" ,
501+ deserialize_with = "bool_from_bool_or_str"
502+ ) ]
500503 pub enabled : bool ,
501504 /// Image Optimizer processing region.
502505 pub region : String ,
@@ -730,7 +733,10 @@ pub enum MissingCropOffsetMode {
730733#[ derive( Debug , Clone , Deserialize , Serialize ) ]
731734pub struct ImageOptimizerCropOffsetsConfig {
732735 /// Enable crop offset normalization.
733- #[ serde( default = "default_asset_image_optimizer_enabled" ) ]
736+ #[ serde(
737+ default = "default_asset_image_optimizer_enabled" ,
738+ deserialize_with = "bool_from_bool_or_str"
739+ ) ]
734740 pub enabled : bool ,
735741 /// Query parameter containing the x-axis offset.
736742 #[ serde( default = "default_crop_offset_x_param" ) ]
@@ -1706,6 +1712,23 @@ where
17061712 }
17071713}
17081714
1715+ pub ( crate ) fn bool_from_bool_or_str < ' de , D > ( deserializer : D ) -> Result < bool , D :: Error >
1716+ where
1717+ D : Deserializer < ' de > ,
1718+ {
1719+ let value = JsonValue :: deserialize ( deserializer) ?;
1720+ match value {
1721+ JsonValue :: Bool ( value) => Ok ( value) ,
1722+ JsonValue :: String ( value) => value
1723+ . trim ( )
1724+ . parse :: < bool > ( )
1725+ . map_err ( serde:: de:: Error :: custom) ,
1726+ other => Err ( serde:: de:: Error :: custom ( format ! (
1727+ "expected bool or parseable bool string, got {other}"
1728+ ) ) ) ,
1729+ }
1730+ }
1731+
17091732pub ( crate ) fn vec_from_seq_or_map < ' de , D , T > ( deserializer : D ) -> Result < Vec < T > , D :: Error >
17101733where
17111734 D : Deserializer < ' de > ,
@@ -2993,6 +3016,114 @@ mod tests {
29933016 }
29943017 }
29953018
3019+ #[ test]
3020+ fn proxy_asset_route_image_optimizer_env_accepts_nested_bool_strings_and_arrays ( ) {
3021+ let toml_str = crate_test_settings_str ( ) ;
3022+ let separator = ENVIRONMENT_VARIABLE_SEPARATOR ;
3023+ let vars = [
3024+ (
3025+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}PROXY{separator}ASSET_ROUTES{separator}0{separator}PREFIX" ) ,
3026+ Some ( "/.image/" ) ,
3027+ ) ,
3028+ (
3029+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}PROXY{separator}ASSET_ROUTES{separator}0{separator}ORIGIN_URL" ) ,
3030+ Some ( "https://bucket.s3.us-west-2.amazonaws.com" ) ,
3031+ ) ,
3032+ (
3033+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}PROXY{separator}ASSET_ROUTES{separator}0{separator}AUTH{separator}TYPE" ) ,
3034+ Some ( "s3_sigv4" ) ,
3035+ ) ,
3036+ (
3037+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}PROXY{separator}ASSET_ROUTES{separator}0{separator}AUTH{separator}REGION" ) ,
3038+ Some ( "us-west-2" ) ,
3039+ ) ,
3040+ (
3041+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}PROXY{separator}ASSET_ROUTES{separator}0{separator}AUTH{separator}ORIGIN_QUERY" ) ,
3042+ Some ( "strip" ) ,
3043+ ) ,
3044+ (
3045+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}PROXY{separator}ASSET_ROUTES{separator}0{separator}IMAGE_OPTIMIZER{separator}ENABLED" ) ,
3046+ Some ( "true" ) ,
3047+ ) ,
3048+ (
3049+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}PROXY{separator}ASSET_ROUTES{separator}0{separator}IMAGE_OPTIMIZER{separator}REGION" ) ,
3050+ Some ( "us_west" ) ,
3051+ ) ,
3052+ (
3053+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}PROXY{separator}ASSET_ROUTES{separator}0{separator}IMAGE_OPTIMIZER{separator}PROFILE_SET" ) ,
3054+ Some ( "default_images" ) ,
3055+ ) ,
3056+ (
3057+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}IMAGE_OPTIMIZER{separator}PROFILE_SETS{separator}DEFAULT_IMAGES{separator}BASE_PARAMS" ) ,
3058+ Some ( "quality=70&resize-filter=bicubic" ) ,
3059+ ) ,
3060+ (
3061+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}IMAGE_OPTIMIZER{separator}PROFILE_SETS{separator}DEFAULT_IMAGES{separator}DEFAULT_PROFILE" ) ,
3062+ Some ( "w828" ) ,
3063+ ) ,
3064+ (
3065+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}IMAGE_OPTIMIZER{separator}PROFILE_SETS{separator}DEFAULT_IMAGES{separator}PROFILES{separator}W828" ) ,
3066+ Some ( "format=auto&width=828" ) ,
3067+ ) ,
3068+ (
3069+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}IMAGE_OPTIMIZER{separator}PROFILE_SETS{separator}DEFAULT_IMAGES{separator}PROFILES{separator}W1536" ) ,
3070+ Some ( "format=auto&width=1536" ) ,
3071+ ) ,
3072+ (
3073+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}IMAGE_OPTIMIZER{separator}PROFILE_SETS{separator}DEFAULT_IMAGES{separator}ASPECT_RATIOS{separator}ALLOWED" ) ,
3074+ Some ( "[\" 1-1\" ,\" 16-9\" ]" ) ,
3075+ ) ,
3076+ (
3077+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}IMAGE_OPTIMIZER{separator}PROFILE_SETS{separator}DEFAULT_IMAGES{separator}ASPECT_RATIOS{separator}PROFILES" ) ,
3078+ Some ( "[\" w828\" ,\" w1536\" ]" ) ,
3079+ ) ,
3080+ (
3081+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}IMAGE_OPTIMIZER{separator}PROFILE_SETS{separator}DEFAULT_IMAGES{separator}CROP_OFFSETS{separator}ENABLED" ) ,
3082+ Some ( "true" ) ,
3083+ ) ,
3084+ (
3085+ format ! ( "{ENVIRONMENT_VARIABLE_PREFIX}{separator}IMAGE_OPTIMIZER{separator}PROFILE_SETS{separator}DEFAULT_IMAGES{separator}CROP_OFFSETS{separator}BUCKETS" ) ,
3086+ Some ( "[10,30,50,70,90]" ) ,
3087+ ) ,
3088+ ] ;
3089+
3090+ temp_env:: with_vars ( vars, || {
3091+ let settings = Settings :: from_toml_and_env ( & toml_str)
3092+ . expect ( "should parse image optimizer env overrides" ) ;
3093+ let route = settings
3094+ . asset_route_for_path ( "/.image/id/example.jpg" )
3095+ . expect ( "should match image optimizer asset route" ) ;
3096+ assert ! ( route. image_optimizer_enabled( ) ) ;
3097+
3098+ let image_optimizer = route
3099+ . image_optimizer
3100+ . as_ref ( )
3101+ . expect ( "should configure image optimizer" ) ;
3102+ assert ! ( image_optimizer. enabled) ;
3103+ assert_eq ! ( image_optimizer. region, "us_west" ) ;
3104+ assert_eq ! ( image_optimizer. profile_set, "default_images" ) ;
3105+
3106+ let profile_set = settings
3107+ . image_optimizer
3108+ . profile_sets
3109+ . get ( "default_images" )
3110+ . expect ( "should configure default image profiles" ) ;
3111+ assert_eq ! ( profile_set. profiles[ "w828" ] , "format=auto&width=828" ) ;
3112+ let aspect_ratios = profile_set
3113+ . aspect_ratios
3114+ . as_ref ( )
3115+ . expect ( "should configure aspect ratios" ) ;
3116+ assert_eq ! ( aspect_ratios. allowed, vec![ "1-1" , "16-9" ] ) ;
3117+ assert_eq ! ( aspect_ratios. profiles, vec![ "w828" , "w1536" ] ) ;
3118+ let crop_offsets = profile_set
3119+ . crop_offsets
3120+ . as_ref ( )
3121+ . expect ( "should configure crop offsets" ) ;
3122+ assert ! ( crop_offsets. enabled) ;
3123+ assert_eq ! ( crop_offsets. buckets, vec![ 10 , 30 , 50 , 70 , 90 ] ) ;
3124+ } ) ;
3125+ }
3126+
29963127 #[ test]
29973128 fn proxy_asset_route_validation_rejects_image_optimizer_preserve_query ( ) {
29983129 let toml_str = crate_test_settings_str ( )
0 commit comments