mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-09-19 02:53:07 -04:00
Merge pull request #3284 from lightpanda-io/xhr-blob
XHR Blob Response Type
This commit is contained in:
2 files changed
+105
-3
No files matched your search
@@ -642,3 +642,80 @@ handler runs, abort() cancels the re-send and no load is delivered.
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=xhr_blob type=module>
|
||||
{
|
||||
const state = await testing.async();
|
||||
const req = new XMLHttpRequest();
|
||||
req.onload = () => { state.resolve() };
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr/binary');
|
||||
req.responseType = 'blob';
|
||||
req.send();
|
||||
|
||||
await state.done(() => {
|
||||
testing.expectEqual(200, req.status);
|
||||
testing.expectEqual('blob', req.responseType);
|
||||
testing.expectEqual(true, req.response instanceof Blob);
|
||||
testing.expectEqual(7, req.response.size);
|
||||
// Per spec the blob response entity body is cached: the same object comes
|
||||
// back on every access.
|
||||
testing.expectEqual(req.response, req.response);
|
||||
// TODO: should be 'application/octet-stream'. Mime keeps a content-type
|
||||
// enum, not the header text, and Mime.contentTypeString() has no entry
|
||||
// for it, so the type is lost on the way to the Blob.
|
||||
testing.expectEqual('', req.response.type);
|
||||
});
|
||||
|
||||
testing.expectEqual([0, 0, 1, 2, 0, 0, 9], new Int8Array(await req.response.arrayBuffer()));
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=xhr_blob_reopen type=module>
|
||||
{
|
||||
// open() discards the cached response, dropping the XHR's reference to the
|
||||
// blob. A blob the script is still holding has to survive that: the cache
|
||||
// and the JS wrapper each own a reference. Release without a matching
|
||||
// acquire (or a double release) frees the arena out from under `first`.
|
||||
const state = await testing.async();
|
||||
const req = new XMLHttpRequest();
|
||||
req.onload = () => { state.resolve() };
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr/binary');
|
||||
req.responseType = 'blob';
|
||||
req.send();
|
||||
await state.done(() => testing.expectEqual(200, req.status));
|
||||
|
||||
const first = req.response;
|
||||
|
||||
const state2 = await testing.async();
|
||||
req.onload = () => { state2.resolve() };
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr/binary');
|
||||
req.send();
|
||||
await state2.done(() => {
|
||||
testing.expectEqual(true, req.response instanceof Blob);
|
||||
// the second request parses a fresh blob, not the discarded one
|
||||
testing.expectEqual(false, req.response === first);
|
||||
});
|
||||
|
||||
testing.expectEqual(7, first.size);
|
||||
testing.expectEqual([0, 0, 1, 2, 0, 0, 9], new Int8Array(await first.arrayBuffer()));
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id=xhr_json_reopen type=module>
|
||||
{
|
||||
// open() releases the persisted handle on the cached json response. That
|
||||
// handle is one v8 root, not ownership of the value, so a script holding
|
||||
// the parsed object must still be able to read it afterwards.
|
||||
const state = await testing.async();
|
||||
const req = new XMLHttpRequest();
|
||||
req.onload = () => { state.resolve() };
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr/json');
|
||||
req.responseType = 'json';
|
||||
req.send();
|
||||
await state.done(() => testing.expectEqual('9000!!!', req.response.over));
|
||||
|
||||
const first = req.response;
|
||||
req.open('GET', 'http://127.0.0.1:9582/xhr/json');
|
||||
testing.expectEqual('9000!!!', first.over);
|
||||
}
|
||||
</script>
|
||||
@@ -28,6 +28,7 @@ const Mime = @import("../../Mime.zig");
|
||||
const Page = @import("../../Page.zig");
|
||||
const Frame = @import("../../Frame.zig");
|
||||
|
||||
const Blob = @import("../Blob.zig");
|
||||
const Node = @import("../Node.zig");
|
||||
const Event = @import("../Event.zig");
|
||||
const EventTarget = @import("../EventTarget.zig");
|
||||
@@ -91,6 +92,7 @@ const Response = union(enum) {
|
||||
json: js.Value.Global,
|
||||
document: *Node.Document,
|
||||
arraybuffer: js.ArrayBuffer,
|
||||
blob: *Blob,
|
||||
};
|
||||
|
||||
const ResponseType = enum {
|
||||
@@ -99,6 +101,7 @@ const ResponseType = enum {
|
||||
json,
|
||||
document,
|
||||
arraybuffer,
|
||||
blob,
|
||||
|
||||
pub fn toString(self: ResponseType) []const u8 {
|
||||
return switch (self) {
|
||||
@@ -120,12 +123,25 @@ pub fn init(exec: *const Execution) !*XMLHttpRequest {
|
||||
return self;
|
||||
}
|
||||
|
||||
pub fn deinit(self: *XMLHttpRequest, _: *Page) void {
|
||||
fn clearResponse(self: *XMLHttpRequest, page: *Page) void {
|
||||
if (self._response) |res| {
|
||||
switch (res) {
|
||||
.blob => |b| b.releaseRef(page),
|
||||
.json => |js_val| js_val.release(),
|
||||
else => {},
|
||||
}
|
||||
self._response = null;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deinit(self: *XMLHttpRequest, page: *Page) void {
|
||||
if (self._http_transfer) |resp| {
|
||||
resp.abort(error.Abort);
|
||||
self._http_transfer = null;
|
||||
}
|
||||
|
||||
self.clearResponse(page);
|
||||
|
||||
if (self._on_ready_state_change) |func| {
|
||||
func.release();
|
||||
}
|
||||
@@ -208,7 +224,7 @@ pub fn open(self: *XMLHttpRequest, method_: []const u8, url: [:0]const u8, async
|
||||
|
||||
// Reset internal state. _override_mime intentionally survives open()
|
||||
// per https://xhr.spec.whatwg.org/#the-overridemimetype()-method.
|
||||
self._response = null;
|
||||
self.clearResponse(self._exec.page);
|
||||
self._response_xml = null;
|
||||
self._response_data.clearRetainingCapacity();
|
||||
self._response_status = 0;
|
||||
@@ -526,6 +542,13 @@ pub fn getResponse(self: *XMLHttpRequest, exec: *const Execution) !?Response {
|
||||
}
|
||||
},
|
||||
.arraybuffer => .{ .arraybuffer = .{ .values = data } },
|
||||
.blob => blk: {
|
||||
const mime = self._override_mime orelse self._response_mime;
|
||||
const content_type = if (mime) |m| m.contentTypeString() else "";
|
||||
const blob = try Blob.initFromBytes(data, content_type, exec);
|
||||
blob.acquireRef();
|
||||
break :blk .{ .blob = blob };
|
||||
},
|
||||
};
|
||||
|
||||
self._response = res;
|
||||
@@ -557,7 +580,9 @@ pub fn getResponseXML(self: *XMLHttpRequest, exec: *const Execution) !?*Node.Doc
|
||||
// With responseType "", only an XML final MIME type is parsed (an HTML
|
||||
// one yields null); absent a Content-Type it defaults to text/xml.
|
||||
const final: Mime = self._override_mime orelse self._response_mime orelse .{ .content_type = .text_xml };
|
||||
if (!final.isXML()) return null;
|
||||
if (!final.isXML()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
switch (exec.js.global) {
|
||||
.frame => |frame| {
|
||||
|
||||
Reference in new issue
Block a user