-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Hi! 👋
Firstly, thanks for your work on this project! 🙂
When using splat routes (/$) with URLs containing encoded special characters (e.g., %20 for spaces, %28/%29 for parentheses), SSR causes an infinite 307 redirect loop.
Root cause: The encodeParam function in path.ts uses encodeURI() for splat params, which doesn't encode spaces or parentheses. When comparing the original URL (/path/file%20name.pdf) with the rebuilt URL (/path/file name.pdf), they don't match, triggering a redirect with unencoded characters in the Location header.
Reproduction:
- Create a splat route ($.tsx)
- Navigate to a URL with spaces: /owner/repo/blob/main/my%20file.pdf
- Refresh the page
- Observe infinite 307 redirect loop
Fix: Replace encodeURI(value) with value.split('/').map(segment => encodeURIComponent(segment)).join('/') to properly encode each path segment.
Today I used patch-package to patch @tanstack/router-core@1.157.3 for the project I'm working on.
Here is the diff that solved my problem:
diff --git a/node_modules/@tanstack/router-core/dist/esm/path.js b/node_modules/@tanstack/router-core/dist/esm/path.js
index b178989..af2c810 100644
--- a/node_modules/@tanstack/router-core/dist/esm/path.js
+++ b/node_modules/@tanstack/router-core/dist/esm/path.js
@@ -120,7 +120,9 @@ function encodeParam(key, params, decoder) {
const value = params[key];
if (typeof value !== "string") return value;
if (key === "_splat") {
- return encodeURI(value);
+ // Use encodeURIComponent for each segment to properly encode spaces and special characters
+ // but preserve forward slashes as path separators
+ return value.split('/').map(segment => encodeURIComponent(segment)).join('/');
} else {
return encodePathParam(value, decoder);
}
diff --git a/node_modules/@tanstack/router-core/dist/esm/utils.js b/node_modules/@tanstack/router-core/dist/esm/utils.js
index d966d48..1b1469c 100644
--- a/node_modules/@tanstack/router-core/dist/esm/utils.js
+++ b/node_modules/@tanstack/router-core/dist/esm/utils.js
@@ -219,8 +219,24 @@ function decodePath(path, decodeIgnore) {
return result;
}
function encodeNonAscii(path) {
- if (!/[^\u0000-\u007F]/.test(path)) return path;
- return path.replace(/[^\u0000-\u007F]/gu, encodeURIComponent);
+ // Encode both non-ASCII characters and special characters that should be encoded in URLs
+ // Split by / to preserve path separators, encode each segment
+ return path.split('/').map(segment => {
+ // Encode special characters: spaces, parentheses, brackets, etc.
+ if (/[\s()[\]{}#]/.test(segment)) {
+ return segment.split('').map(char => {
+ if (/[\s()[\]{}#]/.test(char)) {
+ return encodeURIComponent(char);
+ }
+ return char;
+ }).join('');
+ }
+ // Also encode non-ASCII
+ if (/[^\u0000-\u007F]/.test(segment)) {
+ return segment.replace(/[^\u0000-\u007F]/gu, encodeURIComponent);
+ }
+ return segment;
+ }).join('/');
}
function buildDevStylesUrl(basepath, routeIds) {
const trimmedBasepath = basepath.replace(/^\/+|\/+$/g, "");
This issue body was partially generated by patch-package.