Skip to content

Report Android and Apple response-body failures as transport errors - #38

Open
bkaradzic-microsoft wants to merge 2 commits into
BabylonJS:mainfrom
bkaradzic-microsoft:fix-android-response-read-failure
Open

bkaradzic-microsoft wants to merge 2 commits into
BabylonJS:mainfrom
bkaradzic-microsoft:fix-android-response-read-failure

Conversation

@bkaradzic-microsoft

@bkaradzic-microsoft bkaradzic-microsoft commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

Problem

Companion to BabylonJS/JsRuntimeHost#221, addressing the Android response-read review.

Android published the HTTP status before reading the body. A failed read could therefore retain status 200 and make XHR dispatch load. The pinned InputStream::Read wrapper also leaves Java exceptions pending: the next ByteArrayOutputStream::Write JNI call aborts under CheckJNI when a response is truncated.

Changes

  • Check and clear pending Java exceptions immediately after reads and response-body conversions.
  • Publish HTTP status only after the response is completely read; reject premature EOF for known-length bodies, excluding bodyless 204/304 responses.
  • Clear partial response state and record normalized JavaException / ResponseReadFailed transport diagnostics.
  • Read completed HTTP error responses via getErrorStream(), so a completed 404 remains a successful transfer with HTTP status 404.

Validation

Exercised through the native XHR regression tests added in BabylonJS/JsRuntimeHost#221 on an Android API 36.1 x86_64 emulator, QuickJS, NDK 29:

  • CompletedAndTruncatedHttpBodies: complete and truncated 200/404 responses from a loopback server.
  • AbortResponseReadsWhileBodyIsStreaming: text and arraybuffer getters during synchronous abort.
  • Android suite: 250 JavaScript tests passing; 25 native tests passing, one existing logger test skipped.

The truncated-response test crashes with the original pinned UrlLib under CheckJNI and passes with this change. UrlLib's existing Windows suite also passes (9 passed, 6 platform-specific skips).

Apple follow-up

PR #221's macOS jobs exposed a second backend issue: NSURLSession completes a truncated 404 body without an NSError. Commit 85e8f02 validates fixed-length, identity-encoded HTTP bodies before publishing status or data, returning urllib:ResponseReadFailed(0) on premature EOF.

The check deliberately excludes gzip/other content encodings, chunked transfer encoding, and bodyless 204/304 responses: decoded NSData length is not generally the wire Content-Length.

Native UrlLib loopback regressions now cover complete/truncated 200 and 404 bodies in both response modes, plus Apple gzip, chunked, empty, and bodyless response cases. The existing XHR regression remains unchanged. Linux transport regressions and the downstream XHR ThreadSanitizer run pass locally; Companion CI is green on this commit: 18 macOS tests passed, including both new regressions; Linux and Windows jobs also passed.

Check pending JNI exceptions immediately after reading or copying a response
body, clear partial responses on failure, and publish status only after a
complete read. Preserve completed HTTP error responses via getErrorStream.
Document the Android transport-error diagnostics.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
bkaradzic-microsoft pushed a commit to bkaradzic-microsoft/JsRuntimeHost that referenced this pull request Oct 5, 2026
Prepare replacement requests before invalidating active sends and preserve
responseType. Detach canceled transport state before synchronous callbacks
and guard response access while the transport is active.

Keep callbacks in a JavaScript WeakMap keyed by their XHR, with stable native
listener records and short-lived persistent invocation references. Retain
non-callable handler objects by identity without invoking them.

Pin the Android response-read fix from BabylonJS/UrlLib#38. Add reuse,
failed-open, object-identity, self-capturing GC, streaming-abort, and truncated
HTTP response regressions, and update the polyfill documentation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bkaradzic-microsoft
bkaradzic-microsoft requested a balanced review from Copilot October 6, 2026 01:11

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot review overview

🟢 Approval recommended

The implementation matches the stated behavior and safely clears partial response state on failures.

Review effort: Balanced
Findings: None

What changed in this PR

Defers Android HTTP success reporting until response bodies are fully read and surfaces read failures as transport diagnostics.

Changes:

  • Handles JNI exceptions and truncated known-length responses.
  • Uses error streams for completed HTTP error responses.
  • Documents Android transport-error behavior.
File Description
Source/​UrlRequest_Android.cpp Adds robust response reading and error reporting.
README.md Documents Android response and diagnostic semantics.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

NSURLSession can complete a truncated 404 response without an NSError.
Validate unencoded fixed-length bodies before publishing status, headers,
or data and report ResponseReadFailed on premature EOF.

Keep compressed, chunked, and bodyless responses out of that comparison.
Add loopback regressions covering string/buffer 200 and 404 responses,
gzip, chunked transfer, empty bodies, and 204/304 status semantics.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 2b2272ba-79f8-41d0-aae1-f514a0f712ad
@bkaradzic-microsoft bkaradzic-microsoft changed the title Android: report response-body read failures as transport errors Report Android and Apple response-body failures as transport errors Oct 6, 2026
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.

3 participants