Skip to content

fix(android): cap interceptor body reads to prevent OOM on large responses#26

Merged
imsankalp merged 4 commits into
mainfrom
fix/interceptor-body-oom
Jul 26, 2026
Merged

fix(android): cap interceptor body reads to prevent OOM on large responses#26
imsankalp merged 4 commits into
mainfrom
fix/interceptor-body-oom

Conversation

@imsankalp

Copy link
Copy Markdown
Owner

Summary

Fixes #17

  • Android captureResponseBody: replaces source.request(Long.MAX_VALUE) + buffer.clone().readUtf8() with a bounded read (limit + 1 bytes to detect truncation without consuming it). Appends [... truncated] when the body exceeds the cap.
  • Android captureRequestBody: writes body to a temporary Buffer, then reads only min(size, limit) bytes. Appends truncation marker when needed.
  • Both methods skip binary content types (image/*, video/*, audio/*, application/octet-stream, application/zip, application/pdf, font/*) and return [binary content — not captured] instead of buffering bytes.
  • NetworkToolsManager.maxBodyCaptureBytes defaults to 256 KB and is publicly settable from app code.
  • iOS: promotes the static kNTMaxBodyBytes compile-time constant to a maxBodyCaptureBytes property on NetworkToolsManager, so it is now also configurable at runtime (iOS already had the cap logic; this makes it consistent with Android).
  • Adds setMaxBodyCaptureBytes(bytes) to the TurboModule spec (Android + iOS), the legacy bridge module, and the TypeScript exports.
  • NetworkMonitorProvider accepts a maxBodyCaptureBytes prop and forwards it to native via a useEffect.

Test plan

  • Make a request to an endpoint returning a large JSON payload (> 256 KB) — confirm body is captured up to 256 KB with [... truncated] marker
  • Make a request for an image URL — confirm responseBody is [binary content — not captured]
  • Set maxBodyCaptureBytes={512 * 1024} on NetworkMonitorProvider — confirm larger payloads are now captured up to 512 KB
  • Call setMaxBodyCaptureBytes(128 * 1024) directly — confirm cap takes effect on subsequent requests
  • Verify no regression on normal text/JSON responses under the cap

🤖 Generated with Claude Code

imsankalp and others added 4 commits July 27, 2026 01:45
Replaces `source.request(Long.MAX_VALUE)` with a bounded read so that
large response bodies (images, file downloads, big JSON payloads) no
longer duplicate the full payload in heap memory.

- `captureResponseBody`: request `limit + 1` bytes so truncation is
  detectable, append `[... truncated]` marker when body exceeds cap
- `captureRequestBody`: write body to a temporary buffer then read only
  `min(size, limit)` bytes, append truncation marker when needed
- Both methods bail early with `[binary content — not captured]` for
  image/, video/, audio/, octet-stream, zip, pdf, and font/* types
- `NetworkToolsManager.maxBodyCaptureBytes` default: 256 KB

Closes #17

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Android (TurboModule + legacy bridge) and iOS now implement
setMaxBodyCaptureBytes(bytes) so the capture limit can be changed at
runtime from JavaScript without a rebuild.

iOS: maxBodyCaptureBytes is promoted from a static compile-time constant
in NetworkToolsInterceptor to a property on the NetworkToolsManager
singleton, read dynamically via ntMaxBodyBytes().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Adds setMaxBodyCaptureBytes(bytes) to the TurboModule spec and the
  unavailable-module fallback
- NetworkMonitorProviderProps gains an optional maxBodyCaptureBytes field
- NetworkMonitorProvider calls the native method in a useEffect whenever
  the prop changes
- setMaxBodyCaptureBytes is exported as a named export and on the default
  object for callers that bypass the provider

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
macos-latest now maps to macOS 15 which ships Ruby 3.4. kconv was
removed from Ruby's stdlib in 3.4, causing CocoaPods 1.16.2 to crash
during pod install with "cannot load such file -- kconv".

Adds ruby/setup-ruby@v1 with ruby-version: '3.3' before the pod
install step, and delegates bundle install to setup-ruby via
bundler-cache: true (which also caches the gem bundle).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@imsankalp
imsankalp merged commit 6153952 into main Jul 26, 2026
7 checks passed
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.

bug(android): interceptor buffers full response body in memory — OOM risk for large responses

1 participant