Skip to content

Commit 54649f9

Browse files
authored
refactor(router-core): throw redirect w/ a pre-build location doesn't need to re-parse from string (#6512)
1 parent 3b61ca2 commit 54649f9

File tree

2 files changed

+31
-7
lines changed

2 files changed

+31
-7
lines changed

packages/router-core/src/redirect.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { SAFE_URL_PROTOCOLS, isDangerousProtocol } from './utils'
22
import type { NavigateOptions } from './link'
33
import type { AnyRouter, RegisteredRouter } from './router'
4+
import type { ParsedLocation } from './location'
45

56
export type AnyRedirect = Redirect<any, any, any, any, any>
67

@@ -14,7 +15,13 @@ export type Redirect<
1415
TMaskFrom extends string = TFrom,
1516
TMaskTo extends string = '.',
1617
> = Response & {
17-
options: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
18+
options: NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo> & {
19+
/**
20+
* @internal
21+
* A **trusted** built location that can be used to redirect to.
22+
*/
23+
_builtLocation?: ParsedLocation
24+
}
1825
redirectHandled?: boolean
1926
}
2027

@@ -45,6 +52,11 @@ export type RedirectOptions<
4552
* @link [API Docs](https://tanstack.com/router/latest/docs/framework/react/api/router/RedirectType#headers-property)
4653
*/
4754
headers?: HeadersInit
55+
/**
56+
* @internal
57+
* A **trusted** built location that can be used to redirect to.
58+
*/
59+
_builtLocation?: ParsedLocation
4860
} & NavigateOptions<TRouter, TFrom, TTo, TMaskFrom, TMaskTo>
4961

5062
export type ResolvedRedirect<
@@ -113,13 +125,21 @@ export function redirect<
113125
opts.statusCode = opts.statusCode || opts.code || 307
114126

115127
// Block dangerous protocols in redirect href
116-
if (typeof opts.href === 'string' && isDangerousProtocol(opts.href)) {
128+
if (
129+
!opts._builtLocation &&
130+
typeof opts.href === 'string' &&
131+
isDangerousProtocol(opts.href)
132+
) {
117133
throw new Error(
118134
`Redirect blocked: unsafe protocol in href "${opts.href}". Only ${SAFE_URL_PROTOCOLS.join(', ')} protocols are allowed.`,
119135
)
120136
}
121137

122-
if (!opts.reloadDocument && typeof opts.href === 'string') {
138+
if (
139+
!opts._builtLocation &&
140+
!opts.reloadDocument &&
141+
typeof opts.href === 'string'
142+
) {
123143
try {
124144
new URL(opts.href)
125145
opts.reloadDocument = true

packages/router-core/src/router.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2284,8 +2284,11 @@ export class RouterCore<
22842284
// always uses this.origin when constructing URLs
22852285
if (this.latestLocation.publicHref !== nextLocation.publicHref) {
22862286
const href = this.getParsedLocationHref(nextLocation)
2287-
2288-
throw redirect({ href })
2287+
if (nextLocation.external) {
2288+
throw redirect({ href })
2289+
} else {
2290+
throw redirect({ href, _builtLocation: nextLocation })
2291+
}
22892292
}
22902293
}
22912294

@@ -2614,8 +2617,9 @@ export class RouterCore<
26142617
resolveRedirect = (redirect: AnyRedirect): AnyRedirect => {
26152618
const locationHeader = redirect.headers.get('Location')
26162619

2617-
if (!redirect.options.href) {
2618-
const location = this.buildLocation(redirect.options)
2620+
if (!redirect.options.href || redirect.options._builtLocation) {
2621+
const location =
2622+
redirect.options._builtLocation ?? this.buildLocation(redirect.options)
26192623
const href = this.getParsedLocationHref(location)
26202624
redirect.options.href = href
26212625
redirect.headers.set('Location', href)

0 commit comments

Comments
 (0)