aws_smithy_checksums/
http.rs
1use aws_smithy_types::base64;
9use http::header::{HeaderMap, HeaderValue};
10
11use crate::{
12 Checksum, Crc32, Crc32c, Md5, Sha1, Sha256, CRC_32_C_NAME, CRC_32_NAME, SHA_1_NAME,
13 SHA_256_NAME,
14};
15
16pub static CRC_32_HEADER_NAME: &str = "x-amz-checksum-crc32";
17pub static CRC_32_C_HEADER_NAME: &str = "x-amz-checksum-crc32c";
18pub static SHA_1_HEADER_NAME: &str = "x-amz-checksum-sha1";
19pub static SHA_256_HEADER_NAME: &str = "x-amz-checksum-sha256";
20
21pub(crate) static MD5_HEADER_NAME: &str = "content-md5";
23
24pub const CHECKSUM_ALGORITHMS_IN_PRIORITY_ORDER: [&str; 4] =
28 [CRC_32_C_NAME, CRC_32_NAME, SHA_1_NAME, SHA_256_NAME];
29
30pub trait HttpChecksum: Checksum + Send + Sync {
34 fn headers(self: Box<Self>) -> HeaderMap<HeaderValue> {
37 let mut header_map = HeaderMap::new();
38 header_map.insert(self.header_name(), self.header_value());
39
40 header_map
41 }
42
43 fn header_name(&self) -> &'static str;
45
46 fn header_value(self: Box<Self>) -> HeaderValue {
48 let hash = self.finalize();
49 HeaderValue::from_str(&base64::encode(&hash[..]))
50 .expect("base64 encoded bytes are always valid header values")
51 }
52
53 fn size(&self) -> u64 {
58 let trailer_name_size_in_bytes = self.header_name().len();
59 let base64_encoded_checksum_size_in_bytes =
60 base64::encoded_length(Checksum::size(self) as usize);
61
62 let size = trailer_name_size_in_bytes
63 + ":".len()
66 + base64_encoded_checksum_size_in_bytes;
67
68 size as u64
69 }
70}
71
72impl HttpChecksum for Crc32 {
73 fn header_name(&self) -> &'static str {
74 CRC_32_HEADER_NAME
75 }
76}
77
78impl HttpChecksum for Crc32c {
79 fn header_name(&self) -> &'static str {
80 CRC_32_C_HEADER_NAME
81 }
82}
83
84impl HttpChecksum for Sha1 {
85 fn header_name(&self) -> &'static str {
86 SHA_1_HEADER_NAME
87 }
88}
89
90impl HttpChecksum for Sha256 {
91 fn header_name(&self) -> &'static str {
92 SHA_256_HEADER_NAME
93 }
94}
95
96impl HttpChecksum for Md5 {
97 fn header_name(&self) -> &'static str {
98 MD5_HEADER_NAME
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use aws_smithy_types::base64;
105 use bytes::Bytes;
106
107 use crate::{ChecksumAlgorithm, CRC_32_C_NAME, CRC_32_NAME, SHA_1_NAME, SHA_256_NAME};
108
109 use super::HttpChecksum;
110
111 #[test]
112 fn test_trailer_length_of_crc32_checksum_body() {
113 let checksum = CRC_32_NAME
114 .parse::<ChecksumAlgorithm>()
115 .unwrap()
116 .into_impl();
117 let expected_size = 29;
118 let actual_size = HttpChecksum::size(&*checksum);
119 assert_eq!(expected_size, actual_size)
120 }
121
122 #[test]
123 fn test_trailer_value_of_crc32_checksum_body() {
124 let checksum = CRC_32_NAME
125 .parse::<ChecksumAlgorithm>()
126 .unwrap()
127 .into_impl();
128 let expected_value = Bytes::from_static(b"");
130 let expected_value = base64::encode(&expected_value);
131 let actual_value = checksum.header_value();
132 assert_eq!(expected_value, actual_value)
133 }
134
135 #[test]
136 fn test_trailer_length_of_crc32c_checksum_body() {
137 let checksum = CRC_32_C_NAME
138 .parse::<ChecksumAlgorithm>()
139 .unwrap()
140 .into_impl();
141 let expected_size = 30;
142 let actual_size = HttpChecksum::size(&*checksum);
143 assert_eq!(expected_size, actual_size)
144 }
145
146 #[test]
147 fn test_trailer_value_of_crc32c_checksum_body() {
148 let checksum = CRC_32_C_NAME
149 .parse::<ChecksumAlgorithm>()
150 .unwrap()
151 .into_impl();
152 let expected_value = Bytes::from_static(b"");
154 let expected_value = base64::encode(&expected_value);
155 let actual_value = checksum.header_value();
156 assert_eq!(expected_value, actual_value)
157 }
158
159 #[test]
160 fn test_trailer_length_of_sha1_checksum_body() {
161 let checksum = SHA_1_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
162 let expected_size = 48;
163 let actual_size = HttpChecksum::size(&*checksum);
164 assert_eq!(expected_size, actual_size)
165 }
166
167 #[test]
168 fn test_trailer_value_of_sha1_checksum_body() {
169 let checksum = SHA_1_NAME.parse::<ChecksumAlgorithm>().unwrap().into_impl();
170 let expected_value = Bytes::from_static(&[
172 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55, 0xbf, 0xef, 0x95, 0x60,
173 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09,
174 ]);
175 let expected_value = base64::encode(&expected_value);
176 let actual_value = checksum.header_value();
177 assert_eq!(expected_value, actual_value)
178 }
179
180 #[test]
181 fn test_trailer_length_of_sha256_checksum_body() {
182 let checksum = SHA_256_NAME
183 .parse::<ChecksumAlgorithm>()
184 .unwrap()
185 .into_impl();
186 let expected_size = 66;
187 let actual_size = HttpChecksum::size(&*checksum);
188 assert_eq!(expected_size, actual_size)
189 }
190
191 #[test]
192 fn test_trailer_value_of_sha256_checksum_body() {
193 let checksum = SHA_256_NAME
194 .parse::<ChecksumAlgorithm>()
195 .unwrap()
196 .into_impl();
197 let expected_value = Bytes::from_static(&[
199 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f,
200 0xb9, 0x24, 0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c, 0xa4, 0x95, 0x99, 0x1b,
201 0x78, 0x52, 0xb8, 0x55,
202 ]);
203 let expected_value = base64::encode(&expected_value);
204 let actual_value = checksum.header_value();
205 assert_eq!(expected_value, actual_value)
206 }
207}