Skip to content

fix(start-server-core): redirect misinterpreted protocol-relative URLs#6600

Merged
nlynzaad merged 7 commits intomainfrom
redirect-multi-slash
Feb 7, 2026
Merged

fix(start-server-core): redirect misinterpreted protocol-relative URLs#6600
nlynzaad merged 7 commits intomainfrom
redirect-multi-slash

Conversation

@nlynzaad
Copy link
Contributor

@nlynzaad nlynzaad commented Feb 6, 2026

As part of Protocol-relative URL preventions paths starting with // like //posts is collapsed to a single slash /posts.

Currently this collapsed path is treated as the to for navigation and can be problematic in the case of SEO.

This PR ensures that these are now redirected to the collapsed path instead of normal navigation, cleans up some dead code in decodePath and update the tests accordingly.

Summary by CodeRabbit

  • Bug Fixes

    • Strengthened open redirect prevention with improved protocol-relative URL handling and normalization.
    • Added automatic redirects for properly handled protocol-relative URLs to ensure secure routing.
  • Tests

    • Expanded end-to-end test coverage for URL normalization and open redirect prevention scenarios.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 6, 2026

📝 Walkthrough

Walkthrough

This PR refactors URL and path handling utilities in router-core by changing decodePath, interpolatePath, and getNormalizedURL to return structured objects with nested properties instead of flat values. All call sites are updated to access these new property shapes. Additionally, protocol-relative URL handling is exposed via a new handledProtocolRelativeURL flag, enabling redirect logic in the start server handler.

Changes

Cohort / File(s) Summary
Core Utility API Changes
packages/router-core/src/utils.ts
Updated decodePath signature to return { path: string, handledProtocolRelativeURL: boolean } instead of a string; removed decodeIgnore parameter and now always uses a fixed regex pattern; added tracking for protocol-relative URL sanitization.
Router Path Handling
packages/router-core/src/router.ts
Updated all calls to decodePath(...) and interpolatePath(...) to access the .path property on returned objects; adjusted location parsing and URL path reconstruction to use nested property accessors.
SSR/Server Normalization
packages/router-core/src/ssr/ssr-server.ts, packages/router-core/src/ssr/createRequestHandler.ts
Refactored getNormalizedURL to return { url: URL, handledProtocolRelativeURL: boolean } instead of a plain URL; updated decodePath destructuring to extract path and handledProtocolRelativeURL properties.
Start Server Handler
packages/start-server-core/src/createStartHandler.ts
Added early redirect logic: if handledProtocolRelativeURL is true, respond with a 308 redirect to the normalized URL before continuing with normal start handling.
Test Updates
packages/router-core/tests/utils.test.ts, packages/router-core/tests/getNormalizedURL.test.ts
Updated all test assertions to access .path property on decodePath results and .url nested properties on getNormalizedURL results; added assertions for handledProtocolRelativeURL flag where relevant.
E2E Open Redirect Prevention
e2e/react-start/basic/tests/open-redirect-prevention.spec.ts
Added isSpaMode utility import; captured navigation response and added conditional assertion for non-SPA mode to verify redirect source via request().redirectedFrom().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

package: router-core, package: start-server-core

Suggested reviewers

  • schiller-manuel
  • Sheraff

Poem

🐰 A rabbit's ode to structured returns:
Paths once flat, now nested deep,
Properties dance where strings once sleep,
Protocol-flags expose what's true,
Redirects flow both fresh and new,
Type-safe hops through normalized land! 🛤️

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 40.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: implementing redirects for protocol-relative URLs that were previously being collapsed and treated as normal navigation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch redirect-multi-slash

Comment @coderabbitai help to get the list of available commands and usage tips.

@nlynzaad nlynzaad changed the title fix(start-server-core, router-core-ssr): redirect misinterpreted protocol-relative URLs fix(start-server-core): redirect misinterpreted protocol-relative URLs Feb 6, 2026
@nx-cloud
Copy link

nx-cloud bot commented Feb 6, 2026

View your CI Pipeline Execution ↗ for commit 673f7d1

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ✅ Succeeded 12m 22s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 1m 46s View ↗

☁️ Nx Cloud last updated this comment at 2026-02-06 00:42:13 UTC

@pkg-pr-new
Copy link

pkg-pr-new bot commented Feb 6, 2026

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@6600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6600

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@6600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@6600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@6600

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@6600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@6600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@6600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@6600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@6600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@6600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@6600

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@6600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@6600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@6600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@6600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@6600

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@6600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6600

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-fn-stubs@6600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6600

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@6600

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6600

@tanstack/vue-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6600

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-devtools@6600

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-ssr-query@6600

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6600

@tanstack/vue-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-client@6600

@tanstack/vue-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-server@6600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6600

commit: 673f7d1

@nlynzaad nlynzaad merged commit 40ed683 into main Feb 7, 2026
6 checks passed
@nlynzaad nlynzaad deleted the redirect-multi-slash branch February 7, 2026 00:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants