Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

20 changes: 0 additions & 20 deletions packages/react-router/__tests__/dom/link-href-test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -129,26 +129,6 @@ describe("<Link> href", () => {
expect(renderer.root.findByType("a").props.href).toEqual("//remix.run");
});

test("normalizes special characters in relative <Link> values", () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
renderer = TestRenderer.create(
<MemoryRouter initialEntries={["/inbox/messages"]}>
<Routes>
<Route path="inbox">
<Route
path="messages"
element={<Link to={"/\t/nested/path"} />}
/>
</Route>
</Routes>
</MemoryRouter>,
);
});

expect(renderer.root.findByType("a").props.href).toEqual("/nested/path");
});

test('<Link to="mailto:remix@example.com"> is treated as external link', () => {
let renderer: TestRenderer.ReactTestRenderer;
TestRenderer.act(() => {
Expand Down
6 changes: 0 additions & 6 deletions packages/react-router/__tests__/router/browser-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,6 @@ describe("a browser history", () => {
expect(href).toEqual("/the/path?the=query#the-hash");
});

it("normalizes special characters in relative hrefs", () => {
for (let char of ["\t", "\n", "\r"]) {
expect(history.createHref(`/${char}/nested/path`)).toBe("/nested/path");
}
});

it("does not encode the generated path", () => {
const encodedHref = history.createHref({
pathname: "/%23abc",
Expand Down
21 changes: 1 addition & 20 deletions packages/react-router/__tests__/router/redirects-test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createMemoryHistory } from "../../lib/router/history";
import { IDLE_NAVIGATION, createRouter } from "../../lib/router/router";
import { redirect, replace } from "../../lib/router/utils";
import { replace } from "../../lib/router/utils";
import type { TestRouteObject } from "./utils/data-router-setup";
import { cleanup, setup } from "./utils/data-router-setup";
import { createFormData, tick } from "./utils/utils";
Expand Down Expand Up @@ -482,25 +482,6 @@ describe("redirects", () => {
}
});

it("normalizes special characters in redirects", async () => {
let router = createRouter({
history: createMemoryHistory(),
routes: [
{ path: "/" },
{ path: "/start", loader: () => redirect("/\t/parent") },
{ path: "/parent" },
],
});
router.initialize();
await tick();

await router.navigate("/start");
expect(router.state.location).toMatchObject({
pathname: "/parent",
});
router.dispose();
});

it("properly handles same-origin absolute URLs when using a basename", async () => {
let t = setup({ routes: REDIRECT_ROUTES, basename: "/base" });

Expand Down
7 changes: 4 additions & 3 deletions packages/react-router/lib/dom/lib.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,13 @@ import {
defaultMapRouteProperties,
ErrorResponseImpl,
SUPPORTED_ERROR_TYPES,
isAbsoluteUrl,
joinPaths,
matchPath,
parseToInfo,
resolveTo,
stripBasename,
} from "../router/utils";
import { ABSOLUTE_URL_REGEX } from "../router/url";

// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type * as _ from "./global";
Expand Down Expand Up @@ -1334,7 +1334,7 @@ export const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(
) {
let { basename, navigator, useTransitions } =
React.useContext(NavigationContext);
let isAbsolute = typeof to === "string" && isAbsoluteUrl(to);
let isAbsolute = typeof to === "string" && ABSOLUTE_URL_REGEX.test(to);

let parsed = parseToInfo(to, basename);
to = parsed.to;
Expand Down Expand Up @@ -1944,7 +1944,8 @@ export const Form = React.forwardRef<HTMLFormElement, FormProps>(
let formAction = useFormAction(action, { relative });
let formMethod: HTMLFormMethod =
method.toLowerCase() === "get" ? "get" : "post";
let isAbsolute = typeof action === "string" && isAbsoluteUrl(action);
let isAbsolute =
typeof action === "string" && ABSOLUTE_URL_REGEX.test(action);

let submitHandler: React.SubmitEventHandler<HTMLFormElement> = (event) => {
onSubmit && onSubmit(event);
Expand Down
3 changes: 1 addition & 2 deletions packages/react-router/lib/dom/server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {
convertRoutesToDataRoutes,
isRouteErrorResponse,
} from "../router/utils";
import { ABSOLUTE_URL_REGEX, normalizeRelativeUrl } from "../router/url";
import { ABSOLUTE_URL_REGEX } from "../router/url";
import { DataRoutes, Router } from "../components";
import {
DataRouterContext,
Expand Down Expand Up @@ -457,7 +457,6 @@ function createHref(to: To) {

function encodeLocation(to: To): Path {
let href = typeof to === "string" ? to : createPath(to);
href = normalizeRelativeUrl(href);
// Treating this as a full URL will strip any trailing spaces so we need to
// pre-encode them since they might be part of a matching splat param from
// an ancestor route
Expand Down
5 changes: 2 additions & 3 deletions packages/react-router/lib/router/history.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { normalizeRelativeUrl, PROTOCOL_RELATIVE_URL_REGEX } from "./url";
import { PROTOCOL_RELATIVE_URL_REGEX } from "./url";

////////////////////////////////////////////////////////////////////////////////
//#region Types and Constants
Expand Down Expand Up @@ -407,7 +407,7 @@ export function createBrowserHistory(
}

function createBrowserHref(window: Window, to: To) {
return normalizeRelativeUrl(typeof to === "string" ? to : createPath(to));
return typeof to === "string" ? to : createPath(to);
}

return getUrlBasedHistory(
Expand Down Expand Up @@ -798,7 +798,6 @@ export function createBrowserURLImpl(
invariant(base, "No window.location.(origin|href) available to create URL");

let href = typeof to === "string" ? to : createPath(to);
href = normalizeRelativeUrl(href);

// Treating this as a full URL will strip any trailing spaces so we need to
// pre-encode them since they might be part of a matching splat param from
Expand Down
3 changes: 0 additions & 3 deletions packages/react-router/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,6 @@ import {
} from "./utils";
import {
normalizeProtocolRelativeUrl,
normalizeRelativeUrl,
PROTOCOL_RELATIVE_URL_REGEX,
} from "./url";

Expand Down Expand Up @@ -6909,8 +6908,6 @@ function normalizeRedirectLocation(
basename: string,
historyInstance: History,
): string {
location = normalizeRelativeUrl(location);

if (isAbsoluteUrl(location)) {
// Strip off the protocol+origin for same-origin + same-basename absolute redirects
let normalizedLocation = location;
Expand Down
19 changes: 0 additions & 19 deletions packages/react-router/lib/router/url.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,6 @@
export const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i;
export const PROTOCOL_RELATIVE_URL_REGEX = /^[\\/]{2}/;

// Normalize characters ignored by the URL parser before determining whether a
// URL is relative or absolute.
export function normalizeRelativeUrl(url: string): string {
if (ABSOLUTE_URL_REGEX.test(url)) {
return url;
}

let normalized = url.replace(/[\t\n\r]/g, "");
if (!ABSOLUTE_URL_REGEX.test(normalized)) {
return normalized;
}

if (PROTOCOL_RELATIVE_URL_REGEX.test(normalized)) {
return normalized.replace(/^[\\/]+/, "/");
}

return normalized.replace(/^([a-z][a-z0-9+.-]*):/i, "$1%3A");
}

export function normalizeProtocolRelativeUrl(url: string, protocol: string) {
return protocol + url.replace(/\\/g, "/");
}
9 changes: 2 additions & 7 deletions packages/react-router/lib/router/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { invariant, parsePath, warning } from "./history";
import {
ABSOLUTE_URL_REGEX,
normalizeProtocolRelativeUrl,
normalizeRelativeUrl,
PROTOCOL_RELATIVE_URL_REGEX,
} from "./url";

Expand Down Expand Up @@ -1854,8 +1853,7 @@ export function prependBasename({
return pathname === "/" ? basename : joinPaths([basename, pathname]);
}

export const isAbsoluteUrl = (url: string) =>
ABSOLUTE_URL_REGEX.test(normalizeRelativeUrl(url));
export const isAbsoluteUrl = (url: string) => ABSOLUTE_URL_REGEX.test(url);

/**
* Returns a resolved {@link Path} object relative to the given pathname.
Expand All @@ -1876,7 +1874,6 @@ export function resolvePath(to: To, fromPathname = "/"): Path {

let pathname: string;
if (toPathname) {
toPathname = normalizeRelativeUrl(toPathname);
toPathname = removeDoubleSlashes(toPathname);
if (toPathname.startsWith("/")) {
pathname = resolvePathname(toPathname.substring(1), "/");
Expand Down Expand Up @@ -2410,9 +2407,7 @@ export function parseToInfo<T extends To | string>(
_to: T,
basename: string,
): ParsedLocationInfo<T | string> {
let to = (
typeof _to === "string" ? normalizeRelativeUrl(_to) : _to
) as string;
let to = _to as string;
if (typeof to !== "string" || !ABSOLUTE_URL_REGEX.test(to)) {
return {
absoluteURL: undefined,
Expand Down
7 changes: 1 addition & 6 deletions packages/react-router/lib/rsc/browser.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,7 @@ import type {
RouterContextProvider,
} from "../router/utils";
import { ErrorResponseImpl, createContext, resolvePath } from "../router/utils";
import {
normalizeRelativeUrl,
PROTOCOL_RELATIVE_URL_REGEX,
} from "../router/url";
import { PROTOCOL_RELATIVE_URL_REGEX } from "../router/url";
import type {
DecodedSingleFetchResults,
FetchAndDecodeFunction,
Expand Down Expand Up @@ -1134,8 +1131,6 @@ function isExternalLocation(location: string) {
}

function normalizeRedirectLocation(location: string): string {
location = normalizeRelativeUrl(location);

if (PROTOCOL_RELATIVE_URL_REGEX.test(location)) {
let path = resolvePath(location);
return path.pathname + path.search + path.hash;
Expand Down