From 9d087fced6780ba0fe2f3e548567d7b0d8d1a9bd Mon Sep 17 00:00:00 2001 From: Matt Brophy Date: Tue, 18 Apr 2023 15:01:10 -0400 Subject: [PATCH] Fail gracefully on invalid Link to values --- .changeset/invalid-link-to.md | 5 +++ .../__tests__/link-href-test.tsx | 20 ++++++++++++ packages/react-router-dom/index.tsx | 31 ++++++++++++------- 3 files changed, 45 insertions(+), 11 deletions(-) create mode 100644 .changeset/invalid-link-to.md diff --git a/.changeset/invalid-link-to.md b/.changeset/invalid-link-to.md new file mode 100644 index 0000000000..309699aaf8 --- /dev/null +++ b/.changeset/invalid-link-to.md @@ -0,0 +1,5 @@ +--- +"react-router-dom": patch +--- + +Fail gracefully on `` and other invalid URL values diff --git a/packages/react-router-dom/__tests__/link-href-test.tsx b/packages/react-router-dom/__tests__/link-href-test.tsx index 386fb7d9b2..762f972ddc 100644 --- a/packages/react-router-dom/__tests__/link-href-test.tsx +++ b/packages/react-router-dom/__tests__/link-href-test.tsx @@ -907,4 +907,24 @@ describe(" href", () => { ); }); }); + + test("fails gracefully on invalid `to` values", () => { + let warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {}); + let renderer: TestRenderer.ReactTestRenderer; + TestRenderer.act(() => { + renderer = TestRenderer.create( + + + } /> + + + ); + }); + + expect(renderer.root.findByType("a").props.href).toEqual("//"); + expect(warnSpy).toHaveBeenCalledWith( + ' contains an invalid URL which will probably break when clicked - please update to a valid URL path.' + ); + warnSpy.mockRestore(); + }); }); diff --git a/packages/react-router-dom/index.tsx b/packages/react-router-dom/index.tsx index d4cf14ddcc..7dd37cf655 100644 --- a/packages/react-router-dom/index.tsx +++ b/packages/react-router-dom/index.tsx @@ -449,17 +449,26 @@ export const Link = React.forwardRef( // Only check for external origins client-side if (isBrowser) { - let currentUrl = new URL(window.location.href); - let targetUrl = to.startsWith("//") - ? new URL(currentUrl.protocol + to) - : new URL(to); - let path = stripBasename(targetUrl.pathname, basename); - - if (targetUrl.origin === currentUrl.origin && path != null) { - // Strip the protocol/origin/basename for same-origin absolute URLs - to = path + targetUrl.search + targetUrl.hash; - } else { - isExternal = true; + try { + let currentUrl = new URL(window.location.href); + let targetUrl = to.startsWith("//") + ? new URL(currentUrl.protocol + to) + : new URL(to); + let path = stripBasename(targetUrl.pathname, basename); + + if (targetUrl.origin === currentUrl.origin && path != null) { + // Strip the protocol/origin/basename for same-origin absolute URLs + to = path + targetUrl.search + targetUrl.hash; + } else { + isExternal = true; + } + } catch (e) { + // We can't do external URL detection without a valid URL + warning( + false, + ` contains an invalid URL which will probably break ` + + `when clicked - please update to a valid URL path.` + ); } } }