fix(server): bound search and image response bodies - #1346
Conversation
|
✅ Deterministic PR hygiene checks passed. |
📝 WalkthroughWalkthroughThe PR adds bounded raw-byte response reading and uses it in search and image relays. The relays preserve binary data, enforce response limits, propagate timeouts and client aborts, and cancel upstream streams during cleanup. ChangesBounded response relay handling
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
✅ READY
Review readiness checklist
✅ 4/4 boxes ticked. This pull request is already Ready for Review. |
|
@coderabbitai review |
✅ Action performedReview finished.
|
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/bounded-body.ts`:
- Around line 145-148: Update the public contract documentation near the
bounded-body result, including the description of bytes, to state that bytes is
an exact-length view into internal storage and consumers must use its byteOffset
and byteLength rather than the underlying buffer; preserve the existing
zero-copy subarray return in the completion path.
In `@src/server/search.ts`:
- Around line 159-166: Update the oversized branch in the search response
handling flow to call upstream.recordOutcome with upstreamResponse.status before
returning formatErrorResponse. Preserve the existing status value as the
outcome, matching the success path and recordOutcome contract; do not introduce
a separate marker.
- Around line 171-175: Update the search handler around the upstream fetch and
catch flow to retain the response in a scope visible to its finally block,
preserving the existing req.signal.aborted-first 499/504 ordering. In the
finally cleanup, unconditionally cancel the retained upstream response body when
present, swallowing any rejection, alongside the existing sidecarExit() and
linkedSignal.cleanup() calls; keep normal reader cleanup behavior unchanged.
In `@tests/bounded-body.test.ts`:
- Around line 418-434: Strengthen the “raw byte cancellation rejection is
observed” test by adding a deliberately unhandled rejection through the same
process unhandledRejection listener and wait interval, then assert the listener
records that positive-control rejection before asserting the stream cancellation
path leaves unhandled empty. Keep the existing cleanup and cancellation
regression coverage intact, and verify the control works under the pinned test
runtime.
In `@tests/server-search.test.ts`:
- Around line 485-497: Export the existing SEARCH_RESPONSE_MAX_BYTES constant
from the production search module, then import and use it in the oversized
streaming response test instead of hardcoding 16 * 1024 * 1024. Build the test
chunks so the first fills the cap exactly and the next byte exceeds it, and
update the tail guard to check the chunk length before its byte value, matching
the bounded-body test pattern.
🪄 Autofix
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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: b042aea4-4b01-4138-8210-44d7250e4b4c
📒 Files selected for processing (4)
src/lib/bounded-body.tssrc/server/search.tstests/bounded-body.test.tstests/server-search.test.ts
|
@coderabbitai review |
✅ Action performedReview finished.
|
54acece to
962bb2a
Compare
962bb2a to
114c949
Compare
|
Please rebase this PR onto the latest |
114c949 to
623c4eb
Compare
|
✅ Action performedReview finished.
|
Rate Limit Exceeded
|
Rate Limit Exceeded
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/server/images.ts`:
- Around line 88-97: In the response-body handling flow, after the abort check
and before reading or validating Content-Length, return empty bytes with
oversized set to false when response.body is null. Preserve the existing
size-limit cancellation for responses with a body, and add a regression test
covering a bodyless 304 with a Content-Length above the cap.
In `@tests/server-images.test.ts`:
- Around line 852-853: Remove the duplicate standalone response-body assertions
at tests/server-images.test.ts lines 852-853 and 886-887. Keep the first
response.json() assertion in each test and delete only the subsequent duplicate
reads so each response body is consumed once.
🪄 Autofix
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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 9e1523ee-e484-46b8-8e41-658c380b73ef
📒 Files selected for processing (2)
src/server/images.tstests/server-images.test.ts
|
Thanks @luvs01 — this is a strong reliability/security hardening pass. The bounded raw-byte reader, timeout/abort handling, upstream cancellation, and regression coverage all landed cleanly. Merged! 🙏 |
Summary
.bufferoutside its view bounds.Both relays previously called
arrayBuffer()before enforcing their response limit. A large, stalled, or unbounded upstream body could therefore allocate beyond the intended cap or outlive the configured deadline.Verification
tests/bounded-body.test.ts+tests/server-search.test.ts— 45 passed, 0 failed.bun run typecheck— passed on the final source.bun run privacy:scan— passed on the final source.git diff --check— passed.bun run testwas attempted once. On Windows/currentdev, unrelated Codex user-identity/catalog/history tests failed before Bun 1.3.14 panicked after 1,123 seconds; the changed bounded-body/search/image tests did not fail. Exact-head GitHub CI is still required.Checklist
Review readiness checklist
This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:
All CI tests are green on my local testing.
I pushed my PR to the latest dev commit.
I resolved all correct Codex and CodeRabbit findings.
My PR is ready for review.
Summary by CodeRabbit