diff --git a/.changeset/slimy-parents-dream.md b/.changeset/slimy-parents-dream.md new file mode 100644 index 0000000000..f63cb608ec --- /dev/null +++ b/.changeset/slimy-parents-dream.md @@ -0,0 +1,5 @@ +--- +"react-router": patch +--- + +Fix regex handling for URLs containing newline characters diff --git a/packages/react-router/__tests__/matchPath-test.tsx b/packages/react-router/__tests__/matchPath-test.tsx index 5d4a95b0aa..fab6bdf94e 100644 --- a/packages/react-router/__tests__/matchPath-test.tsx +++ b/packages/react-router/__tests__/matchPath-test.tsx @@ -355,6 +355,17 @@ describe("matchPath *", () => { pathnameBase: "/users/foo*", }); }); + + it("matches a URL with %0A (a newline character)", () => { + expect(matchPath("*", "/%0A")).toMatchObject({ + pathname: "/%0A", + pathnameBase: "/", + }) + expect(matchPath("*", "/new%0Aline")).toMatchObject({ + pathname: "/new%0Aline", + pathnameBase: "/", + }) + }) }); describe("matchPath warnings", () => { diff --git a/packages/react-router/__tests__/matchRoutes-test.tsx b/packages/react-router/__tests__/matchRoutes-test.tsx index 71c4e472ac..2b22713b0c 100644 --- a/packages/react-router/__tests__/matchRoutes-test.tsx +++ b/packages/react-router/__tests__/matchRoutes-test.tsx @@ -65,6 +65,11 @@ describe("matchRoutes", () => { expect(pickPaths(routes, "/hometypo")).toEqual(["*"]); }); + it("matches root * routes for URLs containing %0A (a newline character)", () => { + expect(pickPaths(routes, "/%0A")).toEqual(["*"]); + expect(pickPaths(routes, "/new%0Aline")).toEqual(["*"]); + }); + it("matches index routes with path correctly", () => { expect(pickPaths(routes, "/withpath")).toEqual(["/withpath"]); }); diff --git a/packages/react-router/lib/router/utils.ts b/packages/react-router/lib/router/utils.ts index c3844dc8c0..66d70259f4 100644 --- a/packages/react-router/lib/router/utils.ts +++ b/packages/react-router/lib/router/utils.ts @@ -1257,6 +1257,9 @@ export function compilePath( return isOptional ? "/?([^\\/]+)?" : "/([^\\/]+)"; } ); + // If the URL contains %0A (a newline character), + // the regular expression will not match correctly unless the s (single line) flag is set. + let regexpFlags = ["s"]; if (path.endsWith("*")) { params.push({ paramName: "*" }); @@ -1280,7 +1283,9 @@ export function compilePath( // Nothing to match for "" or "/" } - let matcher = new RegExp(regexpSource, caseSensitive ? undefined : "i"); + if (!caseSensitive) regexpFlags.push("i"); + + let matcher = new RegExp(regexpSource, regexpFlags.join("")); return [matcher, params]; }