mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-08-03 03:13:05 -04:00
fix(net): convert js_value stream chunks for fetch POST bodies
JS controller.enqueue stores chunks as .js_value via enqueueValue, so collectBodyBytes must extract TypedArray/ArrayBuffer/string bytes with local scope and arena.dupe before buffering. Add multi-chunk success and open/locked reject fixtures in fetch.html.
This commit is contained in:
@@ -352,9 +352,11 @@
|
||||
{
|
||||
const state = await testing.async();
|
||||
const payload = "name=Streamed&count=9";
|
||||
const enc = new TextEncoder();
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue(new TextEncoder().encode(payload));
|
||||
controller.enqueue(enc.encode("name=Streamed&"));
|
||||
controller.enqueue(enc.encode("count=9"));
|
||||
controller.close();
|
||||
},
|
||||
});
|
||||
@@ -375,6 +377,44 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=fetch_readablestream_body_reject type=module>
|
||||
{
|
||||
const state = await testing.async();
|
||||
const url = "http://127.0.0.1:9582/xhr/echo_post_body";
|
||||
const opts = { method: "POST", duplex: "half" };
|
||||
|
||||
let openRejected = false;
|
||||
try {
|
||||
const open = new ReadableStream({
|
||||
start(c) { c.enqueue(new TextEncoder().encode("x")); },
|
||||
});
|
||||
await fetch(url, { ...opts, body: open });
|
||||
} catch (e) {
|
||||
openRejected = e instanceof TypeError;
|
||||
}
|
||||
|
||||
let lockedRejected = false;
|
||||
try {
|
||||
const locked = new ReadableStream({
|
||||
start(c) {
|
||||
c.enqueue(new TextEncoder().encode("x"));
|
||||
c.close();
|
||||
},
|
||||
});
|
||||
locked.getReader();
|
||||
await fetch(url, { ...opts, body: locked });
|
||||
} catch (e) {
|
||||
lockedRejected = e instanceof TypeError;
|
||||
}
|
||||
|
||||
state.resolve();
|
||||
await state.done(() => {
|
||||
testing.expectEqual(true, openRejected);
|
||||
testing.expectEqual(true, lockedRejected);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=fetch_blob_url_in_worker type=module>
|
||||
{
|
||||
const state = await testing.async();
|
||||
|
||||
@@ -141,13 +141,32 @@ pub fn collectBodyBytes(self: *ReadableStream, arena: std.mem.Allocator) ![]cons
|
||||
.closed => {},
|
||||
}
|
||||
|
||||
const exec = self._execution;
|
||||
if (exec.js.local == null) return error.TypeError;
|
||||
|
||||
var ls: js.Local.Scope = undefined;
|
||||
exec.js.localScope(&ls);
|
||||
defer ls.deinit();
|
||||
const local = &ls;
|
||||
|
||||
var buf = std.Io.Writer.Allocating.init(arena);
|
||||
const controller = self._controller;
|
||||
while (controller.dequeue()) |chunk| {
|
||||
const bytes = switch (chunk) {
|
||||
const bytes: []const u8 = switch (chunk) {
|
||||
.string => |s| s,
|
||||
.uint8array => |arr| arr.values,
|
||||
.js_value => return error.TypeError,
|
||||
.js_value => |global| blk: {
|
||||
const value = local.toLocal(global);
|
||||
if (value.isTypedArray() or value.isArrayBufferView() or value.isArrayBuffer()) {
|
||||
const typed = try local.jsValueToZig([]u8, value);
|
||||
break :blk try arena.dupe(u8, typed);
|
||||
} else if (value.isString()) |str| {
|
||||
const slice = try str.toSlice();
|
||||
break :blk try arena.dupe(u8, slice);
|
||||
} else {
|
||||
return error.TypeError;
|
||||
}
|
||||
},
|
||||
};
|
||||
try buf.writer.writeAll(bytes);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user