Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,9 +489,13 @@ async fn check_presigned_url(
.headers
.map_signed_headers(&presigned_url.signed_headers);

// Canonicalize the decoded path, the way routing does (decode_uri_path).
// The client signs uri_encode(key) exactly once, so feeding the raw wire
// path would encode a second time ('+' -> %252B) and never match.
let decoded_path = decode_uri_path(ctx.req)?;
let canonical_request = signature_v4::create_presigned_canonical_request(
ctx.req.method(),
ctx.req.uri().path(),
decoded_path.as_ref(),
qs.as_ref(),
&headers,
);
Expand Down Expand Up @@ -544,7 +548,11 @@ async fn check_header_auth(

let signature = {
let method = ctx.req.method();
let uri_path = ctx.req.uri().path();
// Canonicalize the decoded path, the way routing does (decode_uri_path).
// The client signs uri_encode(key) exactly once, so feeding the raw wire
// path would encode a second time ('+' -> %252B) and never match.
let decoded_path = decode_uri_path(ctx.req)?;
let uri_path: &str = decoded_path.as_ref();
let query_strings: &[(String, String)] =
ctx.query_strings.as_ref().map_or(&[], AsRef::as_ref);

Expand Down
20 changes: 20 additions & 0 deletions src/signature_v4.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,26 @@ mod tests {
);
}

#[test]
fn canonical_uri_encodes_plus_in_key() {
// A decoded key with '+' must be percent-encoded exactly once into the canonical URI.
// The auth path feeds in the decoded request path, so '+' -> %2B, matching the client;
// feeding the raw wire path would encode a second time ('+' -> %252B).
let headers = OrderedHeaders::from_slice_unchecked(&[("host", "b.s3.amazonaws.com")]);
let qs: &[(String, String)] = &[];
let canonical_request = create_canonical_request(
&Method::PUT,
"/b/pkg-1.0+post.1.whl",
qs,
&headers,
Payload::Unsigned,
);
assert_eq!(
canonical_request.lines().nth(1).unwrap(),
"/b/pkg-1.0%2Bwasix.1.whl"
);
}

#[test]
fn example_put_object_single_chunk() {
// let access_key_id = "AKIAIOSFODNN7EXAMPLE";
Expand Down
Loading