Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 2 additions & 10 deletions src/compose.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2381,18 +2381,10 @@ export const composeGeneralHandler = (app: AnyElysia) => {
)
switchMap +=
`case 'HEAD':` +
`const _ht=ht[${methods.GET ?? methods.ALL}].composed(c)\n` +
`if(typeof _ht === 'function') {return _ht` +
`.then(_res=>getResponseLength(_res).then((length)=>{` +
`_res.headers.set('content-length', length)\n` +
`return new Response(null,{status:_res.status,statusText:_res.statusText,headers:_res.headers})\n` +
'}))\n' +
`}else{` +
`return getResponseLength(_ht).then((length)=>{` +
`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`
Comment on lines +2384 to +2387
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 | 🟠 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.


for (const [method, index] of Object.entries(methods)) {
if (method === 'ALL' || method === 'GET' || method === 'WS')
Expand Down
Loading