Skip to content

Conversation

@sunnylqm
Copy link
Contributor

@sunnylqm sunnylqm commented Nov 3, 2025

fix #1520 again

Summary by CodeRabbit

  • Refactor
    • Internal restructuring of request handling logic to use Promise-based asynchronous flow instead of conditional branching, improving code maintainability while preserving existing behavior.

@coderabbitai
Copy link

coderabbitai bot commented Nov 3, 2025

Walkthrough

Refactored HEAD request handling in composeGeneralHandler to replace conditional type-checking logic with a Promise-based chain. The new approach wraps the composed response in Promise.resolve().then() and asynchronously computes content-length before constructing a Response object.

Changes

Cohort / File(s) Change Summary
HEAD Response Handler Refactoring
src/compose.ts
Replaced direct type branching with Promise-based flow for computing content-length and constructing Response in HEAD request handling

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Handler as composeGeneralHandler
    participant Promise as Promise Chain
    participant Response as Response Builder

    Client->>Handler: HEAD Request
    Handler->>Promise: Promise.resolve(ht[...].composed(c))
    Promise->>Promise: .then(_ht => getResponseLength(_ht))
    Promise->>Response: Set content-length header
    Response->>Response: Create Response(null, {status, statusText, headers})
    Response-->>Client: Return HEAD Response with Content-Length
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

  • Focus area: Verify async Promise chain correctly computes content-length without altering status/statusText semantics
  • Attention: Ensure Promise error handling and that the null Response body is appropriate for all HEAD request scenarios
  • Consideration: Confirm the control flow consolidation doesn't introduce timing or race condition issues with getResponseLength()

Possibly related PRs

  • fix head request #1522: Modifies the same HEAD-handling logic in src/compose.ts using promise-based chain for Content-Length computation and Response construction for async handlers

Poem

🐰 A promise-based hop through headers so fine,
Content-length computed in a Promise chain line,
HEAD requests dance with async flair,
Response constructed with utmost care,

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'fix head request handler again' is directly related to the main change in the changeset. The diff modifies the HEAD request handling logic in the compose function by refactoring the control flow from conditional branches to a Promise-based chain, which is exactly what the title indicates — a fix to the HEAD request handler. The title is concise, specific, and clearly communicates the primary intent of the change.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@sunnylqm sunnylqm changed the title fix head request handler fix head request handler again Nov 3, 2025
@pkg-pr-new
Copy link

pkg-pr-new bot commented Nov 3, 2025

Open in StackBlitz

npm i https://pkg.pr.new/elysiajs/elysia@1524

commit: 5921169

Copy link

@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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 01d03b5 and 5921169.

📒 Files selected for processing (1)
  • src/compose.ts (1 hunks)

Comment on lines +2384 to +2387
`return Promise.resolve(ht[${methods.GET ?? methods.ALL}].composed(c)).then(_ht=>getResponseLength(_ht).then((length)=>{` +
`_ht.headers.set('content-length', length)\n` +
`return new Response(null,{status:_ht.status,statusText:_ht.statusText,headers:_ht.headers})\n` +
`})` +
`}\n`
`}))\n`
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add null check before calling getResponseLength() to prevent potential runtime errors.

The static route HEAD handling wraps the handler result in Promise.resolve() and immediately chains to getResponseLength(_ht) without checking if _ht is null/undefined. In contrast, the dynamic route HEAD handling (line 2298) includes an if(_res) guard before proceeding. If composed(c) returns null/undefined, this will pass null to getResponseLength(), likely causing a runtime error.

Additionally, the inconsistency between static and dynamic route handling patterns makes the codebase harder to maintain.

Consider applying this pattern to match the dynamic route handling:

 switchMap +=
     `case 'HEAD':` +
-    `return Promise.resolve(ht[${methods.GET ?? methods.ALL}].composed(c)).then(_ht=>getResponseLength(_ht).then((length)=>{` +
+    `return Promise.resolve(ht[${methods.GET ?? methods.ALL}].composed(c)).then(_ht=>{` +
+    `if(!_ht)return\n` +
+    `return getResponseLength(_ht).then((length)=>{` +
     `_ht.headers.set('content-length', length)\n` +
     `return new Response(null,{status:_ht.status,statusText:_ht.statusText,headers:_ht.headers})\n` +
-    `}))\n`
+    `})})\n`

Alternatively, if handlers are guaranteed to never return null/undefined, document this assumption clearly.

📝 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
`return Promise.resolve(ht[${methods.GET ?? methods.ALL}].composed(c)).then(_ht=>getResponseLength(_ht).then((length)=>{` +
`_ht.headers.set('content-length', length)\n` +
`return new Response(null,{status:_ht.status,statusText:_ht.statusText,headers:_ht.headers})\n` +
`})` +
`}\n`
`}))\n`
`return Promise.resolve(ht[${methods.GET ?? methods.ALL}].composed(c)).then(_ht=>{` +
`if(!_ht)return\n` +
`return getResponseLength(_ht).then((length)=>{` +
`_ht.headers.set('content-length', length)\n` +
`return new Response(null,{status:_ht.status,statusText:_ht.statusText,headers:_ht.headers})\n` +
`})})\n`
🤖 Prompt for AI Agents
In src/compose.ts around lines 2384–2387, the static HEAD handler calls
getResponseLength(_ht) without checking whether _ht (the result of composed(c))
is null/undefined; add a truthiness guard like the dynamic route does: if _ht is
truthy, await getResponseLength(_ht), set the content-length header and return
the Response constructed from _ht; if _ht is falsy, skip getResponseLength and
immediately return an appropriate empty Response (mirroring the dynamic route
behavior) so no null is passed into getResponseLength and static and dynamic
handling patterns are consistent.

@SaltyAom SaltyAom merged commit e8e4408 into elysiajs:main Nov 9, 2025
3 checks passed
@stewones
Copy link

I'm in need of this fix @SaltyAom

any idea of when we get a new release? maybe it's time to figure out canary builds.

@SaltyAom
Copy link
Member

SaltyAom commented Nov 12, 2025

@stewones we have patch on going in the "next" branch

The current on going patch is at #1529 which has some PRs pending

As for canary build, you can try

bun add https://pkg.pr.new/elysiajs/elysia@1529

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Async handlers crash on HEAD request

3 participants