Skip to content

Commit cd709f7

Browse files
committed
Fix greedy label matching
fixes #464
1 parent 59dbc85 commit cd709f7

File tree

2 files changed

+23
-20
lines changed

2 files changed

+23
-20
lines changed

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

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,12 @@ describe("simple matching", () => {
3636
}),
3737
new UriSpec(
3838
"GET",
39-
[{ type: "path_literal", value: "mg" }, { type: "greedy" }, { type: "path_literal", value: "z" }],
39+
[
40+
{ type: "path_literal", value: "mg" },
41+
{ type: "greedy" },
42+
{ type: "path_literal", value: "y" },
43+
{ type: "path_literal", value: "z" },
44+
],
4045
[],
4146
{ service: "Test", operation: "MiddleGreedy" }
4247
),
@@ -71,8 +76,10 @@ describe("simple matching", () => {
7176
new HttpRequest({ method: "GET", path: "/greedy/a/b/c/d", query: { abc: "def" } }),
7277
],
7378
"Test#MiddleGreedy": [
74-
new HttpRequest({ method: "GET", path: "/mg/a/z" }),
75-
new HttpRequest({ method: "GET", path: "/mg/a/b/c/d/z", query: { abc: "def" } }),
79+
new HttpRequest({ method: "GET", path: "/mg/a/y/z" }),
80+
new HttpRequest({ method: "GET", path: "/mg/a/b/c/d/y/z", query: { abc: "def" } }),
81+
new HttpRequest({ method: "GET", path: "/mg/a/b/y/c/d/y/z", query: { abc: "def" } }),
82+
new HttpRequest({ method: "GET", path: "/mg/a/b/y/z/d/y/z", query: { abc: "def" } }),
7683
],
7784
"Test#Delete": [
7885
new HttpRequest({ method: "DELETE", path: "/", query: { foo: "bar", baz: "quux" } }),
@@ -103,6 +110,10 @@ describe("simple matching", () => {
103110
new HttpRequest({ method: "GET", path: "/mg" }),
104111
new HttpRequest({ method: "GET", path: "/mg/q" }),
105112
new HttpRequest({ method: "GET", path: "/mg/z" }),
113+
new HttpRequest({ method: "GET", path: "/mg/y/z" }),
114+
new HttpRequest({ method: "GET", path: "/mg/a/z" }),
115+
new HttpRequest({ method: "GET", path: "/mg/a/y/z/a" }),
116+
new HttpRequest({ method: "GET", path: "/mg/a/y/a" }),
106117
new HttpRequest({ method: "GET", path: "/mg/a/b/z/c" }),
107118
new HttpRequest({ method: "DELETE", path: "/", query: { foo: "bar" } }),
108119
new HttpRequest({ method: "DELETE", path: "/", query: { baz: "quux" } }),

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

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export class UriSpec<S extends string, O extends string> {
7878
const requestPathSegments = req.path.split("/").filter((s) => s.length > 0);
7979

8080
let requestPathIdx = 0;
81-
path_loop: for (let i = 0; i < this.pathSegments.length; i++) {
81+
for (let i = 0; i < this.pathSegments.length; i++) {
8282
if (requestPathIdx === requestPathSegments.length) {
8383
// there are more pathSegments but we have reached the end of the requestPath
8484
return false;
@@ -88,24 +88,16 @@ export class UriSpec<S extends string, O extends string> {
8888
return false;
8989
}
9090
if (pathSegment.type === "greedy") {
91-
if (i === this.pathSegments.length - 1) {
92-
// greedy label at the end of pathSegments swallows the remaining path segments
93-
requestPathIdx = requestPathSegments.length;
94-
break path_loop;
95-
}
96-
let matched = false;
97-
if (i < this.pathSegments.length - 1) {
98-
const nextSegment = this.pathSegments[i + 1];
99-
while (!matched && ++requestPathIdx < requestPathSegments.length) {
100-
if (this.matchesSegment(requestPathSegments[requestPathIdx], nextSegment)) {
101-
matched = true;
102-
}
103-
}
104-
}
105-
if (!matched) {
106-
// the next segment after our greedy label did not match any of the remaining request segments
91+
// greedy labels match greedily, and a greedy label cannot be followed by another greedy label
92+
// so just consume as many segments as needed to leave an equal number of segments
93+
// at the end of the request path as we have segments in the pattern
94+
const remainingSegments = this.pathSegments.length - i - 1;
95+
const newRequestPathIdx = requestPathSegments.length - remainingSegments;
96+
if (requestPathIdx === newRequestPathIdx) {
97+
// greedy labels must consume at least one segment
10798
return false;
10899
}
100+
requestPathIdx = newRequestPathIdx;
109101
} else {
110102
requestPathIdx++;
111103
}

0 commit comments

Comments
 (0)