Skip to content

Commit 34779ab

Browse files
authored
Fail gracefully on invalid Link to values (#10367)
1 parent bb799e7 commit 34779ab

File tree

3 files changed

+45
-11
lines changed

3 files changed

+45
-11
lines changed

.changeset/invalid-link-to.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-router-dom": patch
3+
---
4+
5+
Fail gracefully on `<Link to="//">` and other invalid URL values

packages/react-router-dom/__tests__/link-href-test.tsx

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -907,4 +907,24 @@ describe("<Link> href", () => {
907907
);
908908
});
909909
});
910+
911+
test("fails gracefully on invalid `to` values", () => {
912+
let warnSpy = jest.spyOn(console, "warn").mockImplementation(() => {});
913+
let renderer: TestRenderer.ReactTestRenderer;
914+
TestRenderer.act(() => {
915+
renderer = TestRenderer.create(
916+
<MemoryRouter>
917+
<Routes>
918+
<Route path="/" element={<Link to="//" />} />
919+
</Routes>
920+
</MemoryRouter>
921+
);
922+
});
923+
924+
expect(renderer.root.findByType("a").props.href).toEqual("//");
925+
expect(warnSpy).toHaveBeenCalledWith(
926+
'<Link to="//"> contains an invalid URL which will probably break when clicked - please update to a valid URL path.'
927+
);
928+
warnSpy.mockRestore();
929+
});
910930
});

packages/react-router-dom/index.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -451,17 +451,26 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
451451

452452
// Only check for external origins client-side
453453
if (isBrowser) {
454-
let currentUrl = new URL(window.location.href);
455-
let targetUrl = to.startsWith("//")
456-
? new URL(currentUrl.protocol + to)
457-
: new URL(to);
458-
let path = stripBasename(targetUrl.pathname, basename);
459-
460-
if (targetUrl.origin === currentUrl.origin && path != null) {
461-
// Strip the protocol/origin/basename for same-origin absolute URLs
462-
to = path + targetUrl.search + targetUrl.hash;
463-
} else {
464-
isExternal = true;
454+
try {
455+
let currentUrl = new URL(window.location.href);
456+
let targetUrl = to.startsWith("//")
457+
? new URL(currentUrl.protocol + to)
458+
: new URL(to);
459+
let path = stripBasename(targetUrl.pathname, basename);
460+
461+
if (targetUrl.origin === currentUrl.origin && path != null) {
462+
// Strip the protocol/origin/basename for same-origin absolute URLs
463+
to = path + targetUrl.search + targetUrl.hash;
464+
} else {
465+
isExternal = true;
466+
}
467+
} catch (e) {
468+
// We can't do external URL detection without a valid URL
469+
warning(
470+
false,
471+
`<Link to="${to}"> contains an invalid URL which will probably break ` +
472+
`when clicked - please update to a valid URL path.`
473+
);
465474
}
466475
}
467476
}

0 commit comments

Comments
 (0)