diff --git a/.changelog/1724182177.md b/.changelog/1724182177.md new file mode 100644 index 0000000000..64fc083383 --- /dev/null +++ b/.changelog/1724182177.md @@ -0,0 +1,14 @@ +--- +applies_to: +- aws-sdk-rust +- client +authors: +- ysaito1001 +references: +- aws-sdk-rust#821 +- smithy-rs#3797 +breaking: false +new_feature: false +bug_fix: true +--- +Fix the [Length::UpTo](https://docs.rs/aws-smithy-types/1.2.2/aws_smithy_types/byte_stream/enum.Length.html) usage in [FsBuilder](https://docs.rs/aws-smithy-types/1.2.2/aws_smithy_types/byte_stream/struct.FsBuilder.html), ensuring that the specified length does not exceed the remaining file length. diff --git a/rust-runtime/aws-smithy-types/Cargo.toml b/rust-runtime/aws-smithy-types/Cargo.toml index a83fcb4b43..30dcd57e5d 100644 --- a/rust-runtime/aws-smithy-types/Cargo.toml +++ b/rust-runtime/aws-smithy-types/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "aws-smithy-types" -version = "1.2.2" +version = "1.2.3" authors = [ "AWS Rust SDK Team ", "Russell Cohen ", diff --git a/rust-runtime/aws-smithy-types/src/byte_stream/bytestream_util.rs b/rust-runtime/aws-smithy-types/src/byte_stream/bytestream_util.rs index c8d56d3439..cce2fead65 100644 --- a/rust-runtime/aws-smithy-types/src/byte_stream/bytestream_util.rs +++ b/rust-runtime/aws-smithy-types/src/byte_stream/bytestream_util.rs @@ -5,6 +5,7 @@ use crate::body::SdkBody; use crate::byte_stream::{error::Error, error::ErrorKind, ByteStream}; +use std::cmp::min; use std::future::Future; use std::path::PathBuf; use std::pin::Pin; @@ -190,15 +191,16 @@ impl FsBuilder { return Err(ErrorKind::OffsetLargerThanFileSize.into()); } + let remaining_file_length = file_length - offset; let length = match self.length { Some(Length::Exact(length)) => { - if length > file_length - offset { + if length > remaining_file_length { return Err(ErrorKind::LengthLargerThanFileSizeMinusReadOffset.into()); } length } - Some(Length::UpTo(length)) => length, - None => file_length - offset, + Some(Length::UpTo(length)) => min(length, remaining_file_length), + None => remaining_file_length, }; if let Some(path) = self.path { @@ -247,3 +249,57 @@ enum State { bytes_left: u64, }, } + +#[cfg(test)] +mod tests { + use super::*; + use std::io::Write; + use tempfile::NamedTempFile; + + #[tokio::test] + async fn length_up_to_should_work() { + const FILE_LEN: usize = 1000; + // up to less than `FILE_LEN` + { + let mut file = NamedTempFile::new().unwrap(); + file.write_all(vec![0; FILE_LEN].as_slice()).unwrap(); + let byte_stream = FsBuilder::new() + .path(file.path()) + .length(Length::UpTo((FILE_LEN / 2) as u64)) + .build() + .await + .unwrap(); + let (lower, upper) = byte_stream.size_hint(); + assert_eq!(lower, upper.unwrap()); + assert_eq!((FILE_LEN / 2) as u64, lower); + } + // up to equal to `FILE_LEN` + { + let mut file = NamedTempFile::new().unwrap(); + file.write_all(vec![0; FILE_LEN].as_slice()).unwrap(); + let byte_stream = FsBuilder::new() + .path(file.path()) + .length(Length::UpTo(FILE_LEN as u64)) + .build() + .await + .unwrap(); + let (lower, upper) = byte_stream.size_hint(); + assert_eq!(lower, upper.unwrap()); + assert_eq!(FILE_LEN as u64, lower); + } + // up to greater than `FILE_LEN` + { + let mut file = NamedTempFile::new().unwrap(); + file.write_all(vec![0; FILE_LEN].as_slice()).unwrap(); + let byte_stream = FsBuilder::new() + .path(file.path()) + .length(Length::UpTo((FILE_LEN * 2) as u64)) + .build() + .await + .unwrap(); + let (lower, upper) = byte_stream.size_hint(); + assert_eq!(lower, upper.unwrap()); + assert_eq!(FILE_LEN as u64, lower); + } + } +}