aws_runtime/content_encoding/
options.rs1use aws_smithy_types::config_bag::{Storable, StoreReplace};
7
8use super::{
9 CHUNK_SIGNATURE_BEGIN, CHUNK_TERMINATOR, CRLF, DEFAULT_CHUNK_SIZE_BYTE, SIGNATURE_LENGTH,
10};
11
12#[derive(Clone, Debug, Default)]
14#[non_exhaustive]
15pub struct AwsChunkedBodyOptions {
16 pub(crate) stream_length: u64,
18 pub(crate) trailer_lengths: Vec<u64>,
21 pub(crate) disabled: bool,
24 pub(crate) is_signed: bool,
26 pub(crate) chunk_size: Option<usize>,
29}
30
31impl Storable for AwsChunkedBodyOptions {
32 type Storer = StoreReplace<Self>;
33}
34
35impl AwsChunkedBodyOptions {
36 pub fn new(stream_length: u64, trailer_lengths: Vec<u64>) -> Self {
38 Self {
39 stream_length,
40 trailer_lengths,
41 disabled: false,
42 is_signed: false,
43 chunk_size: None,
44 }
45 }
46
47 pub fn with_chunk_size(mut self, chunk_size: usize) -> Self {
52 self.chunk_size = Some(chunk_size);
53 self
54 }
55
56 pub fn chunk_size(&self) -> usize {
60 self.chunk_size.unwrap_or(DEFAULT_CHUNK_SIZE_BYTE)
61 }
62
63 pub(super) fn total_trailer_length(&self) -> u64 {
64 self.trailer_lengths.iter().sum::<u64>()
65 + (self.trailer_lengths.len() * CRLF.len()) as u64
67 }
68
69 pub fn with_stream_length(mut self, stream_length: u64) -> Self {
71 self.stream_length = stream_length;
72 self
73 }
74
75 pub fn with_trailer_len(mut self, trailer_len: u64) -> Self {
77 self.trailer_lengths.push(trailer_len);
78 self
79 }
80
81 pub fn is_trailer_empty(&self) -> bool {
83 self.trailer_lengths.is_empty()
84 }
85
86 pub fn disable_chunked_encoding() -> Self {
90 Self {
91 disabled: true,
92 ..Default::default()
93 }
94 }
95
96 pub fn disabled(&self) -> bool {
98 self.disabled
99 }
100
101 pub fn signed_chunked_encoding(mut self, is_signed: bool) -> Self {
103 self.is_signed = is_signed;
104 self
105 }
106
107 pub fn encoded_length(&self) -> u64 {
109 if self.is_signed {
110 self.signed_encoded_length()
111 } else {
112 self.unsigned_encoded_length()
113 }
114 }
115
116 fn signed_encoded_length(&self) -> u64 {
117 let number_of_data_chunks = self.stream_length / self.chunk_size() as u64;
118 let remaining_data_chunk = self.stream_length % self.chunk_size() as u64;
119
120 let mut length = number_of_data_chunks
121 * get_signed_chunk_bytes_length(self.chunk_size() as u64)
122 + if remaining_data_chunk > 0 {
123 get_signed_chunk_bytes_length(remaining_data_chunk)
124 } else {
125 0
126 };
127
128 length += get_signed_chunk_bytes_length(0);
130
131 length -= CRLF.len() as u64; for len in self.trailer_lengths.iter() {
135 length += len + CRLF.len() as u64;
136 }
137
138 length += CRLF.len() as u64;
140
141 length
142 }
143
144 fn unsigned_encoded_length(&self) -> u64 {
145 let number_of_data_chunks = self.stream_length / self.chunk_size() as u64;
146 let remaining_data_chunk = self.stream_length % self.chunk_size() as u64;
147
148 let mut length = number_of_data_chunks
149 * get_unsigned_chunk_bytes_length(self.chunk_size() as u64)
150 + if remaining_data_chunk > 0 {
151 get_unsigned_chunk_bytes_length(remaining_data_chunk)
152 } else {
153 0
154 };
155
156 length += CHUNK_TERMINATOR.len() as u64;
158
159 for len in self.trailer_lengths.iter() {
161 length += len + CRLF.len() as u64;
162 }
163
164 length += CRLF.len() as u64;
166
167 length
168 }
169}
170
171fn int_log16<T>(mut i: T) -> u64
172where
173 T: std::ops::DivAssign + PartialOrd + From<u8> + Copy,
174{
175 let mut len = 0;
176 let zero = T::from(0);
177 let sixteen = T::from(16);
178
179 if i == zero {
181 return 1;
182 }
183
184 while i > zero {
185 i /= sixteen;
186 len += 1;
187 }
188
189 len
190}
191
192fn get_signed_chunk_bytes_length(payload_length: u64) -> u64 {
198 let hex_repr_len = int_log16(payload_length);
199 hex_repr_len
200 + CHUNK_SIGNATURE_BEGIN.len() as u64
201 + SIGNATURE_LENGTH as u64
202 + CRLF.len() as u64
203 + payload_length
204 + CRLF.len() as u64
205}
206
207fn get_unsigned_chunk_bytes_length(payload_length: u64) -> u64 {
213 let hex_repr_len = int_log16(payload_length);
214 hex_repr_len + CRLF.len() as u64 + payload_length + CRLF.len() as u64
215}
216
217#[cfg(test)]
218mod tests {
219 use super::int_log16;
220
221 #[test]
222 fn test_int_log16() {
223 assert_eq!(int_log16(0u64), 1); assert_eq!(int_log16(1u64), 1); assert_eq!(int_log16(15u64), 1); assert_eq!(int_log16(16u64), 2); assert_eq!(int_log16(255u64), 2); assert_eq!(int_log16(256u64), 3); assert_eq!(int_log16(4095u64), 3); assert_eq!(int_log16(4096u64), 4); assert_eq!(int_log16(65535u64), 4); assert_eq!(int_log16(65536u64), 5); assert_eq!(int_log16(1048575u64), 5); assert_eq!(int_log16(1048576u64), 6); assert_eq!(int_log16(u64::MAX), 16); }
237}