From a7b46ebbfebcf66ed13e36d8af29f91c943ffa78 Mon Sep 17 00:00:00 2001 From: pfg Date: Wed, 14 May 2025 22:14:20 -0700 Subject: [PATCH] fastGet can throw (#19506) Co-authored-by: Meghan Denny Co-authored-by: Jarred Sumner --- src/bun.js/ConsoleObject.zig | 9 ++++--- src/bun.js/api/bun/h2_frame_parser.zig | 2 +- src/bun.js/api/bun/socket.zig | 6 ++--- src/bun.js/api/server.zig | 14 +++++------ src/bun.js/bindings/JSValue.zig | 29 +++++++---------------- src/bun.js/ipc.zig | 6 +++-- src/bun.js/node/node_fs.zig | 2 +- src/bun.js/node/node_fs_watcher.zig | 2 +- src/bun.js/test/expect.zig | 21 ++++++++-------- src/bun.js/test/pretty_format.zig | 8 +++---- src/bun.js/webcore/Body.zig | 6 ++--- src/bun.js/webcore/Request.zig | 20 ++++++++-------- src/bun.js/webcore/Response.zig | 16 ++++++------- src/bun.js/webcore/TextDecoder.zig | 2 +- src/bun.js/webcore/fetch.zig | 14 +++++------ src/bun.js/webcore/streams.zig | 10 ++++---- src/js_ast.zig | 4 ++-- src/shell/shell.zig | 2 +- test/internal/ban-words.test.ts | 2 +- test/js/web/encoding/text-decoder.test.js | 10 ++++++++ 20 files changed, 93 insertions(+), 92 deletions(-) diff --git a/src/bun.js/ConsoleObject.zig b/src/bun.js/ConsoleObject.zig index 0a180a807d..b3156ce3d9 100644 --- a/src/bun.js/ConsoleObject.zig +++ b/src/bun.js/ConsoleObject.zig @@ -1237,7 +1237,7 @@ pub const Formatter = struct { if (js_type.canGet() and js_type != .ProxyObject and !opts.disable_inspect_custom) { // Attempt to get custom formatter - if (value.fastGet(globalThis, .inspectCustom)) |callback_value| { + if (value.fastGet(globalThis, .inspectCustom) catch return .{ .tag = .RevokedProxy }) |callback_value| { if (callback_value.isCallable()) { return .{ .tag = .{ @@ -1250,7 +1250,6 @@ pub const Formatter = struct { }; } } - if (globalThis.hasException()) return .{ .tag = .RevokedProxy }; } if (js_type == .DOMWrapper) { @@ -2939,7 +2938,7 @@ pub const Formatter = struct { }, } - if (value.fastGet(this.globalThis, .message)) |message_value| { + if (try value.fastGet(this.globalThis, .message)) |message_value| { if (message_value.isString()) { if (!this.single_line) { this.writeIndent(Writer, writer_) catch unreachable; @@ -2973,7 +2972,7 @@ pub const Formatter = struct { comptime Output.prettyFmt("data: ", enable_ansi_colors), .{}, ); - const data = value.fastGet(this.globalThis, .data) orelse JSValue.undefined; + const data = (try value.fastGet(this.globalThis, .data)) orelse JSValue.undefined; const tag = Tag.getAdvanced(data, this.globalThis, .{ .hide_global = true, .disable_inspect_custom = this.disable_inspect_custom, @@ -2986,7 +2985,7 @@ pub const Formatter = struct { } }, .ErrorEvent => { - if (value.fastGet(this.globalThis, .@"error")) |error_value| { + if (try value.fastGet(this.globalThis, .@"error")) |error_value| { if (!this.single_line) { this.writeIndent(Writer, writer_) catch unreachable; } diff --git a/src/bun.js/api/bun/h2_frame_parser.zig b/src/bun.js/api/bun/h2_frame_parser.zig index ea48c7d695..a81f3da9aa 100644 --- a/src/bun.js/api/bun/h2_frame_parser.zig +++ b/src/bun.js/api/bun/h2_frame_parser.zig @@ -598,7 +598,7 @@ const Handlers = struct { } } - if (opts.fastGet(globalObject, .@"error")) |callback_value| { + if (try opts.fastGet(globalObject, .@"error")) |callback_value| { if (!callback_value.isCell() or !callback_value.isCallable()) { return globalObject.throwInvalidArguments("Expected \"error\" callback to be a function", .{}); } diff --git a/src/bun.js/api/bun/socket.zig b/src/bun.js/api/bun/socket.zig index 95c5b1d9ef..8f2003ee4a 100644 --- a/src/bun.js/api/bun/socket.zig +++ b/src/bun.js/api/bun/socket.zig @@ -460,7 +460,7 @@ pub const SocketConfig = struct { var handlers = try Handlers.fromJS(globalObject, try opts.get(globalObject, "socket") orelse JSValue.zero, is_server); - if (opts.fastGet(globalObject, .data)) |default_data_value| { + if (try opts.fastGet(globalObject, .data)) |default_data_value| { default_data = default_data_value; } @@ -3383,7 +3383,7 @@ fn NewSocket(comptime ssl: bool) type { } var default_data = JSValue.zero; - if (opts.fastGet(globalObject, .data)) |default_data_value| { + if (try opts.fastGet(globalObject, .data)) |default_data_value| { default_data = default_data_value; default_data.ensureStillAlive(); } @@ -4227,7 +4227,7 @@ pub fn jsUpgradeDuplexToTLS(globalObject: *JSC.JSGlobalObject, callframe: *JSC.C } var default_data = JSValue.zero; - if (opts.fastGet(globalObject, .data)) |default_data_value| { + if (try opts.fastGet(globalObject, .data)) |default_data_value| { default_data = default_data_value; default_data.ensureStillAlive(); } diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 0226a083bf..da92cfc511 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -5427,7 +5427,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d return globalThis.throwInvalidArguments("upgrade options must be an object", .{}); } - if (opts.fastGet(globalThis, .data)) |headers_value| { + if (try opts.fastGet(globalThis, .data)) |headers_value| { data_value = headers_value; } @@ -5435,7 +5435,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d return error.JSError; } - if (opts.fastGet(globalThis, .headers)) |headers_value| { + if (try opts.fastGet(globalThis, .headers)) |headers_value| { if (headers_value.isEmptyOrUndefinedOrNull()) { break :getter; } @@ -5555,7 +5555,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d return globalThis.throwInvalidArguments("upgrade options must be an object", .{}); } - if (opts.fastGet(globalThis, .data)) |headers_value| { + if (try opts.fastGet(globalThis, .data)) |headers_value| { data_value = headers_value; } @@ -5563,7 +5563,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d return error.JSError; } - if (opts.fastGet(globalThis, .headers)) |headers_value| { + if (try opts.fastGet(globalThis, .headers)) |headers_value| { if (headers_value.isEmptyOrUndefinedOrNull()) { break :getter; } @@ -5823,13 +5823,13 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d if (arguments.len >= 2 and arguments[1].isObject()) { var opts = arguments[1]; - if (opts.fastGet(ctx, .method)) |method_| { + if (try opts.fastGet(ctx, .method)) |method_| { var slice_ = try method_.toSlice(ctx, bun.default_allocator); defer slice_.deinit(); method = HTTP.Method.which(slice_.slice()) orelse method; } - if (opts.fastGet(ctx, .headers)) |headers_| { + if (try opts.fastGet(ctx, .headers)) |headers_| { if (headers_.as(WebCore.FetchHeaders)) |headers__| { headers = headers__; } else if (WebCore.FetchHeaders.createFromJS(ctx, headers_)) |headers__| { @@ -5837,7 +5837,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d } } - if (opts.fastGet(ctx, .body)) |body__| { + if (try opts.fastGet(ctx, .body)) |body__| { if (Blob.get(ctx, body__, true, false)) |new_blob| { body = .{ .Blob = new_blob }; } else |_| { diff --git a/src/bun.js/bindings/JSValue.zig b/src/bun.js/bindings/JSValue.zig index ed9f6b8fa7..ac6bb53818 100644 --- a/src/bun.js/bindings/JSValue.zig +++ b/src/bun.js/bindings/JSValue.zig @@ -1709,7 +1709,7 @@ pub const JSValue = enum(i64) { }; pub fn fastGetOrElse(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName, alternate: ?JSC.JSValue) ?JSValue { - return this.fastGet(global, builtin_name) orelse { + return (try this.fastGet(global, builtin_name)) orelse { if (alternate) |alt| return alt.fastGet(global, builtin_name); return null; @@ -1718,24 +1718,13 @@ pub const JSValue = enum(i64) { // `this` must be known to be an object // intended to be more lightweight than ZigString. - pub fn fastGet(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) ?JSValue { - if (bun.Environment.isDebug) - bun.assert(this.isObject()); - - return switch (JSC__JSValue__fastGet(this, global, @intFromEnum(builtin_name))) { - .zero, .undefined, .property_does_not_exist_on_object => null, - else => |val| val, - }; - } - - pub fn fastGetWithError(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) JSError!?JSValue { + pub fn fastGet(this: JSValue, global: *JSGlobalObject, builtin_name: BuiltinName) JSError!?JSValue { if (bun.Environment.isDebug) bun.assert(this.isObject()); return switch (JSC__JSValue__fastGet(this, global, @intFromEnum(builtin_name))) { .zero => error.JSError, - .undefined => null, - .property_does_not_exist_on_object => null, + .undefined, .property_does_not_exist_on_object => null, else => |val| val, }; } @@ -1841,7 +1830,7 @@ pub const JSValue = enum(i64) { // This call requires `get` to be `inline` if (bun.isComptimeKnown(property_slice)) { if (comptime BuiltinName.get(property_slice)) |builtin_name| { - return target.fastGetWithError(global, builtin_name); + return target.fastGet(global, builtin_name); } } @@ -1883,11 +1872,11 @@ pub const JSValue = enum(i64) { return null; } - /// Safe to use on any JSValue - pub fn implementsToString(this: JSValue, global: *JSGlobalObject) bool { + /// Safe to use on any JSValue, can error. + pub fn implementsToString(this: JSValue, global: *JSGlobalObject) bun.JSError!bool { if (!this.isObject()) return false; - const function = this.fastGet(global, BuiltinName.toString) orelse + const function = (try this.fastGet(global, BuiltinName.toString)) orelse return false; return function.isCell() and function.isCallable(); } @@ -1927,7 +1916,7 @@ pub const JSValue = enum(i64) { // TODO: replace calls to this function with `getOptional` pub fn getTruthyComptime(this: JSValue, global: *JSGlobalObject, comptime property: []const u8) bun.JSError!?JSValue { if (comptime BuiltinName.has(property)) { - return truthyPropertyValue(fastGet(this, global, @field(BuiltinName, property)) orelse return null); + return truthyPropertyValue(try fastGet(this, global, @field(BuiltinName, property)) orelse return null); } return getTruthy(this, global, property); @@ -2016,7 +2005,7 @@ pub const JSValue = enum(i64) { pub fn getOptionalEnum(this: JSValue, globalThis: *JSGlobalObject, comptime property_name: []const u8, comptime Enum: type) JSError!?Enum { if (comptime BuiltinName.has(property_name)) { - if (fastGet(this, globalThis, @field(BuiltinName, property_name))) |prop| { + if (try fastGet(this, globalThis, @field(BuiltinName, property_name))) |prop| { if (prop.isEmptyOrUndefinedOrNull()) return null; return try toEnum(prop, globalThis, property_name, Enum); diff --git a/src/bun.js/ipc.zig b/src/bun.js/ipc.zig index b8d395466f..d463307082 100644 --- a/src/bun.js/ipc.zig +++ b/src/bun.js/ipc.zig @@ -1056,8 +1056,10 @@ fn handleIPCMessage(send_queue: *SendQueue, message: DecodedIPCMessage, globalTh if (message == .data) handle_message: { const msg_data = message.data; if (msg_data.isObject()) { - const cmd = msg_data.fastGet(globalThis, .cmd) orelse { - if (globalThis.hasException()) _ = globalThis.takeException(bun.JSError.JSError); + const cmd = msg_data.fastGet(globalThis, .cmd) catch { + globalThis.clearException(); + break :handle_message; + } orelse { break :handle_message; }; if (cmd.isString()) { diff --git a/src/bun.js/node/node_fs.zig b/src/bun.js/node/node_fs.zig index 1fa1bd7b51..340cbd3cf2 100644 --- a/src/bun.js/node/node_fs.zig +++ b/src/bun.js/node/node_fs.zig @@ -1986,7 +1986,7 @@ pub const Arguments = struct { }; fn getEncoding(object: JSC.JSValue, globalObject: *JSC.JSGlobalObject, default: Encoding) bun.JSError!Encoding { - if (object.fastGet(globalObject, .encoding)) |value| { + if (try object.fastGet(globalObject, .encoding)) |value| { return Encoding.assert(value, globalObject, default); } diff --git a/src/bun.js/node/node_fs_watcher.zig b/src/bun.js/node/node_fs_watcher.zig index 618efcb055..4e1c4bcf9f 100644 --- a/src/bun.js/node/node_fs_watcher.zig +++ b/src/bun.js/node/node_fs_watcher.zig @@ -376,7 +376,7 @@ pub const FSWatcher = struct { verbose = verbose_.toBoolean(); } - if (options_or_callable.fastGet(ctx, .encoding)) |encoding_| { + if (try options_or_callable.fastGet(ctx, .encoding)) |encoding_| { encoding = try JSC.Node.Encoding.assert(encoding_, ctx, encoding); } diff --git a/src/bun.js/test/expect.zig b/src/bun.js/test/expect.zig index f2fba97e13..092857a7e3 100644 --- a/src/bun.js/test/expect.zig +++ b/src/bun.js/test/expect.zig @@ -366,7 +366,7 @@ pub const Expect = struct { var custom_label = bun.String.empty; if (arguments.len > 1) { - if (arguments[1].isString() or arguments[1].implementsToString(globalThis)) { + if (arguments[1].isString() or try arguments[1].implementsToString(globalThis)) { const label = try arguments[1].toBunString(globalThis); if (globalThis.hasException()) return .zero; custom_label = label; @@ -2248,7 +2248,7 @@ pub const Expect = struct { if (expected_value.isString()) { const received_message: JSValue = (if (result.isObject()) - result.fastGet(globalThis, .message) + try result.fastGet(globalThis, .message) else JSValue.fromCell(try result.toJSString(globalThis))) orelse .jsUndefined(); if (globalThis.hasException()) return .zero; @@ -2271,7 +2271,7 @@ pub const Expect = struct { if (expected_value.isRegExp()) { const received_message: JSValue = (if (result.isObject()) - result.fastGet(globalThis, .message) + try result.fastGet(globalThis, .message) else JSValue.fromCell(try result.toJSString(globalThis))) orelse .jsUndefined(); @@ -2288,9 +2288,9 @@ pub const Expect = struct { }); } - if (expected_value.fastGet(globalThis, .message)) |expected_message| { + if (try expected_value.fastGet(globalThis, .message)) |expected_message| { const received_message: JSValue = (if (result.isObject()) - result.fastGet(globalThis, .message) + try result.fastGet(globalThis, .message) else JSValue.fromCell(try result.toJSString(globalThis))) orelse .jsUndefined(); if (globalThis.hasException()) return .zero; @@ -2305,7 +2305,7 @@ pub const Expect = struct { var expected_class = ZigString.Empty; expected_value.getClassName(globalThis, &expected_class); - const received_message = result.fastGet(globalThis, .message) orelse .undefined; + const received_message = (try result.fastGet(globalThis, .message)) orelse .undefined; return this.throw(globalThis, signature, "\n\nExpected constructor: not {s}\n\nReceived message: {any}\n", .{ expected_class, received_message.toFmt(&formatter) }); } @@ -2318,7 +2318,8 @@ pub const Expect = struct { result_.?; const _received_message: ?JSValue = if (result.isObject()) - result.fastGet(globalThis, .message) + + try result.fastGet(globalThis, .message) else JSValue.fromCell(try result.toJSString(globalThis)); @@ -2399,7 +2400,7 @@ pub const Expect = struct { // If it's not an object, we are going to crash here. assert(expected_value.isObject()); - if (expected_value.fastGet(globalThis, .message)) |expected_message| { + if (try expected_value.fastGet(globalThis, .message)) |expected_message| { const signature = comptime getSignature("toThrow", "expected", false); if (_received_message) |received_message| { @@ -2477,7 +2478,7 @@ pub const Expect = struct { return this.throw(globalThis, signature, expected_fmt, .{ expected_value.toFmt(&formatter), result.toFmt(&formatter) }); } - if (expected_value.fastGet(globalThis, .message)) |expected_message| { + if (try expected_value.fastGet(globalThis, .message)) |expected_message| { const expected_fmt = "\n\nExpected message: {any}\n\n" ++ received_line; return this.throw(globalThis, signature, expected_fmt, .{ expected_message.toFmt(&formatter), result.toFmt(&formatter) }); } @@ -4823,7 +4824,7 @@ pub const Expect = struct { if (try result.get(globalThis, "pass")) |pass_value| { pass = pass_value.toBoolean(); - if (result.fastGet(globalThis, .message)) |message_value| { + if (try result.fastGet(globalThis, .message)) |message_value| { if (!message_value.isString() and !message_value.isCallable()) { break :valid false; } diff --git a/src/bun.js/test/pretty_format.zig b/src/bun.js/test/pretty_format.zig index 7ff69f5403..545a919e3b 100644 --- a/src/bun.js/test/pretty_format.zig +++ b/src/bun.js/test/pretty_format.zig @@ -1106,7 +1106,7 @@ pub const JestPrettyFormat = struct { var message_string = bun.String.empty; defer message_string.deref(); - if (value.fastGet(this.globalThis, .message)) |message_prop| { + if (try value.fastGet(this.globalThis, .message)) |message_prop| { message_string = try message_prop.toBunString(this.globalThis); } @@ -1459,7 +1459,7 @@ pub const JestPrettyFormat = struct { }, ); - if (value.fastGet(this.globalThis, .message)) |message_value| { + if (try value.fastGet(this.globalThis, .message)) |message_value| { if (message_value.isString()) { this.writeIndent(Writer, writer_) catch unreachable; writer.print( @@ -1480,7 +1480,7 @@ pub const JestPrettyFormat = struct { comptime Output.prettyFmt("data: ", enable_ansi_colors), .{}, ); - const data = value.fastGet(this.globalThis, .data) orelse JSValue.undefined; + const data = (try value.fastGet(this.globalThis, .data)) orelse JSValue.undefined; const tag = Tag.get(data, this.globalThis); if (tag.cell.isStringLike()) { @@ -1491,7 +1491,7 @@ pub const JestPrettyFormat = struct { writer.writeAll(", \n"); }, .ErrorEvent => { - if (value.fastGet(this.globalThis, .@"error")) |data| { + if (try value.fastGet(this.globalThis, .@"error")) |data| { this.writeIndent(Writer, writer_) catch unreachable; writer.print( comptime Output.prettyFmt("error: ", enable_ansi_colors), diff --git a/src/bun.js/webcore/Body.zig b/src/bun.js/webcore/Body.zig index 96031777af..2d78984811 100644 --- a/src/bun.js/webcore/Body.zig +++ b/src/bun.js/webcore/Body.zig @@ -1260,7 +1260,7 @@ pub fn Mixin(comptime Type: type) type { value.toBlobIfPossible(); } - var encoder = this.getFormDataEncoding() orelse { + var encoder = (try this.getFormDataEncoding()) orelse { // TODO: catch specific errors from getFormDataEncoding return globalObject.ERR(.FORMDATA_PARSE_ERROR, "Can't decode form data from body because of incorrect MIME type/boundary", .{}).reject(); }; @@ -1305,7 +1305,7 @@ pub fn Mixin(comptime Type: type) type { this: *Type, globalObject: *JSC.JSGlobalObject, this_value: JSValue, - ) JSC.JSValue { + ) bun.JSError!JSC.JSValue { var value: *Body.Value = this.getBodyValue(); if (value.* == .Used) { @@ -1357,7 +1357,7 @@ pub fn Mixin(comptime Type: type) type { pub fn getBlobWithoutCallFrame( this: *Type, globalObject: *JSC.JSGlobalObject, - ) JSC.JSValue { + ) bun.JSError!JSC.JSValue { return getBlobWithThisValue(this, globalObject, .zero); } }; diff --git a/src/bun.js/webcore/Request.zig b/src/bun.js/webcore/Request.zig index 6be9abcf89..e296282c31 100644 --- a/src/bun.js/webcore/Request.zig +++ b/src/bun.js/webcore/Request.zig @@ -118,7 +118,7 @@ pub fn init( pub fn getContentType( this: *Request, -) ?ZigString.Slice { +) bun.JSError!?ZigString.Slice { if (this.request_context.getRequest()) |req| { if (req.header("content-type")) |value| { return ZigString.Slice.fromUTF8NeverFree(value); @@ -139,11 +139,11 @@ pub fn getContentType( return null; } -pub fn getFormDataEncoding(this: *Request) ?*bun.FormData.AsyncFormData { - var content_type_slice: ZigString.Slice = this.getContentType() orelse return null; +pub fn getFormDataEncoding(this: *Request) bun.JSError!?*bun.FormData.AsyncFormData { + var content_type_slice: ZigString.Slice = (try this.getContentType()) orelse return null; defer content_type_slice.deinit(); const encoding = bun.FormData.Encoding.get(content_type_slice.slice()) orelse return null; - return bun.FormData.AsyncFormData.init(bun.default_allocator, encoding) catch unreachable; + return bun.FormData.AsyncFormData.init(bun.default_allocator, encoding); } pub fn estimatedSize(this: *Request) callconv(.C) usize { @@ -243,7 +243,7 @@ pub fn writeFormat(this: *Request, this_value: JSValue, comptime Formatter: type pub fn mimeType(this: *const Request) string { if (this._headers) |headers| { - if (headers.fastGet(.ContentType)) |content_type| { + if (try headers.fastGet(.ContentType)) |content_type| { return content_type.slice(); } } @@ -629,7 +629,7 @@ pub fn constructInto(globalThis: *JSC.JSGlobalObject, arguments: []const JSC.JSV } if (!fields.contains(.body)) { - if (value.fastGet(globalThis, .body)) |body_| { + if (try value.fastGet(globalThis, .body)) |body_| { fields.insert(.body); req.body.value = try Body.Value.fromJS(globalThis, body_); } @@ -638,14 +638,14 @@ pub fn constructInto(globalThis: *JSC.JSGlobalObject, arguments: []const JSC.JSV } if (!fields.contains(.url)) { - if (value.fastGet(globalThis, .url)) |url| { + if (try value.fastGet(globalThis, .url)) |url| { req.url = try bun.String.fromJS(url, globalThis); if (!req.url.isEmpty()) fields.insert(.url); // first value } else if (@intFromEnum(value) == @intFromEnum(values_to_try[values_to_try.len - 1]) and !is_first_argument_a_url and - value.implementsToString(globalThis)) + try value.implementsToString(globalThis)) { const str = try bun.String.fromJS(value, globalThis); req.url = str; @@ -677,7 +677,7 @@ pub fn constructInto(globalThis: *JSC.JSGlobalObject, arguments: []const JSC.JSV if (!fields.contains(.method) or !fields.contains(.headers)) { if (globalThis.hasException()) return error.JSError; if (try Response.Init.init(globalThis, value)) |response_init| { - if (!explicit_check or (explicit_check and value.fastGet(globalThis, .headers) != null)) { + if (!explicit_check or (explicit_check and (try value.fastGet(globalThis, .headers)) != null)) { if (response_init.headers) |headers| { if (!fields.contains(.headers)) { req._headers = headers; @@ -690,7 +690,7 @@ pub fn constructInto(globalThis: *JSC.JSGlobalObject, arguments: []const JSC.JSV if (globalThis.hasException()) return error.JSError; - if (!explicit_check or (explicit_check and value.fastGet(globalThis, .method) != null)) { + if (!explicit_check or (explicit_check and (try value.fastGet(globalThis, .method)) != null)) { if (!fields.contains(.method)) { req.method = response_init.method; fields.insert(.method); diff --git a/src/bun.js/webcore/Response.zig b/src/bun.js/webcore/Response.zig index ec967b3ff6..37481dd724 100644 --- a/src/bun.js/webcore/Response.zig +++ b/src/bun.js/webcore/Response.zig @@ -27,8 +27,8 @@ pub const getBlob = ResponseMixin.getBlob; pub const getBlobWithoutCallFrame = ResponseMixin.getBlobWithoutCallFrame; pub const getFormData = ResponseMixin.getFormData; -pub fn getFormDataEncoding(this: *Response) ?*bun.FormData.AsyncFormData { - var content_type_slice: ZigString.Slice = this.getContentType() orelse return null; +pub fn getFormDataEncoding(this: *Response) bun.JSError!?*bun.FormData.AsyncFormData { + var content_type_slice: ZigString.Slice = (try this.getContentType()) orelse return null; defer content_type_slice.deinit(); const encoding = bun.FormData.Encoding.get(content_type_slice.slice()) orelse return null; return bun.FormData.AsyncFormData.init(bun.default_allocator, encoding) catch bun.outOfMemory(); @@ -123,7 +123,7 @@ pub fn redirectLocation(this: *const Response) ?[]const u8 { } pub fn header(this: *const Response, name: bun.webcore.FetchHeaders.HTTPHeaderName) ?[]const u8 { - return if ((this.init.headers orelse return null).fastGet(name)) |str| + return if (try (this.init.headers orelse return null).fastGet(name)) |str| str.slice() else null; @@ -343,7 +343,7 @@ pub fn finalize( pub fn getContentType( this: *Response, -) ?ZigString.Slice { +) bun.JSError!?ZigString.Slice { if (this.init.headers) |headers| { if (headers.fastGet(.ContentType)) |value| { return value.toSlice(bun.default_allocator); @@ -643,7 +643,7 @@ pub const Init = struct { return error.JSError; } - if (response_init.fastGet(globalThis, .headers)) |headers| { + if (try response_init.fastGet(globalThis, .headers)) |headers| { if (headers.as(FetchHeaders)) |orig| { if (!orig.isEmpty()) { result.headers = orig.cloneThis(globalThis); @@ -657,7 +657,7 @@ pub const Init = struct { return error.JSError; } - if (response_init.fastGet(globalThis, .status)) |status_value| { + if (try response_init.fastGet(globalThis, .status)) |status_value| { const number = status_value.coerceToInt64(globalThis); if ((200 <= number and number < 600) or number == 101) { result.status_code = @as(u16, @truncate(@as(u32, @intCast(number)))); @@ -674,11 +674,11 @@ pub const Init = struct { return error.JSError; } - if (response_init.fastGet(globalThis, .statusText)) |status_text| { + if (try response_init.fastGet(globalThis, .statusText)) |status_text| { result.status_text = try bun.String.fromJS(status_text, globalThis); } - if (response_init.fastGet(globalThis, .method)) |method_value| { + if (try response_init.fastGet(globalThis, .method)) |method_value| { if (try Method.fromJS(globalThis, method_value)) |method| { result.method = method; } diff --git a/src/bun.js/webcore/TextDecoder.zig b/src/bun.js/webcore/TextDecoder.zig index 516a034aa5..873800b5c3 100644 --- a/src/bun.js/webcore/TextDecoder.zig +++ b/src/bun.js/webcore/TextDecoder.zig @@ -170,7 +170,7 @@ pub fn decode(this: *TextDecoder, globalThis: *JSC.JSGlobalObject, callframe: *J const stream = stream: { if (arguments.len > 1 and arguments[1].isObject()) { - if (arguments[1].fastGet(globalThis, .stream)) |stream_value| { + if (try arguments[1].fastGet(globalThis, .stream)) |stream_value| { const stream_bool = stream_value.coerce(bool, globalThis); if (globalThis.hasException()) { return .zero; diff --git a/src/bun.js/webcore/fetch.zig b/src/bun.js/webcore/fetch.zig index c5ba03e460..2d5ff3031b 100644 --- a/src/bun.js/webcore/fetch.zig +++ b/src/bun.js/webcore/fetch.zig @@ -1671,7 +1671,7 @@ pub fn Bun__fetch_( } if (request_init_object) |request_init| { - if (request_init.fastGet(globalThis, .url)) |url_| { + if (try request_init.fastGet(globalThis, .url)) |url_| { if (!url_.isUndefined()) { break :extract_url try bun.String.fromJS(url_, globalThis); } @@ -2092,7 +2092,7 @@ pub fn Bun__fetch_( // body = extract_body: { if (options_object) |options| { - if (options.fastGet(globalThis, .body)) |body__| { + if (try options.fastGet(globalThis, .body)) |body__| { if (!body__.isUndefined()) { break :extract_body try FetchTasklet.HTTPRequestBody.fromJS(ctx, body__); } @@ -2123,7 +2123,7 @@ pub fn Bun__fetch_( } if (request_init_object) |req| { - if (req.fastGet(globalThis, .body)) |body__| { + if (try req.fastGet(globalThis, .body)) |body__| { if (!body__.isUndefined()) { break :extract_body try FetchTasklet.HTTPRequestBody.fromJS(ctx, body__); } @@ -2149,7 +2149,7 @@ pub fn Bun__fetch_( const fetch_headers: ?*bun.webcore.FetchHeaders = brk: { if (options_object) |options| { - if (options.fastGet(globalThis, .headers)) |headers_value| { + if (try options.fastGet(globalThis, .headers)) |headers_value| { if (!headers_value.isUndefined()) { if (headers_value.as(FetchHeaders)) |headers__| { if (headers__.isEmpty()) { @@ -2183,7 +2183,7 @@ pub fn Bun__fetch_( } if (request_init_object) |options| { - if (options.fastGet(globalThis, .headers)) |headers_value| { + if (try options.fastGet(globalThis, .headers)) |headers_value| { if (!headers_value.isUndefined()) { if (headers_value.as(FetchHeaders)) |headers__| { if (headers__.isEmpty()) { @@ -2590,7 +2590,7 @@ pub fn Bun__fetch_( credentialsWithOptions.options, credentialsWithOptions.acl, credentialsWithOptions.storage_class, - if (headers) |h| h.getContentType() else null, + if (headers) |h| (h.getContentType()) else null, proxy_url, @ptrCast(&Wrapper.resolve), s3_stream, @@ -2630,7 +2630,7 @@ pub fn Bun__fetch_( result.url = ""; // fetch now owns this } - const content_type = if (headers) |h| h.getContentType() else null; + const content_type = if (headers) |h| (h.getContentType()) else null; var header_buffer: [10]picohttp.Header = undefined; if (range) |range_| { diff --git a/src/bun.js/webcore/streams.zig b/src/bun.js/webcore/streams.zig index 634b0cf95a..1e409514a6 100644 --- a/src/bun.js/webcore/streams.zig +++ b/src/bun.js/webcore/streams.zig @@ -88,14 +88,14 @@ pub const Start = union(Tag) { } } - if (value.fastGet(globalThis, .stream)) |val| { + if (try value.fastGet(globalThis, .stream)) |val| { if (val.isBoolean()) { stream = val.toBoolean(); empty = false; } } - if (value.fastGet(globalThis, .highWaterMark)) |chunkSize| { + if (try value.fastGet(globalThis, .highWaterMark)) |chunkSize| { if (chunkSize.isNumber()) { empty = false; chunk_size = @as(Blob.SizeType, @intCast(@max(0, @as(i51, @truncate(chunkSize.toInt64()))))); @@ -115,12 +115,12 @@ pub const Start = union(Tag) { .FileSink => { var chunk_size: Blob.SizeType = 0; - if (value.fastGet(globalThis, .highWaterMark)) |chunkSize| { + if (try value.fastGet(globalThis, .highWaterMark)) |chunkSize| { if (chunkSize.isNumber()) chunk_size = @as(Blob.SizeType, @intCast(@max(0, @as(i51, @truncate(chunkSize.toInt64()))))); } - if (value.fastGet(globalThis, .path)) |path| { + if (try value.fastGet(globalThis, .path)) |path| { if (!path.isString()) { return .{ .err = Syscall.Error{ @@ -174,7 +174,7 @@ pub const Start = union(Tag) { var empty = true; var chunk_size: Blob.SizeType = 2048; - if (value.fastGet(globalThis, .highWaterMark)) |chunkSize| { + if (try value.fastGet(globalThis, .highWaterMark)) |chunkSize| { if (chunkSize.isNumber()) { empty = false; chunk_size = @as(Blob.SizeType, @intCast(@max(256, @as(i51, @truncate(chunkSize.toInt64()))))); diff --git a/src/js_ast.zig b/src/js_ast.zig index 039a512262..bdcdb8e8ec 100644 --- a/src/js_ast.zig +++ b/src/js_ast.zig @@ -8268,9 +8268,9 @@ pub const Macro = struct { if (value.jsType() == .DOMWrapper) { if (value.as(JSC.WebCore.Response)) |resp| { - return this.run(resp.getBlobWithoutCallFrame(this.global)); + return this.run(try resp.getBlobWithoutCallFrame(this.global)); } else if (value.as(JSC.WebCore.Request)) |resp| { - return this.run(resp.getBlobWithoutCallFrame(this.global)); + return this.run(try resp.getBlobWithoutCallFrame(this.global)); } else if (value.as(JSC.WebCore.Blob)) |resp| { blob_ = resp.*; blob_.?.allocator = null; diff --git a/src/shell/shell.zig b/src/shell/shell.zig index 8fb1325114..5a8a4fae94 100644 --- a/src/shell/shell.zig +++ b/src/shell/shell.zig @@ -3847,7 +3847,7 @@ pub fn handleTemplateValue( return; } - if (template_value.implementsToString(globalThis)) { + if (try template_value.implementsToString(globalThis)) { if (!try builder.appendJSValueStr(template_value, true)) { return globalThis.throw("Shell script string contains invalid UTF-16", .{}); } diff --git a/test/internal/ban-words.test.ts b/test/internal/ban-words.test.ts index 89bb431204..33e331394d 100644 --- a/test/internal/ban-words.test.ts +++ b/test/internal/ban-words.test.ts @@ -34,7 +34,7 @@ const words: Record [String.raw`: [a-zA-Z0-9_\.\*\?\[\]\(\)]+ = undefined,`]: { reason: "Do not default a struct field to undefined", limit: 240, regex: true }, "usingnamespace": { reason: "Zig 0.15 will remove `usingnamespace`" }, - "catch unreachable": { reason: "For out-of-memory, prefer 'catch bun.outOfMemory()'", limit: 1851 }, + "catch unreachable": { reason: "For out-of-memory, prefer 'catch bun.outOfMemory()'", limit: 1850 }, "std.fs.Dir": { reason: "Prefer bun.sys + bun.FD instead of std.fs", limit: 180 }, "std.fs.cwd": { reason: "Prefer bun.FD.cwd()", limit: 103 }, diff --git a/test/js/web/encoding/text-decoder.test.js b/test/js/web/encoding/text-decoder.test.js index e23a04dde7..ca27e07890 100644 --- a/test/js/web/encoding/text-decoder.test.js +++ b/test/js/web/encoding/text-decoder.test.js @@ -563,3 +563,13 @@ describe("stream", () => { }); } }); + +it("should not crash with a getter that throws", () => { + expect(() => + new TextDecoder().decode(new Uint8Array(32), { + get stream() { + throw new Error("stream get error"); + }, + }), + ).toThrowErrorMatchingInlineSnapshot(`"stream get error"`); +});