Skip to content

chore: upgrade h3 and cookie-es#7044

Open
ulrichstark wants to merge 7 commits intoTanStack:mainfrom
ulrichstark:chore-upgrade-and-unpin-h3
Open

chore: upgrade h3 and cookie-es#7044
ulrichstark wants to merge 7 commits intoTanStack:mainfrom
ulrichstark:chore-upgrade-and-unpin-h3

Conversation

@ulrichstark
Copy link
Copy Markdown
Contributor

@ulrichstark ulrichstark commented Mar 26, 2026

Closes #7043

The function h3_parseCookies now returns Record<string, string | undefined> instead of Record<string, string>. I handled that by filtering out the undefined values to keep the function signature unchanged to avoid breaking changes. Also inlined code from getCookies into getCookie to avoid the unnecessary execution of the for loop.

Summary by CodeRabbit

  • Chores

    • Updated HTTP library dependency to a newer pinned release and upgraded the cookie helper to v3.
  • Bug Fixes

    • Improved request header access.
    • Normalized cookie parsing to exclude undefined entries.
    • Made single-cookie retrieval behavior consistent.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 26, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 859ff8f2-7f69-4efb-b895-fb251e6e8d6f

📥 Commits

Reviewing files that changed from the base of the PR and between c15834b and dcff88a.

📒 Files selected for processing (1)
  • packages/start-server-core/src/request-response.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/start-server-core/src/request-response.ts

📝 Walkthrough

Walkthrough

Replaced h3-v2 alias with h3@2.0.1-rc.19 in start-server-core, bumped cookie-es to ^3.0.0 in two packages, updated imports in request-response to h3, returned req.headers directly, and changed cookie parsing to filter out undefined values and return a normalized record.

Changes

Cohort / File(s) Summary
Start Server Core package
packages/start-server-core/package.json
Replaced aliased h3-v2 (npm:h3@2.0.1-rc.16) with direct h3@2.0.1-rc.19; bumped devDependency cookie-es to ^3.0.0.
Request/Response code
packages/start-server-core/src/request-response.ts
Switched imports from h3-v2 to h3; getRequestHeaders() now returns event.req.headers (removed as any cast); getCookies() uses h3_parseCookies(event), filters out undefined values and returns a new Record<string,string>; getCookie(name) reads from h3_parseCookies(getH3Event()).
Router Core package
packages/router-core/package.json
Bumped cookie-es dependency from ^2.0.0 to ^3.0.0.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through lines of code today,
Swapped a tag and swept the crumbs away.
Cookies neat in a tidy row,
Events now clearer as they go.
A little nibble, a little cheer — I fixed the path and munched a pear. 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 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 (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'chore: upgrade h3 and cookie-es' clearly and concisely summarizes the main changes in the changeset.
Linked Issues check ✅ Passed The PR successfully addresses all coding requirements from #7043: upgrades h3 from 2.0.1-rc.16 to 2.0.1-rc.19 (resolving three documented vulnerabilities), updates cookie-es to v3 for compatibility, and handles h3's API changes (h3_parseCookies returning Record<string, string | undefined>).
Out of Scope Changes check ✅ Passed All changes are directly related to the PR objectives: package.json updates for h3 and cookie-es, modifications to request-response.ts to handle h3 API changes, and addressing cookie handling for the new return type.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@nx-cloud
Copy link
Copy Markdown
Contributor

nx-cloud bot commented Mar 26, 2026

View your CI Pipeline Execution ↗ for commit dcff88a

Command Status Duration Result
nx affected --targets=test:eslint,test:unit,tes... ❌ Failed 5m 38s View ↗
nx run-many --target=build --exclude=examples/*... ✅ Succeeded 32s View ↗

☁️ Nx Cloud last updated this comment at 2026-03-29 12:43:32 UTC

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 26, 2026

Bundle Size Benchmarks

  • Commit: 9368c5f3bfc9
  • Measured at: 2026-03-29T12:33:50.720Z
  • Baseline source: history:6ee0e795b085
  • Dashboard: bundle-size history
Scenario Current (gzip) Delta vs baseline Raw Brotli Trend
react-router.minimal 87.47 KiB 0 B (0.00%) 275.67 KiB 75.99 KiB █▇▇▃▃▂▂▂▂▁▁
react-router.full 90.76 KiB 0 B (0.00%) 286.86 KiB 78.96 KiB █▇▇▃▃▂▂▂▂▁▁
solid-router.minimal 35.51 KiB 0 B (0.00%) 107.04 KiB 31.90 KiB █▅▅▅▅▂▂▂▂▁▁
solid-router.full 39.98 KiB 0 B (0.00%) 120.57 KiB 35.84 KiB █▄▄▄▄▃▃▃▃▁▁
vue-router.minimal 53.36 KiB 0 B (0.00%) 152.97 KiB 47.91 KiB ███▂▂▂▂▂▂▁▁
vue-router.full 58.22 KiB 0 B (0.00%) 168.43 KiB 52.08 KiB ███▃▃▂▂▂▂▁▁
react-start.minimal 101.99 KiB 0 B (0.00%) 323.91 KiB 88.19 KiB █▆▆▂▂▂▂▂▂▁▁
react-start.full 105.36 KiB 0 B (0.00%) 334.26 KiB 91.00 KiB █▇▇▂▂▂▂▂▂▁▁
solid-start.minimal 49.61 KiB 0 B (0.00%) 153.29 KiB 43.69 KiB █▅▅▅▅▂▂▂▂▁▁
solid-start.full 55.10 KiB 0 B (0.00%) 169.52 KiB 48.41 KiB █▄▄▄▄▃▃▃▃▁▁

Trend sparkline is historical gzip bytes ending with this PR measurement; lower is better.

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new bot commented Mar 26, 2026

More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/@tanstack/arktype-adapter@7044

@tanstack/eslint-plugin-router

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

@tanstack/history

npm i https://pkg.pr.new/@tanstack/history@7044

@tanstack/nitro-v2-vite-plugin

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

@tanstack/react-router

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

@tanstack/react-router-devtools

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

@tanstack/react-router-ssr-query

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

@tanstack/react-start

npm i https://pkg.pr.new/@tanstack/react-start@7044

@tanstack/react-start-client

npm i https://pkg.pr.new/@tanstack/react-start-client@7044

@tanstack/react-start-server

npm i https://pkg.pr.new/@tanstack/react-start-server@7044

@tanstack/router-cli

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

@tanstack/router-core

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

@tanstack/router-devtools

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

@tanstack/router-devtools-core

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

@tanstack/router-generator

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

@tanstack/router-plugin

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

@tanstack/router-ssr-query-core

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

@tanstack/router-utils

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

@tanstack/router-vite-plugin

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

@tanstack/solid-router

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

@tanstack/solid-router-devtools

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

@tanstack/solid-router-ssr-query

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

@tanstack/solid-start

npm i https://pkg.pr.new/@tanstack/solid-start@7044

@tanstack/solid-start-client

npm i https://pkg.pr.new/@tanstack/solid-start-client@7044

@tanstack/solid-start-server

npm i https://pkg.pr.new/@tanstack/solid-start-server@7044

@tanstack/start-client-core

npm i https://pkg.pr.new/@tanstack/start-client-core@7044

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/@tanstack/start-fn-stubs@7044

@tanstack/start-plugin-core

npm i https://pkg.pr.new/@tanstack/start-plugin-core@7044

@tanstack/start-server-core

npm i https://pkg.pr.new/@tanstack/start-server-core@7044

@tanstack/start-static-server-functions

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

@tanstack/start-storage-context

npm i https://pkg.pr.new/@tanstack/start-storage-context@7044

@tanstack/valibot-adapter

npm i https://pkg.pr.new/@tanstack/valibot-adapter@7044

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/@tanstack/virtual-file-routes@7044

@tanstack/vue-router

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

@tanstack/vue-router-devtools

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

@tanstack/vue-router-ssr-query

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

@tanstack/vue-start

npm i https://pkg.pr.new/@tanstack/vue-start@7044

@tanstack/vue-start-client

npm i https://pkg.pr.new/@tanstack/vue-start-client@7044

@tanstack/vue-start-server

npm i https://pkg.pr.new/@tanstack/vue-start-server@7044

@tanstack/zod-adapter

npm i https://pkg.pr.new/@tanstack/zod-adapter@7044

commit: dcff88a

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/start-server-core/package.json (1)

85-85: Dependency is upgraded, but still pinned exactly.

Line 85 uses an exact version (2.0.1-rc.19). If the intent is to also unpin, switch to the repo’s preferred range style (for example ^2.0.1-rc.19).

Suggested change
-    "h3": "2.0.1-rc.19",
+    "h3": "^2.0.1-rc.19",
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/start-server-core/package.json` at line 85, The h3 dependency is
pinned to an exact version ("h3": "2.0.1-rc.19"); change that entry in
package.json to use the repo's preferred semver range (e.g., "h3":
"^2.0.1-rc.19") so the dependency is unpinned and follow-up package installs
pick up compatible updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/start-server-core/src/request-response.ts`:
- Around line 307-309: The getCookie implementation is converting empty-string
cookie values to undefined by using "cookies[name] || undefined"; update
getCookie to return the indexed value directly (i.e., return cookies[name]) so
that explicit empty values are preserved; locate the getCookie function where
getH3Event() and h3_parseCookies(event) are used and remove the "|| undefined"
fallback.

---

Nitpick comments:
In `@packages/start-server-core/package.json`:
- Line 85: The h3 dependency is pinned to an exact version ("h3":
"2.0.1-rc.19"); change that entry in package.json to use the repo's preferred
semver range (e.g., "h3": "^2.0.1-rc.19") so the dependency is unpinned and
follow-up package installs pick up compatible updates.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e2a7c156-ee4d-481d-be81-705786a19f55

📥 Commits

Reviewing files that changed from the base of the PR and between 87a5160 and 0713e9b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (2)
  • packages/start-server-core/package.json
  • packages/start-server-core/src/request-response.ts

Comment on lines +307 to +309
const event = getH3Event()
const cookies = h3_parseCookies(event)
return cookies[name] || undefined
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Check the file exists and view lines 307-309
wc -l packages/start-server-core/src/request-response.ts
sed -n '305,315p' packages/start-server-core/src/request-response.ts

Repository: TanStack/router

Length of output: 407


🏁 Script executed:

# Let's also look for the getCookie function definition and context
sed -n '305,320p' packages/start-server-core/src/request-response.ts

Repository: TanStack/router

Length of output: 493


🏁 Script executed:

# Search for where h3_parseCookies is imported from
rg "h3_parseCookies" packages/start-server-core/src/request-response.ts -B 5 -A 5

Repository: TanStack/router

Length of output: 1108


🏁 Script executed:

# Check package.json to find h3 version
rg '"h3"' packages/start-server-core/package.json

Repository: TanStack/router

Length of output: 83


🏁 Script executed:

# Search for any tests or usage examples of getCookie with empty values
rg "getCookie" packages/start-server-core --type ts -A 3 -B 1 | head -50

Repository: TanStack/router

Length of output: 1351


🏁 Script executed:

# Check if there are any comments or documentation about cookie behavior
rg "cookie" packages/start-server-core/src/request-response.ts -i -B 2 -A 2

Repository: TanStack/router

Length of output: 3291


🏁 Script executed:

# Search for tests related to getCookie function
find packages/start-server-core -name "*.test.*" -o -name "*.spec.*" | xargs rg "getCookie|cookie" 2>/dev/null | head -30

Repository: TanStack/router

Length of output: 41


🏁 Script executed:

# Check if there's any TypeScript type definition or JSDoc for parseCookies
rg "parseCookies" --type ts -B 5 -A 10 | head -50

Repository: TanStack/router

Length of output: 3939


🌐 Web query:

h3 parseCookies TypeScript return type empty string values

💡 Result:

In the h3 library (unjs/h3), the parseCookies(event) utility parses the Cookie header from the request and returns a Record<string, string> (object mapping cookie names to their values as strings). Cookie values are always strings, including empty strings ("") if the cookie was set with an empty value (e.g., name=; Path=/). This is standard behavior for Cookie header parsing using libraries like cookie (jshttp/cookie), which h3 relies on internally. TypeScript treats Record<string, string> as all values being non-nullable strings, so empty string values are fully compatible—no type errors occur. If no cookies are present, it returns {} (empty object), which is also valid. Examples from h3 docs and source: - parseCookies(event) → { cookieName: "cookieValue" } or { cookieName: "" } - getCookie(event, name) → string | undefined (wrapper around parseCookies) No issues or bugs reported specifically about empty string values in TypeScript context. If experiencing type mismatches, ensure proper typing: const cookies: Record<string, string> = parseCookies(event);. For source confirmation, early h3 versions used parse(req.headers.cookie || '') from 'cookie', returning Record<string, string>. Current versions maintain this signature per docs and utils pages.

Citations:


Preserve empty cookie values in getCookie().

Line 309 uses || undefined, which converts valid empty cookie values ('') into undefined. This loses information about whether a cookie was explicitly set to an empty value versus not being set at all. Return the indexed value directly to preserve this distinction.

Suggested fix
 export function getCookie(name: string): string | undefined {
   const event = getH3Event()
   const cookies = h3_parseCookies(event)
-  return cookies[name] || undefined
+  return cookies[name]
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const event = getH3Event()
const cookies = h3_parseCookies(event)
return cookies[name] || undefined
export function getCookie(name: string): string | undefined {
const event = getH3Event()
const cookies = h3_parseCookies(event)
return cookies[name]
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/start-server-core/src/request-response.ts` around lines 307 - 309,
The getCookie implementation is converting empty-string cookie values to
undefined by using "cookies[name] || undefined"; update getCookie to return the
indexed value directly (i.e., return cookies[name]) so that explicit empty
values are preserved; locate the getCookie function where getH3Event() and
h3_parseCookies(event) are used and remove the "|| undefined" fallback.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Mar 26, 2026

Merging this PR will not alter performance

✅ 6 untouched benchmarks


Comparing ulrichstark:chore-upgrade-and-unpin-h3 (dcff88a) with main (6ee0e79)1

Open in CodSpeed

Footnotes

  1. No successful run was found on main (9368c5f) during the generation of this report, so 6ee0e79 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@ulrichstark
Copy link
Copy Markdown
Contributor Author

ulrichstark commented Mar 26, 2026

The e2e test "un-matched malformed paths should return not found on direct navigation" is failing probably because of how h3 now handles malformed paths. I'm not sure what's the best way to continue. I will let the other more experienced contributors decide on how to continue with this PR.

Also no worries if my approach is incorrect and you want to close the PR.

@birkskyum
Copy link
Copy Markdown
Member

birkskyum commented Mar 29, 2026

@ulrichstark , thanks for looking into this. We need to update cookie-es to v3 (release notes) as part of this PR, since it was bumped in h3 v2.0.1-rc.19

@ulrichstark ulrichstark changed the title chore: upgrade and unpin h3 in start-server-core chore: upgrade h3 and cookie-es Mar 29, 2026
nx-cloud[bot]

This comment was marked as outdated.

@ulrichstark
Copy link
Copy Markdown
Contributor Author

@ulrichstark , thanks for looking into this. We need to update cookie-es to v3 (release notes) as part of this PR, since it was bumped in h3 v2.0.1-rc.19

Thanks! I changed the PR title to reflect that and made one commit that removes an unnecessary any.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
packages/start-server-core/src/request-response.ts (1)

315-317: ⚠️ Potential issue | 🟡 Minor

Don’t collapse empty cookie values in getCookie().

Line 317 converts an explicit empty cookie into undefined. h3’s own helper returns the parsed entry directly and documents undefined only for the missing-cookie case, so this makes name= indistinguishable from “missing”. Return cookies[name] as-is. (raw.githubusercontent.com)

Suggested fix
-  return cookies[name] || undefined
+  return cookies[name]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/start-server-core/src/request-response.ts` around lines 315 - 317,
The getCookie implementation collapses explicit empty cookie values to
undefined; update the function that calls getH3Event and h3_parseCookies (the
getCookie helper) to return cookies[name] directly instead of using "||
undefined" so that an explicit empty string (name=) is preserved; locate the
return in getCookie and remove the coalescing to undefined so it mirrors
h3_parseCookies behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/start-server-core/src/request-response.ts`:
- Around line 295-303: The current normalization creates normalizedCookies with
a plain object literal which loses the prototype-less semantics from the
upstream parser; change the initialization of normalizedCookies to use
Object.create(null) so it remains prototype-less while you still copy/filter
values from cookies via the existing loop over Object.entries(cookies); keep the
rest of the logic the same (the variable names to update are normalizedCookies
and the loop using cookies).

---

Duplicate comments:
In `@packages/start-server-core/src/request-response.ts`:
- Around line 315-317: The getCookie implementation collapses explicit empty
cookie values to undefined; update the function that calls getH3Event and
h3_parseCookies (the getCookie helper) to return cookies[name] directly instead
of using "|| undefined" so that an explicit empty string (name=) is preserved;
locate the return in getCookie and remove the coalescing to undefined so it
mirrors h3_parseCookies behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 306bcd6e-518a-4865-a376-3d5f93faf0d2

📥 Commits

Reviewing files that changed from the base of the PR and between 4d84574 and c15834b.

📒 Files selected for processing (1)
  • packages/start-server-core/src/request-response.ts

@ulrichstark
Copy link
Copy Markdown
Contributor Author

I tried Nx's proposed fix for the CI failure, but that didn't turn the CI green. I reverted it and leave the rest of the PR up to other maintainers.

@birkskyum
Copy link
Copy Markdown
Member

@ulrichstark , I've submitted an issue here:

Copy link
Copy Markdown
Contributor

@nx-cloud nx-cloud bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nx Cloud is proposing a fix for your failed CI:

We replaced the bare return new Response(null, { status: 404 }) fallback with a path-sanitization step that double-encodes malformed percent sequences (%%25) so h3 rc.19's new decodePathname/decodeURI call in the H3Event constructor no longer throws. By passing the original (unsanitized) request to the handler, the router still receives the malformed path, catches the URIError in its own findMatch, and renders the default-not-found-component with a proper 404 HTML response — restoring the behavior that existed with h3 rc.16.

Warning

We could not verify this fix.

Suggested Fix changes
diff --git a/packages/start-server-core/src/request-response.ts b/packages/start-server-core/src/request-response.ts
index 2ceb0a2e50..e1dd29babb 100644
--- a/packages/start-server-core/src/request-response.ts
+++ b/packages/start-server-core/src/request-response.ts
@@ -126,10 +126,31 @@ export function requestHandler<TRegister = unknown>(
     try {
       h3Event = new H3Event(request)
     } catch (err) {
-      if (err instanceof URIError) {
+      if (!(err instanceof URIError)) {
+        throw err
+      }
+      // h3 v2 decodes the URL pathname during H3Event construction and throws
+      // URIError for malformed percent-encoded sequences (e.g. %E0%A4).
+      // Sanitize the path so H3Event can be constructed, but pass the original
+      // request to the handler so the router encounters the malformed path,
+      // catches its own URIError, and renders the not-found component with 404.
+      try {
+        const url = new URL(request.url)
+        url.pathname = url.pathname
+          .split('/')
+          .map((segment) => {
+            try {
+              decodeURIComponent(segment)
+              return segment
+            } catch {
+              return segment.replace(/%/g, '%25')
+            }
+          })
+          .join('/')
+        h3Event = new H3Event(new Request(url.toString(), request))
+      } catch {
         return new Response(null, { status: 404 })
       }
-      throw err
     }
 
     const response = eventStorage.run({ h3Event }, () =>

Because this branch comes from a fork, it is not possible for us to apply fixes directly, but you can apply the changes locally using the available options below.

Apply changes locally with:

npx nx-cloud apply-locally 5wuQ-kEUE

Apply fix locally with your editor ↗   View interactive diff ↗



🎓 Learn more about Self-Healing CI on nx.dev

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.

start-server-core depends on vulnerable pinned version of h3

2 participants