fix: resolve ratelimit, worker eviction, body hang, and path traversal - #236
Conversation
1Lucas1apk
left a comment
There was a problem hiding this comment.
Overall, looks good to me. I just left a few comments about some edge cases and consistency stuff that I think would be worth fixing before merging.
| } | ||
|
|
||
| const onEnd = () => { | ||
| const onError = (error: Error) => { |
There was a problem hiding this comment.
I think there’s a small issue here.
In onError, we destroy req and call settle(false), but res is not closed. In the other cases (timeoutId, onData when the body exceeds the limit, and onEnd when the JSON is invalid), sendErrorResponse is used to close the response, but that doesn’t happen here.
So if the headers haven’t been sent yet, the request could end up hanging for the client.
Maybe we should check res.headersSent here and send a 500 before finishing:
if (!res.headersSent) {
sendErrorResponse(
req,
res,
500,
'Internal Server Error',
'Failed to read request body',
parsedUrl.pathname,
trace
)
}That way we don’t leave the response open if reading the body fails.
| clearTimeout(timeoutId) | ||
| } | ||
| req.removeListener?.('data', onData) | ||
| req.removeListener?.('end', onEnd as unknown as (chunk: Buffer) => void) |
There was a problem hiding this comment.
I think we could avoid these as unknown as (chunk: Buffer) => void casts here.
They seem to be needed because ApiRequest in api.types.ts:87-92 currently restricts the listener signature to (chunk: Buffer) => void.
Instead of having to force the type with casts every time, it might be cleaner to make the type definition more generic:
on?: (event: string, listener: (...args: any[]) => void) => void
removeListener?: (event: string, listener: (...args: any[]) => void) => voidThat way we can remove all these as unknown as ... casts and keep the call sites cleaner.
|
|
||
| req.on('data', onData) | ||
| req.on('end', onEnd) | ||
| req.on('end', onEnd as unknown as (chunk: Buffer) => void) |
There was a problem hiding this comment.
Same thing here on lines 600-601 — I think we can avoid these as unknown as ... casts by making the ApiRequest listener types more generic as mentioned above.
2b0f208 to
f61237d
Compare
Changes
src/managers/rateLimitManager.ts): Made the cleanup loop scope-aware so each rate-limit key is pruned based on its own configured time window (global, IP, guild, user) instead of purging all keys against the shortest window.src/managers/sourceWorkerManager.ts):indexOf === -1guard when handling worker exit events so unknown/already removed workers do not accidentally evict active workers from the pool.!res.headersSentcheck before sending 504 on timeouts to avoidERR_HTTP_HEADERS_SENTcrashes when streaming has already begun.src/api/index.ts):Buffer.concat) for incoming chunks.src/sources/local.ts):basePathboundaries on both relative and absolute paths, preventing path traversal outside the configured directory.loadStream.src/typings/api/api.types.ts): AddedheadersSenttoApiResponseandbodyTimeoutto server options.Why
ERR_HTTP_HEADERS_SENT) during worker timeouts on active streams.Checkmarks
Additional information
npm run type-check(0 errors) and Biome check/format (0 errors).