diff options
-rw-r--r-- | src/javascript/jsc/api/server.zig | 40 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h | 10 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/bindings-generator.zig | 6 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/bindings.cpp | 40 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/bindings.zig | 116 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/exports.zig | 18 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/header-gen.zig | 138 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/headers.h | 40 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/headers.zig | 6 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/shimmer.zig | 31 | ||||
-rw-r--r-- | src/javascript/jsc/bindings/webcore/WebSocket.cpp | 105 |
11 files changed, 413 insertions, 137 deletions
diff --git a/src/javascript/jsc/api/server.zig b/src/javascript/jsc/api/server.zig index bec079e90..9a9628094 100644 --- a/src/javascript/jsc/api/server.zig +++ b/src/javascript/jsc/api/server.zig @@ -505,6 +505,8 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp pub threadlocal var pool_allocator: std.mem.Allocator = undefined; pub const RequestContextStackAllocator = NewRequestContextStackAllocator(RequestContext, 2048); + pub const name = "HTTPRequestContext" ++ (if (debug_mode) "Debug" else "") ++ (if (ThisServer.ssl_enabled) "TLS" else ""); + pub const shim = JSC.Shimmer("Bun", name, @This()); server: *ThisServer, resp: *App.Response, @@ -542,6 +544,15 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp // TODO: support builtin compression const can_sendfile = !ssl_enabled; + pub const thenables = shim.thenables(.{ + PromiseHandler, + }); + + pub const lazy_static_functions = thenables; + pub const Export = lazy_static_functions; + + const PromiseHandler = JSC.Thenable(RequestContext, onResolve, onReject); + pub fn setAbortHandler(this: *RequestContext) void { if (this.has_abort_handler) return; this.has_abort_handler = true; @@ -1196,6 +1207,7 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp value: JSC.JSValue, status: u16, ) void { + JSC.markBinding(); if (this.resp.hasResponded()) return; var exception_list: std.ArrayList(Api.JsException) = std.ArrayList(Api.JsException).init(this.allocator); @@ -1399,12 +1411,23 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp pub fn onPullCallback(this: *anyopaque) void { onPull(bun.cast(*RequestContext, this)); } + + comptime { + if (!JSC.is_bindgen) { + @export(PromiseHandler.resolve, .{ + .name = Export[0].symbol_name, + }); + @export(PromiseHandler.reject, .{ + .name = Export[1].symbol_name, + }); + } + } }; } pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { return struct { - const ssl_enabled = ssl_enabled_; + pub const ssl_enabled = ssl_enabled_; const debug_mode = debug_mode_; const ThisServer = @This(); @@ -1627,7 +1650,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { } pub fn onBunInfoRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void { - if (comptime JSC.is_bindgen) return undefined; + JSC.markBinding(); this.pending_requests += 1; defer this.pending_requests -= 1; req.setYield(false); @@ -1654,7 +1677,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { } pub fn onSrcRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void { - if (comptime JSC.is_bindgen) return undefined; + JSC.markBinding(); this.pending_requests += 1; defer this.pending_requests -= 1; req.setYield(false); @@ -1684,7 +1707,7 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { } pub fn onRequest(this: *ThisServer, req: *uws.Request, resp: *App.Response) void { - if (comptime JSC.is_bindgen) return undefined; + JSC.markBinding(); this.pending_requests += 1; var vm = this.vm; req.setYield(false); @@ -1768,13 +1791,8 @@ pub fn NewServer(comptime ssl_enabled_: bool, comptime debug_mode_: bool) type { if (wait_for_promise) { ctx.setAbortHandler(); - response_value.then( - this.globalThis, - RequestContext, - ctx, - RequestContext.onResolve, - RequestContext.onReject, - ); + + RequestContext.PromiseHandler.then(ctx, response_value, this.globalThis); return; } diff --git a/src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h b/src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h index d533abeec..c52f65d85 100644 --- a/src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h +++ b/src/javascript/jsc/bindings/WebCoreJSBuiltinInternals.h @@ -1,7 +1,5 @@ //clang-format off -namespace Zig { -class GlobalObject; -} +namespace Zig { class GlobalObject; } /* * Copyright (c) 2015 Igalia * Copyright (c) 2015 Igalia S.L. @@ -10,7 +8,7 @@ class GlobalObject; * Copyright (c) 2015, 2016, 2017 Canon Inc. * Copyright (c) 2016, 2020 Apple Inc. All rights reserved. * Copyright (c) 2022 Codeblog Corp. All rights reserved. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -19,7 +17,7 @@ class GlobalObject; * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR @@ -31,7 +29,7 @@ class GlobalObject; * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. - * + * */ // DO NOT EDIT THIS FILE. It is automatically generated from JavaScript files for diff --git a/src/javascript/jsc/bindings/bindings-generator.zig b/src/javascript/jsc/bindings/bindings-generator.zig index 4e44fb9c0..a828c5f9e 100644 --- a/src/javascript/jsc/bindings/bindings-generator.zig +++ b/src/javascript/jsc/bindings/bindings-generator.zig @@ -25,16 +25,20 @@ pub fn main() anyerror!void { { const paths = [_][]const u8{ std.fs.path.dirname(src.file) orelse return error.BadPath, "headers.h" }; const paths2 = [_][]const u8{ std.fs.path.dirname(src.file) orelse return error.BadPath, "headers-cpp.h" }; + const paths3 = [_][]const u8{ std.fs.path.dirname(src.file) orelse return error.BadPath, "ZigLazyStaticFunctions.h" }; + const paths4 = [_][]const u8{ std.fs.path.dirname(src.file) orelse return error.BadPath, "ZigLazyStaticFunctions-inlines.h" }; const cpp = try std.fs.createFileAbsolute(try std.fs.path.join(allocator, &paths2), .{}); const file = try std.fs.createFileAbsolute(try std.fs.path.join(allocator, &paths), .{}); + const static = try std.fs.createFileAbsolute(try std.fs.path.join(allocator, &paths3), .{}); + const staticInlines = try std.fs.createFileAbsolute(try std.fs.path.join(allocator, &paths4), .{}); const HeaderGenerator = HeaderGen( Bindings, Exports, "src/javascript/jsc/bindings/bindings.zig", ); - HeaderGenerator.exec(HeaderGenerator{}, file, cpp); + HeaderGenerator.exec(HeaderGenerator{}, file, cpp, static, staticInlines); } // TODO: finish this const use_cpp_generator = false; diff --git a/src/javascript/jsc/bindings/bindings.cpp b/src/javascript/jsc/bindings/bindings.cpp index a8770005a..69d836754 100644 --- a/src/javascript/jsc/bindings/bindings.cpp +++ b/src/javascript/jsc/bindings/bindings.cpp @@ -87,39 +87,18 @@ static void copyToUWS(WebCore::FetchHeaders* headers, UWSResponse* res) } template<typename PromiseType, bool isInternal> -static void handlePromise(PromiseType* promise, JSC__JSGlobalObject* globalObject, void* ctx, void (*ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, void** arg2, size_t arg3), void (*ArgFn4)(JSC__JSGlobalObject* arg0, void* arg1, void** arg2, size_t arg3)) +static void handlePromise(PromiseType* promise, JSC__JSGlobalObject* globalObject, void* ctx, void (*ArgFn3)(void*, JSC__JSGlobalObject* arg0, JSC__CallFrame* callFrame), void (*ArgFn4)(void*, JSC__JSGlobalObject* arg0, JSC__CallFrame* callFrame)) { - JSC::Strong<PromiseType> strongValue = { globalObject->vm(), promise }; - JSC::JSNativeStdFunction* resolverFunction = JSC::JSNativeStdFunction::create( - globalObject->vm(), globalObject, 1, String(), [&strongValue, ctx, ArgFn3](JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) -> const JSC::EncodedJSValue { - auto argCount = static_cast<uint16_t>(callFrame->argumentCount()); - - WTF::Vector<JSC::EncodedJSValue, 16> arguments; - arguments.reserveInitialCapacity(argCount); - if (argCount) { - for (uint16_t i = 0; i < argCount; ++i) { - arguments.uncheckedAppend(JSC::JSValue::encode(callFrame->uncheckedArgument(i))); - } - } - ArgFn3(globalObject, ctx, reinterpret_cast<void**>(arguments.data()), argCount); - strongValue.clear(); + JSC::JSNativeStdFunction* resolverFunction = JSC::JSNativeStdFunction::create( + globalObject->vm(), globalObject, 1, String(), [ctx, ArgFn3](JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) -> const JSC::EncodedJSValue { + ArgFn3(ctx, globalObject, callFrame); return JSC::JSValue::encode(JSC::jsUndefined()); }); JSC::JSNativeStdFunction* rejecterFunction = JSC::JSNativeStdFunction::create( globalObject->vm(), globalObject, 1, String(), - [&strongValue, ctx, ArgFn4](JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) -> JSC::EncodedJSValue { - auto argCount = static_cast<uint16_t>(callFrame->argumentCount()); - WTF::Vector<JSC::EncodedJSValue, 16> arguments; - arguments.reserveInitialCapacity(argCount); - if (argCount) { - for (uint16_t i = 0; i < argCount; ++i) { - arguments.uncheckedAppend(JSC::JSValue::encode(callFrame->uncheckedArgument(i))); - } - } - - ArgFn4(globalObject, ctx, reinterpret_cast<void**>(arguments.data()), argCount); - strongValue.clear(); + [ctx, ArgFn4](JSC::JSGlobalObject* globalObject, JSC::CallFrame* callFrame) -> JSC::EncodedJSValue { + ArgFn4(ctx, globalObject, callFrame); return JSC::JSValue::encode(JSC::jsUndefined()); }); @@ -537,7 +516,7 @@ JSC__JSPromise* JSC__JSPromise__create(JSC__JSGlobalObject* arg0) } // TODO: prevent this from allocating so much memory -void JSC__JSValue___then(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, void* ctx, void (*ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, void** arg2, size_t arg3), void (*ArgFn4)(JSC__JSGlobalObject* arg0, void* arg1, void** arg2, size_t arg3)) +void JSC__JSValue___then(JSC__JSValue JSValue0, JSC__JSGlobalObject* globalObject, void* ctx, void (*ArgFn3)(void*, JSC__JSGlobalObject* arg0, JSC__CallFrame* callFrame), void (*ArgFn4)(void*, JSC__JSGlobalObject* arg0, JSC__CallFrame* callFrame)) { auto* cell = JSC::JSValue::decode(JSValue0).asCell(); @@ -624,8 +603,9 @@ JSC__JSInternalPromise* JSC__VM__reloadModule(JSC__VM* vm, JSC__JSGlobalObject* bool JSC__JSValue__isSameValue(JSC__JSValue JSValue0, JSC__JSValue JSValue1, JSC__JSGlobalObject* globalObject) { - return JSC::sameValue(globalObject, JSC::JSValue::decode(JSValue0), - JSC::JSValue::decode(JSValue1)); + JSC::JSValue left = JSC::JSValue::decode(JSValue0); + JSC::JSValue right = JSC::JSValue::decode(JSValue1); + return JSC::sameValue(globalObject, left, right); } // This is the same as the C API version, except it returns a JSValue which may be a *Exception diff --git a/src/javascript/jsc/bindings/bindings.zig b/src/javascript/jsc/bindings/bindings.zig index 1b6524826..a2757fc62 100644 --- a/src/javascript/jsc/bindings/bindings.zig +++ b/src/javascript/jsc/bindings/bindings.zig @@ -214,9 +214,12 @@ pub const ZigString = extern struct { return from16(slice_.ptr, slice_.len); } + /// Globally-allocated memory only pub fn from16(slice_: [*]const u16, len: usize) ZigString { var str = init(@ptrCast([*]const u8, slice_)[0..len]); str.markUTF16(); + str.mark(); + str.assertGlobal(); return str; } @@ -350,7 +353,7 @@ pub const ZigString = extern struct { } pub fn trimmedSlice(this: *const ZigString) []const u8 { - return strings.trim(this.ptr[0..@minimum(this.len, std.math.maxInt(u32))], " \r\n"); + return strings.trim(this.full(), " \r\n"); } pub fn toValueAuto(this: *const ZigString, global: *JSGlobalObject) JSValue { @@ -361,11 +364,27 @@ pub const ZigString = extern struct { } } + fn assertGlobalIfNeeded(this: *const ZigString) void { + if (comptime bun.Environment.allow_assert) { + if (this.isGloballyAllocated()) { + this.assertGlobal(); + } + } + } + + fn assertGlobal(this: *const ZigString) void { + if (comptime bun.Environment.allow_assert) { + std.debug.assert(bun.Global.Mimalloc.mi_is_in_heap_region(untagged(this.ptr)) or bun.Global.Mimalloc.mi_check_owned(untagged(this.ptr))); + } + } + pub fn toValue(this: *const ZigString, global: *JSGlobalObject) JSValue { + this.assertGlobalIfNeeded(); return shim.cppFn("toValue", .{ this, global }); } pub fn toExternalValue(this: *const ZigString, global: *JSGlobalObject) JSValue { + this.assertGlobal(); return shim.cppFn("toExternalValue", .{ this, global }); } @@ -387,6 +406,7 @@ pub const ZigString = extern struct { } pub fn to16BitValue(this: *const ZigString, global: *JSGlobalObject) JSValue { + this.assertGlobal(); return shim.cppFn("to16BitValue", .{ this, global }); } @@ -406,9 +426,9 @@ pub const ZigString = extern struct { } return if (this.is16Bit()) - C_API.JSStringCreateWithCharactersNoCopy(@ptrCast([*]const u16, @alignCast(@alignOf([*]const u16), this.ptr)), this.len) + C_API.JSStringCreateWithCharactersNoCopy(@ptrCast([*]const u16, @alignCast(@alignOf([*]const u16), untagged(this.ptr))), this.len) else - C_API.JSStringCreateStatic(this.ptr, this.len); + C_API.JSStringCreateStatic(untagged(this.ptr), this.len); } pub fn toErrorInstance(this: *const ZigString, global: *JSGlobalObject) JSValue { @@ -1429,6 +1449,8 @@ pub const SourceCode = extern struct { }; }; +pub const Thenables = opaque {}; + pub const JSFunction = extern struct { pub const shim = Shimmer("JSC", "JSFunction", @This()); bytes: shim.Bytes, @@ -1720,6 +1742,8 @@ fn _WTF(comptime str: []const u8) type { return opaque {}; } } +pub const JSNativeFn = fn (*JSGlobalObject, *JSC.CallFrame) callconv(.C) JSValue; +pub const JSNativeFnWithCtx = fn (?*anyopaque, [*c]JSGlobalObject, ?*JSC.CallFrame) callconv(.C) void; pub const URL = extern struct { pub const shim = Shimmer("WTF", "URL", @This()); @@ -1939,13 +1963,17 @@ pub const String = extern struct { }; }; -pub const JSValue = enum(i64) { - @"undefined" = 0xa, +pub const JSValueReprInt = i64; +pub const JSValue = enum(JSValueReprInt) { + zero = 0, + @"undefined" = @bitCast(JSValueReprInt, @as(i64, 0xa)), _, + pub const Type = JSValueReprInt; + pub const shim = Shimmer("JSC", "JSValue", @This()); pub const is_pointer = false; - pub const Type = i64; + const cppFn = shim.cppFn; pub const Encoded = extern union { @@ -1959,7 +1987,6 @@ pub const JSValue = enum(i64) { pub const include = "JavaScriptCore/JSValue.h"; pub const name = "JSC::JSValue"; pub const namespace = "JSC"; - pub const zero = @intToEnum(JSValue, @as(i64, 0)); pub const JSType = enum(u8) { // The Cell value must come before any JS that is a JSCell. Cell, @@ -2200,16 +2227,15 @@ pub const JSValue = enum(i64) { ?*JSInternalPromise => asInternalPromise(this), ?*JSPromise => asPromise(this), - u52 => @truncate(u52, this.to(u64)), + u52 => @truncate(u52, @intCast(u64, @maximum(this.toInt64(), 0))), - u64 => @intCast(u64, @maximum(toInt64(this), 0)), + u64 => toUInt64NoTruncate(this), u8 => @truncate(u8, toU32(this)), i16 => @truncate(i16, toInt32(this)), i8 => @truncate(i8, toInt32(this)), i32 => @truncate(i32, toInt32(this)), - // TODO: BigInt64 i64 => this.toInt64(), bool => this.toBoolean(), @@ -2693,44 +2719,12 @@ pub const JSValue = enum(i64) { return cppFn("symbolKeyFor", .{ this, global, str }); } - const Thenable = fn ( - global: [*c]JSGlobalObject, - ctx: ?*anyopaque, - arguments_ptr: [*c]*anyopaque, - arguments_len: usize, - ) callconv(.C) void; - pub fn _then(this: JSValue, global: *JSGlobalObject, ctx: ?*anyopaque, resolve: Thenable, reject: Thenable) void { + pub fn _then(this: JSValue, global: *JSGlobalObject, ctx: ?*anyopaque, resolve: JSNativeFnWithCtx, reject: JSNativeFnWithCtx) void { return cppFn("_then", .{ this, global, ctx, resolve, reject }); } - pub fn then(this: JSValue, global: *JSGlobalObject, comptime Then: type, ctx: *Then, comptime onResolve: fn (*Then, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void, comptime onReject: fn (*Then, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void) void { - const Handler = struct { - fn resolve( - globalThis: [*c]JSGlobalObject, - ptr: ?*anyopaque, - arguments_ptr: [*c]*anyopaque, - arguments_len: usize, - ) callconv(.C) void { - @setRuntimeSafety(false); - onResolve(bun.cast(*Then, ptr.?), globalThis, @ptrCast([*]const JSC.JSValue, arguments_ptr)[0..arguments_len]); - } - pub fn reject( - globalThis: [*c]JSGlobalObject, - ptr: ?*anyopaque, - arguments_ptr: [*c]*anyopaque, - arguments_len: usize, - ) callconv(.C) void { - @setRuntimeSafety(false); - onReject(bun.cast(*Then, ptr.?), globalThis, @ptrCast([*]const JSC.JSValue, arguments_ptr)[0..arguments_len]); - } - }; - - this._then( - global, - ctx, - Handler.resolve, - Handler.reject, - ); + pub fn then(this: JSValue, global: *JSGlobalObject, comptime Then: type, ctx: *Then, comptime onResolve: fn (*Then, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void, comptime onReject: fn (*Then, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void) void { + Thenable(Then, onResolve, onReject).then(this, global, ctx); } pub fn getDescription(this: JSValue, global: *JSGlobalObject) ZigString { @@ -2846,7 +2840,7 @@ pub const JSValue = enum(i64) { } pub fn asBoolean(this: JSValue) bool { - return @enumToInt(this) == @bitCast(c_longlong, @as(c_longlong, (@as(c_int, 2) | @as(c_int, 4)) | @as(c_int, 1))); + return FFI.JSVALUE_TO_BOOL(.{ .asJSValue = this }); } pub fn toInt32(this: JSValue) i32 { @@ -2864,11 +2858,11 @@ pub const JSValue = enum(i64) { } pub fn asInt32(this: JSValue) i32 { - return @bitCast(i32, @truncate(c_int, @enumToInt(this))); + return FFI.JSVALUE_TO_INT32(.{ .asJSValue = this }); } pub inline fn toU16(this: JSValue) u16 { - return @intCast(u16, this.toInt32()); + return @truncate(u16, this.toU32()); } pub inline fn toU32(this: JSValue) u32 { @@ -3651,3 +3645,29 @@ pub const WTF = struct { pub const Callback = struct { // zig: Value, }; + +pub fn Thenable(comptime Then: type, comptime onResolve: fn (*Then, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void, comptime onReject: fn (*Then, globalThis: *JSGlobalObject, args: []const JSC.JSValue) void) type { + return struct { + pub fn resolve( + ctx: ?*anyopaque, + globalThis: [*c]JSGlobalObject, + callframe: ?*JSC.CallFrame, + ) callconv(.C) void { + @setRuntimeSafety(false); + onResolve(@ptrCast(*Then, @alignCast(std.meta.alignment(Then), ctx.?)), globalThis, callframe.?.arguments()); + } + + pub fn reject( + ctx: ?*anyopaque, + globalThis: [*c]JSGlobalObject, + callframe: ?*JSC.CallFrame, + ) callconv(.C) void { + @setRuntimeSafety(false); + onReject(@ptrCast(*Then, @alignCast(std.meta.alignment(Then), ctx.?)), globalThis, callframe.?.arguments()); + } + + pub fn then(ctx: *Then, this: JSValue, globalThis: *JSGlobalObject) void { + this._then(globalThis, ctx, resolve, reject); + } + }; +} diff --git a/src/javascript/jsc/bindings/exports.zig b/src/javascript/jsc/bindings/exports.zig index fa7884a50..cb62ba383 100644 --- a/src/javascript/jsc/bindings/exports.zig +++ b/src/javascript/jsc/bindings/exports.zig @@ -1340,6 +1340,8 @@ pub const ZigConsoleClient = struct { JSValue.JSType.BigUint64Array, => .TypedArray, + .HeapBigInt => .BigInt, + // None of these should ever exist here // But we're going to check anyway .GetterSetter, @@ -1367,6 +1369,7 @@ pub const ZigConsoleClient = struct { .StrictEvalActivation, .WithScope, => .NativeCode, + else => .JSON, }, .cell = js_type, @@ -1610,11 +1613,11 @@ pub const ZigConsoleClient = struct { writer.print(comptime Output.prettyFmt("<r><yellow>{d}<r>", enable_ansi_colors), .{value.toInt64()}); }, .BigInt => { - var wtf = value.toWTFString(this.globalThis); - writer.print(comptime Output.prettyFmt("<r><yellow>{s}n<r>", enable_ansi_colors), .{wtf.slice()}); + var out_str = value.getZigString(this.globalThis).slice(); + writer.print(comptime Output.prettyFmt("<r><yellow>{s}n<r>", enable_ansi_colors), .{out_str}); }, .Double => { - writer.print(comptime Output.prettyFmt("<r><yellow>{d}<r>", enable_ansi_colors), .{value.asNumber()}); + writer.print(comptime Output.prettyFmt("<r><yellow>{d}n<r>", enable_ansi_colors), .{value.asNumber()}); }, .Undefined => { writer.print(comptime Output.prettyFmt("<r><d>undefined<r>", enable_ansi_colors), .{}); @@ -2510,6 +2513,10 @@ comptime { const Bun = @import("../api/bun.zig"); pub const BunTimer = Bun.Timer; pub const Formatter = ZigConsoleClient.Formatter; +pub const HTTPServerRequestContext = JSC.API.Server.RequestContext; +pub const HTTPSSLServerRequestContext = JSC.API.SSLServer.RequestContext; +pub const HTTPDebugServerRequestContext = JSC.API.DebugServer.RequestContext; +pub const HTTPDebugSSLServerRequestContext = JSC.API.DebugSSLServer.RequestContext; comptime { WebSocketHTTPClient.shim.ref(); @@ -2517,6 +2524,11 @@ comptime { WebSocketClient.shim.ref(); WebSocketClientTLS.shim.ref(); + HTTPServerRequestContext.shim.ref(); + HTTPSSLServerRequestContext.shim.ref(); + HTTPDebugServerRequestContext.shim.ref(); + HTTPDebugSSLServerRequestContext.shim.ref(); + if (!is_bindgen) { _ = Process.getTitle; _ = Process.setTitle; diff --git a/src/javascript/jsc/bindings/header-gen.zig b/src/javascript/jsc/bindings/header-gen.zig index 3ec73ea94..c11241233 100644 --- a/src/javascript/jsc/bindings/header-gen.zig +++ b/src/javascript/jsc/bindings/header-gen.zig @@ -482,6 +482,7 @@ pub fn getCStruct(comptime T: type) ?NamedStruct { return null; } +var thenables = std.ArrayListUnmanaged([]const u8){}; pub fn HeaderGen(comptime first_import: type, comptime second_import: type, comptime fname: []const u8) type { return struct { source_file: []const u8 = fname, @@ -543,6 +544,10 @@ pub fn HeaderGen(comptime first_import: type, comptime second_import: type, comp ); } + pub fn processThenable(comptime _: Self, _: anytype, comptime static_export: StaticExport) void { + thenables.append(std.heap.c_allocator, comptime static_export.symbol_name) catch unreachable; + } + pub fn processDecl( comptime _: Self, _: anytype, @@ -593,11 +598,11 @@ pub fn HeaderGen(comptime first_import: type, comptime second_import: type, comp } } - pub fn exec(comptime self: Self, file: std.fs.File, impl: std.fs.File) void { + pub fn exec(comptime self: Self, file: std.fs.File, impl: std.fs.File, lazy_functions_header: std.fs.File, lazy_functions_impl: std.fs.File) void { const Generator = C_Generator; validateGenerator(Generator); var file_writer = file.writer(); - file_writer.print("// clang-format: off\n//-- AUTOGENERATED FILE -- {d}\n", .{std.time.timestamp()}) catch unreachable; + file_writer.print("// clang-format off\n//-- AUTOGENERATED FILE -- {d}\n", .{std.time.timestamp()}) catch unreachable; file.writeAll( \\#pragma once \\ @@ -649,6 +654,15 @@ pub fn HeaderGen(comptime first_import: type, comptime second_import: type, comp var impl_fourth_buffer = std.ArrayList(u8).init(std.heap.c_allocator); var impl_fourth_writer = impl_fourth_buffer.writer(); + var lazy_functions_buffer = std.ArrayList(u8).init(std.heap.c_allocator); + var lazy_functions_buffer_writer = lazy_functions_buffer.writer(); + + var lazy_function_definitions_buffer = std.ArrayList(u8).init(std.heap.c_allocator); + var lazy_function_definitions_writer = lazy_function_definitions_buffer.writer(); + + var lazy_function_visitor_buffer = std.ArrayList(u8).init(std.heap.c_allocator); + var lazy_function_visitor_writer = lazy_function_visitor_buffer.writer(); + // inline for (import.all_static_externs) |static_extern, i| { // const Type = static_extern.Type; // var gen = C_Generator.init(static_extern.name, @TypeOf(writer), writer); @@ -688,7 +702,7 @@ pub fn HeaderGen(comptime first_import: type, comptime second_import: type, comp else => false, }; - if (is_container_type and (@hasDecl(Type, "Extern") or @hasDecl(Type, "Export"))) { + if (is_container_type and (@hasDecl(Type, "Extern") or @hasDecl(Type, "Export") or @hasDecl(Type, "lazy_static_functions"))) { const identifier = comptime std.fmt.comptimePrint("{s}_{s}", .{ Type.shim.name, Type.shim.namespace }); if (!bufset.contains(identifier)) { self.startFile( @@ -782,6 +796,75 @@ pub fn HeaderGen(comptime first_import: type, comptime second_import: type, comp gen.write("\n#endif\n"); } } + + if (@hasDecl(Type, "lazy_static_functions")) { + const ExportLIst = comptime brk: { + const Sorder = struct { + pub fn lessThan(_: @This(), comptime lhs: StaticExport, comptime rhs: StaticExport) bool { + return std.ascii.orderIgnoreCase(lhs.symbol_name, rhs.symbol_name) == std.math.Order.lt; + } + }; + var extern_list = Type.lazy_static_functions; + std.sort.sort(StaticExport, &extern_list, Sorder{}, Sorder.lessThan); + break :brk extern_list; + }; + + gen.direction = C_Generator.Direction.export_zig; + if (ExportLIst.len > 0) { + lazy_function_definitions_writer.writeAll("\n#pragma mark ") catch unreachable; + lazy_function_definitions_writer.writeAll(Type.shim.name) catch unreachable; + lazy_function_definitions_writer.writeAll("\n\n") catch unreachable; + + inline for (ExportLIst) |static_export| { + const exp: StaticExport = static_export; + lazy_function_definitions_writer.print(" JSC::LazyProperty<Zig::GlobalObject, Zig::JSFFIFunction> m_{s};", .{exp.symbol_name}) catch unreachable; + lazy_function_definitions_writer.writeAll("\n") catch unreachable; + + lazy_function_definitions_writer.print( + " Zig::JSFFIFunction* get__{s}(Zig::GlobalObject *globalObject) {{ return m_{s}.getInitializedOnMainThread(globalObject); }}", + .{ exp.symbol_name, exp.symbol_name }, + ) catch unreachable; + lazy_function_definitions_writer.writeAll("\n") catch unreachable; + + const impl_format = + \\ + \\ m_{s}.initLater( + \\ [](const JSC::LazyProperty<Zig::GlobalObject, Zig::JSFFIFunction>::Initializer& init) {{ + \\ WTF::String functionName = WTF::String("{s}"_s); + \\ Zig::JSFFIFunction* function = Zig::JSFFIFunction::create( + \\ init.vm, + \\ init.owner, + \\ 1, + \\ functionName, + \\ {s}, + \\ JSC::NoIntrinsic, + \\ {s} + \\ ); + \\ init.set(function); + \\ }}); + \\ + ; + + lazy_functions_buffer_writer.print( + impl_format, + .{ + exp.symbol_name, + exp.local_name, + exp.symbol_name, + exp.symbol_name, + }, + ) catch unreachable; + + lazy_function_visitor_writer.print( + \\ this->m_{s}.visit(visitor); + \\ + , + .{exp.symbol_name}, + ) catch unreachable; + } + gen.write("\n"); + } + } } } } @@ -800,6 +883,55 @@ pub fn HeaderGen(comptime first_import: type, comptime second_import: type, comp impl.writeAll("};\n") catch unreachable; var iter = type_names.iterator(); + lazy_functions_header.writer().print( + \\// GENERATED FILE + \\#pragma once + \\#include "root.h" + \\ + \\namespace Zig {{ + \\ class GlobalObject; + \\ class JSFFIFunction; + \\ + \\ class LazyStaticFunctions {{ + \\ public: + \\ + \\ void init(Zig::GlobalObject* globalObject); + \\ + \\ template<typename Visitor> + \\ void visit(Visitor& visitor); + \\ + \\ + \\ /* -- BEGIN FUNCTION DEFINITIONS -- */ + \\ {s} + \\ /* -- END FUNCTION DEFINITIONS-- */ + \\ }}; + \\ + \\}} // namespace Zig + \\ + , .{lazy_function_definitions_buffer.items}) catch unreachable; + + lazy_functions_impl.writer().print( + \\// GENERATED FILE + \\#pragma once + \\ + \\namespace Zig {{ + \\ + \\ template<typename Visitor> + \\ void LazyStaticFunctions::visit(Visitor& visitor) {{ + \\ {s} + \\ }} + \\ + \\ void LazyStaticFunctions::init(Zig::GlobalObject *globalObject) {{ + \\ {s} + \\ }} + \\ + \\}} // namespace Zig + \\ + , .{ + lazy_function_visitor_buffer.items, + lazy_functions_buffer.items, + }) catch unreachable; + const NamespaceMap = std.StringArrayHashMap(std.BufMap); var namespaces = NamespaceMap.init(std.heap.c_allocator); diff --git a/src/javascript/jsc/bindings/headers.h b/src/javascript/jsc/bindings/headers.h index 3db8ed275..925291a7d 100644 --- a/src/javascript/jsc/bindings/headers.h +++ b/src/javascript/jsc/bindings/headers.h @@ -1,5 +1,5 @@ -// clang-format: off -//-- AUTOGENERATED FILE -- 1655637924 +// clang-format off +//-- AUTOGENERATED FILE -- 1655893003 #pragma once #include <stddef.h> @@ -106,9 +106,9 @@ typedef void* JSClassRef; typedef bJSC__JSInternalPromise JSC__JSInternalPromise; // JSC::JSInternalPromise typedef Bun__Readable Bun__Readable; typedef struct JSC__RegExpPrototype JSC__RegExpPrototype; // JSC::RegExpPrototype + typedef struct JSC__CallFrame JSC__CallFrame; // JSC::CallFrame typedef struct JSC__MapIteratorPrototype JSC__MapIteratorPrototype; // JSC::MapIteratorPrototype typedef struct WebCore__FetchHeaders WebCore__FetchHeaders; // WebCore::FetchHeaders - typedef struct JSC__CallFrame JSC__CallFrame; // JSC::CallFrame typedef bWTF__StringView WTF__StringView; // WTF::StringView typedef bJSC__ThrowScope JSC__ThrowScope; // JSC::ThrowScope typedef bWTF__StringImpl WTF__StringImpl; // WTF::StringImpl @@ -462,7 +462,7 @@ CPP_DECL size_t WTF__String__length(WTF__String* arg0); #pragma mark - JSC::JSValue -CPP_DECL void JSC__JSValue___then(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void (* ArgFn3)(JSC__JSGlobalObject* arg0, void* arg1, void** arg2, size_t arg3), void (* ArgFn4)(JSC__JSGlobalObject* arg0, void* arg1, void** arg2, size_t arg3)); +CPP_DECL void JSC__JSValue___then(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, void* arg2, void (* ArgFn3)(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2), void (* ArgFn4)(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2)); CPP_DECL bool JSC__JSValue__asArrayBuffer_(JSC__JSValue JSValue0, JSC__JSGlobalObject* arg1, Bun__ArrayBuffer* arg2); CPP_DECL JSC__JSCell* JSC__JSValue__asCell(JSC__JSValue JSValue0); CPP_DECL JSC__JSInternalPromise* JSC__JSValue__asInternalPromise(JSC__JSValue JSValue0); @@ -836,3 +836,35 @@ ZIG_DECL JSC__JSValue Bun__Timer__setInterval(JSC__JSGlobalObject* arg0, JSC__JS ZIG_DECL JSC__JSValue Bun__Timer__setTimeout(JSC__JSGlobalObject* arg0, JSC__JSValue JSValue1, JSC__JSValue JSValue2); #endif + +#ifdef __cplusplus + +ZIG_DECL void Bun__HTTPRequestContext__reject(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2); +ZIG_DECL void Bun__HTTPRequestContext__resolve(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2); + +#endif + + +#ifdef __cplusplus + +ZIG_DECL void Bun__HTTPRequestContextTLS__reject(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2); +ZIG_DECL void Bun__HTTPRequestContextTLS__resolve(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2); + +#endif + + +#ifdef __cplusplus + +ZIG_DECL void Bun__HTTPRequestContextDebug__reject(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2); +ZIG_DECL void Bun__HTTPRequestContextDebug__resolve(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2); + +#endif + + +#ifdef __cplusplus + +ZIG_DECL void Bun__HTTPRequestContextDebugTLS__reject(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2); +ZIG_DECL void Bun__HTTPRequestContextDebugTLS__resolve(void* arg0, JSC__JSGlobalObject* arg1, JSC__CallFrame* arg2); + +#endif + diff --git a/src/javascript/jsc/bindings/headers.zig b/src/javascript/jsc/bindings/headers.zig index 306ee44f2..1a42b9532 100644 --- a/src/javascript/jsc/bindings/headers.zig +++ b/src/javascript/jsc/bindings/headers.zig @@ -120,11 +120,11 @@ pub const JSC__JSInternalPromise = bJSC__JSInternalPromise; pub const JSC__RegExpPrototype = struct_JSC__RegExpPrototype; +pub const JSC__CallFrame = struct_JSC__CallFrame; + pub const JSC__MapIteratorPrototype = struct_JSC__MapIteratorPrototype; pub const WebCore__FetchHeaders = struct_WebCore__FetchHeaders; - -pub const JSC__CallFrame = struct_JSC__CallFrame; pub const WTF__StringView = bWTF__StringView; pub const JSC__ThrowScope = bJSC__ThrowScope; pub const WTF__StringImpl = bWTF__StringImpl; @@ -311,7 +311,7 @@ pub extern fn WTF__String__isEmpty(arg0: [*c]WTF__String) bool; pub extern fn WTF__String__isExternal(arg0: [*c]WTF__String) bool; pub extern fn WTF__String__isStatic(arg0: [*c]WTF__String) bool; pub extern fn WTF__String__length(arg0: [*c]WTF__String) usize; -pub extern fn JSC__JSValue___then(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?fn ([*c]JSC__JSGlobalObject, ?*anyopaque, [*c]*anyopaque, usize) callconv(.C) void, ArgFn4: ?fn ([*c]JSC__JSGlobalObject, ?*anyopaque, [*c]*anyopaque, usize) callconv(.C) void) void; +pub extern fn JSC__JSValue___then(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: ?*anyopaque, ArgFn3: ?fn (?*anyopaque, [*c]JSC__JSGlobalObject, ?*JSC__CallFrame) callconv(.C) void, ArgFn4: ?fn (?*anyopaque, [*c]JSC__JSGlobalObject, ?*JSC__CallFrame) callconv(.C) void) void; pub extern fn JSC__JSValue__asArrayBuffer_(JSValue0: JSC__JSValue, arg1: [*c]JSC__JSGlobalObject, arg2: [*c]Bun__ArrayBuffer) bool; pub extern fn JSC__JSValue__asCell(JSValue0: JSC__JSValue) [*c]JSC__JSCell; pub extern fn JSC__JSValue__asInternalPromise(JSValue0: JSC__JSValue) [*c]JSC__JSInternalPromise; diff --git a/src/javascript/jsc/bindings/shimmer.zig b/src/javascript/jsc/bindings/shimmer.zig index 8d8fda591..c180fc864 100644 --- a/src/javascript/jsc/bindings/shimmer.zig +++ b/src/javascript/jsc/bindings/shimmer.zig @@ -126,6 +126,37 @@ pub fn Shimmer(comptime _namespace: []const u8, comptime _name: []const u8, comp }; } + pub fn thenables(comptime Functions: anytype) [std.meta.fieldNames(@TypeOf(Functions)).len * 2]StaticExport { + const FunctionsType = @TypeOf(Functions); + return comptime brk: { + var functions: [std.meta.fieldNames(FunctionsType).len * 2]StaticExport = undefined; + var j: usize = 0; + inline for (Functions) |thenable| { + inline for ([_][]const u8{ "resolve", "reject" }) |fn_name| { + const Function = @TypeOf(@field(thenable, fn_name)); + if (@typeInfo(Function) != .Fn) { + @compileError("Expected " ++ @typeName(Parent) ++ "." ++ @typeName(Function) ++ " to be a function but received " ++ @tagName(@typeInfo(Function))); + } + var Fn: std.builtin.TypeInfo.Fn = @typeInfo(Function).Fn; + if (Fn.calling_convention != .C) { + @compileError("Expected " ++ @typeName(Parent) ++ "." ++ @typeName(Function) ++ " to have a C Calling Convention."); + } + + const export_name = symbolName(fn_name); + functions[j] = StaticExport{ + .Type = Function, + .symbol_name = export_name, + .local_name = fn_name, + .Parent = thenable, + }; + j += 1; + } + } + + break :brk functions; + }; + } + pub inline fn matchNullable(comptime ExpectedReturnType: type, comptime ExternReturnType: type, value: ExternReturnType) ExpectedReturnType { if (comptime isNullableType(ExpectedReturnType) != isNullableType(ExternReturnType)) { return value.?; diff --git a/src/javascript/jsc/bindings/webcore/WebSocket.cpp b/src/javascript/jsc/bindings/webcore/WebSocket.cpp index 7748f2ae8..d9ffd7278 100644 --- a/src/javascript/jsc/bindings/webcore/WebSocket.cpp +++ b/src/javascript/jsc/bindings/webcore/WebSocket.cpp @@ -723,12 +723,23 @@ void WebSocket::didConnect() didClose(0, 0, emptyString()); return; } - ASSERT(scriptExecutionContext()); m_state = OPEN; - // m_subprotocol = m_channel->subprotocol(); - // m_extensions = m_channel->extensions(); - dispatchEvent(Event::create(eventNames().openEvent, Event::CanBubble::No, Event::IsCancelable::No)); - // }); + + if (auto* context = scriptExecutionContext()) { + if (this->hasEventListeners("open"_s)) { + // the main reason for dispatching on a separate tick is to handle when you haven't yet attached an event listener + dispatchEvent(Event::create(eventNames().openEvent, Event::CanBubble::No, Event::IsCancelable::No)); + } else { + context->postTask([this, protectedThis = Ref { *this }](ScriptExecutionContext& context) { + ASSERT(scriptExecutionContext()); + + // m_subprotocol = m_channel->subprotocol(); + // m_extensions = m_channel->extensions(); + protectedThis->dispatchEvent(Event::create(eventNames().openEvent, Event::CanBubble::No, Event::IsCancelable::No)); + // }); + }); + } + } } void WebSocket::didReceiveMessage(String&& message) @@ -744,8 +755,21 @@ void WebSocket::didReceiveMessage(String&& message) // inspector->didReceiveWebSocketFrame(WebSocketChannelInspector::createFrame(utf8Message.dataAsUInt8Ptr(), utf8Message.length(), WebSocketFrame::OpCode::OpCodeText)); // } // } - ASSERT(scriptExecutionContext()); - dispatchEvent(MessageEvent::create(WTFMove(message), m_url.string())); + + if (this->hasEventListeners("message"_s)) { + // the main reason for dispatching on a separate tick is to handle when you haven't yet attached an event listener + dispatchEvent(MessageEvent::create(WTFMove(message), m_url.string())); + return; + } + + if (auto* context = scriptExecutionContext()) { + + context->postTask([this, message_ = message, protectedThis = Ref { *this }](ScriptExecutionContext& context) { + ASSERT(scriptExecutionContext()); + protectedThis->dispatchEvent(MessageEvent::create(message_, protectedThis->m_url.string())); + }); + } + // }); } @@ -766,10 +790,24 @@ void WebSocket::didReceiveBinaryData(Vector<uint8_t>&& binaryData) // // FIXME: We just received the data from NetworkProcess, and are sending it back. This is inefficient. // dispatchEvent(MessageEvent::create(Blob::create(scriptExecutionContext(), WTFMove(binaryData), emptyString()), SecurityOrigin::create(m_url)->toString())); // break; - case BinaryType::ArrayBuffer: - dispatchEvent(MessageEvent::create(ArrayBuffer::create(binaryData.data(), binaryData.size()), m_url.string())); + case BinaryType::ArrayBuffer: { + if (this->hasEventListeners("message"_s)) { + // the main reason for dispatching on a separate tick is to handle when you haven't yet attached an event listener + dispatchEvent(MessageEvent::create(ArrayBuffer::create(binaryData.data(), binaryData.size()), m_url.string())); + return; + } + + if (auto* context = scriptExecutionContext()) { + + context->postTask([this, message_ = message, protectedThis = Ref { *this }](ScriptExecutionContext& context) { + ASSERT(scriptExecutionContext()); + protectedThis->dispatchEvent(MessageEvent::create(ArrayBuffer::create(binaryData.data(), binaryData.size()), m_url.string())); + }); + } + break; } + } // }); } @@ -780,16 +818,18 @@ void WebSocket::didReceiveMessageError(WTF::StringImpl::StaticStringImpl* reason if (m_state == CLOSED) return; m_state = CLOSED; - ASSERT(scriptExecutionContext()); - - // if (UNLIKELY(InspectorInstrumentation::hasFrontends())) { - // if (auto* inspector = m_channel->channelInspector()) - // inspector->didReceiveWebSocketFrameError(reason); - // } - - // FIXME: As per https://html.spec.whatwg.org/multipage/web-sockets.html#feedback-from-the-protocol:concept-websocket-closed, we should synchronously fire a close event. - dispatchEvent(CloseEvent::create(false, 0, WTF::String(reason))); - // }); + if (auto* context = scriptExecutionContext()) { + context->postTask([this, reason, protectedThis = Ref { *this }](ScriptExecutionContext& context) { + ASSERT(scriptExecutionContext()); + // if (UNLIKELY(InspectorInstrumentation::hasFrontends())) { + // if (auto* inspector = m_channel->channelInspector()) + // inspector->didReceiveWebSocketFrameError(reason); + // } + + // FIXME: As per https://html.spec.whatwg.org/multipage/web-sockets.html#feedback-from-the-protocol:concept-websocket-closed, we should synchronously fire a close event. + dispatchEvent(CloseEvent::create(false, 0, WTF::String(reason))); + }); + } } void WebSocket::didUpdateBufferedAmount(unsigned bufferedAmount) @@ -832,11 +872,16 @@ void WebSocket::didClose(unsigned unhandledBufferedAmount, unsigned short code, m_state = CLOSED; m_bufferedAmount = unhandledBufferedAmount; ASSERT(scriptExecutionContext()); - - dispatchEvent(CloseEvent::create(wasClean, code, reason)); - this->m_connectedWebSocketKind = ConnectedWebSocketKind::None; this->m_upgradeClient = nullptr; + + if (auto* context = scriptExecutionContext()) { + context->postTask([this, code, wasClean, reason, protectedThis = Ref { *this }](ScriptExecutionContext& context) { + ASSERT(scriptExecutionContext()); + protectedThis->dispatchEvent(CloseEvent::create(wasClean, code, reason)); + }); + } + // m_pendingActivity = nullptr; // }); } @@ -853,7 +898,13 @@ void WebSocket::dispatchErrorEventIfNeeded() return; m_dispatchedErrorEvent = true; - dispatchEvent(Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No)); + + if (auto* context = scriptExecutionContext()) { + context->postTask([this, protectedThis = Ref { *this }](ScriptExecutionContext& context) { + ASSERT(scriptExecutionContext()); + protectedThis->dispatchEvent(Event::create(eventNames().errorEvent, Event::CanBubble::No, Event::IsCancelable::No)); + }); + } } void WebSocket::didConnect(us_socket_t* socket, char* bufferedData, size_t bufferedDataSize) @@ -873,12 +924,8 @@ void WebSocket::didConnect(us_socket_t* socket, char* bufferedData, size_t buffe } void WebSocket::didFailWithErrorCode(int32_t code) { - m_state = CLOSED; - - // this means we already handled it - if (this->m_upgradeClient == nullptr && this->m_connectedWebSocketKind == ConnectedWebSocketKind::None) { + if (m_state == CLOSED) return; - } this->m_upgradeClient = nullptr; this->m_connectedWebSocketKind = ConnectedWebSocketKind::None; @@ -1047,6 +1094,8 @@ void WebSocket::didFailWithErrorCode(int32_t code) break; } } + + m_state = CLOSED; } } // namespace WebCore |