Skip to content

Commit db89652

Browse files
rcohZelda Hesslerysaito1001
authored
Fix: Only enforce content length for GET requests (#3657)
_By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice._ --------- Co-authored-by: Zelda Hessler <zhessler@amazon.com> Co-authored-by: ysaito1001 <awsaito@amazon.com>
1 parent ccec237 commit db89652

File tree

9 files changed

+555
-6
lines changed

9 files changed

+555
-6
lines changed

CHANGELOG.next.toml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,16 @@
99
# message = "Fix typos in module documentation for generated crates"
1010
# references = ["smithy-rs#920"]
1111
# meta = { "breaking" = false, "tada" = false, "bug" = false, "target" = "client | server | all"}
12-
# author = "rcoh"
12+
# author = "rcoh"
13+
14+
[[aws-sdk-rust]]
15+
message = "Fix the Content-Length enforcement so it is only applied to GET requests."
16+
references = ["smithy-rs#3656", "smithy-rs#3657"]
17+
meta = { "breaking" = false, "tada" = false, "bug" = true }
18+
authors = ["rcoh", "Velfi"]
19+
20+
[[smithy-rs]]
21+
message = "Fix the Content-Length enforcement so it is only applied to GET requests."
22+
references = ["smithy-rs#3656", "smithy-rs#3657"]
23+
meta = { "breaking" = false, "tada" = false, "bug" = true, "target" = "client" }
24+
authors = ["rcoh", "Velfi"]

aws/sdk/integration-tests/s3/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ aws-sdk-s3 = { path = "../../build/aws-sdk/sdk/s3", features = ["test-util", "be
2323
aws-smithy-async = { path = "../../build/aws-sdk/sdk/aws-smithy-async", features = ["test-util", "rt-tokio"] }
2424
aws-smithy-http = { path = "../../build/aws-sdk/sdk/aws-smithy-http" }
2525
aws-smithy-protocol-test = { path = "../../build/aws-sdk/sdk/aws-smithy-protocol-test" }
26-
aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["test-util", "wire-mock"] }
26+
aws-smithy-runtime = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime", features = ["test-util", "wire-mock", "tls-rustls"] }
2727
aws-smithy-runtime-api = { path = "../../build/aws-sdk/sdk/aws-smithy-runtime-api", features = ["test-util"] }
2828
aws-smithy-types = { path = "../../build/aws-sdk/sdk/aws-smithy-types" }
2929
aws-smithy-experimental = { path = "../../build/aws-sdk/sdk/aws-smithy-experimental", features = ["crypto-ring"] }
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
/*
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
use aws_sdk_s3::{config::Region, error::DisplayErrorContext, Client, Config};
7+
use aws_smithy_runtime::client::http::test_util::dvr::ReplayingClient;
8+
9+
#[tokio::test]
10+
async fn test_content_length_enforcement_is_not_applied_to_head_request() {
11+
let http_client =
12+
ReplayingClient::from_file("tests/data/content-length-enforcement/head-object.json")
13+
.expect("recorded HTTP communication exists");
14+
let config = Config::builder()
15+
.with_test_defaults()
16+
.http_client(http_client.clone())
17+
.region(Region::new("us-east-1"))
18+
.build();
19+
let client = Client::from_conf(config);
20+
let _resp = client
21+
.head_object()
22+
.key("dontcare.json")
23+
.bucket("dontcare")
24+
.send()
25+
.await
26+
.expect("content length enforcement must not apply to HEAD requests");
27+
28+
// The body returned will be empty, so we pass an empty string to full_validate.
29+
// That way, it'll do a string equality check on the empty strings.
30+
http_client.full_validate("").await.unwrap();
31+
}
32+
33+
#[tokio::test]
34+
async fn test_content_length_enforcement_get_request_short() {
35+
let http_client =
36+
ReplayingClient::from_file("tests/data/content-length-enforcement/get-object-short.json")
37+
.expect("recorded HTTP communication exists");
38+
let config = Config::builder()
39+
.with_test_defaults()
40+
.http_client(http_client.clone())
41+
.region(Region::new("us-east-1"))
42+
.build();
43+
let client = Client::from_conf(config);
44+
// The file we're fetching is exactly 10,000 bytes long, but we've set the
45+
// response's content-length to 9,999 bytes. This should trigger the
46+
// content-length enforcement.
47+
48+
// This will succeed.
49+
let output = client
50+
.get_object()
51+
.key("1000-lines.txt")
52+
.bucket("dontcare")
53+
.send()
54+
.await
55+
.unwrap();
56+
57+
// This will fail with a content-length mismatch error.
58+
let content_length_err = output.body.collect().await.unwrap_err();
59+
60+
http_client.full_validate("application/text").await.unwrap();
61+
assert_eq!(
62+
DisplayErrorContext(content_length_err).to_string(),
63+
"streaming error: Invalid Content-Length: Expected 9999 bytes but 10000 bytes were received (Error { kind: StreamingError(ContentLengthError { expected: 9999, received: 10000 }) })"
64+
);
65+
}
66+
67+
#[tokio::test]
68+
async fn test_content_length_enforcement_get_request_long() {
69+
let http_client =
70+
ReplayingClient::from_file("tests/data/content-length-enforcement/get-object-long.json")
71+
.expect("recorded HTTP communication exists");
72+
let config = Config::builder()
73+
.with_test_defaults()
74+
.http_client(http_client.clone())
75+
.region(Region::new("us-east-1"))
76+
.build();
77+
let client = Client::from_conf(config);
78+
// The file we're fetching is exactly 10,000 bytes long, but we've set the
79+
// response's content-length to 9,999 bytes. This should trigger the
80+
// content-length enforcement.
81+
82+
// This will succeed.
83+
let output = client
84+
.get_object()
85+
.key("1000-lines.txt")
86+
.bucket("dontcare")
87+
.send()
88+
.await
89+
.unwrap();
90+
91+
// This will fail with a content-length mismatch error.
92+
let content_length_err = output.body.collect().await.unwrap_err();
93+
94+
http_client.full_validate("application/text").await.unwrap();
95+
assert_eq!(
96+
DisplayErrorContext(content_length_err).to_string(),
97+
"streaming error: Invalid Content-Length: Expected 10001 bytes but 10000 bytes were received (Error { kind: StreamingError(ContentLengthError { expected: 10001, received: 10000 }) })"
98+
);
99+
}

0 commit comments

Comments
 (0)