Skip to content

Commit 806cc7f

Browse files
authored
fix: sort query parameter keys after encoding (smithy-lang#1404)
1 parent 69a7e62 commit 806cc7f

File tree

3 files changed

+23
-8
lines changed

3 files changed

+23
-8
lines changed

.changeset/ninety-hairs-obey.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@smithy/signature-v4": patch
3+
---
4+
5+
fix: sort query parameter keys after encoding

packages/signature-v4/src/getCanonicalQuery.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,17 @@ describe("getCanonicalQuery", () => {
3737
).toBe("baz=quux&fizz=buzz&foo=bar");
3838
});
3939

40+
it("should sort query keys alphabetically after URI-encode", () => {
41+
expect(
42+
getCanonicalQuery(
43+
new HttpRequest({
44+
...httpRequestOptions,
45+
query: { A: "65", "[": "91", a: "97", "{": "123" },
46+
})
47+
)
48+
).toBe("%5B=91&%7B=123&A=65&a=97");
49+
});
50+
4051
it("should URI-encode keys and values", () => {
4152
expect(
4253
getCanonicalQuery(

packages/signature-v4/src/getCanonicalQuery.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,28 +9,27 @@ import { SIGNATURE_HEADER } from "./constants";
99
export const getCanonicalQuery = ({ query = {} }: HttpRequest): string => {
1010
const keys: Array<string> = [];
1111
const serialized: Record<string, string> = {};
12-
for (const key of Object.keys(query).sort()) {
12+
for (const key of Object.keys(query)) {
1313
if (key.toLowerCase() === SIGNATURE_HEADER) {
1414
continue;
1515
}
1616

17-
keys.push(key);
17+
const encodedKey = escapeUri(key);
18+
keys.push(encodedKey);
1819
const value = query[key];
1920
if (typeof value === "string") {
20-
serialized[key] = `${escapeUri(key)}=${escapeUri(value)}`;
21+
serialized[encodedKey] = `${encodedKey}=${escapeUri(value)}`;
2122
} else if (Array.isArray(value)) {
22-
serialized[key] = value
23+
serialized[encodedKey] = value
2324
.slice(0)
24-
.reduce(
25-
(encoded: Array<string>, value: string) => encoded.concat([`${escapeUri(key)}=${escapeUri(value)}`]),
26-
[]
27-
)
25+
.reduce((encoded: Array<string>, value: string) => encoded.concat([`${encodedKey}=${escapeUri(value)}`]), [])
2826
.sort()
2927
.join("&");
3028
}
3129
}
3230

3331
return keys
32+
.sort()
3433
.map((key) => serialized[key])
3534
.filter((serialized) => serialized) // omit any falsy values
3635
.join("&");

0 commit comments

Comments
 (0)