diff --git a/src/browser/tests/net/xhr.html b/src/browser/tests/net/xhr.html index 3698db699..0e0a7789f 100644 --- a/src/browser/tests/net/xhr.html +++ b/src/browser/tests/net/xhr.html @@ -642,3 +642,80 @@ handler runs, abort() cancels the re-send and no load is delivered. }); } + + + + + + diff --git a/src/browser/webapi/net/XMLHttpRequest.zig b/src/browser/webapi/net/XMLHttpRequest.zig index 4e7b06f7e..f27db7971 100644 --- a/src/browser/webapi/net/XMLHttpRequest.zig +++ b/src/browser/webapi/net/XMLHttpRequest.zig @@ -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| {