Skip to content

Commit d440f5f

Browse files
committed
Fix query matching against list query values
The existing code doesn't account for the fact that all query parameter values can be multi-valued, even when there's only one value in the input URL. Also, a query string literal can be satisfied by any of the values in the input URL, whereas the existing code would insist that there exist no other value for the key in the literal.
1 parent 766a9bd commit d440f5f

File tree

2 files changed

+24
-3
lines changed

2 files changed

+24
-3
lines changed

smithy-typescript-ssdk-libs/server-common/src/httpbinding/mux.spec.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,10 @@ import { HttpRequest } from "@aws-sdk/protocol-http";
1818
import { HttpBindingMux, UriSpec } from ".";
1919

2020
describe("simple matching", () => {
21-
const router = new HttpBindingMux<"Test", "A" | "LessSpecificA" | "Greedy" | "MiddleGreedy" | "Delete">([
21+
const router = new HttpBindingMux<
22+
"Test",
23+
"A" | "LessSpecificA" | "Greedy" | "MiddleGreedy" | "Delete" | "QueryKeyOnly"
24+
>([
2225
new UriSpec("GET", [{ type: "path_literal", value: "a" }, { type: "path" }, { type: "path" }], [], {
2326
service: "Test",
2427
operation: "A",
@@ -46,6 +49,10 @@ describe("simple matching", () => {
4649
],
4750
{ service: "Test", operation: "Delete" }
4851
),
52+
new UriSpec("GET", [{ type: "path_literal", value: "query_key_only" }], [{ type: "query_literal", key: "foo" }], {
53+
service: "Test",
54+
operation: "QueryKeyOnly",
55+
}),
4956
]);
5057

5158
const matches: { [idx: string]: HttpRequest[] } = {
@@ -68,10 +75,20 @@ describe("simple matching", () => {
6875
new HttpRequest({ method: "GET", path: "/mg/a/b/c/d/z", query: { abc: "def" } }),
6976
],
7077
"Test#Delete": [
78+
new HttpRequest({ method: "DELETE", path: "/", query: { foo: "bar", baz: "quux" } }),
79+
new HttpRequest({ method: "DELETE", path: "/", query: { foo: ["bar"], baz: "quux" } }),
80+
new HttpRequest({ method: "DELETE", path: "/", query: { foo: ["bar", "corge"], baz: "quux" } }),
7181
new HttpRequest({ method: "DELETE", path: "/", query: { foo: "bar", baz: "quux" } }),
7282
new HttpRequest({ method: "DELETE", path: "/", query: { foo: "bar", baz: null } }),
7383
new HttpRequest({ method: "DELETE", path: "", query: { foo: "bar", baz: ["quux", "grault"] } }),
7484
],
85+
"Test#QueryKeyOnly": [
86+
new HttpRequest({ method: "GET", path: "/query_key_only", query: { foo: "bar" } }),
87+
new HttpRequest({ method: "GET", path: "/query_key_only", query: { foo: null } }),
88+
new HttpRequest({ method: "GET", path: "/query_key_only", query: { foo: "" } }),
89+
// this is actually what /query_key_only?foo will look like behind APIGateway
90+
new HttpRequest({ method: "GET", path: "/query_key_only", query: { foo: [""] } }),
91+
],
7592
};
7693

7794
const misses = [
@@ -87,7 +104,6 @@ describe("simple matching", () => {
87104
new HttpRequest({ method: "GET", path: "/mg/q" }),
88105
new HttpRequest({ method: "GET", path: "/mg/z" }),
89106
new HttpRequest({ method: "GET", path: "/mg/a/b/z/c" }),
90-
new HttpRequest({ method: "DELETE", path: "/", query: { foo: ["bar", "corge"], baz: "quux" } }),
91107
new HttpRequest({ method: "DELETE", path: "/", query: { foo: "bar" } }),
92108
new HttpRequest({ method: "DELETE", path: "/", query: { baz: "quux" } }),
93109
new HttpRequest({ method: "DELETE", path: "/" }),

smithy-typescript-ssdk-libs/server-common/src/httpbinding/mux.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,12 @@ export class UriSpec<S extends string, O extends string> {
129129
return false;
130130
}
131131
if (querySegment.type === "query_literal") {
132-
if (querySegment.value && querySegment.value !== req.query[querySegment.key]) {
132+
const input_query_value = req.query[querySegment.key];
133+
if (Array.isArray(input_query_value)) {
134+
if (querySegment.value && !input_query_value.includes(querySegment.value)) {
135+
return false;
136+
}
137+
} else if (querySegment.value && querySegment.value !== input_query_value) {
133138
return false;
134139
}
135140
}

0 commit comments

Comments
 (0)