aws_config/default_provider/
checksums.rs

1/*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 * SPDX-License-Identifier: Apache-2.0
4 */
5
6use crate::provider_config::ProviderConfig;
7use aws_runtime::env_config::EnvConfigValue;
8use aws_smithy_types::error::display::DisplayErrorContext;
9use aws_types::sdk_config::{RequestChecksumCalculation, ResponseChecksumValidation};
10use std::str::FromStr;
11
12mod env {
13    pub(super) const REQUEST_CHECKSUM_CALCULATION: &str = "AWS_REQUEST_CHECKSUM_CALCULATION";
14    pub(super) const RESPONSE_CHECKSUM_VALIDATION: &str = "AWS_RESPONSE_CHECKSUM_VALIDATION";
15}
16
17mod profile_key {
18    pub(super) const REQUEST_CHECKSUM_CALCULATION: &str = "request_checksum_calculation";
19    pub(super) const RESPONSE_CHECKSUM_VALIDATION: &str = "response_checksum_validation";
20}
21
22/// Load the value for `request_checksum_calculation`
23///
24/// This checks the following sources:
25/// 1. The environment variable `AWS_REQUEST_CHECKSUM_CALCULATION=WHEN_SUPPORTED/WHEN_REQUIRED`
26/// 2. The profile key `request_checksum_calculation=WHEN_SUPPORTED/WHEN_REQUIRED`
27///
28/// If invalid values are found, the provider will return `None` and an error will be logged.
29pub async fn request_checksum_calculation_provider(
30    provider_config: &ProviderConfig,
31) -> Option<RequestChecksumCalculation> {
32    let env = provider_config.env();
33    let profiles = provider_config.profile().await;
34
35    let loaded = EnvConfigValue::new()
36         .env(env::REQUEST_CHECKSUM_CALCULATION)
37         .profile(profile_key::REQUEST_CHECKSUM_CALCULATION)
38         .validate(&env, profiles, RequestChecksumCalculation::from_str)
39         .map_err(
40             |err| tracing::warn!(err = %DisplayErrorContext(&err), "invalid value for request_checksum_calculation setting"),
41         )
42         .unwrap_or(None);
43
44    // request_checksum_calculation should always have a non-None value and the
45    // default is WhenSupported
46    loaded.or(Some(RequestChecksumCalculation::WhenSupported))
47}
48
49/// Load the value for `response_checksum_validation`
50///
51/// This checks the following sources:
52/// 1. The environment variable `AWS_RESPONSE_CHECKSUM_VALIDATION=WHEN_SUPPORTED/WHEN_REQUIRED`
53/// 2. The profile key `response_checksum_validation=WHEN_SUPPORTED/WHEN_REQUIRED`
54///
55/// If invalid values are found, the provider will return `None` and an error will be logged.
56pub async fn response_checksum_validation_provider(
57    provider_config: &ProviderConfig,
58) -> Option<ResponseChecksumValidation> {
59    let env = provider_config.env();
60    let profiles = provider_config.profile().await;
61
62    let loaded = EnvConfigValue::new()
63         .env(env::RESPONSE_CHECKSUM_VALIDATION)
64         .profile(profile_key::RESPONSE_CHECKSUM_VALIDATION)
65         .validate(&env, profiles, ResponseChecksumValidation::from_str)
66         .map_err(
67             |err| tracing::warn!(err = %DisplayErrorContext(&err), "invalid value for response_checksum_validation setting"),
68         )
69         .unwrap_or(None);
70
71    // response_checksum_validation should always have a non-None value and the
72    // default is WhenSupported
73    loaded.or(Some(ResponseChecksumValidation::WhenSupported))
74}
75
76#[cfg(test)]
77mod test {
78    use crate::default_provider::checksums::{
79        request_checksum_calculation_provider, response_checksum_validation_provider,
80    };
81    #[allow(deprecated)]
82    use crate::profile::profile_file::{ProfileFileKind, ProfileFiles};
83    use crate::provider_config::ProviderConfig;
84    use aws_smithy_types::checksum_config::{
85        RequestChecksumCalculation, ResponseChecksumValidation,
86    };
87    use aws_types::os_shim_internal::{Env, Fs};
88    use tracing_test::traced_test;
89
90    #[tokio::test]
91    #[traced_test]
92    async fn log_error_on_invalid_value_request() {
93        let conf = ProviderConfig::empty().with_env(Env::from_slice(&[(
94            "AWS_REQUEST_CHECKSUM_CALCULATION",
95            "not-a-valid-value",
96        )]));
97        assert_eq!(
98            request_checksum_calculation_provider(&conf).await,
99            Some(RequestChecksumCalculation::WhenSupported)
100        );
101        assert!(logs_contain(
102            "invalid value for request_checksum_calculation setting"
103        ));
104        assert!(logs_contain("AWS_REQUEST_CHECKSUM_CALCULATION"));
105    }
106
107    #[tokio::test]
108    #[traced_test]
109    async fn environment_priority_request() {
110        let conf = ProviderConfig::empty()
111            .with_env(Env::from_slice(&[(
112                "AWS_REQUEST_CHECKSUM_CALCULATION",
113                "WHEN_REQUIRED",
114            )]))
115            .with_profile_config(
116                Some(
117                    #[allow(deprecated)]
118                    ProfileFiles::builder()
119                        .with_file(
120                            #[allow(deprecated)]
121                            ProfileFileKind::Config,
122                            "conf",
123                        )
124                        .build(),
125                ),
126                None,
127            )
128            .with_fs(Fs::from_slice(&[(
129                "conf",
130                "[default]\nrequest_checksum_calculation = WHEN_SUPPORTED",
131            )]));
132        assert_eq!(
133            request_checksum_calculation_provider(&conf).await,
134            Some(RequestChecksumCalculation::WhenRequired)
135        );
136    }
137
138    #[tokio::test]
139    #[traced_test]
140    async fn profile_works_request() {
141        let conf = ProviderConfig::empty()
142            .with_profile_config(
143                Some(
144                    #[allow(deprecated)]
145                    ProfileFiles::builder()
146                        .with_file(
147                            #[allow(deprecated)]
148                            ProfileFileKind::Config,
149                            "conf",
150                        )
151                        .build(),
152                ),
153                None,
154            )
155            .with_fs(Fs::from_slice(&[(
156                "conf",
157                "[default]\nrequest_checksum_calculation = WHEN_REQUIRED",
158            )]));
159        assert_eq!(
160            request_checksum_calculation_provider(&conf).await,
161            Some(RequestChecksumCalculation::WhenRequired)
162        );
163    }
164
165    #[tokio::test]
166    #[traced_test]
167    async fn default_works_request() {
168        let conf = ProviderConfig::empty();
169        assert_eq!(
170            request_checksum_calculation_provider(&conf).await,
171            Some(RequestChecksumCalculation::WhenSupported)
172        );
173    }
174
175    #[tokio::test]
176    #[traced_test]
177    async fn log_error_on_invalid_value_response() {
178        let conf = ProviderConfig::empty().with_env(Env::from_slice(&[(
179            "AWS_RESPONSE_CHECKSUM_VALIDATION",
180            "not-a-valid-value",
181        )]));
182        assert_eq!(
183            response_checksum_validation_provider(&conf).await,
184            Some(ResponseChecksumValidation::WhenSupported)
185        );
186        assert!(logs_contain(
187            "invalid value for response_checksum_validation setting"
188        ));
189        assert!(logs_contain("AWS_RESPONSE_CHECKSUM_VALIDATION"));
190    }
191
192    #[tokio::test]
193    #[traced_test]
194    async fn environment_priority_response() {
195        let conf = ProviderConfig::empty()
196            .with_env(Env::from_slice(&[(
197                "AWS_RESPONSE_CHECKSUM_VALIDATION",
198                "WHEN_SUPPORTED",
199            )]))
200            .with_profile_config(
201                Some(
202                    #[allow(deprecated)]
203                    ProfileFiles::builder()
204                        .with_file(
205                            #[allow(deprecated)]
206                            ProfileFileKind::Config,
207                            "conf",
208                        )
209                        .build(),
210                ),
211                None,
212            )
213            .with_fs(Fs::from_slice(&[(
214                "conf",
215                "[default]\response_checksum_validation = WHEN_REQUIRED",
216            )]));
217        assert_eq!(
218            response_checksum_validation_provider(&conf).await,
219            Some(ResponseChecksumValidation::WhenSupported)
220        );
221    }
222
223    #[tokio::test]
224    #[traced_test]
225    async fn profile_works_response() {
226        let conf = ProviderConfig::empty()
227            .with_profile_config(
228                Some(
229                    #[allow(deprecated)]
230                    ProfileFiles::builder()
231                        .with_file(
232                            #[allow(deprecated)]
233                            ProfileFileKind::Config,
234                            "conf",
235                        )
236                        .build(),
237                ),
238                None,
239            )
240            .with_fs(Fs::from_slice(&[(
241                "conf",
242                "[default]\nresponse_checksum_validation = WHEN_REQUIRED",
243            )]));
244        assert_eq!(
245            response_checksum_validation_provider(&conf).await,
246            Some(ResponseChecksumValidation::WhenRequired)
247        );
248    }
249
250    #[tokio::test]
251    #[traced_test]
252    async fn default_works_response() {
253        let conf = ProviderConfig::empty();
254        assert_eq!(
255            response_checksum_validation_provider(&conf).await,
256            Some(ResponseChecksumValidation::WhenSupported)
257        );
258    }
259}