fix: buffer multi-segment HTTP POST/PUT bodies in fetch network adapter#1567
fix: buffer multi-segment HTTP POST/PUT bodies in fetch network adapter#1567muralidhar-challa wants to merge 3 commits into
Conversation
When a POST or PUT request body spans multiple TCP segments (~1460 bytes each), only the first segment's body bytes were used — subsequent segments were silently dropped because this.read was cleared after the first \r\n\r\n delimiter match, and no more headers trigger re-processing. This caused "Invalid JSON" errors for any request body larger than approximately one MTU. Fix: - On the first segment: if Content-Length is present and the body is incomplete, store the partial body in this._xb with a deferred callback instead of firing fetch() immediately. - On subsequent segments: accumulate incoming data into this._xb.buf. Once Content-Length is satisfied, decode and invoke the deferred fetch. - Extract the fetch+response handling into _dispatch_fetch() to avoid duplicating it in both the normal and deferred code paths.
|
Could I get a review from one of @basicer @chschnell, @SuperMaxusa or @ProgrammerIn-wonderland |
|
This seems like it'd break for binary post data but I'm unsure if that ever worked, want to see @basicer's review tbh |
| const content_length = parseInt(req_headers.get("content-length") || "0", 10); | ||
| const body_bytes = (data instanceof Uint8Array) ? data : new TextEncoder().encode(data); | ||
| if(content_length > 0 && body_bytes.length < content_length) { | ||
| const fetch_url = this.net.cors_proxy ? this.net.cors_proxy + encodeURIComponent(target.href) : target.href; |
|
To be precise:
That's fine for common HTTP One strategy to solve this would be to buffer the request's entire body before calling We can pass a EDIT: The specification states: In any case, in order to detect that we have processed the body's last chunk we need to evaluate the request's I skimmed through the PR, my suggestions:
While at it, if you don't mind please refactor all the |
IIRC this also requires
I would suggest using here |
Addresses reviewer feedback on PR copy#1567: - Buffer incoming TCP data as raw bytes (Uint8Array) instead of text-decoding everything. Search for \r\n\r\n in binary, text-decode only the header portion. This prevents corruption of binary POST bodies and ensures the first \r\n\r\n in headers (not in body) is used as the separator. - Replace ad-hoc new TextEncoder()/new TextDecoder() with module-scoped singletons (textEncoder, textDecoder). - Refactor _dispatch_fetch into a standalone dispatch_fetch(conn, ...) helper that takes the connection explicitly, avoiding incorrect binding between the connection and adapter objects. - Add comment noting that Transfer-Encoding: chunked is unsupported. - Add unit tests (tests/devices/fetch_network_post.js): * Small POST body in one segment * Large POST body split across 3 segments * Binary body containing embedded CRLFCRLF bytes * GET request (no body) * Headers split across 2 segments
|
Thanks all for the review. I've updated the PR to address the feedback:
Added 5 unit tests in
|
|
While reading the code I had an idea that would improve overall readability of Currently, we have a function I suggest to change the event binding of the function from to and change the prototypes to That is, turn these functions into methods and pass the TCPConnection object
A bit of care needs to be taken when refactoring the two methods, but it looks a lot clearer (in my editior). |
Ah, I see that, sorry. I thought it would be safer to use
Can you add these tests to |
Add a POST handler to the test server that echoes the received body length, and a test case that POSTs 3000 bytes (> ~1460 byte MTU) from the buildroot guest via curl + dd. Verifies the full body reaches the server after the binary-safe buffering fix.
|
@chschnell — good suggestion on moving @SuperMaxusa — agreed on |
When a POST or PUT request body spans multiple TCP segments (~1460 bytes each), only the first segment's body bytes were used — subsequent segments were silently dropped because
this.readwas cleared after the first\r\n\r\ndelimiter match, and no more headers trigger re-processing.This caused "Invalid JSON" errors for any request body larger than approximately one MTU.
Fix:
this._xbwith a deferred callback instead of firingfetch()immediately.this._xb.buf. Once Content-Length is satisfied, decode and invoke the deferred fetch._dispatch_fetch()to avoid duplicating it in both the normal and deferred code paths.