Skip to content

Commit 9d087fc

Browse files
committed
Fail gracefully on invalid Link to values
1 parent 95a295c commit 9d087fc

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
@@ -449,17 +449,26 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
449449

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

0 commit comments

Comments
 (0)