diff options
-rw-r--r-- | src/bun.js/bindings/bindings.zig | 6 | ||||
-rw-r--r-- | src/bun.js/webcore/response.zig | 74 |
2 files changed, 50 insertions, 30 deletions
diff --git a/src/bun.js/bindings/bindings.zig b/src/bun.js/bindings/bindings.zig index 3b933f976..f20a65243 100644 --- a/src/bun.js/bindings/bindings.zig +++ b/src/bun.js/bindings/bindings.zig @@ -103,6 +103,12 @@ pub const ZigString = extern struct { return this; } + extern fn ZigString__toJSONObject(this: *const ZigString, *JSC.JSGlobalObject) callconv(.C) JSC.JSValue; + pub fn toJSONObject(this: ZigString, globalThis: *JSC.JSGlobalObject) JSValue { + JSC.markBinding(@src()); + return ZigString__toJSONObject(&this, globalThis); + } + pub fn substring(this: ZigString, offset: usize) ZigString { if (this.is16Bit()) { return ZigString.from16Slice(this.utf16SliceAligned()[@minimum(this.len, offset)..]); diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index fabaffbad..e3a1bbdfd 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -1703,9 +1703,7 @@ pub const Blob = struct { pub fn findOrCreateFileFromPath(path_: JSC.Node.PathOrFileDescriptor, globalThis: *JSGlobalObject) Blob { var vm = globalThis.bunVM(); - } - - var allocator = globalThis.bunVM().allocator; + const allocator = vm.allocator; const path: JSC.Node.PathOrFileDescriptor = brk: { switch (path_) { @@ -1766,6 +1764,7 @@ pub const Blob = struct { }; pub fn ref(this: *Store) void { + std.debug.assert(this.ref_count > 0); this.ref_count += 1; } @@ -1778,23 +1777,25 @@ pub const Blob = struct { pub fn initFile(pathlike: JSC.Node.PathOrFileDescriptor, mime_type: ?HTTPClient.MimeType, allocator: std.mem.Allocator) !*Store { var store = try allocator.create(Blob.Store); store.* = .{ - .data = .{ .file = FileStore.init( - pathlike, - mime_type orelse brk: { - if (pathlike == .path) { - const sliced = pathlike.path.slice(); - if (sliced.len > 0) { - var extname = std.fs.path.extension(sliced); - extname = std.mem.trim(u8, extname, "."); - if (HTTPClient.MimeType.byExtensionNoDefault(extname)) |mime| { - break :brk mime; + .data = .{ + .file = FileStore.init( + pathlike, + mime_type orelse brk: { + if (pathlike == .path) { + const sliced = pathlike.path.slice(); + if (sliced.len > 0) { + var extname = std.fs.path.extension(sliced); + extname = std.mem.trim(u8, extname, "."); + if (HTTPClient.MimeType.byExtensionNoDefault(extname)) |mime| { + break :brk mime; + } } } - } - break :brk null; - }, - ) }, + break :brk null; + }, + ), + }, .allocator = allocator, .ref_count = 1, }; @@ -1819,6 +1820,7 @@ pub const Blob = struct { } pub fn deref(this: *Blob.Store) void { + std.debug.assert(this.ref_count >= 1); this.ref_count -= 1; if (this.ref_count == 0) { this.deinit(); @@ -1833,7 +1835,6 @@ pub const Blob = struct { bytes.deinit(); }, .file => |file| { - VirtualMachine.vm.removeFileBlob(file.pathlike); if (file.pathlike == .path) { allocator.free(bun.constStrToU8(file.pathlike.path.slice())); } @@ -3480,8 +3481,14 @@ pub const Blob = struct { const bytes = result.buf; if (blob.size > 0) blob.size = @minimum(@truncate(u32, bytes.len), blob.size); - // these are now temporaries - promise.resolve(globalThis, Function(&blob, globalThis, bytes, .temporary)); + const value = Function(&blob, globalThis, bytes, .temporary); + + // invalid JSON needs to be rejected + if (value.isAnyError(globalThis)) { + promise.reject(globalThis, value); + } else { + promise.resolve(globalThis, value); + } }, .err => |err| { promise.reject(globalThis, err.toErrorInstance(globalThis)); @@ -3653,23 +3660,23 @@ pub const Blob = struct { defer if (comptime lifetime == .temporary) bun.default_allocator.free(bun.constStrToU8(buf)); if (could_be_all_ascii == null or !could_be_all_ascii.?) { + var stack_fallback = std.heap.stackFallback(4096, bun.default_allocator); + const allocator = stack_fallback.get(); // if toUTF16Alloc returns null, it means there are no non-ASCII characters - if (strings.toUTF16Alloc(bun.default_allocator, buf, false) catch null) |external| { + if (strings.toUTF16Alloc(allocator, buf, false) catch null) |external| { if (comptime lifetime != .temporary) this.setIsASCIIFlag(false); - return ZigString.toExternalU16(external.ptr, external.len, global).parseJSON(global); + const result = ZigString.init16(external).toJSONObject(global); + allocator.free(external); + return result; } if (comptime lifetime != .temporary) this.setIsASCIIFlag(true); } if (comptime lifetime == .temporary) { - return ZigString.init(buf).toExternalValue( - global, - ).parseJSON(global); + return ZigString.init(buf).toJSONObject(global); } else { - return ZigString.init(buf).toValue( - global, - ).parseJSON(global); + return ZigString.init(buf).toJSONObject(global); } } @@ -4010,14 +4017,14 @@ pub const AnyBlob = union(enum) { return JSValue.jsNull(); } - var str = this.InternalBlob.toStringOwned(global); + const str = this.InternalBlob.toJSON(global); // the GC will collect the string this.* = .{ .Blob = .{}, }; - return str.parseJSON(global); + return str; }, } } @@ -4175,6 +4182,13 @@ pub const InternalBlob = struct { } } + pub fn toJSON(this: *@This(), globalThis: *JSC.JSGlobalObject) JSValue { + const str_bytes = ZigString.init(this.bytes.items).withEncoding(); + const json = str_bytes.toJSONObject(globalThis); + this.deinit(); + return json; + } + pub inline fn sliceConst(this: *const @This()) []const u8 { return this.bytes.items; } |